Ejemplo n.º 1
0
    def meta_to_tag_data(self, meta, tag_cls, tag_index_ref, **kwargs):
        magic = self.map_magic
        engine = self.engine
        map_data = self.map_data
        tag_index = self.tag_index
        is_xbox = get_is_xbox_map(engine)

        if tag_cls == "bitm":
            # set the size of the compressed plate data to nothing
            meta.compressed_color_plate_data.STEPTREE = BytearrayBuffer()

            new_pixels_offset = 0

            # uncheck the prefer_low_detail flag and
            # set up the pixels_offset correctly.
            for bitmap in meta.bitmaps.STEPTREE:
                bitmap.flags.prefer_low_detail = is_xbox
                bitmap.pixels_offset = new_pixels_offset
                new_pixels_offset += bitmap.pixels_meta_size

                # clear some meta-only fields
                bitmap.pixels_meta_size = 0
                bitmap.bitmap_id_unknown1 = bitmap.bitmap_id_unknown2 = 0
                bitmap.bitmap_data_pointer = bitmap.base_address = 0

        elif tag_cls == "snd!":
            meta.maximum_bend_per_second = meta.maximum_bend_per_second**30
            for pitch_range in meta.pitch_ranges.STEPTREE:
                for permutation in pitch_range.permutations.STEPTREE:
                    if permutation.compression.enum_name == "none":
                        # byteswap pcm audio
                        byteswap_pcm16_samples(permutation.samples)

        return meta
Ejemplo n.º 2
0
def extract_bitmaps(tagdata, tag_path, **kw):
    filepath_base = os.path.join(
        kw['out_dir'], os.path.splitext(tag_path)[0])

    ext = kw.get("bitmap_ext", "").strip(". ")
    keep_alpha = kw.get("bitmap_keep_alpha", True)
    engine = kw.pop('engine', '')
    pix_data = tagdata.processed_pixel_data.STEPTREE
    if 'halo_map' in kw:
        engine = kw['halo_map'].engine

    p8_palette = STUBBS_P8_PALETTE if "stubbs" in engine else HALO_P8_PALETTE
    if not ext:
        ext = "dds"

    is_xbox = get_is_xbox_map(engine)
    is_gen3 = hasattr(tagdata, "zone_assets_normal")
    if Arbytmap is None:
        # cant extract xbox bitmaps yet
        return "    Arbytmap not loaded. Cannot extract bitmaps."

    arby = Arbytmap()
    bitm_i = 0
    multi_bitmap = len(tagdata.bitmaps.STEPTREE) > 1
    size_calc = get_h3_pixel_bytes_size if is_gen3 else get_pixel_bytes_size
    dim_calc = get_virtual_dimension if is_gen3 else None

    for bitmap in tagdata.bitmaps.STEPTREE:
        typ = bitmap.type.enum_name
        fmt = bitmap.format.enum_name
        w = bitmap.width
        h = bitmap.height
        d = bitmap.depth
        tiled = False
        if hasattr(bitmap, "format_flags"):
            tiled = bitmap.format_flags.tiled

        filepath = filepath_base
        if multi_bitmap:
            filepath += "__%s" % bitm_i
            bitm_i += 1

        tex_block = []
        tex_info = dict(
            width=w, height=h, depth=d, mipmap_count=bitmap.mipmaps,
            swizzled=bitmap.flags.swizzled, big_endian=is_gen3,
            packed=True, tiled=tiled, tile_method="DXGI",
            packed_width_calc=dim_calc, packed_height_calc=dim_calc,
            filepath=filepath + "." + ext,
            )
        tex_info["texture_type"] = {
            "texture_2d": TYPE_2D, "texture_3d": TYPE_3D,
            "cubemap": TYPE_CUBEMAP}.get(typ, TYPE_2D)
        tex_info["sub_bitmap_count"] = {
            "texture_2d": 1, "texture_3d": 1,
            "cubemap": 6, "multipage_2d": d}.get(typ, 1)
        if typ == "multipage_2d":
            tex_info.update(depth=1)
            d = 1


        if fmt == "p8_bump":
            tex_info.update(
                palette=[p8_palette.p8_palette_32bit_packed]*(bitmap.mipmaps + 1),
                palette_packed=True, indexing_size=8, format=FORMAT_P8_BUMP)
        else:
            tex_info["format"] = {
                "a8": FORMAT_A8, "y8": FORMAT_L8, "ay8": FORMAT_AL8,
                "a8y8": FORMAT_A8L8, "p8": FORMAT_A8,
                "v8u8": FORMAT_V8U8, "g8b8": FORMAT_R8G8,
                "x8r8g8b8": FORMAT_A8R8G8B8, "a8r8g8b8": FORMAT_A8R8G8B8,
                "r5g6b5": FORMAT_R5G6B5, "a1r5g5b5": FORMAT_A1R5G5B5,
                "a4r4g4b4": FORMAT_A4R4G4B4,
                "dxt1": FORMAT_DXT1, "dxt3": FORMAT_DXT3, "dxt5": FORMAT_DXT5,
                "ctx1": FORMAT_CTX1, "dxn": FORMAT_DXN, "dxt5ay": FORMAT_DXT5AY,
                "dxt3a": FORMAT_DXT3A, "dxt3y": FORMAT_DXT3Y,
                "dxt5a": FORMAT_DXT5A, "dxt5y": FORMAT_DXT5Y,
                "rgbfp16": FORMAT_R16G16B16F, "argbfp32": FORMAT_A32R32G32B32F,
                "rgbfp32": FORMAT_R32G32B32F}.get(fmt, None)


        arby_fmt = tex_info["format"]
        if arby_fmt is None:
            continue

        i_max = tex_info["sub_bitmap_count"] if is_xbox else bitmap.mipmaps + 1
        j_max = bitmap.mipmaps + 1 if is_xbox else tex_info['sub_bitmap_count']
        off = bitmap.pixels_offset
        for i in range(i_max):
            if not is_xbox:
                mip_size = size_calc(arby_fmt, w, h, d, i, tiled)

            for j in range(j_max):
                if is_xbox:
                    mip_size = size_calc(arby_fmt, w, h, d, j, tiled)

                if fmt == "p8_bump":
                    tex_block.append(
                        array('B', pix_data[off: off + (mip_size // 4)]))
                    off += len(tex_block[-1])
                else:
                    off = bitmap_io.bitmap_bytes_to_array(
                        pix_data, off, tex_block,
                        arby_fmt, 1, 1, 1, mip_size)

            # skip the xbox alignment padding to get to the next texture
            if is_xbox and typ == "cubemap":
                off += ((CUBEMAP_PADDING - (off % CUBEMAP_PADDING)) %
                        CUBEMAP_PADDING)


        if is_xbox and typ == "cubemap":
            template = tuple(tex_block)
            i = 0
            for f in (0, 2, 1, 3, 4, 5):
                for m in range(bitmap.mipmaps + 1):
                    tex_block[m*6 + f] = template[i]
                    i += 1

        if not tex_block:
            # nothing to extract
            continue

        arby.load_new_texture(texture_block=tex_block, texture_info=tex_info,
                              tile_mode=False, swizzle_mode=False)
        arby.save_to_file(keep_alpha=keep_alpha)
Ejemplo n.º 3
0
    def inject_rawdata(self, meta, tag_cls, tag_index_ref):
        bitmaps = self.maps.get("bitmaps")
        sounds = self.maps.get("sounds")
        loc = self.maps.get("loc")

        magic = self.map_magic
        engine = self.engine

        map_data = self.map_data

        try:
            bitmap_data = bitmaps.map_data
        except Exception:
            bitmap_data = None
        try:
            sound_data = sounds.map_data
        except Exception:
            sound_data = None
        try:
            loc_data = loc.map_data
        except Exception:
            loc_data = None

        is_not_indexed = not self.is_indexed(tag_index_ref.id & 0xFFff)
        might_be_in_rsrc = engine in ("halo1pc", "halo1pcdemo", "halo1ce",
                                      "halo1yelo", "halo1vap")
        might_be_in_rsrc &= not self.is_resource

        # get some rawdata that would be pretty annoying to do in the parser
        if tag_cls == "bitm":
            # grab bitmap data from map
            new_pixels = BytearrayBuffer()

            # to enable compatibility with my bitmap converter we'll set the
            # base address to a certain constant based on the console platform
            is_xbox = get_is_xbox_map(engine)
            for bitmap in meta.bitmaps.STEPTREE:
                pixel_data = map_data
                if might_be_in_rsrc and bitmap.flags.data_in_resource_map:
                    pixel_data = bitmap_data

                if pixel_data is None: return

                # grab the bitmap data from this map(no magic used)
                pixel_data.seek(bitmap.pixels_offset)
                new_pixels += pixel_data.read(bitmap.pixels_meta_size)

                bitmap.base_address = 1073751810 * is_xbox

            meta.processed_pixel_data.STEPTREE = new_pixels
        elif tag_cls == "font":
            # might need to grab pixel data from resource map
            meta_offset = tag_index_ref.meta_offset

            if is_not_indexed:
                return meta
            elif not self.is_resource:
                if loc is None or loc.map_header is None: return
                meta_offset = loc.rsrc_map.data.tags[meta_offset].tag.offset

            if loc_data is None: return

            loc_data.seek(meta.pixels.pointer + meta_offset)
            meta.pixels.data = loc_data.read(meta.pixels.size)
        elif tag_cls == "hmt ":
            # might need to grab string data from resource map
            meta_offset = tag_index_ref.meta_offset

            if is_not_indexed:
                return meta
            elif not self.is_resource:
                if loc is None or loc.map_header is None: return
                meta_offset = loc.rsrc_map.data.tags[meta_offset].tag.offset

            b = meta.string
            loc_data.seek(b.pointer + meta_offset)
            meta.string.data = loc_data.read(b.size).decode('utf-16-le')
        elif tag_cls == "snd!":
            # might need to get samples and permutations from the resource map
            is_pc = engine in ("halo1pc", "halo1pcdemo")
            is_ce = engine in ("halo1ce", "halo1yelo", "halo1vap")
            if not (is_pc or is_ce):
                return meta
            elif sound_data is None:
                return

            # ce tagpaths are in the format:  path__permutations
            #     ex: sound\sfx\impulse\coolant\enter_water__permutations
            #
            # pc tagpaths are in the format:  path__pitchrange__permutation
            #     ex: sound\sfx\impulse\coolant\enter_water__0__0
            other_data = map_data
            sound_magic = 0 - magic
            # DO NOT optimize this section. The logic is like this on purpose
            if is_pc:
                pass
            elif self.is_resource:
                other_data = sound_data
                sound_magic = tag_index_ref.meta_offset + meta.get_size()
            elif sounds is None:
                return

            for pitches in meta.pitch_ranges.STEPTREE:
                for perm in pitches.permutations.STEPTREE:
                    for b in (perm.samples, perm.mouth_data,
                              perm.subtitle_data):
                        inject_sound_data(other_data, sound_data, b,
                                          sound_magic)

        elif tag_cls == "ustr":
            # might need to grab string data from resource map
            meta_offset = tag_index_ref.meta_offset

            if is_not_indexed:
                return meta
            elif not self.is_resource:
                if loc is None or loc.map_header is None: return
                meta_offset = loc.rsrc_map.data.tags[meta_offset].tag.offset

            string_blocks = meta.strings.STEPTREE

            if len(string_blocks):
                desc = string_blocks[0].get_desc('STEPTREE')
                parser = desc['TYPE'].parser

            try:
                FieldType.force_little()
                for b in string_blocks:
                    parser(desc, None, b, 'STEPTREE', loc_data, meta_offset,
                           b.pointer)
                FieldType.force_normal()
            except Exception:
                print(format_exc())
                FieldType.force_normal()
                raise