Dando continuidade à série de posts sobre o meu Trabalho de Conclusão de Curso, vou escrever hoje sobre um erro muito comum que qualquer iniciante pode cometer quando for desenvolver utilizando o .NET CF 2.0 e o Managed Direct3D Mobile.
Para maiores informações sobre o assunto, veja meus outros posts aqui.
- O problema
Em todos os exemplos que desenvolvi até agora, sempre carreguei os objetos a serem desenhados dentro do método Render(), que é chamado no OnPaint() (saiba mais sobre esse conjunto de métodos aqui). Em outras palavras, quando era preciso desenhar, eu criava os objetos e desenhava. Ok, sem problemas à primeira vista, mas e a performance? E se os objetos forem gigantes, vindos de arquivos fonte, que é ainda mais demorado para ler e carregar todas as informações na memória do dispositivo?
Solução: carregar os objetos no início da aplicação e mantê-los em memória para que na hora da renderização não seja necessário carregar coisa alguma. Certo? Errado!
A implementação sugerida acima fica desta maneira:
- Inicialização do Device e do objeto a ser desenhado (Mesh)
private void InitializeGraphics()
{
try
{
PresentParameters presentParams =
new PresentParameters();
presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
// Device
device = new Device(
0,
DeviceType.Default,
this,
CreateFlags.None,
presentParams);
device.RenderState.CullMode = Cull.None;
device.RenderState.Lighting = false;
mesh = Mesh.Box(device, 1, 1, 0);
}
catch (Exception ex)
{
MessageBox.Show("Erro na inicialização: " +
ex.Message);
}
}
- Renderização do Mesh
/// <summary>
/// Render the data
/// </summary>
private void Render()
{
// Clear the device
device.Clear(ClearFlags.Target, Color.White, 1.0f, 0);
// Begin the scene
device.BeginScene();
mesh.DrawSubset(0);
// End the scene and present
device.EndScene();
device.Present();
}
A princípio não há problema algum nessa implementação. Porém, ao executá-la a seguinte exception (System.ObjectDisposedException) é lançada na chamada do método mesh.DrawSubset(0):
Ora pois, se criei o Mesh e mandei o Device desenhá-lo não deveria acontecer este problema… mas isso aqui é computação, esqueceu? Faz parte do show.
- A Solução
Ao invés de criar o objeto Mesh logo após a criação do Device, devemos criá-lo quando o Device é reiniciado.
Por que hããm? Pois antes de renderizar as informações, o Device é reiniciado e perde todas as definições que o Mesh tinha quando foi criado.
Como resolver este problema? Simples:
- Alterar a criação do device (repare no evento OnDeviceReset)
private void InitializeGraphics()
{
try
{
PresentParameters presentParams =
new PresentParameters();
presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
// Device
device = new Device(
0,
DeviceType.Default,
this,
CreateFlags.None,
presentParams);
device.RenderState.CullMode = Cull.None;
device.RenderState.Lighting = false;
device.DeviceReset += new EventHandler(OnDeviceReset);
}
catch (Exception ex)
{
MessageBox.Show("Erro na inicialização: " +
ex.Message);
}
}
- Criar o Mesh quando o Device for reiniciado
protected void OnDeviceReset(object sender, EventArgs e)
{
mesh = Mesh.Box(device, 1, 1, 0);
}
Discretamente vou dar um palpite da origem do erro: todas as informações do Mesh (VertexBuffer, IndexBuffer, etc) ficam na memória do Device. Assim que é reiniciado essas informações são apagadas, conforme descrito em um post anterior.
É isso ae! Até +.