Exemple #1
0
    def from_anim(cls, f):
        size = j3d.read_uint32(f)

        sectioncount = j3d.read_uint32(f)
        assert sectioncount == 1

        svr_data = f.read(16)

        clf_start = f.tell()
        clf_magic = f.read(4)  #clf1
        clf_size = j3d.read_uint32(f)

        loop_mode = j3d.read_uint8(f)
        j3d.read_uint8(f)

        duration = j3d.read_uint16(f)
        bla = cls(loop_mode, duration)

        cluster_count = read_uint16(f)
        scales_count = read_uint16(f)

        #print(scales_count)

        cluster_offset = read_uint32(f) + clf_start
        scales_offset = read_uint32(f) + clf_start

        # Read floats
        scales = []
        f.seek(scales_offset)
        for i in range(scales_count):

            scales.append(read_float(f))

        # Read clusters

        f.seek(cluster_offset)

        while (f.read(2) != b'Th'):
            f.seek(f.tell() - 2)
            new_anim = cluster_anim()

            clus_durati = j3d.read_uint16(f)
            clus_offset = j3d.read_uint16(f)

            #print(clus_durati)

            for j in range(clus_durati):
                new_anim.seq.append(scales[j + clus_offset])

            bla.animations.append(new_anim)

        return bla
Exemple #2
0
    def read_sound_data(cls, filepath):
        with open(filepath, "rb") as f:
            header = f.read(4)

            if header == b"Yaz0":
                decomp = BytesIO()
                decompress(f, decomp)
                #print(decomp)
                f = decomp

            f.seek(0x1c)

            offset = j3d.read_uint32(f)
            if offset == 0xFFFFFFFF:
                return None

            f.seek(offset)

            num_entries = j3d.read_uint16(f)
            f.read(6)

            sound_entries = []

            for i in range(num_entries):

                sound_id = j3d.read_uint32(f)
                start_time = j3d.read_float(f)
                end_time = j3d.read_float(f)
                coarse_pitch = j3d.read_float(f)
                flags = j3d.read_uint32(f)
                volume = j3d.read_uint8(f)
                fine_pitch = j3d.read_uint8(f)
                loop_count = j3d.read_uint8(f)
                pan = j3d.read_uint8(f)
                unk_byte = j3d.read_uint8(f)

                f.read(0x7)

                entry = cls(sound_id, start_time, end_time, coarse_pitch,
                            flags, volume, fine_pitch, loop_count, pan,
                            unk_byte)
                sound_entries.append(entry)
            return sound_entries
def get_bones_from_bmd(bmd_file):
    strings = []
    with open(bmd_file, "rb") as f:
        s = f.read()
        a = s.find(b'\x4A\x4E\x54\x31')
        #print(a)
        f.seek(a + 0x14)
        address = j3d.read_uint32(f)
        #print(address)
        f.seek(address + a)
        strings = j3d.StringTable.from_file(f).strings
        print("bones in bmd ", strings)
        f.close()

    return strings
def get_materials_from_bmd(bmd_file):
    strings = []
    with open(bmd_file, "rb") as f:
        s = f.read()
        a = s.find(b'\x4D\x41\x54\x33')
        #print(a)
        f.seek(a + 0x14)
        address = j3d.read_uint32(f)
        #print(address)
        f.seek(address + a)
        strings = j3d.StringTable.from_file(f).strings
        print(strings)
        f.close()

    return strings
Exemple #5
0
 def from_anim(cls, f):
     size = j3d.read_uint32(f)
     
     sectioncount = j3d.read_uint32(f)
     assert sectioncount == 1
     
     svr_data = f.read(16)
     
     ank_start = f.tell()
     ank_magic = f.read(4) #ank1
     ank_size = j3d.read_uint32(f)
     
     loop_mode = j3d.read_uint8(f)
     angle_scale = j3d.read_sint8(f) 
     rotscale = (2.0**angle_scale) * (180.0 / 32768.0);
     duration = j3d.read_uint16(f)
     bck = cls(loop_mode, angle_scale, duration)
     
     bone_count = read_uint16(f)
     scale_count = read_uint16(f)
     rotation_count = read_uint16(f)
     trans_count = read_uint16(f)
     
     bone_offset = read_uint32(f) + ank_start
     scale_offset = read_uint32(f) + ank_start
     rotation_offset = read_uint32(f) + ank_start
     trans_offset = read_uint32(f) + ank_start
     
     # Read scales 
     scales = []
     f.seek(scale_offset)
     for i in range(scale_count):
         scales.append(read_float(f))
     
     # Read rotations
     rotations = []
     f.seek(rotation_offset)
     for i in range(rotation_count):
         rotations.append((read_sint16(f)))
     
     # Read translations 
     trans = []
     f.seek(trans_offset)
     for i in range(trans_count):
         trans.append(read_float(f))
     
     tangent_type = 0
     
     f.seek(bone_offset)
     for i in range(bone_count):
         values = struct.unpack(">"+"H"*27, f.read(0x36))
         
         x_scale, x_rot, x_trans = values[:3], values[3:6], values[6:9]
         y_scale, y_rot, y_trans = values[9:12], values[12:15], values[15:18]
         z_scale, z_rot, z_trans = values[18:21], values[21:24], values[24:27]
         
         bone_animation = bone_anim()
         
         for scale, axis in ((x_scale, "X"), (y_scale, "Y"), (z_scale, "Z")):
             count, offset, tan_type = scale 
             tangent_type = max(tan_type, tangent_type)
             for j in range(count):
                 comp = j3d.AnimComponent.from_array(offset, j, count, scales, tan_type)
                 bone_animation.add_scale(axis, comp)
                 #print(comp)
         
         for rotation, axis in ((x_rot, "X"), (y_rot, "Y"), (z_rot, "Z")):
             count, offset, tan_type = rotation 
             tangent_type = max(tan_type, tangent_type)
             for j in range(count):
                 comp = j3d.AnimComponent.from_array(offset, j, count, rotations, tan_type)
                 comp.convert_rotation(rotscale)
                 bone_animation.add_rotation(axis, comp)
                 #print(comp)
                 
         for translation, axis in ((x_trans, "X"), (y_trans, "Y"), (z_trans, "Z")):
             count, offset, tan_type = translation
             tangent_type = max(tan_type, tangent_type)
             for j in range(count):
                 comp = j3d.AnimComponent.from_array(offset, j, count, trans, tan_type)
                 bone_animation.add_translation(axis, comp)
                 #print(comp)
                 
         bck.animations.append(bone_animation)
     bck.tan_type = tangent_type
     
     return bck
    def from_anim(cls, f):
        size = j3d.read_uint32(f)

        sectioncount = j3d.read_uint32(f)
        assert sectioncount == 1

        svr_data = f.read(16)

        clk_start = f.tell()
        clk_magic = f.read(4)  #clk1
        clk_size = j3d.read_uint32(f)

        loop_mode = j3d.read_uint8(f)
        j3d.read_uint8(f)

        duration = j3d.read_uint16(f)
        blk = cls(loop_mode, duration)

        cluster_count = read_uint16(f)
        scales_count = int(read_uint16(f))

        print("scales count " + str(scales_count))

        cluster_offset = read_uint32(f) + clk_start
        scales_offset = read_uint32(f) + clk_start

        scales = []
        f.seek(scales_offset)
        for i in range(scales_count):
            scales.append(read_float(f))
            """
            time = read_float(f)
            value = read_float(f)
            tangentIn = read_float(f)
            anim = j3d.AnimComponent( time, value, tangentIn )
            scales.append(anim) 
            """

        tangent_type = 0

        f.seek(cluster_offset)
        while (f.read(2) != b'Th'):
            f.seek(f.tell() - 2)

            new_anim = cluster_anim()

            clus_durati = j3d.read_uint16(f)
            clus_offset = int(j3d.read_uint16(f))
            tan_type = j3d.read_uint16(f)
            tangent_type = max(tangent_type, tan_type)

            for j in range(clus_durati):
                comp = j3d.AnimComponent.from_array(clus_offset, j,
                                                    clus_durati, scales,
                                                    tan_type)
                #new_anim.seq.append( scales[j + clus_offset] )
                new_anim.seq.append(comp)

            blk.animations.append(new_anim)

        blk.tan_type = tangent_type

        return blk
Exemple #7
0
    def from_anim(cls, f):

        size = read_uint32(f)
        #print("Size of btk: {} bytes".format(size))
        sectioncount = read_uint32(f)
        assert sectioncount == 1

        svr_data = f.read(16)

        ttk_start = f.tell()

        ttk_magic = f.read(4)
        ttk_sectionsize = j3d.read_uint32(f)

        loop_mode = j3d.read_uint8(f)
        angle_scale = j3d.read_sint8(f)
        rotscale = (2.0**angle_scale) * (180.0 / 32768.0)
        duration = j3d.read_uint16(f)
        btk = cls(loop_mode, angle_scale, duration)

        threetimestexmatanims = read_uint16(f)
        scale_count = read_uint16(f)
        rotation_count = read_uint16(f)
        translation_count = read_uint16(f)
        """
        print("three times texmat anims", threetimestexmatanims)
        print("scale count", scale_count)
        print("rotation count", rotation_count)
        print("translation count", translation_count)
        """
        texmat_anim_offset = read_uint32(
            f) + ttk_start  # J3DAnmTransformKeyTable
        index_offset = read_uint32(f) + ttk_start  # unsigned short
        stringtable_offset = read_uint32(f) + ttk_start  # 0 terminated strings
        texmat_index_offset = read_uint32(f) + ttk_start  # unsigned byte
        center_offset = read_uint32(f) + ttk_start  # Vector with 3 entries
        scale_offset = read_uint32(f) + ttk_start  # float
        rotation_offset = read_uint32(f) + ttk_start  # signed short
        translation_offset = read_uint32(f) + ttk_start  # float
        """
        print("Position:", hex(f.tell()))
        print("tex anim offset", hex(texmat_anim_offset))
        print("index offset", hex(index_offset))
        print("mat name offset", hex(stringtable_offset))
        print("texmat index offset", hex(texmat_index_offset))
        print("center offset", hex(center_offset))
        print("scale offset", hex(scale_offset))
        print("rotation offset", hex(rotation_offset))
        print("translation offset", hex(translation_offset))
        """

        anim_count = threetimestexmatanims // 3
        #print("Animation count:", anim_count)

        f.seek(0x7C)
        unknown_address = read_uint32(f)
        btk.unknown_address = unknown_address
        # Read indices
        indices = []
        f.seek(index_offset)
        for i in range(anim_count):
            indices.append(read_uint16(f))

        # Read matrix indices
        mat_indices = []
        f.seek(texmat_index_offset)
        for i in range(anim_count):
            mat_indices.append(read_uint8(f))

        # Read stringtable
        f.seek(stringtable_offset)
        stringtable = StringTable.from_file(f)

        # Read scales
        scales = []
        f.seek(scale_offset)
        for i in range(scale_count):
            scales.append(read_float(f))

        # Read rotations
        rotations = []
        f.seek(rotation_offset)
        for i in range(rotation_count):
            rotations.append((read_sint16(f)))

        # Read translations
        translations = []
        f.seek(translation_offset)
        for i in range(translation_count):
            translations.append(read_float(f))

        tangent_type = 0

        # Read data per animation
        for i in indices:
            mat_index = mat_indices[i]

            # Read center for this animation
            f.seek(center_offset + 12 * i)
            center = struct.unpack(">fff", f.read(12))

            name = stringtable.strings[i]
            """
            print("================")
            print("anim", i)
            print("mat index", mat_index, "name", name, "center", center)
            """
            f.seek(texmat_anim_offset + i * 0x36)
            #print(hex(texmat_anim_offset + i*0x36))
            values = struct.unpack(">" + "H" * 27, f.read(0x36))

            u_scale, u_rot, u_trans = values[:3], values[3:6], values[6:9]
            v_scale, v_rot, v_trans = values[9:12], values[12:15], values[
                15:18]
            w_scale, w_rot, w_trans = values[18:21], values[21:24], values[
                24:27]

            matrix_animation = MatrixAnimation(i, mat_index, name, center)

            inter_count = 0

            for scale, axis in ((u_scale, "U"), (v_scale, "V"), (w_scale,
                                                                 "W")):
                count, offset, tan_type = scale
                tan_inter = 0
                tangent_type = max(tan_type, tangent_type)
                for j in range(count):
                    comp = j3d.AnimComponent.from_array(
                        offset, j, count, scales, tan_type)

                    if comp.tangentIn == 0:
                        matrix_animation.tan_inter[inter_count] = 1
                    matrix_animation.add_scale(axis, comp)
                if matrix_animation.tan_inter[inter_count] == -1:
                    matrix_animation.tan_inter[inter_count] = 0
                inter_count += 1
            for rotation, axis in ((u_rot, "U"), (v_rot, "V"), (w_rot, "W")):
                count, offset, tan_type = rotation

                tangent_type = max(tan_type, tangent_type)
                for j in range(count):
                    comp = j3d.AnimComponent.from_array(
                        offset, j, count, rotations, tan_type)
                    comp.convert_rotation(rotscale)

                    if comp.tangentIn != 0:
                        matrix_animation.tan_inter[inter_count] = 0
                    matrix_animation.add_rotation(axis, comp)
                inter_count += 1
                if matrix_animation.tan_inter[inter_count] == -1:
                    matrix_animation.tan_inter[inter_count] = 0
            for translation, axis in ((u_trans, "U"), (v_trans, "V"), (w_trans,
                                                                       "W")):
                count, offset, tan_type = translation

                tangent_type = max(tan_type, tangent_type)
                for j in range(count):
                    comp = j3d.AnimComponent.from_array(
                        offset, j, count, translations, tan_type)
                    if comp.tangentIn != 0:
                        matrix_animation.tan_inter[inter_count] = 0
                    matrix_animation.add_translation(axis, comp)
                if matrix_animation.tan_inter[inter_count] == -1:
                    matrix_animation.tan_inter[inter_count] = 0
                inter_count += 1
            #btk.tan_type = tangent_type
            """
            print(u_scale, u_rot, u_trans)
            
            print(v_scale, v_rot, v_trans)
            
            print(w_scale, w_rot, w_trans)
            """
            btk.animations.append(matrix_animation)
        btk.tan_type = tangent_type
        return btk
def read_bls(filepath):
    with open(filepath, "rb") as f:
        magic = f.read(8)
        size = j3d.read_uint32(f)

        sectioncount = j3d.read_uint32(f)
        assert sectioncount == 1

        svr_data = f.read(16)
        cls_start = f.tell()
        cls_magic = f.read(4)
        cls_size = j3d.read_uint32(f)

        # read counts

        cluster_count = j3d.read_uint16(f)
        keycluster_count = j3d.read_uint16(f)
        nrmblend_count = j3d.read_uint16(f)
        vtxpos_count = j3d.read_uint16(f)
        vtxnorm_count = j3d.read_uint16(f)

        f.read(2)

        #read offsets

        cluster_offset = j3d.read_uint32(f) + cls_start
        keycluster_offset = j3d.read_uint32(f) + cls_start
        nrmblend_offset = j3d.read_uint32(f) + cls_start
        vtxpos_offset = j3d.read_uint32(f) + cls_start
        vtxnorm_offset = j3d.read_uint32(f) + cls_start
        vtxnorm_part2_offset = vtxnorm_offset + 0xc * vtxnorm_count  #index table

        clustername_offset = j3d.read_uint32(f) + cls_start
        clusterkeyname_offset = j3d.read_uint32(f) + cls_start

        #read vertex array
        vertex_poss = []
        f.seek(vtxpos_offset)
        for i in range(vtxpos_count):
            x = j3d.read_float(f)
            y = j3d.read_float(f)
            z = j3d.read_float(f)
            vertex_poss.append(position(x, y, z))

        #read the table that the normal blends refer to - so the normals
        vertex_norms = []
        f.seek(vtxnorm_offset)
        for i in range(vtxnorm_count):
            x = j3d.read_float(f)
            y = j3d.read_float(f)
            z = j3d.read_float(f)
            vertex_norms.append(normal(x, y, z))

        #read normal blend data
        nrmblends = []
        f.seek(nrmblend_offset)
        #the first four shorts starting from offset 0x4e20 are source indices. these source indices are indices into another "blend" table.
        for i in range(nrmblend_count):
            f.seek(nrmblend_offset + 0xc * i)
            num = j3d.read_uint16(f)
            f.read(2)
            src = j3d.read_uint32(
                f
            ) + cls_start  #offsets into section 5 part 2 - point to shorts
            dest = j3d.read_uint32(f) + cls_start

            curr_blend = normal_blend()

            f.seek(src)
            for j in range(num):
                index = j3d.read_uint16(f)
                curr_blend.src.append(vertex_norms[index])

            f.seek(dest)
            for j in range(num):
                index = j3d.read_uint16(f)
                curr_blend.dest.append(vertex_norms[index])

            #print( curr_blend )

            nrmblends.append(curr_blend)

        f.seek(clustername_offset)
        cluster_stringtable = j3d.StringTable.from_file(f)

        f.seek(clusterkeyname_offset)
        clusterkey_stringtable = j3d.StringTable.from_file(f)

        blls = bls()

        for i in range(keycluster_count):
            f.seek(keycluster_offset + 0xc * i)
            #uhh only normals ig
            position_count = j3d.read_uint16(f)
            normal_count = j3d.read_uint16(f)

            position_offset = j3d.read_uint32(f) + cls_start
            normal_offset = j3d.read_uint32(f) + cls_start

            curr_key = clusterkey()

            curr_key.name = clusterkey_stringtable.strings[i]

            f.seek(position_offset)
            for j in range(position_count):
                index = j3d.read_uint16(f)

                sign_bits = (index >> 0xd)

                index = index & 0x1FFF
                curr_key.positions.append(vertex_poss[index].neg(sign_bits))

            f.seek(normal_offset)
            for j in range(normal_count):
                index = j3d.read_uint16(f)
                sign_bits = (index >> 0xd)
                index = index & 0x1FFF
                curr_key.normals.append(vertex_norms[index].neg(sign_bits))

            blls.clusters_key.append(curr_key)

        for i in range(cluster_count):
            f.seek(cluster_offset + 0x24 * i)
            max_angle = j3d.read_float(f)
            min_angle = j3d.read_float(f)
            unk_addr = j3d.read_uint32(f)  #usually the last clusterkeynum
            flag = j3d.read_uint8(f)
            f.read(3)

            key_num = j3d.read_uint16(f)
            pos_num = j3d.read_uint16(f)
            normal_num = j3d.read_uint16(f)
            normalblend_num = j3d.read_uint16(f)

            position_offset = j3d.read_uint32(f) + cls_start
            normalblend_offset = j3d.read_uint32(f) + cls_start
            deformer_offset = j3d.read_uint32(f) + cls_start

            curr_cluster = cluster(max_angle, min_angle, flag, key_num)
            curr_cluster.name = cluster_stringtable.strings[i]

            key_index = int((unk_addr + cls_start - keycluster_offset) / 0xC)
            curr_cluster.clusterkey = blls.clusters_key[key_index]

            f.seek(position_offset)
            for j in range(pos_num):
                index = j3d.read_uint16(f)

                sign_bits = (index >> 0xd)
                #index = index & 0x1FFF
                curr_cluster.positions.append(index)

            for i in range(normalblend_num):
                j = int((normalblend_offset - nrmblend_offset) / 12 + i)
                curr_cluster.normal_blends.append(nrmblends[j])
                #print( nrmblends[j] )

            blls.clusters.append(curr_cluster)

    return blls
Exemple #9
0
    def from_anim(cls, f):
        size = j3d.read_uint32(f)

        sectioncount = j3d.read_uint32(f)
        assert sectioncount == 1

        svr_data = f.read(12)
        sound = j3d.read_uint32(f)
        #print("sound " + str(sound) )

        ank_start = f.tell()
        ank_magic = f.read(4)  #ank1
        ank_size = j3d.read_uint32(f)

        loop_mode = j3d.read_uint8(f)
        angle_scale = j3d.read_sint8(f)
        rotscale = (2.0**angle_scale) * (180.0 / 32768.0)
        duration = j3d.read_uint16(f)
        bck = cls(loop_mode, angle_scale, duration, 1)

        bone_count = read_uint16(f)
        scale_count = read_uint16(f)
        rotation_count = read_uint16(f)
        trans_count = read_uint16(f)

        bone_offset = read_uint32(f) + ank_start
        scale_offset = read_uint32(f) + ank_start
        rotation_offset = read_uint32(f) + ank_start
        trans_offset = read_uint32(f) + ank_start

        # Read scales
        scales = []
        f.seek(scale_offset)
        for i in range(scale_count):
            scales.append(read_float(f))

        # Read rotations
        rotations = []
        f.seek(rotation_offset)
        for i in range(rotation_count):
            rotations.append((read_sint16(f)))

        # Read translations
        trans = []
        f.seek(trans_offset)
        for i in range(trans_count):
            trans.append(read_float(f))

        tangent_type = 0

        f.seek(bone_offset)
        for i in range(bone_count):
            values = struct.unpack(">" + "H" * 27, f.read(0x36))

            x_scale, x_rot, x_trans = values[:3], values[3:6], values[6:9]
            y_scale, y_rot, y_trans = values[9:12], values[12:15], values[
                15:18]
            z_scale, z_rot, z_trans = values[18:21], values[21:24], values[
                24:27]

            bone_animation = bone_anim()

            inter_count = 0

            #default tangent interpolation is smooth
            for scale, axis in ((x_scale, "X"), (y_scale, "Y"), (z_scale,
                                                                 "Z")):
                count, offset, tan_type = scale

                tangent_type = max(tan_type, tangent_type)
                for j in range(count):
                    #print( offset, j, count,tan_type, len(scales) )
                    comp = j3d.AnimComponent.from_array(
                        offset, j, count, scales, tan_type)
                    if comp.tangentIn == 0:
                        bone_animation.tan_inter[inter_count] = 1

                    bone_animation.add_scale(axis, comp)
                    #print(comp)
                if bone_animation.tan_inter[inter_count] == -1:
                    bone_animation.tan_inter[inter_count] = 0
                inter_count += 1

            for rotation, axis in ((x_rot, "X"), (y_rot, "Y"), (z_rot, "Z")):
                count, offset, tan_type = rotation
                tangent_type = max(tan_type, tangent_type)
                for j in range(count):
                    comp = j3d.AnimComponent.from_array(
                        offset, j, count, rotations, tan_type)
                    comp.convert_rotation(rotscale)
                    if comp.tangentIn != 0:
                        bone_animation.tan_inter[inter_count] = 0

                    bone_animation.add_rotation(axis, comp)
                    #print(comp)
                if bone_animation.tan_inter[inter_count] == -1:
                    bone_animation.tan_inter[inter_count] = 1
                inter_count += 1

            for translation, axis in ((x_trans, "X"), (y_trans, "Y"), (z_trans,
                                                                       "Z")):
                count, offset, tan_type = translation
                tangent_type = max(tan_type, tangent_type)
                for j in range(count):
                    comp = j3d.AnimComponent.from_array(
                        offset, j, count, trans, tan_type)
                    if comp.tangentIn == 0:
                        bone_animation.tan_inter[inter_count] = 1
                    bone_animation.add_translation(axis, comp)
                    #print(comp)
                if bone_animation.tan_inter[inter_count] == -1:
                    bone_animation.tan_inter[inter_count] = 0
                inter_count += 1
            bck.animations.append(bone_animation)
        bck.tan_type = tangent_type

        if sound != 0xffffffff:
            f.seek(sound)
            num_entries = j3d.read_uint16(f)
            f.read(6)

            sound_entries = []

            for i in range(num_entries):

                sound_id = j3d.read_uint32(f)
                start_time = j3d.read_float(f)
                end_time = j3d.read_float(f)
                coarse_pitch = j3d.read_float(f)
                flags = j3d.read_uint32(f)
                volume = j3d.read_uint8(f)
                fine_pitch = j3d.read_uint8(f)
                loop_count = j3d.read_uint8(f)
                pan = j3d.read_uint8(f)
                unk_byte = j3d.read_uint8(f)

                f.read(0x7)

                entry = sound_entry(sound_id, start_time, end_time,
                                    coarse_pitch, flags, volume, fine_pitch,
                                    loop_count, pan, unk_byte)
                sound_entries.append(entry)

            bck.sound = sound_entries

        return bck
Exemple #10
0
    def from_anim(cls, f):
        #at this point, f is at 0x09
        size = j3d.read_uint32(f)

        sectioncount = j3d.read_uint32(f)
        assert sectioncount == 1

        svr_data = f.read(16)
        #at this point, f is at the actual start of the documentaion

        tpt_start = f.tell()
        tpt_magic = f.read(4) #TPT1

        tpt_sectionsize = j3d.read_uint32(f)

        flag = j3d.read_uint8(f)
        angle = j3d.read_uint8(f)

        anim_length = j3d.read_uint16(f)
        num_entries = j3d.read_uint16(f) #also known as "keyframe count in the documentation"
        print("there are " + str(num_entries) + " entries")
        
        unknown1 = j3d.read_uint16(f)
        
        btp = cls(flag, angle, unknown1)

        #offsets
        facial_animation_entries_os = j3d.read_uint32(f) + tpt_start
        texture_index_bank_os = j3d.read_uint32(f) + tpt_start
        remap_table_os = j3d.read_uint32(f) + tpt_start
        stringtable_os = j3d.read_uint32(f) + tpt_start

        #at this point, we are at the facial animation entries
        
        
        #make string table
        f.seek(stringtable_os)
        stringtable = j3d.StringTable.from_file(f)
    
        read_animations = []
    
        for i in range(num_entries):
        
            f.seek(facial_animation_entries_os + i * 8)
            print(f.tell())
        
            this_length = j3d.read_uint16(f)
            print("length of " + str(i) + " is " + str(this_length))
            this_start = j3d.read_uint16(f)
            
            indices = []
            
            f.seek(texture_index_bank_os + 2 * this_start)
     
            for j in range(this_length):
                indices.append(j3d.read_uint16(f))
            
            animation = btp_facial_entry(stringtable.strings[i], indices)
            
            read_animations.append(animation)
            
       
        btp.animations = read_animations
        f.close()
        return btp