/*
* RenderQueue.cs
* Authors: August Zinsser
*
* Copyright August Zinsser 2007
* This program is distributed under the terms of the GNU General Public License
*/
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Pina3D.Particles;
namespace Pina3D
{
///
/// Manages a "queue" of all ColladaModels and particles to be rendered. Automatically sorts the queue for optimal render time.
///
public class RenderQueue
{
public enum BlendMode { Alpha, Additive };
protected Dictionary> mRenderables; // Holds "subqueues" sorted by vertex type to minimize vertex delcarations
protected List mParticlesAlphaBlend;
protected List mParticlesAdditiveBlend;
public int Count
{
get
{
int runningTotal = 0;
foreach (KeyValuePair> kvp in mRenderables)
{
runningTotal += kvp.Value.Count;
}
return runningTotal;
}
}
///
/// Allocates internal variables
///
public RenderQueue()
{
mRenderables = new Dictionary>();
mParticlesAlphaBlend = new List();
mParticlesAdditiveBlend = new List();
}
///
/// Tells each model and particle in the render queue to render itself
///
public void Render()
{
Pina.Graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;
Pina.Graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;
Pina.Graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false;
//Pina.Graphics.GraphicsDevice.RenderState.AlphaBlendOperation = BlendFunction.Add;
//Pina.Graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
//Pina.Graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
//Pina.Graphics.GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = false;
foreach (KeyValuePair> kvp in mRenderables)
{
// TODO: Implement IComparable and then sort the renderables (optimization)
// TODO: Store the sourceData of each Renderable and then render each sourceData once with a list of each Renderable's PinaState (optimization)
// TODO: Support transparent geometry (new feature)
for (int i = 0; i < kvp.Value.Count; i++)
{
kvp.Value[i].Render();
}
}
// "Quality" Alpha Blended (requires back-to-front draw order)
//Pina.Graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;
//Pina.Graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;
//Pina.Graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
//Pina.Graphics.GraphicsDevice.RenderState.AlphaBlendOperation = BlendFunction.Add;
//Pina.Graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
//Pina.Graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
//Pina.Graphics.GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = false;
// "Fast" Alpha Blended (does NOT require back-to-front draw order, but some particles may occaisonally falsely occlude other objects. Draw them last to minimize this)
Pina.Graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;
Pina.Graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;
Pina.Graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
Pina.Graphics.GraphicsDevice.RenderState.AlphaBlendOperation = BlendFunction.Add;
Pina.Graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
Pina.Graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
Pina.Graphics.GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = false;
for (int i = 0; i < mParticlesAlphaBlend.Count; i++)
{
mParticlesAlphaBlend[i].Render();
}
QuadRenderer.RenderAllNow();
// Additive Blended
Pina.Graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;
Pina.Graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;
Pina.Graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
Pina.Graphics.GraphicsDevice.RenderState.AlphaBlendOperation = BlendFunction.Add;
Pina.Graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
Pina.Graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;
Pina.Graphics.GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = false;
for (int i = 0; i < mParticlesAdditiveBlend.Count; i++)
{
mParticlesAdditiveBlend[i].Render();
}
QuadRenderer.RenderAllNow();
}
///
/// Tells the specified collada model to render itself each render cycle
///
///
public void Add(Renderable renderable)
{
string vertDec = "defaultDec";
// Is this a new vertex delcaration?
if (!mRenderables.ContainsKey(vertDec))
mRenderables.Add(vertDec, new List());
// Add to the appropriate sublist
mRenderables[vertDec].Add(renderable);
}
///
/// Tells the specified particle to render itself each render cycle
///
///
public void Add(Particle particle, BlendMode blendMode)
{
if (blendMode == BlendMode.Alpha)
mParticlesAlphaBlend.Add(particle);
else
mParticlesAdditiveBlend.Add(particle);
}
///
/// Removes the specified renderable from the render queue
///
/// true if the model was found and removed, false otherwise
public bool Remove(Renderable renderable)
{
string vertDec = "defaultDec";
// Does this vertex declaration even exist?
if (!mRenderables.ContainsKey(vertDec))
return false;
// Try to remove the model
return mRenderables[vertDec].Remove(renderable);
}
///
/// Removes the specified particle from the render queue
///
///
/// true if the model was found and removed, false otherwise
public bool Remove(Particle particle)
{
// Try to remove the particle
if (mParticlesAlphaBlend.Contains(particle))
return mParticlesAlphaBlend.Remove(particle);
else
return mParticlesAdditiveBlend.Remove(particle);
}
///
/// Removes all models and particles from the render queue
///
public void Flush()
{
mRenderables.Clear();
mParticlesAlphaBlend.Clear();
mParticlesAdditiveBlend.Clear();
}
///
/// Removes particles from the render queue, but leaves models
///
public void FlushParticles()
{
mParticlesAlphaBlend.Clear();
mParticlesAdditiveBlend.Clear();
}
}
}