//******************************************************************************
//
// MIDITrail / MTMainViewCtrl
//
// メインビュー制御クラス
//
// Copyright (C) 2012-2019 WADA Masashi. All Rights Reserved.
//
//******************************************************************************

#import "YNBaseLib.h"
#import "MTMainViewCtrl.h"


//******************************************************************************
// プライベートメソッド定義
//******************************************************************************
@interface MTMainViewCtrl ()

// OpneGLコンテキスト初期化
- (int)initializeOpenGLContext;

// OpneGLコンテキスト破棄
- (void)terminateOpenGLContext;

//シーン描画
- (void)drawScene:(NSTimer*)timer;

//シーケンサメッセージ処理
- (int)sequencerMsgProc;

//描画処理
- (int)drawProc;

//演奏状態変更通知受信処理
- (int)postPlayStatus:(NSString*)pNotificationName;

//FPS更新
- (void)updateFPS:(uint64_t)startTime;

//タップ
- (void)onTapped;

//通知送信処理
- (int)postNotificationWithName:(NSString*)pName;

//全アイテム非表示
- (void)hideAllItems;

//ボタン表示状態更新
- (void)updateButtonStatus;

//タッチガイド画像表示状態更新
-(void)updateGuideImageStatus;

//デバイス方向更新
- (int)updateDeviceDirection;

//ゲンームコントローラー接続制御
- (void)onGameControllerDidConnect;
- (void)onGameControllerDidDisconnect;
- (void)selectGameController;
- (void)initializeGameController;

//ゲームコントローラーボタンイベントハンドラ
- (void)onGamePadPauseButtonOnController:(GCController*)pController;
- (void)onGamePadButtonAChanged:(GCControllerButtonInput*)pButtonInput
						  value:(float)value
					  isPressed:(BOOL)isPressed;
- (void)onGamePadButtonBChanged:(GCControllerButtonInput*)pButtonInput
						  value:(float)value
					  isPressed:(BOOL)isPressed;
- (void)onGamePadButtonL1Changed:(GCControllerButtonInput*)pButtonInput
						   value:(float)value
					   isPressed:(BOOL)isPressed;
- (void)onGamePadButtonL2Changed:(GCControllerButtonInput*)pButtonInput
						   value:(float)value
					   isPressed:(BOOL)isPressed;
- (void)onGamePadButtonR1Changed:(GCControllerButtonInput*)pButtonInput
						   value:(float)value
					   isPressed:(BOOL)isPressed;
- (void)onGamePadButtonR2Changed:(GCControllerButtonInput*)pButtonInput
						   value:(float)value
					   isPressed:(BOOL)isPressed;

@end


@implementation MTMainViewCtrl

//******************************************************************************
// 生成
//******************************************************************************
- (id)initWithNibName:(NSString *)nibNameOrNil
			   bundle:(NSBundle *)nibBundleOrNil
		rendererParam:(OGLRedererParam)rendererParam
{
	int result = 0;
	NSString* pDeviceType = nil;
	NSString* pNibNameHowToView = nil;
	NSString* pPathImgButtonPlayN = nil;
	NSString* pPathImgButtonPlayH = nil;
	NSString* pPathImgButtonPauseN = nil;
	NSString* pPathImgButtonPauseH = nil;
	NSNotificationCenter* pCenter = nil;
	
	//メンバ初期化
	m_ScreenWidth = 0;
	m_ScreenHeight = 0;
	m_pEAGLContext = nil;
	m_MSAAFrameBuffer = 0;
	m_DefaultFrameBuffer = 0;
	m_DefaultColorRenderBuffer = 0;
	m_DefaultDepthRenderBuffer = 0;
	m_MSAAColorRenderBuffer = 0;
	m_MSAADepthRenderBuffer = 0;
	m_Timer = nil;
	m_pScene = NULL;
	m_pMsgQueue = NULL;
	m_isStopScene = false;
	m_LastTouchTime = 0;
	m_PrevDrawTime = 0;
	m_FlameCount = 0.0f;
	m_PrevTouchPoint.x = 0;
	m_PrevTouchPoint.y = 0;
	m_TounchesTotalDistance = 0;
	m_isDisplayButtons = YES;
	m_isMonitor = false;
	m_ScreenType = MTScene::StandardView;
    m_isScreenLocked = false;
	
	//レンダリングパラメータ
	m_RendererParam = rendererParam;
	
	//バンドル初期化
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
		//OpenGLコンテキスト初期化
		result = [self initializeOpenGLContext];
		if (result != 0) YN_SHOW_ERR();
    }
	
	//デバイス種別
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
		//iPhone / iPod touch
		pDeviceType = @"iPhone";
    } else {
		//iPad
		pDeviceType = @"iPad";
    }
	
	//Nibファイル名称
	pNibNameHowToView = [NSString stringWithFormat:@"MTHowToView_%@", pDeviceType];
	
	//ビュー制御生成
	m_pHowToViewCtrl = [[MTHowToViewCtrl alloc] initWithNibName:pNibNameHowToView bundle:nil];
	
	//画像ファイルパス
	pPathImgButtonPlayN  = [NSString stringWithFormat:@"img/%@/Button-Play-N", pDeviceType];
	pPathImgButtonPlayH  = [NSString stringWithFormat:@"img/%@/Button-Play-H", pDeviceType];
	pPathImgButtonPauseN = [NSString stringWithFormat:@"img/%@/Button-Pause-N", pDeviceType];
	pPathImgButtonPauseH = [NSString stringWithFormat:@"img/%@/Button-Pause-H", pDeviceType];
	
	//画像読み込み
	m_pImgButtonPlayN  = [[UIImage imageNamed:pPathImgButtonPlayN] retain];
	m_pImgButtonPlayH  = [[UIImage imageNamed:pPathImgButtonPlayH] retain];
	m_pImgButtonPauseN = [[UIImage imageNamed:pPathImgButtonPauseN] retain];
	m_pImgButtonPauseH = [[UIImage imageNamed:pPathImgButtonPauseH] retain];
	
	//デバイスモーション管理
	m_pMotionManager = [[CMMotionManager alloc] init];
	
	//ゲームコントローラ制御
	m_pGameController = nil;
	m_ButtonA_PrevValue = 0.0f;
	m_ButtonB_PrevValue = 0.0f;
	m_ButtonL1_PrevValue = 0.0f;
	m_ButtonL2_PrevValue = 0.0f;
	m_ButtonR1_PrevValue = 0.0f;
	m_ButtonR2_PrevValue = 0.0f;
	
	//ゲームコントローラー接続/切断通知先登録
	pCenter = [NSNotificationCenter defaultCenter];
	[pCenter addObserver:self
				selector:@selector(onGameControllerDidConnect)
					name:GCControllerDidConnectNotification
				  object:nil];
	[pCenter addObserver:self
				selector:@selector(onGameControllerDidDisconnect)
					name:GCControllerDidDisconnectNotification
				  object:nil];
	
	return self;
}

//******************************************************************************
// 破棄
//******************************************************************************
- (void)dealloc
{
	[m_pImgButtonPlayN release];
	[m_pImgButtonPlayH release];
	[m_pImgButtonPauseN release];
	[m_pImgButtonPauseH release];
	
	//ビュー破棄
	[m_pHowToViewCtrl release];
	
	//OpenGLコンテキスト破棄
	[self terminateOpenGLContext];
	
	[super dealloc];
	
	return;
}

//******************************************************************************
// OpneGLコンテキスト初期化
//******************************************************************************
- (int)initializeOpenGLContext
{
	int result = 0;
	CAEAGLLayer* pEAGLLayer = NULL;
	CGRect frame;
	
	//解像度係数を設定：retinaの場合は2.0
	m_pBaseView.contentScaleFactor = [UIScreen mainScreen].scale;	//retina対応
	
	//現在のビューのサイズを確認する
	frame = self.view.frame;
	frame.origin = CGPointZero;
	
	//CAEAGLレイヤー作成
	pEAGLLayer = [CAEAGLLayer layer];
	pEAGLLayer.frame = frame;
	pEAGLLayer.contentsScale = [UIScreen mainScreen].scale;	//retina対応
	
	//縦横サイズを覚えておく
	m_ScreenWidth = frame.size.width * [UIScreen mainScreen].scale;		//retina対応
	m_ScreenHeight = frame.size.height * [UIScreen mainScreen].scale;	//retina対応
	
	//CAEAGLレイヤー：不透明
	pEAGLLayer.opaque = YES;
	//CAEAGLレイヤー：プロパティ
	pEAGLLayer.drawableProperties =
					[NSDictionary dictionaryWithObjectsAndKeys:
						//描画結果保存：しない
						[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
						//描画カラーフォーマット：各色8bit
						kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
					nil];
	
	//EAGLコンテキスト生成：OpenGL ES 1.1
	m_pEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
	[EAGLContext setCurrentContext:m_pEAGLContext];
	
	//--------------------------------------------------
	// デフォルトのフレームバッファとレンダーバッファを作成
	//--------------------------------------------------
	//フレームバッファ作成
	glGenFramebuffersOES(1, &m_DefaultFrameBuffer);
	glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_DefaultFrameBuffer);
	
	//色レンダーバッファ作成
	glGenRenderbuffersOES(1, &m_DefaultColorRenderBuffer);
	glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_DefaultColorRenderBuffer);

	//EAGLコンテキストにストレージ割り当て
	[m_pEAGLContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:pEAGLLayer];
	
	//色レンダーバッファをフレームバッファにアタッチ
	glFramebufferRenderbufferOES(
						GL_FRAMEBUFFER_OES,
						GL_COLOR_ATTACHMENT0_OES,
						GL_RENDERBUFFER_OES,
						m_DefaultColorRenderBuffer);
	
	//深度レンダーバッファ作成
	glGenRenderbuffersOES(1, &m_DefaultDepthRenderBuffer);
	glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_DefaultDepthRenderBuffer);
	glRenderbufferStorageOES(
						GL_RENDERBUFFER_OES,
						GL_DEPTH_COMPONENT16_OES,
						m_ScreenWidth,
						m_ScreenHeight);
	
	//深度レンダーバッファをフレームバッファにつなぐ
	glFramebufferRenderbufferOES(
						GL_FRAMEBUFFER_OES,
						GL_DEPTH_ATTACHMENT_OES,
						GL_RENDERBUFFER_OES,
						m_DefaultDepthRenderBuffer);
	
	//--------------------------------------------------
	// MSAA用のフレームバッファとレンダーバッファを作成
	//--------------------------------------------------
	if (m_RendererParam.isEnableAntialiasing) {
		//フレームバッファ生成
		glGenFramebuffersOES(1, &m_MSAAFrameBuffer);
		glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_MSAAFrameBuffer);
		
		//色レンダーバッファ生成
		glGenRenderbuffersOES(1, &m_MSAAColorRenderBuffer);
		glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_MSAAColorRenderBuffer);
		glRenderbufferStorageMultisampleAPPLE(
							GL_RENDERBUFFER_OES,
							m_RendererParam.sampleNum, //サンプル数
							GL_RGBA8_OES,
							m_ScreenWidth,
							m_ScreenHeight);
		
		//色レンダーバッファをフレームバッファにつなぐ
		glFramebufferRenderbufferOES(
							GL_FRAMEBUFFER_OES,
							GL_COLOR_ATTACHMENT0_OES,
							GL_RENDERBUFFER_OES,
							m_MSAAColorRenderBuffer);
		
		//深度レンダーバッファ作成
		glGenRenderbuffersOES(1, &m_MSAADepthRenderBuffer);
		glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_MSAADepthRenderBuffer);
		glRenderbufferStorageMultisampleAPPLE(
							GL_RENDERBUFFER_OES,
							m_RendererParam.sampleNum, //サンプル数
							GL_DEPTH_COMPONENT16_OES,
							m_ScreenWidth,
							m_ScreenHeight);
		
		//深度レンダーバッファをフレームバッファにつなぐ
		glFramebufferRenderbufferOES(
							GL_FRAMEBUFFER_OES,
							GL_DEPTH_ATTACHMENT_OES,
							GL_RENDERBUFFER_OES,
							m_MSAADepthRenderBuffer);
	}
	
	//CAEAGLレイヤーをビューに追加
	[m_pBaseView.layer addSublayer:pEAGLLayer];
	
EXIT:;
	return result;
}

//******************************************************************************
// OpneGLコンテキスト破棄
//******************************************************************************
- (void)terminateOpenGLContext
{
	//フレームバッファ破棄
	glDeleteFramebuffersOES(1, &m_DefaultFrameBuffer);
	glDeleteFramebuffersOES(1, &m_MSAAFrameBuffer);
	
	//レンダリングバッファ破棄
	glDeleteRenderbuffersOES(1, &m_DefaultColorRenderBuffer);
	glDeleteRenderbuffersOES(1, &m_DefaultDepthRenderBuffer);
	glDeleteRenderbuffersOES(1, &m_MSAAColorRenderBuffer);
	glDeleteRenderbuffersOES(1, &m_MSAADepthRenderBuffer);
	
	//EAGLコンテキスト破棄
	[EAGLContext setCurrentContext:nil];
	[m_pEAGLContext release];
	
	return;
}

//******************************************************************************
// 初期化処理
//******************************************************************************
- (int)initialize:(SMMsgQueue*)pMsgQueue
{
	int result = 0;
	
	//メッセージキュー
	m_pMsgQueue = pMsgQueue;
		
	//レンダラ初期化
	result = m_Renderer.Initialize(m_pBaseView, m_RendererParam);
	if (result != 0) goto EXIT;
	
	//バッファクリア
	result = m_Renderer.RenderScene(NULL, false);
	if (result != 0) goto EXIT;
	
	//時間初期化
	result = m_MachTime.Initialize();
	if (result != 0) goto EXIT;
	
	//モニタ状態
	m_isMonitor = NO;
	
	//全アイテム非表示
	[self hideAllItems];
	
EXIT:;
	return result;
}

//******************************************************************************
// 終了処理
//******************************************************************************
- (void)terminate
{	
	//レンダラ終了
	m_Renderer.Terminate();
	
	return;
}

//******************************************************************************
// デバイス取得
//******************************************************************************
- (OGLDevice*)getDevice
{
	return m_Renderer.GetDevice();
}

//******************************************************************************
// ビュー取得
//******************************************************************************
- (UIView*)getView
{
	return m_pBaseView;
}

//******************************************************************************
// ビュー登録完了
//******************************************************************************
- (void)viewDidLoad
{	
    [super viewDidLoad];
	// Do any additional setup after loading the view.
	
	return;
}

//******************************************************************************
// インターフェース自動回転確認
//******************************************************************************
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
	BOOL isRotate = NO;
	
	//横長のみに対応する
	if ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
	 || (interfaceOrientation == UIInterfaceOrientationLandscapeRight)) {
		isRotate = YES;
	}
	
	return isRotate;
}

//******************************************************************************
// インターフェース自動回転確認（iOS6以降）
//******************************************************************************
- (BOOL)shouldAutorotate
{
	//回転を許可する
	//NSLog(@"shouldAutorotate");
	return YES;
}

//******************************************************************************
// インターフェース自動回転確認：回転方向（iOS6以降）
//******************************************************************************
- (NSUInteger)supportedInterfaceOrientations
{
	//横長のみに対応する
	//NSLog(@"supportedInterfaceOrientations");
	return UIInterfaceOrientationMaskLandscape;
}

//******************************************************************************
// ビュー表示開始
//******************************************************************************
- (void)viewWillAppear:(BOOL)animated
{
	NSString* currSysVer;
	
	//最終タッチ時間
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	//前回描画時間
	m_PrevDrawTime = m_MachTime.GetCurTimeInNanosec();
	m_PrevFPSDrawTime = m_MachTime.GetCurTimeInNanosec();
	
	//描画更新処理間隔設定
	currSysVer = [[UIDevice currentDevice] systemVersion];
	if ([currSysVer compare:@"3.1" options:NSNumericSearch] != NSOrderedAscending) {
		//iOS3.1以降ならDisplayLinkによって描画処理を同期する
		//NSLog(@"Use DisplayLink");
		m_Timer = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self
																	selector:@selector(drawScene:)];
		[m_Timer addToRunLoop:[NSRunLoop currentRunLoop]
					  forMode:NSDefaultRunLoopMode];
	}
	else {
		//iOS3.1未満なら通常のタイマーを使って描画処理間隔を制御する
		//NSLog(@"Use Timer");
		m_Timer = [NSTimer timerWithTimeInterval:(1.0 / 60.0)
										  target:self
										selector:@selector(drawScene:)
										userInfo:nil
										 repeats:YES];
		[[NSRunLoop currentRunLoop] addTimer:m_Timer
									 forMode:NSDefaultRunLoopMode];
	}
	
	return;
}

//******************************************************************************
// ビュー表示終了
//******************************************************************************
- (void)viewDidDisappear:(BOOL)animated
{	
	//タイマー破棄
	[m_Timer invalidate];
	m_Timer = nil;
	
	return;
}

//******************************************************************************
// シーン開始
//******************************************************************************
- (int)startScene:(MTScene*)pScene
		isMonitor:(BOOL)isMonitor
{
	int result = 0;
	
	//シーンオブジェクト
	m_pScene = pScene;
	
	//ダミーのクリックイベントを送ることでタッチ操作を有効化する
	m_pScene->OnWindowClicked(WM_LBUTTONDOWN, 0, 0);
	
	//スクリーン種別設定
	m_pScene->SetScreenType(m_ScreenType);
	
    //ロック状態設定
    m_pScene->LockScreen(m_isScreenLocked);
    
	//モニタフラグ
	m_isMonitor = isMonitor;
	
	//シーンメッセージキューをクリア
	m_SceneMsgQueue.Clear();
	
	//初回描画処理
	result = [self drawProc];
	if (result != 0) goto EXIT;
	
	//最終タッチ時間
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	//VRビューの場合はモーションセンサ利用開始
	if (m_pMotionManager.deviceMotionAvailable) {
		if ((m_ScreenType == MTScene::VRViewSingleLens)
		 || (m_ScreenType == MTScene::VRViewDualLens)) {
			[m_pMotionManager startDeviceMotionUpdates];
		}
	}
	
	//ゲームコントローラ選択
	[self selectGameController];
	
EXIT:;
	return result;
}


//******************************************************************************
// シーン停止
//******************************************************************************
- (int)stopScene
{
	int result = 0;
	
	//シーンオブジェクト
	m_pScene = NULL;
	
	//モーションセンサ利用終了
	if (m_pMotionManager.deviceMotionAvailable) {
		[m_pMotionManager stopDeviceMotionUpdates];
	}
	
	//ゲームコントローラー破棄
	[m_pGameController release];
	m_pGameController = nil;
	
	return result;
}

//******************************************************************************
// シーン操作：演奏開始
//******************************************************************************
- (int)scene_PlayStart
{
	int result = 0;
	
	result = m_pScene->OnPlayStart();
	if (result != 0) goto EXIT;
	
EXIT:;
	return result;
}

//******************************************************************************
// シーン操作：演奏終了
//******************************************************************************
- (int)scene_PlayEnd
{
	int result = 0;
	
	result = m_pScene->OnPlayEnd();
	if (result != 0) goto EXIT;
	
EXIT:;
	return result;
}

//******************************************************************************
// シーン操作：巻き戻し
//******************************************************************************
- (int)scene_Rewind
{
	int result = 0;
	
	result = m_pScene->Rewind();
	if (result != 0) goto EXIT;
	
EXIT:;
	return result;
}

//******************************************************************************
// シーン操作：視点リセット
//******************************************************************************
- (int)scene_ResetViewpoint
{
	int result = 0;
	
	m_pScene->ResetViewpoint();
	
	return result;
}

//******************************************************************************
// シーン操作：静的視点移動
//******************************************************************************
- (int)scene_MoveToStaticViewpoint:(unsigned int)viewpointNo
{
	int result = 0;
	
	m_pScene->MoveToStaticViewpoint(viewpointNo);
	
	return result;
}

//******************************************************************************
// シーン操作：視点登録
//******************************************************************************
- (int)scene_SetViewpoint:(MTScene::MTViewParamMap*)pParamMap
{
	int result = 0;
	
	m_pScene->SetViewParam(pParamMap);
	
	return result;
}

//******************************************************************************
// シーン操作：視点取得
//******************************************************************************
- (int)scene_GetViewpoint:(MTScene::MTViewParamMap*)pParamMap
{
	int result = 0;
	
	m_pScene->GetViewParam(pParamMap);
	
	return result;
}

//******************************************************************************
// シーン操作：エフェクト設定
//******************************************************************************
- (int)scene_SetEffect:(MTScene::EffectType)type isEnable:(bool)isEnable
{
	int result = 0;
	
	m_pScene->SetEffect(type, isEnable);
	
	return result;
}

//******************************************************************************
// シーン操作：スクリーン種別設定
//******************************************************************************
- (int)scene_SetScreenType:(MTScene::ScreenType)type;
{
	int result = 0;
	
	m_ScreenType = type;
	m_pScene->SetScreenType(m_ScreenType);
	
	//VRビューの場合はモーションセンサ利用開始
	//通常ビューに戻る場合はモーションセンサ利用終了
	if (m_pMotionManager.deviceMotionAvailable) {
		if ((m_ScreenType == MTScene::VRViewSingleLens)
		 || (m_ScreenType == MTScene::VRViewDualLens)) {
			[m_pMotionManager startDeviceMotionUpdates];
		}
		else {
			[m_pMotionManager stopDeviceMotionUpdates];
		}
	}
	
	return result;
}

//******************************************************************************
// シーン操作：スクリーンロック
//******************************************************************************
- (int)scene_LockScreen:(bool)isLocked;
{
    int result = 0;
    
    m_pScene->LockScreen(isLocked);
    
    return result;
}

//******************************************************************************
// シーン描画
//******************************************************************************
- (void)drawScene:(NSTimer*)timer
{
	int result = 0;
	
	if (m_pScene == NULL) goto EXIT;
	
	m_isStopScene = NO;
	
	//シーケンサメッセージ処理
	result = [self sequencerMsgProc];
	if (result != 0) goto EXIT;
	
	//デバイス方向更新
	if ((m_ScreenType == MTScene::VRViewSingleLens)
	 || (m_ScreenType == MTScene::VRViewDualLens)) {
		result = [self updateDeviceDirection];
		if (result != 0) goto EXIT;
	}
	
	//ゲームコントローラー設定
	if (m_pScene != NULL) {
		m_pScene->SetGameController(m_pGameController);
	}
	
	//描画
	result = [self drawProc];
	if (result != 0) goto EXIT;
	
	//FPS更新
	[self updateFPS:m_PrevDrawTime];

	//描画処理開始時刻
	m_PrevDrawTime = m_MachTime.GetCurTimeInNanosec();
	
	//ボタン表示状態を更新
	[self updateButtonStatus];
	
	//タッチガイド画像表示状態を更新
	[self updateGuideImageStatus];
	
EXIT:;
	if (result != 0) YN_SHOW_ERR();
}

//******************************************************************************
// シーケンサメッセージ処理
//******************************************************************************
- (int)sequencerMsgProc
{
	int result = 0;
	bool isExist = false;
	unsigned int wParam = 0;
	unsigned int lParam = 0;
	SMMsgParser parser;
	
	while (YES) {
		//メッセージ取り出し
		result = m_pMsgQueue->GetMessage(&isExist, &wParam, &lParam);
		if (result != 0) goto EXIT;
		
		//メッセージがなければ終了
		if (!isExist) break;
		
		//メッセージ通知
		result = m_pScene->OnRecvSequencerMsg(wParam, lParam);
		if (result != 0) goto EXIT;	
		
		//演奏状態変更通知への対応
		parser.Parse(wParam, lParam);
		if (parser.GetMsg() == SMMsgParser::MsgPlayStatus) {
			//一時停止
			if (parser.GetPlayStatus() == SMMsgParser::StatusPause) {
				[self postPlayStatus:@"onChangePlayStatusPause"];
			}
			//停止（演奏終了）
			else if (parser.GetPlayStatus() == SMMsgParser::StatusStop) {
				[self postPlayStatus:@"onChangePlayStatusStop"];
			}
		}
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// 描画処理
//******************************************************************************
- (int)drawProc
{
	int result = 0;
	bool isVRViewDualLens = false;
	const GLenum attachments[] = {GL_COLOR_ATTACHMENT0_OES, GL_DEPTH_ATTACHMENT_OES};
	
	if (m_ScreenType == MTScene::VRViewDualLens) {
		isVRViewDualLens = true;
	}
	
	//EAGLコンテキストを設定
	[EAGLContext setCurrentContext:m_pEAGLContext];
	
	//フレームバッファを設定
	if (m_RendererParam.isEnableAntialiasing) {
		glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_MSAAFrameBuffer);
	}
	
	//レンダリング
	result = m_Renderer.RenderScene((OGLScene*)m_pScene, isVRViewDualLens);
	if (result != 0) goto EXIT;
	
	//レンダリングバッファを表示
	if (m_RendererParam.isEnableAntialiasing) {
		glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, m_MSAAFrameBuffer);
		glBindFramebufferOES(GL_DRAW_FRAMEBUFFER_APPLE, m_DefaultFrameBuffer);
		glResolveMultisampleFramebufferAPPLE();
	}
	glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, attachments);
	glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_DefaultColorRenderBuffer);
	[m_pEAGLContext presentRenderbuffer:GL_RENDERBUFFER_OES];
	
EXIT:;
	return result;
}

//******************************************************************************
// 演奏状態変更通知受信処理
//******************************************************************************
- (int)postPlayStatus:(NSString*)pNotificationName
{
	int result = 0;
	NSNotification* pNotification = nil;
	NSNotificationCenter* pCenter = nil;
	
	//通知オブジェクトを作成
    pNotification = [NSNotification notificationWithName:pNotificationName
												  object:self
												userInfo:nil];
	//通知する
	pCenter = [NSNotificationCenter defaultCenter];
	
	//通知に対応する処理を演奏スレッドで処理させる場合
	//[pCenter postNotification:pNotification];
	
	//通知に対応する処理をメインスレッドに処理させる場合
	[pCenter performSelectorOnMainThread:@selector(postNotification:)
							  withObject:pNotification
						   waitUntilDone:NO];
	
	return result;
}

//******************************************************************************
// FPS更新
//******************************************************************************
- (void)updateFPS:(uint64_t)startTime
{
	uint64_t curTime = 0;
	uint64_t deltaTime = 0;
	float fps = 0.0f;
	
	//表示フレーム数カウント
	m_FlameCount += 1.0f;
	
	//現在時刻
	curTime = m_MachTime.GetCurTimeInNanosec();
	
	//前回FPS表示更新からの経過時間（ナノ秒）
	deltaTime = curTime - m_PrevFPSDrawTime;
	
	//1秒おきにFPS表示更新
	if (deltaTime >= (1000 * 1000000)) {
		fps = (double)(1000 * 1000000) / ((double)deltaTime / m_FlameCount);
		m_pScene->SetFPS(fps);
		m_PrevFPSDrawTime = curTime;
		m_FlameCount = 0.0f;
		//NSLog(@"FPS:%.1f", fps);
	}
}

//******************************************************************************
// クローズボタン押下
//******************************************************************************
- (IBAction)onCloseButton
{
	//クローズ通知
	[self postNotificationWithName:@"onCloseButton"];
	
	return;
}

//******************************************************************************
// 再生ボタン押下
//******************************************************************************
- (IBAction)onPlayButton
{	
	//再生通知
	[self postNotificationWithName:@"onPlayButton"];
	
	//最終タッチ時間更新
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	return;
}

//******************************************************************************
// 停止ボタン押下
//******************************************************************************
- (IBAction)onStopButton
{
	//停止通知
	[self postNotificationWithName:@"onStopButton"];
	
	//最終タッチ時間更新
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	return;
}

//******************************************************************************
// 後方スキップボタン押下
//******************************************************************************
- (IBAction)onSkipBackwardButton
{
	//後方スキップ通知
	[self postNotificationWithName:@"onSkipBackwardButton"];
	
	//最終タッチ時間更新
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	return;
}

//******************************************************************************
// 前方スキップボタン押下
//******************************************************************************
- (IBAction)onSkipForwardButton
{
	//前方スキップ通知
	[self postNotificationWithName:@"onSkipForwardButton"];
	
	//最終タッチ時間更新
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	return;
}

//******************************************************************************
// 再生スピードダウンボタン押下
//******************************************************************************
- (IBAction)onPlaySpeedDownButton
{
	//再生スピードダウン通知
	[self postNotificationWithName:@"onPlaySpeedDownButton"];	
	
	//最終タッチ時間更新
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	return;
}

//******************************************************************************
// 再生スピードアップボタン押下
//******************************************************************************
- (IBAction)onPlaySpeedUpButton
{
	//再生スピードアップ通知
	[self postNotificationWithName:@"onPlaySpeedUpButton"];
	
	//最終タッチ時間更新
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	return;
}

//******************************************************************************
// リピートボタン押下
//******************************************************************************
- (IBAction)onRepeatButton
{
	//通知
	[self postNotificationWithName:@"onRepeatButton"];
	
	//最終タッチ時間更新
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	return;
}

//******************************************************************************
// ビューボタン押下
//******************************************************************************
- (IBAction)onViewButton
{
	UIActionSheet* pActionSheet = nil;
	
	//最終タッチ時間更新
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	//視点制御アクションシート生成
	pActionSheet = [[UIActionSheet alloc] init];
	pActionSheet.delegate = self;
	pActionSheet.tag = 1;
	
    //視点制御アクションシート設定
	//pActionSheet.title = @"Viewpoint";
	[pActionSheet addButtonWithTitle:@"Viewpoint 1"];
	[pActionSheet addButtonWithTitle:@"Viewpoint 2"];
	[pActionSheet addButtonWithTitle:@"Viewpoint 3"];
	[pActionSheet addButtonWithTitle:@"Standard View"];
	[pActionSheet addButtonWithTitle:@"VR View (Single Lens)"];
	[pActionSheet addButtonWithTitle:@"VR View (Dual Lens)"];
	
    if (m_isScreenLocked) {
        [pActionSheet addButtonWithTitle:@"Unlock Screen"];
    }
    else {
        [pActionSheet addButtonWithTitle:@"Lock Screen"];
    }
	
	[pActionSheet addButtonWithTitle:@"Cancel"];
	pActionSheet.cancelButtonIndex = 7;
	//pActionSheet.destructiveButtonIndex = 0;
	
	//視点制御アクションシート表示
	[pActionSheet showInView:self.view];
	
	return;
}

//******************************************************************************
// ヘルプボタン押下
//******************************************************************************
- (IBAction)onHelpButton
{
	//HowToViewヘルプ表示
	m_pHowToViewCtrl.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
    [self presentViewController:m_pHowToViewCtrl animated:YES completion:nil];
	
	//最終タッチ時間更新
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	return;
}

//******************************************************************************
// アクションシートボタン選択イベント
//******************************************************************************
- (void)actionSheet:(UIActionSheet*)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
	//視点制御アクションシート
	if (actionSheet.tag == 1) {
		switch (buttonIndex) {
			case 0:
				//Viewpoint 1
				[self scene_MoveToStaticViewpoint:1];
				break;
			case 1:
				//Viewpoint 2
				[self scene_MoveToStaticViewpoint:2];
				break;
			case 2:
				//Viewpoint 3
				[self scene_MoveToStaticViewpoint:3];
				break;
			case 3:
				//Standard View
				[self scene_SetScreenType:(MTScene::StandardView)];
				break;
			case 4:
				//VR View (Single Lens)
				[self scene_SetScreenType:(MTScene::VRViewSingleLens)];
				break;
			case 5:
				//VR View (Dual Lens)
				[self scene_SetScreenType:(MTScene::VRViewDualLens)];
				break;
			case 6:
				//スクリーンロック
				m_isScreenLocked = m_isScreenLocked ? false : true;
				[self scene_LockScreen:m_isScreenLocked];
				break;
			case 7:
				//キャンセル
				break;
			default:
				break;
		}
	}
	
	return;
}

//******************************************************************************
// タッチイベント：開始
//******************************************************************************
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event
{
	CGPoint point;
	
	//シーンに通知
	if (m_pScene != NULL) {
		//タッチイベント通知
		m_pScene->OnTouchesBegan(touches);
		
		//タップ判定開始
		point = [[touches anyObject] locationInView:m_pBaseView];
		m_PrevTouchPoint.x = point.x;
		m_PrevTouchPoint.y = point.y;
		m_TounchesTotalDistance = 0;
		//NSLog(@"touchesBegan %f, %f", point.x, point.y);
	}
	
	return;
}

//******************************************************************************
// タッチイベント：移動
//******************************************************************************
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent *)event
{
	CGPoint point;
	
	//メモ：本イベントは指を移動させなくても定期的に発生する（同じ座標で通知される）
	
	//シーンに通知
	if (m_pScene != NULL) {
		//タッチイベント通知
		m_pScene->OnTouchesMoved(touches);
		
		//移動距離加算
		point = [[touches anyObject] locationInView:m_pBaseView];
		m_TounchesTotalDistance += sqrtf(powf(point.x - m_PrevTouchPoint.x, 2)
										 + powf(point.y - m_PrevTouchPoint.y, 2));
		m_PrevTouchPoint = point;
		//NSLog(@"touchesMoved %f, %f", point.x, point.y);
	}
	
	return;
}

//******************************************************************************
// タッチイベント：終了
//******************************************************************************
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent *)event
{
	//シーンに通知
	if (m_pScene != NULL) {
		//タッチイベント通知
		m_pScene->OnTouchesEnd(touches);
		
		//移動距離がゼロの場合はタップとみなす
		//NSLog(@"touchesEnded %f", m_TounchesTotalDistance);
		if (m_TounchesTotalDistance == 0.0f) {
			[self onTapped];
			m_PrevTouchPoint.x = 0;
			m_PrevTouchPoint.y = 0;
			m_TounchesTotalDistance = 0;
		}
	}
	
	return;
}

//******************************************************************************
// タッチイベント：キャンセル
//******************************************************************************
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent *)event
{
	//シーンに通知
	if (m_pScene != NULL) {
		//タッチイベント通知
		m_pScene->OnTouchesCanceled(touches);
		
		//キャンセルが発生した場合はタップ判定解除
		m_PrevTouchPoint.x = 0;
		m_PrevTouchPoint.y = 0;
		m_TounchesTotalDistance = 0;
	}
	
	return;
}

//******************************************************************************
// タップ
//******************************************************************************
- (void)onTapped
{
	//ボタン表示状態を反転
	m_isDisplayButtons = !m_isDisplayButtons;

	//最終タッチ時間更新
	m_LastTouchTime = m_MachTime.GetCurTimeInNanosec();
	
	return;
}

//******************************************************************************
// 通知送信処理
//******************************************************************************
- (int)postNotificationWithName:(NSString*)pName
{
	int result = 0;
	NSNotification* pNotification = nil;
	NSNotificationCenter* pCenter = nil;
	
	//通知オブジェクトを作成
    pNotification = [NSNotification notificationWithName:pName
												  object:self
												userInfo:nil];
	//通知する
	pCenter = [NSNotificationCenter defaultCenter];
	
	//通知に対応する処理を演奏スレッドで処理させる場合
	//[pCenter postNotification:pNotification];
	
	//通知に対応する処理をメインスレッドに処理させる場合
	[pCenter performSelectorOnMainThread:@selector(postNotification:)
							  withObject:pNotification
						   waitUntilDone:NO];
	
	return result;
}

//******************************************************************************
// 全アイテム非表示
//******************************************************************************
- (void)hideAllItems
{
	//ボタン：上段
	m_pCloseButton.hidden = YES;
	m_pRepeatButton.hidden = YES;
	m_pViewButton.hidden = YES;
	m_pHelpButton.hidden = YES;
	
	//ボタン：下段
	m_pPlayButton.hidden = YES;
	m_pStopButton.hidden = YES;
	m_pSkipBackwardButton.hidden = YES;
	m_pSkipForwardButton.hidden = YES;
	m_pPlaySpeedDownButton.hidden = YES;
	m_pPlaySpeedUpButton.hidden = YES;
	
	//ガイド
	m_pGuideImageUD.hidden = YES;
	m_pGuideImageFB.hidden = YES;
	m_pGuideImageLR.hidden = YES;
	m_pGuideImageRT.hidden = YES;
	
	//インジケータ
	m_pActivityIndicator.hidden = YES;
	m_pLabel.hidden = YES;
	
	return;
}

//******************************************************************************
// ボタン表示状態更新
//******************************************************************************
- (void)updateButtonStatus
{
	uint64_t elapsedTime = 0;
	
	//最終タッチ時刻から5秒経過したらボタンを隠す
	if (m_isDisplayButtons) {
		elapsedTime = m_MachTime.GetCurTimeInNanosec() - m_LastTouchTime;
		if (elapsedTime > (5ULL * 1000ULL * 1000000ULL)) {
			m_isDisplayButtons = NO;
		}
	}
	
	//ボタンの表示更新
	m_pCloseButton.hidden = !m_isDisplayButtons;
	m_pRepeatButton.hidden = !m_isDisplayButtons;
	m_pViewButton.hidden = !m_isDisplayButtons;
	m_pHelpButton.hidden = !m_isDisplayButtons;
	m_pPlayButton.hidden = !m_isDisplayButtons;
	m_pStopButton.hidden = !m_isDisplayButtons;
	m_pSkipBackwardButton.hidden = !m_isDisplayButtons;
	m_pSkipForwardButton.hidden = !m_isDisplayButtons;
	m_pPlaySpeedDownButton.hidden = !m_isDisplayButtons;
	m_pPlaySpeedUpButton.hidden = !m_isDisplayButtons;

	//MIDI IN モニタでは一部のボタンを表示しない
	if (m_isMonitor) {
		m_pRepeatButton.hidden = YES;
		m_pPlayButton.hidden = YES;
		m_pStopButton.hidden = YES;
		m_pSkipBackwardButton.hidden = YES;
		m_pSkipForwardButton.hidden = YES;
		m_pPlaySpeedDownButton.hidden = YES;
		m_pPlaySpeedUpButton.hidden = YES;
	}
	
	//タッチガイド表示中はすべてのボタンを表示しない
	if ((m_pScene->GetCurOperationType() == MTTouchCtrl::OperationMoveUD)
	 || (m_pScene->GetCurOperationType() == MTTouchCtrl::OperationMoveFB)
	 || (m_pScene->GetCurOperationType() == MTTouchCtrl::OperationMoveLR)
	 || (m_pScene->GetCurOperationType() == MTTouchCtrl::OperationRotate)) {
		m_pCloseButton.hidden = YES;
		m_pRepeatButton.hidden = YES;
		m_pViewButton.hidden = YES;
		m_pHelpButton.hidden = YES;
		m_pPlayButton.hidden = YES;
		m_pStopButton.hidden = YES;
		m_pSkipBackwardButton.hidden = YES;
		m_pSkipForwardButton.hidden = YES;
		m_pPlaySpeedDownButton.hidden = YES;
		m_pPlaySpeedUpButton.hidden = YES;
	}
	
	return;
}

//******************************************************************************
// タッチガイド画像表示状態更新
//******************************************************************************
-(void)updateGuideImageStatus
{
	m_pGuideImageUD.hidden = YES;
	m_pGuideImageFB.hidden = YES;
	m_pGuideImageLR.hidden = YES;
	m_pGuideImageRT.hidden = YES;
	
	if (m_pScene == NULL) goto EXIT;
	
	//操作中のガイドのみを表示
	switch (m_pScene->GetCurOperationType()) {
		case (MTTouchCtrl::OperationNone):
			break;
		case (MTTouchCtrl::OperationEyeDir):
			break;
		case (MTTouchCtrl::OperationMoveUD):
			m_pGuideImageUD.hidden = NO;
			break;
		case (MTTouchCtrl::OperationMoveFB):
			m_pGuideImageFB.hidden = NO;
			break;
		case (MTTouchCtrl::OperationMoveLR):
			m_pGuideImageLR.hidden = NO;
			break;
		case (MTTouchCtrl::OperationRotate):
			m_pGuideImageRT.hidden = NO;
			break;
		default:
			break;
	}
	
EXIT:;
	return;
}

//******************************************************************************
// リピート状態設定
//******************************************************************************
- (void)setRepeatStatus:(BOOL)isRepeat
{
	if (isRepeat) {
		[m_pRepeatButton setSelected:YES];
	}
	else {
		[m_pRepeatButton setSelected:NO];
	}
	
	return;
}

//******************************************************************************
// インジケータアニメーション開始
//******************************************************************************
- (void)startActivityIndicator
{
	[self hideAllItems];
	
	m_pActivityIndicator.hidden = NO;
	m_pLabel.hidden = NO;
	
	[m_pActivityIndicator startAnimating];
	
	return;
}

//******************************************************************************
// インジケータアニメーション停止
//******************************************************************************
- (void)stopActivityIndicator
{
	m_pActivityIndicator.hidden = YES;
	m_pLabel.hidden = YES;
	
	[m_pActivityIndicator stopAnimating];
	
	return;
}

//******************************************************************************
// カレントコンテキスト設定
//******************************************************************************
- (void)setCurrentContext
{
	//OpenGLを利用するスレッドを切り替えるときは
	//当該スレッドにて本メソッドを呼ぶこと
	[EAGLContext setCurrentContext:m_pEAGLContext];
	
	return;
}

//******************************************************************************
// 演奏状態設定
//******************************************************************************
- (void)setPlayStatus:(PlayStatus)status
{
	//再生ボタンの画像を初期化
	[m_pPlayButton setImage:m_pImgButtonPlayN forState:UIControlStateNormal];
	[m_pPlayButton setImage:m_pImgButtonPlayH forState:UIControlStateHighlighted];
	
	switch(status) {
		//データなし
		case NoData:
			break;
		//停止状態
		case Stop:
			break;
		//再生中
		case Play:
			//再生ボタンの画像を一時停止アイコンに置き換える
			[m_pPlayButton setImage:m_pImgButtonPauseN forState:UIControlStateNormal];
			[m_pPlayButton setImage:m_pImgButtonPauseH forState:UIControlStateHighlighted];
			break;
		//一時停止
		case Pause:
			break;	
		//モニタ停止
		case MonitorOFF:
			break;
		//モニタ中
		case MonitorON:
			break;
		default:
			break;
	}
	
	return;
}

//******************************************************************************
// ステータスバー非表示
//******************************************************************************
- (BOOL)prefersStatusBarHidden
{
    return YES;
}

//******************************************************************************
// デバイス方向更新
//******************************************************************************
- (int)updateDeviceDirection
{
	int result = 0;
	CMQuaternion quaternion;
	OGLQuaternion q;
	
	//モーションセンサが有効でなければ何もしない
	if (!m_pMotionManager.deviceMotionAvailable) goto EXIT;
	
	//デバイス方向（クォータニオン）取得
	quaternion = m_pMotionManager.deviceMotion.attitude.quaternion;
	q.x = quaternion.x;
	q.y = quaternion.y;
	q.z = quaternion.z;
	q.w = quaternion.w;
	
	//デバイス方向設定
	if (m_pScene != NULL) {
		m_pScene->SetDeviceDirection(q);
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// ゲームコントローラー接続通知
//******************************************************************************
- (void)onGameControllerDidConnect
{
	NSLog(@"Game Controller connected");
	[self selectGameController];
}

//******************************************************************************
// ゲームコントローラー切断通知
//******************************************************************************
- (void)onGameControllerDidDisconnect
{
	NSLog(@"Game Controller disconnected");
	[self selectGameController];
}

//******************************************************************************
// ゲームコントローラー選択
//******************************************************************************
- (void)selectGameController
{
	NSArray* pControllers = nil;
	GCController* pController = nil;
	
	//ゲームコントローラー破棄
	if (m_pGameController != nil) {
		[m_pGameController release];
		m_pGameController = nil;
	}
	
	//ゲームコントローラー検索
	pControllers = [GCController controllers];
	for (pController in pControllers) {
		//ゲームパッドをサポートしているコントローラを探す
		if (pController.gamepad != nil) {
			//最初に見つかったものを選択する
			[pController retain];
			m_pGameController = pController;
			NSLog(@"Game Controller with gamepad found");
			break;
		}
	}
	
	//ゲームコントローラー初期化
	[self initializeGameController];
	
	return;
}

//******************************************************************************
// ゲームコントローラー初期化
//******************************************************************************
- (void)initializeGameController
{
	//ゲームコントローラーが存在しなければ何もせず終了
	if (m_pGameController == nil) goto EXIT;
	
	//プレイヤーインデックス設定
	m_pGameController.playerIndex = GCControllerPlayerIndex1;
	
	//ポーズボタンのイベントハンドラ
	m_pGameController.controllerPausedHandler
	= ^(GCController* pController) {
		[self onGamePadPauseButtonOnController:pController];
	};
	//Aボタンのイベントハンドラ
	m_pGameController.gamepad.buttonA.valueChangedHandler
	= ^(GCControllerButtonInput* pButton, float value, BOOL isPressed) {
		[self onGamePadButtonAChanged:pButton value:value isPressed:isPressed];
	};
	//Bボタンのイベントハンドラ
	m_pGameController.gamepad.buttonB.valueChangedHandler
	= ^(GCControllerButtonInput* pButton, float value, BOOL isPressed) {
		[self onGamePadButtonBChanged:pButton value:value isPressed:isPressed];
	};
	//拡張ゲームパッドでない場合
	if (m_pGameController.extendedGamepad == nil) {
		//Lボタン：L2ボタン同等
		m_pGameController.gamepad.leftShoulder.valueChangedHandler
		= ^(GCControllerButtonInput* pButtonInput, float value, BOOL isPressed) {
			[self onGamePadButtonL2Changed:pButtonInput value:value isPressed:isPressed];
		};
		//Rボタン：R2ボタン同等
		m_pGameController.gamepad.rightShoulder.valueChangedHandler
		= ^(GCControllerButtonInput* pButtonInput, float value, BOOL isPressed) {
			[self onGamePadButtonR2Changed:pButtonInput value:value isPressed:isPressed];
		};
	}
	//拡張ゲームパッドの場合
	else {
		//L1ボタン
		m_pGameController.extendedGamepad.leftShoulder.valueChangedHandler
		= ^(GCControllerButtonInput* pButtonInput, float value, BOOL isPressed) {
			[self onGamePadButtonL1Changed:pButtonInput value:value isPressed:isPressed];
		};
		//L2ボタン
		m_pGameController.extendedGamepad.leftTrigger.valueChangedHandler
		= ^(GCControllerButtonInput* pButtonInput, float value, BOOL isPressed) {
			[self onGamePadButtonL2Changed:pButtonInput value:value isPressed:isPressed];
		};
		//R1ボタン
		m_pGameController.extendedGamepad.rightShoulder.valueChangedHandler
		= ^(GCControllerButtonInput* pButtonInput, float value, BOOL isPressed) {
			[self onGamePadButtonR1Changed:pButtonInput value:value isPressed:isPressed];
		};
		//R2ボタン
		m_pGameController.extendedGamepad.rightTrigger.valueChangedHandler
		= ^(GCControllerButtonInput* pButtonInput, float value, BOOL isPressed) {
			[self onGamePadButtonR2Changed:pButtonInput value:value isPressed:isPressed];
		};
	}
	
EXIT:;
	return;
}

//******************************************************************************
// ゲームコントローラーボタンイベントに関するメモ
//******************************************************************************
// ボタンを1回押すだけでもvalueの異なる複数の通知が連続発生する
// ボタンを半押しで押し続けるとvalueが異なる通知が発生し続ける
// ボタンを全押しするとvalueが1.0となり通知が止まる
// ボタンを離すとvalueが0.0の通知が発生し、次にボタンを押すまで通知が発生しない

//******************************************************************************
// ポーズボタン イベントハンドラ
//******************************************************************************
- (void)onGamePadPauseButtonOnController:(GCController*)pController
{
	//NSLog(@"Button Pause");
	[self onPlayButton];
}

//******************************************************************************
// ボタンA イベントハンドラ
//******************************************************************************
- (void)onGamePadButtonAChanged:(GCControllerButtonInput*)pButtonInput
						  value:(float)value
					  isPressed:(BOOL)isPressed
{
	//NSLog(@"Button A: %f %d", value, isPressed);
	//0からプラスの値に変化したときだけ反応する
	if ((m_ButtonA_PrevValue == 0.0f) && (value > 0.0f)) {
		[self onPlayButton];
	}
	m_ButtonA_PrevValue = value;
}

//******************************************************************************
// ボタンB イベントハンドラ
//******************************************************************************
- (void)onGamePadButtonBChanged:(GCControllerButtonInput*)pButtonInput
						  value:(float)value
					  isPressed:(BOOL)isPressed
{
	//NSLog(@"Button B: %f %d", value, isPressed);
	//0からプラスの値に変化したときだけ反応する
	if ((m_ButtonB_PrevValue == 0.0f) && (value > 0.0f)) {
		[self onStopButton];
	}
	m_ButtonB_PrevValue = value;
}

//******************************************************************************
// ボタンL1 イベントハンドラ
//******************************************************************************
- (void)onGamePadButtonL1Changed:(GCControllerButtonInput*)pButtonInput
						   value:(float)value
					   isPressed:(BOOL)isPressed
{
	//NSLog(@"Button L1: %f %d", value, isPressed);
	//0からプラスの値に変化したときだけ反応する
	if ((m_ButtonL1_PrevValue == 0.0f) && (value > 0.0f)) {
		[self onPlaySpeedDownButton];
	}
	m_ButtonL1_PrevValue = value;
}

//******************************************************************************
// ボタンL2 イベントハンドラ
//******************************************************************************
- (void)onGamePadButtonL2Changed:(GCControllerButtonInput*)pButtonInput
						   value:(float)value
					   isPressed:(BOOL)isPressed
{
	//NSLog(@"Button L2: %f %d", value, isPressed);
	//0からプラスの値に変化したときだけ反応する
	if ((m_ButtonL2_PrevValue == 0.0f) && (value > 0.0f)) {
		[self onSkipBackwardButton];
	}
	m_ButtonL2_PrevValue = value;
}

//******************************************************************************
// ボタンR1 イベントハンドラ
//******************************************************************************
- (void)onGamePadButtonR1Changed:(GCControllerButtonInput*)pButtonInput
						   value:(float)value
					   isPressed:(BOOL)isPressed
{
	//NSLog(@"Button R1: %f %d", value, isPressed);
	//0からプラスの値に変化したときだけ反応する
	if ((m_ButtonR1_PrevValue == 0.0f) && (value > 0.0f)) {
		[self onPlaySpeedUpButton];
	}
	m_ButtonR1_PrevValue = value;
}

//******************************************************************************
// ボタンR2 イベントハンドラ
//******************************************************************************
- (void)onGamePadButtonR2Changed:(GCControllerButtonInput*)pButtonInput
						   value:(float)value
					   isPressed:(BOOL)isPressed
{
	//NSLog(@"Button R2: %f %d", value, isPressed);
	//0からプラスの値に変化したときだけ反応する
	if ((m_ButtonR2_PrevValue == 0.0f) && (value > 0.0f)) {
		[self onSkipForwardButton];
	}
	m_ButtonR2_PrevValue = value;
}

@end

