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);
        }
        public static string Import(
            string filename          //読み込むファイル名
            , uint magic_baseaddress //魔法アニメの書き換えるアドレス
            )
        {
            string basename = Path.GetFileNameWithoutExtension(filename) + "_";
            string basedir  = Path.GetDirectoryName(filename);

            List <byte> frameData = new List <byte>();
            List <ImageUtilOAM.image_data> bgImagesData = new List <ImageUtilOAM.image_data>();

            //変換したアニメの記録
            Dictionary <string, ImageUtilOAM.animedata> animeDic = new Dictionary <string, ImageUtilOAM.animedata>();

            int lineCount = 0;

            string[] lines = File.ReadAllLines(filename);

            uint image_bg_number  = 0;
            uint image_obj_number = 0;

            ImageUtilOAM.ImportOAM oam = new ImageUtilOAM.ImportOAM();
            oam.SetBaseDir(Path.GetDirectoryName(filename));
            oam.SetIsMagicOAM(true);

            BGScaleMode bgScaleMode = BGScaleMode.NO;

            while (lineCount < lines.Length)
            {
                string line = lines[lineCount];
                if (U.IsComment(line) || U.OtherLangLine(line))
                {
                    lineCount++;
                    continue;
                }
                line = U.ClipComment(line);
                if (line == "")
                {
                    lineCount++;
                    continue;
                }
                InputFormRef.DoEvents(null, "Line:" + lineCount);

                if (line[0] == '~')
                {
                    U.append_u32(frameData, 0x80000100);

                    lineCount++;
                    continue;
                }
                if (line[0] == 'C')
                {//85コマンド
                    uint command = U.atoh(line.Substring(1));
                    if ((command & 0xFF) == 0x53)
                    {//スクリプト側で自動拡大命令を入れている場合 ツールは何もしてはいけないので記録する.
                        bgScaleMode = BGScaleMode.SCRIPT_SCALE_MODE;
                    }

                    uint a = (command & 0x00FFFFFF) | 0x85000000;
                    U.append_u32(frameData, a);

                    lineCount++;
                    continue;
                }

                if (line[0] == 'S')
                {//音楽再生
                    uint music = U.atoh(line.Substring(1));
                    uint a     = ((music & 0xFFFF) << 8) | 0x85000048;
                    U.append_u32(frameData, a);

                    lineCount++;
                    continue;
                }

                if (line[0] != 'O' && line[0] != 'B')
                {
                    //不明な命令なので無視する.
                    lineCount++;
                    continue;
                }

                //O objblank.png
                //B bg3.png
                //1
                ImageUtilOAM.animedata objAnimeData = null;
                ImageUtilOAM.animedata bgAnimeData  = null;
                uint frameSec = U.NOT_FOUND;
                for (int n = 1; n <= 3;)
                {
                    line = lines[lineCount];
                    if (U.IsComment(line) || U.OtherLangLine(line))
                    {
                        lineCount++;
                        continue;
                    }
                    line = U.ClipComment(line);
                    if (line == "")
                    {
                        lineCount++;
                        continue;
                    }

                    if (U.isnum(line[0]))
                    {
                        if (frameSec != U.NOT_FOUND)
                        {
                            return(R.Error("時間指定が連続しています。\r\nO filename\r\nB filename\r\ntime\r\n\r\nFile:{0} Line:{1}\r\n", filename, lineCount + 1));
                        }
                        frameSec = U.atoi(line);

                        lineCount++;
                        n++;
                        continue;
                    }


                    string imagefilename = ImageUtilOAM.parsePFilename(line);
                    if (imagefilename.Length <= 0)
                    {
                        return(R.Error("ファイル名が見つかりませんでした。\r\nFile: {0} line:{1}\r\n\r\nエラー内容:\r\n{2}", filename, lineCount, oam.ErrorMessage));
                    }

                    if (line[0] == 'O')
                    {
                        if (objAnimeData != null)
                        {
                            return(R.Error("OBJ指定が連続しています。\r\nO filename\r\nB filename\r\ntime\r\n\r\nFile:{0} Line:{1}\r\n", filename, lineCount + 1));
                        }

                        string errormessage;
                        objAnimeData = ImportObjImageToData(imagefilename
                                                            , basedir
                                                            , animeDic
                                                            , oam
                                                            , ref image_obj_number
                                                            , out errormessage
                                                            );
                        if (objAnimeData == null)
                        {
                            return(R.Error("OBJ画像をロードできません。 \r\n{2}\r\nFile:{0} Line:{1}", filename, lineCount + 1, errormessage));
                        }
                        lineCount++;
                        n++;
                        continue;
                    }
                    if (line[0] == 'B')
                    {
                        if (bgAnimeData != null)
                        {
                            return(R.Error("BG指定が連続しています。\r\nO filename\r\nB filename\r\ntime\r\n\r\nFile:{0} Line:{1}\r\n", filename, lineCount + 1));
                        }

                        string errormessage;
                        bgAnimeData = ImportBGImageToData(imagefilename
                                                          , basedir
                                                          , animeDic
                                                          , bgImagesData
                                                          , out errormessage
                                                          );
                        if (bgAnimeData == null)
                        {
                            return(R.Error("BG画像をロードできません。 \r\n{2}\r\nFile:{0} Line:{1}", filename, lineCount + 1, errormessage));
                        }
                        lineCount++;
                        n++;
                        continue;
                    }
                }
                if (objAnimeData == null)
                {
                    return(R.Error("OBJ画像がありません。 \r\nO filename\r\nB filename\r\ntime\r\n\r\nみたいに、セットで登録する必要があります。\r\nFile:{0} Line:{1}", filename, lineCount + 1));
                }
                if (bgAnimeData == null)
                {
                    return(R.Error(("IMAGE_POINTER or ZIMAGE_POINTER の指定が必要です。BG画像がありません。 \r\nO filename\r\nB filename\r\n"), filename, lineCount + 1));
                }
                if (frameSec == U.NOT_FOUND)
                {
                    return(R.Error("時間指定がありません。 \r\nO filename\r\nB filename\r\ntime\r\n\r\nみたいに、セットで登録する必要があります。\r\nFile:{0} Line:{1}", filename, lineCount + 1));
                }


                //BGがFEditorの小さい形式だった場合、自動的に拡大命令を追加する.
                if (bgAnimeData.height == 64)
                {
                    if (bgScaleMode == BGScaleMode.NO)
                    {//拡大命令を付与.
                        uint a = (0x00000153) | 0x85000000;
                        U.append_u32(frameData, a);

                        bgScaleMode = BGScaleMode.AUTO_SCALE_MODE;
                    }
                }

                //0x86コマンド
                {
                    uint a = (frameSec & 0xFFFF) | ((image_bg_number & 0xFF) << 16) | 0x86000000;
                    U.append_u32(frameData, a);                            //+0
                    U.append_u32(frameData, objAnimeData.image_pointer);   //+4
                    U.append_u32(frameData, objAnimeData.oam_pos);         //+8 OBJ OAM
                    U.append_u32(frameData, objAnimeData.oam2_pos);        //+12 OBJ BG OAM
                    U.append_u32(frameData, bgAnimeData.image_pointer);    //+16
                    U.append_u32(frameData, objAnimeData.palette_pointer); //+20
                    U.append_u32(frameData, bgAnimeData.palette_pointer);  //+24
                    U.append_u32(frameData, bgAnimeData.tsa_pointer);      //+28 TSA
                    image_bg_number++;
                }
            }

            InputFormRef.DoEvents(null, "Term");

            if (bgScaleMode == BGScaleMode.AUTO_SCALE_MODE)
            {//拡大命令を自動付与していた場合、解除する. 解除しないと経験値バーが表示されない.
                uint a = (0x00000053) | 0x85000000;
                U.append_u32(frameData, a);
            }
            //終端.
            U.append_u32(frameData, 0x80000000);
            //登録完了処理
            oam.Term();

            Undo.UndoData undodata = Program.Undo.NewUndoData("import ", Path.GetFileName(filename));

            //上書きされるアニメデータ領域を使いまわす
            List <Address> recycle = new List <Address>();

            RecycleOldAnime(ref recycle, "", false, magic_baseaddress);

            RecycleAddress ra = new RecycleAddress(recycle);

            //書き込みます.(魔法アニメはなぜか無圧縮)
            ra.WriteAndWritePointer(magic_baseaddress + 4, oam.GetRightToLeftOAM(), undodata);
            ra.WriteAndWritePointer(magic_baseaddress + 8, oam.GetLeftToRightOAM(), undodata);

            //BG用にダミーのOAMを作成
            //byte[] dummyOAM = ImageUtilMagicFEditor.MakeDummyOAM(image_bg_number);
            ra.WriteAndWritePointer(magic_baseaddress + 12, oam.GetRightToLeftOAMBG(), undodata);
            ra.WriteAndWritePointer(magic_baseaddress + 16, oam.GetLeftToRightOAMBG(), undodata);

            //BG
            for (int i = 0; i < bgImagesData.Count; i++)
            {
                bgImagesData[i].write_addr = ra.Write(bgImagesData[i].data, undodata);
            }
            //OBJ
            List <ImageUtilOAM.image_data> objImages = oam.GetImages();

            for (int i = 0; i < objImages.Count; i++)
            {
                objImages[i].write_addr = ra.Write(objImages[i].data, undodata);
            }

            //画像の書き込みアドレスが決定したら、画像ポインタをかかないといけないFrameDataを更新します。
            byte[] frameDataUZ = frameData.ToArray();
            string errorFrame  = updateFrameDataAddress(frameDataUZ, bgImagesData, objImages);

            if (errorFrame != "")
            {
                return(R.Error("OAMフレーム更新中にエラーが発生しました。\r\nこのエラーが頻繁に出る場合は、アニメデータと一緒にreport7zを送ってください。") + "\r\n" + errorFrame);
            }
            ra.WriteAndWritePointer(magic_baseaddress + 0, frameDataUZ, undodata);

            //端数の再利用的ない古いデータは0x00クリア.
            ra.BlackOut(undodata);

            Program.Undo.Push(undodata);
            return("");
        }
        public static bool ImportBorder(Form self, uint origin_x, uint origin_y, out byte[] out_image, out byte[] out_oam)
        {
            out_image = null;
            out_oam   = null;
            string imagefilename = ImageFormRef.OpenFilenameDialogFullColor(self);

            if (imagefilename == "")
            {
                R.ShowStopError("ファイルがありません。\r\nファイル名:{0}", imagefilename);
                return(false);
            }
            string name_filename = MakeBorderNameImageFileName(imagefilename);

            if (!File.Exists(name_filename))
            {
                R.ShowStopError("ファイルがありません。\r\nファイル名:{0}", name_filename);
                return(false);
            }
            string basedir = Path.GetDirectoryName(imagefilename);

            List <uint> battleOAMSplit = new List <uint>();

            ImageUtilOAM.ImportOAM oam = new ImageUtilOAM.ImportOAM();
            oam.SetIsBorderAPOAM(true);
            oam.SetBaseDir(basedir);
            oam.MakeBorderAP(imagefilename);
            battleOAMSplit.Add(oam.GetOAMByteCount());
            oam.MakeBorderAP(name_filename);
            oam.Term();
            battleOAMSplit.Add(oam.GetOAMByteCount());

            List <ImageUtilOAM.image_data> images = oam.GetImages();

            if (images.Count >= 2)
            {
                R.ShowStopError("画像が大きすぎて、256x160のシートに入りきりませんでした");
                return(false);
            }

            byte[] battleOAM = oam.GetRightToLeftOAM();

            List <uint> apOAMSplit = new List <uint>();

            byte[] apOAM = BattleOAMToAPOAM(battleOAM, battleOAMSplit, origin_x, origin_y, apOAMSplit);
            if (apOAM == null)
            {
                return(false);
            }

            List <byte> newOam = new List <byte>();

            //ap_data header
            U.append_u16(newOam, 4); //ap_data header SHORT (frame_list - ap_data)
            U.append_u16(newOam, 8); //ap_data header SHORT (anim_list - ap_data)
            //frame_list
            uint addr_frame_list = (uint)newOam.Count;

            U.append_u16(newOam, 0); //SHORT (frame_0 - frame_list)
            U.append_u16(newOam, 0); //SHORT (frame_1 - frame_list)
            //anim_list
            uint addr_anim_list = (uint)newOam.Count;

            U.append_u16(newOam, 0); //SHORT (anim_0 - anim_list)
            U.append_u16(newOam, 0); //SHORT (anim_1 - anim_list)
            //frame_0
            uint addr_frame_0 = (uint)newOam.Count;

            U.append_u16(newOam, apOAMSplit[0] / 6); // oam entries
            for (uint i = 0; i < apOAMSplit[0]; i++)
            {
                U.append_u8(newOam, apOAM[i]);  // oam entries
            }
            //frame_1
            uint addr_frame_1 = (uint)newOam.Count;

            U.append_u16(newOam, (apOAMSplit[1] - apOAMSplit[0]) / 6); // oam entries
            for (uint i = apOAMSplit[0]; i < apOAMSplit[1]; i++)
            {
                U.append_u8(newOam, apOAM[i]); // oam entries
            }
            //anim_0:
            uint addr_anim_0 = (uint)newOam.Count;

            U.append_u16(newOam, 4); U.append_u16(newOam, 0);
            U.append_u16(newOam, 0);  U.append_u16(newOam, 0xffff);// loop back to start
            //anim_1:
            uint addr_anim_1 = (uint)newOam.Count;

            U.append_u16(newOam, 4); U.append_u16(newOam, 1);
            U.append_u16(newOam, 0); U.append_u16(newOam, 0xffff);// loop back to start

            out_oam = newOam.ToArray();
            //フレームの位置を書き込む
            U.write_u16(out_oam, 4, addr_frame_0 - addr_frame_list); //SHORT  (frame_0 - frame_list)
            U.write_u16(out_oam, 6, addr_frame_1 - addr_frame_list); //SHORT  (frame_1 - frame_list)
            U.write_u16(out_oam, 8, addr_anim_0 - addr_anim_list);   //SHORT  (anim_0 - anim_list)
            U.write_u16(out_oam, 10, addr_anim_1 - addr_anim_list);  //SHORT (anim_1 - anim_list)

            out_image = LZ77.decompress(images[0].data, 0);
            return(true);
        }