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

    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"

////////////////////////////////////////////////////////////////////////////////
#define SAMPLENAME "SHADER ENVELOPE"

#define DEBUG_CHAR_MAX	(1200)

#define NO_TEX					0
#define NO_MOT					0

////////////////////////////////////////////////////////////////////////////////
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用バイナリロード用バッファ(メモリの解放が必要)
#if !NO_MOT
static NNS_MOTION		*pMotion0;				// MOTION0(メモリの解放が必要)
#endif

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

////////////////////////////////////////////////////////////////////////////////
// モーションモード
static enum {
	MOTION_OFF,
	MOTION_ON,
#if NO_MOT
} gMotionMode = MOTION_OFF;
#else
} gMotionMode = MOTION_ON;
#endif
static Float						Frame = 0.0f;	// フレーム数

// エンベロープ描画モード
static enum {
	SHADERENVELOPE_OFF,
	SHADERENVELOPE_ON,
} gShaderEnvelopeMode = SHADERENVELOPE_OFF;

//
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;					// 強さ

////////////////////////////////////////////////////////////////////////////////
//-------------
// NN の初期化
//-------------
static void InitNN(void)
{
	// デバッグプリント初期化
	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;				// フラグメントフォグ
		// 
		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 );

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

	// マトリクスパレット領域の確保 (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 );
}

//--------
// 初期化
//--------
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;
#if !NO_MOT
		pMotion0		= NULL;
#endif
	}
	//
	InitNN();
	//
	LoadImage();
	//
	BuildStdShader();
	//
	SetInitEnv();
}

//------
// 終了
//------
void UserExit(void)
{
	// テクスチャの解放 (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 ){
		nnRotateUpVectorCameraAroundTargetH( &gCamera, NNM_DEGtoA32( -3.f ) );
	}
	if ( pPad1->On & SMPPAD_BTN_R ){
		nnRotateUpVectorCameraAroundTargetH( &gCamera, NNM_DEGtoA32( 3.f ) );
	}
	/* カメラ上下回り込み */
	if ( pPad1->On & SMPPAD_BTN_U ){
		nnRotateUpVectorCameraAroundTargetV( &gCamera, NNM_DEGtoA32( -3.f ) );
	}
	if ( pPad1->On & SMPPAD_BTN_D ){
		nnRotateUpVectorCameraAroundTargetV( &gCamera, NNM_DEGtoA32( 3.f ) );
	}
	/* カメラロール */
	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->Y1 > 50 ){
		nnMoveUpVectorCameraLocal( &gCamera, 0.f, -0.1f * pObject0->Radius, 0.f );
	}
	if ( pPad1->Y1 < -50 ){
		nnMoveUpVectorCameraLocal( &gCamera, 0.f, 0.1f * pObject0->Radius, 0.f );
	}
	if ( pPad1->X1 > 50 ){
		nnMoveUpVectorCameraLocal( &gCamera, -0.1f * pObject0->Radius, 0.f, 0.f );
	}
	if ( pPad1->X1 < -50 ){
		nnMoveUpVectorCameraLocal( &gCamera, 0.1f * pObject0->Radius, 0.f, 0.f );
	}
	/* カメラリセット */
	if( pPad1->Press & SMPPAD_BTN_ST ){
		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 */
	}

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

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

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

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

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

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

	/* マトリクスパレット計算 */
	if ( gMotionMode == MOTION_OFF ){	/* モーションなし */
		nnCalcMatrixPalette( pMtxPalObject0, pNodestatListObject0, pObject0,
								&vomtx, &gMtxStack, 0 );
	} else {
#if !NO_MOT
		nnCalcMatrixPaletteMotion( pMtxPalObject0, pNodestatListObject0, pObject0,
								pMotion0, Frame, &vomtx, &gMtxStack, 0 );
#else
		nnCalcMatrixPalette( pMtxPalObject0, pNodestatListObject0, pObject0,
								&vomtx, &gMtxStack, 0 );
#endif
	}

	/* シェーダエンベロープモード変更 */
	if ( pPad1->Press == SMPPAD_BTN_A ){
		switch ( gShaderEnvelopeMode ) {
			case SHADERENVELOPE_OFF:
				gShaderEnvelopeMode = SHADERENVELOPE_ON;
				break;
			case SHADERENVELOPE_ON:
				gShaderEnvelopeMode = SHADERENVELOPE_OFF;
				break;
		}
	}

	/* モーションを進める */
	if ( gMotionMode == MOTION_ON ){
		Frame += 1.f;
	}
#if !NO_MOT
	/* モーションリピート */
	if( Frame >= pMotion0->EndFrame ){
		Frame = pMotion0->StartFrame;
	}
#endif
	/* モーションストップ */
	if ( pPad1->Press & SMPPAD_BTN_B ){
		if ( gMotionMode == MOTION_ON ){
			gMotionMode = MOTION_OFF;
		} else {
			gMotionMode = MOTION_ON;
		}
	}

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

	if ( gShaderEnvelopeMode == SHADERENVELOPE_OFF ){
		/* エンベロープオブジェクト計算（CPUエンベロープ時） */
		EnvStartTick = smpTmrGet();
		nnCalcPliableObject( pPliableObject0, pMtxPalObject0, 0 );
		EnvEndTick = smpTmrGet();
		DrawStartTick = smpTmrGet();
		/* NNオブジェクト描画（不透明、リジッド）*/
		nnDrawObject( pObject0, pMtxPalObject0, pNodestatListObject0,
			NND_SUBOBJTYPE_OPAQUE | NND_SUBOBJTYPE_PUNCHTHROUGH |
			NND_SUBOBJTYPE_RIGID, drawflag );
		/* NNオブジェクト描画（不透明、プライアブル）*/
		nnDrawPliableObject( pPliableObject0, NULL, pNodestatListObject0,
			NND_SUBOBJTYPE_OPAQUE | NND_SUBOBJTYPE_PUNCHTHROUGH, drawflag );
		/* NNオブジェクト描画（半透明、リジッド）*/
		nnDrawObject( pObject0, pMtxPalObject0, pNodestatListObject0,
			NND_SUBOBJTYPE_TRANSPARENT |
			NND_SUBOBJTYPE_RIGID, drawflag );
		/* NNオブジェクト描画（半透明、プライアブル）*/
		nnDrawPliableObject( pPliableObject0, NULL, pNodestatListObject0,
			NND_SUBOBJTYPE_TRANSPARENT, drawflag );
		DrawEndTick = smpTmrGet();
	} else {
		/****************************/
		/* シェーダエンベロープ描画 */
		/****************************/
		/*============================================================================
		   ※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();
	}
}

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

	// フレーム開始時刻取得
	starttick = smpTmrGet();
	{
		Sample();
	}
	// フレーム終了時刻取得
	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 ) );
	if ( gMotionMode == MOTION_OFF ){
		nnPrint( 3, 9, "[MOTION OFF]" );
	} else {
		nnPrint( 3, 9, "[MOTION ON]" );
	}
	nnPrint( 21, 9, "X key: Change Motion Mode" );
	if ( gShaderEnvelopeMode == SHADERENVELOPE_OFF ){
		nnPrint( 3, 11, "[CPU ENVELOPE]" );
	} else {
		nnPrint( 3, 11, "[SHADER ENVELOPE]" );
	}
	nnPrint( 21, 11, "Z key: Change Envelope Mode" );

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