#include "stdafx.h"
#include "DepthPlane.h"

#include "DepthPlaneObject.h"
#include "SceneManager.h"

#include "RenderSystem.h"

///
void cPlane::WorldPtToScreenPt( NiCamera* pCam, const NiPoint3& pt, float& posX, float& posY, bool InScreen )
{
	assert(pCam);
	const float* mat = pCam->GetWorldToCameraMatrix();
	NiRect<float> port = pCam->GetViewPort();

	// project a world space point to screen space
	float fW = pt.x * (*(mat + (4*3))) + pt.y * (*(mat + (4*3+1))) 
		+ pt.z * (*(mat + (4*3+2))) + (*(mat + (4*3+3)));

	if( fW > 1e-5f )
	{
		float fInvW = 1.0f / fW;

		posX = pt.x * (*mat) + pt.y * (*(mat + 1))
			+ pt.z * (*(mat + 2)) + (*(mat + 3));
		posY = pt.x * (*(mat + (4*1+0))) + pt.y * (*(mat + (4*1+1)))
			+ pt.z * (*(mat + (4*1+2))) + (*(mat + (4*1+3)));

		posX = posX * fInvW;
		posY = posY * fInvW;

		if( InScreen )
		{
			/// 스크린상에서 벗어나는 경우 보정
			if( posX < -1.0f ) posX = -1.0f;
			if( posY < -1.0f ) posY = -1.0f;

			if( posX > 1.0f ) posX = 1.0f;
			if( posY > 1.0f ) posY = 1.0f;
		}

		posX *= (port.m_right - port.m_left) * 0.5f;
		posY *= (port.m_top - port.m_bottom) * 0.5f;

		posX += (port.m_right + port.m_left) * 0.5f;
		posY += (port.m_top + port.m_bottom) * 0.5f;
	}
	else
	{
//		assert(0);
		return;
	}
}

//////////////////////////////////////////////////////////////////////////
///
cDepthPlane::cDepthPlane( unsigned int width, unsigned int height )
{
	mpRenderTargetPlane = NiNew cDepthPlaneObject( NiNew cDepthPlaneData(width, height) );
	assert(mpRenderTargetPlane);

	NiRenderer* pRenderer = NiRenderer::GetRenderer();

	/// rendered texture 구성..
	NiTexture::FormatPrefs prefs;
	const NiRenderTargetGroup* pkRTGroup = pRenderer->GetDefaultRenderTargetGroup();
	const NiPixelFormat* pkPixelFormat = pkRTGroup->GetPixelFormat(0);
	if (pkPixelFormat->GetBitsPerPixel() == 16)
	{
		prefs.m_ePixelLayout = NiTexture::FormatPrefs::HIGH_COLOR_16;
	}
	else
	{
		prefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32;
	}
	prefs.m_ePixelLayout = NiTexture::FormatPrefs::PIX_DEFAULT;
	prefs.m_eAlphaFmt = NiTexture::FormatPrefs::SMOOTH;
	prefs.m_eMipMapped = NiTexture::FormatPrefs::NO;

	mpRenderedTexture = NiRenderedTexture::Create( width, height, pRenderer, prefs );
	assert(mpRenderedTexture);

	mpRenderTargetGroup = NiRenderTargetGroup::Create( mpRenderedTexture->GetBuffer(), pRenderer, false, false );
	assert(mpRenderTargetGroup);

	/// Texture Set 구성..
	NiTexturingProperty::Map* pkMap = NiNew NiTexturingProperty::Map( mpRenderedTexture, 0 );

	assert(pkMap);
	NiTexturingProperty* pkTex = NiNew NiTexturingProperty();
	assert(pkTex);
	pkTex->SetBaseMap(pkMap);
//	pkTex->SetBaseClampMode( NiTexturingProperty::CLAMP_S_CLAMP_T );
	pkTex->SetApplyMode( NiTexturingProperty::APPLY_REPLACE );
	pkTex->SetBaseFilterMode( NiTexturingProperty::FILTER_NEAREST_MIPNEAREST );
	mpRenderTargetPlane->AttachProperty(pkTex);

	/// use vertex colors
	NiVertexColorProperty* pVertex = NiNew NiVertexColorProperty;
	pVertex->SetSourceMode( NiVertexColorProperty::SOURCE_EMISSIVE );
	pVertex->SetLightingMode( NiVertexColorProperty::LIGHTING_E );
	mpRenderTargetPlane->AttachProperty( pVertex );

	/// use Alpha 
	NiAlphaProperty* pAlpha = NiNew NiAlphaProperty;
	pAlpha->SetAlphaBlending( true );
	pAlpha->SetAlphaTesting( true );
	pAlpha->SetTestMode( NiAlphaProperty::TEST_GREATEREQUAL );
	pAlpha->SetTestRef( 230 );

	mpRenderTargetPlane->AttachProperty( pAlpha );

	NiZBufferProperty* pZbuffer = NiNew NiZBufferProperty;
//	pZbuffer->SetZBufferWrite( false );
	mpRenderTargetPlane->AttachProperty( pZbuffer );

	/// plane update
	bool selectiveUpdate = true;
	bool rigid = false;
	mpRenderTargetPlane->SetSelectiveUpdateFlags( selectiveUpdate, true, rigid );
	mpRenderTargetPlane->Update( 0.f );
	mpRenderTargetPlane->UpdateProperties();
	mpRenderTargetPlane->UpdateEffects();

	/// 뒷배경 색깔 지정
	mBackColor = NiColorA(0.0f,0.0f,0.0f,0.0f);
}

cDepthPlane::~cDepthPlane() 
{
	NiDelete mpRenderTargetPlane;
}

void cDepthPlane::OnUpdate( NiCamera* pCamera, const NiPoint3& pos, float scale )
{
	/// 객체의 변환을 실행한다.
	mpRenderTargetPlane->SetTranslate( pos );
	mpRenderTargetPlane->SetScale( scale );
	mpRenderTargetPlane->UpdateSelected(0.0f);

	/// 카메라와 관련된 처리들을 한다.
	mpRenderTargetPlane->OnUpdate( pCamera );
}

/// 주의사항 : 등록된 DepthPlane에 대해서 SceneManager가 호출한다.
void cDepthPlane::Compose( NiDX9Renderer* pRenderer )
{
	if( RENDERSYS->mReCreateContinue == true )
		return;

//	if( pRenderer->IsDeviceLost() )
//		return;

	/// 버퍼 클리어 컬러 지정
	pRenderer->SetBackgroundColor( mBackColor );
	if( pRenderer->BeginUsingRenderTargetGroup( mpRenderTargetGroup, NiRenderer::CLEAR_ALL ) )
	{
		pRenderer->SetScreenSpaceCameraData();
		RenderFrame();

		pRenderer->EndUsingRenderTargetGroup();
	}
}

/// 주의사항 : 등록된 DepthPlane에 대해서 SceneManager가 호출한다.
void cDepthPlane::Render( NiRenderer* pRenderer )
{
	mpRenderTargetPlane->Draw( pRenderer );
}