HRESULT ParaEngine::CCCSFaceLoader::Load()
{
	if (CParaFile::DoesFileExist(m_sFileName.c_str(), false))
		return S_OK;

	// check if all textures involved are loaded. 
	for (int i = 0; i < CFS_TOTAL_NUM; ++i)
	{
		FaceTextureComponent& component = m_layers[i];
		if (component.name.empty())
			continue;

		AssetFileEntry* pEntry = CAssetManifest::GetSingleton().GetFile(component.name);
		if (pEntry)
		{
			if (!pEntry->DoesFileExist())
			{
				m_pAssetFileEntry = pEntry;
				return E_PENDING;
			}
		}
	}

#ifdef USE_DIRECTX_RENDERER
	return ComposeWithGDIPlus();
#else
	return S_OK;
#endif
}
Beispiel #2
0
int CParaFile::OpenAssetFile(const char* filename, bool bDownloadIfNotUpToDate, const char* relativePath)
{
	if (relativePath != NULL)
	{
		int nRes = OpenAssetFile(filename, bDownloadIfNotUpToDate);
		if (nRes == 0)
		{
			// try relative path if not exist. 
			char sNewFilename[MAX_PATH * 2];
			CFileUtils::MakeFileNameFromRelativePath(sNewFilename, filename, relativePath);

			nRes = OpenAssetFile(sNewFilename, bDownloadIfNotUpToDate);
		}
		return nRes;
	}
	AssetFileEntry* pEntry = CAssetManifest::GetSingleton().GetFile(filename);
	if (pEntry)
	{
		if (CParaFile::DoesFileExist(filename, false))
		{
			CAsyncLoader::GetSingleton().log(string("ParaFile.OpenAssetFile using disk file:") + filename + "\n");
			if (OpenFile(filename, true, relativePath))
				return 1;
			else
			{
				OUTPUT_LOG("error: failed open disk file: %s\n", filename);
			}
		}

		if (pEntry->DoesFileExist())
		{
			if (m_filename.empty())
				m_filename = filename;
			return OpenFile(pEntry->GetLocalFileName().c_str(), true, relativePath) ? 1 : 0;
		}
		else
		{
			if (!bDownloadIfNotUpToDate)
			{
				return 0;
			}
			else
			{
				// download the file here. 
				if (pEntry->SyncFile())
				{
					// open the file now. 
					if (m_filename.empty())
						m_filename = filename;
					return OpenFile(pEntry->GetLocalFileName().c_str(), true, relativePath) ? 1 : 0;
				}
			}
		}
	}
	else
	{
		CAsyncLoader::GetSingleton().log(string("ParaFile.OpenAssetFile using local file:") + filename + "\n");
#ifdef PARAENGINE_MOBILE
		if (relativePath == NULL)
		{
			uint32 dwFound = FILE_NOT_FOUND;
			// check file existence, then open file will prevent file not found warnings in mobile version. 
			if ((dwFound = CParaFile::DoesFileExist2(filename, FILE_ON_DISK | FILE_ON_ZIP_ARCHIVE | FILE_ON_SEARCH_PATH)))
			{
				return OpenFile(filename, true, relativePath, false, dwFound) ? 1 : 0;
			}
			return 0;
		}
#endif
		return OpenFile(filename, true, relativePath) ? 1 : 0;
	}
	return 0;
}
Beispiel #3
0
CAudioSource2_ptr ParaEngine::CAudioEngine2::Create(const char* sName, const char* sWavePath, bool bStream)
{
	CAudioSource2_ptr pWave;
	AudioFileMap_type::iterator iter = m_audio_file_map.find(sName);
	if (iter!=m_audio_file_map.end())
	{
		pWave = iter->second;
		if(!pWave)
		{
			pWave = new CAudioSource2(sName);
			iter->second = pWave;
		}
		if(pWave->m_pSource)
		{
			pWave->m_pSource->stop();
		}
	}
	else
	{
		pWave = new CAudioSource2(sName);
		m_audio_file_map[sName] = pWave;
	}
	if(m_pAudioEngine == 0)
		return pWave;

	AssetFileEntry* pEntry = CAssetManifest::GetSingleton().GetFile(sWavePath);
	if(pEntry)
	{
		if(pEntry->DoesFileExist())
		{
			// we already downloaded the file, so load it.
			IParaAudioSource* pSource = NULL;
#ifdef PARAENGINE_MOBILE
			// streaming should be disabled since it is too slow on mobile disk. 
			OUTPUT_LOG("streaming audio file %s is disabled since it is too slow on mobile disk\n", pEntry->GetLocalFileName().c_str());
			bStream = false;
#endif
			if(bStream)
			{
				// Since local cache filename does not have file extension, however audio engine needs to have an extension in order to load from file. 
				// so we will create a file with the proper extension in the same directory. 
				std::string filename = pEntry->GetFullFilePath() + "." + CParaFile::GetFileExtension(sWavePath);
				// OUTPUT_LOG("info:streaming audio file from %s\n", filename.c_str());
				if(!CParaFile::DoesFileExist(filename.c_str(), false))
				{
					if(CParaFile::CopyFile(pEntry->GetLocalFileName().c_str(), filename.c_str(), true))
					{
						pSource = m_pAudioEngine->create(sName, filename.c_str(), bStream);
					}
					else
					{
						OUTPUT_LOG("warning: failed to copy audio file from %s to %s\n", pEntry->GetLocalFileName().c_str(), filename.c_str());
					}
				}
				else
				{
					pSource = m_pAudioEngine->create(sName, filename.c_str(), bStream);
				}
			}
			else
			{
				// always load from memory if no streaming is specified. 
				ParaEngine::CParaFile file(pEntry->GetLocalFileName().c_str());
				// OUTPUT_LOG("info:playing in memory audio file from %s\n", pEntry->GetLocalFileName().c_str());

				if(!file.isEof())
				{
					std::string file_extension = CParaFile::GetFileExtension(sWavePath);
					pSource = m_pAudioEngine->createFromMemory(sName, file.getBuffer(), file.getSize(), file_extension.c_str());
				}
				else
				{
					OUTPUT_LOG("warning: failed to open audio file %s\n", pEntry->GetLocalFileName().c_str());
				}
			}
			if(pSource)
			{
				pWave->SetSource(pSource);

				// if there is pending looped sound, we will play it. For non-looping sound that has just finished downloading, we will ignore it. 
				if(pWave->m_bIsAsyncLoadingWhileLoopPlaying)
				{
					pWave->play2d(true);
				}
			}
		}
		else
		{
			CWaveFileDownloadCallBackData2 callBack(sName, sWavePath, bStream);
			// we shall wait for asset completion. 
			pEntry->SyncFile_Async(callBack);
		}
	}
	else
	{
#if !(defined(STATIC_PLUGIN_CAUDIOENGINE)) && !(defined(PARAENGINE_MOBILE) && defined(WIN32))
		if(ParaEngine::CParaFile::DoesFileExist(sWavePath, false))
		{
			IParaAudioSource* pSource = m_pAudioEngine->create(sName, sWavePath, bStream);
			if(pSource)
			{
				pWave->SetSource(pSource);
			}
		}
		else 
#endif
		{
			// currently it will unzip file each time a zipped music is played. We may first check a fixed temp location and play it from there before extracting to it. 
			ParaEngine::CParaFile file(sWavePath);
			if(!file.isEof())
			{
#ifdef PARAENGINE_MOBILE
				OUTPUT_LOG("audio file opened: %s \n", sWavePath);
#endif
				std::string file_extension = CParaFile::GetFileExtension(sWavePath);
				IParaAudioSource* pSource = m_pAudioEngine->createFromMemory(sWavePath, file.getBuffer(), file.getSize(), file_extension.c_str());
				if(pSource)
				{
					pWave->SetSource(pSource);
				}
			}
		}
	}
	return pWave;
}
Beispiel #4
0
HRESULT ParaEngine::CAudioEngine2::PlayWaveFile( const char* sWavePath, bool bLoop, bool bStream/*=false*/, int dwPlayOffset/*=0*/ )
{
	if(!IsValidAndEnabled() || GetGlobalVolume()<=0.f)
		return E_FAIL;
	// check if the wave file is already prepared before
	CAudioSource2_ptr pWave;
	AudioFileMap_type::iterator iter = m_audio_file_map.find(sWavePath);
	if (iter!=m_audio_file_map.end())
	{
		pWave = iter->second;
		if(pWave && pWave->m_pSource)
		{
			if(pWave->m_pSource->isPlaying())
			{
				// already playing, so return. 
#ifdef DEBUG_AUDIO
				OUTPUT_LOG("PlayWaveFile: %s already playing. audio pos: %d, audio time:%f, total size %d, volume %f\n", sWavePath, 
					pWave->m_pSource->getCurrentAudioPosition(), 
					pWave->m_pSource->getCurrentAudioTime(),
					pWave->m_pSource->getTotalAudioSize(),
					pWave->m_pSource->getVolume());
#endif
				return S_OK;
			}
		}
		else
		{
			// it usually means that the music is pending for downloading. 
#ifdef DEBUG_AUDIO
			OUTPUT_LOG("PlayWaveFile: %s pending for download\n", sWavePath);
#endif
			return S_OK;
		}
	}
	else
	{
		// prepare the wave file. 
		bool bSucceed = false;

		AssetFileEntry* pEntry = CAssetManifest::GetSingleton().GetFile(sWavePath);
		if(pEntry)
		{
			if(pEntry->DoesFileExist())
			{
				// we already downloaded the file, so load it.
				IParaAudioSource* pSource = NULL;
				if(bStream)
				{
					// Since local cache filename does not have file extension, however audio engine needs to have an extension in order to load from file. 
					// so we will create a file with the proper extension in the same directory. 
					std::string filename = pEntry->GetFullFilePath() + "." + CParaFile::GetFileExtension(sWavePath);
					if(!CParaFile::DoesFileExist(filename.c_str(), false))
					{
						if(CParaFile::CopyFile(pEntry->GetLocalFileName().c_str(), filename.c_str(), false))
						{
							pSource = m_pAudioEngine->create(sWavePath, filename.c_str(), bStream);
						}
					}
					else
					{
						pSource = m_pAudioEngine->create(sWavePath, filename.c_str(), bStream);
					}
				}
				else
				{
					// always load from memory if no streaming is specified. 
					ParaEngine::CParaFile file(pEntry->GetLocalFileName().c_str());
					if(!file.isEof())
					{
						std::string file_extension = CParaFile::GetFileExtension(sWavePath);
						pSource = m_pAudioEngine->createFromMemory(sWavePath, file.getBuffer(), file.getSize(), file_extension.c_str());
					}
				}
				if(pSource)
				{
					pWave = new CAudioSource2(sWavePath, pSource);
					m_audio_file_map[sWavePath] = pWave;
					bSucceed = true;
				}
			}
			else
			{
				// push to the queue. 
				m_audio_file_map[sWavePath] = CAudioSource2_ptr(new CAudioSource2(sWavePath));
				CWaveFilePlayCallBackData2 callBack(sWavePath, bLoop, bStream);
				// we shall wait for asset completion. 
				pEntry->SyncFile_Async(callBack);
			}
		}
		else
		{
#if !(defined(STATIC_PLUGIN_CAUDIOENGINE)) && !(defined(PARAENGINE_MOBILE) && defined(WIN32))
			if(ParaEngine::CParaFile::DoesFileExist(sWavePath, false))
			{
				IParaAudioSource* pSource = m_pAudioEngine->create(sWavePath, sWavePath, bStream);
				if(pSource)
				{
					pWave = new CAudioSource2(sWavePath, pSource);
					m_audio_file_map[sWavePath] = pWave;
					bSucceed = true;
#ifdef DEBUG_AUDIO
					OUTPUT_LOG("PlayWaveFile: new audio %s prepared \n", sWavePath);
#endif
				}
			}
			else 
#endif
			{
				// currently it will unzip file each time a zipped music is played. We may first check a fixed temp location and play it from there before extracting to it. 
				ParaEngine::CParaFile file(sWavePath);
				if(!file.isEof())
				{
					std::string file_extension = CParaFile::GetFileExtension(sWavePath);
					IParaAudioSource* pSource = m_pAudioEngine->createFromMemory(sWavePath, file.getBuffer(), file.getSize(), file_extension.c_str());
					if(pSource)
					{
						pWave = new CAudioSource2(sWavePath, pSource);
						m_audio_file_map[sWavePath] = pWave;
						bSucceed = true;
					}
				}
			}
		}
		
		if(!bSucceed)
		{
			m_audio_file_map[sWavePath] = CAudioSource2_ptr(new CAudioSource2(sWavePath));
			OUTPUT_LOG("unable to prepare wave file %s\r\n", sWavePath);
			return E_FAIL;
		}
	}
	// play the sound
	if(pWave)
	{
		if( ! (pWave->play2d(bLoop, false)) )
		{
			return E_FAIL;
		}
#ifdef DEBUG_AUDIO
		if(pWave->m_pSource)
		{
			OUTPUT_LOG("PlayWaveFile: play2d is called for %s. audio pos: %d, audio time:%f, total size %d, volume %f\n", sWavePath, 
					pWave->m_pSource->getCurrentAudioPosition(), 
					pWave->m_pSource->getCurrentAudioTime(),
					pWave->m_pSource->getTotalAudioSize(),
					pWave->m_pSource->getVolume());
		}
#endif
	}
	return S_OK;
}
Beispiel #5
0
HRESULT ParaEngine::CAudioEngine2::PrepareWaveFile( CAudioSource2_ptr& pWave, const char* sWavePath, bool bStream )
{
	// prepare the wave file. 
	bool bSucceed = false;

	if(!pWave)
		return E_FAIL;

	if(pWave->GetSource() != NULL )
	{
		OUTPUT_LOG("warning: repeated all to already prepared wave file %s\n", sWavePath);
		return S_OK;
	}

	AssetFileEntry* pEntry = CAssetManifest::GetSingleton().GetFile(sWavePath);
	if(pEntry)
	{
		if(pEntry->DoesFileExist())
		{
			// we already downloaded the file, so load it.
			IParaAudioSource* pSource = NULL;
			if(bStream)
			{
				// Since local cache filename does not have file extension, however audio engine needs to have an extension in order to load from file. 
				// so we will create a file with the proper extension in the same directory. 
				std::string filename = pEntry->GetLocalFileName() + "."+ CParaFile::GetFileExtension(sWavePath);
				if(!CParaFile::DoesFileExist(filename.c_str(), false))
				{
					if(CParaFile::CopyFile(pEntry->GetLocalFileName().c_str(), filename.c_str(), false))
					{
						pSource = m_pAudioEngine->create(sWavePath, filename.c_str(), bStream);
					}
				}
				else
				{
					pSource = m_pAudioEngine->create(sWavePath, filename.c_str(), bStream);
				}
			}
			else
			{
				// always load from memory if no streaming is specified. 
				ParaEngine::CParaFile file(pEntry->GetLocalFileName().c_str());
				if(!file.isEof())
				{
					std::string file_extension = CParaFile::GetFileExtension(sWavePath);
					pSource = m_pAudioEngine->createFromMemory(sWavePath, file.getBuffer(), file.getSize(), file_extension.c_str());
				}
			}
			if(pSource)
			{
				pWave->SetSource(pSource);
				bSucceed = true;
			}
		}
	}
	else
	{
#if !(defined(STATIC_PLUGIN_CAUDIOENGINE)) && !(defined(PARAENGINE_MOBILE) && defined(WIN32))
		if(ParaEngine::CParaFile::DoesFileExist(sWavePath, false))
		{
			IParaAudioSource* pSource = m_pAudioEngine->create(sWavePath, sWavePath, bStream);
			if(pSource)
			{
				pWave->SetSource(pSource);
				bSucceed = true;
			}
		}
		else 
#endif
		{
			// currently it will unzip file each time a zipped music is played. We may first check a fixed temp location and play it from there before extracting to it. 
			ParaEngine::CParaFile file(sWavePath);
			if(!file.isEof())
			{
				std::string file_extension = CParaFile::GetFileExtension(sWavePath);
				IParaAudioSource* pSource = m_pAudioEngine->createFromMemory(sWavePath, file.getBuffer(), file.getSize(), file_extension.c_str());
				if(pSource)
				{
					pWave->SetSource(pSource);
					bSucceed = true;
				}
			}
		}
	}
	return (bSucceed) ? S_OK : E_FAIL;
}
HRESULT ParaEngine::CParaXProcessor::CopyToResource()
{
	if (m_asset.get() == 0)
		return E_FAIL;
	if (m_asset->m_MeshLODs.size() == 0)
	{
		string filename = m_asset->GetLocalFileName();

		bool bLoadHeaderFromXFile = true;
		bool bSingleLOD = true;
		bool bIsXML = (CParaFile::GetFileExtension(filename) == "xml");
		string sParentDirectory = CParaFile::GetParentDirectoryFromPath(filename);


		// check in manifest
		AssetFileEntry* pEntry = CAssetManifest::GetSingleton().GetFile(filename);
		if (pEntry)
		{
			if (pEntry->DoesFileExist())
			{
				filename = pEntry->GetLocalFileName();
			}
			else
			{
				m_pAssetFileEntry = pEntry;
				return E_PENDING;
			}
		}

		if (bIsXML)
		{
			CParaMeshXMLFile file;
			if (file.LoadFromFile(filename, sParentDirectory))
			{
				if (file.GetType() == CParaMeshXMLFile::TYPE_MESH_LOD)
				{
					int i;
					// check if all sub files are available locally.
					for (i = 0; i < file.GetSubMeshCount(); ++i)
					{
						CParaMeshXMLFile::CSubMesh* pSubLODMesh = file.GetSubMesh(i);
						AssetFileEntry* pEntry = CAssetManifest::GetSingleton().GetFile(pSubLODMesh->m_sFileName);
						if (pEntry)
						{
							if (pEntry->DoesFileExist())
							{
								pSubLODMesh->m_sFileName = pEntry->GetLocalFileName();
							}
							else
							{
								m_pAssetFileEntry = pEntry;
								return E_PENDING;
							}
						}
					}

					if (file.m_bHasBoundingBox)
					{
					}

					for (i = 0; i < file.GetSubMeshCount(); ++i)
					{
						CParaMeshXMLFile::CSubMesh* pSubLODMesh = file.GetSubMesh(i);
						CreateMeshLODLevel(pSubLODMesh->m_fToCameraDist, pSubLODMesh->m_sFileName);
					}
					if (file.GetSubMeshCount() == 0)
					{
						OUTPUT_LOG("warning: LOD file %s does not contain any lod mesh references\n", filename.c_str());
						return E_FAIL;
					}
				}
			}
			else
			{
				OUTPUT_LOG("failed loading mesh xml file: %s\n", filename.c_str());
				return E_FAIL;
			}
		}
		else
		{
			CreateMeshLODLevel(0.f, filename);
		}
	}

	try
	{
		// preload file data to memory in the IO thread. 
		std::vector<MeshLOD> & pMeshLODs = m_MeshLODs.size() > 0 ? m_MeshLODs : m_asset->m_MeshLODs;
		for (auto iCur = pMeshLODs.begin(); iCur != pMeshLODs.end(); ++iCur)
		{
			if ( ! (iCur->m_pParaXMesh) )
			{
				CParaFile myFile(iCur->m_sMeshFileName.c_str());

				if (myFile.isEof())
				{
					OUTPUT_LOG("warning: ParaX model file not found %s\n", iCur->m_sMeshFileName.c_str());
					return E_FAIL;
				}

				std::string sExt = CParaFile::GetFileExtension(iCur->m_sMeshFileName);
				StringHelper::make_lower(sExt);
				if (sExt == "bmax")
				{
					// block max model. 
					BMaxParser p(myFile.getBuffer(), myFile.getSize());
					iCur->m_pParaXMesh = p.ParseParaXModel();
					auto pParaXMesh = iCur->m_pParaXMesh;

#ifdef ENABLE_BMAX_AUTO_LOD
					if (m_MeshLODs.size() == 1)
					{
						// each LOD at least cut triangle count in half and no bigger than a given count. 
						// by default, generate lod in range 30, 60, 90, 120 meters;
						// TODO: currently it is hard-coded, shall we read LOD settings from bmax file, so that users
						// have find-control on the settings. 
						struct LODSetting {
							int nMaxTriangleCount;
							float fMaxDistance;
						};
						const LODSetting nLodsMaxTriangleCounts[] = { {2000, 60.f}, {500, 90.f}, {100, 120.f} };
						
						// from second lod
						for (int i = 0; pParaXMesh && i < sizeof(nLodsMaxTriangleCounts)/sizeof(LODSetting); i++)
						{
							if ((int)pParaXMesh->GetPolyCount() >= nLodsMaxTriangleCounts[i].nMaxTriangleCount)
							{
								MeshLOD lod;
								lod.m_pParaXMesh = p.ParseParaXModel((std::min)(nLodsMaxTriangleCounts[i].nMaxTriangleCount, (int)(pParaXMesh->GetPolyCount() / 2) - 4));
								lod.m_fromDepthSquared = Math::Sqr(nLodsMaxTriangleCounts[i].fMaxDistance);
								if (lod.m_pParaXMesh)
								{
									if (pMeshLODs.size() == 1)
									{
										iCur->m_fromDepthSquared = Math::Sqr(nLodsMaxTriangleCounts[0].fMaxDistance*0.5f);
									}
									pParaXMesh = lod.m_pParaXMesh;
									pMeshLODs.push_back(lod);
									iCur = pMeshLODs.end() - 1;
								}
							}
						}
					}
#endif
				}

#ifdef SUPPORT_FBX_MODEL_FILE
				else if (sExt == "fbx")
				{
					// static or animated fbx model
					FBXParser parser(iCur->m_sMeshFileName);
					iCur->m_pParaXMesh = parser.ParseParaXModel(myFile.getBuffer(), myFile.getSize());
				}
#endif
				else
				{
					CParaXSerializer serializer;
#if  defined(USE_DIRECTX_RENDERER) && !defined(_DEBUG)
					ParaXParser parser(myFile, CAsyncLoader::GetSingleton().GetFileParser());
					iCur->m_pParaXMesh = (CParaXModel*)serializer.LoadParaXMesh(myFile, parser);
#else
					iCur->m_pParaXMesh = (CParaXModel*)serializer.LoadParaXMesh(myFile);
#endif
				}
				if (iCur->m_pParaXMesh == 0)
				{
					// lod.m_pParaXMesh = new CParaXModel(ParaXHeaderDef());
					OUTPUT_LOG("warning: cannot load ParaX model file %s\n", iCur->m_sMeshFileName.c_str());
					return E_FAIL;
				}

				if (!iCur->m_pParaXMesh->IsValid())
				{
					return E_FAIL;
				}
				else
				{
					m_nTechniqueHandle = iCur->m_pParaXMesh->IsBmaxModel() ? TECH_BMAX_MODEL : TECH_CHARACTER;
				}
			}
		}
	}
	catch (...)
	{
		OUTPUT_LOG("warning: failed initialize ParaX model %s\n", m_asset->GetLocalFileName().c_str());
		return E_FAIL;
	}
	return S_OK;
}
HRESULT ParaEngine::CParaXProcessor::CopyToResource()
{
	if (m_asset.get() == 0)
		return E_FAIL;
	if (m_asset->m_MeshLODs.size() == 0)
	{
		string filename = m_asset->GetLocalFileName();

		bool bLoadHeaderFromXFile = true;
		bool bSingleLOD = true;
		bool bIsXML = (CParaFile::GetFileExtension(filename) == "xml");
		string sParentDirectory = CParaFile::GetParentDirectoryFromPath(filename);


		// check in manifest
		AssetFileEntry* pEntry = CAssetManifest::GetSingleton().GetFile(filename);
		if (pEntry)
		{
			if (pEntry->DoesFileExist())
			{
				filename = pEntry->GetLocalFileName();
			}
			else
			{
				m_pAssetFileEntry = pEntry;
				return E_PENDING;
			}
		}

		if (bIsXML)
		{
			CParaMeshXMLFile file;
			if (file.LoadFromFile(filename, sParentDirectory))
			{
				if (file.GetType() == CParaMeshXMLFile::TYPE_MESH_LOD)
				{
					int i;
					// check if all sub files are available locally.
					for (i = 0; i < file.GetSubMeshCount(); ++i)
					{
						CParaMeshXMLFile::CSubMesh* pSubLODMesh = file.GetSubMesh(i);
						AssetFileEntry* pEntry = CAssetManifest::GetSingleton().GetFile(pSubLODMesh->m_sFileName);
						if (pEntry)
						{
							if (pEntry->DoesFileExist())
							{
								pSubLODMesh->m_sFileName = pEntry->GetLocalFileName();
							}
							else
							{
								m_pAssetFileEntry = pEntry;
								return E_PENDING;
							}
						}
					}

					if (file.m_bHasBoundingBox)
					{
					}

					for (i = 0; i < file.GetSubMeshCount(); ++i)
					{
						CParaMeshXMLFile::CSubMesh* pSubLODMesh = file.GetSubMesh(i);
						CreateMeshLODLevel(pSubLODMesh->m_fToCameraDist, pSubLODMesh->m_sFileName);
					}
					if (file.GetSubMeshCount() == 0)
					{
						OUTPUT_LOG("warning: LOD file %s does not contain any lod mesh references\n", filename.c_str());
						return E_FAIL;
					}
				}
			}
			else
			{
				OUTPUT_LOG("failed loading mesh xml file: %s\n", filename.c_str());
				return E_FAIL;
			}
		}
		else
		{
			CreateMeshLODLevel(0.f, filename);
		}
	}

	try
	{
		// preload file data to memory in the IO thread. 
		std::vector<MeshLOD> & pMeshLODs = m_MeshLODs.size() > 0 ? m_MeshLODs : m_asset->m_MeshLODs;
		std::vector<MeshLOD>::iterator iCur, iEnd = pMeshLODs.end();
		for (iCur = pMeshLODs.begin(); iCur != iEnd; ++iCur)
		{
			MeshLOD& lod = (*iCur);
			if (lod.m_pParaXMesh == 0)
			{
				CParaFile myFile(lod.m_sMeshFileName.c_str());

				if (myFile.isEof())
				{
					OUTPUT_LOG("warning: ParaX model file not found %s\n", lod.m_sMeshFileName.c_str());
					return E_FAIL;
				}

				std::string sExt = CParaFile::GetFileExtension(lod.m_sMeshFileName);
				StringHelper::make_lower(sExt);
				if (sExt == "bmax")
				{
					// block max model. 
					BMaxParser p(myFile.getBuffer(), myFile.getSize());
					lod.m_pParaXMesh = p.ParseParaXModel();
				}

#ifdef SUPPORT_FBX_MODEL_FILE
				else if (sExt == "fbx")
				{
					// static or animated fbx model
					FBXParser parser(lod.m_sMeshFileName);
					lod.m_pParaXMesh = parser.ParseParaXModel(myFile.getBuffer(), myFile.getSize());
				}
#endif
				else
				{
					CParaXSerializer serializer;
#ifdef USE_DIRECTX_RENDERER
					ParaXParser parser(myFile, CAsyncLoader::GetSingleton().GetFileParser());
					lod.m_pParaXMesh = (CParaXModel*)serializer.LoadParaXMesh(myFile, parser);
#elif defined(USE_OPENGL_RENDERER)
					lod.m_pParaXMesh = (CParaXModel*)serializer.LoadParaXMesh(myFile);
#endif
				}
				if (lod.m_pParaXMesh == 0)
				{
					// lod.m_pParaXMesh = new CParaXModel(ParaXHeaderDef());
					OUTPUT_LOG("warning: cannot load ParaX model file %s\n", lod.m_sMeshFileName.c_str());
					return E_FAIL;
				}

				if (!lod.m_pParaXMesh->IsValid())
				{
					return E_FAIL;
				}
				else
				{
					m_nTechniqueHandle = lod.m_pParaXMesh->IsBmaxModel() ? TECH_BMAX_MODEL : TECH_CHARACTER;
				}
			}
		}
	}
	catch (...)
	{
		OUTPUT_LOG("warning: failed initialize ParaX model %s\n", m_asset->GetLocalFileName().c_str());
		return E_FAIL;
	}
	return S_OK;
}