#include "Mix/Private/Scene/Common/Camera.h"

#include "Mix/Graphics/ITexture.h"
#include "Mix/Graphics/Utility/ITargetTextureChain.h"

#include "Mix/Private/Scene/Common/ResourceManager.h"
#include "Mix/Private/Scene/Common/Renderer.h"
#include "Mix/Private/Scene/Common/OctreeView.h"

namespace Mix{ namespace Scene{ namespace Common{

//フォールオフの範囲の大きさの最小( 1mm )
const Float32 Camera::MIN_FALLOFF_AMOUNT = 0.001f;

//シャドウマッピング : PCFのサイズ
const UInt32 Camera::SM_PCF_SIZE_TABLE[Camera::SMPS_MAX] = { 3, 5, 7 };

//色収差が最大になる距離の最小( 1mm )
const Float32 Camera::CA_MIN_DIST = 0.001f;

//レンズフレア : ゴーストの最大数
const UInt32 Camera::LF_MIN_GHOST = 1;
const UInt32 Camera::LF_MAX_GHOST = 32;

//レンズフレア : ヘイローのバイアス行列0
const Mix::Matrix4x4 Camera::LF_CAM_BIAS_MAT0(	 2.0f,  0.0f, 0.0f, 0.0f,
												 0.0f,  2.0f, 0.0f, 0.0f,
												 0.0f,  0.0f, 1.0f, 0.0f,
												-1.0f, -1.0f, 0.0f, 1.0f );

//レンズフレア : ヘイローのバイアス行列1
const Mix::Matrix4x4 Camera::LF_CAM_BIAS_MAT1(	0.5f, 0.0f, 0.0f, 0.0f,
												0.0f, 0.5f, 0.0f, 0.0f,
												0.0f, 0.0f, 1.0f, 0.0f,
												0.5f, 0.5f, 0.0f, 1.0f );

const Float32 Camera::VIGNETTE_LEN = 0.707106769f;

Camera::Camera( const Mix::Scene::CAMERA_CONFIG& config ) :
m_pRenderer( NULL ),
m_pOctView( NULL ),
m_Config( config ),
m_ModConfigCaps( 0 ),
m_BGColor( 0.15f, 0.15f, 0.15f, 1.0f ),
m_FilterType( Mix::Graphics::TEXTURE_FILTER_POINT ),
m_FovY( 0.0f ),
m_DefAspect( MIX_FLOAT_DIV( static_cast<Float32>( m_Config.targetSize.x ), static_cast<Float32>( m_Config.targetSize.y ) ) ),
m_Aspect( 0.0f ),
m_NearZ( 0.0f ),
m_FarZ( 0.0f ),
m_bAOEnabled( False ),
m_pAOTex( NULL ),
m_bSMEnabled( False ),
m_LumAdSuspendCount( 0 ),
m_LumAdType( Camera::LUM_AD_FORCE ),
m_LumAdValue( 0.0f ),
m_bBloomEnabled( False ),
m_BloomOverflowNum( 0 ),
m_bLightShaftsEnabled( False ),
m_pLightShaftsTex( NULL ),
m_bLensFlareEnabled( False ),
m_bFilmicEnabled( False ),
m_FilmicType( Mix::Scene::ICamera::FI_NONE ),
m_FilmicSettingsSize( 0 ),
m_bGammaEnabled( False ),
m_GammaValue( 1.0f, 1.0f, 1.0f ),
m_bMotBlurEnabled( False ),
m_bChromatismEnabled( False ),
m_bDofEnabled( False ),
m_bLensDistEnabled( False ),
m_bVignetteEnabled( False ),
m_AAType( Mix::Scene::ICamera::AA_FXAA ),
m_bUnderWater( False )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_VisiSettings.loLimitDistance = 50.0f;
	m_VisiSettings.loFalloffAmount = 25.0f;

	m_VisiSettings.plLimitDistance = 100.0f;
	m_VisiSettings.plFalloffAmount = 80.0f;
	m_VisiSettings.plFalloffThreshold = 0.3f;

	m_VisiSettings.paLimitDistance = 50.0f;
	m_VisiSettings.paFalloffAmount = 0.0f;
	m_VisiSettings.paFalloffDuration = 0.0f;

	m_VisiSettings.amLimitDistance = 100.0f;
	m_VisiSettings.amFalloffAmount = 0.0f;
	m_VisiSettings.amFalloffDuration = 0.0f;

	m_VisiSettings.sdwLimitDistance = 60.0f;
	m_VisiSettings.sdwFalloffAmount = 10.0f;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_AOSettings.radius = 0.05f;
	m_AOSettings.threshold = 0.02f;//0.06f;
	m_AOSettings.dist = 0.3f;
	m_AOSettings.intensity = 1.0f;//2.0f;
	m_AOSettings.blur = Mix::Scene::BLUR::KS_3x3();

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_SMSettings.depthBias = -16.0f;
	m_SMSettings.depthSlopeScale = 0.1f;
	m_SMSettings.depthBiasClamp = 0.1f;
	m_SMSettings.pcfSize = Mix::Scene::ICamera::SMPS_3;
	m_SMSettings.blur = Mix::Scene::BLUR::KS_3x3();
	m_SMSettings.tint = 1.0f;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_LumSettings.flags = 0;//ICamera::LUM_TONE_MAPPING;
	m_LumSettings.minLum = 0.022f;
	m_LumSettings.maxLum = 2.0f;
	m_LumSettings.rods = 0.2f;
	m_LumSettings.cones = 0.4f;
	m_LumSettings.middleGray = 0.07f;
	m_LumSettings.white = 0.2f;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_BloomSettings.brightPass.bLumInf = True;
	m_BloomSettings.brightPass.white = 1.0f;
	m_BloomSettings.brightPass.threshold = 0.5f;
	m_BloomSettings.brightPass.offset = 1.0f;
	m_BloomSettings.blendType = Mix::Graphics::BLEND_ADD;
	m_BloomSettings.intensity = 1.0f;

	if( m_Config.bloomOverflowNum > 0 )
	{
		ResizeBloomOverflows( m_Config.bloomOverflowNum );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_LightShaftsSettings.brightPass.bLumInf = False;
	m_LightShaftsSettings.brightPass.white = 1.0f;
	m_LightShaftsSettings.brightPass.threshold = 1.0f;
	m_LightShaftsSettings.brightPass.offset = 1.0f;
	m_LightShaftsSettings.whiteness = 0.4f;
	m_LightShaftsSettings.samples = Mix::Scene::ICamera::LS_32;
	m_LightShaftsSettings.density = 0.2f;
	m_LightShaftsSettings.decay = 0.92f;
	m_LightShaftsSettings.exposure = 0.1f;
	m_LightShaftsSettings.start = 0.0f;
	m_LightShaftsSettings.end = 5.0f;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_LensFlareSettings.brightPass.bLumInf = False;
	m_LensFlareSettings.brightPass.white = 4.0f;
	m_LensFlareSettings.brightPass.threshold = 4.0f;
	m_LensFlareSettings.brightPass.offset = 1.0f;
	m_LensFlareSettings.ghostNum = 8;
	m_LensFlareSettings.ghostWeight = 1.0f;
	m_LensFlareSettings.ghostDispersal = 0.3f;
	m_LensFlareSettings.haloWeight = 4.0f;
	m_LensFlareSettings.haloWidth = 0.45f;
	m_LensFlareSettings.distortion = 4.0f;
	m_LensFlareSettings.brustSharpness = 4.0f;
	m_LensFlareSettings.brustIntensity = 1.0f;
	m_LensFlareSettings.dirtSharpness = 4.0f;//4.0f;
	m_LensFlareSettings.dirtIntensity = 1.0f;
	m_LensFlareSettings.blur = Mix::Scene::BLUR::GAUSSIAN( 16.0f );
	m_LensFlareSettings.intensity = 0.25f;//0.08f;

	for( UInt32 i = 0; i < Camera::LFT_MAX; i++ )
	{
		m_pLensFlareTex[i] = NULL;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	Mix::Memory::Zero( m_FilmicSettingsBuff, sizeof( m_FilmicSettingsBuff ) );

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_MotBlurSettings.minAngularVelocity = 0.01f;
	m_MotBlurSettings.maxAngularVelocity = 0.2f;
	m_MotBlurSettings.minLinearVelocity = 0.1f;
	m_MotBlurSettings.maxLinearVelocity = 3.0f;
	m_MotBlurSettings.quality = Mix::Scene::ICamera::MBQ_MIDDLE;
	m_MotBlurSettings.amount = 1;
	m_MotBlurSettings.echoTimeLength = 0.05f;
	m_MotBlurSettings.dist = 1.0f;
	m_MotBlurSettings.damping = 0.25f;
	m_MotBlurSettings.scale = 0.5f;
	m_MotBlurSettings.intensity = 1.0f;

	m_MotBlurCtx.invEchoTimeLength = 1.0f / m_MotBlurSettings.echoTimeLength;
	m_MotBlurCtx.viewDir = Mix::Vector3::Zero();
	m_MotBlurCtx.eyePos = Mix::Vector3::Zero();
	m_MotBlurCtx.state = Camera::MB_INIT;
	m_MotBlurCtx.preVPHead = 0;
	m_MotBlurCtx.preVPTail = 0;
	m_MotBlurCtx.preVPCount = 0;
	m_MotBlurCtx.pos = 0.0f;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_ChromatismSettings.distortion.k = 0.02f;
	m_ChromatismSettings.distortion.kCube = 0.03f;
	m_ChromatismSettings.distortion.scale = 0.99f;
	m_ChromatismSettings.colorFactor.Set( 1.0f, 0.0f, 0.0f, 1.0f );
	m_ChromatismSettings.blur = Mix::Scene::BLUR::KS_3x3();
	m_ChromatismSettings.weight = 1.0f;
	m_ChromatismSettings.fiStartZ = 0.0f;
	m_ChromatismSettings.fiEndZ = 0.0f;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_DofSettings.nearZ = 2.0f;
	m_DofSettings.nearDist = 2.0f;
	m_DofSettings.farZ = 20.0f;
	m_DofSettings.farDist = 40.0f;
	m_DofSettings.blur1 = Mix::Scene::BLUR::KS_3x3();
	m_DofSettings.blur2 = Mix::Scene::BLUR::GAUSSIAN( 2.0f );
	m_DofSettings.blurThreshold = 0.5f;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_LensDistSettings.k = 0.02f;
	m_LensDistSettings.kCube = 0.03f;
	m_LensDistSettings.scale = 0.99f;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_VignetteSettings.start = 0.0f;
	m_VignetteSettings.end = 1.0f;
	m_VignetteSettings.color.Set( 0.0f, 0.0f, 0.0f, 1.0f );

	////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef _DEBUG
	m_DebugName = L"";
	m_DebFillType = Mix::Graphics::FILL_SOLID;
	m_DebDrawMethod = Mix::Scene::DDM_XRAYS;
	m_DebDrawFlags = Mix::Scene::DDF_MESH;
	m_DebDrawFilmicSettings.rect = Mix::Rectangle( 0, 0, 0, 0 );
	m_DebDrawFilmicSettings.padding = 8;
	m_DebDrawFilmicSettings.valueMax = 2.0f;
	m_DebDrawFilmicSettings.valueStep = 0.2f;
	m_DebDrawFilmicSettings.memNum = 10;
	m_DebDrawFilmicSettings.errValue = 0.01f;
	m_DebDrawFilmicSettings.rect.width = 384;
	m_DebDrawFilmicSettings.rect.height = 320;
	m_DebDrawFilmicSettings.rect.x = m_Config.targetSize.x - m_DebDrawFilmicSettings.rect.width - 16;
	m_DebDrawFilmicSettings.rect.y = m_Config.targetSize.y - m_DebDrawFilmicSettings.rect.height - 16;
#endif //_DEBUG
}

Camera::~Camera( void )
{
	MIX_ASSERT( m_pOctView == NULL );
	MIX_ASSERT( m_pRenderer == NULL );

	MIX_RELEASE( m_pAOTex );
	MIX_RELEASE( m_pLightShaftsTex );

	for( UInt32 i = 0; i < Camera::LFT_MAX; i++ )
	{
		MIX_RELEASE( m_pLensFlareTex[i] );
	}
}

Boolean Camera::Attach( Mix::Scene::Common::Renderer* pRenderer, Mix::Scene::Common::OctreeView* pOctView )
{
	MIX_ASSERT( RendererObject::IsRendering() == False );
	MIX_ASSERT( pRenderer != NULL );
	MIX_ASSERT( pOctView != NULL );
	MIX_ASSERT( m_pRenderer == NULL );
	MIX_ASSERT( m_pOctView == NULL );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ログ : 開始
	////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef _DEBUG
	MIX_LOG_INFO_SECT_START( L"カメラを追加 : DebugName[%s]", m_DebugName.GetConstPtr() );
#else //_DEBUG
	MIX_LOG_INFO_SECT_START( L"カメラを追加" );
#endif //_DEBUG

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pRenderer = pRenderer;
	m_pOctView = pOctView;

	m_pRenderer->AddCameraView( this );

	if( m_pRenderer->UpdateCameraConfig( m_pOctView->GetID(), m_Config, m_ModConfigCaps ) == False )
	{
		MIX_LOG_INFO_SECT_END();
		return False;
	}

	RendererObject::SetRendering( True );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ログ : 終了
	////////////////////////////////////////////////////////////////////////////////////////////////////

	MIX_LOG_INFO_SECT_END();

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return True;
}

void Camera::Detach( void )
{
	if( m_pRenderer != NULL )
	{
		MIX_ASSERT( m_pOctView != NULL );
		m_pRenderer->RemoveCameraView( m_pOctView->GetID() );
		m_pRenderer = NULL;
	}

	if( m_pOctView != NULL )
	{
		m_pOctView->Destroy();
		m_pOctView = NULL;
	}

	RendererObject::SetRendering( False );
}

UInt32 Camera::GetID( void ) const
{
	if( m_pOctView == NULL )
	{
		return 0xFFFFFFFF;
	}

	return m_pOctView->GetID();
}

const Mix::Scene::CAMERA_CONFIG& Camera::GetConfig( void ) const
{
	return m_Config;
}

Boolean Camera::SetConfig( const Mix::Scene::CAMERA_CONFIG& config )
{
	if( IsRendering() == False )
	{
		return False;
	}

	MIX_ASSERT( m_pRenderer != NULL );
	MIX_ASSERT( m_pOctView != NULL );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ログ : 開始
	////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef _DEBUG
	MIX_LOG_INFO_SECT_START( L"カメラの設定を変更 : DebugName[%s]", m_DebugName.GetConstPtr() );
#else //_DEBUG
	MIX_LOG_INFO_SECT_START( L"カメラの設定を変更" );
#endif //_DEBUG

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pRenderer->UpdateCameraConfig( m_pOctView->GetID(), config, m_ModConfigCaps ) == False )
	{
		MIX_LOG_INFO( L"" );

		if( m_pRenderer->UpdateCameraConfig( m_pOctView->GetID(), m_Config, m_ModConfigCaps ) == False )
		{
			RendererObject::SetRendering( False );
			MIX_LOG_INFO_SECT_END();
			return False;
		}

		MIX_LOG_INFO( L"" );
		MIX_LOG_INFO( L"エラーが発生したため、設定を元にもどしました。" );
		MIX_LOG_INFO( L"" );
	}

	m_Config = config;
	m_DefAspect = MIX_FLOAT_DIV( static_cast<Float32>( m_Config.targetSize.x ), static_cast<Float32>( m_Config.targetSize.y ) );

	RendererObject::SetRendering( True );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ログ : 終了
	////////////////////////////////////////////////////////////////////////////////////////////////////

	MIX_LOG_INFO_SECT_END();

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return True;
}

void Camera::UpdateConfig( void )
{
	MIX_ASSERT( m_pRenderer != NULL );
	MIX_ASSERT( m_pOctView != NULL );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ログ : 開始
	////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef _DEBUG
	MIX_LOG_INFO_SECT_START( L"カメラの設定を更新 : DebugName[%s]", m_DebugName.GetConstPtr() );
#else //_DEBUG
	MIX_LOG_INFO_SECT_START( L"カメラの設定を更新" );
#endif //_DEBUG

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pRenderer->UpdateCameraConfig( m_pOctView->GetID(), m_Config, m_ModConfigCaps ) == True )
	{
		RendererObject::SetRendering( True );
	}
	else
	{
		RendererObject::SetRendering( False );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ログ : 終了
	////////////////////////////////////////////////////////////////////////////////////////////////////

	MIX_LOG_INFO_SECT_END();

	////////////////////////////////////////////////////////////////////////////////////////////////////
}

const Mix::Vector4& Camera::GetBackgroundColor( void ) const
{
	return m_BGColor;
}

void Camera::SetBackgroundColor( const Mix::Vector4& color )
{
	m_BGColor = color;
}

Mix::Graphics::TEXTURE_FILTER_TYPE Camera::GetFilterType( void ) const
{
	return m_FilterType;
}

void Camera::SetFilterType( Mix::Graphics::TEXTURE_FILTER_TYPE type )
{
	m_FilterType = type;
}

const Mix::Matrix4x4& Camera::GetProjectionMatrix( void ) const
{
	return m_ProjMat;
}

void Camera::SetProjection( Float32 fovY, Float32 nearZ, Float32 farZ )
{
	m_FovY = fovY;
	m_Aspect = m_DefAspect;
	m_NearZ = nearZ;
	m_FarZ = farZ;

	Mix::Matrix4x4::PerspectiveFovLH( m_FovY, m_Aspect, m_NearZ, m_FarZ, m_ProjMat );
}

void Camera::SetProjection( Float32 fovY, Float32 aspect, Float32 nearZ, Float32 farZ )
{
	m_FovY = fovY;
	m_Aspect = aspect;
	m_NearZ = nearZ;
	m_FarZ = farZ;

	Mix::Matrix4x4::PerspectiveFovLH( m_FovY, m_Aspect, m_NearZ, m_FarZ, m_ProjMat );
}

void Camera::SetProjection( Float32 fovY, UInt32 width, UInt32 height, Float32 nearZ, Float32 farZ )
{
	m_FovY = fovY;
	m_Aspect = MIX_FLOAT_DIV( static_cast<Float32>( width ), static_cast<Float32>( height ) );
	m_NearZ = nearZ;
	m_FarZ = farZ;

	Mix::Matrix4x4::PerspectiveFovLH( m_FovY, m_Aspect, m_NearZ, m_FarZ, m_ProjMat );
}

Float32 Camera::GetFovY( void ) const
{
	return m_FovY;
}

Float32 Camera::GetDefaultAspect( void ) const
{
	return m_DefAspect;
}

Float32 Camera::GetAspect( void ) const
{
	return m_Aspect;
}

Float32 Camera::GetNearZ( void ) const
{
	return m_NearZ;
}

Float32 Camera::GetFarZ( void ) const
{
	return m_FarZ;
}

const Mix::Vector3& Camera::GetEye( void ) const
{
	return m_Eye;
}

const Mix::Vector3& Camera::GetAt( void ) const
{
	return m_At;
}

const Mix::Vector3& Camera::GetViewVector( void ) const
{
	return m_ViewVec;
}

const Mix::Vector3& Camera::GetViewForward( void ) const
{
	return m_ViewForward;
}

const Mix::Vector3& Camera::GetViewUpward( void ) const
{
	return m_ViewUpward;
}

const Mix::Vector3& Camera::GetViewCrossDirection( void ) const
{
	return m_ViewCrossDir;
}

const Mix::Matrix4x4& Camera::GetViewMatrix( void ) const
{
	return m_ViewMat;
}

const Mix::Geometry::Frustum& Camera::GetFrustum( void ) const
{
	return m_Frustum;
}

const Mix::Matrix4x4& Camera::GetViewProjectionMatrix( void ) const
{
	return m_Frustum.GetViewProjectionMatrix();
}

const Mix::Matrix4x4& Camera::GetInvViewProjectionMatrix( void ) const
{
	return m_InvViewProjMat;
}

const Mix::Matrix4x4& Camera::GetBillboardMatrix( void ) const
{
	return m_BillboardMat;
}

const Mix::Matrix4x4& Camera::GetBillboardMatrixY( void ) const
{
	return m_BillboardMatY;
}

Mix::Point Camera::Project( const Mix::Vector3& pos ) const
{
	const Mix::Point& targetSize = m_Config.targetSize;
	Mix::Rectangle screenRect( 0, 0, targetSize.x, targetSize. y );

	return Project( screenRect, pos );
}

Mix::Point Camera::Project( const Mix::Point& screenPos, const Mix::Vector3& pos ) const
{
	const Mix::Point& targetSize = m_Config.targetSize;
	Mix::Rectangle screenRect( screenPos.x, screenPos.y, targetSize.x, targetSize. y );

	return Project( screenRect, pos );
}

Mix::Point Camera::Project( const Mix::Rectangle& screenRect, const Mix::Vector3& pos ) const
{
/*
	Mix::Matrix4x4 unViewport;
	Mix::Matrix4x4 mat;
	Mix::Vector4 pos;
	Mix::Vector4 result;

	unViewport.m00 = ( screenSize.x * 0.5f );
	unViewport.m11 = -( screenSize.y * 0.5f );
	unViewport.m30 = unViewport.m00;
	unViewport.m31 = ( screenSize.y * 0.5f );

	mat = m_ViewMat;
	mat *= m_ProjMat;

	pos = mat * worldPos;
	pos /= pos.w;

	result = unViewport * pos;

	return Mix::Vector2( result.x, result.y );
*/
	Float32 fw = static_cast<Float32>( screenRect.width );
	Float32 fh = static_cast<Float32>( screenRect.height );

	Mix::Matrix4x4 unViewMat;
	Mix::Matrix4x4 vpMat;
	Mix::Vector4 tmpPos;

	unViewMat.m00 = ( fw * 0.5f );
	unViewMat.m11 = -( fh * 0.5f );
	unViewMat.m30 = unViewMat.m00;
	unViewMat.m31 = ( fh * 0.5f );

	vpMat = m_ViewMat * m_ProjMat;

	tmpPos = vpMat * pos;
	tmpPos /= tmpPos.w;

	tmpPos = unViewMat * tmpPos;

	return Mix::Point( screenRect.x + static_cast<Int32>( tmpPos.x ), screenRect.y + static_cast<Int32>( tmpPos.y ) );
}

Mix::Vector3 Camera::Unproject( const Mix::Point& pos, Float32 z ) const
{
	const Mix::Point& targetSize = m_Config.targetSize;
	Mix::Rectangle screenRect( 0, 0, targetSize.x, targetSize. y );

	return Unproject( screenRect, pos, z );
}

Mix::Vector3 Camera::Unproject( const Mix::Point& screenPos, const Mix::Point& pos, Float32 z ) const
{
	const Mix::Point& targetSize = m_Config.targetSize;
	Mix::Rectangle screenRect( screenPos.x, screenPos.y, targetSize.x, targetSize. y );

	return Unproject( screenRect, pos, z );
}

Mix::Vector3 Camera::Unproject( const Mix::Rectangle& screenRect, const Mix::Point& pos, Float32 z ) const
{
/*
	Mix::Matrix4x4 invViewMat;
	Mix::Matrix4x4 invProjMat;
	Mix::Matrix4x4 unViewport;
	Mix::Matrix4x4 temp;

	invViewMat = m_ViewMat.ToInverse();
	invProjMat = m_ProjMat.ToInverse();

	unViewport.m00 = ( screenSize.x * 0.5f );
	unViewport.m11 = -( screenSize.y * 0.5f );
	unViewport.m30 = unViewport.m00;
	unViewport.m31 = ( screenSize.y * 0.5f );

	unViewport.Inverse();

	temp = unViewport;
	temp *= invProjMat;
	temp *= invViewMat;

	return temp * screenPos;
*/
	Float32 fw = static_cast<Float32>( screenRect.width );
	Float32 fh = static_cast<Float32>( screenRect.height );

	Mix::Matrix4x4 invViewMat = m_ViewMat.ToInverse();
	Mix::Matrix4x4 invProjMat = m_ProjMat.ToInverse();
	Mix::Matrix4x4 unViewMat;
	Mix::Matrix4x4 mat;

	unViewMat.m00 = ( fw * 0.5f );
	unViewMat.m11 = -( fh * 0.5f );
	unViewMat.m30 = unViewMat.m00;
	unViewMat.m31 = ( fh * 0.5f );

	mat = unViewMat.ToInverse() * invProjMat * invViewMat;

	return mat * Mix::Vector3( static_cast<Float32>( pos.x - screenRect.x ), static_cast<Float32>( pos.y - screenRect.y ), z );
}

Boolean Camera::DragObject( const Mix::Point& pos )
{
	if( RendererObject::IsRendering() == False )
	{
		return False;
	}

	MIX_ASSERT( m_pOctView != NULL );

	const Mix::Point& targetSize = m_Config.targetSize;
	Mix::Rectangle screenRect( 0, 0, targetSize.x, targetSize.y );

	return m_pRenderer->DragObject( m_pOctView->GetID(), screenRect, pos );
}

Boolean Camera::DragObject( const Mix::Point& screenPos, const Mix::Point& pos )
{
	if( RendererObject::IsRendering() == False )
	{
		return False;
	}

	MIX_ASSERT( m_pOctView != NULL );

	const Mix::Point& targetSize = m_Config.targetSize;
	Mix::Rectangle screenRect( screenPos.x, screenPos.y, targetSize.x, targetSize.y );

	return m_pRenderer->DragObject( m_pOctView->GetID(), screenRect, pos );
}

Boolean Camera::DragObject( const Mix::Rectangle& screenRect, const Mix::Point& pos )
{
	if( RendererObject::IsRendering() == False )
	{
		return False;
	}

	MIX_ASSERT( m_pOctView != NULL );

	return m_pRenderer->DragObject( m_pOctView->GetID(), screenRect, pos );
}

Boolean Camera::IsUnderWater( void ) const
{
	return m_bUnderWater;
}

void Camera::SetUnderWater( Boolean state )
{
	m_bUnderWater = state;
}

void Camera::Update( Float32 dt )
{
	Float32 invFarZ = MIX_FLOAT_RECIPROCAL( m_FarZ );
	Mix::Matrix4x4 preVPMat = m_Frustum.GetViewProjectionMatrix();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ベクトル
	////////////////////////////////////////////////////////////////////////////////////////////////////

	// 前ベクトル
	m_ViewVec = m_At - m_Eye;

	//前方向
	m_ViewForward.Set( m_ViewMat.m02, m_ViewMat.m12, m_ViewMat.m22 );
	m_ViewForward.Normalize();

	//上方向
	m_ViewUpward.Set( m_ViewMat.m01, m_ViewMat.m11, m_ViewMat.m21 );
	m_ViewUpward.Normalize();

	//横方向
	m_ViewCrossDir.Set( m_ViewMat.m00, m_ViewMat.m10, m_ViewMat.m20 );
	m_ViewCrossDir.Normalize();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 行列
	////////////////////////////////////////////////////////////////////////////////////////////////////

	// フラスタム
	m_Frustum.Update( m_ViewMat * m_ProjMat );

	// 現在の ビュー * プロジェクトの逆行列
	m_InvViewProjMat = m_Frustum.GetViewProjectionMatrix().ToInverse();

	// ビルボード行列
	m_BillboardMat = m_ViewMat;
	m_BillboardMat.Inverse();
	m_BillboardMat.m30 = 0.0f;
	m_BillboardMat.m31 = 0.0f;
	m_BillboardMat.m32 = 0.0f;

	// Y軸固定のビルボード行列
	m_BillboardMatY = Mix::Matrix4x4::Identity();
	m_BillboardMatY.SetRotationY( -::atanf( MIX_FLOAT_DIV( m_ViewForward.z, m_ViewForward.x ) ) - MIX_FLOAT_DIV( MIX_PI, 2.0f ) );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 内部設定
	////////////////////////////////////////////////////////////////////////////////////////////////////

	// 視界
	m_InternalVisiSettings.loFalloffStart = m_VisiSettings.loLimitDistance - m_VisiSettings.loFalloffAmount;
	m_InternalVisiSettings.loInvFalloffAmount = MIX_FLOAT_RECIPROCAL( max( Camera::MIN_FALLOFF_AMOUNT, m_VisiSettings.loFalloffAmount ) );

	m_InternalVisiSettings.sdwFalloffStart = ( m_VisiSettings.sdwLimitDistance - m_VisiSettings.sdwFalloffAmount ) * invFarZ;
	m_InternalVisiSettings.sdwInvFalloffAmount = MIX_FLOAT_RECIPROCAL( max( Camera::MIN_FALLOFF_AMOUNT, m_VisiSettings.sdwFalloffAmount ) * invFarZ );

	m_InternalVisiSettings.plFalloffStart = m_VisiSettings.plLimitDistance - m_VisiSettings.plFalloffAmount;
	m_InternalVisiSettings.plFalloffMiddle = m_InternalVisiSettings.plFalloffStart + m_VisiSettings.plFalloffAmount * m_VisiSettings.plFalloffThreshold;

	// アンビエントオクルージョン

	m_InternalAOSettings.radius = m_AOSettings.radius * invFarZ;
	m_InternalAOSettings.threshold = m_AOSettings.threshold * invFarZ;
	m_InternalAOSettings.depth = ( m_AOSettings.threshold + m_AOSettings.dist ) * invFarZ;

	// シャドウマッピング

	UInt32 sdwPCFSize = Camera::SM_PCF_SIZE_TABLE[m_SMSettings.pcfSize];

	MIX_ASSERT( ( sdwPCFSize % 2 ) == 1 ); //奇数であることを意味する

//	m_InternalSMSettings.depthBias = m_SMSettings.depthBias;
	m_InternalSMSettings.depthBias = m_SMSettings.depthBias * invFarZ;
//	m_InternalSMSettings.depthBias = m_SMSettings.depthBias * MIX_FLOAT_RECIPROCAL( m_VisiSettings.sdwLimitDistance * 2.0f );
	m_InternalSMSettings.pcfRange = static_cast<Float32>( sdwPCFSize - 1 ) * 0.5f;
	m_InternalSMSettings.pcfMul = 1.0f / static_cast<Float32>( sdwPCFSize * sdwPCFSize );

	// ライトシャフト

	m_InternalLightShaftsSettings.start = m_LightShaftsSettings.start * invFarZ;
	m_InternalLightShaftsSettings.end = m_LightShaftsSettings.end * invFarZ;
	m_InternalLightShaftsSettings.invDist = MIX_FLOAT_RECIPROCAL( ( m_LightShaftsSettings.end - m_LightShaftsSettings.start ) * invFarZ );

	// レンズフレア

	Float32 disto = m_LensFlareSettings.distortion;

	Float32 theta = Mix::Vector3::Dot( m_ViewCrossDir, Mix::Vector3::ZAxis() ) + Mix::Vector3::Dot( m_ViewForward, Mix::Vector3::YAxis() );
	Float32 s = ::sinf( theta );
	Float32 c = ::cosf( theta ) * 0.5f;

	Mix::Matrix4x4 mat(	  +c,   +s, 0.0f, 0.0f,
						  -s,   +c, 0.0f, 0.0f,
						0.0f, 0.0f, 1.0f, 0.0f,
						0.0f, 0.0f, 0.0f, 1.0f );

	m_InternalLensFlareSettings.distoVec.x = MIX_FLOAT_RECIPROCAL( static_cast<Float32>( m_Config.targetSize.x ) ) * -disto;
	m_InternalLensFlareSettings.distoVec.y = 0.0f;
	m_InternalLensFlareSettings.distoVec.z = MIX_FLOAT_RECIPROCAL( static_cast<Float32>( m_Config.targetSize.y ) ) * disto;
	m_InternalLensFlareSettings.camMat = Camera::LF_CAM_BIAS_MAT0 * mat * Camera::LF_CAM_BIAS_MAT1;

	// ガンマ補正

	m_InternalGammaValue.x = MIX_FLOAT_RECIPROCAL( m_GammaValue.x );
	m_InternalGammaValue.y = MIX_FLOAT_RECIPROCAL( m_GammaValue.y );
	m_InternalGammaValue.z = MIX_FLOAT_RECIPROCAL( m_GammaValue.z );

	// モーションブラー

	if( ( m_bMotBlurEnabled == True ) && ( m_MotBlurCtx.state != Camera::MB_INIT ) )
	{
		Float32 angularVelocity = MIX_CLAMP( ( 2.0f - ( Mix::Vector3::Dot( m_ViewForward, m_MotBlurCtx.viewDir ) + 1.0f ) ) * 0.5f, 0.0f, 1.0f );
		Float32 linearVelocity = ( m_Eye - m_MotBlurCtx.eyePos ).GetLength();

		Float32 angularSpped = Camera::GetMotionBlurSpeed( m_MotBlurSettings.minAngularVelocity, m_MotBlurSettings.maxAngularVelocity, angularVelocity );
		Float32 linearSpeed = Camera::GetMotionBlurSpeed( m_MotBlurSettings.minLinearVelocity, m_MotBlurSettings.maxLinearVelocity, linearVelocity );
		Float32 speed = max( angularSpped, linearSpeed );

		if( speed > 0.0f )
		{
			const UInt32& amount = m_MotBlurSettings.amount;

			m_MotBlurCtx.preVPMats[m_MotBlurCtx.preVPHead] = preVPMat;

			m_MotBlurCtx.preVPHead++;
			if( m_MotBlurCtx.preVPHead >= amount )
			{
				m_MotBlurCtx.preVPHead = m_MotBlurCtx.preVPHead % amount;
			}

			m_MotBlurCtx.preVPCount++;

			if( m_MotBlurCtx.preVPCount > amount )
			{
				m_MotBlurCtx.preVPCount = amount;

				m_MotBlurCtx.preVPTail++;
				if( m_MotBlurCtx.preVPTail >= amount )
				{
					m_MotBlurCtx.preVPTail = m_MotBlurCtx.preVPTail % amount;
				}
			}
		}

		if( m_MotBlurCtx.state == Camera::MB_WAIT )
		{
			if( speed > 0.0f )
			{
//				MIX_TRACELINE( L"Camera::MB_ACTIVE" );
				m_MotBlurCtx.preSpeed = speed;
				m_MotBlurCtx.pos = speed;
				m_MotBlurCtx.state = Camera::MB_ACTIVE;
			}
		}
		else if( m_MotBlurCtx.state == Camera::MB_ACTIVE )
		{
			m_MotBlurCtx.pos = m_MotBlurCtx.preSpeed;

			if( speed <= MIX_FLOAT_EPSILON )
			{
				m_MotBlurCtx.step = m_MotBlurCtx.pos;
				m_MotBlurCtx.state = Camera::MB_IDLE;
//				MIX_TRACELINE( L"Camera::MB_IDLE POS[%f] STEP[%f]", m_MotBlurCtx.pos, m_MotBlurCtx.step );
			}
		}
		else if( m_MotBlurCtx.state == Camera::MB_IDLE )
		{
			if( speed > 0.0f )
			{
//				MIX_TRACELINE( L"Camera::MB_ACTIVE" );
				m_MotBlurCtx.state = Camera::MB_ACTIVE;
			}
			else
			{
				m_MotBlurCtx.pos -= m_MotBlurCtx.step * dt * m_MotBlurCtx.invEchoTimeLength;

				if( m_MotBlurCtx.pos < 0.0f )
				{
//					MIX_TRACELINE( L"Camera::MB_WAIT" );
					m_MotBlurCtx.state = Camera::MB_WAIT;
					m_MotBlurCtx.preVPCount = 0;
					m_MotBlurCtx.preVPTail = m_MotBlurCtx.preVPHead;
					m_MotBlurCtx.pos = 0.0f;
				}
			}
		}

		m_MotBlurCtx.viewDir = m_ViewForward;
		m_MotBlurCtx.eyePos = m_Eye;
		m_MotBlurCtx.preSpeed = speed;

		m_InternalMotBlurSettings.cp0 = 2.0f * m_NearZ;
		m_InternalMotBlurSettings.cp1 = m_FarZ + m_NearZ;
		m_InternalMotBlurSettings.cp2 = 1.0f / -( m_FarZ - m_NearZ );
		m_InternalMotBlurSettings.scale = m_MotBlurSettings.scale * 0.5f;
		m_InternalMotBlurSettings.intensity = m_MotBlurSettings.intensity * m_MotBlurCtx.pos;
		m_InternalMotBlurSettings.invVolume = MIX_FLOAT_RECIPROCAL( m_MotBlurSettings.damping );
		m_InternalMotBlurSettings.dist = m_MotBlurSettings.dist * invFarZ;
	}
	else
	{
		//m_MotBlurCtx.invEchoTimeLength は UpdateMotionBlurContext で設定される
		m_MotBlurCtx.viewDir = m_ViewForward;
		m_MotBlurCtx.eyePos = m_Eye;
		m_MotBlurCtx.state = Camera::MB_WAIT;
		m_MotBlurCtx.preVPHead = 0;
		m_MotBlurCtx.preVPTail = 0;
		m_MotBlurCtx.preVPCount = 0;
		m_MotBlurCtx.preSpeed = 0.0f;
		m_MotBlurCtx.step = 0.0f;
		m_MotBlurCtx.pos = 0.0f;
	}

	// 色収差

	m_InternalChromatismSettings.fiStartZ = m_ChromatismSettings.fiStartZ * invFarZ;
	m_InternalChromatismSettings.invDist = MIX_FLOAT_RECIPROCAL( ( m_ChromatismSettings.fiEndZ - m_ChromatismSettings.fiStartZ + Camera::CA_MIN_DIST ) * invFarZ );

	// 被写界深度

	m_InternalDofSettings.nearZ = m_DofSettings.nearZ * invFarZ;
	m_InternalDofSettings.farZ = m_DofSettings.farZ * invFarZ;
	m_InternalDofSettings.invNearDist = MIX_FLOAT_RECIPROCAL( m_DofSettings.nearDist * invFarZ );
	m_InternalDofSettings.invFarDist = MIX_FLOAT_RECIPROCAL( m_DofSettings.farDist * invFarZ );
	m_InternalDofSettings.invBlurThresholdN = MIX_FLOAT_RECIPROCAL( m_DofSettings.blurThreshold );
	m_InternalDofSettings.invBlurThresholdF = MIX_FLOAT_RECIPROCAL( 1.0f - m_DofSettings.blurThreshold );

	// ヴィネット

	m_InternalVignetteSettings.start = Camera::VIGNETTE_LEN * m_VignetteSettings.start;
	m_InternalVignetteSettings.invDist = MIX_FLOAT_RECIPROCAL( Camera::VIGNETTE_LEN * ( m_VignetteSettings.end - m_VignetteSettings.start ) );
}

Boolean Camera::Draw( void )
{
	if( RendererObject::IsRendering() == False )
	{
		return False;
	}

	MIX_ASSERT( m_pRenderer != NULL );
	MIX_ASSERT( m_pOctView != NULL );

	m_pOctView->Switch();
	m_pRenderer->Draw( m_pOctView->GetID() );

	return True;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : Visiblity
////////////////////////////////////////////////////////////////////////////////////////////////////

const Mix::Scene::ICamera::VISIBILITY_SETTINGS& Camera::GetVisiblitySettings( void ) const
{
	return m_VisiSettings;
}

const Camera::INTERNAL_VISIBLITY_SETTINGS& Camera::GetInternalVisiblitySettings( void ) const
{
	return m_InternalVisiSettings;
}

void Camera::SetVisiblitySettings( const Mix::Scene::ICamera::VISIBILITY_SETTINGS& settings )
{
	m_VisiSettings.loLimitDistance = max( 0.0f, settings.loLimitDistance );
	m_VisiSettings.loFalloffAmount = max( 0.0f, settings.loFalloffAmount );

	m_VisiSettings.plLimitDistance = max( 0.0f, settings.plLimitDistance );
	m_VisiSettings.plFalloffAmount = max( 0.0f, settings.plFalloffAmount );
	m_VisiSettings.plFalloffThreshold = MIX_CLAMP( settings.plFalloffThreshold, 0.0f, 1.0f );

	m_VisiSettings.paLimitDistance = max( 0.0f, settings.paLimitDistance );
	m_VisiSettings.paFalloffAmount = max( 0.0f, settings.paFalloffAmount );
	m_VisiSettings.paFalloffDuration = max( 0.0f, settings.paFalloffDuration );

	m_VisiSettings.amLimitDistance = max( 0.0f, settings.amLimitDistance );
	m_VisiSettings.amFalloffAmount = max( 0.0f, settings.amFalloffAmount );
	m_VisiSettings.amFalloffDuration = max( 0.0f, settings.amFalloffDuration );

	m_VisiSettings.sdwLimitDistance = max( 0.0f, settings.sdwLimitDistance );
	m_VisiSettings.sdwFalloffAmount = max( 0.0f, settings.sdwFalloffAmount );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : AmbientOcclusion
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsAmbientOcclusionAvailabled( void ) const
{
	return ( MIX_TESTBIT( m_ModConfigCaps, Mix::Scene::RCAP_AMBIENT_OCCLUSION ) == Mix::Scene::RCAP_AMBIENT_OCCLUSION );
}

Boolean Camera::IsAmbientOcclusionEnabled( void ) const
{
	return m_bAOEnabled;
}

void Camera::SetAmbientOcclusionEnabled( Boolean state )
{
	m_bAOEnabled = state;
}

const Mix::Scene::ICamera::AMBIENT_OCCLUSION_SETTINGS& Camera::GetAmbientOcclusionSettings( void ) const
{
	return m_AOSettings;
}

const Camera::INTERNAL_AMBIENT_OCCLUSION_SETTINGS& Camera::GetInternalAmbientOcclusionSettings( void ) const
{
	return m_InternalAOSettings;
}

void Camera::SetAmbientOcclusionSettings( const Mix::Scene::ICamera::AMBIENT_OCCLUSION_SETTINGS& settings )
{
	m_AOSettings.radius = max( 0.0f, settings.radius );
	m_AOSettings.threshold = max( 0.0f, settings.threshold );
	m_AOSettings.dist = max( 0.0f, settings.dist );
	m_AOSettings.intensity = max( 0.0f, settings.intensity );
	m_AOSettings.blur = settings.blur;
}

Boolean Camera::GetAmbientOcclusionTexture( Mix::Graphics::ITexture** ppTex )
{
	MIX_ASSERT( ppTex != NULL );

	if( m_pAOTex == NULL )
	{
		return False;
	}

	MIX_ADD_REF( m_pAOTex );
	( *ppTex ) = m_pAOTex;

	return True;
}

Mix::Graphics::ITexture* Camera::GetAmbientOcclusionTexturePtr( void  ) const
{
	return m_pAOTex;
}

void Camera::SetAmbientOcclusionTexture( Mix::Graphics::ITexture* pTex )
{
	MIX_RELEASE( m_pAOTex );

	MIX_ADD_REF( pTex );
	m_pAOTex = pTex;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : ShadowMapping
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsShadowMappingAvailabled( void ) const
{
	return ( MIX_TESTBIT( m_ModConfigCaps, Mix::Scene::RCAP_SHADOW_MAPPING ) == Mix::Scene::RCAP_SHADOW_MAPPING );
}

Boolean Camera::IsShadowMappingEnabled( void ) const
{
	return m_bSMEnabled;
}

void Camera::SetShadowMappingEnabled( Boolean state )
{
	m_bSMEnabled = state;
}

const Mix::Scene::ICamera::SHADOW_MAPPING_SETTINGS& Camera::GetShadowMappingSettings( void ) const
{
	return m_SMSettings;
}

const Camera::INTERNAL_SHADOW_MAPPING_SETTINGS& Camera::GetInternalShadowMappingSettings( void ) const
{
	return m_InternalSMSettings;
}

void Camera::SetShadowMappingSettings( const Mix::Scene::ICamera::SHADOW_MAPPING_SETTINGS& settings )
{
	m_SMSettings.depthBias = settings.depthBias;
	m_SMSettings.depthBiasClamp = max( 0.0f, settings.depthBiasClamp );
	m_SMSettings.depthSlopeScale = max( 0.0f, settings.depthSlopeScale );
	m_SMSettings.pcfSize = settings.pcfSize;
	m_SMSettings.blur = settings.blur;
	m_SMSettings.tint = MIX_CLAMP( settings.tint, 0.0f, 1.0f );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : Luminosity
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsLuminosityAvailabled( void ) const
{
	return ( MIX_TESTBIT( m_ModConfigCaps, Mix::Scene::RCAP_LUMINOSITY ) == Mix::Scene::RCAP_LUMINOSITY );
}

const Mix::Scene::ICamera::LUMINOSITY_SETTINGS& Camera::GetLuminositySettings( void ) const
{
	return m_LumSettings;
}

void Camera::SetLuminositySettings( const Mix::Scene::ICamera::LUMINOSITY_SETTINGS& param )
{
	m_LumSettings.flags = param.flags;
	m_LumSettings.minLum = MIX_CLAMP( param.minLum, 0.0f, 2.0f );
	m_LumSettings.maxLum = MIX_CLAMP( param.maxLum, m_LumSettings.minLum, 2.0f );
	m_LumSettings.rods = MIX_CLAMP( param.rods, 0.0f, 1.0f );
	m_LumSettings.cones = MIX_CLAMP( param.cones, 0.0f, 1.0f );
	m_LumSettings.middleGray = max( 0.0f, param.middleGray );
	m_LumSettings.white = max( 0.0f, param.white );
}

Boolean Camera::IsLuminosityAdaptationEnabled( void ) const
{
	return ( m_LumAdSuspendCount == 0 );
}

Camera::LUMINOSITY_ADAPTATION_TYPE Camera::GetLuminosityAdaptationType( void )
{
	Camera::LUMINOSITY_ADAPTATION_TYPE ret = m_LumAdType;

	m_LumAdType = Camera::LUM_AD_SLOWLY;

	return ret;
}

Float32 Camera::GetLuminosityAdaptationValue( void ) const
{
	return m_LumAdValue;
}

UInt32 Camera::ResumeLuminosityAdaptation( void )
{
	if( m_LumAdSuspendCount == 0 )
	{
		return 0xFFFFFFFF;
	}

	UInt32 ret = m_LumAdSuspendCount;

	m_LumAdSuspendCount--;

	return ret;
}

UInt32 Camera::SusupendLuminosityAdaptation( void )
{
	if( m_LumAdSuspendCount == 0xFFFFFFFF )
	{
		return 0xFFFFFFFF;
	}

	UInt32 ret = m_LumAdSuspendCount;

	m_LumAdSuspendCount++;

	return ret;
}

UInt32 Camera::GetLuminosityAdaptationSuspendCount( void ) const
{
	return m_LumAdSuspendCount;
}

void Camera::ForceLuminosityAdaptation( void )
{
	m_LumAdType = Camera::LUM_AD_FORCE;
}

void Camera::SetLuminosityAdaptation( Float32 lum )
{
	m_LumAdType = Camera::LUM_AD_SPECIFY;
	m_LumAdValue = MIX_CLAMP( lum, m_LumSettings.minLum, m_LumSettings.maxLum );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : Bloom
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsBloomAvailabled( void ) const
{
	return ( MIX_TESTBIT( m_ModConfigCaps, Mix::Scene::RCAP_BLOOM ) == Mix::Scene::RCAP_BLOOM );
}

Boolean Camera::IsBloomEnabled( void ) const
{
	return m_bBloomEnabled;
}

void Camera::SetBloomEnabled( Boolean state )
{
	m_bBloomEnabled = state;
}

UInt32 Camera::GetBloomOverflowNum( void ) const
{
	return m_BloomOverflowNum;
}

const Mix::Scene::ICamera::BLOOM_OVERFLOW& Camera::GetBloomOverflow( UInt32 index ) const
{
	MIX_ASSERT( m_BloomOverflowNum > index );

	return m_BloomOverflows[index];
}

void Camera::SetBloomOverflow( UInt32 index, const Mix::Scene::ICamera::BLOOM_OVERFLOW& overflow )
{
	MIX_ASSERT( m_BloomOverflowNum > index );

	m_BloomOverflows[index] = overflow;
}

void Camera::ResizeBloomOverflows( UInt32 num )
{
	UInt32 curNum = MIX_UIT_TO_UI32( m_BloomOverflows.size() );

	if( curNum < num )
	{
		Mix::Scene::ICamera::BLOOM_OVERFLOW initial;
		UInt32 addNum;
		UInt32 i;

		if( curNum > 0 )
		{
			initial = m_BloomOverflows.back();
		}
		else
		{
			initial.blur = Mix::Scene::BLUR::GAUSSIAN( 4.0f );
			initial.intensity = 1.0f;
		}

		addNum = num - curNum;

		for( i = 0; i < addNum; i++ )
		{
			m_BloomOverflows.push_back( initial );
		}
	}

	m_BloomOverflowNum = num;
}

const Mix::Scene::ICamera::BLOOM_SETTINGS& Camera::GetBloomSettings( void ) const
{
	return m_BloomSettings;
}

void Camera::SetBloomSettings( const Mix::Scene::ICamera::BLOOM_SETTINGS& settings )
{
	m_BloomSettings.brightPass.bLumInf = settings.brightPass.bLumInf;
	m_BloomSettings.brightPass.white = max( 0.0f, settings.brightPass.white );
	m_BloomSettings.brightPass.threshold = max( 0.0f, settings.brightPass.threshold );
	m_BloomSettings.brightPass.offset = max( 0.0f, settings.brightPass.offset );
	m_BloomSettings.blendType = settings.blendType;
	m_BloomSettings.intensity = max( 0.0f, settings.intensity );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : LightShafts
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsLightShaftsAvailabled( void ) const
{
	return ( MIX_TESTBIT( m_ModConfigCaps, Mix::Scene::RCAP_LIGHT_SHAFTS ) == Mix::Scene::RCAP_LIGHT_SHAFTS );
}

Boolean Camera::IsLightShaftsEnabled( void ) const
{
	return m_bLightShaftsEnabled;
}

void Camera::SetLightShaftsEnabled( Boolean state )
{
	m_bLightShaftsEnabled = state;
}

const Mix::Scene::ICamera::LIGHT_SHAFTS_SETTINGS& Camera::GetLightShaftsSettings( void ) const
{
	return m_LightShaftsSettings;
}

void Camera::SetLightShaftsSettings( const Mix::Scene::ICamera::LIGHT_SHAFTS_SETTINGS& settings )
{
	m_LightShaftsSettings.brightPass.bLumInf = settings.brightPass.bLumInf;
	m_LightShaftsSettings.brightPass.white = max( 0.0f, settings.brightPass.white );
	m_LightShaftsSettings.brightPass.threshold = max( 0.0f, settings.brightPass.threshold );
	m_LightShaftsSettings.brightPass.offset = max( 0.0f, settings.brightPass.offset );
	m_LightShaftsSettings.whiteness = MIX_CLAMP( settings.whiteness, 0.0f, 1.0f );
	m_LightShaftsSettings.samples = settings.samples;
	m_LightShaftsSettings.density = max( 0.0f, settings.density );
	m_LightShaftsSettings.decay = max( 0.0f, settings.decay );
	m_LightShaftsSettings.exposure = max( 0.0f, settings.exposure );
	m_LightShaftsSettings.start = max( 0.0f, settings.start );
	m_LightShaftsSettings.end = max( m_LightShaftsSettings.start, settings.end );
}

Boolean Camera::GetLightShaftsTexture( Mix::Graphics::ITexture** ppTex )
{
	MIX_ASSERT( ppTex != NULL );

	if( m_pLightShaftsTex == NULL )
	{
		return False;
	}

	MIX_ADD_REF( m_pLightShaftsTex );
	( *ppTex ) = m_pLightShaftsTex;

	return True;
}

Mix::Graphics::ITexture* Camera::GetLightShaftsTexturePtr( void  ) const
{
	return m_pLightShaftsTex;
}

void Camera::SetLightShaftsTexture( Mix::Graphics::ITexture* pTex )
{
	MIX_RELEASE( m_pLightShaftsTex );

	MIX_ADD_REF( pTex );
	m_pLightShaftsTex = pTex;
}

const Camera::INTERNAL_LIGHT_SHAFTS_SETTINGS& Camera::GetInternalLightShaftsSettings( void ) const
{
	return m_InternalLightShaftsSettings;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : LensFlare
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsLensFlareAvailabled( void ) const
{
	return ( MIX_TESTBIT( m_ModConfigCaps, Mix::Scene::RCAP_LENS_FLARE ) == Mix::Scene::RCAP_LENS_FLARE );
}

Boolean Camera::IsLensFlareEnabled( void ) const
{
	return m_bLensFlareEnabled;
}

void Camera::SetLensFlareEnabled( Boolean state )
{
	m_bLensFlareEnabled = state;
}

const Mix::Scene::ICamera::LENS_FLARE_SETTINGS& Camera::GetLensFlareSettings( void ) const
{
	return m_LensFlareSettings;
}

const Camera::INTERNAL_LENS_FLARE_SETTINGS& Camera::GetInternalLensFlareSettings( void ) const
{
	return m_InternalLensFlareSettings;
}

void Camera::SetLensFlareSettings( const Mix::Scene::ICamera::LENS_FLARE_SETTINGS& settings )
{
	m_LensFlareSettings.brightPass.bLumInf = settings.brightPass.bLumInf;
	m_LensFlareSettings.brightPass.white = max( 0.0f, settings.brightPass.white );
	m_LensFlareSettings.brightPass.threshold = max( 0.0f, settings.brightPass.threshold );
	m_LensFlareSettings.brightPass.offset = max( 0.0f, settings.brightPass.offset );
	m_LensFlareSettings.ghostNum = MIX_CLAMP( settings.ghostNum, Camera::LF_MIN_GHOST, Camera::LF_MAX_GHOST );
	m_LensFlareSettings.ghostWeight = max( 1.0f, settings.ghostWeight );
	m_LensFlareSettings.ghostDispersal = MIX_CLAMP( settings.ghostDispersal, 0.0f, 1.0f );
	m_LensFlareSettings.haloWeight = max( 1.0f, settings.haloWeight );
	m_LensFlareSettings.haloWidth = MIX_CLAMP( settings.haloWidth, 0.0f, 1.0f );
	m_LensFlareSettings.distortion = max( 0.0f, settings.distortion );
	m_LensFlareSettings.brustSharpness = max( 1.0f, settings.brustSharpness );
	m_LensFlareSettings.brustIntensity = max( 0.0f, settings.brustIntensity );
	m_LensFlareSettings.dirtSharpness = max( 1.0f, settings.dirtSharpness );
	m_LensFlareSettings.dirtIntensity = max( 0.0f, settings.dirtIntensity );
	m_LensFlareSettings.blur = settings.blur;
	m_LensFlareSettings.intensity = settings.intensity;
}

Boolean Camera::GetLensFlareTexture( Mix::Scene::ICamera::LENS_FLARE_TEXTURE_TYPE type, Mix::Graphics::ITexture** ppTex )
{
	MIX_ASSERT( type < Camera::LFT_MAX );

	if( m_pLensFlareTex[type] == NULL )
	{
		return False;
	}

	MIX_ADD_REF( m_pLensFlareTex[type] );
	( *ppTex ) = m_pLensFlareTex[type];

	return True;
}

Mix::Graphics::ITexture* Camera::GetLensFlareTexturePtr( Mix::Scene::ICamera::LENS_FLARE_TEXTURE_TYPE type ) const
{
	MIX_ASSERT( type < Camera::LFT_MAX );
	return m_pLensFlareTex[type];
}

void Camera::SetLensFlareTexture( Mix::Scene::ICamera::LENS_FLARE_TEXTURE_TYPE type, Mix::Graphics::ITexture* pTex )
{
	MIX_ASSERT( type < Camera::LFT_MAX );

	MIX_RELEASE( m_pLensFlareTex[type] );
	MIX_ADD_REF( pTex );
	m_pLensFlareTex[type] = pTex;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : Filmic
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsFilmicEnabled( void ) const
{
	return m_bFilmicEnabled;
}

void Camera::SetFilmicEnabled( Boolean state )
{
	m_bFilmicEnabled = state;
}

Mix::Scene::ICamera::FILMIC_TYPE Camera::GetFilmicType( void ) const
{
	return m_FilmicType;
}

Boolean Camera::GetFilmicSettings( void* pSettings, UInt32 paramSize ) const
{
	if( ( pSettings == NULL ) || ( paramSize == 0 ) || ( paramSize != m_FilmicSettingsSize ) )
	{
		return False;
	}

	Mix::Memory::Copy( pSettings, m_FilmicSettingsBuff, m_FilmicSettingsSize );

	return True;
}

const void* Camera::GetFilmicSettingsBuff( UInt32 paramSize ) const
{
	MIX_ASSERT( m_FilmicSettingsSize == paramSize );

	return m_FilmicSettingsBuff;
}

Boolean Camera::SetFilmicType( Mix::Scene::ICamera::FILMIC_TYPE type, const void* pSettings, UInt32 paramSize )
{
	if( type == Mix::Scene::ICamera::FI_HABLE )
	{
		if( ( pSettings != NULL ) && ( paramSize == sizeof( Mix::Scene::ICamera::FILMIC_HABLE_SETTINGS ) ) )
		{
			MIX_ASSERT( paramSize <= Camera::FI_SETTINGS_BUFF_SIZE );

			Mix::Memory::Copy( m_FilmicSettingsBuff, pSettings, paramSize );
		}
		else if( ( pSettings == NULL ) && ( paramSize == 0 ) )
		{
			ICamera::FILMIC_HABLE_SETTINGS* pDst = reinterpret_cast<ICamera::FILMIC_HABLE_SETTINGS*>( &( m_FilmicSettingsBuff[0] ) );

			pDst->exposureBias = 2.0f;
			pDst->shoulderStrength = 0.22f;
			pDst->linearStrength = 0.3f;
			pDst->linearAngle = 0.1f;
			pDst->toeStrength = 0.2f;
			pDst->toeNumerator = 0.01f;
			pDst->toeDenominator = 0.3f;
			pDst->linearWhitePointValue = 11.2f;
		}
		else
		{
			return False;
		}

		m_FilmicSettingsSize = sizeof( Mix::Scene::ICamera::FILMIC_HABLE_SETTINGS );
	}
	else
	{
		Mix::Memory::Zero( m_FilmicSettingsBuff, Camera::FI_SETTINGS_BUFF_SIZE );
		m_FilmicSettingsSize = 0;
	}

	m_FilmicType = type;

	return True;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : GammaCorrect
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsGammaEnabled( void ) const
{
	return m_bGammaEnabled;
}

void Camera::SetGammaEnabled( Boolean state )
{
	m_bGammaEnabled = state;
}

const Mix::Vector3& Camera::GetGammaValue( void ) const
{
	return m_GammaValue;
}

const Mix::Vector3& Camera::GetInternalGammaValue( void ) const
{
	return m_InternalGammaValue;
}

void Camera::SetGammaValue( const Mix::Vector3& value )
{
	m_GammaValue.x = max( MIX_FLOAT_EPSILON, value.x );
	m_GammaValue.y = max( MIX_FLOAT_EPSILON, value.y );
	m_GammaValue.z = max( MIX_FLOAT_EPSILON, value.z );
}

void Camera::SetGammaValue( Float32 value )
{
	Float32 temp = max( MIX_FLOAT_EPSILON, value );

	m_GammaValue.Set( temp, temp, temp );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : MotionBlur
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsMotionBlurEnabled( void ) const
{
	return m_bMotBlurEnabled;
}

void Camera::SetMotionBlurEnabled( Boolean state )
{
	m_bMotBlurEnabled = state;
}

const Mix::Scene::ICamera::MOTION_BLUR_SETTINGS& Camera::GetMotionBlurSettings( void ) const
{
	return m_MotBlurSettings;
}

void Camera::SetMotionBlurSettings( const Mix::Scene::ICamera::MOTION_BLUR_SETTINGS& settings )
{
	m_MotBlurSettings.quality = settings.quality;
	m_MotBlurSettings.minAngularVelocity = max( 0.0f, settings.minAngularVelocity );
	m_MotBlurSettings.maxAngularVelocity = max( m_MotBlurSettings.minAngularVelocity, settings.maxAngularVelocity );
	m_MotBlurSettings.minLinearVelocity = max( 0.0f, settings.minLinearVelocity );
	m_MotBlurSettings.maxLinearVelocity = max( m_MotBlurSettings.minLinearVelocity, settings.maxLinearVelocity );
	m_MotBlurSettings.amount = MIX_CLAMP( settings.amount, Camera::MB_MIN_AMOUNT, Camera::MB_MAX_AMOUNT );
	m_MotBlurSettings.echoTimeLength = max( 0.0f, settings.echoTimeLength );
	m_MotBlurSettings.dist = max( 0.0f, settings.dist );
	m_MotBlurSettings.damping = MIX_CLAMP( settings.damping, 0.0f, 1.0f );
	m_MotBlurSettings.scale = MIX_CLAMP( settings.scale, 0.0f, 1.0f );
	m_MotBlurSettings.intensity = max( 0.0f, settings.intensity );

	if( MIX_FLOAT_IS_ZERO( m_MotBlurSettings.echoTimeLength ) == False )
	{
		m_MotBlurCtx.invEchoTimeLength = 1.0f / m_MotBlurSettings.echoTimeLength;
	}
	else
	{
		m_MotBlurCtx.invEchoTimeLength = 1.0f;
	}
}

const Camera::INTERNAL_MOTION_BLUR_SETTINGS& Camera::GetInternalMotionBlurSettings( void ) const
{
	return m_InternalMotBlurSettings;
}

Boolean Camera::IsMotionBlurActivated( void ) const
{
	return ( m_MotBlurCtx.state > Camera::MB_WAIT );
}

UInt32 Camera::GetMotionBlurCurrentAmount( void ) const
{
	if( m_MotBlurCtx.state <= Camera::MB_WAIT )
	{
		return 0;
	}

	return m_MotBlurCtx.preVPCount;
}

const Mix::Matrix4x4& Camera::GetMotionBlurPreVPMat( void ) const
{
	MIX_ASSERT( m_MotBlurCtx.preVPCount > 0 );

	return m_MotBlurCtx.preVPMats[m_MotBlurCtx.preVPTail];
}

const Mix::Matrix4x4& Camera::GetMotionBlurPreVPMatByIndex( UInt32 index ) const
{
	MIX_ASSERT( m_MotBlurCtx.preVPCount > index );

	return m_MotBlurCtx.preVPMats[index];
}

Float32 Camera::GetMotionBlurSpeed( Float32 minValue, Float32 maxValue, Float32 curValue )
{
	MIX_ASSERT( minValue <= maxValue );

	return MIX_CLAMP( MIX_FLOAT_DIV( curValue - minValue, max( 0.0f, maxValue - minValue ) ), 0.0f, 1.0f );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : Chromatism
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsChromatismAvailabled( void ) const
{
	return ( MIX_TESTBIT( m_ModConfigCaps, Mix::Scene::RCAP_CHROMATISM ) == Mix::Scene::RCAP_CHROMATISM );
}

Boolean Camera::IsChromatismEnabled( void ) const
{
	return m_bChromatismEnabled;
}

void Camera::SetChromatismEnabled( Boolean state )
{
	m_bChromatismEnabled = state;
}

const Mix::Scene::ICamera::CHROMATISM_SETTINGS& Camera::GetChromatismSettings( void ) const
{
	return m_ChromatismSettings;
}

const Camera::INTERNAL_CHROMATISM_SETTINGS& Camera::GetInternalChromatismSettings( void ) const
{
	return m_InternalChromatismSettings;
}

void Camera::SetChromatismSettings( const Mix::Scene::ICamera::CHROMATISM_SETTINGS& settings )
{
	m_ChromatismSettings.distortion.k = MIX_CLAMP( settings.distortion.k, -1.0f, +1.0f );
	m_ChromatismSettings.distortion.kCube = MIX_CLAMP( settings.distortion.kCube, -1.0f, +1.0f );
	m_ChromatismSettings.distortion.scale = max( 0.0f, settings.distortion.scale );
	m_ChromatismSettings.colorFactor = settings.colorFactor.ToSaturate();
	m_ChromatismSettings.blur = settings.blur;
	m_ChromatismSettings.weight = max( 1.0f, settings.weight );
	m_ChromatismSettings.fiStartZ = max( 0.0f, settings.fiStartZ );
	m_ChromatismSettings.fiEndZ = max( m_ChromatismSettings.fiStartZ, settings.fiEndZ );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : Dof
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsDofAvailabled( void ) const
{
	return ( MIX_TESTBIT( m_ModConfigCaps, Mix::Scene::RCAP_DEPTH_OF_FIELD ) == Mix::Scene::RCAP_DEPTH_OF_FIELD );
}

Boolean Camera::IsDofEnabled( void ) const
{
	return m_bDofEnabled;
}

void Camera::SetDofEnabled( Boolean state )
{
	m_bDofEnabled = state;
}

const Mix::Scene::ICamera::DOF_SETTINGS& Camera::GetDofSettings( void ) const
{
	return m_DofSettings;
}

void Camera::SetDofSettings( const Mix::Scene::ICamera::DOF_SETTINGS& param )
{
	m_DofSettings.nearZ = param.nearZ;
	m_DofSettings.nearDist = max( 0.0f, param.nearDist );
	m_DofSettings.farZ = max( m_DofSettings.nearZ, param.farZ );
	m_DofSettings.farDist = max( 0.0f, param.farDist );
	m_DofSettings.blur1 = param.blur1;
	m_DofSettings.blur2 = param.blur2;
	m_DofSettings.blurThreshold = MIX_CLAMP( param.blurThreshold, 0.0f, 1.0f );
}

const Camera::INTERNAL_DOF_SETTINGS& Camera::GetInternalDofSettings( void ) const
{
	return m_InternalDofSettings;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : LensDistortion
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsLensDistortionEnabled( void ) const
{
	return m_bLensDistEnabled;
}

void Camera::SetLensDistortionEnabled( Boolean state )
{
	m_bLensDistEnabled = state;
}

const Mix::Scene::ICamera::DISTORTION_SETTINGS& Camera::GetLendDistortionSettings( void ) const
{
	return m_LensDistSettings;
}

void Camera::SetLendDistortionSettings( const Mix::Scene::ICamera::DISTORTION_SETTINGS& param )
{
	m_LensDistSettings.k = param.k;
	m_LensDistSettings.kCube = param.kCube;
	m_LensDistSettings.scale = max( 0.0f, param.scale );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : Vignette
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean Camera::IsVignetteEnabled( void ) const
{
	return m_bVignetteEnabled;
}

void Camera::SetVignetteEnabled( Boolean state )
{
	m_bVignetteEnabled = state;
}

const Mix::Scene::ICamera::VIGNETTE_SETTINGS& Camera::GetVignetteSettings( void ) const
{
	return m_VignetteSettings;
}

const Camera::INTERNAL_VIGNETTE_SETTINGS& Camera::GetInternalVignetteSettings( void ) const
{
	return m_InternalVignetteSettings;
}

void Camera::SetVignetteSettings( const Mix::Scene::ICamera::VIGNETTE_SETTINGS& settings )
{
	m_VignetteSettings.start = max( 0.0f, settings.start );
	m_VignetteSettings.end = max( m_VignetteSettings.start, settings.end );
	m_VignetteSettings.color = settings.color;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : AntiAliasing
////////////////////////////////////////////////////////////////////////////////////////////////////

Mix::Scene::ICamera::ANTIALIASING_TYPE Camera::GetAntiAliasingType( void ) const
{
	return m_AAType;
}

void Camera::SetAntiAliasingType( Mix::Scene::ICamera::ANTIALIASING_TYPE type )
{
	m_AAType = type;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Camera : Debug
////////////////////////////////////////////////////////////////////////////////////////////////////

void Camera::Debug_SetFillType( Mix::Graphics::FILL_TYPE type )
{
#ifdef _DEBUG
	m_DebFillType = type;
#endif //_DEBUG
}

Mix::Graphics::FILL_TYPE Camera::Debug_GetFillType( void ) const
{
#ifdef _DEBUG
	return m_DebFillType;
#else //_DEBUG
	return Mix::Graphics::FILL_SOLID;
#endif //_DEBUG
}

void Camera::Debug_SetDrawMethod( Mix::Scene::DEBUG_DRAW_METHOD method )
{
#ifdef _DEBUG
	m_DebDrawMethod = method;
#endif //_DEBUG
}

Mix::Scene::DEBUG_DRAW_METHOD Camera::Debug_GetDrawMethod( void ) const
{
#ifdef _DEBUG
	return m_DebDrawMethod;
#else //_DEBUG
	return Mix::Scene::DDM_BEFORE;
#endif //_DEBUG
}

void Camera::Debug_SetDrawFlags( UInt32 flags )
{
#ifdef _DEBUG
	m_DebDrawFlags = flags;
#endif //_DEBUG
}

UInt32 Camera::Debug_GetDrawFlags( void ) const
{
#ifdef _DEBUG
	return m_DebDrawFlags;
#else //_DEBUG
	return Mix::Scene::DDF_MESH;
#endif //_DEBUG
}

const Mix::Scene::ICamera::DEBUG_DRAW_FILIMIC_SETTINGS& Camera::Debug_GetDrawFilmicSettings( void ) const
{
#ifdef _DEBUG
	return m_DebDrawFilmicSettings;
#else //_DEBUG
	static const Mix::Scene::ICamera::DEBUG_DRAW_FILIMIC_SETTINGS DUMMY = { Mix::Rectangle( 0, 0, 0, 0 ), 0, 0.0f, 0.0f, 0, 0.0f };
	return DUMMY;
#endif //_DEBUG
}

void Camera::Debug_SetDrawFilmicSettings( const Mix::Scene::ICamera::DEBUG_DRAW_FILIMIC_SETTINGS& settings )
{
#ifdef _DEBUG
	m_DebDrawFilmicSettings.rect.x = settings.rect.x;
	m_DebDrawFilmicSettings.rect.y = settings.rect.y;
	m_DebDrawFilmicSettings.rect.width = max( 1, settings.rect.width );
	m_DebDrawFilmicSettings.rect.height = max( 1, settings.rect.height );
	m_DebDrawFilmicSettings.padding = max( 0, settings.padding );
	m_DebDrawFilmicSettings.valueMax = max( 1.0f, settings.valueMax );
	m_DebDrawFilmicSettings.valueStep = max( 0.1f, settings.valueStep );
	m_DebDrawFilmicSettings.memNum = max( 2, settings.memNum );
	m_DebDrawFilmicSettings.errValue = max( MIX_FLOAT_EPSILON, settings.errValue );
#endif //_DEBUG
}

UInt32 Camera::Debug_GetProfile( UInt32 type, void* pProf, UInt32 size ) const
{
#ifdef _DEBUG

	if( RendererObject::IsRendering() == False )
	{
		return 0;
	}

	MIX_ASSERT( m_pRenderer != NULL );
	MIX_ASSERT( m_pOctView != NULL );

	return m_pRenderer->Debug_GetCameraProfile( m_pOctView->GetID(), type, pProf, size );

#else //_DEBUG
	return 0;
#endif //_DEBUG
}

UInt32 Camera::Debug_GetImageNum( UInt32 type ) const
{
#ifdef _DEBUG

	if( RendererObject::IsRendering() == False )
	{
		return 0;
	}

	MIX_ASSERT( m_pRenderer != NULL );
	MIX_ASSERT( m_pOctView != NULL );

	return m_pRenderer->Debug_GetCameraImageNum( m_pOctView->GetID(), type );

#else //_DEBUG
	return 0;
#endif //_DEBUG
}

Boolean Camera::Debug_GetImage( UInt32 type, UInt32 index, Mix::Graphics::ITexture** ppTexture )
{
#if _DEBUG

	if( RendererObject::IsRendering() == False )
	{
		return 0;
	}

	MIX_ASSERT( m_pRenderer != NULL );
	MIX_ASSERT( m_pOctView != NULL );

	return m_pRenderer->Debug_GetCameraImage( m_pOctView->GetID(), type, index, ppTexture );

#else //_DEBUG
	return False;
#endif //_DEBUG
}

#ifdef _DEBUG

const wchar_t* Camera::Debug_GetName( void ) const
{
	return m_DebugName.GetConstPtr();
}

void Camera::Debug_SetName( const wchar_t* pName )
{
	m_DebugName = MIX_SAFE_NAME( pName );
}

#endif //_DEBUG

}}}
