Result::Name RegisterAsPlanarMirror( CCopyEntity& entity, BasicMesh& mesh, int subset_index )
{
	const AABB3& aabb = mesh.GetAABB(subset_index);

	EntityRenderManager& entity_render_mgr
		= *(entity.GetStage()->GetEntitySet()->GetRenderManager());

	// >>> TODO: support planes that are not axis-aligned or facing along the negative half-space
	SPlane plane;
	int plane_axis = 1;
	if(      aabb.vMax.x - aabb.vMin.x < 0.001f ) plane_axis = 0;
	else if( aabb.vMax.y - aabb.vMin.y < 0.001f ) plane_axis = 1;
	else if( aabb.vMax.z - aabb.vMin.z < 0.001f ) plane_axis = 2;
	else plane_axis = 1;

	plane.normal = Vector3(0,0,0);
	plane.normal[plane_axis] = 1;
	plane.dist = aabb.vMax[plane_axis];

	Result::Name res = entity_render_mgr.AddPlanarReflector( EntityHandle<>( entity.Self() ), plane );

	if( res != Result::SUCCESS )
		return Result::UNKNOWN_ERROR;

	entity.RaiseEntityFlags( BETYPE_PLANAR_REFLECTOR );

	// Create shader variable loader for mirror 

	if( !entity.m_pMeshRenderMethod )
	{
		if( entity.pBaseEntity->MeshProperty().m_pMeshRenderMethod )
		{
			entity.m_pMeshRenderMethod
				= entity.pBaseEntity->MeshProperty().m_pMeshRenderMethod->CreateCopy();

			if( !entity.m_pMeshRenderMethod )
				return Result::UNKNOWN_ERROR;
		}
		else
			return Result::UNKNOWN_ERROR;
	}

	// create a planar reflection entity
//	shared_ptr<MeshContainerRenderMethod> pMeshRenderMethodCopy
//		= entity.m_pMeshRenderMethod->CreateCopy();

	shared_ptr<MirroredSceneTextureParam> pTexParam;
	pTexParam.reset( new MirroredSceneTextureParam( EntityHandle<>( entity.Self() ) ) );
	pTexParam->m_fReflection = mesh.GetMaterial(subset_index).m_Mat.fReflection;
//	pMeshRenderMethodCopy->SetShaderParamsLoaderToAllMeshRenderMethods( pTexParam );

	// test - we assume that the entity's mesh is composed of polygons that belong to a single plane.
	entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( pTexParam );

	// Move the indices of the planar reflection subset(s)
	// to the render method of the planar reflection entity

	return Result::SUCCESS;
}
bool RegisterAsMirrorIfReflective( CCopyEntity& entity, BasicMesh& mesh, int subset_index, GenericShaderDesc& shader_desc )
{
	if( mesh.GetMaterial(subset_index).m_Mat.fReflection < 0.001f )
		return false;

	const MeshMaterial& mat = mesh.GetMaterial(subset_index);
	const AABB3& aabb = mesh.GetAABB(subset_index);

	bool subset_triangles_on_plane = false;
	if( aabb.vMax.x - aabb.vMin.x < 0.001f
	 || aabb.vMax.y - aabb.vMin.y < 0.001f
	 || aabb.vMax.z - aabb.vMin.z < 0.001f )
	{
		// The triangles of the i-th subset is on an axis-aligned plane.
		subset_triangles_on_plane = true;
	}
//	else if( IsSubsetTrianglesOnSinglePlane(pMesh,i) )
//	{
//		subset_triangles_on_plane = true;
//	}

	if( subset_triangles_on_plane )
	{
		RegisterAsPlanarMirror( entity, mesh, subset_index );
		shader_desc.PlanarReflection = PlanarReflectionOption::FLAT;
		return true;
	}
	else
	{
		// TODO: Register as an envmap target?
//		entity.RaiseEntityFlags( BETYPE_ENVMAPTARGET );
//		shader_desc.EnvMap = EnvMapOption::ENABLED;
		return false;
	}

	return false;
}
// - Set the world transform 'world_transform' to shader
// - Update shader params
// - Set technique
void MeshContainerRenderMethod::RenderMesh( BasicMesh &mesh, const Matrix34& world_transform )
{
	if( !m_RenderMethodsAndSubsetIndices.empty() )
	{
		if( m_RenderMethodsAndSubsetIndices.size() == 1
		 && m_RenderMethodsAndSubsetIndices[0].second.empty() )
		{
			// render all the subsets at once
			RenderMeshOrMeshSubsets( mesh, m_RenderMethodsAndSubsetIndices[0].second, m_RenderMethodsAndSubsetIndices[0].first, world_transform );
		}
		else
		{
			for( int i=0; i<(int)m_RenderMethodsAndSubsetIndices.size(); i++ )
			{
				SubsetRenderMethod& render_method = m_RenderMethodsAndSubsetIndices[i].first;
				const vector<int>& subset_indices  = m_RenderMethodsAndSubsetIndices[i].second;

				for( int j=0; j<(int)subset_indices.size(); j++ )
				{
					RenderMeshOrMeshSubsets( mesh, subset_indices, render_method, world_transform );
				}
			}
		}
	}
	else if( 0 < m_vecSubsetNameToRenderMethod.size() )
	{
		// render subsets one by one

		// set different shaders / techniques for each subset
		const int num_subsets = mesh.GetNumMaterials();
		std::vector<int> *pvecIndicesOfSubsetsToRender = NULL;
		if( m_vecIndicesOfSubsetsToRender.size() == 0 )
		{
			// render all the subsets
			// - create the full indices list
			// - For the same mesh, this is done only once.
			for( int j=(int)m_vecFullIndicesOfSubsets.size(); j<num_subsets; j++ )
				m_vecFullIndicesOfSubsets.push_back( j );
			pvecIndicesOfSubsetsToRender = &m_vecFullIndicesOfSubsets;
		}
		else
		{
			pvecIndicesOfSubsetsToRender = &m_vecIndicesOfSubsetsToRender;
		}

		int lod_index = 0;
//		for( i=0; i<num_subsets; i++ )
		for( size_t i=0; i<pvecIndicesOfSubsetsToRender->size(); i++ )
		{
			int index = (*pvecIndicesOfSubsetsToRender)[i];

			map< string, SubsetRenderMethod >::iterator itr
				= m_vecSubsetNameToRenderMethod[lod_index].find( mesh.GetMaterial(index).Name );

			if( itr == m_vecSubsetNameToRenderMethod[lod_index].end() )
				continue;

			SubsetRenderMethod& subset_render_method = (*itr).second;

			ShaderManager *pShaderMgr = subset_render_method.m_Shader.GetShaderManager();
			if( !pShaderMgr )
				continue;

			pShaderMgr->SetWorldTransform( world_transform );

			pShaderMgr->SetTechnique( subset_render_method.m_Technique );

			for( size_t j=0; j<subset_render_method.m_vecpShaderParamsLoader.size(); j++ )
			{
				subset_render_method.m_vecpShaderParamsLoader[j]->UpdateShaderParams( *pShaderMgr );
			}

			mesh.RenderSubset( *pShaderMgr, index );

			for( size_t j=0; j<subset_render_method.m_vecpShaderParamsLoader.size(); j++ )
			{
				subset_render_method.m_vecpShaderParamsLoader[j]->ResetShaderParams( *pShaderMgr );
			}
		}
	}
}