//******************************************************************************
//
// OpenGL Utility / OGLRenderer
//
// レンダラクラス
//
// Copyright (C) 2010-2019 WADA Masashi. All Rights Reserved.
//
//******************************************************************************

#include "YNBaseLib.h"
#include "OGLRenderer.h"
#include <new>


//******************************************************************************
// コンストラクタ
//******************************************************************************
OGLRenderer::OGLRenderer()
{
	m_pOGLDevice = NULL;
	m_pView = NULL;
}

//******************************************************************************
// デストラクタ
//******************************************************************************
OGLRenderer::~OGLRenderer()
{
	Terminate();
}

//******************************************************************************
// 初期化
//******************************************************************************
int OGLRenderer::Initialize(
		UIView* pView,
		OGLRedererParam rendererParam
	)
{
	int result = 0;
	CGRect baseRect;
	OGLVIEWPORT viewPort;
	
	m_pView = pView;
	
	//ディスプレイデバイス作成（ダミー）
	try {
		m_pOGLDevice = new OGLDevice();
	}
	catch (std::bad_alloc) {
		result = YN_SET_ERR(@"Could not allocate memory.", 0, 0);
		goto EXIT;
	}
	
	//ディスプレイデバイス初期化
	result = m_pOGLDevice->Initialize();
	if (result != 0) goto EXIT;
	
	//ビューポート情報作成
	baseRect = m_pView.frame;
	baseRect.origin = CGPointZero;	
	viewPort.originx = baseRect.origin.x;
	viewPort.originy = baseRect.origin.y;
	viewPort.width   = baseRect.size.width;
	viewPort.height  = baseRect.size.height;
	m_pOGLDevice->SetViewPort(viewPort);
	
	//アンチエイリアス有効化
	//  ハードウェアによって無視される場合があるため気休め程度の設定である
	//  アンチエイリアスの有効化はNSView生成時に指定するピクセルフォーマットで確定するようだ
	if (rendererParam.isEnableAntialiasing) {
		glEnable(GL_MULTISAMPLE);
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// デバイス取得
//******************************************************************************
OGLDevice* OGLRenderer::GetDevice()
{
	return m_pOGLDevice;
}

//*****************************************************************************
// シーン描画
//******************************************************************************
int OGLRenderer::RenderScene(
		OGLScene* pScene,
		bool isVRViewDualLens,	//VR View(Dual Lens)描画フラグ
		CGFloat ipdPoints		//瞳孔間距離ポイント数
	)
{
	int result = 0;
	CGRect baseRect;
	OGLVIEWPORT viewPort;
	CGFloat ipdPointsTmp = ipdPoints;
	
	//バッファ初期化色の指定：RGBA
	glClearColor(0.0, 0.0, 0.0, 0.0);
	
	//バッファクリア：色バッファ＋深度バッファ
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	baseRect = m_pView.frame;
	baseRect.origin = CGPointZero;
	
	//描画
	if (pScene != NULL) {
		//VRビュー
		if (isVRViewDualLens) {
			//瞳孔間距離が画面横幅の1/2より大きい場合または瞳孔間距離が無効な場合
			if ((ipdPoints > (baseRect.size.width / 2)) || (ipdPoints <= 0)) {
				ipdPointsTmp = baseRect.size.width / 2;
			}
			//左目用の描画
			viewPort.originx = baseRect.origin.x + (baseRect.size.width / 2) - ipdPointsTmp;
			viewPort.originy = baseRect.origin.y;
			viewPort.width   = ipdPointsTmp;
			viewPort.height  = baseRect.size.height;
			m_pOGLDevice->SetViewPort(viewPort);
			result = pScene->Draw(m_pOGLDevice, OGLScene::CameraLeftEye);
			if (result != 0) {
				//失敗しても描画定型処理を続行する
				YN_SHOW_ERR();
			}
			//右目用の描画
			viewPort.originx = baseRect.origin.x + (baseRect.size.width / 2);
			viewPort.originy = baseRect.origin.y;
			viewPort.width   = ipdPointsTmp;
			viewPort.height  = baseRect.size.height;
			m_pOGLDevice->SetViewPort(viewPort);
			result = pScene->Draw(m_pOGLDevice, OGLScene::CameraRightEye);
			if (result != 0) {
				//失敗しても描画定型処理を続行する
				YN_SHOW_ERR();
			}
		}
		//通常ビュー
		else {
			viewPort.originx = baseRect.origin.x;
			viewPort.originy = baseRect.origin.y;
			viewPort.width   = baseRect.size.width;
			viewPort.height  = baseRect.size.height;
			m_pOGLDevice->SetViewPort(viewPort);
			result = pScene->Draw(m_pOGLDevice, OGLScene::CameraNormal);
			if (result != 0) {
				//失敗しても描画定型処理を続行する
				YN_SHOW_ERR();
			}
		}
	}
	
	//描画処理終了
	//  キューに残っている全てのOpenGLコマンドをハードウェアに送信して制御を戻す
	//  コマンド実行完了まで待機したければglFinishを使う
	glFlush();
	
EXIT:;
	return result;
}

//*****************************************************************************
// 終了処理
//******************************************************************************
void OGLRenderer::Terminate()
{
	if (m_pOGLDevice != NULL) {
		m_pOGLDevice->Release();
		m_pOGLDevice = NULL;
	}
}


