You can make a game that sets the proper profile with just a few lines :
-First make sure that that you set the Reach profile for your Game, in the property tab.
-Next in your Game constructor after the GraphicDeviceManager was created handle the .PreparingDeviceSettings event on the newly created device manager.
graphics = new GraphicsDeviceManager(this);
//This event is called when the device is created,reseated or recreated so it's the perfect place to set the profile.
graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
-In the handling function simply iterate trough all the available devices and select the one that satisfies your needs.
#if !FORCE_REACH
for (int i = 0; i < GraphicsAdapter.Adapters.Count; i++)
{
if (GraphicsAdapter.Adapters[i].IsProfileSupported(GraphicsProfile.HiDef))
{
e.GraphicsDeviceInformation.Adapter = GraphicsAdapter.Adapters[i];
e.GraphicsDeviceInformation.GraphicsProfile = GraphicsProfile.HiDef;
IsHiDef = true;
return;
}
}
#endif
for (int i = 0; i < GraphicsAdapter.Adapters.Count; i++)
{
if (GraphicsAdapter.Adapters[i].IsProfileSupported(GraphicsProfile.Reach))
{
e.GraphicsDeviceInformation.Adapter = GraphicsAdapter.Adapters[i];
e.GraphicsDeviceInformation.GraphicsProfile = GraphicsProfile.Reach;
IsHiDef = false;
return;
}
}
-To work around the fact that we can't have ContentProjects with different profiles we can create little projects with different profiles that reference the content projects specific for each content type and reference those project in our main game.
That's all you have to do, now if you want to simplify the way you load content and not bother with the type of the content you are loading you can create a ContentManager that is aware of the current GraphicProfile, for this :
-Create a new class that inherits from ContentManage.
-Create a new constructor that takes as parameters an instance of the IServiceProvider and 3 strings for the different kind of assets we need(Common,HiDef and Reach)
public ContentManager2(IServiceProvider services, string commonAssetRoot, string hiDefAssetRoot, string reachAssetRoot)
: base(services)
{
this.commonAssetRoot = commonAssetRoot;
this.hiDefAssetRoot = hiDefAssetRoot;
this.reachAssetRoot = reachAssetRoot;
}
-Then create a method that can detect if the current device is a HiDef device.
private IGraphicsDeviceService graphicsDeviceService;
private bool? usingHiDeffDevice;
/// <summary>
/// Returns true if the current graphic device supports the HiDef profile.
/// </summary>
public bool IsHiDef
{
get
{
if (graphicsDeviceService == null)
{
graphicsDeviceService = this.ServiceProvider.GetService(typeof(IGraphicsDeviceService)) as IGraphicsDeviceService;
if (graphicsDeviceService == null)
{
throw new Exception("No GraphicDevice available!!!");
}
}
if (usingHiDeffDevice == null)
{
usingHiDeffDevice = graphicsDeviceService.GraphicsDevice.Adapter.IsProfileSupported(GraphicsProfile.HiDef);
}
#if FORCE_REACH
return false;
#endif
return usingHiDeffDevice.Value;
}
}
-Next we need to change the Load() method.
public override T Load<T>(string assetName)
{
try
{
return base.Load<T>(commonAssetRoot + "\\" + assetName);
}
catch
{
if (IsHiDef)
{
return base.Load<T>(hiDefAssetRoot + "\\" + assetName);
}
else
{
return base.Load<T>(reachAssetRoot + "\\" + assetName);
}
}
}
-We will have to change the default ContentManager that comes with the Game class with ours so in the Game class constructor we will.
-And we are done now if we need an asset we will load it like with a standard ContentManager
-Here is a project set using what I was talking about, it's on SkyDrive so if you have an account and you are not logged you might not see it :
MultipleTargetProject
-To force the load in Reach profile you must define FORCE_REACH :
-As a last note if you use this method always test your game with and without forcing the Reach profile.


Your post here just saved my sanity. Thank you so much for this :)
ReplyDelete