/*----------------------------------------------------------------------

    Shader envelope application main sample

    Copyright (C) 2008 SEGA Corporation Creative Center Graphics Sect.
    All Rights Reserved.

    Module  : Shader envelope application main sample
    File    : smpapp.cpp
    Create  : 2008/07/18 (Ver.0.30.01)
    Modify  : 2008/09/10 (Ver.0.30.02)
				NNS_OBJECTのメモリを取得して処理する方法に変更。
			  2008/11/04 (Ver.0.30.03)
                nnExitVertexBufferDXG20 の記述忘れ。
				nnCalcVertexBufferObjectSizeDXG20 に変更。
			  2008/11/14 (Ver.0.30.04)
			    プラットフォーム別処理関数を smpmain.cpp へ移動した。
				nnGetDirect3DDeviceDXG20, nnGetD3DPresentParametersDXG20 に変更。
				D3DUSAGE_DYNAMIC を D3DUSAGE_WRITEONLY に変更。
			  2008/12/12 (Ver.0.30.05)
				D3DUSAGE_WRITEONLY を D3DUSAGE_DYNAMIC に変更(2008/11/14の変更をもとに戻した)。
			  2009/01/19 (Ver.0.30.06)
	            smpSetIncludePathDXG20 関数を追加。
			  2009/01/21 (Ver.0.30.07)
			    nnSetCompileErrorCallbackStdShaderDXG20 関数を追加。
			  2009/06/11 (Ver.0.30.08)
			    プラットフォーム別処理関数(IDirect3DDevice9_CreateVertexBuffer, IDirect3DVertexBuffer9_Release)を smpmain.cpp へ移動した。
    Version : 0.30.08
    Note    : 

----------------------------------------------------------------------*/

#define __SMPAPP_CPP__

//--------------------
// 組み込みファイル名
//--------------------
#include "smpapp.h"
#include "smputil.h"
#if 0
#include "posteffect.vs.inc"
#include "adapted.ps.inc"
#include "bloom.ps.inc"
#include "log.ps.inc"
#include "small.ps.inc"
#include "through.ps.inc"
#include "final.ps.inc"
#endif

////////////////////////////////////////////////////////////////////////////////
#define SAMPLENAME "High Dynamic Range"

#define DEBUG_CHAR_MAX	(1200)

#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
////////////////////////////////////////////////////////////////////////////////
NNS_MATRIXSTACK			gMtxStack;				// マトリクススタック

static void				*pPrintBuf;				// デバッグ文字用バッファ(メモリの解放が必要)

static void				*pMtxStackBuf;			// マトリクススタックバッファ先頭(メモリの解放が必要)

// 標準シェーダ用
static void				*pShaderMgrBuf;			// シェーダーマネージャバッファ領域(メモリの解放が必要)
static Uint32			VsCodeSize;				// 頂点シェーダコードサイズ
static Uint32			PsCodeSize;				// ピクセルシェーダコードサイズ
static void				*pVsCodeBuf;			// 頂点シェーダコードバッファ領域(メモリの解放が必要)
static void				*pPsCodeBuf;			// ピクセルシェーダコードバッファ領域(メモリの解放が必要)

static SMPPAD_STATUS	*pPad1, *pPad2;			// コントローラ情報

//------------------------------------------------------------------------------
// データ用
static NNS_MATRIX		*pMtxPalMax;			// 最大マトリクスパレット

static void				*pBuf0;					// OBJECTFILE0用バイナリロード用バッファ(メモリの解放が必要)
static NNS_OBJECT		*pObject0;				// OBJECT0(メモリの解放が必要)
static NNS_MATRIX		*pMtxPalObject0;		// OBJECT0用マトリクスパレット先頭(メモリの解放が必要)
static NNF_NODESTATUS	*pNodestatListObject0;	// OBJECT0用ノードステータスリスト先頭(メモリの解放が必要)

static void				*pTexListBuf0;			// TEXFILELIST0用テクスチャ情報領域用バッファ(メモリの解放が必要)
static NNS_TEXLIST		*pTexList0;				// TEXLIST0(メモリの解放が必要)

static NNS_PLIABLEOBJ	*pPliableObject0;		// エンベロープオブジェクト

static void				*pBuf1;					// MOTIONFILE0用バイナリロード用バッファ(メモリの解放が必要)
static NNS_MOTION		*pMotion0;				// MOTION0(メモリの解放が必要)

//------------------------------------------------------------------------------
// 描画フラグ
static const NNF_DRAWOBJ drawflag = NND_DRAWOBJ_FRAGPARALIGHT1;			// フラグメントライティング（パラレルライト×1)

//
Sint32 cursor = 0;

//
Float Frame = 0.0f;
bool  atFirst = true;

//
Uint32 EnvStartTick, EnvEndTick;
Uint32 DrawStartTick, DrawEndTick;

// プロジェクションマトリクス
static NNS_MATRIX44					gProjmtx;

// カメラ
static NNS_CAMERA_TARGET_UPVECTOR	gCamera;		// ターゲットアップベクトルカメラ

// ライト
static NNS_LIGHT_PARALLEL			gLight;			// Parallel light
static NNS_VECTOR					gLightDir = { 0.f, -1.f, 0.f };		// 方向
static NNS_RGBA						gLightCol = { 1.f, 1.f, 1.f, 1.f };	// 色
static Float						gLightInten = 1.f;					// 強さ

//
LPDIRECT3DDEVICE9            g_device         = NULL;

LPDIRECT3DTEXTURE9           g_rt_hdr         = NULL;
LPDIRECT3DTEXTURE9           g_rt_log_256     = NULL;
LPDIRECT3DTEXTURE9           g_rt_log_64      = NULL;
LPDIRECT3DTEXTURE9           g_rt_log_16      = NULL;
LPDIRECT3DTEXTURE9           g_rt_log_4       = NULL;
LPDIRECT3DTEXTURE9           g_rt_log_1       = NULL;
LPDIRECT3DTEXTURE9           g_rt_log_adapted = NULL;
LPDIRECT3DTEXTURE9           g_rt_log_prev    = NULL;
LPDIRECT3DTEXTURE9           g_rt_bloom_256   = NULL;
LPDIRECT3DTEXTURE9           g_rt_bloom_64    = NULL;
LPDIRECT3DTEXTURE9           g_rt_bloom_16    = NULL;
LPDIRECT3DTEXTURE9           g_rt_ldr         = NULL;

LPDIRECT3DSURFACE9           g_ds_hdr         = NULL;
LPDIRECT3DSURFACE9           g_ds_log_256     = NULL;
LPDIRECT3DSURFACE9           g_ds_log_64      = NULL;
LPDIRECT3DSURFACE9           g_ds_log_16      = NULL;
LPDIRECT3DSURFACE9           g_ds_log_4       = NULL;
LPDIRECT3DSURFACE9           g_ds_log_1       = NULL;
LPDIRECT3DSURFACE9           g_ds_ldr         = NULL;

LPDIRECT3DVERTEXDECLARATION9 g_declaration    = NULL;
LPDIRECT3DVERTEXSHADER9      g_vs_posteffect  = NULL;
LPDIRECT3DPIXELSHADER9       g_ps_log         = NULL;
LPDIRECT3DPIXELSHADER9       g_ps_small       = NULL;
LPDIRECT3DPIXELSHADER9       g_ps_adapted     = NULL;
LPDIRECT3DPIXELSHADER9       g_ps_through     = NULL;
LPDIRECT3DPIXELSHADER9       g_ps_bloom       = NULL;
LPDIRECT3DPIXELSHADER9       g_ps_final       = NULL;

static D3DXVECTOR4 c_adapted_param( 8.0f, 0.0f, 0.0f, 0.0f );
static D3DXVECTOR4 c_bloom_param( 0.1f, 0.8f, 0.0f, 0.0f );
static D3DXVECTOR4 c_final_param( 1.0f, 0.0f, 0.0f, 0.0f );
static Float       c_luminance_bias = 2.0f;
////////////////////////////////////////////////////////////////////////////////
//-------------
// NN の初期化
//-------------
static void InitNN(void)
{
	g_device = (LPDIRECT3DDEVICE9) nnGetDirect3DDeviceDXG20();
    
	// デバッグプリント初期化
	Uint32 size;
	size      = nnGetPrintBufferSize( DEBUG_CHAR_MAX );
	pPrintBuf = smpMemAlloc( size );
	nnInitPrint( pPrintBuf, DEBUG_CHAR_MAX, NULL );

	// マトリクススタック領域の確保、設定
	pMtxStackBuf = smpMemAlloc( MATRIX_STACK_SIZE * sizeof( NNS_MATRIX ) );
	nnSetUpMatrixStack( &gMtxStack, pMtxStackBuf, MATRIX_STACK_SIZE );

	// 標準シェーダーの初期化
	{
		NNS_STDSHADER_CONFIG shaderconfig;
		Uint32				 size;

		// 標準シェーダマネージャの初期化
        // 
		nnSetUpStdShaderConfigBasic( &shaderconfig );
		shaderconfig.bNormalizeVertexNormal	= NNE_TRUE;					// 頂点法線正規化
		//shaderconfig.bRescaleVertexNormal	= NNE_TRUE;					// 頂点法線再スケール
		shaderconfig.nMaxParallelLight		= 1;						// パラレルライト最大数
		shaderconfig.nMaxPointLight			= 0;						// ポイントライト最大数
		shaderconfig.nMaxSpotLight			= 0;						// スポットライト最大数
		shaderconfig.bLightAmbient			= NNE_FALSE;				// ライトアンビエント
		shaderconfig.PointLightDistAtten	= NNE_ATTEN_CONSTANT;		// ポイントライト距離減衰モデル
		//shaderconfig.PointLightDistAtten	= NNE_ATTEN_INVLINEAR;
		//shaderconfig.PointLightDistAtten	= NNE_ATTEN_INVQUADRATIC;
		shaderconfig.SpotLightDistAtten		= NNE_ATTEN_CONSTANT;		// スポットライト距離減衰モデル
		//shaderconfig.SpotLightDistAtten	= NNE_ATTEN_INVLINEAR;
		//shaderconfig.SpotLightDistAtten	= NNE_ATTEN_INVQUADRATIC;
		shaderconfig.FogModel				= NNE_FOG_NONE;				// フォグモデル
		//shaderconfig.FogModel				= NNE_FOG_LINEAR;
		//shaderconfig.FogModel				= NNE_FOG_EXP;
		//shaderconfig.FogModel				= NNE_FOG_EXP2;
		shaderconfig.bDistanceFog			= NNE_FALSE;				// 距離フォグ or Z値フォグ
		shaderconfig.bFragmentFog			= NNE_FALSE;				// フラグメントフォグ
        shaderconfig.nUserUniform           = 1;
		// 
		size = nnCalcStdShaderManageBufferSize( STDSHADER_NUM );
		pShaderMgrBuf = smpMemAlloc( size );
		nnConfigureStdShader( &shaderconfig,  pShaderMgrBuf, STDSHADER_NUM );

        // 標準シェーダコードのロード
        // 頂点シェーダ
		VsCodeSize = smpGetFileSize( STDVSPATH );
		pVsCodeBuf = smpMemAlloc( VsCodeSize );
		smpReadFile( STDVSPATH, pVsCodeBuf );
        // ピクセルシェーダー
		PsCodeSize = smpGetFileSize( STDPSPATH );
		pPsCodeBuf = smpMemAlloc( PsCodeSize );
		smpReadFile( STDPSPATH, pPsCodeBuf );
	}

    // 
	smpBinSetFilePath( BINPATH );
	smpTexSetFilePath( TEXPATH );

	// サンプル用パッドライブラリ初期化
	smpPadInit();
	pPad1 = smpPadGet( SMPPAD_PORT1 );	// １番ポート
	pPad2 = smpPadGet( SMPPAD_PORT2 );	// ２番ポート

	// サンプル用タイマライブラリ初期化
	smpTmrInit();
}

//------------------------
// サンプルデータのロード
//------------------------
static void LoadImage(void)
{
	Sint32 num;
	Uint32 size;
	NNS_OBJECT		*pLoadObject0;
	NNS_TEXFILELIST	*pTexFileList0;

	// オブジェクトデータロード
	size = smpBinGetFileSize( OBJECTFILE0 );
	pBuf0 = smpMemAlloc( size );
	smpBinReadFile( OBJECTFILE0, pBuf0 );

	// オブジェクトデータのセットアップ
	smpBinSetUpObject( &pLoadObject0, &pTexFileList0, pBuf0 );

	// ※※※ オブジェクトにD3Dリソースを割り当てる ※※※
	size = nnCalcVertexBufferObjectSizeDXG20(pLoadObject0, 0);
	pObject0 = (NNS_OBJECT*)smpMemAlloc( size );
	nnVertexBufferObjectDXG20( pObject0, pLoadObject0, 0);

	if(pTexFileList0 != NULL){
		// テクスチャ情報領域の確保 (TEXFILELIST0用)
		num = pTexFileList0->nTex;	// テクスチャ数
		pTexListBuf0 = smpMemAlloc( (Uint32)nnEstimateTexlistSize(num) );

		// テクスチャリストの初期化
		nnSetUpTexlist( &pTexList0, num, pTexListBuf0);

		// テクスチャのロード、テクスチャ情報の設定 (TEXFILELIST0用)
		if ( smpTexLoadFile( pTexList0, pTexFileList0 ) < 0 ){
			while(1){}	// Texture file read error
		}
	}

	// 読み込みオブジェクトデータ領域の解放
	smpMemFree( pBuf0 );

	// エンベロープオブジェクト作成(CPUエンベロープ時)
	size = nnCalcPliableObjectBufferSize( pObject0, 0 );
	pPliableObject0 = (NNS_PLIABLEOBJ*)smpMemAlloc( size );
	nnInitPliableObject( pPliableObject0, pObject0, 0 );

	// モーションデータロード キャラ
	size = smpBinGetFileSize( MOTIONFILE0 );
	pBuf1 = smpMemAlloc( size );
	smpBinReadFile( MOTIONFILE0, pBuf1 );
	smpBinSetUpMotion( &pMotion0, pBuf1 );

	// マトリクスパレット領域の確保 (OBJECT0用)
	num = pObject0->nMtxPal;	// マトリクスパレット数
	pMtxPalObject0 = (NNS_MATRIX*)smpMemAlloc( num * sizeof( NNS_MATRIX ) );

	// ノードステータスリスト領域の確保 (OBJECT0用)
	num = pObject0->nNode;	// ノード数
	pNodestatListObject0 = (NNF_NODESTATUS*)smpMemAlloc( num * sizeof( NNF_NODESTATUS ) );
}

//----------------------
// 標準シェーダーの作成
//----------------------
static void BuildStdShader(void)
{
	// シェーダー登録
	nnRegistObjectStdShaderProfiles( pObject0, drawflag );

	// CPUでエンベロープ計算して描画する場合は必要
	// プライアブルオブジェクト使用シェーダプロファイル登録
	nnRegistPliableObjectStdShaderProfiles( pPliableObject0, drawflag );

	// シェーダのインクルードのパス設定
	smpSetIncludePathDXG20(STDINCPATH);
#if OUTPUT_COMPILE_SHADER_ERROR
	// シェーダのコンパイルエラーコールバック関数の設定
	nnSetCompileErrorCallbackStdShaderDXG20(smpOutputCompileShaderErrorDXG20);
#endif
	// シェーダ作成
	nnBuildStdShader( (const char*)pVsCodeBuf, VsCodeSize,
					  (const char*)pPsCodeBuf, PsCodeSize );
}

//--------------------------
// メインループ前の初期設定
//--------------------------
static void SetInitEnv(void)
{
	D3DPRESENT_PARAMETERS *pD3DPP;
	pD3DPP = (D3DPRESENT_PARAMETERS*) nnGetD3DPresentParametersDXG20();

	// カメラ初期設定
	gCamera.Position    = gCamera.Target = pObject0->Center;
	gCamera.Position.z += -pObject0->Radius * 3.f;
	gCamera.Position.x += pObject0->Radius * 1.5f;
	gCamera.UpVector.x  = 0.f;					// アップベクトルX
	gCamera.UpVector.y  = 1.f;					// アップベクトルY
	gCamera.UpVector.z  = 0.f;					// アップベクトルZ
	gCamera.Fovy        = NNM_DEGtoA32( 45.f );	// カメラ視野角
	gCamera.Aspect      = (Float)pD3DPP->BackBufferWidth / (Float)pD3DPP->BackBufferHeight;	// アスペクト
	gCamera.ZNear       = 1.f;					// カメラ近接面
	gCamera.ZFar        = 10000.f;				// カメラ遠方面

	// プロジェクション設定
	nnMakePerspectiveMatrix( &gProjmtx, gCamera.Fovy, gCamera.Aspect,
										gCamera.ZNear, gCamera.ZFar );
	nnSetProjection( &gProjmtx, NNE_PROJECTION_TYPE_PERSPECTIVE );

	// ライトの初期設定
	//   全てのライトの初期化
	nnInitLight();
	//   環境光 RGB
	nnSetAmbientColor( 0.6f, 0.6f, 0.6f );

	//   ライト０初期設定
	nnSetUpParallelLight( &gLight, &gLightCol, gLightInten, &gLightDir );
	nnSetLight( NNE_LIGHT_0, &gLight, NND_LIGHTTYPE_PARALLEL );	// パラレルライト
	nnSetLightSwitch( NNE_LIGHT_0, NNE_ON );
}

//--------
// 初期化
//--------
#if 1
#define IzBool bool
#define IZ_TRUE true
#define IZ_FALSE false
#define IzHeapAlloc malloc
#define IzMemSet memset
#define IZ_SAFE_HEAPFREE(_x_) \
	{\
		if (_x_) {\
			free(_x_);\
			(_x_) = NULL;\
		}\
	}\

#include "stdio.h"

int FileGetSize(FILE *fp)
{
	int filesize = 0;

	fseek(fp, 0, SEEK_END);
	filesize = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	return filesize;
}

static IzBool SetVertexShaderFromFile(LPD3DXBUFFER *pCompiledShader, const char* filename, const char* func = "main" )
{
	FILE *fp;

	fp = fopen(filename, "rt");

	int size = FileGetSize(fp);

	char* src = (char*)IzHeapAlloc( size + 1 );
	IzMemSet( src, 0x00, size + 1 );

	fread(src, size, 1, fp);

	fclose(fp);

	HRESULT hr;
	LPD3DXCONSTANTTABLE pVertexConstTable;

	char errormsg[2048];
	LPD3DXBUFFER pErrorBuffer;

	hr = D3DXCompileShader( src, size, NULL, NULL, func, "vs_3_0", 0, pCompiledShader, &pErrorBuffer, &pVertexConstTable );
	if ( FAILED(hr) )
	{
		sprintf( errormsg, "%s", (char*)pErrorBuffer->GetBufferPointer() );
	}

	IZ_SAFE_HEAPFREE( src );

	if ( FAILED( hr ) ) {
		return IZ_FALSE;
	}

	return IZ_TRUE;
}

static IzBool SetPixelShaderFromFile( LPD3DXBUFFER *pCompiledShader, const char* filename, const char* func = "main" )
{
	FILE *fp;

	fp = fopen(filename, "rt");

	int size = FileGetSize(fp);

	char* src = (char*)IzHeapAlloc( size + 1 );
	IzMemSet( src, 0x00, size + 1 );

	fread(src, size, 1, fp);

	fclose(fp);

	HRESULT hr;
	LPD3DXCONSTANTTABLE pPixelConstTable;

	hr = D3DXCompileShader( src, size, NULL, NULL, func, "ps_3_0", 0, pCompiledShader, NULL, &pPixelConstTable );

	IZ_SAFE_HEAPFREE( src );

	if ( FAILED( hr ) ) {
		return IZ_FALSE;
	}

	return IZ_TRUE;
}

void SetVertexShader(LPDIRECT3DVERTEXSHADER9 *vs, char *filename)
{
	LPD3DXBUFFER compiledShader;
	SetVertexShaderFromFile(&compiledShader, filename);
	g_device->CreateVertexShader( reinterpret_cast<const DWORD *>(compiledShader->GetBufferPointer()), vs );
	compiledShader->Release();
}

void SetPixelShader(LPDIRECT3DPIXELSHADER9 *ps, char *filename)
{
	LPD3DXBUFFER compiledShader;
	SetPixelShaderFromFile(&compiledShader, filename);
	g_device->CreatePixelShader( reinterpret_cast<const DWORD *>(compiledShader->GetBufferPointer()), ps );
	compiledShader->Release();
}
#endif

void UserInit( void )
{
	pPrintBuf			= NULL;

	pMtxStackBuf		= NULL;

	{	// 標準シェーダ
		pShaderMgrBuf	= NULL;
		VsCodeSize		= 0;
		PsCodeSize		= 0;
		pVsCodeBuf		= NULL;
		pPsCodeBuf		= NULL;
	}
	{	// コントローラ
		pPad1			= NULL;
		pPad2			= NULL;
	}
	{	// データ
		pBuf0			= NULL;
		pObject0		= NULL;
		pMtxPalObject0	= NULL;
		pNodestatListObject0	= NULL;

		pTexListBuf0	= NULL;
		pTexList0		= NULL;

		pPliableObject0	= NULL;

		pBuf1			= NULL;
		pMotion0		= NULL;
	}
	//
	InitNN();
	//
	LoadImage();
	//
	BuildStdShader();
    // 頂点定義の作成
    D3DVERTEXELEMENT9 c_element[] = {
        { 0,  0, D3DDECLTYPE_FLOAT2,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_POSITION,  0 },
        { 0,  8, D3DDECLTYPE_FLOAT2,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_TEXCOORD,  0 },
        D3DDECL_END()
    };
    g_device->CreateVertexDeclaration( c_element, &g_declaration );
    
    //
	D3DXCreateTexture( g_device, 1024, 1024, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_hdr     );
	D3DXCreateTexture( g_device,  256,  256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_log_256 );
	D3DXCreateTexture( g_device,   64,   64, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_log_64  );
	D3DXCreateTexture( g_device,   16,   16, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_log_16  );
	D3DXCreateTexture( g_device,    4,    4, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_log_4   );
	D3DXCreateTexture( g_device,    1,    1, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_log_1   );
	D3DXCreateTexture( g_device,    1,    1, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_log_adapted );
	D3DXCreateTexture( g_device,    1,    1, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_log_prev  );
	D3DXCreateTexture( g_device,  256,  256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_bloom_256 );
	D3DXCreateTexture( g_device,   64,   64, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_bloom_64  );
	D3DXCreateTexture( g_device,   16,   16, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_bloom_16  );
	D3DXCreateTexture( g_device, 1024, 1024, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &g_rt_ldr     );

    g_device->CreateDepthStencilSurface( 1024, 1024, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &g_ds_hdr,     NULL );
    g_device->CreateDepthStencilSurface(  256,  256, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &g_ds_log_256, NULL );
    g_device->CreateDepthStencilSurface(   64,   64, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &g_ds_log_64,  NULL );
    g_device->CreateDepthStencilSurface(   16,   16, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &g_ds_log_16,  NULL );
    g_device->CreateDepthStencilSurface(    4,    4, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &g_ds_log_4,   NULL );
    g_device->CreateDepthStencilSurface(    1,    1, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &g_ds_log_1,   NULL );
    g_device->CreateDepthStencilSurface( 1024, 1024, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &g_ds_ldr,     NULL );

	SetVertexShader(&g_vs_posteffect, "s\\posteffect.vs");

	SetPixelShader(&g_ps_log, "s\\log.ps");
	SetPixelShader(&g_ps_small, "s\\small.ps");
	SetPixelShader(&g_ps_adapted, "s\\adapted.ps");
	SetPixelShader(&g_ps_through, "s\\through.ps");
	SetPixelShader(&g_ps_bloom, "s\\bloom.ps");
	SetPixelShader(&g_ps_final, "s\\final.ps");

#if 0
	g_device->CreateVertexShader( reinterpret_cast<const DWORD *>(g_posteffect_vs), &g_vs_posteffect );
	g_device->CreatePixelShader( reinterpret_cast<const DWORD *>(g_log_ps),     &g_ps_log     );
    g_device->CreatePixelShader( reinterpret_cast<const DWORD *>(g_small_ps),   &g_ps_small   );
    g_device->CreatePixelShader( reinterpret_cast<const DWORD *>(g_adapted_ps), &g_ps_adapted );
    g_device->CreatePixelShader( reinterpret_cast<const DWORD *>(g_through_ps), &g_ps_through );
    g_device->CreatePixelShader( reinterpret_cast<const DWORD *>(g_bloom_ps),   &g_ps_bloom  );
    g_device->CreatePixelShader( reinterpret_cast<const DWORD *>(g_final_ps),   &g_ps_final   );
#endif

	//
	SetInitEnv();
}

//------
// 終了
//------
void UserExit(void)
{
    SAFE_RELEASE( g_rt_ldr );
    SAFE_RELEASE( g_rt_log_prev );
    SAFE_RELEASE( g_rt_log_adapted );
    SAFE_RELEASE( g_rt_log_1 );
    SAFE_RELEASE( g_rt_log_4 );
    SAFE_RELEASE( g_rt_log_16 );
    SAFE_RELEASE( g_rt_log_64 );
    SAFE_RELEASE( g_rt_log_256 );
    SAFE_RELEASE( g_rt_hdr );
    SAFE_RELEASE( g_declaration );

	// テクスチャの解放 (TEXLIST0用)
	if(pTexList0 != NULL){
		if ( smpTexRelease( pTexList0 ) < 0 ){
			while(1){}	// Texture release error
		}
	}
	// テクスチャ情報領域の解放 (TEXLIST0用)
	smpMemFree( pTexListBuf0 );

	// エンベロープオブジェクト解放
	nnExitPliableObject( pPliableObject0 );
	smpMemFree( pPliableObject0 );

	// ノードステータスリスト領域の解放 (OBJECT0用)
	smpMemFree( pNodestatListObject0 );

	// マトリクスパレット領域の解放 (OBJECT0用)
	smpMemFree( pMtxPalObject0 );

	// ※※※ オブジェクトに割り当てたD3Dリソース解放 ※※※
	nnDeleteVertexObjectDXG20(pObject0);
	
	// オブジェクトデータ領域の解放
	smpMemFree( pObject0 );

	// モーションデータ領域の解放
	smpMemFree( pBuf1 );

	{	// シェーダの開放
		nnReleaseStdShader();			// ビルド済みシェーダ解放
		nnClearStdShaderProfiles();		// 登録済みシェーダの開放

		// シェーダーコード領域の開放
		smpMemFree( pPsCodeBuf );
		smpMemFree( pVsCodeBuf );

		// シェーダーマネージャー領域の開放
		smpMemFree( pShaderMgrBuf );
	}

	// マトリクススタック領域の解放
	smpMemFree( pMtxStackBuf );

	// デバッグプリントの終了
	nnExitPrint();
	smpMemFree( pPrintBuf );
}

//------------------------
// デバイスの消失時の処理
//------------------------
void UserDeviceLost(void)
{
	UserExit();
}

//--------------------------
// デバイスのリストアの処理
//--------------------------
void UserDeviceReset(void)
{
	UserInit();
}

//----------
// サンプル
//----------
static void Sample(void)
{
	NNS_MATRIX	viewmtx;	/* ビューマトリクス */
	NNS_MATRIX	objectmtx;	/* オブジェクトマトリクス */
	NNS_MATRIX	vomtx;		/* 描画用マトリクス */

	/* パッド情報更新 */
	smpPadCheck();

	/* カメラ前進 */
	if ( pPad1->On & SMPPAD_BTN_TR ){
		Float dist = nnDistanceVector( &gCamera.Position, &gCamera.Target );
		if ( dist > pObject0->Radius * 2.f ){
			nnApproachTargetUpVectorCamera( &gCamera, dist * 0.05f );
		}
	}
	/* カメラ後退 */
	if ( pPad1->On & SMPPAD_BTN_TL ){
		Float dist = nnDistanceVector( &gCamera.Position, &gCamera.Target );
		nnApproachTargetUpVectorCamera( &gCamera, -dist * 0.05f );
	}
	/* カメラ左右回り込み */
	if ( pPad1->On & SMPPAD_BTN_L ){
        switch( cursor ){
        case 0:
            c_luminance_bias -= 0.01f;
            if( c_luminance_bias < 0.0f ){
                c_luminance_bias = 0.0f;
            }
            break;
        case 1:
            c_final_param.x = 0.0f;
            break;
        case 2:
            c_adapted_param.x -= 0.1f;
            if( c_adapted_param.x < 0.0f ){
                c_adapted_param.x = 0.0f;
            }
            break;
        case 3:
            c_bloom_param.x -= 0.01f;
            if( c_bloom_param.x < 0.0f ){
                c_bloom_param.x = 0.0f;
            }
            break;
        case 4:
            c_bloom_param.y -= 0.01f;
            if( c_bloom_param.y < 0.0f ){
                c_bloom_param.y = 0.0f;
            }
            break;
        }
	}
	if ( pPad1->On & SMPPAD_BTN_R ){
        switch( cursor ){
        case 0:
            c_luminance_bias += 0.01f;
            if( 5.0f < c_luminance_bias ){
                c_luminance_bias = 5.0f;
            }
            break;
        case 1:
            c_final_param.x = 1.0f;
            break;
        case 2:
            c_adapted_param.x += 0.1f;
            if( 20.0f < c_adapted_param.x ){
                c_adapted_param.x = 20.0f;
            }
            break;
        case 3:
            c_bloom_param.x += 0.01f;
            if( 5.0f < c_bloom_param.x ){
                c_bloom_param.x = 5.0f;
            }
            break;
        case 4:
            c_bloom_param.y += 0.01f;
            if( 5.0f < c_bloom_param.y ){
                c_bloom_param.y = 5.0f;
            }
            break;
        }
	}
    
	if ( pPad1->Press & SMPPAD_BTN_U ){
        if( --cursor < 0 ){
            cursor = 0;
        }
	}
	if ( pPad1->Press & SMPPAD_BTN_D ){
        if( 4 < ++cursor ){
            cursor = 4;
        }
	}
	/* カメラロール */
	if ( pPad1->On & SMPPAD_BTN_X ){
		nnRollUpVectorCamera( &gCamera, NNM_DEGtoA32( -3.f ) );
	}
	if ( pPad1->On & SMPPAD_BTN_Y ){
		nnRollUpVectorCamera( &gCamera, NNM_DEGtoA32( 3.f ) );
	}
	/* カメラリセット */
	if( pPad1->Press & SMPPAD_BTN_ST ){
        atFirst = true;
	}

	/**************************/
	/* ビューマトリクスの計算 */
	/**************************/
	/* カメラからビューマトリクスを求める */
	nnMakeTargetUpVectorCameraViewMatrix( &viewmtx, &gCamera );

	/********************************/
	/* オブジェクトマトリクスの計算 */
	/********************************/
	/* オブジェクトのワールド内での姿勢（ここでは原点にそのまま） */
	nnMakeUnitMatrix( &objectmtx );

	/************************************/
	/* ライト用にビューマトリクスを設定 */
	/************************************/
	nnSetLightMatrix( &viewmtx );

	/* ライト設定の転送 */
	nnPutLightSettings();

	/************************/
	/* 描画用マトリクス生成 */
	/************************/
	nnMultiplyMatrix( &vomtx, &viewmtx, &objectmtx );

	/* ノードステータスリストのクリア */
	nnSetUpNodeStatusList( pNodestatListObject0, pObject0->nNode, NND_NODESTATUS_NONE );

	/* マトリクスパレット計算 */
    nnCalcMatrixPaletteMotion( pMtxPalObject0, pNodestatListObject0, pObject0, pMotion0, Frame, &vomtx, &gMtxStack, 0 );

	/* モーションを進める */
    Frame += 1.f;

	/* モーションリピート */
	if( Frame >= pMotion0->EndFrame ){
		Frame = pMotion0->StartFrame;
	}

    nnSetUserUniformDXG20( 0, c_luminance_bias, 0.0f, 0.0f, 0.0f );

	/********************/
	/* テクスチャセット */
	/********************/
	nnSetTextureList( pTexList0 );

	/****************************/
	/* シェーダエンベロープ描画 */
	/****************************/
	/*============================================================================
	   ※NND_SUBOBJTYPE_PLIABLE or NND_SUBOBJTYPE_PLIABILITY_ALL を指定するだけで
	     シェーダエンベロープになる。
	   ※nnDrawObject はシェーダエンベロープのみでCPUエンベロープはありません。
	  ============================================================================*/
	EnvStartTick = EnvEndTick = 0;
	DrawStartTick = smpTmrGet();
	/* NNオブジェクト描画（不透明）*/
	nnDrawObject( pObject0, pMtxPalObject0, pNodestatListObject0, NND_SUBOBJTYPE_OPAQUE | NND_SUBOBJTYPE_PUNCHTHROUGH | NND_SUBOBJTYPE_PLIABILITY_ALL, drawflag );
	/* NNオブジェクト描画（半透明）*/
	nnDrawObject( pObject0, pMtxPalObject0, pNodestatListObject0, NND_SUBOBJTYPE_TRANSPARENT | NND_SUBOBJTYPE_PLIABILITY_ALL, drawflag );
	DrawEndTick = smpTmrGet();
}

//----------------
// テクスチャ表示
//----------------
static void dispTexture( Sint32 num0, Sint32 num1, LPDIRECT3DTEXTURE9 pTexture, bool mode = true )
{
	// カリング無効
	g_device->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
	// ブレンド無効
	g_device->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
	g_device->SetRenderState( D3DRS_SEPARATEALPHABLENDENABLE , FALSE );
	// ライティング無効
	g_device->SetRenderState( D3DRS_LIGHTING, FALSE );
	//
	g_device->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID);
	// 深度バッファリングを無効
	g_device->SetRenderState( D3DRS_ZENABLE, FALSE );
	// サンプラステート設定
	g_device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
	g_device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
	g_device->SetSamplerState(0, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP);
	g_device->SetSamplerState(0, D3DSAMP_BORDERCOLOR, D3DCOLOR_RGBA(255, 255, 255, 255));
	g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
	g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
	g_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
	g_device->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, 0);
	g_device->SetSamplerState(0, D3DSAMP_MAXMIPLEVEL, 0);
	g_device->SetSamplerState(0, D3DSAMP_MAXANISOTROPY,1);
	g_device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, 0);
	g_device->SetSamplerState(0, D3DSAMP_ELEMENTINDEX, 0);
	g_device->SetSamplerState(0, D3DSAMP_DMAPOFFSET, 0);
	//
	g_device->SetTextureStageState(0,D3DTSS_COLOROP,	D3DTOP_SELECTARG1);
	g_device->SetTextureStageState(0,D3DTSS_COLORARG1,	D3DTA_TEXTURE);
	g_device->SetTextureStageState(1,D3DTSS_COLOROP,    D3DTOP_DISABLE);
	FLOAT size = 128.0f;
	struct TVERTEX{
		    FLOAT       p[4];
			FLOAT       tu, tv;
	} Vertex[4] = {
		// x      y  z rhw tu tv
		{   0, size, 0, 1, 0, 1,},
		{size, size, 0, 1, 1, 1,},
		{size,    0, 0, 1, 1, 0,},
		{   0,    0, 0, 1, 0, 0,},
	};
	D3DVIEWPORT9 vp;
	g_device->GetViewport(&vp);
	for(int i=0;i<4; i++){
		Vertex[i].p[0] += (Float)num0 * size + (Float)(1 * num0);
        if( mode )
        {
            Vertex[i].p[1] += (Float)num1 * size + (Float)(1 * num1);
        } else {
            Vertex[i].p[1] += (Float)vp.Height - size;
        }
	}
	g_device->SetTexture( 0, pTexture );
	g_device->SetFVF( D3DFVF_XYZRHW | D3DFVF_TEX1 );
	g_device->SetVertexShader(NULL);
	g_device->SetPixelShader(NULL);
	g_device->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, Vertex, sizeof( TVERTEX ) );
	//
	nnResetVertexDeclarationDXG20();
}

//--------
// パス
//--------
void Pass( LPDIRECT3DPIXELSHADER9 ps,
           LPDIRECT3DTEXTURE9 pTexture0,
           LPDIRECT3DTEXTURE9 pTexture1 = NULL,
           LPDIRECT3DTEXTURE9 pTexture2 = NULL,
           LPDIRECT3DTEXTURE9 pTexture3 = NULL,
           LPDIRECT3DTEXTURE9 pTexture4 = NULL )
{
    {
        D3DSURFACE_DESC desc;
        pTexture0->GetLevelDesc( 0, &desc );
        D3DXVECTOR4 sz( 1.0f/FLOAT(desc.Width), 1.0f/FLOAT(desc.Height), 0.0f, 1.0f );
        g_device->SetPixelShaderConstantF( 0, reinterpret_cast<const float *>(&sz), 1 );
    }

    g_device->SetVertexShader( g_vs_posteffect );
    g_device->SetPixelShader( ps );

	// カリング無効
	g_device->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
	//
	g_device->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
	// 深度バッファリングを無効
	g_device->SetRenderState( D3DRS_ZENABLE, FALSE );
	// ブレンド無効
    g_device->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
    g_device->SetRenderState( D3DRS_SEPARATEALPHABLENDENABLE, FALSE );
	// サンプラステート設定
	g_device->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
	g_device->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
	g_device->SetSamplerState( 0, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP );
	g_device->SetSamplerState( 0, D3DSAMP_BORDERCOLOR, D3DCOLOR_RGBA(255, 255, 255, 255));
	g_device->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
	g_device->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
	g_device->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );

	g_device->SetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
	g_device->SetSamplerState( 1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
	g_device->SetSamplerState( 1, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP );
	g_device->SetSamplerState( 1, D3DSAMP_BORDERCOLOR, D3DCOLOR_RGBA(255, 255, 255, 255));
	g_device->SetSamplerState( 1, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
	g_device->SetSamplerState( 1, D3DSAMP_MINFILTER, D3DTEXF_POINT );
	g_device->SetSamplerState( 1, D3DSAMP_MIPFILTER, D3DTEXF_NONE );

	g_device->SetSamplerState( 2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
	g_device->SetSamplerState( 2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
	g_device->SetSamplerState( 2, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP );
	g_device->SetSamplerState( 2, D3DSAMP_BORDERCOLOR, D3DCOLOR_RGBA(255, 255, 255, 255));
	g_device->SetSamplerState( 2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
	g_device->SetSamplerState( 2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
	g_device->SetSamplerState( 2, D3DSAMP_MIPFILTER, D3DTEXF_NONE );

	g_device->SetSamplerState( 3, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
	g_device->SetSamplerState( 3, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
	g_device->SetSamplerState( 3, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP );
	g_device->SetSamplerState( 3, D3DSAMP_BORDERCOLOR, D3DCOLOR_RGBA(255, 255, 255, 255));
	g_device->SetSamplerState( 3, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
	g_device->SetSamplerState( 3, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
	g_device->SetSamplerState( 3, D3DSAMP_MIPFILTER, D3DTEXF_NONE );

	g_device->SetSamplerState( 4, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
	g_device->SetSamplerState( 4, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
	g_device->SetSamplerState( 4, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP );
	g_device->SetSamplerState( 4, D3DSAMP_BORDERCOLOR, D3DCOLOR_RGBA(255, 255, 255, 255));
	g_device->SetSamplerState( 4, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
	g_device->SetSamplerState( 4, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
	g_device->SetSamplerState( 4, D3DSAMP_MIPFILTER, D3DTEXF_NONE );
    
	g_device->SetSamplerState( 0, D3DSAMP_MIPMAPLODBIAS, 0 );
	g_device->SetSamplerState( 0, D3DSAMP_MAXMIPLEVEL,   0 );
	g_device->SetSamplerState( 0, D3DSAMP_MAXANISOTROPY, 1 );
	g_device->SetSamplerState( 0, D3DSAMP_SRGBTEXTURE,   0 );
	g_device->SetSamplerState( 0, D3DSAMP_ELEMENTINDEX,  0 );
	g_device->SetSamplerState( 0, D3DSAMP_DMAPOFFSET,    0 );
	//
	struct TVERTEX{
		    FLOAT       p[2];
			FLOAT       tu, tv;
	} Vertex[4] = {
		// x      y  z rhw tu tv
		{  -1, -1, 0, 1,},
		{   1, -1, 1, 1 },
		{   1,  1, 1, 0,},
		{  -1,  1, 0, 0,},
	};
	g_device->SetTexture( 0, pTexture0 );
	g_device->SetTexture( 1, pTexture1 );
	g_device->SetTexture( 2, pTexture2 );
	g_device->SetTexture( 3, pTexture3 );
	g_device->SetTexture( 4, pTexture4 );
    g_device->SetVertexDeclaration( g_declaration );
	g_device->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, Vertex, sizeof( TVERTEX ) );
	g_device->SetTexture( 0, NULL );
	g_device->SetTexture( 1, NULL );
	g_device->SetTexture( 2, NULL );
	g_device->SetTexture( 3, NULL );
	g_device->SetTexture( 4, NULL );
	//
	nnResetVertexDeclarationDXG20();
}

//--------
// ポストプロセス
//--------
void Process( LPDIRECT3DTEXTURE9 pRenderTarget,
              LPDIRECT3DSURFACE9 pDepthStencil,
              LPDIRECT3DPIXELSHADER9 ps,
              LPDIRECT3DTEXTURE9 pTexture0,
              LPDIRECT3DTEXTURE9 pTexture1 = NULL,
              LPDIRECT3DTEXTURE9 pTexture2 = NULL,
              LPDIRECT3DTEXTURE9 pTexture3 = NULL,
              LPDIRECT3DTEXTURE9 pTexture4 = NULL )
{
    LPDIRECT3DSURFACE9 pSuf;
    pRenderTarget->GetSurfaceLevel( 0, &pSuf );
    g_device->SetRenderTarget( 0, pSuf );
    g_device->SetDepthStencilSurface( pDepthStencil );
    g_device->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0x00, 0x00, 0x00), 1.0f, 0 );
    if(SUCCEEDED(g_device->BeginScene()))
    {
        Pass( ps, pTexture0, pTexture1, pTexture2, pTexture3, pTexture4 );
        g_device->EndScene();
    }
    SAFE_RELEASE( pSuf );
}

//--------
// メイン
//--------
void UserMain(void)
{
	Uint32 starttick, endtick;

	// フレーム開始時刻取得
	starttick = smpTmrGet();
	{
        // バックバッファの保存
        LPDIRECT3DSURFACE9 pOld_RT;
        LPDIRECT3DSURFACE9 pOld_DS;
        g_device->GetRenderTarget( 0, &pOld_RT );
        g_device->GetDepthStencilSurface( &pOld_DS );

        // 過去の平均輝度をクリアしておこう
        if( atFirst )
        {
            LPDIRECT3DSURFACE9 pSuf;
            g_rt_log_prev->GetSurfaceLevel( 0, &pSuf );
            g_device->SetRenderTarget( 0, pSuf );
            g_device->SetDepthStencilSurface( g_ds_log_1 );
            g_device->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0x00, 0x00, 0x00, 0x00), 1.0f, 0 );
            if(SUCCEEDED(g_device->BeginScene()))
            {
                g_device->EndScene();
            }
            SAFE_RELEASE( pSuf );
            atFirst = false;
        }

        // オフスクリーンレンダリング( High Dynamic Range )
        {
            LPDIRECT3DSURFACE9 pSuf;
            g_rt_hdr->GetSurfaceLevel( 0, &pSuf );
            g_device->SetRenderTarget( 0, pSuf );
            g_device->SetDepthStencilSurface( g_ds_hdr );
            g_device->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0x00, 0x00, 0x80), 1.0f, 0 );
            if(SUCCEEDED(g_device->BeginScene()))
            {
                Sample();
                g_device->EndScene();
            }
            SAFE_RELEASE( pSuf );
        }

        // 対数平均の算出
        g_device->SetPixelShaderConstantF( 1, reinterpret_cast<const float *>(&c_adapted_param), 1 );
        Process( g_rt_log_256,     g_ds_log_256, g_ps_log,     g_rt_hdr );
        Process( g_rt_log_64,      g_ds_log_64,  g_ps_small,   g_rt_log_256 );
        Process( g_rt_log_16,      g_ds_log_16,  g_ps_small,   g_rt_log_64 );
        Process( g_rt_log_4,       g_ds_log_4,   g_ps_small,   g_rt_log_16 );
        Process( g_rt_log_1,       g_ds_log_1,   g_ps_small,   g_rt_log_4 );
        Process( g_rt_log_adapted, g_ds_log_1,   g_ps_adapted, g_rt_log_1, g_rt_log_prev );
        Process( g_rt_log_prev,    g_ds_log_1,   g_ps_through, g_rt_log_adapted );

        // ブルーム処理
        g_device->SetPixelShaderConstantF( 1, reinterpret_cast<const float *>(&c_bloom_param), 1 );
        Process( g_rt_bloom_256,   g_ds_log_256, g_ps_bloom,   g_rt_hdr       );
        Process( g_rt_bloom_64,    g_ds_log_64,  g_ps_bloom,   g_rt_bloom_256 );
        Process( g_rt_bloom_16,    g_ds_log_16,  g_ps_bloom,   g_rt_bloom_64  );
        
        // 最終映像作成
        g_device->SetPixelShaderConstantF( 1, reinterpret_cast<const float *>(&c_final_param), 1 );
        Process( g_rt_ldr, g_ds_ldr, g_ps_final, g_rt_hdr, g_rt_log_adapted, g_rt_bloom_256, g_rt_bloom_64, g_rt_bloom_16 );

        // バックバッファへのレンダリング
        {
            g_device->SetRenderTarget( 0, pOld_RT );
            g_device->SetDepthStencilSurface( pOld_DS );
            g_device->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0x80,0x80,0x80), 1.0f, 0 );
            if(SUCCEEDED(g_device->BeginScene()))
            {
                Pass( g_ps_through, g_rt_ldr );
                dispTexture( 0, 0, g_rt_hdr );
                dispTexture( 1, 0, g_rt_log_256 );
                dispTexture( 2, 0, g_rt_log_64  );
                dispTexture( 3, 0, g_rt_log_16  );
                dispTexture( 4, 0, g_rt_log_4   );
                dispTexture( 5, 0, g_rt_log_1   );
                dispTexture( 6, 0, g_rt_log_adapted );
                dispTexture( 0, 0, g_rt_hdr, false );
                dispTexture( 1, 0, g_rt_bloom_256, false );
                dispTexture( 2, 0, g_rt_bloom_64, false  );
                dispTexture( 3, 0, g_rt_bloom_16, false  );
                g_device->SetTexture( 0, NULL );
                
                // フレーム終了時刻取得
                endtick = smpTmrGet();

                // 情報表示
                nnPrint( 3,  3, "NN "SAMPLENAME" SAMPLE" );
                nnPrint( 3,  5, "ALL      CPU Time%6d[us]", smpTmrDiff( endtick, starttick ) );
                nnPrint( 3,  6, "ENVELOPE CPU Time%6d[us]", smpTmrDiff( EnvEndTick, EnvStartTick ) );
                nnPrint( 3,  7, "DRAW     CPU Time%6d[us]", smpTmrDiff( DrawEndTick, DrawStartTick ) );
                nnPrint( 3,  9 + cursor, ">" );
                nnPrint( 5,  9, "USER UNIFORM    x%1.2f", c_luminance_bias );
                nnPrint( 5, 10, "TONE MAP         %s", (c_final_param.x == 0.0f) ? "FALSE" : "TRUE" );
                nnPrint( 5, 11, "ADAPTED          %2.1f[s]", c_adapted_param.x );
                nnPrint( 5, 12, "BLOOM THRESHOLD  %1.2f[lum]", c_bloom_param.x );
                nnPrint( 5, 13, "BLOOM BIAS      x%1.2f", c_bloom_param.y );

                // 登録文字の描画
                nnFlushPrint();

                g_device->EndScene();
            }
        }

        SAFE_RELEASE( pOld_RT );
        SAFE_RELEASE( pOld_DS );
    }
}
