def __init__(self, frame_info, data): self.info = frame_info self.boundaries = [] # for each row, contains the (left, right) number of boundary pixels self.cmd_offsets = [] # for each row, store the file offset to the first drawing command self.pcolor = [] # matrix that contains all the palette indices drawn by commands, key: rowid dbg(push="frame", lvl=3) # process bondary table for i in range(self.info.size[1]): outline_entry_position = self.info.outline_table_offset + i * SLPFrame.slp_frame_row_edge.size left, right = SLPFrame.slp_frame_row_edge.unpack_from(data, outline_entry_position) # is this row completely transparent? if left == 0x8000 or right == 0x8000: self.boundaries.append(self.transparent) # TODO: -1 or like should be enough else: self.boundaries.append((left, right)) dbg("boundary values: " + str(self.boundaries)) # process cmd table for i in range(self.info.size[1]): cmd_table_position = self.info.qdl_table_offset + i * SLPFrame.slp_command_offset.size cmd_offset, = SLPFrame.slp_command_offset.unpack_from(data, cmd_table_position) self.cmd_offsets.append(cmd_offset) dbg("cmd_offsets: " + str(self.cmd_offsets)) self.pcolor = [] for i in range(self.info.size[1]): palette_color_row = self.create_palette_color_row(data, i) self.pcolor.append(palette_color_row) if ifdbg(4): dbg("frame color index data:\n" + str(self.pcolor), 4) dbg(pop="frame")
def main(): args = parse_args() #set verbose value in util set_verbosity(args.verbose) #assume to extract all files when nothing specified. if args.extract == []: args.extract.append('*:*.*') extraction_rules = [ ExtractionRule(e) for e in args.extract ] merge_images = not args.nomerge exec_dev = args.development #set path in utility class dbg("setting age2 input directory to " + args.srcdir, 1) set_read_dir(args.srcdir) #write mode is disabled by default, unless destdir is set if args.destdir != '/dev/null' and not args.listfiles and not args.dumpfilelist: dbg("setting write dir to " + args.destdir, 1) set_write_dir(args.destdir) write_enabled = True else: write_enabled = False drsfiles = { "graphics": DRS("Data/graphics.drs"), "interface": DRS("Data/interfac.drs"), "sounds0": DRS("Data/sounds.drs"), "sounds1": DRS("Data/sounds_x1.drs"), "gamedata0": DRS("Data/gamedata.drs"), "gamedata1": DRS("Data/gamedata_x1.drs"), "gamedata2": DRS("Data/gamedata_x1_p1.drs"), "terrain": DRS("Data/terrain.drs") } palette = ColorTable(drsfiles["interface"].get_file_data('bin', 50500)) if exec_dev: if write_enabled: print("no indev function available at the moment.") return else: raise Exception("development mode requires write access") if write_enabled: file_write(file_get_path('processed/player_color_palette.pal', write=True), palette.gen_player_color_palette()) import blendomatic blend_data = blendomatic.Blendomatic("Data/blendomatic.dat") for (modeidx, png, size, metadata) in blend_data.draw_alpha_frames_merged(): fname = 'alphamask/mode%02d' % (modeidx) filename = file_get_path(fname, write=True) file_write(filename + ".png", png) file_write(filename + ".docx", metadata) dbg("blending mode%02d -> saved packed atlas" % (modeidx), 1) import gamedata.empiresdat datfile = gamedata.empiresdat.Empires2X1P1("Data/empires2_x1_p1.dat") filename = file_get_path("processed/terrain_meta.docx", write=True) tmeta = "#terrain specification\n" tmeta += "#idx=terrain_id, slp_id, sound_id, blend_mode, blend_priority, angle_count, frame_count, terrain_dimensions0, terrain_dimensions1, terrain_replacement_id, name0, name1\n" tmeta += "n=%d\n" % len(datfile.data["terrain"]["terrain"]) i = 0 blending_modes = set() for tk in datfile.data["terrain"]["terrain"]: if tk["slp_id"] < 0: continue blending_modes.add(tk["blend_mode"]) wanted = ["terrain_id", "slp_id", "sound_id", "blend_mode", "blend_priority", "angle_count", "frame_count", "terrain_dimensions0", "terrain_dimensions1", "terrain_replacement_id", "name0", "name1"] line = [tk[w] for w in wanted] #as blending mode 0==1 and 7==8, and ice is 5 for sure, #we subtract one from the ids, and can map -1 to 0, as mode (0-1) == (1-1) #TODO: this can't be correct... line[3] -= 1 if line[3] < 0: line[3] = 0 line = map(str, line) tmeta += ("%d=" % i) + ",".join(line) + "\n" i += 1 file_write(filename, tmeta) filename = file_get_path("processed/blending_meta.docx", write=True) bmeta = "#blending mode specification\n" bmeta += "#yeah, i know that this content is totally stupid, but that's how the data can be injected later\n" bmeta += "#idx=mode_id\n" bmeta += "n=%d\n" % len(blending_modes) i = 0 for m in blending_modes: bmeta += "%d=%d\n" % (i, m) i += 1 file_write(filename, bmeta) if args.extrafiles: file_write(file_get_path('info/colortable.pal.png', write=True), palette.gen_image()) file_list = dict() files_extracted = 0 for drsname, drsfile in drsfiles.items(): for file_extension, file_id in drsfile.files: if not any((er.matches(drsname, file_id, file_extension) for er in extraction_rules)): continue if args.listfiles or args.dumpfilelist: fid = int(file_id) if fid not in file_list: file_list[fid] = list() file_list[fid] += [(drsfile.fname, file_extension)] continue if write_enabled: fbase = file_get_path('raw/' + drsfile.fname + '/' + str(file_id), write=True) fname = fbase + '.' + file_extension dbg("Extracting to " + fname + "...", 2) file_data = drsfile.get_file_data(file_extension, file_id) if file_extension == 'slp': if write_enabled: s = SLP(file_data) out_file_tmp = drsname + ": " + str(file_id) + "." + file_extension if merge_images: png, (width, height), metadata = s.draw_frames_merged(palette) file_write(fname + ".png", png) file_write(fname + '.docx', metadata) dbg(out_file_tmp + " -> saved packed atlas", 1) else: for idx, (png, metadata) in enumerate(s.draw_frames(palette)): filename = fname + '.' + str(idx) file_write(filename + '.png', png.image) file_write(filename + '.docx', metadata) dbg(out_file_tmp + " -> extracting frame %3d...\r" % (idx), 1, end="") dbg(out_file_tmp + " -> saved single frame(s)", 1) elif file_extension == 'wav': if write_enabled: file_write(fname, file_data) use_opus = True if use_opus: #opusenc invokation (TODO: ffmpeg?) opus_convert_call = ['opusenc', fname, fbase + '.opus'] dbg("converting... : " + fname + " to opus.", 1) oc = subprocess.Popen(opus_convert_call, stdout=subprocess.PIPE, stderr=subprocess.PIPE) oc_out, oc_err = oc.communicate() if ifdbg(2): oc_out = oc_out.decode("utf-8") oc_err = oc_err.decode("utf-8") dbg(oc_out + "\n" + oc_err, 2) #remove original wave file remove(fname) else: #this type is unknown or does not require conversion if write_enabled: file_write(fname, file_data) files_extracted += 1 if write_enabled: dbg(str(files_extracted) + " files extracted", 0) if args.listfiles or args.dumpfilelist: #file_list = sorted(file_list) if not args.dumpfilelist: for idx, f in file_list.items(): ret = "%d = [ " % idx for file_name, file_extension in f: ret += "%s/%d.%s, " % (file_name, idx, file_extension) ret += "]" print(ret) else: ret = "#!/usr/bin/python\n\n#auto generated age2tc file list\n\n" import pprint ret += "avail_files = " ret += pprint.pformat(file_list) print(ret)