//******************************************************************************
//
// OpenGL Utility / OGLTexture
//
// テクスチャクラス
//
// Copyright (C) 2010-2012 WADA Masashi. All Rights Reserved.
//
//******************************************************************************

#import "YNBaseLib.h"
#import "OGLTexture.h"


//##############################################################################
// テクスチャクラス
//##############################################################################
//******************************************************************************
// コンストラクタ
//******************************************************************************
OGLTexture::OGLTexture(void)
{
	m_Target = GL_TEXTURE_2D;
	m_isLoaded = false;
	m_TextureId = 0;
	m_Width = 0;
	m_Height = 0;
	
	m_pBitmapImage = nil;
	m_CFDataRef = NULL;
}

//******************************************************************************
// デストラクタ
//******************************************************************************
OGLTexture::~OGLTexture(void)
{
	Release();
}

//******************************************************************************
// 任意画像サイズ有効化：初期値 false
//******************************************************************************
//void OGLTexture::EnableRectanbleExt(
//		bool isEnable
//	)
//{
//	m_Target = GL_TEXTURE_RECTANGLE_EXT;
//}

//******************************************************************************
// 画像ファイル読み込み
//******************************************************************************
int OGLTexture::LoadImageFile(
		NSString* pImageFilePath
	)
{
	int result = 0;
	
	//画像ファイル読み込み
	m_pBitmapImage = [UIImage imageWithContentsOfFile:pImageFilePath];
	if (m_pBitmapImage == nil) {
		result = YN_SET_ERR(@"Bitmap file open error.", 0, 0);
		goto EXIT;
	}
	
	//ビットマップからテクスチャ作成
	result = LoadBitmap(m_pBitmapImage);
	if (result != 0) goto EXIT;
	
EXIT:;
	return result;
}

//******************************************************************************
// ビットマップ読み込み
//******************************************************************************
int OGLTexture::LoadBitmap(
		UIImage* pBitmapImage
	)
{
	int result = 0;
	GLenum glresult = 0;
	GLenum pixelDataFormat = 0;
	CGImageRef cgImageRef = NULL;
	size_t bitsPerPixel = 0;
	size_t bytesPerRow = 0;
	CGDataProviderRef dataProviderRef = NULL;
	UInt8* pBitmapData = NULL;

	if (pBitmapImage == nil) {
		result = YN_SET_ERR(@"Program error.", 0, 0);
		goto EXIT;
	}
	
	Release();
	
	//Quartzイメージを参照
	cgImageRef = pBitmapImage.CGImage;
	
	//画像サイズを取得
	m_Width = CGImageGetWidth(cgImageRef);
	m_Height = CGImageGetHeight(cgImageRef);
	
	//画像属性を取得
	bitsPerPixel = CGImageGetBitsPerPixel(cgImageRef),
	bytesPerRow = CGImageGetBytesPerRow(cgImageRef);
	
	//ビットマップデータのコピーを作成
	dataProviderRef = CGImageGetDataProvider(cgImageRef);
	m_CFDataRef = CGDataProviderCopyData(dataProviderRef);
	pBitmapData = (UInt8*)CFDataGetBytePtr(m_CFDataRef);
	
	if ((m_Width > OGL_TEXTURE_IMAGE_MAX_WIDTH) 
	 || (m_Height > OGL_TEXTURE_IMAGE_MAX_HEIGHT)) {
		result = YN_SET_ERR(@"Bitmap size is too large.", m_Width, m_Height);
		goto EXIT;
	}
	
	//ピクセルデータフォーマット確認
	if (bitsPerPixel == 24) {
		//24bitカラー
		pixelDataFormat = GL_RGB;
	}
	else if (bitsPerPixel == 32) {
		//24bitカラー＋8bitアルファ
		pixelDataFormat = GL_RGBA;
	}
	else {
		result = YN_SET_ERR(@"Unsupported bitmap format.", bitsPerPixel, 0);
		goto EXIT;
	}
	
	//テクスチャ有効
	glEnable(m_Target);
	
	//テクスチャID生成
	glGenTextures(1, &m_TextureId);
	if ((glresult = glGetError()) != GL_NO_ERROR) {
		result = YN_SET_ERR(@"OpenGL API error.", glresult, 0);
		goto EXIT;
	}
	
	//テクスチャバインド
	glBindTexture(m_Target, m_TextureId);
	
	//テクスチャ画像を登録
	glTexImage2D(
			m_Target,			//ターゲット
			0,					//詳細レベル：ベースイメージレベル
			pixelDataFormat,	//色要素数
			m_Width,			//幅
			m_Height,			//高さ
			0,					//ボーダー幅
			pixelDataFormat,	//ピクセルデータフォーマット
			GL_UNSIGNED_BYTE,	//ピクセルデータタイプ
			pBitmapData			//画像データ
		);
	if ((glresult = glGetError()) != GL_NO_ERROR) {
		result = YN_SET_ERR(@"OpenGL API error.", glresult, 0);
		goto EXIT;
	}
	
	//テクスチャ無効化
	glDisable(m_Target);
	
	m_isLoaded = true;
	
EXIT:;
	return result;
}

//******************************************************************************
// 破棄
//******************************************************************************
void OGLTexture::Release()
{
	if (m_isLoaded) {
		glDeleteTextures(1, &m_TextureId);
		m_isLoaded = false;
		m_TextureId = 0;
	}
	m_Width = 0;
	m_Height = 0;
	
	if (m_CFDataRef != NULL) {
		CFRelease(m_CFDataRef);
		m_CFDataRef = NULL;
	}
	
	//破棄するとエラーが発生する
	//[m_pBitmapImage release];
	m_pBitmapImage = nil;
	
	return;
}

//******************************************************************************
// テクスチャサイズ取得：幅
//******************************************************************************
GLsizei OGLTexture::GetWidth()
{
	return m_Width;
}

//******************************************************************************
// テクスチャサイズ取得：高さ
//******************************************************************************
GLsizei OGLTexture::GetHeight()
{
	return m_Height;
}

//******************************************************************************
// テクスチャ描画開始処理
//******************************************************************************
void OGLTexture::BindTexture()
{
	//テクスチャ繰り返し無効（有効にする場合はGL_REPEAT）
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	
	//この設定がないとテクスチャが描画されない
	//テクスチャ拡大縮小方式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,  GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,  GL_LINEAR);
	
	if (m_isLoaded) {
		//テクスチャ有効化
		glEnable(m_Target);
		//テクスチャ登録
		glBindTexture(m_Target, m_TextureId);
	}
}

//******************************************************************************
// テクスチャ描画終了処理
//******************************************************************************
void OGLTexture::UnbindTexture()
{
	if (m_isLoaded) {
		//テクスチャ無効化
		glDisable(m_Target);
	}
}


