Пример #1
0
        protected override void DoRender(DeviceContext context)
        {
            // Tell the IA we are using triangles
            context.InputAssembler.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleList;
            // Set the index buffer
            context.InputAssembler.SetIndexBuffer(indexBuffer, Format.R32_UInt, 0);
            // Pass in the quad vertices (note: only 4 vertices)
            context.InputAssembler.SetVertexBuffers(0, vertexBinding);
            // Draw the 36 vertices that make up the two triangles in the quad
            // using the vertex indices

            var perObject = new ConstantBuffers.PerObject();

            angle = (float)Math.PI * 2 * time * (ID % 2); // move only sphere with even IDs
            if (angle >= 2 * Math.PI)
            {
                angle = 0;
            }
            time += 0.016f / 60f;
            if (time >= 1f)
            {
                time = 0;
            }
            perObject.World = World * Matrix.RotationY((float)angle) * Scene.Model;
            perObject.WorldInverseTranspose = Matrix.Transpose(Matrix.Invert(perObject.World));
            perObject.WorldViewProjection   = perObject.World * Scene.ViewProjection;
            perObject.Transpose();
            context.UpdateSubresource(ref perObject, PerObjectBuffer);

            var perMaterial = new ConstantBuffers.PerMaterial
            {
                Ambient       = Color.SaddleBrown,
                Diffuse       = Color.White,
                Emissive      = Color.Black,
                Specular      = Color.White,
                SpecularPower = 100,
                HasTexture    = 0,
                UVTransform   = Matrix.Identity
            };

            if (EnvironmentMap != null)
            {
                perMaterial.IsReflective     = reflectionAmount > 0 ? 1u : 0;
                perMaterial.ReflectionAmount = reflectionAmount;
                context.PixelShader.SetShaderResource(1, EnvironmentMap.EnvMapSRV);
            }

            context.UpdateSubresource(ref perMaterial, PerMaterialBuffer);
            context.DrawIndexed(totalVertexCount, 0, 0);
            if (EnvironmentMap != null)
            {
                context.PixelShader.SetShaderResource(1, null);
            }

            // Note: we have called DrawIndexed so that the index buffer will be used
        }
Пример #2
0
        protected override void DoRender(DeviceContext context)
        {
            var state = context.Rasterizer.State;

            context.Rasterizer.State = skyBoxState;

            // Tell the IA we are using triangles
            context.InputAssembler.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleList;
            // Set the index buffer
            context.InputAssembler.SetIndexBuffer(indexBuffer, Format.R16_UInt, 0);
            // Pass in the quad vertices (note: only 4 vertices)
            context.InputAssembler.SetVertexBuffers(0, vertexBinding);
            // Draw the 6 vertices that make up the two triangles in the quad
            // using the vertex indices

            var perMaterial = new ConstantBuffers.PerMaterial
            {
                Ambient       = Color.Black,
                Diffuse       = Color.Black,
                Emissive      = Color.Black,
                Specular      = Color.Black,
                SpecularPower = 0,
                HasTexture    = 0,
                UVTransform   = Matrix.Identity
            };

            if (EnvironmentMap != null)
            {
                perMaterial.IsReflective     = 1;
                perMaterial.ReflectionAmount = ReflectionAmount;
                context.PixelShader.SetShaderResource(1, EnvironmentMap.EnvMapSRV);
            }
            context.UpdateSubresource(ref perMaterial, PerMaterialBuffer);

            context.DrawIndexed(6, 0, 0);
            //context.Draw(12, 0);

            if (EnvironmentMap != null)
            {
                context.PixelShader.SetShaderResource(1, null);
            }

            context.Rasterizer.State = state;
        }
Пример #3
0
        protected override void DoRender(DeviceContext context)
        {
            var state = context.Rasterizer.State;

            context.Rasterizer.State = frontState;

            //var perObject = new ConstantBuffers.PerObject();
            //perObject.M = World * Scene.Model;
            //perObject.N = Matrix.Transpose(Matrix.Invert(perObject.M));
            //perObject.MVP = perObject.M * Scene.ViewProjection;
            //perObject.Transpose();
            //context.UpdateSubresource(ref perObject, Scene.PerObjectBuffer);
            var perMaterial = new ConstantBuffers.PerMaterial
            {
                Ambient       = Color.Gray,
                Diffuse       = Color.Gray,
                Emissive      = Color.Black,
                Specular      = Color.Gray,
                SpecularPower = 10f,
                HasTexture    = 0,
                UVTransform   = Matrix.Identity
            };

            if (EnvironmentMap != null)
            {
                perMaterial.IsReflective     = 1;
                perMaterial.ReflectionAmount = 0.4f;
                context.PixelShader.SetShaderResource(1, EnvironmentMap.EnvMapSRV);
            }
            context.UpdateSubresource(ref perMaterial, PerMaterialBuffer);
            context.InputAssembler.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleList;
            context.InputAssembler.SetIndexBuffer(indexBuffers.First(), SharpDX.DXGI.Format.R32_UInt, 0);
            context.InputAssembler.SetVertexBuffers(0, vertexBinding_);
            context.Draw(indices.Count, 0);

            context.Rasterizer.State = state;

            if (EnvironmentMap != null)
            {
                context.PixelShader.SetShaderResource(1, null);
            }
        }
Пример #4
0
        protected override void DoRender(DeviceContext context)
        {
            // Calculate elapsed seconds
            var time = clock.ElapsedMilliseconds / 1000.0f;

            // Calculate skin matrices for each bone
            ConstantBuffers.PerArmature skinMatrices = new ConstantBuffers.PerArmature();
            if (mesh.Bones != null)
            {
                // Retrieve each bone's local transform
                for (var i = 0; i < mesh.Bones.Count; i++)
                {
                    skinMatrices.Bones[i] = mesh.Bones[i].BoneLocalTransform;
                }

                // Load bone transforms from animation frames
                if (CurrentAnimation.HasValue)
                {
                    // Keep track of the last key-frame used for each bone
                    Mesh.Keyframe?[] lastKeyForBones = new Mesh.Keyframe?[mesh.Bones.Count];
                    // Keep track of whether a bone has been interpolated
                    bool[] lerpedBones = new bool[mesh.Bones.Count];
                    for (var i = 0; i < CurrentAnimation.Value.Keyframes.Count; i++)
                    {
                        // Retrieve current key-frame
                        var frame = CurrentAnimation.Value.Keyframes[i];

                        // If the current frame is not in the future
                        if (frame.Time <= time)
                        {
                            // Keep track of last key-frame for bone
                            lastKeyForBones[frame.BoneIndex] = frame;
                            // Retrieve transform from current key-frame
                            skinMatrices.Bones[frame.BoneIndex] = frame.Transform;
                        }
                        // Frame is in the future, check if we should interpolate
                        else
                        {
                            // Only interpolate a bone's key-frames ONCE
                            if (!lerpedBones[frame.BoneIndex])
                            {
                                // Retrieve the previous key-frame if exists
                                Mesh.Keyframe prevFrame;
                                if (lastKeyForBones[frame.BoneIndex] != null)
                                {
                                    prevFrame = lastKeyForBones[frame.BoneIndex].Value;
                                }
                                else
                                {
                                    continue; // nothing to interpolate
                                }
                                // Make sure we only interpolate with
                                // one future frame for this bone
                                lerpedBones[frame.BoneIndex] = true;

                                // Calculate time difference between frames
                                var frameLength = frame.Time - prevFrame.Time;
                                var timeDiff    = time - prevFrame.Time;
                                var amount      = timeDiff / frameLength;

                                // Interpolation using Lerp on scale and translation, and Slerp on Rotation (Quaternion)
                                Vector3    t1, t2; // Translation
                                Quaternion q1, q2; // Rotation
                                float      s1, s2; // Scale
                                // Decompose the previous key-frame's transform
                                prevFrame.Transform.DecomposeUniformScale(out s1, out q1, out t1);
                                // Decompose the current key-frame's transform
                                frame.Transform.DecomposeUniformScale(out s2, out q2, out t2);

                                // Perform interpolation and reconstitute matrix
                                skinMatrices.Bones[frame.BoneIndex] =
                                    Matrix.Scaling(MathUtil.Lerp(s1, s2, amount)) *
                                    Matrix.RotationQuaternion(Quaternion.Slerp(q1, q2, amount)) *
                                    Matrix.Translation(Vector3.Lerp(t1, t2, amount));
                            }
                        }
                    }
                }

                // Apply parent bone transforms
                // We assume here that the first bone has no parent
                // and that each parent bone appears before children
                for (var i = 1; i < mesh.Bones.Count; i++)
                {
                    var bone = mesh.Bones[i];
                    if (bone.ParentIndex > -1)
                    {
                        var parentTransform = skinMatrices.Bones[bone.ParentIndex];
                        skinMatrices.Bones[i] = (skinMatrices.Bones[i] * parentTransform);
                    }
                }

                // Change the bone transform from rest pose space into bone space (using the inverse of the bind/rest pose)
                for (var i = 0; i < mesh.Bones.Count; i++)
                {
                    skinMatrices.Bones[i] = Matrix.Transpose(mesh.Bones[i].InvBindPose * skinMatrices.Bones[i]);
                }

                // Check need to loop animation
                if (!PlayOnce && CurrentAnimation.HasValue && CurrentAnimation.Value.EndTime <= time)
                {
                    this.Clock.Restart();
                }
            }

            // Update the constant buffer with the skin matrices for each bone
            context.UpdateSubresource(skinMatrices.Bones, PerArmatureBuffer);

            // Draw sub-meshes grouped by material
            for (var mIndx = 0; mIndx < mesh.Materials.Count; mIndx++)
            {
                // Retrieve sub meshes for this material
                var subMeshesForMaterial =
                    (from sm in mesh.SubMeshes
                     where sm.MaterialIndex == mIndx
                     select sm).ToArray();

                // If the material buffer is available and there are submeshes
                // using the material update the PerMaterialBuffer
                if (PerMaterialBuffer != null && subMeshesForMaterial.Length > 0)
                {
                    // update the PerMaterialBuffer constant buffer
                    var material = new ConstantBuffers.PerMaterial()
                    {
                        Ambient       = new Color4(mesh.Materials[mIndx].Ambient),
                        Diffuse       = new Color4(mesh.Materials[mIndx].Diffuse),
                        Emissive      = new Color4(mesh.Materials[mIndx].Emissive),
                        Specular      = new Color4(mesh.Materials[mIndx].Specular),
                        SpecularPower = mesh.Materials[mIndx].SpecularPower,
                        UVTransform   = mesh.Materials[mIndx].UVTransform,
                    };

                    // Bind textures to the pixel shader
                    int texIndxOffset = mIndx * Common.Mesh.MaxTextures;
                    material.HasTexture = (uint)(textureViews[texIndxOffset] != null ? 1 : 0); // 0=false
                    context.PixelShader.SetShaderResources(0, textureViews.GetRange(texIndxOffset, Common.Mesh.MaxTextures).ToArray());

                    // Set texture sampler state
                    context.PixelShader.SetSampler(0, samplerState);

                    // If this mesh has a cube map assigned set
                    // the material buffer accordingly
                    if (this.EnvironmentMap != null)
                    {
                        material.IsReflective     = 1;
                        material.ReflectionAmount = 0.4f;
                        context.PixelShader.SetShaderResource(1, this.EnvironmentMap.EnvMapSRV);
                    }

                    // Update material buffer
                    context.UpdateSubresource(ref material, PerMaterialBuffer);
                }

                // For each sub-mesh
                foreach (var subMesh in subMeshesForMaterial)
                {
                    // Ensure the vertex buffer and index buffers are in range
                    if (subMesh.VertexBufferIndex < vertexBuffers.Count && subMesh.IndexBufferIndex < indexBuffers.Count)
                    {
                        // Retrieve and set the vertex and index buffers
                        var vertexBuffer = vertexBuffers[(int)subMesh.VertexBufferIndex];
                        context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertexBuffer, Utilities.SizeOf <Vertex>(), 0));
                        context.InputAssembler.SetIndexBuffer(indexBuffers[(int)subMesh.IndexBufferIndex], Format.R16_UInt, 0);
                        // Set topology
                        context.InputAssembler.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleList;
                    }

                    // Draw the sub-mesh (includes Primitive count which we multiply by 3)
                    // The submesh also includes a start index into the vertex buffer
                    context.DrawIndexed((int)subMesh.PrimCount * 3, (int)subMesh.StartIndex, 0);
                }
                // Unbind the cubemap SRV
                if (this.EnvironmentMap != null)
                {
                    context.PixelShader.SetShaderResource(1, null);
                }
            }
        }
Пример #5
0
        public override void Run()
        {
            #region Create renderers

            // Note: the renderers take care of creating their own
            // device resources and listen for DeviceManager.OnInitialize

            #region Initialize MeshRenderer instances
            List <I3Dobject> meshes = new List <I3Dobject>();

            // Create and initialize the mesh renderer
            var loadedMesh = Common.Mesh.LoadFromFile("Projet.cmo");
            List <MeshRenderer> tempMeshes = new List <MeshRenderer>();
            tempMeshes.AddRange((from mesh in loadedMesh
                                 select ToDispose(new MeshRenderer(mesh))));

            var         spheres = new List <SphereRenderer>();
            SkyBox      skyBox  = null;
            ObjRenderer venus;

            ShadowMap shadowMap = null;

            // We will support a cubemap for each mesh that contains "reflector" in its name
            List <DynamicCubeMap> envMaps = new List <DynamicCubeMap>();

            // We will rotate any meshes that contains "rotate" in its name
            List <MeshRenderer> rotateMeshes = new List <MeshRenderer>();

            // We will generate meshRows * meshColumns of any mesh that contains "replicate" in its name
            int meshRows    = 10;
            int meshColumns = 10;

            // Define an action to initialize our meshes so that we can
            // dynamically change the number of reflective surfaces and
            // replicated meshes
            Action createMeshes = () =>
            {
                if (shadowMap)
                {
                    shadowMap.Dispose();
                }

                shadowMap = ToDispose(new ShadowMap((uint)this.Viewport.Width, (uint)this.Viewport.Height));
                shadowMap.Initialize(this);
                // Clear context states, ensures we don't have
                // any of the resources we are going to release
                // assigned to the pipeline.
                DeviceManager.Direct3DContext.ClearState();
                if (contextList != null)
                {
                    foreach (var context in contextList)
                    {
                        context.ClearState();
                    }
                }

                // Remove meshes
                foreach (var mesh in meshes)
                {
                    mesh.Dispose();
                }
                meshes.Clear();

                // Remove environment maps
                foreach (var envMap in envMaps)
                {
                    envMap.Dispose();
                }
                envMaps.Clear();

                // Add skybox to make it render first
                if (skyBox != null)
                {
                    skyBox.Dispose();
                }
                skyBox = ToDispose(new SkyBox());
                skyBox.PerObjectBuffer = perObjectBuffer;
                meshes.Add(skyBox);


                venus       = ToDispose(new ObjRenderer("Models/venus-low.obj"));
                venus.World = Matrix.Scaling(0.15f);

                meshes.Add(venus);
                //meshes.Add(robot);

                spheres.ForEach(s =>
                {
                    s.Dispose();
                    s = null;
                });
                spheres.Clear();
                var colors = new[] { Color.Red, Color.Green, Color.Blue };
                for (int i = 1; i <= 5; i++)
                {
                    var s = ToDispose(new SphereRenderer(colors[i % colors.Length]));
                    s.Initialize(this);
                    //s.World = Matrix.Translation((float)(i * 1.5 / 2 * Math.Pow(-1, i)), 1f, 1f);
                    var pos = new Vector3((float)(-5f + i * (s.MeshExtent.Radius * 3)), 1f, (float)(1.5 / 2 * Math.Pow(-1, i)));
                    s.World    = Matrix.Translation(pos);
                    s.Position = pos;
                    spheres.Add(s);
                }

                #region Create replicated meshes
                // Add the same mesh multiple times, separate by the combined extent
                var replicatedMeshes = (from mesh in loadedMesh
                                        where (mesh.Name ?? "").ToLower().Contains("replicate")
                                        select mesh).ToArray();
                if (replicatedMeshes.Length > 0)
                {
                    var minExtent = (from mesh in replicatedMeshes
                                     orderby new { mesh.Extent.Min.X, mesh.Extent.Min.Z }
                                     select mesh.Extent).First();
                    var maxExtent = (from mesh in replicatedMeshes
                                     orderby new { mesh.Extent.Max.X, mesh.Extent.Max.Z } descending
                                     select mesh.Extent).First();
                    var extentDiff = (maxExtent.Max - minExtent.Min);

                    for (int x = -(meshColumns / 2); x < (meshColumns / 2); x++)
                    {
                        for (int z = -(meshRows / 2); z < (meshRows / 2); z++)
                        {
                            var meshGroup = (from mesh in replicatedMeshes
                                             where (mesh.Name ?? "").ToLower().Contains("replicate")
                                             select ToDispose(new MeshRenderer(mesh))).ToList();

                            // Reposition based on width/depth of combined extent
                            foreach (var m in meshGroup)
                            {
                                m.World.TranslationVector = new Vector3(m.Mesh.Extent.Center.X + extentDiff.X * x, m.Mesh.Extent.Min.Y, m.Mesh.Extent.Center.Z + extentDiff.Z * z);
                            }

                            //meshes.AddRange(meshGroup.Select(m=> m as I3Dobject));
                        }
                    }
                }
                #endregion

                #region Create reflective meshes
                // Create reflections where necessary and add rotation meshes
                int reflectorCount = 0;
                meshes.ForEach(m =>
                {
                    var name = (m.Mesh.Name ?? "").ToLower();
                    if (name.Contains("reflector") && reflectorCount < maxReflectors)
                    {
                        reflectorCount++;
                        var envMap       = ToDispose(new DynamicCubeMap(1024));
                        envMap.Reflector = (RendererBase)m;
                        envMap.Initialize(this);
                        m.EnvironmentMap = envMap;
                        envMaps.Add(envMap);
                    }
                    if (name.Contains("rotate"))
                    {
                        rotateMeshes.Add((MeshRenderer)m);
                    }

                    m.Initialize(this);
                });
                spheres.ForEach(s =>
                {
                    var envMap       = ToDispose(new DynamicCubeMap(1024));
                    envMap.Reflector = s;
                    envMap.Initialize(this);
                    s.EnvironmentMap = envMap;
                    envMaps.Add(envMap);
                });


                var venusEnv = ToDispose(new DynamicCubeMap(1024));
                venusEnv.Reflector = venus;
                venusEnv.Initialize(this);
                venus.EnvironmentMap = venusEnv;

                envMaps.AddRange(new[] { venusEnv /*, robotEnv*/ });
                #endregion

                // Initialize each mesh
                // meshes.ForEach(m => m.Initialize(this));
                meshes.AddRange(spheres.Select(s => s as I3Dobject));
                //spheres.ForEach(s => s.Initialize(this));
            };
            createMeshes();

            // Set the first animation as the current animation and start clock
            meshes.ForEach(m =>
            {
                if (m.Mesh != null)
                {
                    if (m.Mesh.Animations != null && m.Mesh.Animations.Any())
                    {
                        m.CurrentAnimation = m.Mesh.Animations.First().Value;
                    }
                    m.Clock.Start();
                }
            });

            // Create the overall mesh World matrix
            var meshWorld = Matrix.Identity;

            #endregion


            // Create an axis-grid renderer
            var axisGrid = ToDispose(new AxisGridRenderer());
            axisGrid.Initialize(this);

            // Create and initialize a Direct2D FPS text renderer
            var fps = ToDispose(new Common.FpsRenderer("Calibri", Color.CornflowerBlue, new Point(8, 8), 16));
            fps.Initialize(this);

            // Create and initialize a general purpose Direct2D text renderer
            // This will display some instructions and the current view and rotation offsets
            var textRenderer = ToDispose(new Common.TextRenderer("Calibri", Color.CornflowerBlue, new Point(8, 40), 12));
            textRenderer.Initialize(this);

            #endregion
            base.SizeChanged(true);

            // Initialize the world matrix
            var worldMatrix = Matrix.Identity;

            // Set the camera position
            cameraPosition = new Vector3(0, 1, 2);
            cameraTarget   = Vector3.Zero;  // Looking at the origin 0,0,0
            cameraUp       = Vector3.UnitY; // Y+ is Up

            // Prepare matrices
            // Create the view matrix from our camera position, look target and up direction
            viewMatrix = Matrix.LookAtRH(cameraPosition, cameraTarget, cameraUp);
            viewMatrix.TranslationVector += new Vector3(0, -0.98f, 0);

            // Create the projection matrix
            /* FoV 60degrees = Pi/3 radians */
            // Aspect ratio (based on window size), Near clip, Far clip
            projectionMatrix = Matrix.PerspectiveFovRH((float)Math.PI / 3f, Width / (float)Height, 0.1f, 100f);



            // Maintain the correct aspect ratio on resize
            Window.Resize += (s, e) =>
            {
                projectionMatrix = Matrix.PerspectiveFovRH((float)Math.PI / 3f, Width / (float)Height, 0.1f, 100f);
            };

            #region Rotation and window event handlers

            // Create a rotation vector to keep track of the rotation
            // around each of the axes
            var rotation = new Vector3(0.0f, 0.0f, 0.0f);

            // We will call this action to update text
            // for the text renderer
            Action updateText = () =>
            {
                textRenderer.Text =
                    String.Format(
                        "\nPause rotation: P"
                        + "\nLighting mode: {0} (Shift-Up/Down)"
                        + "\n"
                        ,
                        threadCount);
            };

            Dictionary <Keys, bool> keyToggles = new Dictionary <Keys, bool>();
            keyToggles[Keys.Z] = false;
            keyToggles[Keys.F] = false;

            // Support keyboard/mouse input to rotate or move camera view
            var moveFactor = 0.02f; // how much to change on each keypress
            var shiftKey   = false;
            var ctrlKey    = false;
            var background = Color.Black;
            Window.KeyDown += (s, e) =>
            {
                var context = DeviceManager.Direct3DContext;

                shiftKey = e.Shift;
                ctrlKey  = e.Control;

                switch (e.KeyCode)
                {
                // WASD -> pans view
                case Keys.A:
                    viewMatrix.TranslationVector += new Vector3(moveFactor * 2, 0f, 0f);
                    break;

                case Keys.D:
                    viewMatrix.TranslationVector -= new Vector3(moveFactor * 2, 0f, 0f);
                    break;

                case Keys.S:
                    if (shiftKey)
                    {
                        viewMatrix.TranslationVector += new Vector3(0f, moveFactor * 2, 0f);
                    }
                    else
                    {
                        viewMatrix.TranslationVector -= new Vector3(0f, 0f, 1) * moveFactor * 2;
                    }
                    break;

                case Keys.W:
                    if (shiftKey)
                    {
                        viewMatrix.TranslationVector -= new Vector3(0f, moveFactor * 2, 0f);
                    }
                    else
                    {
                        viewMatrix.TranslationVector += new Vector3(0f, 0f, 1) * moveFactor * 2;
                    }
                    break;

                // Up/Down and Left/Right - rotates around X / Y respectively
                // (Mouse wheel rotates around Z)
                //case Keys.Down:
                //    worldMatrix *= Matrix.RotationX(moveFactor);
                //    rotation += new Vector3(moveFactor, 0f, 0f);
                //    break;
                //case Keys.Up:
                //    worldMatrix *= Matrix.RotationX(-moveFactor);
                //    rotation -= new Vector3(moveFactor, 0f, 0f);
                //    break;
                //case Keys.Left:
                //    worldMatrix *= Matrix.RotationY(moveFactor);
                //    rotation += new Vector3(0f, moveFactor, 0f);
                //    break;
                //case Keys.Right:
                //    worldMatrix *= Matrix.RotationY(-moveFactor);
                //    rotation -= new Vector3(0f, moveFactor, 0f);
                //    break;
                case Keys.T:
                    fps.Show          = !fps.Show;
                    textRenderer.Show = !textRenderer.Show;
                    break;

                //case Keys.B:
                //    if (background == Color.White)
                //    {
                //        background = new Color(30, 30, 34);
                //    }
                //    else
                //    {
                //        background = Color.White;
                //    }
                //    break;
                case Keys.G:
                    axisGrid.Show = !axisGrid.Show;
                    break;

                case Keys.P:
                    break;

                case Keys.X:
                    // To test for correct resource recreation
                    // Simulate device reset or lost.
                    System.Diagnostics.Debug.WriteLine(SharpDX.Diagnostics.ObjectTracker.ReportActiveObjects());
                    DeviceManager.Initialize(DeviceManager.Dpi);
                    System.Diagnostics.Debug.WriteLine(SharpDX.Diagnostics.ObjectTracker.ReportActiveObjects());
                    break;

                case Keys.F:
                    keyToggles[Keys.F] = !keyToggles[Keys.F];
                    RasterizerStateDescription rasterDesc;
                    if (context.Rasterizer.State != null)
                    {
                        rasterDesc = context.Rasterizer.State.Description;
                    }
                    else
                    {
                        rasterDesc = new RasterizerStateDescription()
                        {
                            CullMode = CullMode.Back,
                            FillMode = FillMode.Solid
                        }
                    };
                    if (keyToggles[Keys.F])
                    {
                        rasterDesc.FillMode = FillMode.Wireframe;
                        rasterizerState     = ToDispose(new RasterizerState(context.Device, rasterDesc));
                    }
                    else
                    {
                        rasterDesc.FillMode = FillMode.Solid;
                        rasterizerState     = ToDispose(new RasterizerState(context.Device, rasterDesc));
                    }
                    break;

                case Keys.L: normalLighting = 0; break;

                case Keys.M: normalLighting = 1; break;

                case Keys.C: specularEnviron = specularEnviron == 0 ? 1u : 0; break;

                case Keys.B: specularLocal = specularLocal == 0 ? 1u : 0; break;
                }

                updateText();
            };
            Window.KeyUp += (s, e) =>
            {
                // Clear the shift/ctrl keys so they aren't sticky
                if (e.KeyCode == Keys.ShiftKey)
                {
                    shiftKey = false;
                }
                if (e.KeyCode == Keys.ControlKey)
                {
                    ctrlKey = false;
                }
            };
            Window.MouseWheel += (s, e) =>
            {
                if (shiftKey)
                {
                    // Zoom in/out
                    viewMatrix.TranslationVector += new Vector3(0f, 0f, (e.Delta / 120f) * moveFactor * 2);
                }
                else
                {
                    // rotate around Z-axis
                    viewMatrix *= Matrix.RotationZ((e.Delta / 120f) * moveFactor);
                    rotation   += new Vector3(0f, 0f, (e.Delta / 120f) * moveFactor);
                }
                updateText();
            };

            var lastX = 0;
            var lastY = 0;

            Window.MouseDown += (s, e) =>
            {
                if (e.Button == MouseButtons.Left)
                {
                    lastX = e.X;
                    lastY = e.Y;
                }
            };

            Window.MouseMove += (s, e) =>
            {
                if (e.Button == MouseButtons.Left)
                {
                    var yRotate = lastX - e.X;
                    var xRotate = lastY - e.Y;
                    lastY = e.Y;
                    lastX = e.X;

                    // Mouse move changes
                    viewMatrix *= Matrix.RotationX(-xRotate * moveFactor);
                    viewMatrix *= Matrix.RotationY(-yRotate * moveFactor);

                    updateText();
                }
            };

            // Display instructions with initial values
            updateText();

            #endregion

            var clock = new System.Diagnostics.Stopwatch();
            clock.Start();

            // Setup the deferred contexts
            SetupContextList();

            #region Render loop

            // Whether or not to reinitialize meshes
            bool initializeMesh = false;

            // Define additional key handlers for controlling the
            // number of threads, reflectors, and replicated meshes
            #region Dynamic Cube map and threading KeyDown handlers
            Window.KeyDown += (s, e) =>
            {
                switch (e.KeyCode)
                {
                case Keys.Up:
                    if (shiftKey)
                    {
                        maxReflectors++;
                    }
                    else
                    {
                        meshRows += 2;
                    }
                    initializeMesh = true;
                    break;

                case Keys.Down:
                    if (shiftKey)
                    {
                        maxReflectors = Math.Max(0, maxReflectors - 1);
                    }
                    else
                    {
                        meshRows = Math.Max(2, meshRows - 2);
                    }
                    initializeMesh = true;
                    break;

                case Keys.Right:
                    meshColumns   += 2;
                    initializeMesh = true;
                    break;

                case Keys.Left:
                    meshColumns    = Math.Max(2, meshColumns - 2);
                    initializeMesh = true;
                    break;

                case Keys.Add:
                    if (shiftKey)
                    {
                        additionalCPULoad += 100;
                    }
                    else
                    {
                        threadCount++;
                    }
                    break;

                case Keys.Subtract:
                    if (shiftKey)
                    {
                        additionalCPULoad = Math.Max(0, additionalCPULoad - 100);
                    }
                    else
                    {
                        threadCount = Math.Max(1, threadCount - 1);
                    }
                    break;

                case Keys.G:
                    buildCubeMapGeometryInstancing = !buildCubeMapGeometryInstancing;
                    break;

                default:
                    break;
                }
                updateText();
            };
            #endregion

            #region Render mesh group
            // Action for rendering a group of meshes for a
            // context (based on number of available contexts)
            Action <int, DeviceContext, Matrix, Matrix> renderMeshGroup = (contextIndex, renderContext, view, projection) =>
            {
                var viewProjection = view * projection;


                // Determine the meshes to render for this context
                int batchSize  = (int)Math.Floor((double)meshes.Count / contextList.Length);
                int startIndex = batchSize * contextIndex;
                int endIndex   = Math.Min(startIndex + batchSize, meshes.Count - 1);
                // If this is the last context include whatever remains to be
                // rendered due to the rounding above.
                if (contextIndex == contextList.Length - 1)
                {
                    endIndex = meshes.Count - 1;
                }

                // Loop over the meshes for this context and render them
                var perObject = new ConstantBuffers.PerObject();
                for (var i = startIndex; i <= endIndex; i++)
                {
                    // Retrieve current mesh
                    var m = meshes[i];

                    perObject.World = m.World * worldMatrix;
                    // Update perObject constant buffer
                    perObject.WorldInverseTranspose = Matrix.Transpose(Matrix.Invert(perObject.World));
                    perObject.WorldViewProjection   = perObject.World * viewProjection;
                    perObject.Transpose();
                    renderContext.UpdateSubresource(ref perObject, perObjectBuffer);

                    // Provide the material and armature constant buffer to the mesh renderer
                    m.PerArmatureBuffer = perArmatureBuffer;
                    m.PerMaterialBuffer = perMaterialBuffer;

                    m.PerObjectBuffer = perObjectBuffer;

                    // Render the mesh using the provided DeviceContext
                    m.Render(renderContext);
                }
            };

            #endregion

            #region Render scene
            Vector3 lightDirection;
            // Action for rendering the entire scene
            Action <DeviceContext, Matrix, Matrix, RenderTargetView, DepthStencilView, DynamicCubeMap> renderScene = (context, view, projection, rtv, dsv, envMap) =>
            {
                // We must initialize the context every time we render
                // the scene as we are changing the state depending on
                // whether we are rendering the envmaps or final scene
                InitializeContext(context, false);

                // We always need the immediate context
                // Note: the passed in context will normally be the immediate context
                // however it is possible to run this method threaded also.
                var immediateContext = this.DeviceManager.Direct3DDevice.ImmediateContext;

                // Clear depth stencil view
                context.ClearDepthStencilView(dsv, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1.0f, 0);
                // Clear render target view
                if (rtv != null)
                {
                    context.ClearRenderTargetView(rtv, background);
                }

                // Create viewProjection matrix
                var viewProjection = Matrix.Multiply(view, projection);

                // Extract camera position from view
                var camPosition = Matrix.Transpose(Matrix.Invert(view)).Column4;
                cameraPosition = new Vector3(camPosition.X, camPosition.Y, camPosition.Z);

                // Update scene variable properties
                Scene.Model          = worldMatrix;
                Scene.View           = view;
                Scene.ViewProjection = viewProjection;
                Scene.Projection     = projection;
                Scene.CameraPosition = cameraPosition;
                Scene.Time           = clock.ElapsedMilliseconds;

                // Setup the per frame constant buffer
                var perFrame = new ConstantBuffers.PerFrame();
                perFrame.Light.Color = new Color(0.9f, 0.9f, 0.9f, 1.0f);
                var lightDir = Vector3.Transform(new Vector3(-1f, -1f, -1f), worldMatrix);
                perFrame.Light.Direction = new Vector3(lightDir.X, lightDir.Y, lightDir.Z);
                perFrame.CameraPosition  = cameraPosition;
                perFrame.NormalLighting  = normalLighting;
                //perFrame.SpecularEnviron = specularEnviron;
                //perFrame.SpecularLocal = specularLocal;

                context.UpdateSubresource(ref perFrame, perFrameBuffer);
                lightDirection = new Vector3(lightDir.X, lightDir.Y, lightDir.Z);
                // Render each object

                // Prepare the default per material constant buffer
                var perMaterial = new ConstantBuffers.PerMaterial();
                perMaterial.Ambient       = new Color4(0.2f);
                perMaterial.Diffuse       = Color.White;
                perMaterial.Emissive      = new Color4(0);
                perMaterial.Specular      = Color.White;
                perMaterial.SpecularPower = 20f;
                context.UpdateSubresource(ref perMaterial, perMaterialBuffer);

                context.PixelShader.SetShaderResource(2, textureCube);

                // ----------Render meshes------------

                if (contextList.Length == 1)
                {
                    // If there is only one context available there is no need to
                    // generate command lists and execute them so just render the
                    // mesh directly on the current context (which may or may
                    // not be an immediate context depending on the caller).
                    renderMeshGroup(0, context, view, projection);
                }
                else
                {
                    // There are multiple contexts therefore
                    // we are using deferred contexts. Prepare a
                    // separate thread for each available context
                    // and render a group of meshes on each.
                    Task[]        renderTasks = new Task[contextList.Length];
                    CommandList[] commands    = new CommandList[contextList.Length];
                    var           viewports   = context.Rasterizer.GetViewports();

                    for (var i = 0; i < contextList.Length; i++)
                    {
                        // Must store the iteration value in another variable
                        // or each task action will use the last iteration value.
                        var contextIndex = i;

                        // Create task to run on new thread from ThreadPool
                        renderTasks[i] = Task.Run(() =>
                        {
                            // Retrieve context for this thread
                            var renderContext = contextList[contextIndex];
                            // Initialize the context state
                            InitializeContext(renderContext, false);

                            // Set the render targets and viewport
                            renderContext.OutputMerger.SetRenderTargets(dsv, rtv);
                            renderContext.Rasterizer.SetViewports(viewports);

                            // If we are rendering for a cubemap we must set the
                            // per environment map buffer.
                            if (envMap != null)
                            {
                                renderContext.GeometryShader.SetConstantBuffer(4, envMap.PerEnvMapBuffer);
                            }

                            // Render logic
                            renderMeshGroup(contextIndex, renderContext, view, projection);

                            // Create the command list
                            if (renderContext.TypeInfo == DeviceContextType.Deferred)
                            {
                                commands[contextIndex] = renderContext.FinishCommandList(false);
                            }
                        });
                    }
                    // Wait for all the tasks to complete
                    Task.WaitAll(renderTasks);

                    // Replay the command lists on the immediate context
                    for (var i = 0; i < contextList.Length; i++)
                    {
                        if (contextList[i].TypeInfo == DeviceContextType.Deferred && commands[i] != null)
                        {
                            immediateContext.ExecuteCommandList(commands[i], false);
                            // Clean up command list
                            commands[i].Dispose();
                            commands[i] = null;
                        }
                    }
                }
            };

            #endregion

            long frameCount      = 0;
            int  lastThreadCount = threadCount;

            // Create and run the render loop
            RenderLoop.Run(Window, () =>
            {
                // Allow dynamic changes to number of reflectors and replications
                if (initializeMesh)
                {
                    initializeMesh = false;
                    createMeshes();
                }

                // Allow dynamic chnages to the number of threads to use
                if (lastThreadCount != threadCount)
                {
                    SetupContextList();
                    lastThreadCount = threadCount;
                }

                // Start of frame:
                frameCount++;

                // Retrieve immediate context
                var context = DeviceManager.Direct3DContext;

                if (frameCount % 3 == 1) // to update cubemap once every third frame
                {
                    #region Update environment maps

                    // Update each of the cubemaps
                    if (buildCubeMapGeometryInstancing)
                    {
                        activeVertexShader   = envMapVSShader;
                        activeGeometryShader = envMapGSShader;
                        activePixelShader    = envMapPSShader;
                    }
                    else
                    {
                        //activeVertexShader = vertexShader;
                        //activeGeometryShader = null;
                        //activePixelShader = blinnPhongShader;
                    }

                    // Render the scene from the perspective of each of the environment maps
                    SkyBox.EnableSkyBoxState = (specularEnviron == 1u);
                    foreach (var envMap in envMaps)
                    {
                        var mesh = envMap.Reflector as I3Dobject;
                        if (mesh != null)
                        {
                            // Calculate view point for reflector
                            var meshCenter = Vector3.Transform(mesh.MeshExtent.Center, mesh.World * worldMatrix);
                            envMap.SetViewPoint(new Vector3(meshCenter.X, meshCenter.Y, meshCenter.Z));
                            if (buildCubeMapGeometryInstancing)
                            {
                                // Render cubemap in single full render pass using
                                // geometry shader instancing.
                                envMap.UpdateSinglePass(context, renderScene);
                            }
                        }
                    }

                    //activeVertexShader = shadowVSShader;
                    //activeGeometryShader = null;
                    //activePixelShader = null;

                    //InitializeContext(context, false);

                    //var lightDir = Vector3.Transform(new Vector3(-1f, -1f, -1f), worldMatrix);
                    //shadowMap.SetLightDirection(new Vector3(lightDir.X, lightDir.Y, lightDir.Z));
                    //shadowMap.Update(context, renderScene);
                    #endregion
                }

                #region Render final scene
                // Reset the vertex, geometry and pixel shader
                activeVertexShader   = vertexShader;
                activeGeometryShader = null;
                activePixelShader    = blinnPhongShader;
                // Initialize context (also resetting the render targets)
                InitializeContext(context, true);

                // Render the final scene
                SkyBox.EnableSkyBoxState = true;
                renderScene(context, viewMatrix, projectionMatrix, RenderTargetView, DepthStencilView, null);
                #endregion

                // Render FPS
                fps.Render();

                // Render instructions + position changes
                textRenderer.Render();

                // Present the frame
                Present();
            });
            #endregion
        }