Formeln

Sunday, May 20, 2012

The Scene Class

Up to now we created a triangle and called its render method in the RenderManager:


public void renderScene()
{
  Renderables.Triangle triangle = new Renderables.Triangle();

  while (true)
  {
    DeviceManager dm = DeviceManager.Instance;
    dm.context.ClearRenderTargetView(dm.renderTarget, new Color4(0.25f, 0.75f, 0.25f));

    triangle.render();
                
    dm.swapChain.Present(0, PresentFlags.None);
  }
}

The Renderable Class


But what you usually want to do is add and remove objects to render dynamically. So we have to have a data structure to hold all our render objects. For the sake of simplicity lets start with a list. To be able to iterate through the List, all renderable objects have to inherit from a base class called Renderable.

So this is the bare minimum we need:


public abstract class Renderable
{
  public abstract void render();
}

Now let us derive our Triangle Class from this abstract class override our render method:


class Triangle : Renderable
{
  ShaderSignature inputSignature;
  VertexShader vertexShader;
  PixelShader pixelShader;
  .
  .
  .


public override void render()
{
  // configure the Input Assembler portion of the pipeline with the vertex data
  DeviceManager.Instance.context.InputAssembler.InputLayout = layout;
  DeviceManager.Instance.context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
  DeviceManager.Instance.context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertexBuffer, 12, 0));

  // set the shaders
  DeviceManager.Instance.context.VertexShader.Set(vertexShader);
  DeviceManager.Instance.context.PixelShader.Set(pixelShader);

  // render the triangle
  DeviceManager.Instance.context.Draw(3, 0);
}

The Scene Class

Now lets add a Singleton Class called Scene. This holds a List of Renderables, a method to add Renderables, a method to remove Renderables and a method to iterate our List to render the objects.
To prevent altering the List while the render-loop is calling the render method, I use the lock Statement.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Apparat.Renderables;

namespace Apparat
{
    public class Scene
    {
        #region Singleton Pattern
        private static Scene instance = null;
        public static Scene Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Scene();
                }
                return instance;
            }
        }
        #endregion

        #region Constructor
        private Scene() { }
        #endregion

        List<Renderable> RenderObjects = new List<Renderable>();

        public void addRenderObject(Renderable renderObject)
        {
            lock (RenderObjects)
            {
                RenderObjects.Add(renderObject);
            }
        }

        public void removeRenderObject(Renderable renderObject)
        {
            lock (RenderObjects)
            {
                if( RenderObjects.Contains( renderObject ))
                {
                    RenderObjects.Remove( renderObject );
                }
            }
        }

        public void render()
        {
            lock (RenderObjects)
            {
                foreach (Renderable renderable in RenderObjects)
                {
                    renderable.render();
                }
            }
        }
    }
}

Using the Scene

Now we can change the code in our renderScene method in our RenderManager to call the render method of our Scene (compare with the first method at the top):

public void renderScene()
{
  while (true)
  {
    DeviceManager dm = DeviceManager.Instance;
    dm.context.ClearRenderTargetView(dm.renderTarget, new Color4(0.25f, 0.75f, 0.25f));

    Scene.Instance.render();
                
    dm.swapChain.Present(0, PresentFlags.None);
  }
}

While we created the triangle at first in our renderScene method, we are now able to add and remove Renderables from our Application!

For example:


public Form1()
{
  InitializeComponent();
  DeviceManager.Instance.createDeviceAndSwapChain(this);
  RenderManager.Instance.init();

  Triangle triangle = new Triangle();
  Scene.Instance.addRenderObject(triangle);
}

You can download the code to this project here:

http://apparat.codeplex.com/SourceControl/changeset/changes/ba452d5587ac

No comments:

Post a Comment