void net_task_menager::receive(  INetReader& r )
{
	send_receive_data_lock.Enter();
	u32 id = r.r_u32();
	xr_vector<u32>::iterator it =std::find( pool.begin(), pool.end(), id );
	if( it == pool.end() )
		return;
	pool.erase( it );
	u32 pool_size = pool.size();
	send_receive_data_lock.Leave();

	VERIFY(inlc_global_data());
	//inlc_global_data()->create_read_faces();
	inlc_global_data()->g_deflectors()[id]->read( r );
	//inlc_global_data()->destroy_read_faces();


	u32 size = inlc_global_data()->g_deflectors().size();
	


	clMsg( "received task : %d", id );
	DumpDeflctor( id );
	
	VERIFY( size > 0 );
	//thProgress+=(1.f/size);
	Progress(1.f - float(pool.size())/float(size));
	clMsg( "num task complited : %d , num task left %d  (task num %d)", size - pool_size, pool_size, size );
	if(pool.empty())
	{
		clMsg	( "calculation complited" );
		clMsg	("%f net lightmaps calculation seconds",start_time.GetElapsed_sec());
	}
	
}
Beispiel #2
0
void OGF::DumpFaces()
{
	clMsg	("normal:");
	for (u32 i=0; i<data.faces.size(); i++)
		clMsg("face #%4d: %4d %4d %4d",i,int(data.faces[i].v[0]),int(data.faces[i].v[1]),int(data.faces[i].v[2]));
	clMsg	("fast:");
	for (u32 i=0; i<fast_path_data.faces.size(); i++)
		clMsg("face #%4d: %4d %4d %4d",i,int(fast_path_data.faces[i].v[0]),int(fast_path_data.faces[i].v[1]),int(fast_path_data.faces[i].v[2]));
}
Beispiel #3
0
void	CThread::startup(void* P)
{
	CThread* T = (CThread*)P;

	if (T->thMessages)	clMsg("* THREAD #%d: Started.",T->thID);
	FPU::m64r		();
	T->Execute		();
	T->thCompleted	= TRUE;
	if (T->thMessages)	clMsg("* THREAD #%d: Task Completed.",T->thID);
}
void create_global_data_write()
{
	 clMsg( "create_global_data_write:  start" );
	
	
	gl_data_write = xr_new<INetWriter>( (IGenericStream*)(0), u32(-1) );
	 //INetWriter w( *stream, u32(-1) );
	//send_receive_data_lock.Enter();
	inlc_global_data()->write( *gl_data_write );
	//send_receive_data_lock.Leave();
	clMsg( "create_global_data_write:  end, size %d", gl_data_write->count() );
}
Beispiel #5
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			();
}
	void	net_global_data_impl<gl_base_cl_data>::create_data_file( LPCSTR path  )
	{
		FPU::m64r			();
		Memory.mem_compact	();
		//std::random_shuffle	(inlc_global_data()->g_deflectors().begin(),inlc_global_data()->g_deflectors().end());
		clMsg( "create_base_global_data_write:  start" );
		IWriter * file = FS.w_open(path);
		inlc_global_data()->write_base( *file );
		FS.w_close(file);
		compress( path ); 
		clMsg( "create_base_global_data_write:  end" );
		//inlc_global_data()->create_read_faces();
		//inlc_global_data()->create_write_faces();
	}
	void	net_global_data_impl<gl_detail_cl_data>::create_data_file( LPCSTR path  )
	{
		//FPU::m64r			();
		//Memory.mem_compact	();
		//if(!write_faces)
			//inlc_global_data()->create_write_faces();
		clMsg( "gl_detail_cl_data:  start" );
		
		IWriter * file = FS.w_open(path);
		gl_data.write( *file );
		FS.w_close(file);
		compress( path ); 
		clMsg( "gl_detail_cl_data:  end" );

	}
void __cdecl GetDataCallback(const char* dataDesc, IGenericStream** stream)
{
	 clMsg( "GetDataCallback: send start" );
	 VERIFY(xr_strcmp(dataDesc,"global_data")==0);
	 CTimer			time;
	 time.Start();
	 R_ASSERT(gl_data_write);
	 *stream  = CreateGenericStream();
	 //*stream = gl_data_write->net_stream();
	 gl_data_write->send_not_clear(*stream);
	 //*stream->Release();
	 clMsg( "GetDataCallback: send end time elapsed sec: %f, ", time.GetElapsed_sec() );
 //(*stream) = new TGenericStream(20000000);

 //(*stream)->Write(globalDataStream->GetBasePointer(), globalDataStream->GetLength()); 
}
void	net_task_menager::run()
{
	start_time.Start();
	create_global_data_write();
	inlc_global_data()->create_read_faces();

	IGridUser* user = CreateGridUserObject(IGridUser::VERSION);
	VERIFY( user );
	user->BindGetDataCallback(GetDataCallback);
	Status			("Lighting...");

	  VERIFY ( inlc_global_data() );
	  u32 size = inlc_global_data()->g_deflectors().size();

	std::random_shuffle	(inlc_global_data()->g_deflectors().begin(),inlc_global_data()->g_deflectors().end());
	for	(u32 dit = 0; dit<size; dit++)
		pool.push_back(dit);
	
	FPU::m64r		();
	Memory.mem_compact	();
	
	for	(u32 dit = 0; dit<size; dit++)
		send( *user, dit ); 

	user->WaitForCompletion();

	gl_data_write->clear();
	xr_delete(gl_data_write);
	inlc_global_data()->destroy_read_faces();

	user->Release();
	clMsg			("%f net lightmaps seconds",start_time.GetElapsed_sec());
}
Beispiel #10
0
	virtual void	Execute()
	{
		CDeflector* D	= 0;

		for (;;) 
		{
			// Get task
			task_CS.Enter		();
			thProgress			= 1.f - float(task_pool.size())/float(g_deflectors.size());
			if (task_pool.empty())	
			{
				task_CS.Leave		();
				return;
			}

			D					= g_deflectors[task_pool.back()];
			task_pool.pop_back	();
			task_CS.Leave		();

			// Perform operation
			try {
				D->Light	(&DB,&LightsSelected,H);
			} catch (...)
			{
				clMsg("* ERROR: CLMThread::Execute - light");
			}
		}
	}
	void	net_global_data_impl<gl_implicit_cl_data>::create_data_file( LPCSTR path  )
	{
		//FPU::m64r			();
		//Memory.mem_compact	();
		//if(!write_faces)
			//inlc_global_data()->create_write_faces();
		clMsg( "create_implicit_data_write:  start" );
		R_ASSERT(write_faces);

		
		IWriter * file = FS.w_open(path);
		cl_globs.write( *file );
		FS.w_close(file);
		
		compress( path ); 
		clMsg( "create_implicit_data_write:  end" );

	}
Beispiel #12
0
void CBuild::validate_splits			()
{
	for (splitIt it=g_XSplit.begin(); it!=g_XSplit.end(); it++)
	{
		u32 MODEL_ID		= u32(it-g_XSplit.begin())	;
		if ((*it)->size() > c_SS_HighVertLimit*2)		{
			clMsg	("! ERROR: subdiv #%d has more than %d faces (%d)",MODEL_ID,2*c_SS_HighVertLimit,(*it)->size());
		}
	};
}
Beispiel #13
0
// Calculate T&B
void OGF::CalculateTB()
{
	remove_isolated_verts( data.vertices, data.faces );
		// ************************************* Declare inputs
	Status						( "Declarator..." );
	u32 v_count_reserve			= iFloor( float( data.vertices.size() )*1.33f );
	u32 i_count_reserve			= 3*data.faces.size();


	mender_mapping_out_to_in_vert	.clear( );

	mender_mapping_out_to_in_vert	.reserve( v_count_reserve );
	mender_in_out_verts				.reserve( v_count_reserve );
	mender_in_out_indices			.reserve( i_count_reserve );

	mender_in_out_verts				.clear( );
	mender_in_out_indices			.clear( );
	fill_mender_input( data.vertices, data.faces, mender_in_out_verts, mender_in_out_indices );

	u32			v_was	= data.vertices.size();
	u32			v_become= mender_in_out_verts.size();
	clMsg		("duplication: was[%d] / become[%d] - %2.1f%%",v_was,v_become,100.f*float(v_become-v_was)/float(v_was));

	// ************************************* Perform mungle
	Status			("Calculating basis...");
	
	MeshMender	mender	;
	if (	!mender.Mend		(
		  mender_in_out_verts,
		  mender_in_out_indices,
		  mender_mapping_out_to_in_vert,
		  1,
		  0.5,
		  0.5,
		  0.0f,
		  MeshMender::DONT_CALCULATE_NORMALS,
		  MeshMender::RESPECT_SPLITS,
		  MeshMender::DONT_FIX_CYLINDRICAL
		)
	)
	{
		xrDebug::Fatal	(DEBUG_INFO, "NVMeshMender failed " );
		//xrDebug::Fatal	(DEBUG_INFO,"NVMeshMender failed (%s)",mender.GetLastError().c_str());
	}

	// ************************************* Bind declarators
	// bind

	retrive_data_from_mender_otput( data.vertices, data.faces, mender_in_out_verts, mender_in_out_indices, mender_mapping_out_to_in_vert  );
	remove_isolated_verts( data.vertices, data.faces );

	mender_in_out_verts				.clear( );
	mender_in_out_indices			.clear( );
	mender_mapping_out_to_in_vert	.clear( );
}
Beispiel #14
0
void CBuild::CorrectTJunctions()
{
	Status					("Processing...");
	vecJunctions			= xr_new<xr_vector<record> > (); vecJunctions->reserve	(1024);
	vecEdges				= xr_new<xr_vector<record> > (); vecEdges->reserve		(1024);

	for (u32 I=0; I<g_faces.size(); I++)
	{
		Face* F = g_faces[I];

		// Iterate on edges
		for (u32 e=0; e<3; e++)
		{
			Vertex			*vA,*vB;
			F->EdgeVerts	(e,&vA,&vB);

			// Iterate on 'vA'-adjacent faces
			for (u32 f1=0; f1!=vA->adjacent.size(); f1++)
			{
				Face*	F1	= vA->adjacent[f1];

				// Iterate on it's edges
				for (u32 e1=0; e1<3; e1++)
				{
					Vertex			*v1,*v2;
					F1->EdgeVerts	(e1,&v1,&v2);
					edge						(v1,v2);
					if (v1==vA && v2!=vB)		check(vA,vB,v2);
					else if (v2==vA && v1!=vB)	check(vA,vB,v1);
				}
			}
			// Iterate on 'vB'-adjacent faces
			for (u32 f2=0; f2!=vB->adjacent.size(); f2++)
			{
				Face*	F2	= vB->adjacent[f2];

				// Iterate on it's edges
				for (u32 e1=0; e1<3; e1++)
				{
					Vertex			*v1,*v2;
					F2->EdgeVerts	(e1,&v1,&v2);
					edge						(v1,v2);
					if (v1==vB && v2!=vA)		check(vA,vB,v2);
					else if (v2==vB && v1!=vA)	check(vA,vB,v1);
				}
			}
		}
		Progress(float(I)/float(g_faces.size()));
	}
	clMsg("*** %d junctions and %d long edges found.",vecJunctions->size(),vecEdges->size());

	xr_delete(vecJunctions);
	xr_delete(vecEdges);
}
Beispiel #15
0
void transfer(const char *name, xr_vector<T> &dest, IReader& F, u32 chunk)
{
	IReader*	O	= F.open_chunk(chunk);
	u32		count	= O?(O->length()/sizeof(T)):0;
	clMsg			("* %16s: %d",name,count);
	if (count)  
	{
		dest.reserve(count);
		dest.insert	(dest.begin(), (T*)O->pointer(), (T*)O->pointer() + count);
	}
	if (O)		O->close	();
}
void calc_ogf( xrMU_Model &	mu_model )
{
	// Build OGFs
	for (xrMU_Model::v_subdivs_it it=mu_model.m_subdivs.begin(); it!=mu_model.m_subdivs.end(); it++)
	{
		OGF*		pOGF	= xr_new<OGF> ();
		b_material*	M		= &(pBuild->materials()[it->material]);	// and it's material
		R_ASSERT	(M);

		try {
			// Common data
			pOGF->Sector		= 0;
			pOGF->material		= it->material;

			// Collect textures
			OGF_Texture			T;
			TRY					(T.name		= pBuild->textures()[M->surfidx].name);
			TRY					(T.pBuildSurface = &(pBuild->textures()[M->surfidx]));
			TRY					(pOGF->textures.push_back(T));

			// Collect faces & vertices
			try {
				xrMU_Model::v_faces_it	_beg	= mu_model.m_faces.begin() + it->start;
				xrMU_Model::v_faces_it	_end	= _beg + it->count;
				for (xrMU_Model::v_faces_it Fit =_beg; Fit!=_end; Fit++)
				{
					_face*	FF		= *Fit;
					R_ASSERT			(FF);
					OGF_AddFace( *pOGF, *FF, mu_model ); 
				}
			} catch (...) {  clMsg("* ERROR: MU2OGF, model %s, *faces*",*(mu_model.m_name)); }
		} catch (...)
		{
			clMsg("* ERROR: MU2OGF, 1st part, model %s",*(mu_model.m_name));
		}

		try {
			pOGF->Optimize			();
		} catch (...)	{ clMsg	("* ERROR: MU2OGF, [optimize], model %s",*(mu_model.m_name)); }
		try {
			pOGF->CalcBounds		();
		} catch (...)	{ clMsg	("* ERROR: MU2OGF, [bounds], model %s",*(mu_model.m_name)); }
		try {
			pOGF->CalculateTB		();
		} catch (...)	{ clMsg	("* ERROR: MU2OGF, [calc_tb], model %s",*(mu_model.m_name)); }
		try {
			pOGF->MakeProgressive	(c_PM_MetricLimit_mu);
		} catch (...)	{ clMsg	("* ERROR: MU2OGF, [progressive], model %s",*(mu_model.m_name)); }
		try {
			pOGF->Stripify			();
		} catch (...)	{ clMsg	("* ERROR: MU2OGF, [stripify], model %s",*(mu_model.m_name)); }

		it->ogf		=	pOGF;
	}
}
Beispiel #17
0
void CBuild::LightVertex	()
{
	g_trans				= xr_new<mapVert>	();

	// Start threads, wait, continue --- perform all the work
	Status				("Calculating...");
	CThreadManager		Threads;
	VLT.init			();
	CTimer	start_time;	start_time.Start();				
	for (u32 thID=0; thID<NUM_THREADS; thID++)	Threads.start(xr_new<CVertexLightThread>(thID));
	Threads.wait		();
	clMsg				("%f seconds",start_time.GetElapsed_sec());

	// Process all groups
	Status				("Transluenting...");
	for (mapVertIt it=g_trans->begin(); it!=g_trans->end(); it++)
	{
		// Unique
		vecVertex&	VL	= it->second;
		std::sort		(VL.begin(),VL.end());
		VL.erase		(std::unique(VL.begin(),VL.end()),VL.end());

		// Calc summary color
		base_color_c	C;
		for (u32 v=0; v<VL.size(); v++)
		{
			base_color_c	cc;	VL[v]->C._get(cc);
			C.max			(cc);
		}

		// Calculate final vertex color
		for (u32 v=0; v<VL.size(); v++)
		{
			base_color_c		vC;
			VL[v]->C._get		(vC);

			// trans-level
			float	level		= vC._tmp_;

			// 
			base_color_c		R;
			R.lerp				(vC,C,level);
			R.max				(vC);
			VL[v]->C._set		(R);
		}
	}
	xr_delete	(g_trans);
}
void net_task_menager::send( IGridUser& user, u32 id )
{
	//send_receive_data_lock.Enter();
	IGenericStream* stream  = CreateGenericStream();
	{
		INetWriter w( stream, 100 );
		w.w_u32( id );
	}
	DWORD t_id = id;
	
	user.RunTask( libraries ,"RunTask",stream,Finalize,&t_id,true);

	clMsg( "send task : %d", id );
	DumpDeflctor( id );
	//send_receive_data_lock.Leave();
}
Beispiel #19
0
void CBuild::mem_CompactSubdivs()
{
	// Memory compact
	CTimer	dwT;	dwT.Start();
	vecFace			temp;
	for (int SP = 0; SP<int(g_XSplit.size()); SP++) 
	{
		temp.clear			();
		temp.assign			(g_XSplit[SP]->begin(),g_XSplit[SP]->end());
		xr_delete			(g_XSplit[SP]);
		mem_Compact			();
		g_XSplit[SP]		= xr_new<vecFace> ();
		g_XSplit[SP]->assign(temp.begin(),temp.end());
	}
	clMsg		("%d ms for memory compacting...",dwT.GetElapsed_ms());
}
Beispiel #20
0
void vfOptimizeParameters(xr_vector<xr_vector<REAL> > &A, xr_vector<xr_vector<REAL> > &B, xr_vector<REAL> &C, xr_vector<REAL> &D, REAL dEpsilon, REAL dAlpha, REAL dBeta, REAL dNormaFactor, u32 dwMaxIterationCount)
{
	u32						dwTestCount	= (u32)B.size();
	xr_vector<REAL>			daGradient;
	xr_vector<REAL>			daDelta;
	xr_vector<xr_vector<REAL> >	daEvalResults; daEvalResults.resize(dwTestCount);
	
	if (!B.size()) {
		clMsg				("! ERROR : there are no parameters to fit!");
		return;
	}
	
	u32						dwParameterCount = (u32)B[0].size();
	C.assign				(dwParameterCount,1.0f);
	D.assign				(dwParameterCount,0.0f);
	daDelta.assign			(dwParameterCount,0);
	daGradient.assign		(dwParameterCount,0);
	{
		for (u32 i=0; i<dwTestCount; i++)
			daEvalResults[i].resize(dwParameterCount);
	}
	u32						i = 0;
	REAL					dFunctional = dfComputeEvalResults(daEvalResults,A,B,C,D), dPreviousFunctional;
	//clMsg					("* MU-fitter: %6d : %17.8f (%17.8f)",i,dFunctional,dFunctional/dwTestCount);
	do {
		dPreviousFunctional = dFunctional;
		dafGradient			(daEvalResults,			daGradient,			B,					dNormaFactor);
		std::transform		(daGradient.begin(),	daGradient.end(),	daGradient.begin(),	std::bind2nd(std::multiplies<REAL>(), -dAlpha));
		std::transform		(daDelta.begin(),		daDelta.end(),		daDelta.begin(),	std::bind2nd(std::multiplies<REAL>(), dBeta));
		std::transform		(daGradient.begin(),	daGradient.end(),	daDelta.begin(),	daDelta.begin(),	std::plus<REAL>());
		std::transform		(C.begin(),				C.end(),			daDelta.begin(),	C.begin(),			std::plus<REAL>());
		std::transform		(D.begin(),				D.end(),			daDelta.begin(),	D.begin(),			std::plus<REAL>());
		dFunctional			= dfComputeEvalResults(daEvalResults,A,B,C,D);
		i++;
	}
	while ((((dPreviousFunctional - dFunctional)/dwTestCount) > dEpsilon) && (i <= dwMaxIterationCount));
	
	if (dPreviousFunctional < dFunctional) {
		std::transform		(daDelta.begin(),		daDelta.end(),		daDelta.begin(),	std::bind2nd(std::multiplies<REAL>(), -1));
		std::transform		(C.begin(),				C.end(),			daDelta.begin(),	C.begin(),			std::plus<REAL>());
		std::transform		(D.begin(),				D.end(),			daDelta.begin(),	D.begin(),			std::plus<REAL>());
	}
	
	dFunctional				= dfComputeEvalResults(daEvalResults,A,B,C,D);
	//clMsg					("* MU-fitter: %6d : %17.8f (%17.8f)",i,dFunctional,dFunctional/dwTestCount);
}
Beispiel #21
0
void CBuild::Light()
{
	//****************************************** Implicit
	{
		FPU::m64r		();
		Phase			("LIGHT: Implicit...");
		mem_Compact		();
		ImplicitLighting();
	}

	//****************************************** Lmaps
	{
		FPU::m64r		();
		Phase			("LIGHT: LMaps...");
		mem_Compact		();

		// Randomize deflectors
		std::random_shuffle	(g_deflectors.begin(),g_deflectors.end());
		for					(u32 dit = 0; dit<g_deflectors.size(); dit++)	task_pool.push_back(dit);

		// Main process (4 threads)
		Status			("Lighting...");
		CThreadManager	threads;
		const	u32	thNUM	= 6;
		CTimer	start_time;	start_time.Start();				
		for				(int L=0; L<thNUM; L++)	threads.start(xr_new<CLMThread> (L));
		threads.wait	(500);
		clMsg			("%f seconds",start_time.GetElapsed_sec());
	}

	//****************************************** Vertex
	FPU::m64r		();
	Phase			("LIGHT: Vertex...");
	mem_Compact		();

	LightVertex		();

	//****************************************** Merge LMAPS
	{
		FPU::m64r		();
		Phase			("LIGHT: Merging lightmaps...");
		mem_Compact		();

		xrPhase_MergeLM	();
	}
}
void xrMU_Model::calc_lighting	()
{
	// BB
	Fbox			BB; 
	BB.invalidate	();
	for (v_vertices_it vit=m_vertices.begin(); vit!=m_vertices.end(); vit++)
		BB.modify	((*vit)->P);

	// Export CForm
	CDB::CollectorPacked	CL	(BB,(u32)m_vertices.size(),(u32)m_faces.size());
	export_cform_rcast		(CL,Fidentity);

	CDB::MODEL*				M	= xr_new<CDB::MODEL>	();
	M->build				(CL.getV(),(u32)CL.getVS(),CL.getT(),(u32)CL.getTS());

	calc_lighting			(color,Fidentity,M,inlc_global_data()->L_static(),LP_dont_rgb+LP_dont_sun);

	xr_delete				(M);

	clMsg					("model '%s' - REF_lighted.",*m_name);
}
Beispiel #23
0
void CLevelSpawnConstructor::fill_level_changers				()
{
	for (u32 i=0, n=(u32)level_changers().size(); i<n; ++i) {
		if (level_id(level_changers()[i]->m_caLevelToChange) != m_level.id())
			continue;

		bool found = false;
		GRAPH_POINT_STORAGE::const_iterator I = m_graph_points.begin();
		GRAPH_POINT_STORAGE::const_iterator E = m_graph_points.end();
		for ( ; I != E; ++I)
			if (!xr_strcmp(*level_changers()[i]->m_caLevelPointToChange,(*I)->name_replace())) {
				bool ok = false;
				for (u32 ii=0, nn = game_graph().header().vertex_count(); ii<nn; ++ii) {
					if ((game_graph().vertex(ii)->level_id() != m_level.id()) || !game_graph().vertex(ii)->level_point().similar((*I)->o_Position,.001f))
						continue;
					level_changers()[i]->m_tNextGraphID		= (GameGraph::_GRAPH_ID)ii;
					level_changers()[i]->m_tNextPosition	= (*I)->o_Position;
					level_changers()[i]->m_tAngles			= (*I)->o_Angle;
					level_changers()[i]->m_dwNextNodeID		= game_graph().vertex(ii)->level_vertex_id();
					ok										= true;
					break;
				}

				R_ASSERT3					(ok,"Cannot find a correspndance between graph and graph points from level editor! Rebuild graph for the level ",*level_changers()[i]->m_caLevelToChange);

				level_changers().erase		(level_changers().begin() + i);
				--i;
				--n;
				found		= true;
				break;
			}

		if (!found) {
			clMsg			("Graph point %s not found (level changer %s)",*level_changers()[i]->m_caLevelPointToChange,level_changers()[i]->name_replace());
			VERIFY			(false);
		}
	}
}
Beispiel #24
0
void CBuild::BuildSectors()
{
	Status("Determining sectors...");
	Progress(0);
	u32 SectorMax=0;
	for (u32 I=0; I<g_tree.size(); I++)
		if (g_tree[I]->Sector>SectorMax) SectorMax=g_tree[I]->Sector;
	R_ASSERT(SectorMax<0xffff);

	u32 SectorCount = SectorMax+1; 
	g_sectors.resize(SectorCount);
	ZeroMemory(&*g_sectors.begin(),(u32)g_sectors.size()*sizeof(void*));
	clMsg("%d sectors accepted.",SectorCount);

	Status("Spatializing geometry...");
	for (u32 I=0; I<g_tree.size(); I++)
	{
		u32 Sector = g_tree[I]->Sector;
		if (0==g_sectors[Sector]) g_sectors[Sector] = xr_new<CSector> (Sector);
	}

	Status("Building hierrarhy...");
	for (u32 I=0; I<g_sectors.size(); I++)
	{
		R_ASSERT(g_sectors[I]);
		g_sectors[I]->BuildHierrarhy();
		Progress(float(I)/float(g_sectors.size()));
	}

	Status("Assigning portals, occluders, glows, lights...");
	// portals
	for (u32 I=0; I<portals.size(); I++)
	{
		b_portal &P = portals[I];
		R_ASSERT(u32(P.sector_front)<g_sectors.size());
		R_ASSERT(u32(P.sector_back) <g_sectors.size());
		g_sectors[u32(P.sector_front)]->add_portal	(u16(I));
		g_sectors[u32(P.sector_back)]->add_portal		(u16(I));
	}
	// glows
	for (u32 I=0; I<glows.size(); I++)
	{
		b_glow		&G = glows[I];
		b_material	&M = materials[G.dwMaterial];
		R_ASSERT(M.sector<g_sectors.size());
		g_sectors[M.sector]->add_glow			(u16(I));
	}
	// lights
	for (u32 I=0; I<L_dynamic.size(); I++)
	{
		b_light_dynamic	&L = L_dynamic[I];
		if (L.data.type == D3DLIGHT_DIRECTIONAL)
		{
			for (u32 j=0; j<g_sectors.size(); j++)
			{
				R_ASSERT(g_sectors[j]);
				g_sectors[j]->add_light(u16(I));
			}
		} else {
			if	(L.sectors.size()) {
				for (u32 j=0; j<L.sectors.size(); j++)
				{
					R_ASSERT	(L.sectors[j]<g_sectors.size());
					g_sectors	[L.sectors[j]]->add_light(u16(I));
				}
			} else {
				clMsg("F**k!!! Light at position %f,%f,%f non associated!!!",
					L.data.position.x,L.data.position.y,L.data.position.z
					);
			}
		}
	}
}
Beispiel #25
0
void CBuild::xrPhase_UVmap()
{
	// Main loop
	Status					("Processing...");
	lc_global_data()->g_deflectors().reserve	(64*1024);
	float		p_cost	= 1.f / float(g_XSplit.size());
	float		p_total	= 0.f;
	vecFace		faces_affected;
	for (int SP = 0; SP<int(g_XSplit.size()); SP++) 
	{
		Progress			(p_total+=p_cost);
		
		// ManOwaR, unsure:
		// Call to IsolateVertices() looks useless here
		// Calculation speed up, so commented
		// IsolateVertices		(FALSE);
		
		// Detect vertex-lighting and avoid this subdivision
		R_ASSERT	(!g_XSplit[SP]->empty());
		Face*		Fvl = g_XSplit[SP]->front();
		if (Fvl->Shader().flags.bLIGHT_Vertex) 	continue;	// do-not touch (skip)
		if (!Fvl->Shader().flags.bRendering) 	continue;	// do-not touch (skip)
		if (Fvl->hasImplicitLighting())			continue;	// do-not touch (skip)
		
		//   find first poly that doesn't has mapping and start recursion
		while (TRUE) 
		{
			// Select maximal sized poly
			Face *	msF		= NULL;
			float	msA		= 0;
			for (vecFaceIt it = g_XSplit[SP]->begin(); it!=g_XSplit[SP]->end(); it++)
			{
				if ( (*it)->pDeflector == NULL ) {
					float a = (*it)->CalcArea();
					if (a>msA) {
						msF = (*it);
						msA = a;
					}
				}
			}
			if (msF) {

				CDeflector *D = xr_new<CDeflector>();
				lc_global_data()->g_deflectors().push_back	(D);
				// Start recursion from this face
				start_unwarp_recursion();
				D->OA_SetNormal	(msF->N);
				
				msF->OA_Unwarp			(D);
				//Deflector  = D;
				// break the cycle to startup again
				D->OA_Export	();
				
				// Detach affected faces
				faces_affected.clear	();
				for (int i=0; i<int(g_XSplit[SP]->size()); i++) {
					Face *F = (*g_XSplit[SP])[i];
					if ( F->pDeflector == D ) {
						faces_affected.push_back(F);
						g_XSplit[SP]->erase		(g_XSplit[SP]->begin()+i); 
						i--;
					}
				}
				
				// detaching itself
				Detach				(&faces_affected);
				g_XSplit.push_back	(xr_new<vecFace> (faces_affected));
			} else {
				if (g_XSplit[SP]->empty()) 
				{
					xr_delete		(g_XSplit[SP]);
					g_XSplit.erase	(g_XSplit.begin()+SP);
					SP--;
				}
				// Cancel infine loop (while)
				break;
			}
		}
	}
	clMsg("%d subdivisions...",g_XSplit.size());
	err_save		();
}
Beispiel #26
0
void CBuild::BuildCForm	()
{
	// Collecting data
	Phase		("CFORM: creating...");
	vecFace*	cfFaces		= new vecFace();
	vecVertex*	cfVertices	= new vecVertex();
	{
		xr_vector<bool>			cfVertexMarks;
		cfVertexMarks.assign	(lc_global_data()->g_vertices().size(),false);

		Status("Sorting...");
		std::sort(lc_global_data()->g_vertices().begin(),lc_global_data()->g_vertices().end());

		Status("Collecting faces...");
		cfFaces->reserve	(lc_global_data()->g_faces().size());
		for (vecFaceIt I=lc_global_data()->g_faces().begin(); I!=lc_global_data()->g_faces().end(); ++I)
		{
			Face* F = *I;
			if (F->Shader().flags.bCollision) 
			{
				cfFaces->push_back(F);
				int index = GetVertexIndex(F->v[0]);
				cfVertexMarks[index] = true;

				index = GetVertexIndex(F->v[1]);
				cfVertexMarks[index] = true;

				index = GetVertexIndex(F->v[2]);
				cfVertexMarks[index] = true;
			}
		}

		Status("Collecting vertices...");
		cfVertices->reserve	(lc_global_data()->g_vertices().size());
		std::sort(cfFaces->begin(),cfFaces->end());
		for (u32 V=0; V<lc_global_data()->g_vertices().size(); V++)
			if (cfVertexMarks[V]) cfVertices->push_back(lc_global_data()->g_vertices()[V]);
	}

	float	p_total = 0;
	float	p_cost  = 1.f/(cfVertices->size());
	
	Fbox BB; BB.invalidate();
	for (vecVertexIt it = cfVertices->begin(); it!=cfVertices->end(); it++)
		BB.modify((*it)->P );

	// CForm
	Phase	("CFORM: collision model...");
	Status	("Items to process: %d", cfFaces->size());
	p_total = 0;
	p_cost  = 1.f/(cfFaces->size());

	// Collect faces
	CDB::CollectorPacked CL	(BB,cfVertices->size(),cfFaces->size());
	for (vecFaceIt F = cfFaces->begin(); F!=cfFaces->end(); F++)
	{
		Face*	T = *F;

		TestEdge	(T->v[0],T->v[1],T);
		TestEdge	(T->v[1],T->v[2],T);
		TestEdge	(T->v[2],T->v[0],T);

		CL.add_face	(
			T->v[0]->P, T->v[1]->P, T->v[2]->P,
			T->dwMaterialGame, materials()[T->dwMaterial].sector, T->sm_group
			);
		Progress(p_total+=p_cost);		// progress
	}
	if (bCriticalErrCnt) {
		err_save	();
		clMsg		("MultipleEdges: %d faces",bCriticalErrCnt);
	}
	xr_delete		(cfFaces);
	xr_delete		(cfVertices);

	// Models
	Status			("Models...");
	for (u32 ref=0; ref<mu_refs().size(); ref++)
		mu_refs()[ref]->export_cform_game(CL);

	// Simplification
	if (g_params().m_quality!=ebqDraft)
		SimplifyCFORM	(CL);

	// bb?
	BB.invalidate	();
	for (size_t it = 0; it<CL.getVS(); it++)
		BB.modify( CL.getV()[it] );

	// Saving
	string_path		fn;
	IWriter*		MFS	= FS.w_open	(strconcat(sizeof(fn),fn,pBuild->path,"level.cform"));
	Status			("Saving...");

	// Header
	hdrCFORM hdr;
	hdr.version		= CFORM_CURRENT_VERSION;
	hdr.vertcount	= (u32)CL.getVS();
	hdr.facecount	= (u32)CL.getTS();
	hdr.aabb		= BB;
	MFS->w			(&hdr,sizeof(hdr));

	// Data
	MFS->w			(CL.getV(),(u32)CL.getVS()*sizeof(Fvector));
	MFS->w			(CL.getT(),(u32)CL.getTS()*sizeof(CDB::TRI));

	// Clear pDeflector (it is stored in the same memory space with dwMaterialGame)
	for (vecFaceIt I=lc_global_data()->g_faces().begin(); I!=lc_global_data()->g_faces().end(); I++)
	{
		Face* F			= *I;
		F->pDeflector	= NULL;
	}

	FS.w_close		(MFS);
}
Beispiel #27
0
void CBuild::BuildPVS()
{
	Fvector size;
	Fvector pos;
	Fvector	ground_dir;

	Status("Preparing...");

	g_TREE_ROOT->bbox.getsize(size);
	g_pvs_X = iROUND(ceilf(size.x/g_params.m_sample_step))+1;
	g_pvs_Y = iROUND(ceilf(size.y/g_params.m_sample_step))+1;
	g_pvs_Z = iROUND(ceilf(size.z/g_params.m_sample_step))+1;
	clMsg("Ceiling dimensions: [%3d,%3d,%3d]",g_pvs_X, g_pvs_Y, g_pvs_Z);

	// ground pick setup
	XRC.RayMode			(RAY_ONLYFIRST|RAY_CULL);
	ground_dir.set		(0,-1,0);

	// reserve memory
	CFS_File			pvs_map		("pvs.temp");
	u32				dwSlot		= 0;
	u32				dwSlotsTotal= g_pvs_X*g_pvs_Y*g_pvs_Z;
	u32	pvs_reserve	= dwSlotsTotal/1024 + 512;
	clMsg("PVS: %d M",	(pvs_reserve*sizeof(vecW))/(1024*1024));
	g_pvs.reserve		(pvs_reserve);

	// begin!
	Status("Processing...");
	u32				dwStartTime	= timeGetTime();
	for (int z=0; z<g_pvs_Z; z++) {
		for (int x=0; x<g_pvs_X; x++) {
			for (int y=0; y<g_pvs_Y; y++)
			{
				pos.set(x,y,z);
				pos.mul(g_params.m_sample_step);
				pos.add(g_TREE_ROOT->bbox.min);
				dwSlot++;
				
				// ground pick
				XRC.RayPick(precalc_identity,1.f,&RCAST_Model,pos,ground_dir,g_params.m_sample_break);
				if (XRC.GetRayContactCount()==0)
				{
					// don't calculate PVS for this point
					int tmp = -1;
					pvs_map.write(&tmp,4);
					continue;
				}

				// Sample PVS data
				g_TREE_ROOT->VisUnroll(pos,g_selected);
				if (!g_selected.empty()) {
					g_result.resize(g_selected.size());
					ZeroMemory(g_result.begin(),g_result.size()*sizeof(BOOL));
					ORM_Process(g_selected.size(),pos,g_selected.begin(),g_result.begin());
					
					// Exclude invisible
					for (int i=0; i<g_selected.size(); i++)
					{
						if (!g_result[i]) {
							if (g_tree[g_selected[i]]->isPatch) continue;
							g_selected.erase(g_selected.begin()+i);
							g_result.erase(g_result.begin()+i);
							i--;
						}
					}
				}
				
				// Compress and record PVS sample
				pvs_map.w_u32(CompressSelected());
				g_selected.clear();

				// Statistic
				if (dwSlot%64 == 63)
				{
					Progress(float(dwSlot)/float(dwSlotsTotal));
					u32 dwCurrentTime = timeGetTime();
					Status("Sample #%d\nSpeed %3.1f samples per second\nPVS entrys: %d",
						dwSlot,1000.f*float(dwSlot)/float(dwCurrentTime-dwStartTime),
						g_pvs.size()
						);

				}
			}
		}
	}
	ORM_Destroy();
	clMsg("* PVS entrys:  %d",	g_pvs.size());
	clMsg("* Aver. Speed: %3.1f",	1000.f*float(dwSlot)/float(timeGetTime()-dwStartTime));
}
Beispiel #28
0
void CBuild::PreOptimize()
{
	// We use overlapping hash table to avoid boundary conflicts
	vecVertex*			HASH	[HDIM_X+1][HDIM_Y+1][HDIM_Z+1];
	Fvector				VMmin,	VMscale, VMeps, scale;
	
	// Calculate offset,scale,epsilon
	Fbox				bb = scene_bb;
	VMscale.set			(bb.max.x-bb.min.x, bb.max.y-bb.min.y, bb.max.z-bb.min.z);
	VMmin.set			(bb.min);
	VMeps.set			(VMscale.x/HDIM_X/2,VMscale.y/HDIM_Y/2,VMscale.z/HDIM_Z/2);
	VMeps.x				= (VMeps.x<EPS_L)?VMeps.x:EPS_L;
	VMeps.y				= (VMeps.y<EPS_L)?VMeps.y:EPS_L;
	VMeps.z				= (VMeps.z<EPS_L)?VMeps.z:EPS_L;
	scale.set			(float(HDIM_X),float(HDIM_Y),float(HDIM_Z));
	scale.div			(VMscale);
	
	u32	Vcount		= lc_global_data()->g_vertices().size(),	Vremoved=0;
	u32	Fcount		= lc_global_data()->g_faces().size(),		Fremoved=0;
	
	// Pre-alloc memory
	int		_size	= (HDIM_X+1)*(HDIM_Y+1)*(HDIM_Z+1);
	int		_average= (Vcount/_size)/2;	if (_average<2)	_average = 2;
	{
		for (int ix=0; ix<HDIM_X+1; ix++)
			for (int iy=0; iy<HDIM_Y+1; iy++)
				for (int iz=0; iz<HDIM_Z+1; iz++)
				{
					HASH[ix][iy][iz] = new vecVertex();
					HASH[ix][iy][iz]->reserve	(_average);
				}
	}
	
	// 
	Status("Processing...");
	g_bUnregister		= false;
	for (int it = 0; it<(int)lc_global_data()->g_vertices().size(); it++)
	{
		if (0==(it%100000)) {
			Progress(_sqrt(float(it)/float(lc_global_data()->g_vertices().size())));
			Status	("Processing... (%d verts removed)",Vremoved);
		}

		if (it>=(int)lc_global_data()->g_vertices().size()) break;

		Vertex	*pTest	= lc_global_data()->g_vertices()[it];
		Fvector	&V		= pTest->P;

		// Hash
		u32 ix,iy,iz;
		ix = iFloor		((V.x-VMmin.x)*scale.x);
		iy = iFloor		((V.y-VMmin.y)*scale.y);
		iz = iFloor		((V.z-VMmin.z)*scale.z);
		R_ASSERT		(ix<=HDIM_X && iy<=HDIM_Y && iz<=HDIM_Z);
		vecVertex &H	= *(HASH[ix][iy][iz]);

		// Search similar vertices in hash table
		for (vecVertexIt T=H.begin(); T!=H.end(); T++)
		{
			Vertex *pBase = *T;
			if (pBase->similar(*pTest,g_params().m_weld_distance)) 
			{
				while(pTest->m_adjacents.size())	
					pTest->m_adjacents.front()->VReplace(pTest, pBase);

				lc_global_data()->destroy_vertex(lc_global_data()->g_vertices()[it]);
				Vremoved			+= 1;
				pTest				= NULL;
				break;
			}
		}
		
		// If we get here - there is no similar vertices - register in hash tables
		if (pTest) 
		{
			H.push_back	(pTest);

			u32 ixE,iyE,izE;
			ixE = iFloor((V.x+VMeps.x-VMmin.x)*scale.x);
			iyE = iFloor((V.y+VMeps.y-VMmin.y)*scale.y);
			izE = iFloor((V.z+VMeps.z-VMmin.z)*scale.z);
			R_ASSERT(ixE<=HDIM_X && iyE<=HDIM_Y && izE<=HDIM_Z);

			if (ixE!=ix)							HASH[ixE][iy][iz]->push_back		(pTest);
			if (iyE!=iy)							HASH[ix][iyE][iz]->push_back		(pTest);
			if (izE!=iz)							HASH[ix][iy][izE]->push_back		(pTest);
			if ((ixE!=ix)&&(iyE!=iy))				HASH[ixE][iyE][iz]->push_back		(pTest);
			if ((ixE!=ix)&&(izE!=iz))				HASH[ixE][iy][izE]->push_back		(pTest);
			if ((iyE!=iy)&&(izE!=iz))				HASH[ix][iyE][izE]->push_back		(pTest);
			if ((ixE!=ix)&&(iyE!=iy)&&(izE!=iz))	HASH[ixE][iyE][izE]->push_back		(pTest);
		}
	}
	
	Status("Removing degenerated/duplicated faces...");
	g_bUnregister	= false;
	for (u32 it=0; it<lc_global_data()->g_faces().size(); it++)
	{
		R_ASSERT		(it>=0 && it<(int)lc_global_data()->g_faces().size());
		Face* F			= lc_global_data()->g_faces()[it];
		if ( F->isDegenerated()) {
			lc_global_data()->destroy_face	(lc_global_data()->g_faces()[it]);
			Fremoved			++;
		} else {
			// Check validity
			F->Verify			( );
		}
		Progress	(float(it)/float(lc_global_data()->g_faces().size()));
	}
	if (InvalideFaces())	
	{
		err_save		();
		xrDebug::Fatal		(DEBUG_INFO,"* FATAL: %d invalid faces. Compilation aborted",InvalideFaces());
	}

	Status				("Adjacency check...");
	g_bUnregister		= false;

	for (u32 it = 0; it<lc_global_data()->g_vertices().size(); ++it)
	{
		if (lc_global_data()->g_vertices()[it] && (lc_global_data()->g_vertices()[it]->m_adjacents.empty()))
		{
			lc_global_data()->destroy_vertex	(lc_global_data()->g_vertices()[it]);
			++Vremoved;
		}
	}
	
	Status				("Cleanup...");
	lc_global_data()->g_vertices().erase	(std::remove(lc_global_data()->g_vertices().begin(),lc_global_data()->g_vertices().end(),(Vertex*)0),lc_global_data()->g_vertices().end());
	lc_global_data()->g_faces().erase		(std::remove(lc_global_data()->g_faces().begin(),lc_global_data()->g_faces().end(),(Face*)0),lc_global_data()->g_faces().end());
	{
		for (int ix=0; ix<HDIM_X+1; ix++)
			for (int iy=0; iy<HDIM_Y+1; iy++)
				for (int iz=0; iz<HDIM_Z+1; iz++)
				{
					xr_delete(HASH[ix][iy][iz]);
				}
	}
	mem_Compact			();
	clMsg("%d vertices removed. (%d left)",Vcount-lc_global_data()->g_vertices().size(),lc_global_data()->g_vertices().size());
	clMsg("%d faces removed. (%d left)",   Fcount-lc_global_data()->g_faces().size(),   lc_global_data()->g_faces().size());
	
	// -------------------------------------------------------------
	/*
	int		err_count	=0 ;
	for (int _1=0; _1<g_faces.size(); _1++)
	{
		Progress(float(_1)/float(g_faces.size()));
		for (int _2=0; _2<g_faces.size(); _2++)
		{
			if (_1==_2)		continue;
			if (FaceEqual(*g_faces[_1],*g_faces[_2]))	{
				err_count	++;
			}
		}
	}
	clMsg		("! duplicate/same faces found:%d",err_count);
	*/
	// -------------------------------------------------------------
}
Beispiel #29
0
void CBuild::MergeLM()
{
	vecDefl		Layer;
	vecDefl		deflNew;
	vecDefl		SEL;

	Status("Processing...");
	for (u32 light_layer=0; light_layer<pBuild->lights.size(); light_layer++)
	{
		// Select all deflectors, which contain this light-layer
		Layer.clear	();
		b_light*	L_base	= pBuild->lights[light_layer].original;
		for (int it=0; it<(int)g_deflectors.size(); it++)
		{
			if (g_deflectors[it].bMerged)				continue;
			if (0==g_deflectors[it].GetLayer(L_base))	continue;	
			Layer.push_back	(g_deflectors[it]);
		}
		if (Layer.empty())	continue;
		
		// Resort layer


		// Merge this layer
		while (Layer.size()) 
		{
			// Sort layer (by material and distance from "base" deflector)
			Deflector	= Layer[0];
			std::sort	(Layer.begin()+1,Layer.end(),cmp_defl);

			// Select first deflectors which can fit
			int maxarea = lmap_size*lmap_size*6;	// Max up to 6 lm selected
			int curarea = 0;
			for (it=1; it<(int)Layer.size(); it++)
			{
				int		defl_area	= Layer[it]->GetLayer(L_base)->Area();
				if (curarea + defl_area > maxarea) break;
				curarea		+=	defl_area;
				SEL.push_back(Layer[it]);
			}
			if (SEL.empty()) 
			{
				// No deflectors found to merge
				// Simply transfer base deflector to _new list
				deflNew.push_back(Deflector);
				g_deflectors.erase(g_deflectors.begin());
			} else {
				// Transfer rects
				SEL.push_back(Deflector);
				for (int K=0; K<(int)SEL.size(); K++)
				{
					_rect	T; 
					T.a.set	(0,0);
					T.b.set	(SEL[K]->lm.dwWidth+2*BORDER-1, SEL[K]->lm.dwHeight+2*BORDER-1);
					T.iArea = SEL[K]->iArea;
					selected.push_back	(T);
					perturb.push_back	(K);
				}
				
				// Sort by size decreasing and startup
				std::sort			(perturb.begin(),perturb.end(),cmp_rect);
				InitSurface			();
				int id				= perturb[0];
				_rect &First		= selected[id];
				_rect_register		(First,SEL[id],FALSE);
				best.push_back		(First);
				best_seq.push_back	(id);
				brect.set			(First);
				
				// Process 
				collected.reserve	(SEL.size());
				for (int R=1; R<(int)selected.size(); R++) 
				{
					int ID = perturb[R];
					if (_rect_place(selected[ID],SEL[ID])) 
					{
						brect.Merge			(collected.back());
						best.push_back		(collected.back());
						best_seq.push_back	(ID);
					}
					Progress(float(R)/float(selected.size()));
				}
				R_ASSERT	(brect.a.x==0 && brect.a.y==0);
				
				//  Analyze resuls
				clMsg("%3d / %3d - [%d,%d]",best.size(),selected.size(),brect.SizeX(),brect.SizeY());
				CDeflector*	pDEFL = new CDeflector();
				pDEFL->lm.bHasAlpha = FALSE;
				pDEFL->lm.dwWidth   = lmap_size;
				pDEFL->lm.dwHeight  = lmap_size;
				for (K = 0; K<(int)best.size(); K++) 
				{
					int			iRealIndex	= best_seq	[K];
					_rect&		Place		= best		[K];
					_point&		Offset		= Place.a;
					BOOL		bRotated;
					b_texture&	T			= SEL[iRealIndex]->lm;
					int			T_W			= (int)T.dwWidth	+ 2*BORDER;
					int			T_H			= (int)T.dwHeight	+ 2*BORDER;
					if (Place.SizeX() == T_W) {
						R_ASSERT(Place.SizeY() == T_H);
						bRotated = FALSE;
					} else {
						R_ASSERT(Place.SizeX() == T_H);
						R_ASSERT(Place.SizeY() == T_W);
						bRotated = TRUE;
					}
					
					// Merge
					pDEFL->Capture		(SEL[iRealIndex],Offset.x,Offset.y,Place.SizeX(),Place.SizeY(),bRotated);
					
					// Destroy old deflector
					vecDeflIt		OLD = std::find(g_deflectors.begin(),g_deflectors.end(),SEL[iRealIndex]);
					VERIFY			(OLD!=g_deflectors.end());
					g_deflectors.erase(OLD);
					xr_delete		(SEL[iRealIndex]);
				}
				pDEFL->Save			();
				deflNew.push_back	(pDEFL);
				
				// Cleanup
				SEL.clear			();
				collected.clear		();
				selected.clear		();
				perturb.clear		();
				best.clear			();
				best_seq.clear		();
				brect.iArea			= INT_MAX;
			}
			Progress(1.f-float(g_deflectors.size())/float(dwOldCount));
		}
	}
	
	R_ASSERT(g_deflectors.empty());
	g_deflectors = deflNew;
	clMsg	("%d lightmaps builded",g_deflectors.size());
}
void	CBuild::xrPhase_ResolveMaterials()
{
	// Count number of materials
	Status		("Calculating materials/subdivs...");
	xr_vector<_counter>	counts;
	{
		counts.reserve		(256);
		for (vecFaceIt F_it=g_faces.begin(); F_it!=g_faces.end(); F_it++)
		{
			Face*	F			= *F_it;
			BOOL	bCreate		= TRUE;
			for (u32 I=0; I<counts.size(); I++)
			{
				if (F->dwMaterial == counts[I].dwMaterial)
				{
					counts[I].dwCount	+= 1;
					bCreate				= FALSE;
					break;
				}
			}
			if (bCreate)	{
				_counter	C;
				C.dwMaterial	= F->dwMaterial;
				C.dwCount		= 1;
				counts.push_back(C);
			}
			Progress(float(F_it-g_faces.begin())/float(g_faces.size()));
		}
	}
	
	Status				("Perfroming subdivisions...");
	{
		g_XSplit.reserve(64*1024);
		g_XSplit.resize	(counts.size());
		for (u32 I=0; I<counts.size(); I++) 
		{
			g_XSplit[I] = xr_new<vecFace> ();
			g_XSplit[I]->reserve	(counts[I].dwCount);
		}
		
		for (vecFaceIt F_it=g_faces.begin(); F_it!=g_faces.end(); F_it++)
		{
			Face*	F							= *F_it;
			if (!F->Shader().flags.bRendering)	continue;

			for (u32 I=0; I<counts.size(); I++)
			{
				if (F->dwMaterial == counts[I].dwMaterial)
				{
					g_XSplit[I]->push_back	(F);
				}
			}
			Progress(float(F_it-g_faces.begin())/float(g_faces.size()));
		}
	}

	Status				("Removing empty subdivs...");
	{
		for (int SP = 0; SP<int(g_XSplit.size()); SP++) 
			if (g_XSplit[SP]->empty())	xr_delete(g_XSplit[SP]);
		g_XSplit.erase(std::remove(g_XSplit.begin(),g_XSplit.end(),(vecFace*) NULL),g_XSplit.end());
	}
	
	Status				("Detaching subdivs...");
	{
		for (u32 it=0; it<g_XSplit.size(); it++)
		{
			Detach(g_XSplit[it]);
		}
	}
	clMsg				("%d subdivisions.",g_XSplit.size());
}