Olá a todos, continuando a série de artigos, hoje vou falar sobre um dos novos templates disponíveis no Visual Studio para a versão Mango, o “Rich Graphics Application” (conhecido na versão beta anterior como “3d graphics application”), que permite ao desenvolvedor renderizar XNA e Silverlight na mesma aplicação. Até agora (versão 7.0) era possível escolher entre XNA ou Silverlight, e sim, até era possível algumas misturas, como utilizar a API de microfone ou touch input do XNA em uma aplicação Silverlight, mas na hora dos gráficos, você precisava escolher. Ou desenvolvia algo em XNA e teria complicações para renderização de texto, integração com IE, vídeos, etc.. Ou então partia para uma app Silverlight, mas tinha algumas dificuldades (e impossibilidades) de usar gráficos 3d ou mesmo criar “cenas” e loops bacanas em sua app. Agora o novo template permita que tudo seja feito em uma app só. É possível ter um xaml renderizando Silverlight, navegar para um segundo xaml renderizando apenas XNA e em um terceiro ter uma mistura dos dois. Vamos ver alguns pontos teóricos onde isso se torna possível
O TEMPLATE
Nos templates, verá que pode escolher o “Rich Graphics Application”. É o template que vou detalhar para vocês.

Figura 1 – o template
Ao criar o projeto, você verá algumas coisas interessantes. O projeto é composto por um MainPage.xaml que apenas tem um botão. Esse xaml, assim como essa aplicação, é Silverlight e exatamente o que já conhecemos como desenvolvedores Silverlight.

Figura 2 – a página inicial é XAML Silverlight que todos conhecemos
É importante que o desenvolvedor entenda que usar esse template significa criar uma aplicação Silverlight e adicionar uma renderização XNA onde desejar. Então todos os conceitos e estrutura continuam funcionando da mesma maneira. Teremos nosso app.xaml, MainPage.xaml, vamos seguir as lógicas e tudo que já existe no Silverlight.
A Mudança inicial vem quando você clica no botão. A aplicação navega para uma segunda página, GamePage.xaml, que será um xaml renderizando APENAS XNA. Ou seja, nesse momento o Silverlight ira sair de cena, o WP7 O.S. irá liberar o máximo possível de memória e trará o XNA para a tela. Legal, mas onde está meu conteúdo XNA? Olhando o solution explorer você entenderá

Figura 3 – Solution explorer com projeto XNA referenciado
Conforme você pode notar no Solution explorer, o XNA é adicionado como um projeto a parte e depois referenciado no projeto Silverlight. Então fica claro que estamos criando nossas texturas e o que precisarmos no XNA, depois o consumindo no Silverlight. Entenda como diversas camadas sendo “desenhadas” na tela. A figura abaixo mostra como isso acontece em uma tela renderizando Silverlight e XNA.

Figura 4 – as camadas em uma renderização XNA + SL
Legal, mas e como a página “GamePage” consegue renderizar XNA? E como é o código xmal dessa página?
Em uma página 100% renderizada em XNA não há código! O código completo do GamePage.xaml (no início e mesmo após você adicionar qualquer conteúdo XNA) é esse:
1: <phone:PhoneApplicationPage
2: x:Class="GraphicsApp1.GamePage"
3: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5: xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
6: xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
7: xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
8: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9: FontFamily="{StaticResource PhoneFontFamilyNormal}"
10: FontSize="{StaticResource PhoneFontSizeNormal}"
11: Foreground="{StaticResource PhoneForegroundBrush}"
12: SupportedOrientations="Portrait" Orientation="Portrait"
13: mc:Ignorable="d" d:DesignHeight="800" d:DesignWidth="480"
14: shell:SystemTray.IsVisible="False">
15:
16: <!--No XAML content is required as the page is rendered entirely with the XNA Framework-->
17:
18: </phone:PhoneApplicationPage>
19:
Ao verificar o code behind GamePage.xaml.cs você tem algumas coisas interessantes e diferentes do que está acostumado, como ContentManager, GameTimer , SpriteBatch ou SharedGraphicsDeviceManager. Mas antes de qualquer coisa, vamos explicar como o XNA renderiza.
Abrindo o arquivo app.xaml há um novo tag:
1: <xna:SharedGraphicsDeviceManager />
É esse o responsável por fazer a mágica e trazer o XNA do nível mais baixo para a sua aplicação. Como o SharedGraphicsDeviceManager implementa a interface IApplicationLifetimeAware , você o verá como parte dos seus Application.ApplicationLifetimeObjects . Isso é o que possibilita renderizarmos XNA na nossa GamePage. É o SharedGraphicsDeviceManager que vai fazer o motor do XNA acontecer.
Bacana Rodo, mas e aí? Sei que “é possível” renderizar na página, mas aquele XAML não tem nada! Como é que estamos realmente “ligando” o XNA e colocando nosso conteúdo (seja ele qual for) para rodar na página?
Voltando ao code behind do “GamePage”, é importante sempre lembrar do nosso OnNavigatedTo , que é o evento que irá ser disparado quando a navegação chegar na página. Ou seja, toda vez que formos acessar a nossa GamePage, esse evento ocorre. Então, lá nesse evento, o seguinte código é adicionado:
1: protected override void OnNavigatedTo(NavigationEventArgs e)
2: {
3: SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);
4: spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);
5: // aqui colocamos o código para carregar o conteúdo XNA que quisermos.
6: timer.Start();
7: base.OnNavigatedTo(e);
8: }
O código contém a grande mágica, que é a linha onde usamos o SharedGraphicsDeviceManager . É ali que estamos dizendo à aplicação que queremos usar o XNA. O método SetSharingMode nos permite isso. Após isso iremos usar o XNA para desenhar e carregar o que quisermos na tela, como por exemplo:
1: ContentManager appContent = new ContentManager(app, "Content");
2: fundo = appContent.Load<Texture2D>("background");
A segunda parte da mágica ocorre no evento OnDraw, que irá realmente montar os layers na tela. Lá é onde se tornará possível, por exemplo, ter código XAML sendo renderizado junto com o XNA.
1: SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);
2: spriteBatch.Begin();
3: spriteBatch.Draw(background, Vector2.Zero, Color.White);
4: spriteBatch.End();
Aqui limpamos o buffer e depois iremos colocar os layers na tela. Se fôssemos utilizar uma tela com XNA + Silverlight, precisamos explicitamente dizer que queremos renderizar o nosso Silverlight (imaginem que tenhamos adicionado código XAML para termos botões, grids, etc..). Como vocês viram, quando renderizamos XNA, não precisamos (nem iremos) ter nenhum código XAML. Quando adicionarmos código XAML para renderizar Silverlight em uma página, ele simplesmente não aparecerá se o seu SetSharingMode estiver como true. Para renderizar Silverlight + XNA é necessário usar o UIElementRenderer , que vai renderizar um UIElement qualquer do Silverlight junto com o XNA.
É O UIElementeRenderer que possibilita , então, a integração entre ambas as tecnologias. Os conceitos ficam mais ou menos divididos como SharedGraphicsDeviceManager permite que possamos acessar e ligar os motores do XNA em uma aplicação Silverlight, SetSharingMode é o cara que irá nos informar que desejamos renderizar XNA naquela página (e que queremos tirar o Silverlight de cena, por isso mesmo que tenhamos botões e controles Silverlight eles não irão aparecer) e o UIElementeRenderer é o que possibilitará a renderização de ambas as tecnologias. É com esse cara que iremos unir nossos layers, criar as camadas e as desenhar na tela como algo único para o usuário final.
No código acima, por exemplo, iríamos simplesmente adicionar mais uma linha de “Draw” para o Silverlight, montando nossos layers da forma como preferirmos. Se você “desenhar” o XNA primeiro, ele aparece por baixo do Silverlight, e vice versa.
Espero que essa explicação de conceitos do novo template tenha os ajudado um pouco a entender esse que é um dos novos conceitos do mango e que causam um pouco de confusão. Acredito que nesse assunto o mais complicado, muito mais do que entender códigos e demos, é entender como XNA + SL funcionam juntos e, mais do que isso, qual a necessidade do template.
Devo admitir que o código envolvido para fazer as tecnologias se conversarem é simples e a parte complexa fica para o XNA, o qual demanda uma veia artística que esse que vos fala inclusive não possui. O grande porém é que, apesar de simples, são conceitos um pouco diferentes e que demandam entender algumas coisas diferentes do que estamos acostumados a ver no Silverlight. Mas nada que uma demo simples caseira com quadrados e circunferências não resolva! Faça o teste e me conte!
Abraços!