// spconvDlg.cpp : インプリメンテーション ファイル
//

#include "stdafx.h"
#include "cfbmp.h"
#include "stdio.h"
#include "stdlib.h"
#include "spconv.h"
#include "spconvDlg.h"
#include "DirSelectDialog.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// アプリケーションのバージョン情報で使われている CAboutDlg ダイアログ

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

	// ダイアログ データ
		//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard は仮想関数を生成しオーバーライドします
	//{{AFX_VIRTUAL(CAboutDlg)
protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV のサポート
	//}}AFX_VIRTUAL

// インプリメンテーション
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// メッセージ ハンドラがありません。
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSpconvDlg ダイアログ

CSpconvDlg::CSpconvDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CSpconvDlg::IDD, pParent)
	, m_spReadTo(_T(""))
	, m_spReadCount(0)
	, m_palReadCount(0)
	, m_palReadTo(0)
	, m_csvList(_T(""))
	, m_scriptBasePath(_T(""))
	, m_spAssumedPal(0)
	, m_spReadOffset(0)
	, m_palReadOffset(0)
	, m_bmpBmpFilename(_T(""))
	, m_bmpSpSizeX(1)
	, m_bmpSpSizeY(1)
	, m_bmpSpFrameCount(1)
	, m_bmpSpReadTo(_T(""))
	, m_bmpSpReadOffset(0)
	, m_bmpPalReadTo(0)
	, m_bmpPalReadOffset(0)
	, m_bmpPalReadCount(16)
	, m_bmpPalShift(FALSE)
	, m_spSaveSpFilename(_T(""))
	, m_spSaveSpFrom(_T("00"))
	, m_spSaveSpCount(256)
	, m_spSavePalFilename(_T(""))
	, m_spSavePalFrom(0)
	, m_spSavePalCount(16)
	, m_bmpSaveAutoSw(FALSE)
	, m_scriptFilename(_T(""))
{
	//{{AFX_DATA_INIT(CSpconvDlg)
	m_BmpFile = _T("");
	m_DirName = _T("");
	m_MainName = _T("");
	m_PalFile = _T("");
	m_SpFile = _T("");
	//}}AFX_DATA_INIT
	// メモ: LoadIcon は Win32 の DestroyIcon のサブシーケンスを要求しません。
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CSpconvDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CSpconvDlg)
	DDX_Text(pDX, IDC_BMPFILE, m_BmpFile);
	DDX_Text(pDX, IDC_DIRNAME, m_DirName);
	DDX_Text(pDX, IDC_MAINNAME, m_MainName);
	DDX_Text(pDX, IDC_PALFILE, m_PalFile);
	DDX_Text(pDX, IDC_SPFILE, m_SpFile);
	//}}AFX_DATA_MAP
	DDX_Control(pDX, IDC_BUTTON_LOADBMP, m_loadBmpButton);
	DDX_Control(pDX, IDC_BUTTON_CONV_TO_SP, m_convToSpButton);
	DDX_Text(pDX, IDC_EDIT_SP_READ_TO, m_spReadTo);
	DDV_MaxChars(pDX, m_spReadTo, 2);
	//  DDX_Text(pDX, IDC_EDIT_PAL_READ_TO, m_palReadTo);
	DDX_Text(pDX, IDC_EDIT_SP_COUNT, m_spReadCount);
	DDV_MinMaxInt(pDX, m_spReadCount, 0, 256);
	DDX_Text(pDX, IDC_EDIT_PAL_COUNT, m_palReadCount);
	DDV_MinMaxInt(pDX, m_palReadCount, 0, 16);
	DDX_Text(pDX, IDC_EDIT_PAL_READ_TO, m_palReadTo);
	DDV_MinMaxInt(pDX, m_palReadTo, 0, 15);
	DDX_Text(pDX, IDC_EDIT_CSVLIST, m_csvList);
	DDX_Text(pDX, IDC_EDIT_SCRIPT_BASEPATH, m_scriptBasePath);
	DDX_Text(pDX, IDC_EDIT_SP_ASSUMED_PAL, m_spAssumedPal);
	DDV_MinMaxInt(pDX, m_spAssumedPal, 0, 15);
	DDX_Text(pDX, IDC_EDIT_SP_READ_OFFSET, m_spReadOffset);
	DDV_MinMaxInt(pDX, m_spReadOffset, 0, 255);
	DDX_Text(pDX, IDC_EDIT_PAL_READ_OFFSET, m_palReadOffset);
	DDV_MinMaxInt(pDX, m_palReadOffset, 0, 15);
	DDX_Text(pDX, IDC_EDIT_BMP_FILENAME, m_bmpBmpFilename);
	DDX_Text(pDX, IDC_EDIT_BMP_SP_SIZE_X, m_bmpSpSizeX);
	DDV_MinMaxInt(pDX, m_bmpSpSizeX, 1, INT_MAX);
	DDX_Text(pDX, IDC_EDIT_BMP_SP_SIZE_Y, m_bmpSpSizeY);
	DDV_MinMaxInt(pDX, m_bmpSpSizeY, 1, INT_MAX);
	DDX_Text(pDX, IDC_EDIT_BMP_SP_FRAME_COUNT, m_bmpSpFrameCount);
	DDV_MinMaxInt(pDX, m_bmpSpFrameCount, 1, INT_MAX);
	DDX_Text(pDX, IDC_EDIT_BMP_SP_READ_TO, m_bmpSpReadTo);
	DDV_MaxChars(pDX, m_bmpSpReadTo, 2);
	DDX_Text(pDX, IDC_EDIT_BMP_SP_READ_OFFSET, m_bmpSpReadOffset);
	DDV_MinMaxInt(pDX, m_bmpSpReadOffset, 0, 255);
	DDX_Text(pDX, IDC_EDIT_BMP_PAL_READ_TO, m_bmpPalReadTo);
	DDV_MinMaxInt(pDX, m_bmpPalReadTo, 0, 15);
	DDX_Text(pDX, IDC_EDIT_BMP_PAL_READ_OFFSET, m_bmpPalReadOffset);
	DDV_MinMaxInt(pDX, m_bmpPalReadOffset, 0, 15);
	DDX_Text(pDX, IDC_EDIT_BMP_PAL_READ_COUNT, m_bmpPalReadCount);
	DDV_MinMaxInt(pDX, m_bmpPalReadCount, 1, 16);
	DDX_Check(pDX, IDC_CHECK_SHIFT_PAL, m_bmpPalShift);
	DDX_Text(pDX, IDC_EDIT_SP_SAVE_SP_FILENAME, m_spSaveSpFilename);
	DDX_Text(pDX, IDC_EDIT_SP_SAVE_SP_FROM, m_spSaveSpFrom);
	DDV_MaxChars(pDX, m_spSaveSpFrom, 2);
	DDX_Text(pDX, IDC_EDIT_SP_SAVE_SP_COUNT, m_spSaveSpCount);
	DDV_MinMaxInt(pDX, m_spSaveSpCount, 1, 256);
	DDX_Text(pDX, IDC_EDIT_SP_SAVE_PAL_FILENAME, m_spSavePalFilename);
	DDX_Text(pDX, IDC_EDIT_SP_SAVE_PAL_FROM, m_spSavePalFrom);
	DDV_MinMaxInt(pDX, m_spSavePalFrom, 0, 15);
	DDX_Text(pDX, IDC_EDIT_SP_SAVE_PAL_COUNT, m_spSavePalCount);
	DDV_MinMaxInt(pDX, m_spSavePalCount, 1, 16);
	DDX_Check(pDX, IDC_AUTOSW, m_bmpSaveAutoSw);
	DDX_Text(pDX, IDC_EDIT_SCRIPT_FILENAME, m_scriptFilename);
}

BEGIN_MESSAGE_MAP(CSpconvDlg, CDialog)
	//{{AFX_MSG_MAP(CSpconvDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_AUTOSW, OnAutosw)
	ON_BN_CLICKED(IDC_SPREF, OnSpref)
	ON_BN_CLICKED(IDC_PALREF, OnPalref)
	ON_BN_CLICKED(IDC_BMPREF, OnBmpref)
	ON_BN_CLICKED(IDC_CLEAR, OnClear)
	ON_WM_LBUTTONDOWN()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_DIRREF, &CSpconvDlg::OnBnClickedDirref)
	ON_BN_CLICKED(IDC_BUTTON_LOADBMP, &CSpconvDlg::OnBnClickedButtonLoadbmp)
	ON_BN_CLICKED(IDC_BUTTON_CONV_TO_SP, &CSpconvDlg::OnBnClickedButtonConvToSp)
	ON_BN_CLICKED(IDC_BUTTON_SP_TO_BMP, &CSpconvDlg::OnBnClickedButtonSpToBmp)
	ON_WM_CLOSE()
	ON_BN_CLICKED(IDCANCEL, &CSpconvDlg::OnBnClickedCancel)
	ON_BN_CLICKED(IDC_BUTTON_READ_PAL, &CSpconvDlg::OnBnClickedButtonReadPal)
	ON_BN_CLICKED(IDC_BUTTON_REF_BASEPATH, &CSpconvDlg::OnBnClickedButtonRefBasepath)
	ON_BN_CLICKED(IDC_BUTTON_READ_SP, &CSpconvDlg::OnBnClickedButtonReadSp)
	ON_BN_CLICKED(IDC_BUTTON_BMP_FILENAME_REF, &CSpconvDlg::OnBnClickedButtonBmpFilenameRef)
	ON_BN_CLICKED(IDC_BUTTON_BMP_SP_READ, &CSpconvDlg::OnBnClickedButtonBmpSpRead)
	ON_BN_CLICKED(IDC_BUTTON_SP_SAVE_SP_REF, &CSpconvDlg::OnBnClickedButtonSpSaveSpRef)
	ON_BN_CLICKED(IDC_BUTTON_SP_SAVE_PAL_REF, &CSpconvDlg::OnBnClickedButtonSpSavePalRef)
	ON_BN_CLICKED(IDC_BUTTON_BMP_SAVE_FULLCOLOR_BMP, &CSpconvDlg::OnBnClickedButtonBmpSaveFullcolorBmp)
	ON_BN_CLICKED(IDC_BUTTON_SCRIPT_FILENAME_REF, &CSpconvDlg::OnBnClickedButtonScriptFilenameRef)
	ON_BN_CLICKED(IDC_BUTTON_SAVE_CSV, &CSpconvDlg::OnBnClickedButtonSaveCsv)
	ON_BN_CLICKED(IDC_BUTTON_READ_CSV, &CSpconvDlg::OnBnClickedButtonReadCsv)
	ON_BN_CLICKED(IDC_BUTTON_EXEC_CSV, &CSpconvDlg::OnBnClickedButtonExecCsv)
	ON_EN_KILLFOCUS(IDC_EDIT_CSVLIST, &CSpconvDlg::OnEnKillfocusEditCsvlist)
	ON_BN_CLICKED(IDC_BUTTON_SAVE256, &CSpconvDlg::OnBnClickedButtonSave256)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSpconvDlg メッセージ ハンドラ

BOOL CSpconvDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// "バージョン情報..." メニュー項目をシステム メニューへ追加します。

	// IDM_ABOUTBOX はコマンド メニューの範囲でなければなりません。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	CString strAboutMenu;
	strAboutMenu.LoadString(IDS_ABOUTBOX);
	if (!strAboutMenu.IsEmpty())
	{
		pSysMenu->AppendMenu(MF_SEPARATOR);
		pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
	}

	// このダイアログ用のアイコンを設定します。フレームワークはアプリケーションのメイン
	// ウィンドウがダイアログでない時は自動的に設定しません。
	SetIcon(m_hIcon, TRUE);			// 大きいアイコンを設定
	SetIcon(m_hIcon, FALSE);		// 小さいアイコンを設定

	// TODO: 特別な初期化を行う時はこの場所に追加してください。
	Initialize();

	return TRUE;  // TRUE を返すとコントロールに設定したフォーカスは失われません。
}

/// <summary>
/// 初期化処理
/// </summary>
void CSpconvDlg::Initialize()
{
	// データ取り込み
	UpdateData(true);
	// カレントディレクトリ取得
	char cdir[260];								// カレントディレクトリ取得
	GetCurrentDirectory(260, cdir);
	
	// <<< 値の初期設定 >>>
	//
	// 入力：スプライト
	//
	m_spReadTo = CString("00");				// SPの読み込み先Index
	m_spReadOffset = 0;
	m_spReadCount = 256;
	m_spAssumedPal = 0;
	m_palReadTo = 0;
	m_palReadOffset = 0;
	m_palReadCount = 16;
	//
	// 入力：BMP
	// 
	m_bmpBmpFilename = "";
	m_bmpSpSizeX = 1;
	m_bmpSpSizeY = 1;
	m_bmpSpFrameCount = 256;
	m_bmpSpReadTo = "00";
	m_bmpSpReadOffset = 0;
	m_bmpPalReadTo = 0;
	m_bmpPalReadOffset = 0;
	m_bmpPalReadCount = 16;
	m_bmpPalShift = true;

	//
	// 出力：BMP
	//
	m_DirName = CString(cdir);				// カレントディレクトリ
	m_MainName = CString("sprite.bmp");		// メインファイル名

	// オブジェクトの初期化処理
	spimage = NULL;										// ＳＰイメージＢＭＰへのポインタを初期化
	palimage = NULL;									// ＰＡＬイメージＢＭＰへのポインタを初期化
	tximage = NULL;										// テクスチャイメージBMPへのポインタを初期化

	MakeSpImage();										// スプライトのイメージビットマップの作成
	MakePalImage();										// パレットのイメージビットマップの作成
	InitializeTextureImage();									// テクスチャのイメージビットマップの作成

	SelectedPalBlock = 0;								// 選択中のパレットブロックは０

	// 値をダイアログに反映
	UpdateData(FALSE);
}

/// <summary>
/// 各種データの解放
/// </summary>
void CSpconvDlg::Release()
{
	// 画像を解放する
	if (spimage != NULL) {
		delete spimage;
		spimage = NULL;
	}
	if (palimage != NULL) {
		delete palimage;
		palimage = NULL;
	}
	if (tximage != NULL) {
		delete tximage;
		tximage = NULL;
	}
}

void CSpconvDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// もしダイアログボックスに最小化ボタンを追加するならば、アイコンを描画する
// コードを以下に記述する必要があります。MFC アプリケーションは document/view
// モデルを使っているので、この処理はフレームワークにより自動的に処理されます。

void CSpconvDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 描画用のデバイス コンテキスト

		SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);

		// クライアントの矩形領域内の中央
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// アイコンを描画します。
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
		DrawScreenAll();					// とりあえず、全体を再描画する関数へ・・・
	}
}

// システムは、ユーザーが最小化ウィンドウをドラッグしている間、
// カーソルを表示するためにここを呼び出します。
HCURSOR CSpconvDlg::OnQueryDragIcon()
{
	return (HCURSOR)m_hIcon;
}

//------------------------------------------------------------------< 変換実行の処理 >
void CSpconvDlg::OnOK()
{


	//	CDialog::OnOK();
}


//----------------------------------------------------------------------< 画面の描きなおし >
void CSpconvDlg::DrawScreenAll()
{
	// イメージの表示
	CDC* pDC;
	pDC = GetDC();

	spimage->NormalDraw(CPoint(SPIMAGE_X, SPIMAGE_Y), pDC);			// 描画
	palimage->NormalDraw(CPoint(PALIMAGE_X, PALIMAGE_Y), pDC);		// 描画
	tximage->NormalDraw(CPoint(TXIMAGE_X, TXIMAGE_Y), pDC);		// 描画

	{
		CBrush tempbrush;												// 選択されているパレットを囲む
		tempbrush.CreateSolidBrush(RGB(255, 255, 255));
		pDC->FrameRect(
			CRect(
				PALIMAGE_X, PALIMAGE_Y + (SelectedPalBlock * 8)
				, PALIMAGE_X + 128, PALIMAGE_Y + (SelectedPalBlock * 8) + 8)
			, &tempbrush);
	}
	ReleaseDC(pDC);													// 描画終了

	char nstr[3];										// パレットブロックの番号表示
	sprintf(nstr, "%2d", SelectedPalBlock);
	CStatic* no;
	no = (CStatic*)GetDlgItem(IDC_PALBLOCKNO);
	no->SetWindowText(CString(nstr));
}

/// <summary>
/// BMPからSPにパターンを転写する
/// </summary>
/// <param name="idxFrom"></param>
/// <param name="idxTo"></param>
void CSpconvDlg::TranslateBmpToSp(int idxFrom, int idxTo)
{
	BOOL needToBitOperation = false;
	if (!tximage->isBitOpe()) {
		needToBitOperation = true;
	}

	if (needToBitOperation) {
		tximage->PrepareBitOperation();
	}

	// 画像取り込み
	for(int idx = idxFrom;idx<=idxTo;idx++) {
		int spY = idx / 16;
		int spX = idx & 15;
		int offX = spX * 16;	// 画像上のSPパターン左上ピクセル位置
		int offY = spY * 16;

		int pcgIndex = 0;
		// 左8ドット
		for (int y = 0; y < 16; y++) {
			for (int x = 0; x < 8; x += 2) {
				BYTE l = tximage->GetPixelIndex(offX + x, offY + y) & 15;
				BYTE r = tximage->GetPixelIndex(offX + x + 1, offY + y) & 15;
				BYTE v = (l << 4) + r;
				sp_data[spY][spX][pcgIndex++] = v;
			}
		}
		// 右8ドット
		for (int y = 0; y < 16; y++) {
			for (int x = 8; x < 16; x += 2) {
				BYTE l = tximage->GetPixelIndex(offX + x, offY + y) & 15;
				BYTE r = tximage->GetPixelIndex(offX + x + 1, offY + y) & 15;
				BYTE v = (l << 4) + r;
				sp_data[spY][spX][pcgIndex++] = v;
			}
		}
	}

	if (needToBitOperation) {
		CDC* pDC = GetDC();
		tximage->EndBitOperation(pDC);
		ReleaseDC(pDC);
	}

	// 画像を再構築する
	MakeSpImage();
}

/// <summary>
/// SPからBMPにパターンを転写する
/// </summary>
/// <param name="idxFrom"></param>
/// <param name="idxTo"></param>
void CSpconvDlg::TranslateSpToBmp(int idxFrom, int idxTo, int spAssumedPal)
{
	BOOL needToBitOperation = false;
	if (!tximage->isBitOpe()) {
		needToBitOperation = true;
	}

	if (needToBitOperation) {
		tximage->PrepareBitOperation();
	}

	// 画像取り込み
	for (int idx = idxFrom; idx <= min(idxTo,255); idx++) {
		int spY = idx / 16;
		int spX = idx & 15;
		int offX = spX * 16;	// 画像上のSPパターン左上ピクセル位置
		int offY = spY * 16;

		for (int y = 0; y < 16; y++) {
			for (int x = 0; x < 16; x++) {
				int code = spimage->GetPixelIndex(offX + x, offY + y);
				int adjustedCode = code + (spAssumedPal * 16);
				if ((adjustedCode < 0) || (adjustedCode >= 256)) {
					adjustedCode = code;
				}
				tximage->SetPixelIndex(offX + x, offY + y, adjustedCode);
			}
		}
	}

	if (needToBitOperation) {
		CDC* pDC = GetDC();
		tximage->EndBitOperation(pDC);
		ReleaseDC(pDC);
	}
}


//------------------------------------------------------< 自動実行スイッチがクリックされた場合 >
void CSpconvDlg::OnAutosw()
{
	CButton* btn;
	btn = (CButton*)GetDlgItem(IDC_AUTOSW);					// スイッチのオブジェクトへのポインタを得る

	CEdit* bmpedit;								// ＢＭＰファイル名エディットボックス
	CEdit* extedit;								// 展開ディレクトリ名エディットボックス
	CEdit* mainedit;							// 主ファイル名エディットボックス
	CButton* bmpref;							// ＢＭＰ参照ボタン
	CButton* extref;							// 展開ディレクトリ参照ボタン
	bmpedit = (CEdit*)GetDlgItem(IDC_BMPFILE);			// 各コントロールのポインタを得る
	extedit = (CEdit*)GetDlgItem(IDC_DIRNAME);
	mainedit = (CEdit*)GetDlgItem(IDC_MAINNAME);
	bmpref = (CButton*)GetDlgItem(IDC_BMPREF);
	extref = (CButton*)GetDlgItem(IDC_DIRREF);

	if (btn->GetCheck()) {									// チェックがオンになった場合
		bmpedit->EnableWindow(FALSE);				// ファイル名のエディットボックスは使用不能
		extedit->EnableWindow(TRUE);				// 展開ディレクトリのエディットボックスは使用可能
		mainedit->EnableWindow(TRUE);				// 主ファイル名のエディットボックスは使用可能
		bmpref->EnableWindow(FALSE);				// ＢＭＰの参照は使用不可
		extref->EnableWindow(TRUE);					// 展開ディレクトリの参照は使用可能
	}
	else {												// チェックがオフになった場合
		bmpedit->EnableWindow(TRUE);				// ファイル名のエディットボックスは使用不能
		extedit->EnableWindow(FALSE);				// 展開ディレクトリのエディットボックスは使用可能
		mainedit->EnableWindow(FALSE);				// 主ファイル名のエディットボックスは使用可能
		bmpref->EnableWindow(TRUE);					// ＢＭＰの参照は使用不可
		extref->EnableWindow(FALSE);				// 展開ディレクトリの参照は使用可能
	}

}


//--------------------------------------------------------------------< ＳＰファイル参照 >
void CSpconvDlg::OnSpref()
{
	CFileDialog dlg(
		TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST, "SPファイル|*.sp|すべてのファイル|*.*||"
	);

	if (dlg.DoModal() == IDOK) {						// ダイアログ表示
		CString filename;
		filename = dlg.GetPathName();					// ファイルネーム取得
		CEdit* spfile;								// エディットボックスへのポインタを得る
		spfile = (CEdit*)GetDlgItem(IDC_SPFILE);
		spfile->SetWindowText(filename);			// ファイルネームをエディットボックスへ書き込む
	}
}


//---------------------------------------------------------< パレットファイル名参照 >
void CSpconvDlg::OnPalref()
{
	CFileDialog dlg(
		TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST, "PALファイル|*.pal|すべてのファイル|*.*||"
	);

	if (dlg.DoModal() == IDOK) {						// ダイアログ表示
		CString filename;
		filename = dlg.GetPathName();					// ファイルネーム取得
		CEdit* palfile;								// エディットボックスへのポインタを得る
		palfile = (CEdit*)GetDlgItem(IDC_PALFILE);
		palfile->SetWindowText(filename);			// ファイルネームをエディットボックスへ書き込む
	}
}


//---------------------------------------------------------< ＢＭＰファイル名参照 >
void CSpconvDlg::OnBmpref()
{
	CFileDialog dlg(
		FALSE, "bmp", NULL, OFN_HIDEREADONLY | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST, "BMPファイル|*.bmp||"
	);

	if (dlg.DoModal() == IDOK) {						// ダイアログ表示
		CString filename;
		filename = dlg.GetPathName();					// ファイルネーム取得
		CEdit* bmpfile;								// エディットボックスへのポインタを得る
		bmpfile = (CEdit*)GetDlgItem(IDC_BMPFILE);
		bmpfile->SetWindowText(filename);			// ファイルネームをエディットボックスへ書き込む
	}
}


//---------------------------------------------------------< 展開ディレクトリ参照 >
void CSpconvDlg::OnBnClickedDirref()
{
	/*
	CDirSelectDialog dlg;

	CString temp;
	GetDlgItemText(IDC_DIRNAME, temp);
	dlg.InitialDirectory = temp;
	if (dlg.DoModal() == IDOK) {				// ダイアログを表示
		CEdit* dirname;								// エディットボックスへのポインタを得る
		dirname = (CEdit*)GetDlgItem(IDC_DIRNAME);
		dirname->SetWindowText(dlg.SelectedPath);	// ファイルネームをエディットボックスへ書き込む
	}
	*/

	UpdateData();
	CFolderPickerDialog folderDialog(m_DirName);

	// ダイアログ表示
	if (folderDialog.DoModal() == IDOK)
	{
		CString fullPathName = folderDialog.GetPathName();
		m_DirName = fullPathName;
		UpdateData(FALSE);
	}
}


//--------------------------------------------------------------<ＲＧＢテーブルを作る>
void CSpconvDlg::MakeRGBTable()
{
	union {
		WORD mixed;
		struct {
			unsigned dummy : 1;
			unsigned blue : 5;
			unsigned red : 5;
			unsigned green : 5;
		}bit;
	}map;
	int i, c, d;

	for (i = 0; i < 16; i++) {
		for (c = 0; c < 16; c++) {
			d = pal_data[i][c] & 255;									// ＳＷＡＰ用
			map.mixed = ((pal_data[i][c] >> 8) & 255) + ((d << 8) & 0xFF00);	// 値を取り込んで
			rgb_data[i][c].rgbRed = (map.bit.red * 255) / 31;			// 変換
			rgb_data[i][c].rgbGreen = (map.bit.green * 255) / 31;
			rgb_data[i][c].rgbBlue = (map.bit.blue * 255) / 31;
		}
	}
}


//------------------------------------------------------------------< ＳＰの表示イメージを作る >
void CSpconvDlg::MakeSpImage()
{
	int i, c, d;

	if (spimage != NULL) {				// すでにＢＭＰがセットされていたら、まず消去する
		delete spimage;
	}

	// イメージ作成中の文字を書く
	CDC* pDC, memDC;									// デバイスコンテキストを用意
	pDC = GetDC();									// 取得
	spimage = new Cfbmp(256, 256, 4, pDC);				// １６色でCfbmpオブジェクトを作成する
	CFont tempfont;									// フォントを作る
	tempfont.CreateFont(16, 0, 0, 0, FW_NORMAL, 0, 0, 0
		, SHIFTJIS_CHARSET, OUT_DEVICE_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY
		, DEFAULT_PITCH, "System");
	memDC.CreateCompatibleDC(pDC);					// コンパチを作る
	pDC->TextOut(SPIMAGE_X + 5, SPIMAGE_Y + 5, CString("イメージ作成中..."));

	// 描画
	spimage->PrepareBitOperation();
	for (i = 0; i < 16; i++)spimage->SetPalet(i, rgb_data[SelectedPalBlock][i]);	// パレットを適用
	for (int y = 0; y < 256; y++) {						// 出力画像を０で初期化
		for (int x = 0; x < 256; x++) {
			spimage->SetPixelIndex(x, y, 0);
		}
	}
	int IndexArray[256 * 256];							// インデックスのマップを保存する
	for (i = 0; i < 16; i++) {
		for (c = 0; c < 16; c++) {
			for (d = 0; d < 128; d++) {
				int offset_x, offset_y;
				if (d < 64) {						// オフセット設定(￣▽￣;
					offset_x = 0;
					offset_y = 0;
				}
				else {
					offset_x = 8;
					offset_y = -16;
				}
				//
				IndexArray[(((i * 16) + ((d * 2) / 8) + offset_y) * 256) + ((c * 16) + offset_x + (((d * 2)) & 7))] = (sp_data[i][c][d] >> 4) & 15;
				IndexArray[(((i * 16) + ((d * 2) / 8) + offset_y) * 256) + ((c * 16) + offset_x + (((d * 2) + 1) & 7))] = sp_data[i][c][d] & 15;
			}
		}
	}
	for (i = 0; i < 256; i++) {
		for (c = 0; c < 256; c++) {
			int index;
			index = spimage->SetPixelIndex(c, i, IndexArray[(i * 256) + c]);
		}
	}
	spimage->EndBitOperation(pDC);

	ReleaseDC(pDC);									// ＤＣを解放して終わり

	return;
}


//------------------------------------------------------------------< ＰＡＬの表示イメージを作る >
void CSpconvDlg::MakePalImage()
{
	int i, c;
	if (palimage != NULL) {
		delete palimage;
	}

	CDC* pDC, memDC;									// デバイスコンテキストを用意
	pDC = GetDC();									// 取得
	palimage = new Cfbmp(128, 128, 24, pDC);			// ビットマップオブジェクトを作成する
	CFont tempfont;									// フォントを作る
	tempfont.CreateFont(16, 0, 0, 0, FW_NORMAL, 0, 0, 0
		, SHIFTJIS_CHARSET, OUT_DEVICE_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY
		, DEFAULT_PITCH, "System");
	memDC.CreateCompatibleDC(pDC);					// コンパチを作る

	/*
	if(isPalSet == FALSE){					// ＰＡＬのデータがセットされていない場合
		CBitmap *tmpbmp=CBitmap::FromHandle(palimage->GetBmpHandle());	// 一時的なCBitmapオブジェクト作成
		CBitmap *oldbmp;								// 古いＢＭＰを保存し
		oldbmp=memDC.SelectObject(tmpbmp);				// ＳＰイメージＢＭＰを選択し
		CFont *oldfont;									// 古いフォントを保存し
		oldfont=memDC.SelectObject(&tempfont);			// フォントを選択し
		int oldbm;										// 古い透過モードを保存し
		oldbm=memDC.SetBkMode(TRANSPARENT);				// 透過モードをセットし
		COLORREF oldcolor;								// 古い選択色を保存し
		oldcolor=memDC.SetTextColor(RGB(255,255,255));	// 色を選択し

											// 描画
		memDC.FillSolidRect(CRect(0,0,128,128),RGB(0,0,0));
		memDC.TextOut(18,56,CString("- No Image -"));

		memDC.SetTextColor(oldcolor);					// 色を戻し
		memDC.SetBkMode(oldbm);							// 透過モードを戻し
		memDC.SelectObject(oldfont);					// フォントを戻し
		memDC.SelectObject(oldbmp);						// ＢＭＰを戻し
		ReleaseDC(pDC);									// ＤＣを解放して終わり

		isPalBmpReady = TRUE;							// 準備完了
		return;
	}
	*/


	// データが揃っている場合
	CBitmap* tmpbmp = CBitmap::FromHandle(palimage->GetBmpHandle());	// 一時的なCBitmapオブジェクト作成
	CBitmap* oldbmp;								// 古いＢＭＰを保存し
	oldbmp = memDC.SelectObject(tmpbmp);				// ＰＡＬイメージＢＭＰを選択し

	// 描画
	memDC.FillSolidRect(CRect(0, 0, 128, 128), RGB(0, 0, 0));
	for (i = 0; i < 16; i++) {
		for (c = 0; c < 16; c++) {
			memDC.FillSolidRect(CRect(c * 8, i * 8, (c * 8) + 7, (i * 8) + 7),
				RGB(rgb_data[i][c].rgbRed,
					rgb_data[i][c].rgbGreen,
					rgb_data[i][c].rgbBlue)
			);
		}
	}

	memDC.SelectObject(oldbmp);						// ＢＭＰを戻し
	ReleaseDC(pDC);									// ＤＣを解放して終わり

	return;
}


/// <summary>
/// テクスチャ画像を初期化する
/// </summary>
void CSpconvDlg::InitializeTextureImage()
{
	if (tximage != NULL) {
		delete tximage;
	}

	CDC* pDC = GetDC();								// 取得
	tximage = new Cfbmp(256, 256, 8, pDC);			// 256色でCfbmpオブジェクトを作成する
	ReleaseDC(pDC);									// ＤＣを解放して終わり

	return;
}


/// <summary>
/// テクスチャ画像のパレットを再構築する
/// </summary>
void CSpconvDlg::MakeTexturePalet()
{
	// 画像がなければ無視
	if (tximage == NULL) {
		return;
	}

	CDC* pDC = GetDC();									// 取得

	// 描画
	tximage->PrepareBitOperation();
		// パレット全体を転送
	for (int i = 0; i < 16; i++) {
		for (int c = 0; c < 16; c++) {
			tximage->SetPalet((i * 16) + c, rgb_data[i][c]);
		}
	}
	tximage->EndBitOperation(pDC);

	ReleaseDC(pDC);									// ＤＣを解放して終わり

	return;
}

/// <summary>
/// CSV一覧を再構築する
/// </summary>
void CSpconvDlg::MakeCsvList()
{
	// ベースパス表現を相対パスに変更
	m_csvList = "";
	for (int i = 0; i < m_operationCsv.GetSize(); i++) {
		m_operationCsv[i].AdjustBasePath(m_scriptBasePath);
		m_csvList.Append(m_operationCsv[i].GetCsvLine());
		m_csvList.Append("\r\n");
	}
	UpdateData(false);
}

/// <summary>
/// 全てのイメージを再構築する
/// </summary>
void CSpconvDlg::MakeAllImages()
{
	MakeRGBTable();
	MakeSpImage();
	MakePalImage();
	MakeTexturePalet();
	MakeCsvList();
}


//----------------------------------------------------------< クリアボタンが押された >
void CSpconvDlg::OnClear()
{
	int i, c, d;

	// SP, PALをクリアする
	for (i = 0; i < 16; i++) {
		for (c = 0; c < 16; c++) {
			pal_data[i][c] = 0;					// ＰＡＬデータをクリア
			for (d = 0; d < 128; d++) {
				sp_data[i][c][d] = 0;			// ＳＰデータをクリア
			}
		}
	}

	// CSVをクリアする
	//m_operationCsv.RemoveAll();

	// BMPを初期化する
	if (spimage != NULL) {								// イメージＢＭＰを破棄
		delete spimage;
		spimage = NULL;
	}
	if (palimage != NULL) {
		delete palimage;
		palimage = NULL;
	}
	if (tximage != NULL) {
		delete tximage;
		tximage = NULL;
	}
	InitializeTextureImage();

	// 画面を再構築する
	MakeAllImages();
	SelectedPalBlock = 0;						// 選択中のパレットブロックは０
	DrawScreenAll();
}


//---------------------------------------------------< フォーム上で左クリックされた >
void CSpconvDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	if ((point.x >= PALIMAGE_X) && (point.x < PALIMAGE_X + 128)) {		// パレットイメージ上だった場合
		if ((point.y >= PALIMAGE_Y) && (point.y < PALIMAGE_Y + 128)) {
			int tempblock;
			tempblock = (point.y - PALIMAGE_Y) / 8;				// 選択されているパレットを変更して
			if (tempblock == SelectedPalBlock)return;
			SelectedPalBlock = tempblock;
			MakeSpImage();									// 絵を描き換えて
			DrawScreenAll();								// 全体を描き直す
		}
	}

	CDialog::OnLButtonDown(nFlags, point);
}


//-----------------------------------------------------------< ＢＭＰファイルを出力する >
void CSpconvDlg::SaveBmp(CString fname, BOOL indexedColor)
{
	CString fname_main = fname.Left(fname.GetLength() - 4);
	CString fname_a = fname_main + "_a.bmp";

	BOOL bRes = FALSE;
	if (indexedColor) {
		bRes = doSave256((LPCTSTR)fname, spimage);
	}
	else {
		bRes = doSave((LPCTSTR)fname, spimage);
		bRes &= doSaveStencil((LPCTSTR)fname_a, spimage);
	}
	if (bRes == FALSE) {
		MessageBox("BMPファイルの保存に失敗しました。", "Error", MB_OK);
		return;
	}

	return;											// 終了
}

BOOL CSpconvDlg::doSave(LPCTSTR fname, Cfbmp* pBmp) {
	if (pBmp->isReady() == FALSE)return FALSE;				// 画像が準備できていなければエラー

	FILE* stream;									// ファイルストリーム
	stream = fopen(fname, "wb");					// ファイルオープン
	if (stream == NULL)return FALSE;				// オープンできなかった場合

	// ビット配列のサイズを計算
	UINT uSizeImage;
	uSizeImage = (pBmp->GetWidth() * 32) / 8;	// 横方向バイト数（32bit固定）
	uSizeImage += (4 - (uSizeImage & 3)) & 3;		// ４バイト境界調整
	uSizeImage *= pBmp->GetHeight();				// 高さをかけて全体のサイズ

	// Bitmap File Header 作成
	//UINT nColors = 1 << 32;
	UINT QuadSize = 0;

	BITMAPFILEHEADER bmfh;
	memset(&bmfh, 0, sizeof(BITMAPFILEHEADER));
	bmfh.bfType = 0x4d42;
	bmfh.bfSize = sizeof(BITMAPV4HEADER) + sizeof(BITMAPFILEHEADER) + QuadSize + uSizeImage;
	bmfh.bfReserved1 = 0;
	bmfh.bfReserved2 = 0;
	bmfh.bfOffBits = sizeof(BITMAPV4HEADER) + sizeof(BITMAPFILEHEADER) + QuadSize;

	// Bitmap V4 Header 作成 >>
	BITMAPV4HEADER bmih;
	memset(&bmih, 0, sizeof(BITMAPV4HEADER));
	bmih.bV4Size = sizeof(BITMAPV4HEADER);
	bmih.bV4Width = pBmp->GetWidth();
	bmih.bV4Height = pBmp->GetHeight();
	bmih.bV4Planes = 1;
	bmih.bV4BitCount = 32;
	bmih.bV4V4Compression = BI_BITFIELDS;
	bmih.bV4SizeImage = 0;
	bmih.bV4XPelsPerMeter = 0;
	bmih.bV4YPelsPerMeter = 0;
	bmih.bV4ClrUsed = 0;
	bmih.bV4ClrImportant = 0;
	bmih.bV4RedMask = 0x000000FF;
	bmih.bV4GreenMask = 0x0000FF00;
	bmih.bV4BlueMask = 0x00FF0000;
	bmih.bV4AlphaMask = 0xFF000000;
	bmih.bV4CSType = LCS_sRGB;
	//bmih.bV4Endpoints = xx;	N/A
	bmih.bV4GammaRed = 0;
	bmih.bV4GammaGreen = 0;
	bmih.bV4GammaBlue = 0;

	// 書き込み
	fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, stream);	// BITMAPFILEHEADER書き込み
	fwrite(&bmih, sizeof(BITMAPV4HEADER), 1, stream);	// BITMAPV4HEADER書き込み

	//int SizeImage;														// ビット配列のサイズを計算
	for (int y = pBmp->GetHeight() - 1; y >= 0; y--) {
		for (int x = 0; x < pBmp->GetWidth(); x++) {
			int palIndex = pBmp->GetPixelIndex(x, y);
			RGBQUAD quad = pBmp->GetPixelColor(x, y);

			fputc(quad.rgbRed & 0xFF, stream);
			fputc(quad.rgbGreen & 0xFF, stream);
			fputc(quad.rgbBlue & 0xFF, stream);
			fputc(((palIndex&15) == 0 ? 0x00 : 0xFF), stream);
		}
	}

	fclose(stream);												// ファイルクローズ

	return TRUE;
}

BOOL CSpconvDlg::doSaveStencil(LPCTSTR fname, Cfbmp* pBmp) {
	if (pBmp->isReady() == FALSE)return FALSE;				// 画像が準備できていなければエラー

	FILE* stream;									// ファイルストリーム
	stream = fopen(fname, "wb");					// ファイルオープン
	if (stream == NULL)return FALSE;				// オープンできなかった場合

	// ビット配列のサイズを計算
	UINT uSizeImage;
	uSizeImage = (pBmp->GetWidth() * 32) / 8;	// 横方向バイト数（32bit固定）
	uSizeImage += (4 - (uSizeImage & 3)) & 3;		// ４バイト境界調整
	uSizeImage *= pBmp->GetHeight();				// 高さをかけて全体のサイズ

	// Bitmap File Header 作成
	//UINT nColors = 1 << 32;
	UINT QuadSize = 0;

	BITMAPFILEHEADER bmfh;
	memset(&bmfh, 0, sizeof(BITMAPFILEHEADER));
	bmfh.bfType = 0x4d42;
	bmfh.bfSize = sizeof(BITMAPV4HEADER) + sizeof(BITMAPFILEHEADER) + QuadSize + uSizeImage;
	bmfh.bfReserved1 = 0;
	bmfh.bfReserved2 = 0;
	bmfh.bfOffBits = sizeof(BITMAPV4HEADER) + sizeof(BITMAPFILEHEADER) + QuadSize;

	// Bitmap V4 Header 作成 >>
	BITMAPV4HEADER bmih;
	memset(&bmih, 0, sizeof(BITMAPV4HEADER));
	bmih.bV4Size = sizeof(BITMAPV4HEADER);
	bmih.bV4Width = pBmp->GetWidth();
	bmih.bV4Height = pBmp->GetHeight();
	bmih.bV4Planes = 1;
	bmih.bV4BitCount = 32;
	bmih.bV4V4Compression = BI_BITFIELDS;
	bmih.bV4SizeImage = 0;
	bmih.bV4XPelsPerMeter = 0;
	bmih.bV4YPelsPerMeter = 0;
	bmih.bV4ClrUsed = 0;
	bmih.bV4ClrImportant = 0;
	bmih.bV4RedMask = 0x000000FF;
	bmih.bV4GreenMask = 0x0000FF00;
	bmih.bV4BlueMask = 0x00FF0000;
	bmih.bV4AlphaMask = 0xFF000000;
	bmih.bV4CSType = LCS_sRGB;
	//bmih.bV4Endpoints = xx;	N/A
	bmih.bV4GammaRed = 0;
	bmih.bV4GammaGreen = 0;
	bmih.bV4GammaBlue = 0;

	// 書き込み
	fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, stream);	// BITMAPFILEHEADER書き込み
	fwrite(&bmih, sizeof(BITMAPV4HEADER), 1, stream);	// BITMAPV4HEADER書き込み

	//int SizeImage;														// ビット配列のサイズを計算
	for (int y = pBmp->GetHeight() - 1; y >= 0; y--) {
		for (int x = 0; x < pBmp->GetWidth(); x++) {
			int palIndex = pBmp->GetPixelIndex(x, y);
			RGBQUAD quad = pBmp->GetPixelColor(x, y);

			if ((palIndex & 15) == 0) {
				fputc(0x00, stream);
				fputc(0x00, stream);
				fputc(0x00, stream);
				fputc(0xFF, stream);
			}
			else {
				fputc(0xFF, stream);
				fputc(0xFF, stream);
				fputc(0xFF, stream);
				fputc(0xFF, stream);
			}
		}
	}

	fclose(stream);												// ファイルクローズ

	return TRUE;
}

BOOL CSpconvDlg::doSave256(LPCTSTR fname, Cfbmp* pBmp) {
	if (pBmp->isReady() == FALSE)return FALSE;				// 画像が準備できていなければエラー
	BOOL res = pBmp->Save(fname);
	return res;
}


//-----------------------------------------------------------------< フルパス名を作る >
CString CSpconvDlg::MakeFullPathName(CString& dirname, CString& fname)
{
	int i;
	int length1, length2, length;
	length1 = dirname.GetLength();			// ディレクトリ名の長さ
	length2 = fname.GetLength();			// ファイル名の長さ
	length = length1 + length2 + 1;			// フルパス名の長さの最大

	unsigned char* full, * work;				// フルパス名格納
	full = (unsigned char*)malloc(length + 1);
	work = full;							// 作業用ポインタ

	for (int i = 0; i < length1; i++) {				// ディレクトリ名のコピー
		*work++ = dirname[i];				// １文字コピーしてインクリンメント
	}
	while (1) {								// 最後の文字が \ だったら、キャンセルする
		if ((length1 == 1) && (*(work - 1) == '\\')) {	// １文字で￥だけ
			work--;
			break;
		}
		if ((*(work - 1) == '\\') && (*(work - 2) < 0x80) && (length1 >= 2)) {	// ２文字以上で￥でマルチバイトじゃない
			work--;
			length1 -= 1;
		}
		else break;
	}
	*work++ = '\\';							// 区切り

	for (i = 0; i < length2; i++) {					// ファイル名のコピー
		*work++ = fname[i];
	}
	*work++ = 0;							// エンドコード

	CString res(full);
	free(full);
	return res;								// 返る
}

/// <summary>
/// SP, PALを保存
/// </summary>
void CSpconvDlg::OnBnClickedButtonConvToSp()
{
	UpdateData();

	// ファイル指定有無を確認
	if (m_spSaveSpFilename.GetLength() == 0) {
		MessageBox("SPファイルの出力先が指定されていません。");
		return;
	}
	if (m_spSavePalFilename.GetLength() == 0) {
		MessageBox("PALファイルの出力先が指定されていません。");
		return;
	}

	// ファイル既存確認
	CFileStatus spFileStatus;
	CFileStatus palFileStatus;
	BOOL spFileExists = CFile::GetStatus(m_spSaveSpFilename, spFileStatus);
	BOOL palFileExists = CFile::GetStatus(m_spSavePalFilename, palFileStatus);
	CString existingFile = "";
	if (spFileExists) { existingFile += CString(m_spSaveSpFilename); }
	if (palFileExists) {
		if (existingFile.GetLength() > 0) {
			existingFile += CString(", ");
		}
		existingFile += CString(m_spSavePalFilename);
	}
	if (spFileExists || palFileExists) {
		CString msg = existingFile + CString("は既存です。上書きしますか？");
		int mbRes = MessageBox(msg, "確認", MB_YESNO);
		if (mbRes != IDYES) {
			// キャンセル
			return;
		}
	}

	// SPの先頭アドレスと個数を確定させる
	int spSaveSpFromDec = 0;
	int parseResult = sscanf(m_spSaveSpFrom, "%02X", &spSaveSpFromDec);
	if (parseResult <= 0) {
		MessageBox("先頭Indexは2桁の16進数で指定してください。");
		return;
	}

	CRes res = ExecSaveSpPal(m_spSaveSpFilename, spSaveSpFromDec, m_spSaveSpCount
		, m_spSavePalFilename, m_spSavePalFrom, m_spSavePalCount, m_scriptBasePath);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// CSVにオペレーションを追加
	CsvEntry entry(CSVCMD_SAVE_SP_PAL);
	entry.AddParam(m_spSaveSpFilename, true);
	entry.AddParam(m_spSaveSpFrom, true);
	entry.AddParam(m_spSaveSpCount);
	entry.AddParam(m_spSavePalFilename, true);
	entry.AddParam(m_spSavePalFrom);
	entry.AddParam(m_spSavePalCount);
	m_operationCsv.Add(entry);

	// 終了メッセージ
	MessageBox("SP, PALを保存しました。");

	// 再描画
	MakeAllImages();
	DrawScreenAll();
}

/// <summary>
/// BMP保存ボタン
/// </summary>
void CSpconvDlg::OnBnClickedButtonSpToBmp()
{
	UpdateData(TRUE);									// データをメンバ変数へ取り込み

	// ファイル既存確認
	if (!m_bmpSaveAutoSw) {
		CFileStatus fileStatus;
		BOOL fileExists = CFile::GetStatus(m_BmpFile, fileStatus);
		if (fileExists) {
			CString msg = m_BmpFile + CString("は既存です。上書きしますか？");
			int mbRes = MessageBox(msg, "確認", MB_YESNO);
			if (mbRes != IDYES) {
				// キャンセル
				return;
			}
		}
	}

	if (m_bmpSaveAutoSw) {				//--------- オートの場合
		if (m_DirName == "") {
			MessageBox("出力の展開ディレクトリが指定されていません");
			return;
		}
		if (m_MainName == "") {
			MessageBox("出力ＢＭＰファイルの主ファイル名が指定されていません");
			return;
		}
	}
	else {							//------------ オートじゃない場合
		if (m_BmpFile == "") {
			MessageBox("出力するBMPファイル名が指定されていません");
			return;
		}
	}

	CRes res = ExecSaveBmpCnv(m_BmpFile, m_DirName, m_MainName, m_bmpSaveAutoSw, m_scriptBasePath, FALSE, SelectedPalBlock);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// CSVにオペレーションを追加
	CsvEntry entry(CSVCMD_SAVE_BMP_CNV);
	entry.AddParam(m_BmpFile, true);
	entry.AddParam(m_DirName, true);
	entry.AddParam(m_MainName, true);
	entry.AddParamBool(m_bmpSaveAutoSw);
	entry.AddParam(SelectedPalBlock);
	m_operationCsv.Add(entry);

	// 画面再描画
	MakeAllImages();
	DrawScreenAll();

	// 終了メッセージ
	MessageBox("BMPファイルを保存しました。");
}

/// <summary>
/// ×ボタンを押したときのイベントハンドラ
/// </summary>
void CSpconvDlg::OnClose()
{
	Release();
	CDialog::OnClose();
}

/// <summary>
/// 閉じるボタンを押したときのイベントハンドラ
/// </summary>
void CSpconvDlg::OnBnClickedCancel()
{
	Release();
	CDialog::OnCancel();
}

/// <summary>
/// PAL読み込みボタンを押したときのイベントハンドラ
/// </summary>
void CSpconvDlg::OnBnClickedButtonReadPal()
{
	// データ取り込み
	UpdateData();

	// 値チェック
	if (m_PalFile.GetLength() == 0) {
		MessageBox("パレットファイル名が指定されていません", "Error", MB_OK);
		return;
	}
	if ((m_palReadTo < 0) || (m_palReadTo > 16)) {
		CString message;
		message.Format("パレットの読み込み先のブロック番号が不正です。Block=[%d]", m_palReadTo);
		MessageBox(message, "Error", MB_OK);
		return;
	}
	if ((m_palReadTo + m_palReadCount) > 16) {
		m_palReadCount = 16 - m_palReadTo;
	}

	CRes res = ExecReadPalet(m_PalFile, m_palReadTo, m_palReadOffset, m_palReadCount, m_scriptBasePath);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// CSVにオペレーションを追加
	CsvEntry entry(CSVCMD_READ_PALET);
	entry.AddParam(m_PalFile, true);
	entry.AddParam(m_palReadTo);
	entry.AddParam(m_palReadOffset);
	entry.AddParam(m_palReadCount);
	m_operationCsv.Add(entry);

	// 画像を再構築して再描画する
	SelectedPalBlock = 0;					// 選択中のパレットブロックは０
	MakeAllImages();						// すべての画像を再構築する
	DrawScreenAll();										// 再描画

	// 値を画面に反映
	UpdateData(false);
}

/*
//-------------------------------------------< ＳＰ、ＰＡＬファイルを読み込み、画面に反映する >
void CSpconvDlg::OnView()
{
	int i, c, d;

	UpdateData();											// ダイアログの表示内容をメンバ変数へ格納
	for (i = 0; i < 16; i++) {
		for (c = 0; c < 16; c++) {
			pal_data[i][c] = 0;					// ＰＡＬデータをクリア
			for (d = 0; d < 128; d++) {
				sp_data[i][c][d] = 0;			// ＳＰデータをクリア
			}
		}
	}
	MakeSpImage();
	MakePalImage();
	DrawScreenAll();							// 一度初期画面で初期化

	FILE* stream;											// ファイルストリーム
	int res;												// 結果保持
	char tempstring[1024];									// 文字列表示用のバッファ
	// ＜ＳＰ読み込み＞
	if (m_SpFile.GetLength() == 0) {							// ファイル名が指定されていない
		MessageBox("ＳＰファイル名が指定されていません", "Error", MB_OK);
		MakeSpImage();										// ＳＰイメージを作る
		return;
	}
	stream = fopen((LPCTSTR)m_SpFile, "rb");							// ＳＰファイルオープン
	if (stream == 0) {											// オープン失敗の場合
		sprintf(tempstring, "[%s]が開けませんでした", (LPCTSTR)m_SpFile);
		MessageBox(tempstring, MB_OK);
		MakeSpImage();										// ＳＰイメージを作る
		return;
	}
	res = (int)fread(sp_data, (16 * 16) / 2, 256, stream);				// データの読み込み
	fclose(stream);
	MakeSpImage();										// ＳＰイメージを作る

	// ＜ＰＡＬ読み込み＞
	if (m_PalFile.GetLength() == 0) {
		MessageBox("パレットファイル名が指定されていません", "Error", MB_OK);
		MakePalImage();										// パレットイメージを作る
		return;
	}
	stream = fopen((LPCTSTR)m_PalFile, "rb");							// ＰＡＬファイルオープン
	if (stream == 0) {											// オープン失敗の場合
		sprintf(tempstring, "[%s]は開けませんでした", (LPCTSTR)m_PalFile);
		MessageBox(tempstring, "Error", MB_OK);
		MakePalImage();										// パレットイメージを作る
		return;
	}
	res = (int)fread(pal_data, 16 * 2, 16, stream);						// データの読み込み
	fclose(stream);
	MakeRGBTable();							// ＰＡＬデータからＲＧＢテーブルを作成する

	SelectedPalBlock = 0;					// 選択中のパレットブロックは０
	MakeSpImage();							// ＳＰイメージを作る
	MakePalImage();							// パレットイメージを作る
	DrawScreenAll();										// 再描画
}
*/

/// <summary>
/// ベースパスの参照ボタンのイベントハンドラ
/// </summary>
void CSpconvDlg::OnBnClickedButtonRefBasepath()
{
	UpdateData();
	CFolderPickerDialog folderDialog(m_scriptBasePath);

	// ダイアログ表示
	if (folderDialog.DoModal() == IDOK)
	{
		CString fullPathName = folderDialog.GetPathName();
		m_scriptBasePath = fullPathName;
		UpdateData(FALSE);

		// 再表示
		MakeCsvList();
	}
}

/// <summary>
/// 入力：SP スプライト読み込み
/// </summary>
void CSpconvDlg::OnBnClickedButtonReadSp()
{
	// 値取り込み
	UpdateData();

	// 確認
	if (m_SpFile.GetLength() == 0) {							// ファイル名が指定されていない
		MessageBox("ＳＰファイル名が指定されていません", "Error", MB_OK);
		return;
	}
	unsigned int spReadToDec = 0;
	m_spReadTo.MakeUpper();
	int count= sscanf((LPCTSTR)m_spReadTo, "%02X", &spReadToDec);
	if (count <= 0) {
		MessageBox("読込先は16進数で指定してください。");
		return;
	}
	if ((spReadToDec < 0) || (spReadToDec >= 256)) {
		MessageBox("読込先は0〜FFの範囲で指定してください。");
		return;
	}
	if ((m_spReadOffset < 0) || (m_spReadOffset >= 256)) {
		MessageBox("読込Offsetは0〜255の範囲で指定してください。");
		return;
	}
	if ((m_spAssumedPal < 0) || (m_spAssumedPal >= 16)) {
		MessageBox("Palは0〜15の範囲で指定してください。");
		return;
	}
	if ((m_spReadCount < 1) || (m_spReadCount > 256)) {
		MessageBox("個数は1〜256の範囲で指定してください。");
		return;
	}

	// SP読み込みを実行する
	CRes res = ExecReadSp(m_SpFile, spReadToDec, m_spReadOffset, m_spReadCount, m_spAssumedPal, m_scriptBasePath);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// CSVにオペレーションを追加
	CsvEntry entry(CSVCMD_READ_SP);
	entry.AddParam(m_SpFile, true);
	entry.AddParam(m_spReadTo, true);
	entry.AddParam(m_spReadOffset);
	entry.AddParam(m_spReadCount);
	entry.AddParam(m_spAssumedPal);
	m_operationCsv.Add(entry);

	// 描画する
	MakeAllImages();		// すべての画像を再構築する
	DrawScreenAll();		// 再描画
}

/// <summary>
/// SP定義からBMPに変換転送します
/// </summary>
/// <param name="spDefIndex"></param>
void CSpconvDlg::SpToBmp(int spDefIndex, int palIndex)
{
	// パレット全体を転送
	MakeTexturePalet();

	// パターンを転記
	int indexX = spDefIndex & 15;
	int indexY = spDefIndex / 16;
	int px = indexX * 16;
	int py = indexY * 16;

	CDC* pDC = GetDC();
	tximage->PrepareBitOperation();
	for (int y = 0; y < 16; y++) {
		for (int x = 0; x < 16; x++) {
			int code = spimage->GetPixelIndex(px + x, py + y);
			if (code != 0) {
				int a = 1;
			}
			int code256 = palIndex * 16 + code;
			tximage->SetPixelIndex(px + x, py + y, code256);
		}
	}
	tximage->EndBitOperation(pDC);
}

/// <summary>
/// BMP：ビットマップファイルの参照
/// </summary>
void CSpconvDlg::OnBnClickedButtonBmpFilenameRef()
{
	UpdateData(true);

	CFileDialog dlg(
		FALSE, "bmp", m_bmpBmpFilename, OFN_HIDEREADONLY | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST, "BMPファイル|*.bmp||"
	);
	if (dlg.DoModal() != IDOK) {						// ダイアログ表示
		return;
	}

	// OKが押された時の処理
	m_bmpBmpFilename = dlg.GetPathName();					// ファイルネーム取得
	UpdateData(false);
}

/// <summary>
/// BMP：SP読み込み
/// </summary>
void CSpconvDlg::OnBnClickedButtonBmpSpRead()
{
	UpdateData();

	int bmpSpReadToDec = 0;
	int scanCount = sscanf(m_bmpSpReadTo, "%02X", &bmpSpReadToDec);
	if (scanCount <= 0) {
		MessageBox("読み込み先は16進数2桁で入力してください。");
		return;
	}

	CRes res = ExecReadBmpSp(m_bmpBmpFilename, m_bmpSpSizeX, m_bmpSpSizeY
		, m_bmpSpFrameCount, bmpSpReadToDec, m_bmpSpReadOffset
		, m_bmpPalReadTo, m_bmpPalReadOffset, m_bmpPalReadCount
		, m_bmpPalShift, m_scriptBasePath
	);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// CSVにオペレーションを追加
	CsvEntry entry(CSVCMD_READ_BMP_SP);
	entry.AddParam(m_bmpBmpFilename, true);
	entry.AddParam(m_bmpSpSizeX);
	entry.AddParam(m_bmpSpSizeY);
	entry.AddParam(m_bmpSpFrameCount);
	entry.AddParam(m_bmpSpReadTo, true);
	entry.AddParam(m_bmpSpReadOffset);
	entry.AddParam(m_bmpPalReadTo);
	entry.AddParam(m_bmpPalReadOffset);
	entry.AddParam(m_bmpPalReadCount);
	entry.AddParamBool(m_bmpPalShift);
	m_operationCsv.Add(entry);

	// 画面再描画
	MakeAllImages();
	DrawScreenAll();
}

/// <summary>
/// BMP：Palだけ読み込み
/// </summary>
void CSpconvDlg::OnBnClickedButtonLoadbmp()
{
	UpdateData();

	CRes res = ExecReadBmpPal(m_bmpBmpFilename, m_bmpPalReadTo, m_bmpPalReadOffset, m_bmpPalReadCount, m_scriptBasePath);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// CSVにオペレーションを追加
	CsvEntry entry(CSVCMD_READ_BMP_PAL);
	entry.AddParam(m_bmpBmpFilename, true);
	entry.AddParam(m_bmpPalReadTo);
	entry.AddParam(m_bmpPalReadOffset);
	entry.AddParam(m_bmpPalReadCount);
	m_operationCsv.Add(entry);

	// 画面再描画
	MakeAllImages();
	DrawScreenAll();
}

/// <summary>
/// SP保存先ファイル名の指定
/// </summary>
void CSpconvDlg::OnBnClickedButtonSpSaveSpRef()
{
	UpdateData();

	CFileDialog dlg(
		FALSE, "sp", m_spSaveSpFilename, OFN_HIDEREADONLY | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST, "SPファイル|*.sp||"
	);

	if (dlg.DoModal() != IDOK) {						// ダイアログ表示
		return;
	}

	m_spSaveSpFilename = dlg.GetPathName();				// ファイルネーム取得

	UpdateData(false);
}

/// <summary>
/// PAL保存先ファイル名の指定
/// </summary>
void CSpconvDlg::OnBnClickedButtonSpSavePalRef()
{
	UpdateData();

	CFileDialog dlg(
		FALSE, "pal", m_spSavePalFilename, OFN_HIDEREADONLY | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST, "PALファイル|*.pal||"
	);

	if (dlg.DoModal() != IDOK) {						// ダイアログ表示
		return;
	}

	m_spSavePalFilename = dlg.GetPathName();				// ファイルネーム取得

	UpdateData(false);
}


/// <summary>
/// BMP保存
/// </summary>
void CSpconvDlg::OnBnClickedButtonBmpSaveFullcolorBmp()
{
	UpdateData(TRUE);									// データをメンバ変数へ取り込み

	if (m_BmpFile.GetLength() <= 0) {
		MessageBox("保存先のファイル名が指定されていません。");
		return;
	}

	// ファイル既存確認
	CFileStatus fileStatus;
	BOOL fileExists = CFile::GetStatus(m_BmpFile, fileStatus);
	if (fileExists) {
		CString msg = m_BmpFile + CString("は既存です。上書きしますか？");
		int mbRes = MessageBox(msg, "確認", MB_YESNO);
		if (mbRes != IDYES) {
			// キャンセル
			return;
		}
	}

	CRes res = ExecSaveBmpFul(m_BmpFile, m_scriptBasePath);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// CSVにオペレーションを追加
	CsvEntry entry(CSVCMD_SAVE_BMP_FUL);
	entry.AddParam(m_BmpFile, true);
	m_operationCsv.Add(entry);

	// 画面再描画
	MakeAllImages();
	DrawScreenAll();

	// 終了メッセージ
	MessageBox("BMPファイルを保存しました。");
}

/// <summary>
/// CSV保存先パスの参照ボタン
/// </summary>
void CSpconvDlg::OnBnClickedButtonScriptFilenameRef()
{
	UpdateData();

	CFileDialog dlg(
		FALSE, "csv", m_scriptFilename, OFN_HIDEREADONLY | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST, "CSVファイル|*.csv||"
	);

	if (dlg.DoModal() == IDOK) {						// ダイアログ表示
		m_scriptFilename = dlg.GetPathName();			// ファイルネーム取得
		UpdateData(false);
	}
}

/// <summary>
/// CSVを保存する
/// </summary>
void CSpconvDlg::OnBnClickedButtonSaveCsv()
{
	UpdateData();
	
	// ファイル名確認
	if (m_scriptFilename.GetLength() == 0) {
		MessageBox("CSVファイル名が指定されていません。");
		return;
	}

	CFileStatus fileStatus;
	BOOL fileExists = CFile::GetStatus(m_scriptFilename, fileStatus);
	if (fileExists) {
		CString msg = m_scriptFilename + CString("は既存です。上書きしますか？");
		int mbRes = MessageBox(msg, "確認", MB_YESNO);
		if (mbRes != IDYES) {
			// キャンセル
			return;
		}
	}

	// ファイルを開く
	FILE* fn = fopen(m_scriptFilename, "wt");
	if (fn == NULL) {
		MessageBox("CSVファイルを開けませんでした。");
		return;
	}

	// 1行目を書く
	CString str = m_csvList;
	str.Replace("\r\n", "\n");
	fprintf(fn, "%s,%s\n", CSVCMD_SET_BASEPATH, (LPCTSTR)m_scriptBasePath);
	fprintf(fn, "%s", (LPCTSTR)str);

	// ファイルを閉じる
	fclose(fn);

	MessageBox("CSVスクリプトを保存しました。");
}

/// <summary>
/// CSV一括読み込み
/// </summary>
void CSpconvDlg::OnBnClickedButtonReadCsv()
{
	CRes result;

	OnClear();
	UpdateData();

	// 事前確認
	if (m_scriptFilename.GetLength() <= 0) {
		MessageBox("CSVファイル名が入力されていません。");
		return;
	}

	// 上書き確認
	CFileStatus fileStatus;
	BOOL fileExists = CFile::GetStatus(m_scriptFilename, fileStatus);
	if (!fileExists) {
		CString msg = m_scriptFilename + CString("が見つかりませんでした。");
		MessageBox(msg);
		return;
	}

	// ファイルから取り込む
	m_operationCsv.RemoveAll();
	result = CsvEntry::FromFile(m_scriptFilename, m_operationCsv);
	if (!result.GetResult()) {
		CString msg;
		msg.Format("CSVファイルの読み込み・解釈に失敗しました。\r\n%s", (LPCTSTR)(result.GetMsg()));
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// ベースパス指定がある場合は、それを取り込む
	CString basePath = CsvEntry::AdjustAboutBasePath(m_operationCsv);
	if (!basePath.IsEmpty()) {
		m_scriptBasePath = basePath;
	}

	// CSVテキストを再構築
	m_csvList = CsvEntry::BuildCsvText(m_operationCsv);

	// コマンドリストを実行する
	result = ExecOperationCsv(m_operationCsv, m_scriptBasePath);
	if (result.GetResult() == FALSE) {
		MessageBox(result.GetMsg(), MB_OK);
	}

	// 画面更新
	MakeAllImages();
	DrawScreenAll();

	UpdateData(false);
}

/// <summary>
/// CSV実行
/// </summary>
/// <param name="operationCsv"></param>
CRes CSpconvDlg::ExecOperationCsv(CArray<CsvEntry>& operationCsv, CString basePath)
{
	// 1行ずつ処理する
	int line = 0;
	for (int i = 0; i < operationCsv.GetSize(); i++) {
		CsvEntry csvEntry = operationCsv.GetAt(i);
		line += 1;

		// コマンドごとに処理する
		CRes result = ExecOperationEntry(csvEntry, basePath);
		if (!result.GetResult()) {
			// エラーが発生した
			CString errorMessage;
			errorMessage.Format("%s\r\nline : %d", (LPCTSTR)(result.GetMsg()), line);
			return CRes::CreateError((LPCTSTR)errorMessage);
		}
	}

	// 正常終了
	MakeAllImages();
	DrawScreenAll();

	return CRes::CreateOk();
}

/// <summary>
/// CsvEntryを実行する
/// </summary>
/// <param name="entry"></param>
/// <returns></returns>
CRes CSpconvDlg::ExecOperationEntry(CsvEntry& entry, CString basePath)
{
	// コマンド取り込み
	CString command = CString(entry.command);

	// コマンドによって呼び分け
	CRes result = CRes::CreateOk();
	if (command.Compare(CSVCMD_NOP) == 0) {
		result = CRes::CreateOk();
	}
	if (command.Compare(CSVCMD_COMMENT) == 0) {
		// コメントは何もしない
		result = CRes::CreateOk();
	}
	else if (command.Compare(CSVCMD_ERROR) == 0) {
		result = CRes::CreateError("不明なエラー");
	}
	else if (command.Compare(CSVCMD_READ_PALET) == 0) {
		CString palFile = entry.GetParamStr(0);
		int palReadTo = entry.GetParamInt(1);
		int palReadOffset = entry.GetParamInt(2);
		int palReadCount = entry.GetParamInt(3);

		result = ExecReadPalet(palFile, palReadTo, palReadOffset, palReadCount, basePath);
	}
	else if (command.Compare(CSVCMD_READ_SP) == 0) {
		CString spFile = entry.GetParamStr(0);
		int spReadTo = entry.GetParamHex(1);
		int spReadOffset = entry.GetParamInt(2);
		int spReadCount = entry.GetParamInt(3);
		int spAssumedPal = entry.GetParamInt(4);

		result = ExecReadSp(spFile, spReadTo, spReadOffset, spReadCount, spAssumedPal, basePath);
	}
	else if (command.Compare(CSVCMD_READ_BMP_PAL) == 0) {
		CString bmpBmpFilename = entry.GetParamStr(0);
		int bmpPalReadTo = entry.GetParamInt(1);
		int bmpPalReadOffset = entry.GetParamInt(2);
		int bmpPalReadCount = entry.GetParamInt(3);

		result = ExecReadBmpPal(bmpBmpFilename, bmpPalReadTo, bmpPalReadOffset, bmpPalReadCount, basePath);
	}
	else if (command.Compare(CSVCMD_READ_BMP_SP) == 0) {
		CString bmpBmpFilename = entry.GetParamStr(0);
		int bmpSpSizeX = entry.GetParamInt(1);
		int bmpSpSizeY = entry.GetParamInt(2);
		int bmpSpFrameCount = entry.GetParamInt(3);
		int bmpSpReadTo = entry.GetParamHex(4);
		int bmpSpReadOffset = entry.GetParamInt(5);
		int bmpPalReadTo = entry.GetParamInt(6);
		int bmpPalReadOffset = entry.GetParamInt(7);
		int bmpPalReadCount = entry.GetParamInt(8);
		BOOL bmpPalShift = entry.GetParamBool(9);

		result = ExecReadBmpSp( bmpBmpFilename, bmpSpSizeX, bmpSpSizeY
			, bmpSpFrameCount, bmpSpReadTo, bmpSpReadOffset
			, bmpPalReadTo, bmpPalReadOffset, bmpPalReadCount
			, bmpPalShift, basePath
		);
	}
	else if (command.Compare(CSVCMD_SAVE_SP_PAL) == 0) {
		CString spSaveSpFilename = entry.GetParamStr(0);
		int spSaveSpFrom = entry.GetParamHex(1);
		int spSaveSpCount = entry.GetParamInt(2);
		CString spSavePalFilename = entry.GetParamStr(3);
		int spSavePalFrom = entry.GetParamInt(4);
		int spSavePalCount = entry.GetParamInt(5);

		result = ExecSaveSpPal(spSaveSpFilename, spSaveSpFrom, spSaveSpCount
			, spSavePalFilename, spSavePalFrom, spSavePalCount, basePath);
	}
	else if (command.Compare(CSVCMD_SAVE_BMP_CNV) == 0) {
		CString bmpFile = entry.GetParamStr(0);
		CString dirName = entry.GetParamStr(1);
		CString mainName = entry.GetParamStr(2);
		BOOL bmpSaveAutoSw = entry.GetParamBool(3);
		int selectedPalBlock = entry.GetParamInt(4);

		result = ExecSaveBmpCnv(bmpFile, dirName, mainName, bmpSaveAutoSw, basePath, FALSE, selectedPalBlock);
	}
	else if (command.Compare(CSVCMD_SAVE_BMP_CNV256) == 0) {
		CString bmpFile = entry.GetParamStr(0);
		CString dirName = entry.GetParamStr(1);
		CString mainName = entry.GetParamStr(2);
		BOOL bmpSaveAutoSw = entry.GetParamBool(3);

		result = ExecSaveBmpCnv(bmpFile, dirName, mainName, bmpSaveAutoSw, basePath, TRUE, SelectedPalBlock);
	}
	else if (command.Compare(CSVCMD_SAVE_BMP_FUL) == 0) {
		CString bmpFile = entry.GetParamStr(0);

		result = ExecSaveBmpFul(bmpFile, basePath);
	}
	else if (command.Compare(CSVCMD_SET_BASEPATH) == 0) {
		CString basePath = entry.GetParamStr(0);
		m_scriptBasePath = basePath;
		result = CRes::CreateOk();
	}

	// 結果を返す
	return result;
}

// ReadPaletを実行
CRes CSpconvDlg::ExecReadPalet(CString palFile, int palReadTo, int palReadOfset, int palReadCount, CString basePath)
{
	CString filepath = JoinBasePath(palFile, basePath);

	// 読み込み先と件数の確定
	WORD* pReadTo = (WORD*)(pal_data[palReadTo]);

	// PAL読み込み
	FILE* stream = fopen((LPCTSTR)filepath, "rb");			// ＰＡＬファイルオープン
	if (stream == 0) {										// オープン失敗の場合
		CString message;
		message.Format("[%s]は開けませんでした", (LPCTSTR)filepath);
		return CRes::CreateError(message);
	}

	// オフセットの分だけ読み捨て
	char buffer[16 * 16 * 2];
	memset(buffer, 0, sizeof(buffer));
	int readCount = (int)fread(buffer, 16 * 2, palReadOfset, stream);

	// データ読み込み
	readCount = (int)fread(pReadTo, 16 * 2, palReadCount, stream);
	fclose(stream);

	return CRes::CreateOk();
}

// ReadSp
CRes CSpconvDlg::ExecReadSp(CString spFile, int spReadToDec, int spReadOffset, int spReadCount, int spAssumedPal, CString basePath)
{
	CString filepath = JoinBasePath(spFile, basePath);

	// ファイルオープン
	FILE* stream = fopen((LPCTSTR)filepath, "rb");							// ＳＰファイルオープン
	if (stream == 0) {											// オープン失敗の場合
		CString message;
		message.Format("[% s]が開けませんでした", (LPCTSTR)filepath);
		return CRes::CreateError(message);
	}

	// 読み込む
	int indexX = spReadToDec & 15;
	int indexY = spReadToDec / 16;
	char* pReadTo = sp_data[indexY][indexX];
	int sprCount = 0;
	// Offsetだけスキップする
	for (int i = 0; i < spReadOffset; i++) {
		// 読み捨て
		int result = (int)fread(pReadTo, (16 * 16) / 2, 1, stream);
	}
	// 読み込む
	for (int i = 0; i < spReadCount; i++) {
		// 読み込み先の最大インデックスのクリッピング
		if ((spReadToDec + i) > 255) { break; }
		// 読み込み
		int result = (int)fread(pReadTo, (16 * 16) / 2, 1, stream);
		if (result == 0) { break; }	// EOF
		pReadTo += (16 * 16) / 2;
		sprCount += 1;
	}

	// ファイルを閉じる
	fclose(stream);

	// 画像を作る
	MakeSpImage();			// ＳＰイメージを作る
	for (int i = 0; i < sprCount; i++) {
		if ((spReadToDec + i) >= 256) { break; }
		SpToBmp(spReadToDec + i, spAssumedPal);
	}

	// 転送
	TranslateSpToBmp(spReadToDec, spReadToDec + spReadCount - 1, spAssumedPal);

	return CRes::CreateOk();
}

// ReadBmpPal
CRes CSpconvDlg::ExecReadBmpPal(CString bmpBmpFilename, int bmpPalReadTo, int bmpPalReadOffset, int bmpPalReadCount, CString basePath)
{
	// 
	// ファイルを開く
	//
	CString filename = JoinBasePath(bmpBmpFilename, basePath);
	CFileStatus bmpFileStatus;
	BOOL fileExists = CFile::GetStatus(filename, bmpFileStatus);
	if (!fileExists) {
		CString msg = CString("指定されたファイルを開けませんでした。") + CString(filename) + CString("]");
		return CRes::CreateError(msg);
	}

	// bmpを読み込む
	CDC* pDC = GetDC();
	Cfbmp bmp(filename, pDC);
	if ((bmp.GetColorDepth() != 4) && (bmp.GetColorDepth() != 8)) {
		CString msg = CString("16色か256色のBMPを指定してください。");
		return CRes::CreateError(msg);
	}

	// BitOperation開始
	tximage->PrepareBitOperation();

	// 画像からパレットを取り込む
	{
		int pal_block_count = (1 << bmp.GetColorDepth()) / 16;
		WORD bmp_pal_data[16][16];
		memset(bmp_pal_data, 0, sizeof(bmp_pal_data));
		for (int i = 0; i < pal_block_count * 16; i++) {
			RGBQUAD quad = bmp.GetPalet(i);
			int r = (int)((32.0 * (double)(quad.rgbRed)) / 256.0);
			int g = (int)((32.0 * (double)(quad.rgbGreen)) / 256.0);
			int b = (int)((32.0 * (double)(quad.rgbBlue)) / 256.0);
			WORD pal = (g << 11) + (r << 6) + (b << 1) + 0;	// 輝度ビットは0
			pal = ((pal >> 8) & 255) + ((pal << 8) & 0xFF00);	// リトルエンディアンにする

			bmp_pal_data[i / 16][i & 15] = pal;
		}

		// パレットを転送する
		int toBlock = bmpPalReadTo;
		int readBlockMax = (bmpPalReadOffset + bmpPalReadCount - 1);
		if (readBlockMax >= 16) { readBlockMax = 15; }
		for (int i = bmpPalReadOffset; i <= readBlockMax; i++) {
			for (int c = 0; c < 16; c++) {
				tximage->SetPalet((toBlock * 16) + c, bmp.GetPalet((i * 16) + c));
				pal_data[toBlock][c] = bmp_pal_data[i][c];
			}
			toBlock++;
			if (toBlock >= 16) { break; }
		}
	}

	// BitOperation終了
	tximage->EndBitOperation(pDC);

	// リソース解放
	ReleaseDC(pDC);
	return CRes::CreateOk();
}

// ReadBmpSp
CRes CSpconvDlg::ExecReadBmpSp(
	CString bmpBmpFilename, int bmpSpSizeX, int bmpSpSizeY, int bmpSpFrameCount,
	int bmpSpReadTo, int bmpSpReadOffset, int bmpPalReadTo, int bmpPalReadOffset, int bmpPalReadCount,
	BOOL bmpPalShift, CString basePath)
{
	// 
	// ファイルを開く
	//
	CString filename = JoinBasePath(bmpBmpFilename, basePath);
	CFileStatus bmpFileStatus;
	BOOL fileExists = CFile::GetStatus(filename, bmpFileStatus);
	if (!fileExists) {
		CString msg = CString("指定されたファイルを開けませんでした。") + CString(filename) + CString("]");
		return CRes::CreateError(msg);
	}

	// bmpを読み込む
	CDC* pDC = GetDC();
	Cfbmp bmp(filename, pDC);
	if ((bmp.GetColorDepth() != 4) && (bmp.GetColorDepth() != 8)) {
		return CRes::CreateError("16色か256色のBMPを指定してください。");
	}

	// BitOperation開始
	tximage->PrepareBitOperation();

	// スプライトの情報を整理する
	int sheetXCount = bmp.GetWidth() / (bmpSpSizeX * 16);
	int sheetYCount = bmp.GetHeight() / (bmpSpSizeY * 16);

	// 取り込み処理
	int processedFrames = 0;
	int maxFrameIndex = bmpSpReadOffset + bmpSpFrameCount - 1;
	for (int py = 0; py < bmp.GetHeight(); py += (bmpSpSizeY * 16)) {
		for (int px = 0; px < bmp.GetWidth(); px += (bmpSpSizeX * 16)) {
			// オフセット処理
			if (processedFrames < bmpSpReadOffset) {
				// オフセットしたフレームまで処理をスキップ
				processedFrames++;
				continue;
			}

			// 処理するフレームすべて終わったら終了
			if (processedFrames > maxFrameIndex) { break; }

			// パターンのSPサイズ分を展開
			for (int cy = 0; cy < bmpSpSizeY; cy++) {
				for (int cx = 0; cx < bmpSpSizeX; cx++) {
					int sourceX = px + (cx * 16);
					int sourceY = py + (cy * 16);

					// BMP取り込み
					int idx = bmpSpReadTo	// 読み込み先インデックス
							+ ((processedFrames-bmpSpReadOffset) * (bmpSpSizeX * bmpSpSizeY))	// すでに処理したSPの数
							+ (cy * bmpSpSizeX + cx);	// 当該のフレームのSP分のインデックス
					int idxX = idx & 15;
					int idxY = idx / 16;

					// パレット番号をシフトするなら、その補正をする
					int palOffset = 0;
					if (bmpPalShift) {
						palOffset = (bmpPalReadTo * 16) - (bmpPalReadOffset * 16);	// 読み込み先と、読み込みOffsetを考慮する
					}

					// 一つ分のSPを処理する
					for (int y = 0; y < 16; y++) {
						for (int x = 0; x < 16; x++) {
							int colCode = bmp.GetPixelIndex(sourceX + x, sourceY + y);
							int adjustedCode = colCode + palOffset;
							if ((adjustedCode < 0) || (adjustedCode >= 256) || (bmpPalShift == false)) {
								adjustedCode = colCode;
							}
							tximage->SetPixelIndex(idxX * 16 + x, idxY * 16 + y, adjustedCode);
						}
					}
				}
			}

			// 1フレーム分完了
			processedFrames++;
		}
	}

	// BitOperation終了
	tximage->EndBitOperation(pDC);

	// リソース解放
	ReleaseDC(pDC);

	// BMPからSPにパターンを転写する
	int transSpCount = (bmpSpSizeX * bmpSpSizeY) * (sheetXCount * sheetYCount);
	int toIndex = bmpSpReadTo + transSpCount - 1;
	if (toIndex >= 256) { toIndex = 255; }
	TranslateBmpToSp(bmpSpReadTo, toIndex);

	return CRes::CreateOk();
}

// SaveSpPal
CRes CSpconvDlg::ExecSaveSpPal(CString spSaveSpFilename, int spSaveSpFromDec, int spSaveSpCount
	, CString spSavePalFilename, int spSavePalFrom, int spSavePalCount, CString basePath)
{
	// ファイル指定有無を確認
	if (spSaveSpFilename.GetLength() == 0) {
		return CRes::CreateError("SPファイルの出力先が指定されていません。");
	}
	if (spSavePalFilename.GetLength() == 0) {
		return CRes::CreateError("PALファイルの出力先が指定されていません。");
	}

	CString spFilepath = JoinBasePath(spSaveSpFilename, basePath);
	CString palFilepath = JoinBasePath(spSavePalFilename, basePath);

	char* pSpTop = ((char*)sp_data) + (spSaveSpFromDec * 128);
	int spSSC = spSaveSpCount;
	if ((spSaveSpFromDec + spSaveSpCount) > 256) {
		spSSC = 256 - spSaveSpFromDec;
	}

	// SPファイルを保存
	FILE* fn;
	fn = fopen((LPCTSTR)spFilepath, "wb");
	if (fn == NULL) {
		CString message;
		message.Format("SPファイルを開けませんでした。FilePath = %s\n", spFilepath);
		return CRes::CreateError(message);
	}
	fwrite((void*)pSpTop, (16 * 16 / 2), spSSC, fn);
	fclose(fn);

	// PALの先頭アドレスと個数を確定させる
	char* pPalTop = ((char*)pal_data) + (spSavePalFrom * 16 * 2);
	int spSPC = spSavePalCount;
	if ((spSavePalFrom + spSavePalCount) > 16) {
		spSPC = 16 - spSavePalFrom;
	}

	// PALファイルを保存
	fn = fopen((LPCTSTR)palFilepath, "wb");
	if (fn == NULL) {
		CString message;
		message.Format("PALファイルを開けませんでした。FilePath = %s\n", palFilepath);
		return CRes::CreateError(message);
	}
	fwrite((void*)pPalTop, 2 * 16, spSPC, fn);
	fclose(fn);

	return CRes::CreateOk();
}

// SaveBmpCnv
CRes CSpconvDlg::ExecSaveBmpCnv(CString bmpFile, CString dirName, CString mainName, BOOL bmpSaveAutoSw, CString basePath, BOOL indexedColor, int selectedPalBlock)
{
	// パレットブロックを再選択
	SelectedPalBlock = selectedPalBlock;		// パレットブロックを設定
	//MakeSpImage();								// ＳＰイメージを作る
	MakeAllImages();
	DrawScreenAll();

	dirName = JoinBasePath(dirName, basePath);

	if (bmpSaveAutoSw) {				//--------- オートの場合
		if (dirName == "") {
			return CRes::CreateError("出力の展開ディレクトリが指定されていません");
		}
		if (mainName == "") {
			return CRes::CreateError("出力ＢＭＰファイルの主ファイル名が指定されていません");
		}
	}
	else {							//------------ オートじゃない場合
		if (bmpFile == "") {
			return CRes::CreateError("出力するBMPファイル名が指定されていません");
		}
	}

	if (bmpSaveAutoSw) {				//--------- オートの場合
		int i;
		int oldPal = SelectedPalBlock;
		for (i = 0; i < 16; i++) {
			char tempstring[3];					// 番号を作る
			tempstring[0] = '0' + (i + 1) / 10;
			tempstring[1] = '0' + (i + 1) % 10;
			tempstring[2] = 0;
			CString temp, full;
			temp = mainName + tempstring + ".bmp";		// ファイル名を作る
			full = MakeFullPathName(dirName, temp);		// フルパスネームを作る

			SelectedPalBlock = i;						// パレットブロックを設定
			//MakeSpImage();								// ＳＰイメージを作る
			MakeAllImages();
			DrawScreenAll();							// 全体を描き換える
			SaveBmp(full, indexedColor);								// ＢＭＰをセーブする
		}
		SelectedPalBlock = oldPal;						// パレットを元に戻して
		//MakeSpImage();									// イメージを再構築して
		MakeAllImages();
		DrawScreenAll();								// 描き換えておわり
	}
	else {							//------------ オートじゃない場合
		CString filepath = JoinBasePath(bmpFile, basePath);
		SaveBmp(filepath, indexedColor);								// ＢＭＰ書き込み
	}

	return CRes::CreateOk();
}

// SaveBmpFul
CRes CSpconvDlg::ExecSaveBmpFul(CString bmpFile, CString basePath)
{
	if (bmpFile.GetLength() <= 0) {
		return CRes::CreateError("保存先のファイル名が指定されていません。");
	}

	// 保存
	MakeAllImages();
	DrawScreenAll();
	CString filepath = JoinBasePath(bmpFile, basePath);
	CString filepathMain = filepath.Left(filepath.GetLength() - 4);
	CString filepath_a = filepathMain + "_a.bmp";

	BOOL result = doSave(filepath, tximage);
	if (!result) {
		CRes res = CRes::CreateError("BMPファイルの保存に失敗しました。");
		return res;
	}

	result = doSaveStencil(filepath_a, tximage);
	if (!result) {
		CRes res = CRes::CreateError("StencilBMPファイルの保存に失敗しました。");
		return res;
	}

	return CRes::CreateOk();
}

// JoinBasePath
CString CSpconvDlg::JoinBasePath(CString filename, CString basePath)
{
	// filenameが空ならそのまま
	if (filename.GetLength() == 0) {
		return filename;
	}

	// basePathの指定がなければfilenameそのまま
	if (basePath.IsEmpty()) {
		return filename;
	}

	// filenameがフルパスならそのまま
	if (filename.GetAt(1) == ':') {
		return filename;
	}
	if (filename.GetAt(0) == '\\') {
		return filename;
	}

	// basepathの末尾に \ をつける
	basePath = basePath + "\\";
	basePath.Replace("\\\\", "\\");

	// filenameと結合する
	CString result = basePath + filename;

	// 結果を返す
	return result;
}

void CSpconvDlg::OnBnClickedButtonExecCsv()
{
	UpdateData();

	// クリアしてから実行
	OnClear();

	// テキストからリストを構築する
	CArray<CsvEntry> operationCsv;
	CRes res = CsvEntry::FromCsvText(m_csvList, operationCsv);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// 構築に成功したら実行
	CsvEntry::FromCsvText(m_csvList, m_operationCsv);

	// 実行する
	res = ExecOperationCsv(m_operationCsv, m_scriptBasePath);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// 実行終了
	MakeAllImages();
	DrawScreenAll();
	UpdateData(false);
}


void CSpconvDlg::OnEnKillfocusEditCsvlist()
{
	UpdateData();

	// テキストからリストを構築する
	CArray<CsvEntry> operationCsv;
	CRes res = CsvEntry::FromCsvText(m_csvList, operationCsv);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// 構築に成功したら実行
	CsvEntry::FromCsvText(m_csvList, m_operationCsv);

	// 再描画
	MakeAllImages();
	DrawScreenAll();
}


void CSpconvDlg::OnBnClickedButtonSave256()
{
	UpdateData(TRUE);									// データをメンバ変数へ取り込み

	// ファイル既存確認
	if (!m_bmpSaveAutoSw) {
		CFileStatus fileStatus;
		BOOL fileExists = CFile::GetStatus(m_BmpFile, fileStatus);
		if (fileExists) {
			CString msg = m_BmpFile + CString("は既存です。上書きしますか？");
			int mbRes = MessageBox(msg, "確認", MB_YESNO);
			if (mbRes != IDYES) {
				// キャンセル
				return;
			}
		}
	}

	if (m_bmpSaveAutoSw) {				//--------- オートの場合
		if (m_DirName == "") {
			MessageBox("出力の展開ディレクトリが指定されていません");
			return;
		}
		if (m_MainName == "") {
			MessageBox("出力ＢＭＰファイルの主ファイル名が指定されていません");
			return;
		}
	}
	else {							//------------ オートじゃない場合
		if (m_BmpFile == "") {
			MessageBox("出力するBMPファイル名が指定されていません");
			return;
		}
	}

	CRes res = ExecSaveBmpCnv(m_BmpFile, m_DirName, m_MainName, m_bmpSaveAutoSw, m_scriptBasePath, TRUE, SelectedPalBlock);
	if (!res.GetResult()) {
		MessageBox(res.GetMsg());
		MakeAllImages();
		DrawScreenAll();
		return;
	}

	// CSVにオペレーションを追加
	CsvEntry entry(CSVCMD_SAVE_BMP_CNV256);
	entry.AddParam(m_BmpFile, true);
	entry.AddParam(m_DirName, true);
	entry.AddParam(m_MainName, true);
	entry.AddParamBool(m_bmpSaveAutoSw);
	m_operationCsv.Add(entry);

	// 画面再描画
	MakeAllImages();
	DrawScreenAll();

	// 終了メッセージ
	MessageBox("BMPファイルを保存しました。");
}
