#include "Mix/Common.h"

#include <Shlwapi.h>

#ifdef _DEBUG
	#include <map>
	#include <string>
#endif //_DEBUG

#define MIX_USE_MEMORY_LOCKS

#define ONLY_MSPACES 1

#ifdef MIX_USE_MEMORY_LOCKS
	#include "Mix/ScopedLock.h"
	#include "Mix/CriticalSection.h"
#else //MIX_USE_MEMORY_LOCKS
	#define USE_LOCKS 1
#endif //MIX_USE_MEMORY_LOCKS

#include "malloc.c"

#include "SFMT.h"

#include "Mix/Dynamics/IObject.h"

#include "Mix/Private/Engine.h"

#include "Mix/Private/Memory/Buffer.h"

#include "Mix/Geometry/Plane.h"
#include "Mix/Geometry/Sphere.h"
#include "Mix/Geometry/AABB.h"
#include "Mix/Geometry/OBB.h"

#include "Mix/Private/Graphics/Common/Manager.h"
#include "Mix/Private/Graphics/Utility/Common/TextPrinter.h"

#include "Mix/Private/Dynamics/Utility.h"
#include "Mix/Private/Dynamics/Object.h"
#include "Mix/Private/Dynamics/Shape.h"
#include "Mix/Dynamics/IShape.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Memory
////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef MIX_USE_MEMORY_LOCKS
	#define MIX_MEM_LOCK( index ) Mix::ScopedLock lock( g_Sections[index].sync )
#else // MIX_USE_MEMORY_LOCKS
	#define MIX_MEM_LOCK( index )
#endif //MIX_USE_MEMORY_LOCKS

namespace Mix{ namespace Memory{

#ifdef _DEBUG
	struct DEBUG_ALLOCATE_INFO
	{
		UInt16 alignment;
		UIntT size;
		std::wstring srcFile;
		Int32 srcLine;
	};

	static const UInt32 DEBUG_GAP_VALUE = 0xFDFDFDFD;
	typedef std::map<void*, Mix::Memory::DEBUG_ALLOCATE_INFO> DebugAllocateInfoMap;

	UInt32 g_DebBlokenCount = 0;

#endif //_DEBUG

	struct ALLOCATE_DESC
	{
		UInt16 section;
		UInt16 alignment;
		void* real;
	};

	struct SECTION
	{
		mspace space;

#ifdef MIX_USE_MEMORY_LOCKS
		Mix::CriticalSection sync;
#endif //MIX_USE_MEMORY_LOCKS

#ifdef _DEBUG
		DebugAllocateInfoMap* debAllocInfoMap;
#endif //_DEBUG
	};

	static const UInt32 GAP_VALUE = 0x4D474D47;

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

	Mix::Memory::SECTION g_Sections[Mix::Memory::SECTION_TYPE_MAX];

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

#ifdef _DEBUG
	void Debug_Print( const wchar_t* pFormat, ... )
	{
		va_list args;
		wchar_t str[4096] = L"";

		va_start( args, pFormat );
		_vsnwprintf_s( str, sizeof( str ) >> 1, _TRUNCATE, pFormat, args );
		va_end( args );

		::OutputDebugString( str );
		::OutputDebugString( L"\n" );
	}

	void Debug_AddAllocateInfo( void* ptr, UInt16 section, UInt16 alignment, UIntT size, const wchar_t* pSrcFile, Int32 srcLine )
	{
		UInt32* debGap = reinterpret_cast<UInt32*>( reinterpret_cast<UInt8*>( ptr ) + size );
		DEBUG_ALLOCATE_INFO debAllocInfo;

		*debGap = Mix::Memory::DEBUG_GAP_VALUE;

		debAllocInfo.alignment = alignment;
		debAllocInfo.size = size;
		debAllocInfo.srcFile = ( pSrcFile != NULL )? pSrcFile : Mix::STR_UNKNOWN;
		debAllocInfo.srcLine = srcLine;

		g_Sections[section].debAllocInfoMap->insert( Mix::Memory::DebugAllocateInfoMap::value_type( ptr, debAllocInfo ) );
	}

	Mix::Memory::DEBUG_ALLOCATE_INFO Debug_RemoveAllocateInfo( UInt16 section, void* ptr )
	{
		Mix::Memory::DebugAllocateInfoMap* debAllocInfoMap = g_Sections[section].debAllocInfoMap;
		Mix::Memory::DebugAllocateInfoMap::iterator it_deb = debAllocInfoMap->find( ptr );
		MIX_ASSERT( it_deb != debAllocInfoMap->end() );
		Mix::Memory::DEBUG_ALLOCATE_INFO debAllocInfo = it_deb->second;
		UInt32* debGap = reinterpret_cast<UInt32*>( reinterpret_cast<UInt8*>( ptr ) + debAllocInfo.size );

		if( *debGap != Mix::Memory::DEBUG_GAP_VALUE )
		{
			Mix::Memory::Debug_Print( L"Mix : (MEMORY_BLOKEN) : Section[%u] Address[0x%u] Alignment[%u] Size[%u]\n  \"%s\"(%u)",
				section, ptr, debAllocInfo.alignment, debAllocInfo.size,
				debAllocInfo.srcFile.c_str(), debAllocInfo.srcLine );

			if( g_DebBlokenCount != 0xFFFFFFFF )
			{
				g_DebBlokenCount++;
			}
		}

		debAllocInfoMap->erase( it_deb );

		return debAllocInfo;
	}

#endif //_DEBUG

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

	void CreateSection( Mix::Memory::SECTION& section, UIntT defSize = 1024 * 1024 )
	{
		section.space = create_mspace( defSize, 0 );

#ifdef _DEBUG
		section.debAllocInfoMap = MIX_NEW Mix::Memory::DebugAllocateInfoMap();
#endif //_DEBUG
	}

	void DestroySection( Mix::Memory::SECTION& section )
	{
#ifdef _DEBUG
		MIX_DELETE( section.debAllocInfoMap );
#endif //_DEBUG

		destroy_mspace( section.space );
	}

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

	void Initialize( void )
	{
		// メモリスペースを作成

		CreateSection( g_Sections[Mix::Memory::SECTION_GENERAL] );
		CreateSection( g_Sections[Mix::Memory::SECTION_GRAPHICS] );
		CreateSection( g_Sections[Mix::Memory::SECTION_SOUND] );
		CreateSection( g_Sections[Mix::Memory::SECTION_DYNAMICS] );
		CreateSection( g_Sections[Mix::Memory::SECTION_SCENE] );
		CreateSection( g_Sections[Mix::Memory::SECTION_USER] );
	}

	void Terminate( void )
	{
		// メモリリーク、メモリ破壊を通知

#ifdef _DEBUG
		const wchar_t* SECTION_NAME_TABLE[Mix::Memory::SECTION_TYPE_MAX] =
		{
			L"GENERAL",
			L"GRAPHICS",
			L"SOUND",
			L"DYNAMICS",
			L"SCENE",
			L"USER",
		};

		UInt32 debLeakCount = 0;

		for( UInt16 i = 0; i < Mix::Memory::SECTION_TYPE_MAX; i++ )
		{
			const Mix::Memory::DebugAllocateInfoMap* debAllocInfoMap = g_Sections[i].debAllocInfoMap;

			if( debAllocInfoMap->size() > 0 )
			{
				Mix::Memory::DebugAllocateInfoMap::const_iterator it_begin = debAllocInfoMap->begin();
				Mix::Memory::DebugAllocateInfoMap::const_iterator it_end = debAllocInfoMap->end();
				Mix::Memory::DebugAllocateInfoMap::const_iterator it;

				for( it = it_begin; it != it_end; ++it )
				{
					const Mix::Memory::DEBUG_ALLOCATE_INFO& debAllocInfo = it->second;

					Mix::Memory::Debug_Print( L"Mix : (MEMORY_LEAK) : Section[%s] Address[0x%u] Alignment[%u] Size[%u]\n  \"%s\"(%u)",
						SECTION_NAME_TABLE[i], it->first, debAllocInfo.alignment, debAllocInfo.size,
						debAllocInfo.srcFile.c_str(), debAllocInfo.srcLine );

					if( debLeakCount != 0xFFFFFFFF )
					{
						debLeakCount++;
					}
				}
			}
		}

		if( ( debLeakCount > 0 ) || ( g_DebBlokenCount > 0 ) )
		{
			wchar_t mes[2048];

			::wsprintf( mes, L"いくつかのメモリリーク、メモリ破壊が検出されました。\nログを確認してください。\n\nメモリリーク %u\nメモリ破壊 %u", debLeakCount, g_DebBlokenCount );
			::MessageBox( GetDesktopWindow(), mes, L"Mix デバッグ", MB_ICONWARNING | MB_OK );
		}
#endif // _DEBUG

		// メモリスペースを破棄

		for( UInt16 i = 0; i < Mix::Memory::SECTION_TYPE_MAX; i++ )
		{
			DestroySection( g_Sections[i] );
		}
	}

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

	void* WriteAllocateDesc( void* ptr, UInt16 section, UInt16 alignment )
	{
		UInt32* real = static_cast<UInt32*>( ptr ) + ( alignment >> 1 );

		*( real - 2 ) = ( section << 16 ) | alignment;
		*( real - 1 ) = Mix::Memory::GAP_VALUE; // ギャップ

		return real;
	}

	Mix::Memory::ALLOCATE_DESC GetAllocateDesc( void* ptr )
	{
		UInt32* addr = static_cast<UInt32*>( ptr );
		UInt32 data = *( addr - 2 );

		Mix::Memory::ALLOCATE_DESC ret;

		ret.section = static_cast<UInt16>( ( data >> 16 ) & 0x0000FFFF );
		ret.alignment = static_cast<UInt16>( data & 0x0000FFFF );
		ret.real = addr - ( ret.alignment >> 1 );

		return ret;
	}

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

	Mix::Memory::SECTION_INFO GetSectionInfo( UInt16 section )
	{
		MIX_ASSERT( section < Mix::Memory::SECTION_TYPE_MAX );

		mallinfo info;
		Mix::Memory::SECTION_INFO ret;

		MIX_MEM_LOCK( section );

		info = mspace_mallinfo( g_Sections[section].space );

		ret.maxTotalAllocatedSize = info.usmblks;
		ret.totalAllocatedSize = info.uordblks;
		ret.totalFreeSize= info.fordblks;
		ret.releasableSize= info.keepcost - TOP_FOOT_SIZE;

		return ret;
	}

	void* Allocate( UInt16 section, UIntT size, const wchar_t* pSrcFile, Int32 srcLine )
	{
		MIX_ASSERT( section < Mix::Memory::SECTION_TYPE_MAX );

		static const UIntT alignment = sizeof( size_t );
		void* real;

		MIX_MEM_LOCK( section );

#ifdef _DEBUG
		real = mspace_malloc( g_Sections[section].space, alignment /* 情報 1 */ + alignment/* 情報 2 */ + size + alignment /* メモリ破壊確認用 */ );
#else //_DEBUG
		real = mspace_malloc( g_Sections[section].space, size + alignment + alignment );
#endif //_DEBUG
		if( real != NULL )
		{
			real = WriteAllocateDesc( real, section, alignment );

#ifdef _DEBUG
			Debug_AddAllocateInfo( real, section, alignment, size, pSrcFile, srcLine );
#endif //_DEBUG
		}

		return real;
	}

	void* AllocateAligned( UInt16 section, UInt16 alignment, UIntT size, const wchar_t* pSrcFile, Int32 srcLine )
	{
		void* real;

		MIX_MEM_LOCK( section );

#ifdef _DEBUG
		real = mspace_memalign( g_Sections[section].space, alignment, size + alignment + alignment + alignment );
#else //_DEBUG
		real = mspace_memalign( g_Sections[section].space, alignment, size + alignment + alignment );
#endif //_DEBUG
		if( real != NULL )
		{
			real = WriteAllocateDesc( real, section, alignment );

#ifdef _DEBUG
			Debug_AddAllocateInfo( real, section, alignment, size, pSrcFile, srcLine );
#endif //_DEBUG
		}

		return real;
	}

	void* Reallocate( void* ptr, UIntT size, const wchar_t* pSrcFile, Int32 srcLine )
	{
		MIX_ASSERT( ptr != NULL );
		MIX_ASSERT( size != 0 );

		Mix::Memory::ALLOCATE_DESC allocDesc = Mix::Memory::GetAllocateDesc( ptr );
		MIX_ASSERT_EX( allocDesc.section <= Mix::Memory::SECTION_TYPE_MAX, L"管理外のメモリを再確保しようとしました。\n\nFile[%s]\nLine[%d]", pSrcFile, srcLine );

		void* real;

		MIX_MEM_LOCK( allocDesc.section );

#ifdef _DEBUG
		Mix::Memory::DEBUG_ALLOCATE_INFO debAllocInfo;

		debAllocInfo = Debug_RemoveAllocateInfo( allocDesc.section, ptr );
#endif //_DEBUG

#ifdef _DEBUG
		real = mspace_realloc( g_Sections[allocDesc.section].space, allocDesc.real, size + allocDesc.alignment + allocDesc.alignment + allocDesc.alignment );
#else //_DEBUG
		real = mspace_realloc( g_Sections[allocDesc.section].space, allocDesc.real, size + allocDesc.alignment + allocDesc.alignment );
#endif //_DEBUG
		if( real != NULL )
		{
			real = Mix::Memory::WriteAllocateDesc( real, allocDesc.section, allocDesc.alignment );

#ifdef _DEBUG
			Debug_AddAllocateInfo(	real,
									allocDesc.section,
									debAllocInfo.alignment,
									size,
									debAllocInfo.srcFile.c_str(),
									debAllocInfo.srcLine );
#endif //_DEBUG
		}

		return real;
	}

	void Free( void* ptr, const wchar_t* pSrcFile, Int32 srcLine )
	{
		Mix::Memory::ALLOCATE_DESC allocDesc = Mix::Memory::GetAllocateDesc( ptr );
		MIX_ASSERT_EX( allocDesc.section <= Mix::Memory::SECTION_TYPE_MAX, L"管理外のメモリを解放しようとしました。\n\nFile[%s]\nLine[%d]", pSrcFile, srcLine );

		MIX_MEM_LOCK( allocDesc.section );

#ifdef _DEBUG
		Debug_RemoveAllocateInfo( allocDesc.section, ptr );
#endif //_DEBUG

		mspace_free( g_Sections[allocDesc.section].space, allocDesc.real );
	}

	void Memory::Copy( void* pDst, const void* pSrc, UIntT size )
	{
		::memcpy( pDst, pSrc, size );
	}

	void Memory::Fill( void* pDst, UIntT size, UInt8 value )
	{
		::memset( pDst, value, size );
	}

	void Memory::Zero( void* pDst, UIntT size )
	{
		::memset( pDst, 0, size );
	}

	Boolean Memory::CreateBuffer( UInt16 section, UIntT size, const void* pInitialData, Mix::Memory::IBuffer** ppBuffer )
	{
		MIX_ASSERT( section < Mix::Memory::SECTION_TYPE_MAX );
		MIX_ASSERT( size > 0 );
		MIX_ASSERT( ppBuffer != NULL );

		Mix::Memory::Buffer* pBuffer;

		pBuffer = Mix::Memory::Buffer::CreateInstance();
		if( pBuffer == NULL )
		{
			return False;
		}

		if( pBuffer->Create( section, size ) == False )
		{
			return False;
		}

		if( pInitialData != NULL )
		{
			::CopyMemory( pBuffer->GetPointer(), pInitialData, size );
		}

		( *ppBuffer ) = pBuffer;

		return True;
	}

	class Initializer
	{
	public:
		Initializer( void ) { Mix::Memory::Initialize(); }
		~Initializer( void ) { Mix::Memory::Terminate(); }
	};

	#pragma warning( disable: 4074 )

	#if defined(__cplusplus) && defined(__GNUC__)
		Initializer init __attribute__((init_priority( 111 )));
	#elif defined (_MSC_VER)
		#pragma init_seg(compiler)
		Initializer init;
	#else
		#error not supported.
	#endif
}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::IO
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mix{ namespace IO{

	//CSIDLテーブル( 特殊フォルダ取得用 )
	const Int32 CSIDL_TABLE[Mix::IO::DIRECTORY_IDENT_MAX] =
	{
		0x0000,			//ダミー
		CSIDL_APPDATA,	//アプリケーションデータ
		CSIDL_DESKTOP,	//デスクトップ
		CSIDL_PERSONAL	//マイドキュメント
	};

	Mix::IO::IManager* GetManagerPtr( void )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );
		return Mix::GetInternalEnginePtr()->GetInternalIOManagerPtr();
	}

	Boolean GetManager( Mix::IO::IManager** ppManager )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );

		Mix::IO::IManager* pManager = Mix::GetInternalEnginePtr()->GetInternalIOManagerPtr();

		if( pManager != NULL )
		{
			MIX_ADD_REF( pManager );
			( *ppManager ) = pManager;
		}
		else
		{
			return False;
		}

		return True;
	}

	Boolean IsAbsolutePath( const wchar_t* pPath )
	{
		if( ( pPath == NULL ) || ( ::wcslen( pPath ) == 0 ) )
		{
			return False;
		}

		Boolean bAbsolute;

		if( ::wcslen( pPath ) >= 3 )
		{
			if( ( pPath[1] == L':' ) &&
				( ( pPath[2] == L'\\' ) || ( pPath[2] == L'/' ) ) )
			{
				bAbsolute = True;
			}
			else
			{
				bAbsolute = False;
			}
		}
		else
		{
			bAbsolute = False;
		}

		return bAbsolute;
	}

	Boolean IsRelativePath( const wchar_t* pPath )
	{
		if( ( pPath == NULL ) || ( ::wcslen( pPath ) == 0 ) )
		{
			return True;
		}

		return ( IsAbsolutePath( pPath ) == False );
	}

	Boolean CombinePath( const wchar_t* pBaseDirPath, Boolean bCnvBase, const wchar_t* pRelPath, Mix::StringW& outPath )
	{
		wchar_t baseDirPath[_MAX_PATH];

		if( ( pBaseDirPath == NULL ) || ( wcslen( pBaseDirPath ) == 0 ) )
		{
			if( ::GetCurrentDirectoryW( _MAX_PATH, baseDirPath ) == 0 )
			{
				return False;
			}
		}
		else
		{
			if( ( bCnvBase == False ) ||
				( IsAbsolutePath( pBaseDirPath ) == True ) )
			{
				::wcscpy_s( baseDirPath, pBaseDirPath );
			}
			else
			{
				wchar_t curDirPath[_MAX_PATH];

				if( ::GetCurrentDirectoryW( _MAX_PATH, curDirPath ) == 0 )
				{
					return False;
				}

				if( PathCombineW( baseDirPath, curDirPath, pBaseDirPath ) == NULL )
				{
					return False;
				}
			}
		}

		if( ( ( pRelPath == NULL ) || ( wcslen( pRelPath ) == 0 ) ) )
		{
			wchar_t currentDirPath[_MAX_PATH];

			if( ::GetCurrentDirectoryW( _MAX_PATH, currentDirPath ) == 0 )
			{
				return False;
			}

			outPath = baseDirPath;
		}
		else
		{
			if( ( wcslen( pRelPath ) == 1 ) && ( ( pRelPath[0] == '\\' ) || ( pRelPath[0] == '/' ) ) )
			{
				// ベースのディレクトリパスは指定されているが、結合しようとしているパスがデリミタの場合

				wchar_t lastChar = baseDirPath[wcslen( baseDirPath ) - 1];

				if( ( lastChar != '\\' ) && ( lastChar != '/' ) )
				{
					outPath.Sprintf( L"%s\\", baseDirPath );
				}
				else
				{
					outPath = baseDirPath;
				}
			}
			else
			{
				// 通常の結合

				wchar_t tempPath[_MAX_PATH];

				Mix::Memory::Zero( &tempPath, sizeof( tempPath ) );

				if( PathCombineW( tempPath, baseDirPath, pRelPath ) == NULL )
				{
					return False;
				}

				outPath = tempPath;
			}
		}

		return True;
	}

	Boolean GetSpecialDirectoryPath( Mix::IO::SPECIAL_DIRECTORY_TYPE type, Mix::String& dirPath )
	{
		wchar_t temp[MAX_PATH];

		IMalloc* pMalloc;

		if( ::SHGetMalloc( &pMalloc ) == S_OK )
		{
			LPITEMIDLIST pItemIdList;

			if( ::SHGetSpecialFolderLocation( NULL, Mix::IO::CSIDL_TABLE[type], &pItemIdList ) == S_OK )
			{
				::SHGetPathFromIDList( pItemIdList, temp );
				pMalloc->Free( pItemIdList );
			}
			else
			{
				pMalloc->Release();
				return False;
			}

			pMalloc->Release();
		}

		if( Mix::IO::CombinePath( temp, False, L"\\", dirPath ) == False )
		{
			return False;
		}

		dirPath.Lower();

		return True;
	}

}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::HID
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mix{ namespace HID{

	Mix::HID::IManager* GetManagerPtr( void )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );
		return Mix::GetInternalEnginePtr()->GetHIDManagerPtr();
	}

	Boolean GetManager( Mix::HID::IManager** ppManager )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );

		Mix::HID::IManager* pManager = Mix::GetInternalEnginePtr()->GetHIDManagerPtr();

		if( pManager != NULL )
		{
			MIX_ADD_REF( pManager );
			( *ppManager ) = pManager;
		}
		else
		{
			return False;
		}

		return True;
	}

}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Parallel
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mix{ namespace Parallel{

	Mix::Parallel::IManager* GetManagerPtr( void )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );
		return Mix::GetInternalEnginePtr()->GetParallelManagerPtr();
	}

	Boolean GetManager( Mix::Parallel::IManager** ppManager )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );

		Mix::Parallel::IManager* pManager = Mix::GetInternalEnginePtr()->GetParallelManagerPtr();

		if( pManager != NULL )
		{
			MIX_ADD_REF( pManager );
			( *ppManager ) = pManager;
		}
		else
		{
			return False;
		}

		return True;
	}

}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Geometry
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mix{ namespace Geometry{

	Float32 DistancePointPlane( const Mix::Vector3& p, const Mix::Geometry::Plane& plane )
	{
		return ( Mix::Vector3::Dot( plane.normal, p ) + plane.d );
	}

	void ClosestPointSphere( const Mix::Vector3& p, const Mix::Geometry::Sphere& sphere, Mix::Vector3& q )
	{
		Mix::Vector3 v = ( p - sphere.center );

		if( sphere.radius >= v.GetLength() )
		{
			q = p;
		}

		v.Normalize();
		q = ( sphere.center + ( v * sphere.radius ) );
	}

	void ClosestPointPlane( const Mix::Vector3& p, const Mix::Geometry::Plane& plane, Mix::Vector3& q )
	{
		Float32 t = Mix::Vector3::Dot( plane.normal, p ) - plane.d;

		q = ( p - ( t * plane.normal ) );
	}

	void ClosestPointOBB( const Mix::Vector3& p, const Mix::Geometry::OBB& obb, Mix::Vector3& q )
	{
		Int32 i;
		Mix::Vector3 d = ( p - obb.center );

		q = obb.center;

		for( i = 0; i < 3; i++ )
		{
			float dist = Mix::Vector3::Dot( d, obb.axis[i] );

			if( dist > obb.length.data[i] )
			{
				dist = obb.length.data[i];
			}

			if( dist < -obb.length.data[i] )
			{
				dist = -obb.length.data[i];
			}

			q += ( obb.axis[i] * dist );
		}
	}

	void ClosestPointAABB( const Mix::Vector3& p, const Mix::Geometry::AABB& aabb, Mix::Vector3& q )
	{
		const Float32* point = p.data;
		const Float32* pointEnd = point + 3;
		const Float32* aabbMin = aabb.min.data;
		const Float32* aabbMax = aabb.max.data;

		Float32* out = q.data;

		Float32 elm;
		Float32 tmp;

		while( point != pointEnd )
		{
			elm = *point++;

			tmp = *aabbMin++;
			if( elm < tmp ) { elm = tmp; }

			tmp = *aabbMax++;
			if( elm > tmp ) { elm = tmp; }

			*out++ = elm;
		}
	}

	Boolean PointInTriangle( const Mix::Vector3& p, const Mix::Vector3& a, const Mix::Vector3& b, const Mix::Vector3& c )
	{
		Mix::Vector3 aa = ( a - p );
		Mix::Vector3 bb = ( b - p );
		Mix::Vector3 cc = ( c - p );
		Mix::Vector3 u = Mix::Vector3::Cross( bb, cc );
		Mix::Vector3 v = Mix::Vector3::Cross( cc, aa );

		if( Mix::Vector3::Dot( u, v ) < MIX_FLOAT_EPSILON )
		{
			return False;
		}

		Mix::Vector3 w = Mix::Vector3::Cross( a, b );

		if( Mix::Vector3::Dot( u, w ) < MIX_FLOAT_EPSILON )
		{
			return False;
		}

		return True;
	}

	Boolean IntersectPointAABB( const Mix::Vector3& p, const Mix::Geometry::AABB& aabb )
	{
		const Mix::Vector3& aabbMin = aabb.min;
		const Mix::Vector3& aabbMax = aabb.max;

		if( ( aabbMin.x >  p.x ) || ( aabbMin.y >  p.y ) || ( aabbMin.z >  p.z ) ||
			( aabbMax.x <= p.x ) || ( aabbMax.y <= p.y ) || ( aabbMax.z <= p.z ) )
		{
			return False;
		}

		return True;
	}

	Boolean IntersectSphereSphere( const Mix::Geometry::Sphere& sphere1, const Mix::Geometry::Sphere& sphere2, Float32* pDist )
	{
		Mix::Vector3 vec = ( sphere1.center - sphere2.center );
		Float32 dist = vec.GetLength();

		if( pDist != NULL )
		{
			*pDist = dist;
		}

		return ( sphere1.radius + sphere2.radius ) >= dist;
	}

	Boolean IntersectSpherePlane( const Mix::Geometry::Sphere& sphere, const Mix::Geometry::Plane& plane, Float32* pDist )
	{
		Float32 distance = Mix::Vector3::Dot( sphere.center, plane.normal ) - plane.d;

		if( pDist != NULL )
		{
			( *pDist ) = distance;
		}

		return ::fabs( distance ) <= sphere.radius;
	}

	Boolean IntersectSphereOBB( const Mix::Geometry::Sphere& sphere, const Mix::Geometry::OBB& obb, Mix::Vector3* pPos )
	{
		Mix::Vector3 pos;
		Mix::Vector3 vec;

		ClosestPointOBB( sphere.center, obb, pos );

		if( pPos != NULL )
		{
			*pPos = pos;
		}

		vec = ( pos - sphere.center );

		return ( Mix::Vector3::Dot( vec, vec ) <= ( sphere.radius * sphere.radius ) );
	}

	Boolean IntersectSphereAABB( const Mix::Geometry::Sphere& sphere, const Mix::Geometry::AABB& aabb, Mix::Vector3* pPos )
	{
		Mix::Vector3 pos;
		Mix::Vector3 vec;

		ClosestPointAABB( sphere.center, aabb, pos );

		if( pPos != NULL )
		{
			*pPos = pos;
		}

		vec = ( pos - sphere.center );

		return ( vec.GetLengthSqr() <= ( sphere.radius * sphere.radius ) );
	}

	Boolean IntersectPlanePlane( const Mix::Geometry::Plane& plane1, const Mix::Geometry::Plane& plane2, Mix::Vector3* pPos, Mix::Vector3* pDir )
	{
		Mix::Vector3 d = Mix::Vector3::Cross( plane1.normal, plane2.normal );
		Float32 denom = Mix::Vector3::Dot( d, d );

		if( pDir != NULL )
		{
			*pDir = d;
		}

		if( denom < MIX_FLOAT_EPSILON )
		{
			return False;
		}

		if( pPos != NULL )
		{
			*pPos = ( Mix::Vector3::Cross( ( plane1.d * plane2.normal ) - ( plane2.d * plane1.normal ), d ) / denom );
		}

		return True;
	}

	Boolean IntersectPlaneOBB( const Mix::Geometry::Plane& plane, const Mix::Geometry::OBB& obb )
	{
		Int32 i;
		Float32 r;
		Float32 s;

		r = 0;
		for( i = 0; i < 3; i++ )
		{
			r += ( obb.length.data[i] * ::fabs( Mix::Vector3::Dot( plane.normal, obb.axis[i] ) ) );
		}

		s = ( Mix::Vector3::Dot( plane.normal, obb.center ) - plane.d );

		return ( ::fabs( s ) <= r );
	}

	Boolean IntersectPlaneAABB( const Mix::Geometry::Plane& plane, const Mix::Geometry::AABB& aabb )
	{
		Int32 i;
		Float32 r;
		Float32 s;
		Mix::Vector3 c = ( ( aabb.max + aabb.min ) * 0.5f );
		Mix::Vector3 e = ( aabb.max - c );

		r = 0;
		for( i = 0; i < 3; i++ )
		{
			r += e.data[i] * ::fabs( plane.normal.data[i] );
		}

		s = ( Mix::Vector3::Dot( plane.normal, c ) - plane.d );

		return ( ::fabs( s ) <= r );
	}

	Boolean IntersectOBBOBB( const Mix::Geometry::OBB& obb1, const Mix::Geometry::OBB& obb2 )
	{
		static const Int32 INDEX_TABLE[9][18] = 
		{
			{ 1, 2, 0, 2, 1, 0, /**/ 1, 0, 2, 2, 0, 1, /**/ 2, 1, 0, 1, 2, 0, },
			{ 1, 2, 1, 2, 1, 1, /**/ 0, 0, 2, 2, 0, 0, /**/ 2, 1, 1, 1, 2, 1, },
			{ 1, 2, 2, 2, 1, 2, /**/ 0, 0, 1, 1, 0, 0, /**/ 2, 1, 2, 1, 2, 2, },
			{ 0, 2, 0, 2, 0, 0, /**/ 1, 1, 2, 2, 1, 1, /**/ 0, 2, 0, 2, 0, 0, },
			{ 0, 2, 1, 2, 0, 1, /**/ 0, 1, 2, 2, 1, 0, /**/ 0, 2, 1, 2, 0, 1, },
			{ 0, 2, 2, 2, 0, 2, /**/ 0, 1, 1, 1, 1, 0, /**/ 0, 2, 2, 2, 0, 2, },
			{ 0, 1, 0, 1, 0, 0, /**/ 1, 2, 2, 2, 2, 1, /**/ 1, 0, 0, 0, 1, 0, },
			{ 0, 1, 1, 1, 0, 1, /**/ 0, 2, 2, 2, 2, 0, /**/ 1, 0, 1, 0, 1, 1, },
			{ 0, 1, 2, 1, 0, 2, /**/ 0, 2, 1, 1, 2, 0, /**/ 1, 0, 2, 0, 1, 2, },
		};

		Int32 i;
		Int32 j;
		Float32 ra;
		Float32 rb;
		Mix::Matrix3x3 R;
		Mix::Matrix3x3 absR;

		for( i = 0; i < 3; i++ )
		{
			for( j = 0; j < 3; j++ )
			{
				R.m[i][j] = Mix::Vector3::Dot( obb1.axis[i], obb2.axis[j] );
			}
		}

		Mix::Vector3 d = ( obb2.center - obb1.center );
		Mix::Vector3 t;

		for( i = 0; i < 3; i++ )
		{
			t.data[i] = Mix::Vector3::Dot( d, obb1.axis[i] );
		}

		//演算エラーがでないようにイプシロンを追加
		for( i = 0; i < 3; i++ )
		{
			for( j = 0; j < 3; j++ )
			{
				absR.m[i][j] = ( ::fabs( absR.m[i][j] ) + MIX_FLOAT_EPSILON );
			}
		}

		for( i = 0; i < 3; i++ )
		{
			ra = obb1.length.data[i];

			rb = 0;
			for( j = 0; j < 3; j++ )
			{
				rb += ( obb2.length.data[j] * absR.m[i][j] );
			}

			if( ::fabs( t.data[i] ) > ( ra + rb ) )
			{
				return False;
			}
		}

		for( i = 0; i < 3; i++ )
		{
			ra = 0;
			for( j = 0; j < 3; j++ )
			{
				ra += ( obb1.length.data[j] * absR.m[j][i] );
			}

			rb = obb2.length.data[i];

			if( ::fabs( t.data[0] * R.m[0][i] + t.data[1] * R.m[1][i] + t.data[2] * R.m[2][i] ) > ( ra + rb ) )
			{
				return False;
			}
		}

		for( i = 0; i < 9; i++ )
		{
			const Int32* p = &( INDEX_TABLE[i][0] );

			ra = ( ( obb1.length.data[p[0]] * absR.m[p[1]][p[2]] ) + ( obb1.length.data[p[3]] * absR.m[p[4]][p[5]] ) );
			rb = ( ( obb2.length.data[p[6]] * absR.m[p[7]][p[8]] ) + ( obb2.length.data[p[9]] * absR.m[p[10]][p[11]] ) );
			if( ::fabs( t.data[p[12]] * R.m[p[13]][p[14]] - t.data[p[15]] * R.m[p[16]][p[17]] ) > ( ra + rb ) )
			{
				return False;
			}
		}

		return True;
	}

	Boolean IntersectAABBAABB( const Mix::Geometry::AABB& aabb1, const Mix::Geometry::AABB& aabb2 )
	{
		Int32 i;

		for( i = 0; i < 3; i++ )
		{
			if( ( aabb1.max.data[i] < aabb2.min.data[i] ) ||
				( aabb1.min.data[i] > aabb2.max.data[i] ) )
			{
				return False;
			}
		}

		return True;
	}

	Boolean IntersectRaySphere( const Mix::Vector3& rayPos, const Mix::Vector3& rayDir, const Mix::Geometry::Sphere& sphere, Float32* pDist, Mix::Vector3* pPos )
	{
		Mix::Vector3 m = ( rayPos - sphere.center );
		float b = Mix::Vector3::Dot( m, rayDir );
		float c = ( Mix::Vector3::Dot( m, m ) - ( sphere.radius * sphere.radius ) );

		if( ( c > MIX_FLOAT_EPSILON ) &&
			( b > MIX_FLOAT_EPSILON ) )
		{
			return False;
		}

		float discr = ( ( b * b ) - c );

		if( discr < MIX_FLOAT_EPSILON )
		{
			return False;
		}

		float t = ( -b - ::sqrtf( discr ) );

		if( t < MIX_FLOAT_EPSILON )
		{
			t = 0.0f;
		}
	
		if( pDist != NULL )
		{
			*pDist = t;
		}
	
		Mix::Vector3 pos = ( rayPos + ( rayDir * t ) );

		if( pPos != NULL )
		{
			*pPos = pos;
		}

		return True;
	}

	Boolean IntersectRayPlane( const Mix::Vector3& rayPos, const Mix::Vector3& rayDir, const Mix::Geometry::Plane& plane, Float32* pDist, Mix::Vector3* pPos )
	{
		Float32 t = ( ( plane.d - Mix::Vector3::Dot( rayPos, plane.normal ) ) / Mix::Vector3::Dot( rayDir, plane.normal ) );

		if( pDist != NULL )
		{
			*pDist = t;
		}

		if( MIX_FLOAT_MIN >= t )
		{
			return False;
		}

		if( pPos != NULL )
		{
			*pPos = ( rayPos + ( rayDir * t ) );
		}

		return True;
	}

	Boolean IntersectRayOBB( const Mix::Vector3& rayPos, const Mix::Vector3& rayDir, const Mix::Geometry::OBB& obb )
	{
		Mix::Vector3 m = ( rayPos + rayDir ) * 0.5f;
		Mix::Vector3 d = ( rayDir - m );

		m = ( m - obb.center );
		m = Mix::Vector3( Mix::Vector3::Dot( obb.axis[0], m ), Mix::Vector3::Dot( obb.axis[1], m ), Mix::Vector3::Dot( obb.axis[2], m ) );
		d = Mix::Vector3( Mix::Vector3::Dot( obb.axis[0], d ), Mix::Vector3::Dot( obb.axis[1], d ), Mix::Vector3::Dot( obb.axis[2], d ) );

		Float32 adx = ::fabsf( d.x );
		if( ::fabsf( m.x ) > obb.length.x + adx )
		{
			return False;
		}

		Float32 ady = ::fabsf( d.y );
		if( ::fabsf( m.y ) > obb.length.y + ady )
		{
			return False;
		}

		Float32 adz = ::fabsf( d.z );
		if( ::fabsf( m.z ) > obb.length.z + adz )
		{
			return False;
		}

		adx += MIX_FLOAT_EPSILON;
		ady += MIX_FLOAT_EPSILON;
		adz += MIX_FLOAT_EPSILON;
        
		if( ::fabsf( m.y * d.z - m.z * d.y ) > obb.length.y * adz + obb.length.z * ady )
		{
			return False;
		}

		if( ::fabsf( m.z * d.x - m.x * d.z ) > obb.length.x * adz + obb.length.z * adx )
		{
			return False;
		}

		if( ::fabsf( m.x * d.y - m.y * d.x ) > obb.length.x * ady + obb.length.y * adx )
		{
			return False;
		}

		return True;
	}

	Boolean IntersectRayAABB( const Mix::Vector3& rayPos, const Mix::Vector3& rayDir, const Mix::Geometry::AABB& aabb, Float32* pDist, Mix::Vector3* pPos )
	{
		Int32 i;
		Float32 tmin = 0.0f;
		Float32 tmax = 10000.0f;

		for( i = 0; i < 3; i++ )
		{
			if( ::fabs( rayDir.data[i] ) < MIX_FLOAT_EPSILON )
			{
				if( ( rayPos.data[i] < aabb.min.data[i] ) ||
					( rayPos.data[i] > aabb.max.data[i] ) )
				{
					return False;
				}
			}
			else
			{
				Float32 ood = ( 1.0f / rayDir.data[i] );
				Float32 t1 = ( ( aabb.min.data[i] - rayPos.data[i] ) * ood );
				Float32 t2 = ( ( aabb.max.data[i] - rayPos.data[i] ) * ood );

				if( t1 > t2 )
				{
					Float32 t = t1;
					t1 = t2;
					t2 = t;
				}

				if( t1 > tmin )
				{
					tmin = t1;
				}

				if( t2 > tmax )
				{
					tmax = t2;
				}

				if( tmin > tmax )
				{
					return False;
				}
			}
		}

		if( pDist != NULL )
		{
			*pDist = tmin;
		}

		if( pPos != NULL )
		{
			*pPos = ( rayPos + ( rayDir * tmin ) );
		}

		return True;
	}

	Boolean IntersectSegmentSphere( const Mix::Vector3& p1, const Mix::Vector3& p2, const Mix::Geometry::Sphere& sphere )
	{
		Mix::Vector3 v = ( p2 - p1 );
		Mix::Vector3 c = ( sphere.center - p1 );
		Float32 d = Mix::Vector3::Dot( v, c );

		if( d < MIX_FLOAT_EPSILON )
		{
			return ( sphere.radius >= c.GetLength() );
		}

		Float32 r2 = ( sphere.radius * sphere.radius );

		if( v.GetLengthSqr() < d )
		{
			Mix::Vector3 ce = ( sphere.center - p2 );
			return ( r2 > ce.GetLengthSqr() );
		}

		Float32 ce2 = ( c.GetLengthSqr() - d / v.GetLengthSqr() );
		if( r2 > ce2 )
		{
			return True;
		}

		return False;
	}

	Boolean IntersectSegmentPlane( const Mix::Vector3& p1, const Mix::Vector3& p2, const Mix::Geometry::Plane& plane, Float32* pDist, Mix::Vector3* pPos )
	{
		Mix::Vector3 ab = ( p2 - p1 );
		Float32 t = ( ( plane.d - Mix::Vector3::Dot( plane.normal, p1 ) ) / Mix::Vector3::Dot( plane.normal, ab ) );

		if( pDist != NULL )
		{
			*pDist = t;
		}

		if( ( t < MIX_FLOAT_EPSILON ) ||
			( t > 1.0f ) )
		{
			return False;
		}

		if( pPos != NULL )
		{
			*pPos = ( p1 + ( ab * t ) );
		}

		return True;
	}

	Boolean IntersectSegmentOBB( const Mix::Vector3& p1, const Mix::Vector3& p2, const Mix::Geometry::OBB& obb, Float32* pDist, Mix::Vector3* pPos )
	{
		return False;
	}

	Boolean IntersectSegmentAABB( const Mix::Vector3& p1, const Mix::Vector3& p2, const Mix::Geometry::AABB& aabb )
	{
		Mix::Vector3 e = ( aabb.max - aabb.min );
		Mix::Vector3 d = ( p2 - p1 );
		Mix::Vector3 m = ( p1 + p2 - aabb.min - aabb.max );

		Float32 adx = ::fabs( d.x );
		if( ::fabs( m.x ) > ( e.x + adx ) )
		{
			return False;
		}

		Float32 ady = ::fabs( d.y );
		if( ::fabs( m.y ) > ( e.y + ady ) )
		{
			return False;
		}

		Float32 adz = ::fabs( d.z );
		if( ::fabs( m.z ) > ( e.z + adz ) )
		{
			return False;
		}

		adx += MIX_FLOAT_EPSILON;
		ady += MIX_FLOAT_EPSILON;
		adz += MIX_FLOAT_EPSILON;

		if( ::fabs( m.y * d.z - m.z * d.y ) > ( e.y * adz * e.z * ady ) )
		{
			return False;
		}

		if( ::fabs( m.z * d.x - m.x * d.z ) > ( e.x * adz * e.z * adx ) )
		{
			return False;
		}

		if( ::fabs( m.x * d.y - m.y * d.x ) > ( e.x * ady * e.y * adx ) )
		{
			return False;
		}

		return True;
	}

}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Graphics
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mix{ namespace Graphics{

	static HMODULE g_hD3DCompiler = NULL;

	Mix::Graphics::IManager* GetManagerPtr( void )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );
		return Mix::GetInternalEnginePtr()->GetGraphicsManagerPtr();
	}

	Boolean GetManager( Mix::Graphics::IManager** ppManager )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );

		Mix::Graphics::IManager* pManager = Mix::GetInternalEnginePtr()->GetGraphicsManagerPtr();

		if( pManager != NULL )
		{
			MIX_ADD_REF( pManager );
			( *ppManager ) = pManager;
		}
		else
		{
			return False;
		}

		return True;
	}

}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Graphics::Utility
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mix{ namespace Graphics{ namespace Utility{

	Boolean CompileShader(	const wchar_t* pFilePath,
							const void* pSrc, UInt32 srcSize,
							Mix::Graphics::SHADER_MACRO* pMacros,
							const char* pFuncName,
							Mix::Graphics::SHADER_TARGET target,
							Mix::Memory::IBuffer** ppBuffer )
	{
		if( g_hD3DCompiler == NULL )
		{
			return False;
		}

		void* pProcAddr = ::GetProcAddress( g_hD3DCompiler, "D3DCompile" );
		if( pProcAddr == NULL )
		{
			return False;
		}

		UInt32 compileFlags = D3D10_SHADER_OPTIMIZATION_LEVEL3 | D3D10_SHADER_PACK_MATRIX_COLUMN_MAJOR | D3D10_SHADER_ENABLE_STRICTNESS;

		pD3DCompile CompileShader = static_cast<pD3DCompile>( pProcAddr );

		Mix::STL::Vector<Mix::Memory::SECTION_GRAPHICS, D3D10_SHADER_MACRO> d3dMacros;

		ID3D10Blob* pShaderBuffer = NULL;
		ID3D10Blob* pShaderError = NULL;

		Mix::Memory::IBuffer* pDst = NULL;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// マクロリストの作成
		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( pMacros != NULL )
		{
			D3D10_SHADER_MACRO temp;

			for( UInt32 i = 0; ( ( pMacros[i].pNameA != NULL ) && ( pMacros[i].pDefA != NULL ) ); i++ )
			{
				temp.Name = pMacros[i].pNameA;
				temp.Definition = pMacros[i].pDefA;
				d3dMacros.push_back( temp );
			}

			temp.Name = NULL;
			temp.Definition = NULL;
			d3dMacros.push_back( temp );
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// コンパイル
		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( CompileShader(	pSrc,
							srcSize,
							NULL,
							( d3dMacros.size() > 0 )? &( d3dMacros[0] ) : NULL,
							NULL,
							pFuncName,
							Mix::Graphics::SHADER_TARGET_TABLE[target],
							compileFlags,
							0,
							&pShaderBuffer,
							&pShaderError ) != S_OK )
		{
			Mix::StringW errMsg = ( pShaderError != NULL )? reinterpret_cast<char*>( pShaderError->GetBufferPointer() ) : "???";

			MIX_LOG_ERROR( L"D3DCompile %s : %s", Mix::STR_RETERROR, errMsg.GetConstPtr() );

			MIX_RELEASE( pShaderBuffer );
			MIX_RELEASE( pShaderError );

			return False;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// バッファを作成してコピー
		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( Mix::Memory::CreateBuffer( Mix::Memory::SECTION_GRAPHICS, pShaderBuffer->GetBufferSize(), pShaderBuffer->GetBufferPointer(), &pDst ) == False )
		{
			MIX_LOG_ERROR( L"%s : Size[%dByte]", Mix::STR_OUTOFMEMORY, pShaderBuffer->GetBufferSize() );

			MIX_RELEASE( pShaderBuffer );
			MIX_RELEASE( pShaderError );

			return False;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 後処理
		////////////////////////////////////////////////////////////////////////////////////////////////////

		MIX_RELEASE( pShaderBuffer );
		MIX_RELEASE( pShaderError );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 譲渡
		////////////////////////////////////////////////////////////////////////////////////////////////////

		( *ppBuffer ) = pDst;

		return True;
	}

	Boolean CompileShaderFromFile(	const wchar_t* pFilePath,
									Mix::Graphics::SHADER_MACRO* pMacros,
									const char* pFuncName,
									Mix::Graphics::SHADER_TARGET target,
									Mix::Memory::IBuffer** ppBuffer )
	{
		if( ( pFilePath == NULL ) || ( wcslen( pFilePath ) == 0 ) ||
			( pFuncName == NULL ) || ( strlen( pFuncName ) == 0 ) ||
			( ppBuffer == NULL ) )
		{
			return False;
		}

		Mix::IO::IManager* pFileMgr = Mix::IO::GetManagerPtr();
		Mix::Memory::IBuffer* pSrcBuffer = NULL;

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

		if( pFileMgr->CreateBufferFromFile( pFilePath, &pSrcBuffer ) == False )
		{
			return False;
		}

		if( CompileShader(	pFilePath,
							pSrcBuffer->GetConstPointer(),
							MIX_UIT_TO_UI32( pSrcBuffer->GetSize() ),
							pMacros,
							pFuncName,
							target,
							ppBuffer ) == False )
		{
			MIX_RELEASE( pSrcBuffer );
			return False;
		}

		MIX_RELEASE( pSrcBuffer );

		return True;
	}

	Boolean CompileShaderFromMemory(	const wchar_t* pFilePath,
										const void* pSrc, UInt32 srcSize,
										Mix::Graphics::SHADER_MACRO* pMacros,
										const char* pFuncName,
										Mix::Graphics::SHADER_TARGET target,
										Mix::Memory::IBuffer** ppBuffer )
	{
		if( ( pFilePath == NULL ) || ( wcslen( pFilePath ) == 0 ) ||
			( pFuncName == NULL ) || ( strlen( pFuncName ) == 0 ) ||
			( pSrc == NULL ) || ( srcSize == 0 ) ||
			( ppBuffer == NULL ) )
		{
			return False;
		}

		if( CompileShader(	pFilePath,
							pSrc,
							srcSize,
							pMacros,
							pFuncName,
							target,
							ppBuffer ) == False )
		{
			return False;
		}

		return True;
	}

	Mix::Point MeasureString( Mix::Graphics::Utility::IFont* pFont, const wchar_t* pStr )
	{
		if( ( Mix::Graphics::GetInternalManagerPtr() == NULL ) ||
			( pFont == NULL ) ||
			( pStr == NULL ) ||
			( ::wcslen( pStr ) == 0 ) )
		{
			return Mix::Point::Zero();
		}

		return Mix::Graphics::GetInternalManagerPtr()->GetTextPrinterPtr()->Measure( pFont, pStr );
	}
}}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Sound
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mix{ namespace Sound{

	Mix::Sound::IManager* GetManagerPtr( void )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );
		return Mix::GetInternalEnginePtr()->GetSoundManagerPtr();
	}

	Boolean GetManager( Mix::Sound::IManager** ppManager )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );

		Mix::Sound::IManager* pManager = Mix::GetInternalEnginePtr()->GetSoundManagerPtr();

		if( pManager != NULL )
		{
			MIX_ADD_REF( pManager );
			( *ppManager ) = pManager;
		}
		else
		{
			return False;
		}

		return True;
	}

}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Dynamics
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mix{ namespace Dynamics{

	Mix::Dynamics::IManager* GetManagerPtr( void )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );
		return Mix::GetInternalEnginePtr()->GetDynamicsManagerPtr();
	}

	Boolean GetManager( Mix::Dynamics::IManager** ppManager )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );

		Mix::Dynamics::IManager* pManager = Mix::GetInternalEnginePtr()->GetDynamicsManagerPtr();

		if( pManager != NULL )
		{
			MIX_ADD_REF( pManager );
			( *ppManager ) = pManager;
		}
		else
		{
			return False;
		}

		return True;
	}

	Boolean TestRay( const Mix::Vector3& rayFrom, const Mix::Vector3& rayTo, Mix::Dynamics::IObject* pReceiveObject, Mix::Dynamics::TEST_LOCAL_RESULT& result )
	{
		static const wchar_t* FAILED_TEST = L"レイの交差判定に失敗";

		if( pReceiveObject == NULL )
		{
			MIX_LOG_ERROR( L"%s : %s : pReceiveObject[%s]",
				FAILED_TEST,
				Mix::STR_ILLEGALARG,
				( pReceiveObject != NULL )? L"○" : L"NULL" );

			return False;
		}

		Mix::Dynamics::Object* pInternalObject = dynamic_cast<Mix::Dynamics::Object*>( pReceiveObject );
		MIX_ASSERT_EX( pInternalObject != NULL, L"%s : 内部オブジェクトへキャストできませんでした", FAILED_TEST );

		btVector3 from = ToBulletVector3( rayFrom );
		btVector3 to = ToBulletVector3( rayTo );

		btCollisionObject* pCollObj = pInternalObject->Bullet_GetCollisionObjectPtr();
		btTransform collObjTr( ToBulletQuaternion( pReceiveObject->GetWorldRotation() ), ToBulletVector3( pReceiveObject->GetWorldPosition() ) );

		btCollisionWorld::ClosestRayResultCallback resultCallback( from, to );

		btCollisionWorld::rayTestSingle(
			btTransform( btQuaternion::getIdentity(), from ),
			btTransform( btQuaternion::getIdentity(), to ),
			NULL,
			pCollObj->getCollisionShape(),
			pCollObj->getWorldTransform(),
			resultCallback );

		if( resultCallback.hasHit() == true )
		{
			result.pos = ToMixVector3( resultCallback.m_hitPointWorld );
			result.normal = ToMixVector3( resultCallback.m_hitNormalWorld );
		}
		else
		{
			return False;
		}

		return True;
	}

	Boolean TestSweep(	const Mix::Dynamics::IShape* pCastShape,
						const Mix::Vector3& castShapeFromPos,
						const Mix::Vector3& castShapeToPos,
						const Mix::Dynamics::IObject* pReceiveObject,
						Mix::Dynamics::TEST_LOCAL_RESULT& result )
	{
		return TestSweep(	pCastShape,
							Mix::Quaternion::Identity(), castShapeFromPos,
							Mix::Quaternion::Identity(), castShapeToPos,
							pReceiveObject,
							result );
	}

	Boolean TestSweep(	const Mix::Dynamics::IShape* pCastShape,
						const Mix::Quaternion& castShapeFromRot, const Mix::Vector3& castShapeFromPos,
						const Mix::Quaternion& castShapeToRot, const Mix::Vector3& castShapeToPos,
						const Mix::Dynamics::IObject* pReceiveObject,
						Mix::Dynamics::TEST_LOCAL_RESULT& result )
	{
		static const wchar_t* FAILED_TEST = L"スィープの交差判定に失敗";

		if( ( pCastShape == NULL ) ||
			( pReceiveObject == NULL ) )
		{
			MIX_LOG_ERROR( L"%s : %s : pCastShape[%s] pReceiveObject[%s]",
				FAILED_TEST,
				Mix::STR_ILLEGALARG,
				MIX_LOG_PTR( pCastShape ),
				MIX_LOG_PTR( pReceiveObject ) );

			return False;
		}

		if( pCastShape->GetType() == Mix::Dynamics::IShape::COMPOUND )
		{
			MIX_LOG_ERROR( L"%s : キャストシェイプにコンパウンドシェイプを指定することはできません", FAILED_TEST );
			return False;
		}

		const Mix::Dynamics::Shape* pInternalCastShape = dynamic_cast<const Mix::Dynamics::Shape*>( pCastShape );
		const Mix::Dynamics::Object* pInternalReceiveObject = dynamic_cast<const Mix::Dynamics::Object*>( pReceiveObject );
		btCollisionObject* pReceiveCollObject = pInternalReceiveObject->Bullet_GetCollisionObjectPtr();
		btCollisionShape* pReceiveCollShape = pReceiveCollObject->getCollisionShape();

		btVector3 castFromPos = ToBulletVector3( castShapeFromPos );
		btVector3 castToPos = ToBulletVector3( castShapeToPos );
		btTransform castFromTr( ToBulletQuaternion( castShapeFromRot ), castFromPos );
		btTransform castToTr( ToBulletQuaternion( castShapeToRot ), castToPos );
		btTransform receiveTr( ToBulletQuaternion( pReceiveObject->GetWorldRotation() ), ToBulletVector3( pReceiveObject->GetWorldPosition() ) );

		btCollisionWorld::ClosestConvexResultCallback resultCallback( castFromPos, castToPos );

		btCollisionWorld::objectQuerySingle(
							pInternalCastShape->Bullet_GetConvexShapePtr(),
							castFromTr,
							castToTr,
							NULL,
							pReceiveCollShape,
							receiveTr,
							resultCallback,
							0.0f );

		if( resultCallback.hasHit() == true )
		{
			result.pos = ToMixVector3( resultCallback.m_hitPointWorld );
			result.normal = ToMixVector3( resultCallback.m_hitNormalWorld );
		}
		else
		{
			return False;
		}

		return True;
	}

}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Scene
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mix{ namespace Scene{

	// ブラー構造体 //

	static const Int32 BLUR_FP_RES_I = 10000;
	static const Float32 BLUR_FP_RES_F = 10000.0f;
	static const Float32 BLUR_FP_RES_F_INV = 0.0001f;

	BLUR::BLUR( void ) :
	type( Mix::Scene::BLUR::T_NONE ),
	data( 0 )
	{
	}

	BLUR::TYPE BLUR::GetType( void ) const
	{
		return type;
	}

	Int32 BLUR::GetIntValue( void ) const
	{
		return data / BLUR_FP_RES_I;
	}

	Float32 BLUR::GetFloatValue( void ) const
	{
		return static_cast<Float32>( data ) * BLUR_FP_RES_F_INV;
	}

	Boolean BLUR::IsValid( void ) const
	{
		return ( type != Mix::Scene::BLUR::T_NONE );
	}

	const Mix::Scene::BLUR& BLUR::NONE( void )
	{
		static const Mix::Scene::BLUR none;
		return none;
	}

	Mix::Scene::BLUR BLUR::KS_3x3( void )
	{
		Mix::Scene::BLUR ret;

		ret.type = Mix::Scene::BLUR::T_KS_3x3;
		ret.data = Mix::Scene::KS_BLUR_MIN_ITERATION * BLUR_FP_RES_I;

		return ret;
	}

	Mix::Scene::BLUR BLUR::KS_3x3( Int32 iteration )
	{
		Mix::Scene::BLUR ret;

		ret.type = Mix::Scene::BLUR::T_KS_3x3;
		ret.data = MIX_CLAMP( iteration, Mix::Scene::KS_BLUR_MIN_ITERATION, Mix::Scene::KS_BLUR_MAX_ITERATION ) * BLUR_FP_RES_I;

		return ret;
	}

	Mix::Scene::BLUR BLUR::KS_5x5( void )
	{
		Mix::Scene::BLUR ret;

		ret.type = Mix::Scene::BLUR::T_KS_5x5;
		ret.data = Mix::Scene::KS_BLUR_MIN_ITERATION * BLUR_FP_RES_I;

		return ret;
	}

	Mix::Scene::BLUR BLUR::KS_5x5( Int32 iteration )
	{
		Mix::Scene::BLUR ret;

		ret.type = Mix::Scene::BLUR::T_KS_5x5;
		ret.data = MIX_CLAMP( iteration, Mix::Scene::KS_BLUR_MIN_ITERATION, Mix::Scene::KS_BLUR_MAX_ITERATION ) * BLUR_FP_RES_I;

		return ret;
	}

	Mix::Scene::BLUR BLUR::GAUSSIAN( void )
	{
		Mix::Scene::BLUR ret;

		ret.type = Mix::Scene::BLUR::T_GAUSSIAN;
		ret.data = static_cast<Int32>( Mix::Scene::GAUSSIAN_BLUR_MIN_DISPERSION * BLUR_FP_RES_F );

		return ret;
	}

	Mix::Scene::BLUR BLUR::GAUSSIAN( Float32 dispersion )
	{
		Mix::Scene::BLUR ret;

		ret.type = Mix::Scene::BLUR::T_GAUSSIAN;
		ret.data = static_cast<Int32>( MIX_CLAMP( dispersion, Mix::Scene::GAUSSIAN_BLUR_MIN_DISPERSION, Mix::Scene::GAUSSIAN_BLUR_MAX_DISPERSION ) * BLUR_FP_RES_F );

		return ret;
	}

	Mix::Scene::BLUR BLUR::GAUSSIAN_EX( void )
	{
		Mix::Scene::BLUR ret;

		ret.type = Mix::Scene::BLUR::T_GAUSSIAN_EX;
		ret.data = Mix::Scene::GAUSSIAN_BLUR_EX_MIN_RADIUS * BLUR_FP_RES_I;

		return ret;
	}

	Mix::Scene::BLUR BLUR::GAUSSIAN_EX( Int32 radius )
	{
		Mix::Scene::BLUR ret;

		ret.type = Mix::Scene::BLUR::T_GAUSSIAN_EX;
		ret.data = MIX_CLAMP( radius, Mix::Scene::GAUSSIAN_BLUR_EX_MIN_RADIUS, Mix::Scene::GAUSSIAN_BLUR_EX_MAX_RADIUS ) * BLUR_FP_RES_I;

		return ret;
	}

	// モーションハンドル構造体 //

	MOTION_HANDLE::MOTION_HANDLE( void ) :
	ref0( NULL ),
	ref1( NULL )
	{
	}

	MOTION_HANDLE::MOTION_HANDLE( Int32 value ) :
	ref0( NULL ),
	ref1( NULL )
	{
	}

	MOTION_HANDLE::MOTION_HANDLE( const MOTION_HANDLE& handle ) :
	ref0( handle.ref0 ),
	ref1( handle.ref1 )
	{
	}

	MOTION_HANDLE::MOTION_HANDLE( const void* r0, const void* r1 ) :
	ref0( r0 ),
	ref1( r1 )
	{
	}

	MOTION_HANDLE& MOTION_HANDLE::operator = ( Int32 value )
	{
		*this = MOTION_HANDLE();

		return *this;
	}

	MOTION_HANDLE& MOTION_HANDLE::operator = ( const MOTION_HANDLE& handle )
	{
		ref0 = handle.ref0;
		ref1 = handle.ref1;

		return *this;
	}

	Boolean MOTION_HANDLE::operator == ( Int32 value ) const
	{
		if( ( ref0 != NULL ) ||
			( ref1 != NULL ) )
		{
			return False;
		}

		return True;
	}

	Boolean MOTION_HANDLE::operator != ( Int32 value ) const
	{
		if( ( ref0 != NULL ) ||
			( ref1 != NULL ) )
		{
			return True;
		}

		return False;
	}

	Boolean MOTION_HANDLE::operator != ( const MOTION_HANDLE& handle ) const
	{
		if( ( ref0 != handle.ref0 ) ||
			( ref1 != handle.ref1 ) )
		{
			return True;
		}

		return False;
	}

	Boolean MOTION_HANDLE::operator == ( const MOTION_HANDLE& handle ) const
	{
		if( ( ref0 != handle.ref0 ) ||
			( ref1 != handle.ref1 ) )
		{
			return False;
		}

		return True;
	}

	bool MOTION_HANDLE::operator < ( const MOTION_HANDLE& handle ) const
	{
		if( ref0 < handle.ref0 )
		{
			return true;
		}
		else if( ref0 > handle.ref0 )
		{
			return false;
		}

		if( ref1 < handle.ref1 )
		{
			return true;
		}
		else if( ref1 > handle.ref1 )
		{
			return false;
		}

		return false;
	}

	// 関数 //

	Mix::Scene::IManager* GetManagerPtr( void )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );
		return Mix::GetInternalEnginePtr()->GetSceneManagerPtr();
	}

	Boolean GetManager( Mix::Scene::IManager** ppManager )
	{
		MIX_ASSERT( Mix::GetInternalEnginePtr() != NULL );

		Mix::Scene::IManager* pManager = Mix::GetInternalEnginePtr()->GetSceneManagerPtr();

		if( pManager != NULL )
		{
			MIX_ADD_REF( pManager );
			( *ppManager ) = pManager;
		}
		else
		{
			return False;
		}

		return True;
	}

}}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix
////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mix{

	static Boolean g_bInitialize		= False; //初期化している場合は True
	static Boolean g_bComInitialize		= False; //COMを初期化している場合は True
	static Boolean g_bTimeBeginPeriod	= False; //Sleepの制度を上げた( timeBeginPeriod )場合は True

	// デバッグ : 型の変換

#ifdef _DEBUG

	// IntT → Int

	Int8 IntT_ToInt8( IntT value ) 
	{
		MIX_ASSERT( ( SCHAR_MIN <= value ) && ( SCHAR_MAX >= value ) );
		return static_cast<Int8>( value );
	}

	Int16 IntT_ToInt16( IntT value )
	{
		MIX_ASSERT( ( SHRT_MIN <= value ) && ( SHRT_MAX >= value ) );
		return static_cast<Int16>( value );
	}

#ifdef _WIN64
	Int32 IntT_ToInt32( IntT value )
	{
		MIX_ASSERT( ( INT_MIN <= value ) && ( INT_MAX >= value ) );
		return static_cast<Int32>( value );
	}
#else //_WIN64
	IntT Int64_ToIntT( Int64 value )
	{
		MIX_ASSERT( ( INT_MIN <= value ) && ( INT_MAX >= value ) );
		return static_cast<IntT>( value );
	}
#endif //_WIN64

	// IntT → UInt

	UInt8 IntT_ToUInt8( IntT value )
	{
		MIX_ASSERT( ( 0 <= value ) && ( UCHAR_MAX >= value ) );
		return static_cast<UInt8>( value );
	}

	UInt16 IntT_ToUInt16( IntT value )
	{
		MIX_ASSERT( ( 0 <= value ) && ( USHRT_MAX >= value ) );
		return static_cast<UInt16>( value );
	}

	UInt32 IntT_ToUInt32( IntT value )
	{
		MIX_ASSERT( ( 0 <= value ) && ( UINT_MAX >= value ) );
		return static_cast<UInt32>( value );
	}

	// UIntT → UInt

	UInt8 UIntT_ToUInt8( UIntT value )
	{
		MIX_ASSERT( UCHAR_MAX >= value );
		return static_cast<UInt8>( value );
	}

	UInt16 UIntT_ToUInt16( UIntT value )
	{
		MIX_ASSERT( USHRT_MAX >= value );
		return static_cast<UInt16>( value );
	}

#ifdef _WIN64
	UInt32 UIntT_ToUInt32( UIntT value )
	{
		MIX_ASSERT( UINT_MAX >= value );
		return static_cast<UInt32>( value );
	}
#else //_WIN64
	UIntT UInt64_ToUIntT( UInt64 value )
	{
		MIX_ASSERT( UINT_MAX >= value );
		return static_cast<UIntT>( value );
	}
#endif //_WIN64

	// UIntT → Int

	Int8 UIntT_ToInt8( UIntT value )
	{
		MIX_ASSERT( CHAR_MAX >= value );
		return static_cast<Int8>( value );
	}

	Int16 UIntT_ToInt16( UIntT value )
	{
		MIX_ASSERT( SHRT_MAX >= value );
		return static_cast<Int16>( value );
	}

	Int32 UIntT_ToInt32( UIntT value )
	{
		MIX_ASSERT( INT_MAX >= value );
		return static_cast<Int32>( value );
	}

#endif //_DEBUG

	Boolean Initialize( const Mix::ENGINE_CONFIG& config )
	{
		if( g_bInitialize == True )
		{
			::MessageBox( ::GetDesktopWindow(), L"Mix::Initialize : すでに初期化されています", L"エラー", MB_OK | MB_ICONSTOP );
			Mix::Finalize();
			return False;
		}

		Mix::UserFile sysReport;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// メモリリークの検出を初期化
		////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef _DEBUG
		::_CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF );
#endif //_DEBUG

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// システムレポートを初期化
		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( sysReport.Initialize( ( config.pUserDirectoryPath != NULL )? config.pUserDirectoryPath : Mix::DEF_USERDIRECTORYNAME, Mix::SYSTEM_FILENAME ) == False )
		{
			::MessageBox( ::GetDesktopWindow(), L"システムレポートの初期化に失敗しました", L"エラー", MB_OK | MB_ICONSTOP );
			Mix::Finalize();
			return False;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// オペレーティングシステムの確認
		////////////////////////////////////////////////////////////////////////////////////////////////////

		OSVERSIONINFOEX osex;
		DWORDLONG osCondMask;

		Mix::Memory::Zero( &osex, sizeof( OSVERSIONINFOEX ) );

		osex.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
		osex.dwMajorVersion = 6; // Windows Vista 以降
		osex.dwMinorVersion = 0;
		osex.dwBuildNumber = 0;
		osex.dwPlatformId = 0;
		osex.szCSDVersion[0] = L'\0';
		osex.wServicePackMajor = 0;
		osex.wServicePackMinor = 0;
		osex.wSuiteMask = 0;
		osex.wProductType = VER_NT_WORKSTATION;
		osex.wReserved;

		osCondMask = 0;

		VER_SET_CONDITION( osCondMask, VER_MAJORVERSION, VER_GREATER_EQUAL );
		VER_SET_CONDITION( osCondMask, VER_MINORVERSION, VER_GREATER_EQUAL );
		VER_SET_CONDITION( osCondMask, VER_PRODUCT_TYPE, VER_GREATER_EQUAL );

		if( ::VerifyVersionInfo( &osex, VER_MAJORVERSION | VER_MINORVERSION | VER_PRODUCT_TYPE, osCondMask ) == FALSE )
		{
			::MessageBox( ::GetDesktopWindow(), L"サポート対象外のオペレーティングシステムを使用しています", L"エラー", MB_OK | MB_ICONSTOP );
			Mix::Finalize();
			return False;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 高分解能パフォーマンスカウンタが使用できるかチェック
		////////////////////////////////////////////////////////////////////////////////////////////////////

		LARGE_INTEGER liDammy;

		if( ::QueryPerformanceCounter( &liDammy ) == FALSE )
		{
			::MessageBox( ::GetDesktopWindow(), L"高性能分解パフォーマンスカウンタを使用することができません", L"エラー", MB_OK | MB_ICONSTOP );
			Mix::Finalize();
			return False;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// COMを初期化
		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( SUCCEEDED( ::CoInitializeEx( NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE ) ) )
		{
			g_bComInitialize = True;
		}
		else
		{
			::MessageBox( ::GetDesktopWindow(), L"COM の初期化に失敗しました", L"エラー", MB_OK | MB_ICONSTOP );
			Mix::Finalize();
			return False;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// タイマー制度をあげる
		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( ::timeBeginPeriod( 1 ) == TIMERR_NOERROR )
		{
			g_bTimeBeginPeriod = True;
		}
		else
		{
			::MessageBox( ::GetDesktopWindow(), L"最小タイマ分解能の設定に失敗しました", L"エラー", MB_OK | MB_ICONSTOP );
			Mix::Finalize();
			return False;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 乱数の初期化
		////////////////////////////////////////////////////////////////////////////////////////////////////
	
		Mix::InitRand();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// ロガーを作成
		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( Mix::Logger::CreateInstance( ( config.pUserDirectoryPath != NULL )? config.pUserDirectoryPath : Mix::DEF_USERDIRECTORYNAME, Mix::LOG_FILENAME ) == False )
		{
			::MessageBox( ::GetDesktopWindow(), L"ロガーの作成に失敗しました", L"エラー", MB_OK | MB_ICONSTOP );
			Mix::Finalize();
			return False;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// モジュールの読み込み
		////////////////////////////////////////////////////////////////////////////////////////////////////

		// D3DCompiler
		Mix::Graphics::g_hD3DCompiler = ::LoadLibrary( D3DCOMPILER_DLL_W );
		if( Mix::Graphics::g_hD3DCompiler == NULL )
		{
			MIX_LOG_INFO( L"\"" D3DCOMPILER_DLL_W L"\" が存在しないため、シェーダーのコンパイルはできません。" );
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// エンジンを作成
		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( Mix::Engine::CreateInstance( config, &sysReport ) == False )
		{
			::MessageBox( ::GetDesktopWindow(), L"エンジンの作成に失敗しました", L"エラー", MB_OK | MB_ICONSTOP );
			Mix::Finalize();
			return False;
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 初期化済
		////////////////////////////////////////////////////////////////////////////////////////////////////

		g_bInitialize = True;

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

		return True;
	}

	void Mix::Finalize( void )
	{
		//エンジンを解放
		Mix::Engine::ReleaseInstance();

		//モジュールの解放( D3DCompiler )
		if( Mix::Graphics::g_hD3DCompiler != NULL )
		{
			::FreeLibrary( Mix::Graphics::g_hD3DCompiler );
			Mix::Graphics::g_hD3DCompiler = NULL;
		}

		//ロガーを解放
		Mix::Logger::ReleaseInstance();

		//タイマー制度を戻す
		if( g_bTimeBeginPeriod == True )
		{
			::timeEndPeriod( 1 );
			g_bTimeBeginPeriod = False;
		}

		//COMを終了
		if( g_bComInitialize == True )
		{
			::CoUninitialize();
			g_bComInitialize = False;
		}

		//未初期化
		g_bInitialize = False;
	}

	/*
		インスタンスのハンドル
	*/

	HINSTANCE GetInstanceHandle( void )
	{
		return GetModuleHandle( NULL );
	}

	/*
		エンジンの取得
	*/

	Mix::IEngine* GetEnginePtr( void )
	{
		return Mix::Engine::GetInstance();
	}

	Boolean GetEngine( Mix::IEngine** ppEngine )
	{
		Mix::Engine* pEngine = Mix::Engine::GetInstance();

		if( pEngine != NULL )
		{
			MIX_ADD_REF( pEngine );
			( *ppEngine ) = pEngine;
		}
		else
		{
			return False;
		}

		return True;
	}

	/*
		符号の取得
	*/

	Int32 Sign( Int32 value )
	{
		return ( value >= 0 )? +1 : -1;
	}

	Float32 SignF( Float32 value )
	{
		return ( value >= 0.0f )? +1.0f : -1.0f;
	}

	/*
		浮動小数点の平方根
	*/

	Float32 SqrtF( const Float32& value )
	{
		Float32 xHalf = 0.5f * value;
		Int32 tmp = 0x5F3759DF - ( *(Int32*)&value >> 1 ); //initial guess
		Float32 xRes  = *( Float32* )&tmp;

		xRes *= ( 1.5f - ( xHalf * xRes * xRes ) );
		//xRes *= ( 1.5f - ( xHalf * xRes * xRes ) );//コメントアウトを外すと精度が上がる

		return xRes * value;
	}

	/*
		浮動小数点の逆数
	*/

	Float32 InvF( Float32 value )
	{
		UInt32* i = ( UInt32* )&value;

//		*i = 0x7F000000 - *i;
		*i = 0x7EEEEEEE - *i;

		return value;
	}

	/*
		平方根の逆数
	*/

	Float32 InvSqrtF( Float32 value )
	{
		Float32 x2 = value * 0.5f;
		Float32 y = value;
		Long32 i = *( Long32* )&y;

		i = 0x5F3759DF - ( i >> 1 );
		y = *( Float32* )&i;
		y = y * ( 1.5f - ( x2 * y * y ) );

		return y;
	}

	/*
		乱数
	*/

	static sfmt_t g_SFMT;

	void InitRand( void )
	{
		::sfmt_init_gen_rand( &g_SFMT, static_cast<uint32_t>( ::time( NULL ) ) );
	}

	void InitRand( UInt32 seed )
	{
		::sfmt_init_gen_rand( &g_SFMT, seed );
	}

	void InitRand( UInt32* seeds, UInt32 numSeed )
	{
		::sfmt_init_by_array( &g_SFMT, seeds, static_cast<int>( numSeed ) );
	}

	UInt32 Rand( void )
	{
		return ::sfmt_genrand_uint32( &g_SFMT );
	}

	UInt32 Rand( Int32 maxRnd )
	{
		return Mix::Rand() % maxRnd;
	}

	UInt32 Rand( UInt32 r0, UInt32 r1 )
	{
		if( r0 == r1 )
		{
			return r0;
		}

		UInt32 minRnd;
		UInt32 maxRnd;

		if( r0 < r1 )
		{
			minRnd = r0;
			maxRnd = r1;
		}
		else
		{
			minRnd = r1;
			maxRnd = r0;
		}

		return minRnd + Mix::Rand() * ( maxRnd - minRnd );
	}

	Float32 RandF( void )
	{
		#define RND_INNER_LOOP() \
			if( coinFlips & 1 ) \
			{ \
				break; \
			} \
			coinFlips >>= 1; \
			ret -= 0x800000;

		UInt32 ret = 0x3F000000 | ( 0x7FFFFF & ( ( rand() << 8 ) ^ rand() ) );
		UInt16 coinFlips;

		for( ;; )
		{
			coinFlips = Mix::Rand();

			RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();

			if( ( ret & 0x3F800000 ) == 0  )
			{
				return 0.0f;
			}

			RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
			RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
			RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
			RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
		}

		return *( ( Float32* )( &ret ) );
	}

	Float32 RandF( Float32 maxRnd )
	{
		return Mix::RandF() * maxRnd;
	}

	Float32 RandF( Float32 r0, Float32 r1 )
	{
		if( r0 == r1 )
		{
			return r0;
		}

		Float32 minRnd;
		Float32 maxRnd;

		if( r0 < r1 )
		{
			minRnd = r0;
			maxRnd = r1;
		}
		else
		{
			minRnd = r1;
			maxRnd = r0;
		}

		return minRnd + Mix::RandF() * ( maxRnd - minRnd );
	}

	/*
		浮動小数点の補間
	*/

	Float32 LerpF( Float32 a, Float32 b, Float32 t )
	{
		return ( a * ( 1.0f - t ) ) + ( b * t );
	}

	/*
		指定されたベクトルから２本の垂直なベクトルを求める
	*/

	void PlaneSpace( const Mix::Vector3& n, Mix::Vector3& p, Mix::Vector3& q )
	{
		static Float32 SQRT12 = 0.7071067811865475244008443621048490f;

		if( ::fabs( n.z ) > SQRT12 )
		{
			Float32 a = n.y * n.y + n.z * n.z;
			Float32 k = MIX_FLOAT_RECIPROCAL( ::sqrtf( a ) );

			p.x = 0.0f;
			p.y = -n.z * k;
			p.z = n.y * k;

			q.x = a * k;
			q.y = -n.x * p.z;
			q.z = n.x * p.y;
		}
		else
		{
			Float32 a = n.x * n.x + n.y * n.y;
			Float32 k = MIX_FLOAT_RECIPROCAL( ::sqrtf( a ) );

			p.x = -n.y * k;
			p.y = n.x * k;
			p.z = 0.0f;

			q.x = -n.z * p.y;
			q.y = n.z * p.x;
			q.z = a * k;
		}
	}

	/*
		指定された直行する２本のベクトルから最短の回転を求める
	*/

	Mix::Quaternion ShortestArc( const Mix::Vector3& v0, const Mix::Vector3& v1 )
	{
		Mix::Vector3 cv = Mix::Vector3::Cross( v0, v1 );
		Float32 d = Mix::Vector3::Dot( v0, v1 );

		Mix::Quaternion ret;

		if( d < ( -1.0f + MIX_FLOAT_EPSILON ) )
		{
			Mix::Vector3 av;
			Mix::Vector3 dummy;

			Mix::PlaneSpace( v0, av, dummy );

			ret.x = av.x;
			ret.y = av.y;
			ret.z = av.z;
			ret.w = 0.0f;
		}
		else
		{
			Float32 s = ::sqrtf( ( 1.0f + d ) * 2.0f );
			Float32 rs = MIX_FLOAT_RECIPROCAL( s );

			ret.x = cv.x * rs;
			ret.y = cv.y * rs;
			ret.z = cv.z * rs;
			ret.w = s * 0.5f;
		}

		return ret;
	}

	/*
		行列4x4 : ワールド座標をスクリーン座標に変換
	*/

	Mix::Vector3 Project( const Mix::Matrix4x4& viewMat, const Mix::Matrix4x4& projMat, const Mix::Vector3& worldPos, const Mix::Vector2& screenSize )
	{
		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 = viewMat;
		mat *= projMat;

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

		result = unViewport * pos;

		return Mix::Vector3( result.x, result.y, result.z );
	}

	/*
		行列4x4 : スクリーン座標をワールド座標に変換
	*/

	Mix::Vector3 Unproject( const Mix::Matrix4x4& viewMat, const Mix::Matrix4x4& projMat, const Mix::Vector3& screenPos, const Mix::Vector2& screenSize )
	{
		Mix::Matrix4x4 invViewMat;
		Mix::Matrix4x4 invProjMat;
		Mix::Matrix4x4 unViewport;
		Mix::Matrix4x4 temp;

		invViewMat = viewMat.ToInverse();
		invProjMat = 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;
	}
}
