static ImageUtilOAM.animedata ImportObjImageToData(string imagefilename
                                                           , string basedir
                                                           , Dictionary <string, ImageUtilOAM.animedata> animeDic
                                                           , ImageUtilOAM.ImportOAM oam
                                                           , ref uint image_number
                                                           , out string errormessage
                                                           )
        {
            string key = "OBJ" + imagefilename;

            ImageUtilOAM.animedata magic_animedata;
            if (animeDic.ContainsKey(key))
            {
                errormessage = "";

                magic_animedata = animeDic[key];
                return(magic_animedata);
            }
            string hash = ImageUtil.HashBitmap(imagefilename, basedir);

            magic_animedata = ImageUtilOAM.FindHash(hash, animeDic);
            if (magic_animedata != null)
            {
                errormessage = "";
                return(magic_animedata);
            }


            Bitmap loadbitmap = ImageUtil.OpenBitmap(ImageUtilMagicFEditor.GetFullPath(imagefilename, basedir), null, out errormessage);

            if (loadbitmap == null)
            {
                return(null);
            }

            int width  = ImageUtilMagicFEditor.SRC_OBJ_SEAT_TILE_WIDTH * 8 - 16;
            int height = ImageUtilMagicFEditor.SRC_OBJ_SEAT_TILE_HEIGHT * 8;

            if (loadbitmap.Width < width || loadbitmap.Height < height)
            {
                errormessage = R.Error("画像サイズが正しくありません。\r\nWidth:{2} Height:{3} でなければなりません。\r\n\r\n選択された画像のサイズ Width:{0} Height:{1}", loadbitmap.Width, loadbitmap.Height, width, height, imagefilename);
                loadbitmap.Dispose();
                return(null);
            }

            magic_animedata = oam.MakeMagicAnime(imagefilename);
            if (magic_animedata == null)
            {
                errormessage = oam.ErrorMessage;
                loadbitmap.Dispose();
                return(null);
            }
            magic_animedata.image_number = image_number++;
            magic_animedata.imageHash    = hash;

            animeDic[key] = magic_animedata;
            errormessage  = "";
            loadbitmap.Dispose();
            return(magic_animedata);
        }
        private void X_N_JumpEditor_Click(object sender, EventArgs e)
        {
            if (InputFormRef.IsPleaseWaitDialog(this))
            {//2重割り込み禁止
                return;
            }

            uint ID = (uint)AddressList.SelectedIndex + 1;

            string filehint = this.AddressList.Text;

            //少し時間がかかるので、しばらくお待ちください表示.
            using (InputFormRef.AutoPleaseWait pleaseWait = new InputFormRef.AutoPleaseWait(this))
                //テンポラリディレクトリを利用する
                using (U.MakeTempDirectory tempdir = new U.MakeTempDirectory())
                {
                    string filename = Path.Combine(tempdir.Dir, "anime.txt");
                    ImageUtilMagicFEditor.Export(false, filename, (uint)P0.Value, (uint)P4.Value, (uint)P12.Value);
                    if (!File.Exists(filename))
                    {
                        R.ShowStopError("アニメーションエディタを表示するために、アニメーションをエクスポートしようとしましたが、アニメをファイルにエクスポートできませんでした。\r\n\r\nファイル:{0}", filename);
                        return;
                    }

                    ToolAnimationCreatorForm f = (ToolAnimationCreatorForm)InputFormRef.JumpFormLow <ToolAnimationCreatorForm>();
                    f.Init(ToolAnimationCreatorUserControl.AnimationTypeEnum.MagicAnime_FEEDitor
                           , ID, filehint, filename);
                    f.Show();
                }
        }
        public ImageMagicFEditorForm()
        {
            InitializeComponent();
            U.SetIcon(MagicAnimeExportButton, Properties.Resources.icon_arrow);
            U.SetIcon(MagicAnimeImportButton, Properties.Resources.icon_upload);

            if (ImageUtilMagic.SearchMagicSystem(out MagicEngineBaseAddr, out DimAddr, out NoDimAddr) != ImageUtilMagic.magic_system_enum.FEDITOR_ADV)
            {
                Debug.Assert(false);
                return;
            }

            InputFormRef.markupJumpLabel(LinkInternt);

            U.SelectedIndexSafety(ShowZoomComboBox, 0);
            Dictionary <uint, string> effectDic = U.LoadDicResource(U.ConfigDataFilename("item_anime_effect_"));
            uint spellDataCount = ImageUtilMagicFEditor.SpellDataCount();
            uint csaSpellTablePointer;
            uint csaSpellTable = ImageUtilMagic.FindCSASpellTable("FEditor", out csaSpellTablePointer);

            if (csaSpellTable == U.NOT_FOUND)
            {
                R.ShowWarning("魔法リストの拡張がされていません。\r\nリストの拡張を選択して、魔法リストを増やしてください。");
            }

            this.InputFormRef = Init(this, DimAddr, NoDimAddr, spellDataCount, csaSpellTable, effectDic);
            this.InputFormRef.MakeGeneralAddressListContextMenu(true);
            this.InputFormRef.IsMemoryNotContinuous = true; //メモリは連続していないので、警告不能.
            if (this.InputFormRef.DataCount > Program.ROM.RomInfo.magic_effect_original_data_count())
            {                                               //拡張済みなので、拡張ボタンを無効にする
                MagicListExpandsButton.Enabled = false;
            }
        }
        void DrawSelectedAnime()
        {
            string log;

            X_B_ANIME_PIC2.Image = ImageUtilMagicFEditor.Draw((uint)ShowFrameUpDown.Value, (uint)P0.Value, (uint)P4.Value, (uint)P12.Value, out log);
            BinInfo.Text         = log;
        }
        //全データの取得
        public static void MakeAllDataLength(List <Address> list, bool isPointerOnly)
        {
            string       name;
            InputFormRef InputFormRef;
            uint         baseaddr, dimaddr, no_dimaddr;

            if (ImageUtilMagic.SearchMagicSystem(out baseaddr, out dimaddr, out no_dimaddr) != ImageUtilMagic.magic_system_enum.CSA_CREATOR)
            {
                return;
            }

            {
                uint spellDataCount = ImageUtilMagicFEditor.SpellDataCount();
                uint csaSpellTable  = ImageUtilMagic.GetCSASpellTableAddr();
                if (csaSpellTable == U.NOT_FOUND)
                {
                    return;
                }
                uint csaSpellTablePointer = ImageUtilMagic.GetCSASpellTablePointer();

                Dictionary <uint, string> effectDic = new Dictionary <uint, string>();
                InputFormRef = Init(null, dimaddr, no_dimaddr, spellDataCount, csaSpellTable, effectDic);

                name = "Magic";
                FEBuilderGBA.Address.AddAddress(list
                                                , InputFormRef
                                                , name, new uint[] { 0 }
                                                );

                //追加魔法テーブル(結構無駄な構造ですが、仕方ない)
                FEBuilderGBA.Address.AddAddress(list
                                                , csaSpellTable
                                                , InputFormRef.DataCount * 4 * 5
                                                , csaSpellTablePointer
                                                , "Magic_Append_SpellTable"
                                                , FEBuilderGBA.Address.DataTypeEnum.MAGIC_APPEND_SPELLTABLE
                                                );

                uint addr = InputFormRef.BaseAddress;
                for (int i = 0; i < InputFormRef.DataCount; i++, addr += InputFormRef.BlockSize)
                {
                    uint baseaddress = Program.ROM.p32(Program.ROM.RomInfo.magic_effect_pointer);
                    uint csaaddress  = (uint)(csaSpellTable + (20 * i));

                    uint dataaddr = Program.ROM.p32(addr);
                    if (dataaddr == 0)
                    {
                        continue;
                    }
                    if (
                        dataaddr == dimaddr ||
                        dataaddr == no_dimaddr)
                    {
                        name = "Magic:" + U.To0xHexString(i);
                        ImageUtilMagicCSACreator.RecycleOldAnime(ref list, name, isPointerOnly, csaaddress);
                    }
                }
            }
        }
        private void MagicAnimeExportButton_Click(object sender, EventArgs e)
        {
            string title  = R._("保存するファイル名を選択してください");
            string filter = R._("魔法アニメ コメントあり|*.txt|魔法アニメ コメントなし|*.txt|アニメGIF|*.gif|Dump All|*.txt|All files|*");

            SaveFileDialog save = new SaveFileDialog();

            save.Title        = title;
            save.Filter       = filter;
            save.AddExtension = true;
            Program.LastSelectedFilename.Load(this, "", save, "magic_" + this.AddressList.Text.Trim());

            DialogResult dr = save.ShowDialog();

            if (dr != DialogResult.OK)
            {
                return;
            }
            if (save.FileNames.Length <= 0 || !U.CanWriteFileRetry(save.FileNames[0]))
            {
                return;
            }
            string filename = save.FileNames[0];

            Program.LastSelectedFilename.Save(this, "", save);

            if (save.FilterIndex == 2)
            {//コメントなし
                bool enableComment = false;
                ImageUtilMagicFEditor.Export(enableComment, filename, (uint)P0.Value, (uint)P4.Value, (uint)P12.Value);
            }
            else if (save.FilterIndex == 3)
            {//GIF
                ImageUtilMagicFEditor.ExportGif(filename, (uint)P0.Value, (uint)P4.Value, (uint)P12.Value);
            }
            else if (save.FilterIndex == 4)
            {//All
                bool enableComment = false;
                ImageUtilMagicFEditor.Export(enableComment, filename, (uint)P0.Value, (uint)P4.Value, (uint)P12.Value);
                filename = U.ChangeExtFilename(filename, ".gif");
                ImageUtilMagicFEditor.ExportGif(filename, (uint)P0.Value, (uint)P4.Value, (uint)P12.Value);
            }
            else
            {//コメントあり
                bool enableComment = true;
                ImageUtilMagicFEditor.Export(enableComment, filename, (uint)P0.Value, (uint)P4.Value, (uint)P12.Value);
            }

            //エクスプローラで選択しよう
            U.SelectFileByExplorer(filename);
        }
        //エラーチェック
        public static void MakeCheckError(List <FELint.ErrorSt> errors)
        {
            string       name;
            InputFormRef InputFormRef;
            uint         baseaddr, dimaddr, no_dimaddr;

            if (ImageUtilMagic.SearchMagicSystem(out baseaddr, out dimaddr, out no_dimaddr) != ImageUtilMagic.magic_system_enum.FEDITOR_ADV)
            {
                return;
            }

            {
                uint spellDataCount = ImageUtilMagicFEditor.SpellDataCount();
                uint csaSpellTablePointer;
                uint csaSpellTable = ImageUtilMagic.FindCSASpellTable("FEditor", out csaSpellTablePointer);
                if (csaSpellTable == U.NOT_FOUND)
                {
                    return;
                }
                Dictionary <uint, string> effectDic = new Dictionary <uint, string>();
                InputFormRef = Init(null, dimaddr, no_dimaddr, spellDataCount, csaSpellTable, effectDic);

                uint addr = InputFormRef.BaseAddress;
                for (int i = 0; i < InputFormRef.DataCount; i++, addr += InputFormRef.BlockSize)
                {
                    uint baseaddress = Program.ROM.p32(Program.ROM.RomInfo.magic_effect_pointer());
                    uint csaaddress  = (uint)(csaSpellTable + (20 * i));

                    uint dataaddr = Program.ROM.p32(addr);
                    if (dataaddr == 0)
                    {
                        continue;
                    }

                    if (U.isSafetyOffset(dataaddr))
                    {
                    }

                    if (
                        dataaddr == dimaddr ||
                        dataaddr == no_dimaddr)
                    {
                        name = "Magic:" + U.To0xHexString(i);

                        ImageUtilMagicFEditor.MakeCheckError(ref errors, name, csaaddress, (uint)i);
                    }
                }
            }
        }
        //変更するアニメデータから、他のアニメーションでも使っているものを除外する
        public static void SubConfilctArea(RecycleAddress ra, uint Now_baseaddress)
        {
            InputFormRef InputFormRef;
            uint         baseaddr, dimaddr, no_dimaddr;

            if (ImageUtilMagic.SearchMagicSystem(out baseaddr, out dimaddr, out no_dimaddr) != ImageUtilMagic.magic_system_enum.FEDITOR_ADV)
            {
                return;
            }

            {
                uint spellDataCount = ImageUtilMagicFEditor.SpellDataCount();
                uint csaSpellTable  = ImageUtilMagic.GetCSASpellTableAddr();
                if (csaSpellTable == U.NOT_FOUND)
                {
                    return;
                }
                Dictionary <uint, string> effectDic = new Dictionary <uint, string>();
                InputFormRef = Init(null, dimaddr, no_dimaddr, spellDataCount, csaSpellTable, effectDic);

                uint addr = InputFormRef.BaseAddress;
                for (int i = 0; i < InputFormRef.DataCount; i++, addr += InputFormRef.BlockSize)
                {
                    uint baseaddress = Program.ROM.p32(Program.ROM.RomInfo.magic_effect_pointer);
                    uint csaaddress  = (uint)(csaSpellTable + (20 * i));

                    uint dataaddr = Program.ROM.p32(addr);
                    if (dataaddr == 0)
                    {
                        continue;
                    }
                    if (csaaddress == Now_baseaddress)
                    {
                        continue;
                    }

                    if (
                        dataaddr == dimaddr ||
                        dataaddr == no_dimaddr)
                    {
                        List <Address> list = new List <Address>();
                        ImageUtilMagicFEditor.RecycleOldAnime(ref list, "", false, csaaddress);
                        ra.SubRecycle(list);
                    }
                }
            }
        }
        public string MagicAnimeImportDirect(uint id, string filename)
        {
            if (InputFormRef.IsPleaseWaitDialog(this))
            {//2重割り込み禁止
                return(R._("現在他の処理中です"));
            }

            if (id <= 0)
            {
                return(R._("指定されたID({0})は存在しません。", U.To0xHexString(id)));
            }

            uint magic_baseaddress = InputFormRef.SelectToAddr(AddressList, (int)id - 1);

            if (magic_baseaddress == U.NOT_FOUND)
            {
                return(R._("指定されたID({0})は存在しません。", U.To0xHexString(id)));
            }

            string error = "";

            //少し時間がかかるので、しばらくお待ちください表示.
            using (InputFormRef.AutoPleaseWait pleaseWait = new InputFormRef.AutoPleaseWait(this))
            {
                string ext = U.GetFilenameExt(filename);
                error = ImageUtilMagicFEditor.Import(filename, magic_baseaddress);
            }

            if (error != "")
            {
                return(error);
            }

            if (DimComboBox.SelectedIndex >= 2)
            {//EMPTYになっている場合は、dim_pcを選択.
                DimComboBox.SelectedIndex = 0;
                WriteDim();
            }

            U.ReSelectList(AddressList);
            InputFormRef.ShowWriteNotifyAnimation(this, magic_baseaddress);

            return("");
        }
        public static Dictionary <uint, string> MakeItemEffectAndAppendMagic(Form from)
        {
            InputFormRef InputFormRef;
            Dictionary <uint, string> effectDic = U.LoadDicResource(U.ConfigDataFilename("item_anime_effect_"));

            uint baseaddr, dimaddr, no_dimaddr;

            if (ImageUtilMagic.SearchMagicSystem(out baseaddr, out dimaddr, out no_dimaddr) != ImageUtilMagic.magic_system_enum.FEDITOR_ADV)
            {
                return(effectDic);
            }

            uint spellDataCount = ImageUtilMagicFEditor.SpellDataCount();
            uint csaSpellTable  = ImageUtilMagic.GetCSASpellTableAddr();

            if (csaSpellTable == U.NOT_FOUND)
            {
                return(effectDic);
            }

            InputFormRef = Init(from, dimaddr, no_dimaddr, spellDataCount, csaSpellTable, effectDic);
            List <U.AddrResult> ret = InputFormRef.MakeList();

            for (int i = 0; i < ret.Count; i++)
            {
                U.AddrResult ar = ret[i];
                if (ar.name.IndexOf(" EMPTY") >= 0)
                {
                    continue;
                }

                //処理効率最悪なのだが、 テキストの先頭に16進数でIDが入っている
                uint   no         = U.atoh(ar.name);
                string effectname = R._("追加魔法");
                if (Program.CommentCache.CheckFast(ar.addr))
                {
                    effectname = " " + Program.CommentCache.At(ar.addr);
                }

                effectDic[no] = effectname;
            }

            return(effectDic);
        }
        private void MagicListExpandsButton_Click(object sender, EventArgs e)
        {
            DialogResult dr = R.ShowYesNo("魔法テーブルを拡張してもよろしいですか?");

            if (dr != System.Windows.Forms.DialogResult.Yes)
            {
                return;
            }

            Undo.UndoData undodata = Program.Undo.NewUndoData(this, "expands");

            uint csaSpellTablePointer = ImageUtilMagic.GetCSASpellTablePointer();

            if (csaSpellTablePointer == U.NOT_FOUND)
            {
                R.ShowStopError("CSASpellTable Not Found.");
                return;
            }

            //魔法エフェクトテーブルの拡張.
            uint spellDataCount = ImageUtilMagicFEditor.SpellDataCount();
            uint datasize       = spellDataCount;

            InputFormRef.ExpandsArea(this, 254, Program.ROM.RomInfo.magic_effect_pointer, datasize, FEBuilderGBA.InputFormRef.ExpandsFillOption.NO, 4, undodata);

            //CSA追加魔法テーブルの拡張
            if (U.isSafetyOffset(csaSpellTablePointer) && InputFormRef != null)
            {//CSA追加魔法テーブルが正しくセットされている場合
                datasize = InputFormRef.DataCount;
            }
            else
            {//セットされていなければ初期値は0
                datasize = 0;
            }

            uint csaSpellTable = InputFormRef.ExpandsArea(this, 254, csaSpellTablePointer, datasize, FEBuilderGBA.InputFormRef.ExpandsFillOption.NO, 5 * 4, undodata);

            Program.Undo.Push(undodata);

            //開きなおす.
            InputFormRef.ReOpenForm <ImageMagicCSACreatorForm>();
        }
 void DrawSelectedAnime()
 {
     X_B_ANIME_PIC2.Image = ImageUtilMagicFEditor.Draw((uint)ShowFrameUpDown.Value, (uint)P0.Value, (uint)P4.Value, (uint)P12.Value);
 }
        //上書きされるアニメデータ領域を使いまわす
        public static void RecycleOldAnime(ref List <Address> recycle, string basename, bool isPointerOnly, uint magic_baseaddress)
        {
            uint frameData_offset        = Program.ROM.p32(magic_baseaddress + 0);  //
            uint RightToLeftOAM_offset   = Program.ROM.u32(magic_baseaddress + 4);  //OBJ OAM
            uint LeftToRightOAM_offset   = Program.ROM.u32(magic_baseaddress + 8);  //OBJ OAM
            uint RightToLeftOAMBG_offset = Program.ROM.u32(magic_baseaddress + 12); //OBJ BG OAM
            uint LeftRightOAMBG_offset   = Program.ROM.u32(magic_baseaddress + 16); //OBJ BG OAM

            if (frameData_offset == 0)
            {
                return;
            }

            //圧縮されていないデータなので、事故防止のため リミッターをかける.
            uint limitter = frameData_offset + 1024 * 1024; //1MBサーチしたらもうあきらめる.

            limitter = (uint)Math.Min(limitter, Program.ROM.Data.Length);

            //最大OAM数を求める.
            uint maxObjOAM = 0;
            uint maxBGOAM  = 0;

            byte[] frameData = Program.ROM.Data;
            uint   i;

            for (i = frameData_offset; i < limitter; i += 4)
            {
                if (frameData[i + 3] == 0x80)
                {                                 //終端データ
                    if (frameData[i + 1] == 0x01) //0x00 0x01 0x00 0x80 の場合続くときがある.
                    {
                        continue;
                    }
                    i += 4;
                    break;
                }
                if (frameData[i + 3] != 0x86)
                {
                    if (frameData[i + 3] == 0x85)
                    {
                        continue;
                    }
                    //不明な命令.
                    break;
                }
                //OBJ画像をリサイクルリストに突っ込む.
                FEBuilderGBA.Address.AddLZ77Pointer(recycle
                                                    , (uint)(i + 4)
                                                    , basename + "OBJ"
                                                    , isPointerOnly
                                                    , Address.DataTypeEnum.LZ77IMG);

                //BG画像をリサイクルリストに突っ込む.
                FEBuilderGBA.Address.AddLZ77Pointer(recycle
                                                    , (uint)(i + 16)
                                                    , basename + "BG"
                                                    , isPointerOnly
                                                    , Address.DataTypeEnum.LZ77IMG);

                //OBJパレットをリサイクルリストに突っ込む.
                FEBuilderGBA.Address.AddPointer(recycle
                                                , (uint)(i + 20)
                                                , 0x20 //16色*2バイト=0x20バイト
                                                , basename + "OBJ PAL"
                                                , Address.DataTypeEnum.PAL);

                //BGパレットをリサイクルリストに突っ込む.
                FEBuilderGBA.Address.AddPointer(recycle
                                                , (uint)(i + 24)
                                                , 0x20 //16色*2バイト=0x20バイト
                                                , basename + "BG PAL"
                                                , Address.DataTypeEnum.PAL);

                //BG TSAをリサイクルリストに突っ込む.
                FEBuilderGBA.Address.AddLZ77Pointer(recycle
                                                    , (uint)(i + 28)
                                                    , basename + "TSA"
                                                    , isPointerOnly
                                                    , Address.DataTypeEnum.LZ77TSA);

                //最大OAMを求める.
                uint objOAM = U.u32(frameData, (uint)(i + 8));
                uint bgOAM  = U.u32(frameData, (uint)(i + 12));
                if (objOAM > maxObjOAM)
                {
                    maxObjOAM = objOAM;
                }
                if (bgOAM > maxBGOAM)
                {
                    maxBGOAM = bgOAM;
                }

                i += 24 + 4; // 24+4+4 = 32bytes
            }

            if (i > limitter)
            {//リミッターを超えているので、危険なので、フレーム等の再利用はしない
            }
            else
            {
                FEBuilderGBA.Address.AddPointer(recycle
                                                , magic_baseaddress + 0
                                                , i - frameData_offset
                                                , basename + "FRAME"
                                                , Address.DataTypeEnum.MAGICFRAME_CSA);

                FEBuilderGBA.Address.AddPointer(recycle
                                                , magic_baseaddress + 4
                                                , ImageUtilMagicFEditor.calcOAMLength(RightToLeftOAM_offset, maxObjOAM)
                                                , basename + "RihtToLeftOAM"
                                                , Address.DataTypeEnum.MAGICOAM);

                FEBuilderGBA.Address.AddPointer(recycle
                                                , magic_baseaddress + 8
                                                , ImageUtilMagicFEditor.calcOAMLength(LeftToRightOAM_offset, maxObjOAM)
                                                , basename + "LeftRightOAM"
                                                , Address.DataTypeEnum.MAGICOAM);

                FEBuilderGBA.Address.AddPointer(recycle
                                                , magic_baseaddress + 12
                                                , ImageUtilMagicFEditor.calcOAMLength(RightToLeftOAMBG_offset, maxBGOAM)
                                                , basename + "RihtToLeftOAMBG"
                                                , Address.DataTypeEnum.MAGICOAM);

                FEBuilderGBA.Address.AddPointer(recycle
                                                , magic_baseaddress + 16
                                                , ImageUtilMagicFEditor.calcOAMLength(LeftRightOAMBG_offset, maxBGOAM)
                                                , basename + "LeftRightOAMBG"
                                                , Address.DataTypeEnum.MAGICOAM);
            }
        }
        public static void Export(
            bool enableComment  //コメントを出すかどうか
            , string filename   //書き込むファイル名
            , uint frame
            , uint objRightToLeftOAM
            , uint objBGRightToLeftOAM
            )
        {
            objRightToLeftOAM   = U.toOffset(objRightToLeftOAM);
            objBGRightToLeftOAM = U.toOffset(objBGRightToLeftOAM);

            string basename = Path.GetFileNameWithoutExtension(filename) + "_";
            string basedir  = Path.GetDirectoryName(filename);

            //読みやすいようにコメントを入れます.
            Dictionary <uint, string> Comment_85command_Dic = U.LoadDicResource(U.ConfigDataFilename("battleanime_85command_"));

            U.MapMarge(ref Comment_85command_Dic, U.LoadDicResource(U.ConfigDataFilename("magic_command_")));

            List <String> lines = new List <String>();
            string        line;

            if (enableComment)
            {
                lines.Add("#######################################################");
                lines.Add("#");
                lines.Add("#" + R._("CSA_Creatorにインポートする時には各行の#以降を削除してください。"));
                lines.Add("#######################################################");
            }
            //同じアニメを何度も出力しないように記録する.
            List <uint> animeHash = new List <uint>();

            frame = U.toOffset(frame);
            byte[] frameData = Program.ROM.Data;

            //圧縮されていないデータなので、事故防止のため リミッターをかける.
            uint limitter = frame + 1024 * 1024; //1MBサーチしたらもうあきらめる.

            limitter = (uint)Math.Min(limitter, Program.ROM.Data.Length);

            int termCount = 0;

            for (uint n = frame; n < limitter; n += 4)
            {
                if (frameData[n + 3] == 0x80)     //0x80 Term
                {                                 //終端.
                    termCount++;
                    if (frameData[n + 1] == 0x01) //0x00 0x01 0x00 0x80 の場合続くときがある.
                    {
                        line = "~";
                        if (termCount == 1)
                        {
                            if (enableComment)
                            {
                                line += "                               #miss terminator";
                            }
                            lines.Add(line);
                            continue;
                        }
                        else
                        {
                            if (enableComment)
                            {
                                line += "                               #terminator";
                            }
                            lines.Add(line);
                        }
                    }
                    break;
                }
                else if (frameData[n + 3] == 0x85) //0x85 コマンド
                {
                    if (frameData[n] == 0x48)
                    {//音楽再生なのだが魔法ではS命令不可.
                        uint musicid = U.u16(frameData, n + 1);
                        uint id      = U.u24(frameData, n);
                        line = "C" + id.ToString("X06");
                        if (enableComment)
                        {
                            line += "                               #Sound " + musicid + " " + SongTableForm.GetSongName(musicid);
                        }
                        lines.Add(line);
                    }
                    else
                    {//それ以外の 0x85命令
                        uint id = U.u24(frameData, n);
                        line = "C" + id.ToString("X06");
                        if (enableComment)
                        {
                            line += "                               #" + U.at(Comment_85command_Dic, frameData[n]);
                        }
                        lines.Add(line);
                    }
                    continue;
                }
                else if (frameData[n + 3] != 0x86)
                {//不明な命令なので終了
                    break;
                }

                //0x86 画像 pointer
                uint wait = U.u16(frameData, n);

                //OBJの出力
                string obj_framefilename = ImageUtilMagicFEditor.ExportOBjFrameImage(
                    n
                    , frameData
                    , objRightToLeftOAM
                    , objBGRightToLeftOAM
                    , basedir
                    , basename
                    , animeHash
                    );

                //BGの出力
                string bg_framefilename = ExportBGFrameImage(n, frameData
                                                             , basedir
                                                             , basename
                                                             , animeHash
                                                             );
                if (obj_framefilename == "")
                {
                    Log.Error("borken obj frame", n.ToString());
                    obj_framefilename = ImageUtil.SaveDummyImage(basedir, basename + "_broken_obj" + n + ".png"
                                                                 , 480, 160);
                }
                if (bg_framefilename == "")
                {
                    Log.Error("borken bg frame", n.ToString());
                    bg_framefilename = ImageUtil.SaveDummyImage(basedir, basename + "_broken_bg" + n + ".png"
                                                                , 264, 160);
                }

                line = "O " + obj_framefilename;
                lines.Add(line);
                line = "B " + bg_framefilename;
                lines.Add(line);

                //表示時間の出力.
                line = wait.ToString();
                lines.Add(line);

                n += 24 + 4; // 24+4+4 = 32bytes

                lines.Add("");
            }

            line = "/// - End of animation";
            lines.Add(line);

            //まとめて書き込み
            File.WriteAllLines(filename, lines);
        }
        static ImageUtilOAM.animedata ImportBGImageToData(string imagefilename
                                                          , string basedir
                                                          , Dictionary <string, ImageUtilOAM.animedata> animeDic
                                                          , List <ImageUtilOAM.image_data> imagesData
                                                          , out string errormessage
                                                          )
        {
            string key = "BG" + imagefilename;

            ImageUtilOAM.animedata magic_animedata;
            if (animeDic.ContainsKey(key))
            {
                errormessage    = "";
                magic_animedata = animeDic[key];
                return(magic_animedata);
            }

            string hash = ImageUtil.HashBitmap(imagefilename, basedir);

            magic_animedata = ImageUtilOAM.FindHash(hash, animeDic);
            if (magic_animedata != null)
            {
                errormessage = "";
                return(magic_animedata);
            }

            magic_animedata = new ImageUtilOAM.animedata();
            string bgfilename = ImageUtilMagicFEditor.GetFullPath(imagefilename, basedir);
            Bitmap loadbitmap = ImageUtil.OpenBitmap(bgfilename, null, out errormessage);

            if (loadbitmap == null)
            {
                return(null);
            }

//            int width = ImageUtilMagicFEditor.SRC_BG_SEAT_TILE_WIDTH * 8;
//            int height = ImageUtilMagicFEditor.SRC_BG_SEAT_TILE_HEIGHT * 8;
            int width  = 240;
            int height = 160;

            if (loadbitmap.Width < width || loadbitmap.Height < height)
            {
                if ((loadbitmap.Width >= 240 && loadbitmap.Width <= 264) &&
                    (loadbitmap.Height >= 64 && loadbitmap.Height < 160))
                {
                    height = 64;
                    //FEditor Magic
                    Log.Notify("これはFEditorの小さいBG形式です。");
                }
                else if ((loadbitmap.Width >= 240 && loadbitmap.Width <= 264) &&
                         loadbitmap.Height == 160)
                {//CSA Creator
                }
                else
                {
                    errormessage = R.Error("画像サイズが正しくありません。\r\n{4}\r\nWidth:{2} Height:{3} でなければなりません。\r\n\r\n選択された画像のサイズ Width:{0} Height:{1}", loadbitmap.Width, loadbitmap.Height, width, height, imagefilename);
                    loadbitmap.Dispose();
                    return(null);
                }
            }

            Bitmap savebitmap = ImageUtil.Copy(loadbitmap, 0, 0, width, height);

            byte[] image; //画像
            byte[] tsa;   //TSA
            string error_string = ImageUtil.ImageToBytePackedTSA(savebitmap, savebitmap.Width, savebitmap.Height, 0, out image, out tsa);

            if (error_string != "")
            {
                errormessage = error_string;
                loadbitmap.Dispose();
                return(null);
            }

            //画像の高さを記録. BGは、FEditor=64   Scale Creator=160 と、違う.
            magic_animedata.height = height;
            //ハッシュ値
            magic_animedata.imageHash = hash;

            //画像
            magic_animedata.image_pointer = (uint)imagesData.Count;
            ImageUtilOAM.image_data image_data = new ImageUtilOAM.image_data();
            image_data.data = image;
            image_data.data = LZ77.compress(image_data.data);
            imagesData.Add(image_data);

            //パレット
            magic_animedata.palette_pointer = (uint)imagesData.Count;
            ImageUtilOAM.image_data palette_data = new ImageUtilOAM.image_data();
            palette_data.data = ImageUtil.ImageToPalette(savebitmap);
            imagesData.Add(palette_data);

            //TSA
            magic_animedata.tsa_pointer = (uint)imagesData.Count;
            ImageUtilOAM.image_data tsa_data = new ImageUtilOAM.image_data();
            tsa_data.data = tsa;
            tsa_data.data = LZ77.compress(tsa_data.data);
            imagesData.Add(tsa_data);


            animeDic[key] = magic_animedata;
            errormessage  = "";
            loadbitmap.Dispose();
            return(magic_animedata);
        }