Esempio n. 1
0
	void						save_cross_table	(IWriter &stream)
	{
		stream.w_u32			(m_cross_table.size() + sizeof(u32));
		m_cross_table.seek		(0);
		stream.w				(m_cross_table.pointer(),m_cross_table.size());
		m_cross_table.clear		();
	}
bool manager::save_current_blend(char* buffer, u32 const& buffer_size)
{
    CInifile temp(0, FALSE, FALSE, FALSE);

    using editor::environment::weathers::time;
    time* frame = static_cast<time*>(m_manager.CurrentEnv);
    frame->save(temp);

    CMemoryWriter writer;
    temp.save_as(writer);
    if (writer.size() > buffer_size)
        return (false);

    writer.w_u8(0);
    writer.seek(0);
    Memory.mem_copy(buffer, writer.pointer(), writer.size());
    return (true);
}
Esempio n. 3
0
void CBuild::SaveTREE	(IWriter &fs)
{
	CMemoryWriter		MFS;

	Status				("Geometry buffers...");
	xr_vector<u32>		remap;
	remap.reserve		(g_tree.size());
	for (u32 rid=0; rid<g_tree.size(); rid++)	{
		OGF*	o		= dynamic_cast<OGF*>	(g_tree[rid]);
		if		(o)		remap.push_back(rid);
	}
	std::stable_sort	(remap.begin(),remap.end(),remap_order);
	clMsg				("remap-size: %d / %d",remap.size(),g_tree.size());
	for (u32 sid=0; sid<remap.size(); sid++)	{
		u32				id	= remap[sid];
		//clMsg			("%3d: subdiv: %d",sid,id);
		g_tree[id]->PreSave	(id);
	}

	Status				("Visuals...");
	fs.open_chunk		(fsL_VISUALS);
	for (xr_vector<OGF_Base*>::iterator it = g_tree.begin(); it!=g_tree.end(); it++)	{
		u32			idx = u32(it-g_tree.begin());
		MFS.open_chunk	(idx);
		(*it)->Save		(MFS);
		MFS.close_chunk	();
		Progress		(float(idx)/float(g_tree.size()));
	}
	fs.w				(MFS.pointer(),MFS.size());
	fs.close_chunk		();
	clMsg				("Average: %d verts/%d faces, 50(%2.1f), 100(%2.1f), 500(%2.1f), 1000(%2.1f), 5000(%2.1f)",
		g_batch_verts/g_batch_count,
		g_batch_faces/g_batch_count,
		100.f * float(g_batch_50)/float(g_batch_count),
		100.f * float(g_batch_100)/float(g_batch_count),
		100.f * float(g_batch_500)/float(g_batch_count),
		100.f * float(g_batch_1000)/float(g_batch_count),
		100.f * float(g_batch_5000)/float(g_batch_count)
		);
	mem_Compact			();

	SaveGEOMs			("level.geom",	g_VB,g_IB,g_SWI);	// Normal
	SaveGEOMs			("level.geomx",	x_VB,x_IB,x_SWI);	// Fast-Path

	Status				("Shader table...");
	fs.open_chunk		(fsL_SHADERS);
	fs.w_u32			(g_Shaders.size());
	for (xr_vector<LPCSTR>::iterator T=g_Shaders.begin(); T!=g_Shaders.end(); T++)
		fs.w_stringZ	(*T);
	fs.close_chunk		();
	//mem_Compact			();
}
bool weather::save_time_frame			(shared_str const& frame_id, char* buffer, u32 const& buffer_size)
{
	container_type::iterator	i = m_times.begin();
	container_type::iterator	e = m_times.end();
	for ( ; i != e; ++i) {
		if (frame_id._get() != (*i)->id()._get())
			continue;

		CInifile		temp(0, FALSE, FALSE, FALSE);
		(*i)->save		(temp);

		CMemoryWriter	writer;
		temp.save_as	(writer);
		if (writer.size() > buffer_size)
			return		(false);

		writer.seek		(0);
		Memory.mem_copy	(buffer, writer.pointer(), writer.size());
		return			(true);
	}

	return				(false);
}
Esempio n. 5
0
void	ClosePack			()
{
	fs->close_chunk	(); 
	// save list
	bytesDST		= fs->tell	();
	Log				("...Writing pack desc");
#ifdef MOD_COMPRESS
	DUMMY_STUFF*		_dummy_stuff_tmp;
	_dummy_stuff_tmp	= g_dummy_stuff;
	g_dummy_stuff		 = NULL;
#endif
	fs->w_chunk		(1|CFS_CompressMark, fs_desc.pointer(),fs_desc.size());
#ifdef MOD_COMPRESS
	g_dummy_stuff	= _dummy_stuff_tmp;
#endif

	Msg				("Data size: %d. Desc size: %d.",bytesDST,fs_desc.size());
	FS.w_close		(fs);
	Log				("Pack saved.");
	u32	dwTimeEnd	= timeGetTime();
	printf			("\n\nFiles total/skipped/VFS/aliased: %d/%d/%d/%d\nOveral: %dK/%dK, %3.1f%%\nElapsed time: %d:%d\nCompression speed: %3.1f Mb/s",
		filesTOTAL,filesSKIP,filesVFS,filesALIAS,
		bytesDST/1024,bytesSRC/1024,
		100.f*float(bytesDST)/float(bytesSRC),
		((dwTimeEnd-dwTimeStart)/1000)/60,
		((dwTimeEnd-dwTimeStart)/1000)%60,
		float((float(bytesDST)/float(1024*1024))/(t_compress.GetElapsed_sec()))
		);
	Msg			("\n\nFiles total/skipped/VFS/aliased: %d/%d/%d/%d\nOveral: %dK/%dK, %3.1f%%\nElapsed time: %d:%d\nCompression speed: %3.1f Mb/s\n\n",
		filesTOTAL,filesSKIP,filesVFS,filesALIAS,
		bytesDST/1024,bytesSRC/1024,
		100.f*float(bytesDST)/float(bytesSRC),
		((dwTimeEnd-dwTimeStart)/1000)/60,
		((dwTimeEnd-dwTimeStart)/1000)%60,
		float((float(bytesDST)/float(1024*1024))/(t_compress.GetElapsed_sec()))
		);
}
Esempio n. 6
0
void CSoundManager::MakeGameSound(ESoundThumbnail* THM, LPCSTR src_name, LPCSTR game_name)
{
	VerifyPath(game_name);
    CMemoryWriter 	F;
    F.w_u32			(OGG_COMMENT_VERSION);
    F.w_float		(THM->m_fMinDist);
    F.w_float		(THM->m_fMaxDist);
    F.w_float		(THM->m_fBaseVolume);
    F.w_u32			(THM->m_uGameType);
    F.w_float		(THM->m_fMaxAIDist);
	if (!ogg_enc(src_name,game_name, THM->m_fQuality,F.pointer(),F.size())){
    	FS.file_delete(game_name);
    	ELog.DlgMsg(mtError,"Can't make game sound '%s'.",game_name);
    }
}
Esempio n. 7
0
void CBuild::SaveSectors(IWriter& fs)
{
	CMemoryWriter MFS;
	Status("Processing...");

	// validate & save
	for (u32 I=0; I<g_sectors.size(); I++)
	{
		MFS.open_chunk(I);
		g_sectors[I]->Validate();
		g_sectors[I]->Save(MFS);
		MFS.close_chunk();
		Progress(float(I)/float(g_sectors.size()));
	}

	fs.w_chunk(fsL_SECTORS,MFS.pointer(),MFS.size());
}
Esempio n. 8
0
void xrCompressor::OpenPack(LPCSTR tgt_folder, int num)
{
	VERIFY			(0==fs_pack_writer);

	string_path		fname;
	string128		s_num;
#ifdef MOD_COMPRESS
	strconcat		(sizeof(fname),fname,tgt_folder,".xdb",itoa(num,s_num,10));
#else
	strconcat		(sizeof(fname),fname,tgt_folder,".pack_#",itoa(num,s_num,10));
#endif
	unlink			(fname);
	fs_pack_writer	= FS.w_open	(fname);
	fs_desc.clear	();
	aliases.clear	();

	bytesSRC		= 0;
	bytesDST		= 0;
	filesTOTAL		= 0;
	filesSKIP		= 0;
	filesVFS		= 0;
	filesALIAS		= 0;

	dwTimeStart		= timeGetTime();

	//write pack header without compression
//	DUMMY_STUFF* _dummy_stuff_subst		= NULL;
//	_dummy_stuff_subst					= g_dummy_stuff;
//	g_dummy_stuff						= NULL;

	if(config_ltx && config_ltx->section_exist("header"))
	{
		CMemoryWriter			W;
		CInifile::Sect&	S		= config_ltx->r_section("header");
		CInifile::SectCIt it	= S.Data.begin();
		CInifile::SectCIt it_e	= S.Data.end();
		string4096				buff;
		xr_sprintf					(buff,"[%s]",S.Name.c_str());
		W.w_string				(buff);
		for(;it!=it_e;++it)
		{
			const CInifile::Item& I	= *it;
			xr_sprintf					(buff, "%s = %s", I.first.c_str(), I.second.c_str());
			W.w_string				(buff);
		}
		W.seek						(0);
		IReader	R(W.pointer(), W.size());

		printf						("...Writing pack header\n");
		fs_pack_writer->open_chunk	(CFS_HeaderChunkID);
		fs_pack_writer->w			(R.pointer(), R.length());
		fs_pack_writer->close_chunk	();
	}else
	if(pPackHeader)
	{
		printf						("...Writing pack header\n");
		fs_pack_writer->open_chunk	(CFS_HeaderChunkID);
		fs_pack_writer->w			(pPackHeader->pointer(), pPackHeader->length());
		fs_pack_writer->close_chunk	();
	}else
		printf			("...Pack header not found\n");

//	g_dummy_stuff	= _dummy_stuff_subst;

	fs_pack_writer->open_chunk	(0);
}
Esempio n. 9
0
CGraphMerger::CGraphMerger(
		LPCSTR game_graph_id,
		LPCSTR name,
		bool rebuild
	)
{
	// load all the graphs
	Phase("Processing level graphs");
	
	CInifile *Ini = new CInifile(INI_FILE);
	if (!Ini->section_exist("levels"))
		THROW(false);
	R_ASSERT						(Ini->section_exist("levels"));

	tGraphHeader.m_guid				= generate_guid();

	GRAPH_P_MAP						tpGraphs;
	string4096						S1, S2;
	CGameGraph::SLevel				tLevel;
	u32								dwOffset = 0;
	u32								l_dwPointOffset = 0;
	LEVEL_POINT_STORAGE				l_tpLevelPoints;
	l_tpLevelPoints.clear			();

	xr_set<CLevelInfo>				levels;
	xr_vector<LPCSTR>				needed_levels;
	string4096						levels_string;
	strcpy_s						(levels_string,name);
	strlwr							(levels_string);
	fill_needed_levels				(levels_string,needed_levels);

	read_levels						(
		Ini,
		levels,
		rebuild,
		&needed_levels
	);

	xr_set<CLevelInfo>::const_iterator	I = levels.begin();
	xr_set<CLevelInfo>::const_iterator	E = levels.end();
	for ( ; I != E; ++I) {
		tLevel.m_offset				= (*I).m_offset;
		tLevel.m_name				= (*I).m_name;
		strcpy_s					(S1,sizeof(S1),*(*I).m_name);
		strconcat					(sizeof(S2),S2,name,S1);
		strconcat					(sizeof(S1),S1,S2,"\\");
		tLevel.m_id					= (*I).m_id;
		tLevel.m_section			= (*I).m_section;
		Msg							("%9s %2d %s","level",tLevel.id(),*tLevel.m_name);
		string_path					_0, _1;
		generate_temp_file_name		("local_graph_",*tLevel.m_name,_0);
		generate_temp_file_name		("raw_cross_table_",*tLevel.m_name,_1);
		string_path					level_folder;
		FS.update_path				(level_folder,"$game_levels$",*tLevel.m_name);
		strcat						(level_folder,"\\");
		CGameGraphBuilder().build_graph	(_0,_1,level_folder);
		::CLevelGameGraph			*tpLevelGraph = new ::CLevelGameGraph(
			_0,
			_1,
			&tLevel,
			level_folder,
			dwOffset,
			tLevel.id(),
			Ini
		);
		dwOffset					+= tpLevelGraph->m_tpGraph->header().vertex_count();
		R_ASSERT2					(tpGraphs.find(tLevel.id()) == tpGraphs.end(),"Level ids _MUST_ be different!");
		tpGraphs.insert				(mk_pair(tLevel.id(),tpLevelGraph));
		tGraphHeader.m_levels.insert(std::make_pair(tLevel.id(),tLevel));
	}
	
	R_ASSERT(tpGraphs.size());
	
	Phase("Adding interconnection points");
	{
		GRAPH_P_PAIR_IT				I = tpGraphs.begin();
		GRAPH_P_PAIR_IT				E = tpGraphs.end();
		for ( ; I != E; I++) {
			VERTEX_PAIR_IT			i = (*I).second->m_tVertexMap.begin();
			VERTEX_PAIR_IT			e = (*I).second->m_tVertexMap.end();
			for ( ; i != e; i++)
				if ((*i).second.caConnectName[0]) {
					GRAPH_P_PAIR_IT				K;
					VERTEX_PAIR_IT				M;
					CGameGraph::CEdge			tGraphEdge;
					SConnectionVertex			&tConnectionVertex = (*i).second;
					K							= tpGraphs.find(tConnectionVertex.dwLevelID);
					if (K == tpGraphs.end()) {
						Msg						("Cannot find level with level_id %d. Connection point will not be generated!",tConnectionVertex.dwLevelID);
						continue;
					}
					R_ASSERT					(K != tpGraphs.end());
					M							= (*K).second->m_tVertexMap.find(tConnectionVertex.caConnectName);
					if (M == (*K).second->m_tVertexMap.end()) {
						Msg						("Level %s with id %d has an INVALID connection point %s,\nwhich references to graph point %s on the level %s with id %d\n",*(*I).second->m_tLevel.name(),(*I).second->m_tLevel.id(),(*i).first,tConnectionVertex.caConnectName,*(*K).second->m_tLevel.name(),(*K).second->m_tLevel.id());
						R_ASSERT				(M != (*K).second->m_tVertexMap.end());
					}

//					if (!stricmp("l06_rostok",*(*I).second->m_tLevel.name())) {
//						__asm int 3;
//					}
					Msg							("Level %s with id %d has VALID connection point %s,\nwhich references to graph point %s on the level %s with id %d\n",*(*I).second->m_tLevel.name(),(*I).second->m_tLevel.id(),(*i).first,tConnectionVertex.caConnectName,*(*K).second->m_tLevel.name(),(*K).second->m_tLevel.id());

					VERIFY						(((*M).second.tGraphID + (*K).second->m_dwOffset) < (u32(1) << (8*sizeof(GameGraph::_GRAPH_ID))));
					tGraphEdge.m_vertex_id		= (GameGraph::_GRAPH_ID)((*M).second.tGraphID + (*K).second->m_dwOffset);
					VERIFY3						(tConnectionVertex.tGraphID < (*I).second->m_tpVertices.size(),"Rebuild graph for the level",*(*I).second->m_tLevel.name());
					VERIFY3						((*M).second.tGraphID < (*K).second->m_tpVertices.size(),"Rebuild graph for the level",*(*K).second->m_tLevel.name());
					tGraphEdge.m_path_distance	= (*I).second->m_tpVertices[tConnectionVertex.tGraphID].tGlobalPoint.distance_to((*K).second->m_tpVertices[(*M).second.tGraphID].tGlobalPoint);
					(*I).second->vfAddEdge		((*i).second.tGraphID,tGraphEdge);
//					tGraphEdge.dwVertexNumber	= (*i).second.tGraphID + (*I).second->m_dwOffset;
//					(*K).second->vfAddEdge		((*M).second.tGraphID,tGraphEdge);
				}
		}
	}
	// counting edges
	{
		tGraphHeader.m_edge_count			= 0;
		tGraphHeader.m_death_point_count	= 0;
		GRAPH_P_PAIR_IT						I = tpGraphs.begin();
		GRAPH_P_PAIR_IT						E = tpGraphs.end();
		for ( ; I != E; I++) {
			VERIFY							((u32(tGraphHeader.m_edge_count) + (*I).second->dwfGetEdgeCount()) < (u32(1) << (8*sizeof(GameGraph::_GRAPH_ID))));
			tGraphHeader.m_edge_count		+= (GameGraph::_GRAPH_ID)(*I).second->dwfGetEdgeCount();
			tGraphHeader.m_death_point_count+= (*I).second->dwfGetDeathPointCount();
		}
	}

	///////////////////////////////////////////////////
	
	// save all the graphs
	Phase("Saving graph being merged");
	CMemoryWriter				F;
	tGraphHeader.m_version		= XRAI_CURRENT_VERSION;
	VERIFY						(dwOffset < (u32(1) << (8*sizeof(GameGraph::_GRAPH_ID))));
	tGraphHeader.m_vertex_count	= (GameGraph::_GRAPH_ID)dwOffset;
	tGraphHeader.save			(&F);

	u32							vertex_count = 0;
	dwOffset					*= sizeof(CGameGraph::CVertex);
	u32							l_dwOffset = F.size();
	l_dwPointOffset				= dwOffset + tGraphHeader.edge_count()*sizeof(CGameGraph::CEdge);
	u32							l_dwStartPointOffset = l_dwPointOffset;
	{
		GRAPH_P_PAIR_IT			I = tpGraphs.begin();
		GRAPH_P_PAIR_IT			E = tpGraphs.end();
		for ( ; I != E; I++) {
			(*I).second->vfSaveVertices	(F,dwOffset,l_dwPointOffset,&l_tpLevelPoints);
			vertex_count		+= (*I).second->m_tpGraph->header().vertex_count();
		}
	}
	{
		GRAPH_P_PAIR_IT			I = tpGraphs.begin();
		GRAPH_P_PAIR_IT			E = tpGraphs.end();
		for ( ; I != E; I++)
			(*I).second->vfSaveEdges(F);
	}
	{
		l_tpLevelPoints.clear	();
		GRAPH_P_PAIR_IT			I = tpGraphs.begin();
		GRAPH_P_PAIR_IT			E = tpGraphs.end();
		for ( ; I != E; I++)
			l_tpLevelPoints.insert(l_tpLevelPoints.end(),(*I).second->m_tpLevelPoints.begin(),(*I).second->m_tpLevelPoints.end());
	}
	R_ASSERT2						(l_dwStartPointOffset == F.size() - l_dwOffset,"Graph file format is corrupted");
	{
		LEVEL_POINT_STORAGE::const_iterator	I = l_tpLevelPoints.begin();
		LEVEL_POINT_STORAGE::const_iterator	E = l_tpLevelPoints.end();
		for ( ; I != E; ++I)
			save_data				(*I,F);
	}
	{
		GRAPH_P_PAIR_IT			I = tpGraphs.begin();
		GRAPH_P_PAIR_IT			E = tpGraphs.end();
		for ( ; I != E; I++) {
			Msg					("cross_table offset: %d",F.size());
			(*I).second->save_cross_table	(F);
		}
	}
	
	string256						l_caFileName;
	strcpy_s							(l_caFileName,game_graph_id);
	F.save_to						(l_caFileName);

	// free all the graphs
	Phase("Freeing resources being allocated");
	{
		GRAPH_P_PAIR_IT				I = tpGraphs.begin();
		GRAPH_P_PAIR_IT				E = tpGraphs.end();
		for ( ; I != E; I++)
			xr_free((*I).second);
	}
	xr_delete						(Ini);
}
Esempio n. 10
0
void CGameGraphBuilder::save_graph			(const float &start, const float &amount)
{
	Progress				(start);

	Msg						("Saving graph");

	// header
	CMemoryWriter				writer;
	CGameGraph::CHeader			header;
	header.m_version			= XRAI_CURRENT_VERSION;
	VERIFY						(graph().vertices().size() < (u32(1) << (8*sizeof(GameGraph::_GRAPH_ID))));
	header.m_vertex_count		= (GameGraph::_GRAPH_ID)graph().vertices().size();
	VERIFY						(graph().edge_count() < (u32(1) << (8*sizeof(GameGraph::_GRAPH_ID))));
	header.m_edge_count			= (GameGraph::_GRAPH_ID)graph().edge_count();
	header.m_death_point_count	= 0;
	header.m_guid				= m_graph_guid;

	// levels
	CGameGraph::SLevel			level;
	level.m_offset.set			(0,0,0);
	level.m_id					= 0;
	level.m_name				= m_level_name;
	level.m_section				= "";
	level.m_guid				= level_graph().header().guid();

	header.m_levels.insert		(std::make_pair(level.m_id,level));

	header.save					(&writer);

	{
		u32								edge_offset = graph().vertices().size()*sizeof(CGameGraph::CVertex);

		graph_type::const_vertex_iterator	I = graph().vertices().begin();
		graph_type::const_vertex_iterator	E = graph().vertices().end();
		for ( ; I != E; ++I) {
			CGameGraph::CVertex		&vertex = (*I).second->data();

			VERIFY					((*I).second->edges().size() < 256);
			vertex.tNeighbourCount	= (u8)(*I).second->edges().size();
			vertex.dwEdgeOffset		= edge_offset;
			edge_offset				+= vertex.tNeighbourCount*sizeof(CGameGraph::CEdge);

			writer.w				(&vertex,sizeof(CGameGraph::CVertex));
		}
	}
	
	{
		graph_type::const_vertex_iterator	I = graph().vertices().begin();
		graph_type::const_vertex_iterator	E = graph().vertices().end();
		for ( ; I != E; ++I) {
			graph_type::const_iterator	i = (*I).second->edges().begin();
			graph_type::const_iterator	e = (*I).second->edges().end();
			for ( ; i != e; ++i) {
				GameGraph::CEdge			edge;
				VERIFY						((*i).vertex_id() < (u32(1) << (8*sizeof(GameGraph::_GRAPH_ID))));
				edge.m_vertex_id			= (GameGraph::_GRAPH_ID)(*i).vertex_id();
				edge.m_path_distance		= (*i).weight();

				writer.w					(&edge.m_vertex_id,sizeof(edge.m_vertex_id));
				writer.w_float				(edge.m_path_distance);
			}
		}
	}

#ifdef PRIQUEL
	writer.save_to				(m_graph_name);
#else // PRIQUEL
	string_path					file_name;
	strconcat					(sizeof(file_name),file_name,*m_level_name,GAME_LEVEL_GRAPH);
	writer.save_to				(file_name);
#endif // PRIQUEL
	Msg							("%d bytes saved",int(writer.size()));

	Progress					(start + amount);
}
Esempio n. 11
0
BOOL SceneBuilder::BuildGame()
{
	SExportStreams 		F;
    F.envmodif.stream.open_chunk	(F.envmodif.chunk++);
    F.envmodif.stream.w_u32			(u32(SPAWNPOINT_VERSION));
    F.envmodif.stream.close_chunk	();
    
    if (!Scene->ExportGame(&F))				return FALSE;

    BOOL bRes 			= TRUE;
    // save spawn
    {
        xr_string lev_spawn 	  			= MakeLevelPath("level.spawn");
        EFS.MarkFile						(lev_spawn.c_str(),true);
        if (F.spawn.chunk)
            if (!F.spawn.stream.save_to		(lev_spawn.c_str())) bRes = FALSE;

        lev_spawn 	  						= MakeLevelPath("level_rs.spawn");
        EFS.MarkFile						(lev_spawn.c_str(),true);
        if (F.spawn_rs.chunk)
            if (!F.spawn_rs.stream.save_to	(lev_spawn.c_str())) bRes = FALSE;
    }

    // save game
    {
        CMemoryWriter GAME; 
        GAME.w_chunk(WAY_PATROLPATH_CHUNK,	F.patrolpath.stream.pointer(),	F.patrolpath.stream.size());
        GAME.w_chunk(RPOINT_CHUNK,			F.rpoint.stream.pointer(),		F.rpoint.stream.size());
        xr_string lev_game 					= MakeLevelPath("level.game");
        EFS.MarkFile						(lev_game.c_str(),true);
        if (GAME.size())
            if (!GAME.save_to				(lev_game.c_str())) bRes = FALSE;
    }

    // save weather env modificator
    {
        xr_string lev_env_mod				= MakeLevelPath("level.env_mod");
        EFS.MarkFile						(lev_env_mod.c_str(),true);
        if (F.envmodif.chunk)
	        if (!F.envmodif.stream.save_to	(lev_env_mod.c_str())) bRes = FALSE;
    }

    // save static sounds
    {
        xr_string lev_sound_static 			= MakeLevelPath("level.snd_static");
        EFS.MarkFile						(lev_sound_static.c_str(),true);
        if (F.sound_static.chunk)    	
            if (!F.sound_static.stream.save_to	(lev_sound_static.c_str())) bRes = FALSE;
    }
/*
    // save sound envs
    {
        xr_string lev_sound_env 			= MakeLevelPath("level.snd_env");
        EFS.MarkFile						(lev_sound_env.c_str(),true);
        if (LSndLib->MakeEnvGeometry		(F.sound_env_geom.stream,false))
            if (!F.sound_env_geom.stream.save_to(lev_sound_env.c_str())) bRes = FALSE;
    }
*/
    // save static PG
    {
        xr_string lev_pe_static 			= MakeLevelPath("level.ps_static");
        EFS.MarkFile						(lev_pe_static.c_str(),true);
        if (F.pe_static.chunk)    	
            if (!F.pe_static.stream.save_to	(lev_pe_static.c_str())) bRes = FALSE;
    }

    // save fog volumes
    if(1)
    {
        xr_string lev_fog_vol 				= MakeLevelPath("level.fog_vol");
        EFS.MarkFile						(lev_fog_vol.c_str(),true);

        F.fog_vol.stream.w_u16				(3); //version

		ObjectList& fogs 					= Scene->ListObj(OBJCLASS_FOG_VOL);

        typedef xr_vector<EFogVolume*> 		tfog_group;
        typedef xr_map<u32, tfog_group> 		tfog_groups;

        tfog_groups							fog_groups;

        for (ObjectIt oit=fogs.begin(); oit!=fogs.end(); ++oit)
        {
            EFogVolume* E 		= dynamic_cast<EFogVolume*>(*oit);
            R_ASSERT			(E);
            u32 grp_id			= E->m_group_id;
            fog_groups[grp_id].push_back(E);
        }

        F.fog_vol.stream.w_u32				(fog_groups.size());

		tfog_groups::iterator git 			= fog_groups.begin();
		tfog_groups::iterator git_e 			= fog_groups.end();
        for(; git!=git_e; ++git)
        {
        	tfog_group& one_group			= git->second;
            std::sort(one_group.begin(), one_group.end(), sort_fog_vol);

            tfog_group::iterator fgit = one_group.begin();
            tfog_group::iterator fgit_e = one_group.end();

            for(; fgit!=fgit_e; ++fgit)
            {
                EFogVolume* E 				= *fgit;
                if(fgit==one_group.begin())
                {
                    if(E->m_volumeType!=fvEmitter)
                    {
                    	bRes 			= FALSE;
                        Msg("! incorrect fog volumes grouping");
						break;
                    }
                    
                    F.fog_vol.stream.w_string	(E->m_volume_profile.c_str());
				}
                Fmatrix M						= E->_Transform();
                F.fog_vol.stream.w				(&M, sizeof(M));

                if(fgit==one_group.begin())
                {
                    if(E->m_volumeType!=fvEmitter)
                    {
                    
                    	bRes 			= FALSE;
                        Msg("! incorrect fog volumes grouping");
						break;
                    }
                    
                    F.fog_vol.stream.w_u32	(one_group.size()-1);
                }else
                {
                
                    if(E->m_volumeType!=fvOcclusion)
                    {
                    	bRes 			= FALSE;
                        Msg("! incorrect fog volumes grouping");
						break;
                    }
                    
                 }   
                    if(!bRes)
                    	break;
            }
            if(!bRes)
                break;
        }

        if (!F.fog_vol.stream.save_to(lev_fog_vol.c_str()))
        	bRes = FALSE;
    }

    return bRes;
}