Pete Stoves - 2007-11-30

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX.Direct3D;
using System.Windows.Forms;
using System.Drawing;
using Microsoft.DirectX;
using System.Threading;
using RetinaCore.UserInterface;
using System.Collections;
using RetinaCore.SceneGraph;

namespace retTest.ControlRenderer
{
    /// <summary>
    /// Default renderer implementation.
    /// </summary>
    public class ControlRenderer : IRenderer
    {
        #region Fields
        Control renderControl;
        Size windowSize;
        Point windowLocation;
        int desktopWidth;
        int desktopHeight;
        int desktopRefreshRate;
        Device device;
        IScene scene;
        IUserInterface userInterface;
        ISceneNode cameraNode;
        Color background = Color.Black;
        bool active = false;
        bool fullScreen = false;
        bool deviceLostOrReseting = false;
        PresentParameters presentParams = new PresentParameters();
        List<IParticleEffect> particleEffectsToRender = new List<IParticleEffect>();
        #endregion

        #region Constructor
        public ControlRenderer(Control RenderControl)
        {
            this.renderControl = RenderControl;
            this.scene = new Scene();
        }
        #endregion

        #region IRenderer Members
        public Device Device
        {
            get
            {
                return device;
            }
        }

        public bool Active
        {
            get
            {
                return device != null && scene != null && cameraNode != null && active;
            }
        }

        public bool DeviceLostOrReseting
        {
            get { return deviceLostOrReseting; }
            set { deviceLostOrReseting = value; }
        }

        public bool FullScreen
        {
            get
            {
                return false;
            }
            set
            {
            }
        }

        public Color Background
        {
            get
            {
                return background;
            }
            set
            {
                background = value;
            }
        }

        public IScene Scene
        {
            get
            {
                return scene;
            }
            set
            {
                scene = value;
            }
        }

        public IUserInterface UserInterface
        {
            get
            {
                return userInterface;
            }
            set
            {
                userInterface = value;
                if (userInterface != null)
                {
                    userInterface.FullScreen = fullScreen;
                }
            }
        }

        public ISceneNode CameraNode
        {
            get
            {
                return cameraNode;
            }
            set
            {
                cameraNode = value;
            }
        }

        public bool DeviceStart()
        {
            try
            {
                DisplayMode adapterDesktopMode = Manager.Adapters[0].CurrentDisplayMode;
                desktopWidth = adapterDesktopMode.Width;
                desktopHeight = adapterDesktopMode.Height;
                desktopRefreshRate = adapterDesktopMode.RefreshRate;
                windowSize = this.renderControl.Size;
                windowLocation = this.renderControl.Location;

                Caps deviceCapabilities = Manager.GetDeviceCaps(0, DeviceType.Hardware);
                CreateFlags flags;
                if (deviceCapabilities.DeviceCaps.SupportsHardwareTransformAndLight)
                {
                    flags = CreateFlags.HardwareVertexProcessing;
                }
                else
                {
                    flags = CreateFlags.SoftwareVertexProcessing;
                }

                if (deviceCapabilities.DeviceCaps.SupportsPureDevice)
                {
                    flags |= CreateFlags.PureDevice;
                }
                presentParams.BackBufferCount = 3;
                presentParams.Windowed = true;
                presentParams.SwapEffect = SwapEffect.Discard;
                presentParams.AutoDepthStencilFormat = DepthFormat.D16;
                presentParams.EnableAutoDepthStencil = true;
                presentParams.PresentationInterval = PresentInterval.Immediate;
                presentParams.ForceNoMultiThreadedFlag = true;

                presentParams.MultiSampleQuality = 0;
                presentParams.MultiSample = MultiSampleType.None;
                presentParams.PresentFlag = PresentFlag.DiscardDepthStencil;

                device = new Device(0, DeviceType.Hardware, renderControl, flags, presentParams);
                device.DeviceReset += new System.EventHandler(OnResetDeviceEvent);
                device.DeviceLost += new System.EventHandler(OnLostDeviceEvent);
                Device.IsUsingEventHandlers = false;

                device.Reset(presentParams);

                active = true;
                return true;
            }
            catch (Exception e)
            {
                System.Diagnostics.Trace.TraceError("Graphics device initialization threw: " + e);
                return false;
            }
        }

        public void DeviceStop()
        {
            active = false;
            device.Dispose();
        }

        public void OnRestartDevice()
        {
            device.SetTexture(0, null);
            device.RenderState.CullMode = Cull.CounterClockwise;
            device.RenderState.ZBufferEnable = true;
            device.RenderState.Lighting = true;
            device.RenderState.Ambient = System.Drawing.Color.FromArgb(0x101010);
            device.RenderState.ShadeMode = ShadeMode.Phong;
            device.RenderState.NormalizeNormals = true;
            device.SamplerState[0].MipFilter = TextureFilter.Linear;
            active = true;
        }

        public void OnLostDevice()
        {
            active = false;
            if (scene != null)
            {
                scene.OnLostDevice();
            }
            if (userInterface != null)
            {
                userInterface.OnLostDevice();
            }
        }

        public void Render()
        {
                // Check for invisible control
            if (renderControl.Visible == false)
            {
                Thread.Sleep(50);
                return;
            }

            // Check for lost device
            int result;
            if (device != null && !device.CheckCooperativeLevel(out result))
            {
                deviceLostOrReseting = true;
                if (result == (int)ResultCode.DeviceLost)
                {
                    // The device has been lost but cannot be reset at this time. 
                    // So wait until it can be reset.
                    Thread.Sleep(50);
                    return;
                }
                try
                {
                    device.Reset(presentParams);
                }
                catch (DeviceLostException)
                {
                    // The device was lost again. Trying reset on next round.
                    return;
                }
                catch (Exception e)
                {
                    // Reset threw unexpected exception.
                    System.Diagnostics.Trace.TraceError("Unable to reset device: " + e.ToString());
                    return;
                }
            }

            deviceLostOrReseting = false;

            if (!active)
            {
                // Skip rendering as renderer is not active.
                return;
            }

            // Render scene
            try
            {
                // Clear background and zbuffer
                device.Clear(ClearFlags.Target, background, 1.0f, 0);
                device.Clear(ClearFlags.ZBuffer, 0, 1.0f, 0);

                // Set world view transformation and projection according to the camera.
                if (CameraNode != null && CameraNode.Camera != null)
                {
                    float aspectRatio = fullScreen ? (float)desktopWidth / (float)desktopHeight : (float)renderControl.Width / (float)renderControl.Height;
                    device.Transform.View = CameraNode.Camera.View;
                    device.Transform.Projection = Matrix.PerspectiveFovLH(cameraNode.Camera.FieldOfView, aspectRatio, cameraNode.Camera.ZNearPlane, cameraNode.Camera.ZFarPlane);
                }

                StateBlock sb = new StateBlock(device, StateBlockType.All);
                device.BeginScene();

                // Render scene
                if (scene != null)
                {
                    sb.Capture();
                    scene.RenderModels(device);
                    sb.Apply();
                    sb.Capture();
                    scene.RenderEffects(device, CameraNode != null ? CameraNode.Camera.View : Matrix.Identity);
                    sb.Apply();
                }

                // Render user interface
                if (userInterface != null)
                {
                    sb.Capture();
                    userInterface.Render();
                    sb.Apply();
                }

                device.EndScene();
                sb.Dispose();

            }
            catch (DeviceLostException)
            {
                // Device was lost during rendering. Do nothing.
            }

        }

        public void Present()
        {
            try
            {
                device.Present();
            }
            catch (DeviceLostException)
            {
                // Device was lost during rendering. Do nothing.
            }
        }

        public void Dispose()
        {
            if (device != null)
            {
                device.Dispose();
            }
        }

        #endregion

        #region Internal methods

        protected void OnResetDeviceEvent(object sender, EventArgs e)
        {
            OnRestartDevice();
        }

        protected void OnLostDeviceEvent(object sender, EventArgs e)
        {
            OnLostDevice();
        }

        protected void ToggleFullScreen()
        {
        }

        #endregion
    }
}