Monday, August 2, 2010

XNA 4 Beta

Microsoft's been pushing Windows Phone 7 development quite hard for the past few months. The XNA and Silverlight teams have been pushing out news, examples and generally evangelizing it. I don't have much interest in phone development yet, but the latest version of the Windows Phone 7 SDK included the XNA beta (and is the only place to download it). The team's been hard at work updating XNA for greater cross-platform development and cleaning up some of the oddities in the API. In switching OTD over to the beta, I found a fair number of issues that either haven't been implemented or just moved somewhere new. I actually gave up after a while and started up a new dummy project to walk through the basics and start from a cleaner code base.

Changes

This is by no means a comprehensive list, but a short list of things that I've encountered and my solutions (if any) so far.

  • Content folder is now a separate project by default. Cool, this works, no problem here.
  • BasicEffect no longer uses SetParameter, but rather all parameters are properties.

BasicEffect

Shawn Hargreaves talks about two changes to Basic Effect:

Rendering Sample

Below is a simple object generated from the pipeline and consists of just a VertexBuffer and IndexBuffer. We reference the BasicEffect and Graphics Device statically. View, World, and Projection are much simpler as properties now. Within the effect pass loop, we no longer begin() and end() the effect and passes, but only Apply() each pass at the start. Less code for less mistakes.

The way vertex and index buffers are set on the device has changed as well to a simpler interface. Vertex buffers contain the information of their contained format and a single stream has only on vertex type. We set the length now by number of vertices and indices rather than byte sizes. The call to set the vertex buffer is much simpler.

class Sphere
{
    public VertexBuffer Vertices;
    public IndexBuffer Indices;

     public void Draw(Matrix view, Matrix projection)
     {
         // Set shader projections
         Core.BasicEffect.View = view;
         Core.BasicEffect.World = Matrix.Identity;
         Core.BasicEffect.Projection = projection;

         // Set vertex and index buffers on the device
         Core.GraphicsDevice.SetVertexBuffer(Vertices);
         Core.GraphicsDevice.Indices = Indices;

         foreach (EffectPass pass in Core.BasicEffect.CurrentTechnique.Passes)
         {
             pass.Apply();

             Core.BasicEffect.GraphicsDevice.DrawIndexedPrimitives(
                 PrimitiveType.TriangleList,
                 0,
                 0,
                 Vertices.VertexCount,
                 0,
                 Indices.IndexCount / 3);
         }
     }
 }

Content Pipeline

When building vertex buffers in the pipeline, a few things have changed here as well. Since vertex formats are now embedded in the buffer object, it takes an extra bit of initialization. A new class, VertexBufferContent is now needed.

VertexBufferContent

Building the VertexBufferContent is pretty simple since the information is available in the vertex format - we just need to loop through the VertexElements.

// Generate the VertexDeclarationContent from the VertexElements in our format
VertexDeclarationContent vdc = new VertexDeclarationContent();
foreach (VertexElement ve in VertexPositionColor.VertexDeclaration.GetVertexElements())
{
    vdc.VertexElements.Add(ve);
}

// Set the declaration fors the buffer
Vertices.VertexDeclaration = vdc;

Code

Here's the whole pipeline object that gets processed.

public class SphereContent
{
    public VertexBufferContent Vertices;
    public IndexCollection Indices;

    public SphereContent(int subdivisionLevel)
    {
        Vertices = new VertexBufferContent();
        Indices = new IndexCollection();

        // Generate the vertices
        List<VertexPositionColor> vertices;
        List<int> indices;
        Generate(out vertices, out indices);

        // Generate the VertexDeclarationContent from the VertexElements in our format
        VertexDeclarationContent vdc = new VertexDeclarationContent();
        foreach (VertexElement ve in VertexPositionColor.VertexDeclaration.GetVertexElements())
        {
            vdc.VertexElements.Add(ve);
        }

        // Set the declaration fors the buffer
        Vertices.VertexDeclaration = vdc;

        // Write to the vertex buffer
        Vertices.Write<VertexPositionColor>(
            0, 
            VertexPositionColor.VertexDeclaration.VertexStride, 
            vertices
        );

        // Add indices
        Indices.AddRange(indices);
    }

    private void Generate(out List<VertexPositionColor> vertices, out List<int> indices)
    {
        // Magic!
    }
}

More coming as I explore further.

No comments:

Post a Comment