Render to a control on a form

2007-11-30
2013-04-08
  • Pete Stoves
    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
        }
    }