//
//  GTNLIB for VC++
//
#include "stdafx.h"
#include "cfbmp.h"


//-------------------------------------------------------<< 初期化 >>
Cfbmp::Cfbmp()										// デフォルトコンストラクタ
{
	isSet=FALSE;						// 何もデータはセットされていない。
	isBitOperating=FALSE;				// ビット配列の操作中ではない
}

Cfbmp::Cfbmp(LPCTSTR fname,CDC* pDC)				// ファイル名指定コンストラクタ
{
	isSet=FALSE;						// とりあえず...
	isBitOperating=FALSE;				// ビット配列の操作中ではない
	Load(fname,pDC);					// こいつにまかせる
}

Cfbmp::Cfbmp( int SizeX , int SizeY , int BitDepth , CDC* pDC )	// サイズ、ビット深度指定コンストラクタ
{
	isSet=FALSE;						// とりあえず...
	isBitOperating=FALSE;				// ビット配列の操作中ではない

//							<< ビット配列のサイズを計算 >>
	UINT uSizeImage;
	uSizeImage = (SizeX*BitDepth)/8;								// 横方向バイト数
	uSizeImage += ( 4-(uSizeImage&3) )&3;							// ４バイト境界調整
	uSizeImage *= SizeY;											// 高さをかけて全体のサイズ

//							<< Bitmap File Header 作成 >>
	UINT nColors = 1<<BitDepth;
	UINT QuadSize;
	if( BitDepth>=24 )QuadSize=0;
	else QuadSize=sizeof(RGBQUAD)*nColors;

	bmfh.bfType = 0x4d42;
	bmfh.bfSize = sizeof( BITMAPINFOHEADER )+sizeof( BITMAPFILEHEADER )
		+QuadSize+uSizeImage;
	bmfh.bfReserved1 = 0;
	bmfh.bfReserved2 = 0;
	bmfh.bfOffBits = sizeof( BITMAPINFOHEADER )+sizeof( BITMAPFILEHEADER )
		+QuadSize;

//							<< Bitmap Info Header 作成 >>
	bmih.biSize = sizeof( BITMAPINFOHEADER );
	bmih.biWidth = SizeX;
	bmih.biHeight = SizeY;
	bmih.biPlanes = 1;
	bmih.biBitCount = BitDepth;
	bmih.biCompression = 0;
	bmih.biSizeImage = uSizeImage;
	bmih.biXPelsPerMeter = 0;
	bmih.biYPelsPerMeter = 0;
	bmih.biClrUsed = 0;
	bmih.biClrImportant = 0;

//							<< フルカラーかどうか >>
	if( BitDepth>=24 )isFullColor = TRUE;
	else isFullColor = FALSE;


//							<< BITMAPINFO を作成する >>
	if(bmih.biClrUsed!=0)nColors=bmih.biClrUsed;
	else nColors=1 << bmih.biBitCount;

	if(bmih.biBitCount<24)
	{	// フルカラーでない場合
		lpbmi=(LPBITMAPINFO)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*nColors);
		lpbmi->bmiHeader=bmih;
	}
	else
	{	// フルカラーの場合
		lpbmi=(LPBITMAPINFO)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD));
		lpbmi->bmiHeader=bmih;
	}

//							<< ハンドルの作成 >>
																	// BMP作成
	lpBits=(void*)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,uSizeImage);	// DIBバッファ確保
	memset( lpBits , 0 , uSizeImage );								// ０で画像を初期化

	hBmp=CreateDIBitmap(pDC->m_hDC,&bmih,CBM_INIT,lpBits,lpbmi,DIB_RGB_COLORS);	// ハンドル作成
	if(hBmp==NULL){										// 失敗！
		GlobalFree(lpBits);			// DIBバッファ解放
		GlobalFree((HGLOBAL)lpbmi);	// メモリ解放
		return;
	}

//							<< パレットハンドル作成 >>
	if(!isFullColor){						// フルカラーじゃない場合のみ。
		lpLogPal=(LPLOGPALETTE)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*nColors);

		lpLogPal->palVersion=0x300;
		lpLogPal->palNumEntries=nColors;
		for(UINT i=0;i<nColors;i++){
			lpLogPal->palPalEntry[i].peRed=lpbmi->bmiColors[i].rgbRed;
			lpLogPal->palPalEntry[i].peGreen=lpbmi->bmiColors[i].rgbGreen;
			lpLogPal->palPalEntry[i].peBlue=lpbmi->bmiColors[i].rgbBlue;
		}

	hPal=CreatePalette(lpLogPal);			// パレットハンドル作成
	}

	isSet=TRUE;					// セット完了
	return;				// 正常終了
}

Cfbmp::~Cfbmp()										// デストラクタ
{
	Free();								// メモリの解放
}


//---------------------------------------------------------<< 操作 >>
//---------------------------------------------------<< ファイル名指定で、データをロード >>
BOOL Cfbmp::Load(LPCTSTR fname,CDC* pDC)
{
	Free();								// データが読み込まれている場合、まず破棄する

//							<< ヘッダ関連の処理 >>
	BOOL bResult;						// ブール値での結果格納
	DWORD dwRead;
	HANDLE hFile;						// ファイルハンドル

	// ファイルオープン
	hFile=CreateFile(fname,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if(hFile == NULL)return FALSE;				// ファイルオープン失敗

	// ビットマップファイルヘッダ読み込み
	dwRead=0;
	bResult=ReadFile(hFile,&bmfh,sizeof(BITMAPFILEHEADER),&dwRead,NULL);
	if(bResult==FALSE||bmfh.bfType!=0x4D42){	// ビットマップファイルじゃない？！
		CloseHandle(hFile);
		return FALSE;
	}

	// ビットマップインフォヘッダ読み込み
	if(ReadFile(hFile,&bmih,sizeof(BITMAPINFOHEADER),&dwRead,NULL)==FALSE){
		CloseHandle(hFile);
		return FALSE;							// インフォヘッダ読めない？！
	}

//							<< パレット関連の処理 >>
	UINT nColors;								// 色数

	if(bmih.biClrUsed!=0)nColors=bmih.biClrUsed;
	else nColors=1 << bmih.biBitCount;

	// パレットインデックスの場合
	if(bmih.biBitCount<24)
	{
		isFullColor=FALSE;						// フルカラーじゃない
		lpbmi=(LPBITMAPINFO)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*nColors);
		lpbmi->bmiHeader=bmih;
		if(ReadFile(hFile,&(lpbmi->bmiColors),sizeof(RGBQUAD)*nColors,&dwRead,NULL)==FALSE){
			CloseHandle(hFile);
			GlobalFree((HGLOBAL)lpbmi);
			return FALSE;
		}
	}
	// フルカラーの場合
	else
	{
		isFullColor=TRUE;						// フルカラーだ
		lpbmi=(LPBITMAPINFO)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD));
		lpbmi->bmiHeader=bmih;
	}



//							<< ハンドルの作成 >>
																	// BMP作成
	UINT uSizeImage;												// サイズ計算
	uSizeImage = GetWidthByte()*bmih.biHeight;

	lpBits=(void*)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,uSizeImage);	// DIBバッファ確保

	if(ReadFile(hFile,lpBits,uSizeImage,&dwRead,NULL)==FALSE){	// データ読み込み
		CloseHandle(hFile);			// ファイルハンドル閉じる
		GlobalFree(lpBits);			// DIBバッファ解放
		GlobalFree((HGLOBAL)lpbmi);	// メモリ解放
		return FALSE;
	}
	hBmp=CreateDIBitmap(pDC->m_hDC,&bmih,CBM_INIT,lpBits,lpbmi,DIB_RGB_COLORS);	// ハンドル作成
	if(hBmp==NULL){										// 失敗！
		CloseHandle(hFile);			// ファイルハンドル閉じる
		GlobalFree(lpBits);			// DIBバッファ解放
		GlobalFree((HGLOBAL)lpbmi);	// メモリ解放
		return FALSE;
	}
	CloseHandle(hFile);									// ファイルクローズ


//							<< パレットハンドル作成 >>
	if(!isFullColor){						// フルカラーじゃない場合のみ。
		lpLogPal=(LPLOGPALETTE)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*nColors);

		lpLogPal->palVersion=0x300;
		lpLogPal->palNumEntries=nColors;
		for(UINT i=0;i<nColors;i++){
			lpLogPal->palPalEntry[i].peRed=lpbmi->bmiColors[i].rgbRed;
			lpLogPal->palPalEntry[i].peGreen=lpbmi->bmiColors[i].rgbGreen;
			lpLogPal->palPalEntry[i].peBlue=lpbmi->bmiColors[i].rgbBlue;
		}

	hPal=CreatePalette(lpLogPal);			// パレットハンドル作成
	}

	isSet=TRUE;					// セット完了
	return TRUE;				// 正常終了
}


//---------------------------------------------------<< サイズ、ビット深度指定のイニシャライザ >>
BOOL Cfbmp::Initialize( int SizeX , int SizeY , int BitDepth , CDC* pDC )
{
	Free();
	isSet=FALSE;						// とりあえず...

//							<< ビット配列のサイズを計算 >>
	UINT uSizeImage;												// サイズ計算
	uSizeImage = (SizeX*BitDepth)/8;								// 横方向バイト数
	uSizeImage += ( 4-(uSizeImage&3) )&3;							// ４バイト境界調整
	uSizeImage *= SizeY;											// 高さをかけて全体のサイズ

//							<< Bitmap File Header 作成 >>
	UINT nColors = 1<<BitDepth;
	UINT QuadSize;
	if( BitDepth>=24 )QuadSize=0;
	else QuadSize=sizeof(RGBQUAD)*nColors;

	bmfh.bfType = 0x4d42;
	bmfh.bfSize = sizeof( BITMAPINFOHEADER )+sizeof( BITMAPFILEHEADER )
		+QuadSize+uSizeImage;
	bmfh.bfReserved1 = 0;
	bmfh.bfReserved2 = 0;
	bmfh.bfOffBits = sizeof( BITMAPINFOHEADER )+sizeof( BITMAPFILEHEADER )
		+QuadSize;

//							<< Bitmap Info Header 作成 >>
	bmih.biSize = sizeof( BITMAPINFOHEADER );
	bmih.biWidth = SizeX;
	bmih.biHeight = SizeY;
	bmih.biPlanes = 1;
	bmih.biBitCount = BitDepth;
	bmih.biCompression = 0;
	bmih.biSizeImage = uSizeImage;
	bmih.biXPelsPerMeter = 0;
	bmih.biYPelsPerMeter = 0;
	bmih.biClrUsed = 0;
	bmih.biClrImportant = 0;

//							<< フルカラーかどうか >>
	if( BitDepth>=24 )isFullColor = TRUE;
	else isFullColor = FALSE;


//							<< BITMAPINFO を作成する >>
	if(bmih.biClrUsed!=0)nColors=bmih.biClrUsed;
	else nColors = 1<<bmih.biBitCount;

	if(bmih.biBitCount<24)
	{	// フルカラーでない場合
		lpbmi=(LPBITMAPINFO)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*nColors);
		lpbmi->bmiHeader=bmih;
	}
	else
	{	// フルカラーの場合
		lpbmi=(LPBITMAPINFO)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD));
		lpbmi->bmiHeader=bmih;
	}

//							<< ハンドルの作成 >>
																	// BMP作成
	lpBits=(void*)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,uSizeImage);	// DIBバッファ確保
	memset( lpBits , 0 , uSizeImage );								// ０で画像を初期化

	hBmp=CreateDIBitmap(pDC->m_hDC,&bmih,CBM_INIT,lpBits,lpbmi,DIB_RGB_COLORS);	// ハンドル作成
	if(hBmp==NULL){										// 失敗！
		GlobalFree(lpBits);			// DIBバッファ解放
		GlobalFree((HGLOBAL)lpbmi);	// メモリ解放
		return FALSE;
	}

//							<< パレットハンドル作成 >>
	if(!isFullColor){						// フルカラーじゃない場合のみ。
		lpLogPal=(LPLOGPALETTE)GlobalAlloc(GMEM_DISCARDABLE|GMEM_ZEROINIT,sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*nColors);

		lpLogPal->palVersion=0x300;
		lpLogPal->palNumEntries=nColors;
		for(UINT i=0;i<nColors;i++){
			lpLogPal->palPalEntry[i].peRed=lpbmi->bmiColors[i].rgbRed;
			lpLogPal->palPalEntry[i].peGreen=lpbmi->bmiColors[i].rgbGreen;
			lpLogPal->palPalEntry[i].peBlue=lpbmi->bmiColors[i].rgbBlue;
		}

	hPal=CreatePalette(lpLogPal);			// パレットハンドル作成
	}

	isSet=TRUE;					// セット完了
	return TRUE;				// 正常終了
}


//---------------------------------------------------<< 画像をセーブする >>
BOOL Cfbmp::Save(LPCTSTR fname)
{
	if( isReady()==FALSE )return FALSE;				// 画像が準備できていなければエラー

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

	fwrite( GetBMFH(),sizeof(BITMAPFILEHEADER),1,stream);	// BITMAPFILEHEADER書き込み
	fwrite( GetBMIH(),sizeof(BITMAPINFOHEADER),1,stream);	// BITMAPINFOHEADER書き込み
	if( GetColorDepth()<24 ){								// インデックスカラーの場合は
																		// RGBQUADを出力
		RGBQUAD quad;
		int nColors;
		nColors=1<<GetColorDepth();										// 色数を計算
		for( int i=0;i<nColors;i++ ){
			quad = GetPalet(i);											// パレット取得
			fwrite( &quad,sizeof(RGBQUAD),1,stream );					// 書き込み
		}
	}

	int SizeImage;														// ビット配列のサイズを計算
	SizeImage = GetWidthByte()*GetHeight();
	fwrite( GetLPBits(),SizeImage,1,stream );						// ビット配列書き込み

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

	return TRUE;													// 正常終了
}


//---------------------------------------------------<< 透過画像をセーブする >>
BOOL Cfbmp::SaveStencil(LPCTSTR fname)
{
	if (isReady() == FALSE)return FALSE;				// 画像が準備できていなければエラー

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

	// ビット配列のサイズを計算
	UINT uSizeImage;
	uSizeImage = (this->GetWidth() * 32) / 8;	// 横方向バイト数（32bit固定）
	uSizeImage += (4 - (uSizeImage & 3)) & 3;		// ４バイト境界調整
	uSizeImage *= this->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 = this->GetWidth();
	bmih.bV4Height = this->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 = this->GetHeight() - 1; y >= 0; y--) {
		for (int x = 0; x < this->GetWidth(); x++) {
			int palIndex = this->GetPixelIndex(x, y);
			RGBQUAD quad = this->GetPixelColor(x, y);
			int mask = (1 << GetColorDepth()) - 1;

			if ((palIndex & mask) == 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;
}


//---------------------------------------------------<< 画像を破棄する >>
void Cfbmp::Free()
{
	if(isSet==FALSE)return;					// データが読まれてなければキャンセル

	if( isBitOperating==FALSE ){			// ビット直接操作中でなければ
		DeleteObject(hBmp);						// ＢＭＰ解放
	}
	if(!isFullColor){						// パレット解放
		if( isBitOperating==FALSE )DeleteObject(hPal);
		GlobalFree((HGLOBAL)lpLogPal);
	}
	GlobalFree(lpBits);
	GlobalFree((HGLOBAL)lpbmi);
	isSet=FALSE;
}

//---------------------------------------------------<< 指定ＤＣの指定位置に指定範囲で描画 >>
void Cfbmp::FrameDraw(CPoint& src,CRect& dist,CDC *pDC)
{
	if(isSet==FALSE)return;						// データは準備されていない。

	CDC memDC;									// メモリＤＣ
	memDC.CreateCompatibleDC(pDC);				// コンパチブル設定

	CBitmap *tempbmp;
	tempbmp=CBitmap::FromHandle(hBmp);			// 一時的なCBitmapObjectを作成
	memDC.SelectObject(tempbmp);				// メモリＤＣに選択

	if(!isFullColor){							// フルカラーでなければパレットをrealize
		pDC->SelectPalette(CPalette::FromHandle(hPal),FALSE);
		pDC->RealizePalette();
	}

	pDC->BitBlt(dist.left,dist.top				// 描画！
		,abs(dist.right-dist.left)+1,abs(dist.bottom-dist.top)+1
		,&memDC,src.x,src.y,SRCCOPY);
}


//---------------------------------------------------<< 単純に描画 >>
void Cfbmp::NormalDraw(CPoint& dist,CDC *pDC)
{
	if(isSet==FALSE)return;						// データは準備されていない。

	CDC memDC;									// メモリＤＣ
	memDC.CreateCompatibleDC(pDC);				// コンパチブル設定

	CBitmap *tempbmp;
	tempbmp=CBitmap::FromHandle(hBmp);			// 一時的なCBitmapObjectを作成
	memDC.SelectObject(tempbmp);				// メモリＤＣに選択

	if(!isFullColor){							// フルカラーでなければパレットをrealize
		pDC->SelectPalette(CPalette::FromHandle(hPal),FALSE);
		pDC->RealizePalette();
	}

	pDC->BitBlt(dist.x,dist.y,bmih.biWidth,bmih.biHeight	// 描画！
		,&memDC,0,0,SRCCOPY);
}



//--------------------------<< 指定ＤＣの指定位置に指定部分を指定サイズにリサイズして描画 >>
void Cfbmp::StretchDraw(CRect& src,CRect& dist,CDC *pDC)
{
	if(isSet==FALSE)return;						// データは準備されていない。

	CDC memDC;									// メモリＤＣ
	memDC.CreateCompatibleDC(pDC);				// コンパチブル設定

	CBitmap *tempbmp;
	tempbmp=CBitmap::FromHandle(hBmp);			// 一時的なCBitmapObjectを作成
	memDC.SelectObject(tempbmp);				// メモリＤＣに選択

	if(!isFullColor){						// フルカラーでなければパレットをrealize
		pDC->SelectPalette(CPalette::FromHandle(hPal),FALSE);
		pDC->RealizePalette();
	}

	pDC->StretchBlt(dist.left,dist.top			// 描画！
		,abs(dist.right-dist.left)+1,abs(dist.bottom-dist.top)+1
		,&memDC
		,src.left,src.top
		,abs(src.right-src.left)+1,abs(src.bottom-src.top)+1
		,SRCCOPY);
}


//-----------------------------------------------------------------<< 画像の幅を返す >>
int Cfbmp::GetWidth()
{
	if(isSet==FALSE)return 0;			// 画像が読まれていなければ０
	return bmih.biWidth;				// 画像の幅
}


//-----------------------------------------------------------------<< 画像の高さを返す >>
int Cfbmp::GetHeight()
{
	if(isSet==FALSE)return 0;			// 画像が読まれていなければ０
	return bmih.biHeight;				// 画像の高さ
}


//-----------------------------------------------------------------<< カラーデプスを返す >>
int Cfbmp::GetColorDepth()
{
	if(isSet==FALSE)return 0;			// 画像が読まれていなければ０
	return bmih.biBitCount;				// 画像のビットデプス
}

//-----------------------------------------------------------------<< 色数を返す >>
int Cfbmp::GetColorNum()
{
	if(isSet==FALSE)return 0;			// 画像が読まれていなければ０
	return 1<<bmih.biBitCount;			// 画像の色数
}


//-----------------------------------------------------------------<< 画像のサイズを返す >>
CSize Cfbmp::GetSize()
{
	if(isSet==FALSE)return CSize(0,0);			// 画像が読まれていなければ０
	CSize result;
	result.cx=bmih.biWidth;		// 幅セット
	result.cy=bmih.biHeight;		// 高さセット
	return result;					// サイズを返す
}


//-------------------------------------------------------------<< ＢＭＰハンドルを返す >>
HBITMAP Cfbmp::GetBmpHandle()
{
	if(isSet == FALSE)return(0);
	if(isBitOperating)return(0);			// ビット操作中なら０を返す
	else return(hBmp);
}


//-------------------------------------------------------------<< BITMAPFILEHEADERへのポインタを返す >>
BITMAPFILEHEADER* Cfbmp::GetBMFH()
{
	return &bmfh;
}


//-------------------------------------------------------------<< BITMAPINFOHEADERへのポインタを返す >>
BITMAPINFOHEADER* Cfbmp::GetBMIH()
{
	return &bmih;
}


//-------------------------------------------------------------<< ビット配列へのポインタを返す >>
void* Cfbmp::GetLPBits()
{
	return lpBits;
}

//-------------------------------------------------<< ＢＭＰ表示の準備ができているか否か >>
BOOL Cfbmp::isReady()
{
	return isSet;
}

//-------------------------------------------------<< ビットオペレーション中か否か >>
BOOL Cfbmp::isBitOpe()
{
	return isBitOperating;
}


//----------------------------------------------------------<< 指定 index のパレットを返す >>
RGBQUAD Cfbmp::GetPalet( int index )
{
	RGBQUAD quad;
	memset( &quad , 0 , sizeof(RGBQUAD) );
	if( isReady()==FALSE )return quad;						// 準備できていないなら0を返す

	int colors = 1<<bmih.biBitCount;					// 色数計算
	if( bmih.biBitCount>=24 )return quad;				// フルカラーなら0を返す
	if( index >= colors )return quad;					// index が間違っているなら0を返す

	return lpbmi->bmiColors[index];
}


//--------------------------------------------<< 指定位置のピクセルのパレットコードを返す >>
RGBQUAD Cfbmp::GetPixelColor( int x, int y )
{
	int cy;
	cy = bmih.biHeight-y-1;				// ボトムアップの換算

	RGBQUAD quad;
	memset( &quad , 0 , sizeof(RGBQUAD) );
	if( isReady()==FALSE )return quad;					//準備できていないなら0を返す
	if( x >= bmih.biWidth )return quad;					// クリッピング
	if( y >= bmih.biHeight)return quad;
	if( x<0 )return quad;
	if( y<0 )return quad;

	int colors=1<<bmih.biBitCount;						// 色数計算


	if( bmih.biBitCount>=24 ){							// フルカラーの場合
		int offset;									// オフセットを計算
		offset = (GetWidthByte()*cy) + ((x*bmih.biBitCount)/8);

		BYTE *work;									// 色を算出
		work = ((BYTE*)lpBits)+offset;
		quad.rgbRed   = *(work+2);
		quad.rgbGreen = *(work+1);
		quad.rgbBlue  = *(work+0);
		return quad;
	}
														// ２５６色の場合
	if( bmih.biBitCount==8 ){
		int offset;									// オフセットを計算
		offset = (GetWidthByte()*cy) + ((x*bmih.biBitCount)/8);

		BYTE *work;									// 色を算出
		work = ((BYTE*)lpBits)+offset;
		return GetPalet( *work );
	}

	if( bmih.biBitCount==4 ){							// １６色の場合
		int offset,uplow;								// オフセット、upper か lowerか
		offset = (GetWidthByte()*cy) + ((x*bmih.biBitCount)/8);
		uplow  = ( (bmih.biWidth*cy)+x )&1;

		BYTE *work;									// 色を算出
		work = ((BYTE*)lpBits)+offset;
		if( uplow )return GetPalet( (*work)&15 );
		else return	GetPalet( (*work)/16 );
	}

	return quad;										// サポートしていないビットマップは0を返す
}


//--------------------------------------------<< 指定位置のピクセルのインデックスを返す >>
//  フルカラーだった場合は -1(Error) を返す
int Cfbmp::GetPixelIndex( int x, int y )
{
	if( isReady()==FALSE )return -1;					//準備できていないなら0を返す
	if( x >= bmih.biWidth )return -1;					// クリッピング
	if( y >= bmih.biHeight)return -1;
	if( x<0 )return -1;
	if( y<0 )return -1;
	if( bmih.biBitCount==24 )return -1;					// フルカラーならエラー

	int cy;
	cy = bmih.biHeight-y-1;				// ボトムアップの換算

	if( bmih.biBitCount==8 ){						// ２５６色の場合
		int offset;									// オフセットを計算
		offset = (GetWidthByte()*cy) + ((x*bmih.biBitCount)/8);

		BYTE *work;									// ポイントを算出
		work = ((BYTE*)lpBits)+offset;
		return *work;
	}

	if( bmih.biBitCount==4 ){							// １６色の場合
		int offset,uplow;								// オフセット、upper か lowerか
		offset = (GetWidthByte()*cy) + ((x*bmih.biBitCount)/8);
		uplow  = ( (bmih.biWidth*cy)+x )&1;

		BYTE *work;									// ポイントを算出
		work = ((BYTE*)lpBits)+offset;
		if( uplow )return (*work)&15;
		else return	((*work)/16)&15;
	}

	return -1;										// サポートしていないビットマップは-1を返す
}



//-------------------------------------------<< ビット配列の直接操作の準備をする >>
void Cfbmp::PrepareBitOperation()
{
	if( isReady()==FALSE )return;						// 画像が準備できていなければ返る
	if( isBitOperating )return;							// すでに準備ができているなら何もしない

	DeleteObject( hBmp );								// ＢＭＰハンドルを解放するのです。
	if( !isFullColor )DeleteObject( hPal );				// パレットハンドルも解放する
	isBitOperating=TRUE;								// ビット配列の直接操作の準備完了
}


//-------------------------------------------<< ビット配列の直接操作を終了する >>
void Cfbmp::EndBitOperation(CDC* pDC)
{
	if( isReady()==FALSE )return;						// 画像が準備できていないなら返る
	if( isBitOperating==FALSE )return;					// ビットの直接操作中でなければ返る

	hBmp=CreateDIBitmap(pDC->m_hDC,&bmih,CBM_INIT,lpBits,lpbmi,DIB_RGB_COLORS);	// ハンドル作成
	if( !isFullColor )hPal=CreatePalette(lpLogPal);		// パレットハンドル作成
	isBitOperating=FALSE;								// ビットの直接操作中ではないことを示す
}


//----------------------------------------------------------<< 指定 index にパレットを設定する >>
void Cfbmp::SetPalet( int index , RGBQUAD& quad )
{
	if( isReady()==FALSE )return;						// 準備できていないなら0を返す
	if( isBitOperating==FALSE )return;					// ビット操作の準備ができてないなら返る
	if( bmih.biBitCount>=24 )return;

	int colors = 1<<bmih.biBitCount;					// 色数計算
	if( index >= colors )return;						// index が間違っているなら0を返す

	lpbmi->bmiColors[index] = quad;						// 色を設定

	lpLogPal->palPalEntry[index].peRed  =quad.rgbRed;	// log palette にも設定
	lpLogPal->palPalEntry[index].peGreen=quad.rgbGreen;
	lpLogPal->palPalEntry[index].peBlue =quad.rgbBlue;

	return;
}


//-------------------------------------------<< 指定位置にピクセルを置く（フルカラーの時のみ） >>
BOOL Cfbmp::SetPixelColor( int x, int y , RGBQUAD& quad )
{
	if( isReady()==FALSE )return FALSE;						// 準備できてなければ返る
	if( isBitOperating==FALSE )return FALSE;			// ビット操作の準備ができてないなら返る
	if( bmih.biBitCount!=24 )return FALSE;				// フルカラーじゃなければ返る

	int cy;
	cy = bmih.biHeight-y-1;				// ボトムアップの換算

	if( isReady()==FALSE )return FALSE;					//準備できていないならFALSEを返す
	if( x >= bmih.biWidth )return FALSE;					// クリッピング
	if( y >= bmih.biHeight)return FALSE;
	if( x<0 )return FALSE;
	if( y<0 )return FALSE;

	int offset;									// オフセットを計算
		offset = (GetWidthByte()*cy) + ((x*bmih.biBitCount)/8);

	BYTE *work;									// 色を配置
	work = ((BYTE*)lpBits)+offset;
	*(work+2) = quad.rgbRed;
	*(work+1) = quad.rgbGreen;
	*(work+0) = quad.rgbBlue;

	return TRUE;										// 正常終了
}


//-------------------------------------------<< 指定位置にピクセルを置く（インデックスのみ） >>
BOOL Cfbmp::SetPixelIndex( int x, int y , int col )
{
	if( isReady()==FALSE )return FALSE;					// 準備できてなければ返る
	if( isBitOperating==FALSE )return FALSE;			// ビット配列の直接操作の準備ができていなければ返る
	if( bmih.biBitCount==24 )return FALSE;				// フルカラーはダメ
	if( bmih.biBitCount<  4 )return FALSE;				// １６色より少ないのもダメ（２色とか）

	int cy;
	cy = bmih.biHeight-y-1;				// ボトムアップの換算

	if( x >= bmih.biWidth )return FALSE;					// クリッピング
	if( y >= bmih.biHeight)return FALSE;
	if( x<0 )return FALSE;
	if( y<0 )return FALSE;

										// ２５６色の場合
	if( bmih.biBitCount==8 ){
		int offset;									// オフセットを計算
		offset = (GetWidthByte()*cy) + ((x*bmih.biBitCount)/8);

		BYTE *work;									// ポインタの位置を算出
		work = ((BYTE*)lpBits)+offset;
		*work = col;								// 色を配置

		return TRUE;
	}

	if( bmih.biBitCount==4 ){							// １６色の場合
		int offset,uplow;								// オフセット、upper か lowerか
		offset = (GetWidthByte()*cy) + ((x*bmih.biBitCount)/8);
		uplow  = ( (bmih.biWidth*cy)+x )&1;

		BYTE *work;									// 色を算出
		work = ((BYTE*)lpBits)+offset;
		BYTE temp;
		temp = *work;
		if( uplow ){								// 上の４ビット
			temp &= 0xF0;
			temp |= col&0x0F;
			*work = temp;
			return TRUE;
		} else {									// 下の４ビット
			temp &= 0x0F;
			temp |= (col<<4)&0xF0;
			*work = temp;
			return TRUE;
		}
	}

	return FALSE;										// ここまで来る筈はない。
														// bmih.biBitCountの値に誤りがある可能性がある
}


//-------------------------------------------<< 指定位置にピクセルを置く（インデックスのみ） >>
UINT Cfbmp::GetWidthByte()
{
	UINT res;
	res = (bmih.biWidth*bmih.biBitCount)/8;							// 横方向バイト数
	res += ( 4-(res&3) )&3;											// ４バイト境界調整
	return res;														// 結果を返す
}
