
import "sample_app.rs" ;


class	CubeRenderableSprite	extends RenderableSprite
{
	private static const float[]	s_vertexCube = (float[])
	[
		-1, -1, -1,
		 1, -1, -1,
		-1,  1, -1,
		 1,  1, -1,
		-1, -1,  1,
		 1, -1,  1,
		-1,  1,  1,
		 1,  1,  1,
	] ;
	private static const int[]		s_faceCube = (int[])
	[
		0, 3, 1,
		0, 2, 3,
		4, 2, 0,
		4, 6, 2,
		1, 7, 5,
		1, 3, 7,
		5, 6, 4,
		5, 7, 6,
		4, 1, 5,
		4, 0, 1,
		2, 7, 3,
		2, 6, 7,
	] ;
	protected Material				m_material ;
	protected VertexBuffer			m_vbCube ;
	protected RenderContext.Light	m_lights ;
	protected Matrix3D				m_matRotate ;
	protected Vector3D				m_vMove ;

	// 表示領域矩形
	protected boolean getRenderRect( Rect rect )
	{
		rect.x = 0 ;
		rect.y = 0 ;
		rect.w = SampleApp.SCREEN_WIDTH ;
		rect.h = SampleApp.SCREEN_HEIGHT ;
		return	true ;
	}

	// マウスクリック当たり判定
	protected boolean isHitTest( double xLocal, double yLocal )
	{
		return	false ;
	}

	// 描画
	protected void onRender( RenderContext render, int s3dView )
	{
		// 背景を半透明描画
		render.fillRectangle
			( 0, 0, SampleApp.SCREEN_WIDTH,
					SampleApp.SCREEN_HEIGHT, 0x80000040 ) ;
		render.flush() ;

		// 3D レンダリングのための設定
		setPerspective( render ) ;
		setCameraTo( render ) ;
		render.setLightEntries( m_lights, 1 ) ;

		// 3D 描画開始（モデル空間の設定と標準の Phong シェーダー選択）
		render.begin3DRenderer() ;
		render.pushTransformation() ;
		render.setShadingFlag( Material.shadingMethodPhong ) ;
		render.appendMatrixTransformation( m_matRotate, m_vMove ) ;
		//
		// 立方体描画
		// 速度を気にしないなら VertexBuffer を使用せず、
		// renderCube( render ) ;
		// でも良い
		render.addVertexBuffer( 0, m_vbCube ) ;
		//
		// 3D 描画の終了とシェーディング設定を元に戻す
		render.popTransformation() ;
		render.end3DRenderer() ;
	}

	// タイマー処理
	protected void onTimer( int msecPast )
	{
		double	rx = msecPast * (Math.PI / 10000.0) ;
		double	ry = msecPast * (Math.PI / 7000.0) ;
		m_matRotate.rotateOnX( Math.sin(rx), Math.cos(rx) ) ;
		m_matRotate.rotateOnY( Math.sin(ry), Math.cos(ry) ) ;
		postUpdate() ;
	}


	// 初期設定
	public void initialize( void )
	{
		prepareMaterial() ;
		prepareCube() ;
		prepareLights() ;
		m_matRotate = new Matrix3D( 1, 0, 0,  0, 1, 0,  0, 0, 1 ) ;
		m_vMove = new Vector3D( 0, 0, 0 ) ;
	}

	// マテリアル準備
	public void prepareMaterial( void )
	{
		SurfaceAttribute	sufattr = new SurfaceAttribute() ;
		sufattr.flagsShading =
			Material.shadingMethodPhong
			| Material.shadingSingleSidePlane ;
		sufattr.colorBase.rgbMul = 0 ;
		sufattr.colorBase.rgbAdd = 0x00ffff ;
		sufattr.colorShade.rgbMul = 0 ;
		sufattr.colorShade.rgbAdd = 0x400040 ;
		sufattr.nAmbient = 0 ;
		sufattr.nDiffusion = 0x100 ;
		sufattr.nSpecular = 0x100 ;
		sufattr.nSpecularSize = 0x10 ;

		m_material = new Material() ;
		m_material.setSurfaceAttribute( sufattr ) ;
	}

	// 立方体準備
	public void prepareCube( void )
	{
		m_vbCube = new VertexBuffer() ;
		renderCube( m_vbCube ) ;
	}

	// 立方体描画
	public void renderCube( RenderBuffer render )
	{
		const int	nVertexCount = s_vertexCube.length() / 3 ;
		const int	nIndexCount = s_faceCube.length() ;
		const int	nTriangleCount = nIndexCount / 3 ;

		Vector3D4		pVertex = new Vector3D4( nVertexCount ) ;
		Uint32Pointer	pIndex = new Uint32Pointer( nIndexCount ) ;

		for ( int i = 0, j = 0; i < nVertexCount; i ++, j += 3 )
		{
			Vector3D4	v = pVertex + i ;
			v.x = s_vertexCube[j] ;
			v.y = s_vertexCube[j + 1] ;
			v.z = s_vertexCube[j + 2] ;
		}
		for ( int i = 0; i < nIndexCount; i ++ )
		{
			pIndex[i] = s_faceCube[i] ;
		}

		render.addPrimitiveList
			( m_material,
				RenderBuffer.renderAutoNormal,
				RenderBuffer.primitiveTriangle,
				nIndexCount, nVertexCount,
				pVertex, null, null, null, pIndex ) ;
	}

	// 光源準備
	public void prepareLights( void )
	{
		m_lights = new RenderContext.Light( 1 ) ;
		m_lights.typeLight = RenderContext.lightTypeVector ;
		m_lights.rgbColor = 0xffffff ;
		m_lights.fpBrightness = 1.0 ;
		m_lights.vecDirection.x = 0.5 ;
		m_lights.vecDirection.y = 1 ;
		m_lights.vecDirection.z = 0.7 ;
	}

	// 透視変換設定
	public void setPerspective( RenderContext render )
	{
		const double	degFOV = 65 ;
		const double	radHalfFOV = degFOV * 0.5 * Math.PI / 180 ;
		//
		Vector3D	vScreen = new Vector3D() ;
		vScreen.x = SampleApp.SCREEN_WIDTH * 0.5 ;
		vScreen.y = SampleApp.SCREEN_HEIGHT * 0.5 ;
		vScreen.z = vScreen.x / Math.tan(radHalfFOV) ;
		//
		render.setProjectionScreen( vScreen ) ;
		render.setZClipRange( 0.1, 100.0 ) ;
	}

	// カメラ設定
	public void setCameraTo( RenderContext render )
	{
		Vector3D 	vCameraPos = new Vector3D( 0.0, 0.0, -5.0 ) ;	// 視点
		Vector3D 	vCameraTarget = new Vector3D( 0.0, 0.0, 0.0 ) ;	// 注視点
		Vector3D 	vCameraTop = new Vector3D( 0.0, -1.0, 0.0 ) ;	// 天頂方向

		Matrix3D	matCamera = new Matrix3D() ;
		Vector3D	vCamera =
			matCamera.cameraAngleOf
				( vCameraTarget, vCameraPos, vCameraTop ) ;

		render.setCamera( matCamera, vCamera ) ;
	}

}


class	SpriteActionRunnable	implements Runnable
{
	public SampleApp			m_app ;
	public CubeRenderableSprite	m_cube ;

	public SpriteActionRunnable( SampleApp app )
	{
		m_app = app ;
	}

	public void run()
	{
		// 標準の Phong シェーダーを準備しておく
		RenderDevice	device = m_app.getWindow().getRenderDevice() ;
		device.buildCustomShader
			( RenderDevice.DefaultShaderId.Phong, null ) ;

		// RenderableSprite 準備
		m_cube = new CubeRenderableSprite() ;
		m_cube.setErrorMode( RenderableSprite.errorStdOut ) ;
		m_cube.initialize() ;

		// 表示
		m_app.getWindow().addChild( m_cube ) ;
		m_app.waitFor( function() : boolean { return false; } ) ;
	}

	public void releaseRef( void )
	{
		m_app.getWindow().detachChild( m_cube ) ;
		m_cube.dispose() ;
		m_cube = null ;
		m_app = null ;
	}
}


int main( String[] args )
{
	SampleApp	app = new SampleApp() ;
	app.initialize( "Renderable Sprite Sample" ) ;

	SpriteActionRunnable	runnable = new SpriteActionRunnable(app) ;
	try
	{
		app.run( runnable ) ;
	}
	finally
	{
		runnable.releaseRef() ;
		app.release() ;
	}
	return	0 ;
}


