#region File Description //----------------------------------------------------------------------------- // RenderContext.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using System; using System.Collections; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using RobotGameData.Camera; #endregion namespace RobotGameData.Render { #region Render Tracer /// /// rendering information. /// public class RenderTracer { public GraphicsDevice Device = null; public GameTime GameTime = null; public BoundingFrustum Frustum = null; public Matrix View = Matrix.Identity; public Matrix ViewInvert = Matrix.Identity; public Matrix Projection = Matrix.Identity; public SpriteBatch SpriteBatch = null; public RenderFog Fog = null; public RenderLighting Lighting = null; } #endregion #region Render Fog /// /// fog information. /// public class RenderFog { public bool enabled = false; public float start = 1.0f; public float end = 10000.0f; public Color color = Color.White; } #endregion #region Render Lighting /// /// lighting information. /// public class RenderLighting { public bool enabled = false; public Vector3 direction = Vector3.Zero; public Color ambientColor = Color.White; public Color diffuseColor = Color.White; public Color specularColor = Color.White; } #endregion #region Render Material /// /// material information /// public class RenderMaterial { public float alpha = 1.0f; public Color diffuseColor = Color.White; public Color specularColor = Color.White; public Color emissiveColor = Color.Black; public float specularPower = 24; public bool vertexColorEnabled = false; public bool preferPerPixelLighting = false; } #endregion /// /// It has an important role of managing all of the scene objects /// and drawing on screen. scene3DRoot node manages and allows the drawing /// of all of the object nodes on 3D screen. /// There is only one scene3DRoot node in framework. /// For scene2DLayer, depending on the game content, there may be /// several scene 2D root nodes and it allows the registered /// 2D sprite nodes to be drawn. Depending on the creation, /// there may be zero or n numbers. /// The internal draw function classifies the nature of the dimension, 3D or 2D, /// and draws on screen by level. /// Also, it has Viewport and view frustum. /// public class RenderContext : DrawableGameComponent { #region Fields /// /// The scene renrder information /// RenderTracer renderTracer = new RenderTracer(); SpriteBatch spriteBatch = null; /// /// The root scene node /// GameSceneNode scene3DRoot = null; /// /// The 2D scene node layer /// List scene2DLayer = null; /// /// The 2D overlay scene layer /// List scene2DOverlay = null; /// /// Frustum culling for render mesh /// BoundingFrustum frustum = null; /// /// color of the back buffer. /// Color clearColor = Color.Black; public event EventHandler RenderingPreDrawScene; public event EventHandler RenderingPostDrawScene; public event EventHandler RenderingPreDraw3D; public event EventHandler RenderingPostDraw3D; public event EventHandler RenderingPreDraw2D; public event EventHandler RenderingPostDraw2D; #endregion #region Properties public GameSceneNode Scene3DRoot { get { return scene3DRoot; } } public GameSceneNode[] Scene2DLayers { get { return scene2DLayer.ToArray(); } } public GameSceneNode Scene2DFadeLayer { get { return scene2DOverlay[0]; } } public GameSceneNode Scene2DTopLayer { get { return scene2DOverlay[1]; } } public SpriteBatch SpriteBatch { get { return spriteBatch; } } public BoundingFrustum Frustum { get { return frustum; } } public Color ClearColor { get { return this.clearColor; } set { this.clearColor = value; } } #endregion /// /// Constructor. /// /// game public RenderContext(Game game) : base(game) { // Create scene root nodes scene2DLayer = new List(); scene2DOverlay = new List(); GameSceneNode SceneFade = new GameSceneNode(); SceneFade.Name = "Scene2DFadeRoot"; GameSceneNode SceneTop = new GameSceneNode(); SceneTop.Name = "Scene2DTopRoot"; scene2DOverlay.Add(SceneFade); scene2DOverlay.Add(SceneTop); scene3DRoot = new GameSceneNode(); scene3DRoot.Name = "Scene3DRoot"; } /// /// Allows the game component to perform any initialization /// it needs to before starting to run. This is where it can query /// for any required services and load content. /// public override void Initialize() { spriteBatch = new SpriteBatch(FrameworkCore.Game.GraphicsDevice); DefaultRenderState(); base.Initialize(); } /// /// Allows the game component to update itself. /// /// Provides a snapshot of timing values. public override void Update(GameTime gameTime) { // 3D Scene update scene3DRoot.Update(gameTime); // 2D Layers update for (int i = 0; i < scene2DLayer.Count; i++) scene2DLayer[i].Update(gameTime); // Overlay Layer update for (int i = 0; i < scene2DOverlay.Count; i++) scene2DOverlay[i].Update(gameTime); base.Update(gameTime); } /// /// draws every scene node which is attached to the scene node. /// Draws in order of 3D scene node, 2D scene node, and overlay text. /// When there are more than one view cameras that have registered /// to the 3D scene, Viewport is applied to the 3D scene node, /// which is drawn as many as the number of the view camera. /// When render event handler has been registered, it is called /// before or after drawing. /// public override void Draw(GameTime gameTime) { // Set to render information renderTracer.Device = FrameworkCore.Game.GraphicsDevice; renderTracer.GameTime = gameTime; renderTracer.SpriteBatch = SpriteBatch; renderTracer.Fog = FrameworkCore.Viewer.BasicFog; renderTracer.Lighting = FrameworkCore.Viewer.BasicLighting; ClearBackBuffer(); if (RenderingPreDrawScene != null) { RenderingPreDrawScene(this, EventArgs.Empty); } // 3D Render { if (RenderingPreDraw3D != null) { RenderingPreDraw3D(this, EventArgs.Empty); } // process multiple camera for (int i = 0; i < FrameworkCore.CurrentCamera.Count; i++) { ViewCamera viewCamera = FrameworkCore.Viewer.CurrentCamera; CameraBase camera = viewCamera.GetCamera(i); renderTracer.View = camera.ViewMatrix; renderTracer.ViewInvert = Matrix.Invert(camera.ViewMatrix); renderTracer.Projection = camera.ProjectionMatrix; // Update frustum UpdateFrustum(camera.ViewMatrix, camera.ProjectionMatrix); renderTracer.Frustum = this.Frustum; // Set to each viewport ApplyViewport(viewCamera.GetViewport(i)); // Render the 3D scene Draw3D(renderTracer); } // restore to default viewport ApplyViewport(FrameworkCore.DefaultViewport); if (RenderingPostDraw3D != null) { RenderingPostDraw3D(this, EventArgs.Empty); } } // 2D Render { if (RenderingPreDraw2D != null) { RenderingPreDraw2D(this, EventArgs.Empty); } // Render the 2D scene Draw2D(renderTracer); if (RenderingPostDraw2D != null) { RenderingPostDraw2D(this, EventArgs.Empty); } } if (RenderingPostDrawScene != null) { RenderingPostDrawScene(this, EventArgs.Empty); } // Display overlaped texts or others DrawOverlayText(gameTime); // Draw other components base.Draw(gameTime); } /// /// removes every scene node and scene layer that have been attached to /// the scene root node. /// /// protected override void Dispose(bool disposing) { if (disposing) { if (spriteBatch != null) { spriteBatch.Dispose(); spriteBatch = null; } } ClearScene3DRoot(disposing); ClearScene2DLayer(disposing); ClearScene2DOverlay(disposing); scene3DRoot = null; base.Dispose(disposing); } /// /// applies the specified Viewport to GraphicsDevice. /// /// a new Viewport public static void ApplyViewport(Viewport viewport) { FrameworkCore.Game.GraphicsDevice.Viewport = viewport; } /// /// updates the bounding frustum. /// /// /// public void UpdateFrustum(Matrix view, Matrix proj) { // Computes the bounding frustum. this.frustum = new BoundingFrustum(view * proj); } /// /// returns the 2D scene layer of the specified index. /// /// an index of 2D scene layer public GameSceneNode GetScene2DLayer(int index) { if (scene2DLayer.Count - 1 < index) { throw new ArgumentException( "Cannot return a 2D layer. Invalid index (" + index.ToString() + ")"); } return scene2DLayer[index]; } /// /// creates new 2D scene layers. /// /// count of layers public void CreateScene2DLayer(int count) { for (int i = 0; i < count; i++) { scene2DLayer.Add(new GameSceneNode()); } } /// /// clears all 2D scene layers. /// public void ClearScene2DLayer(bool disposing) { if (disposing ) { for (int i = 0; i < scene2DLayer.Count; i++) scene2DLayer[i].Dispose(); } scene2DLayer.Clear(); } /// /// clears 2D overlay layer. /// /// public void ClearScene2DOverlay(bool disposing) { if (disposing ) { for (int i = 0; i < scene2DOverlay.Count; i++) scene2DOverlay[i].Dispose(); } scene2DOverlay.Clear(); } /// /// clears 3D scene layer. /// public void ClearScene3DRoot(bool disposing) { if (scene3DRoot != null) { if( disposing) scene3DRoot.Dispose(); scene3DRoot.RemoveAllChild(true); } } /// /// sets render target. /// /// an index of render target /// public void SetRenderTarget(int index, RenderTarget2D renderTarget) { GraphicsDevice.SetRenderTarget(index, renderTarget); } /// /// clears the back buffer of viewport. /// public void ClearBackBuffer() { // Screen clear FrameworkCore.Game.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, ClearColor, 1.0f, 0); } /// /// sets the default render target. /// public void RestoreDefaultRenderTarget() { GraphicsDevice.SetRenderTarget(0, null); } /// /// draws the 3D scene. /// protected void Draw3D(RenderTracer renderTracer) { DefaultRenderState(); // Draw all 3D objects scene3DRoot.Draw(renderTracer); } /// /// draws the 2D scene. /// protected void Draw2D(RenderTracer renderTracer) { spriteBatch.Begin(SpriteBlendMode.AlphaBlend); // Draw all 2D objects for (int i = 0; i < scene2DLayer.Count; i++) scene2DLayer[i].Draw(renderTracer); // Draw all 2D overlay for (int i = 0; i < scene2DOverlay.Count; i++) scene2DOverlay[i].Draw(renderTracer); spriteBatch.End(); } /// /// draws the overlay text. /// protected static void DrawOverlayText(GameTime gameTime) { // Overlay text on screen FrameworkCore.TextManager.Draw(gameTime); } /// /// sets default render state. /// protected static void DefaultRenderState() { GraphicsDevice device = FrameworkCore.Game.GraphicsDevice; device.RenderState.DepthBufferEnable = true; device.RenderState.DepthBufferWriteEnable = true; device.SamplerStates[0].AddressU = TextureAddressMode.Wrap; device.SamplerStates[0].AddressV = TextureAddressMode.Wrap; // Set to alpha blending device.RenderState.AlphaTestEnable = true; device.RenderState.AlphaBlendEnable = true; device.RenderState.SourceBlend = Blend.SourceAlpha; device.RenderState.DestinationBlend = Blend.InverseSourceAlpha; device.RenderState.BlendFunction = BlendFunction.Add; device.RenderState.CullMode = CullMode.CullCounterClockwiseFace; device.RenderState.StencilEnable = false; // Set 0 and greater alpha compare device.RenderState.ReferenceAlpha = 0; device.RenderState.AlphaFunction = CompareFunction.Greater; } } }