// Build a shader for all supported feature levels and save its
 // bytecode to the shader library.
 private static void saveToLibrary(PlanetShaderKey k)
 {
     var planetShader = new PlanetShader11(k);
     foreach (var level in ShaderLibrary.ShaderLevels)
     {
         planetShader.BuildShader(level.vertexProfile, level.pixelProfile);
     }
 }
        public static void CompileAndSaveShaders()
        {
            PlanetShaderKey k = new PlanetShaderKey(PlanetSurfaceStyle.Emissive, false, 0);
            saveToLibrary(k);
            k.textures = PlanetShaderKey.SurfaceProperty.Diffuse;
            saveToLibrary(k);

            for (int lightCount = 0; lightCount < 2; ++lightCount)
            {
                int maxShadows = Math.Min(lightCount, 1);
                for (int shadowCount = 0; shadowCount < maxShadows; ++shadowCount)
                {
                    for (int tex = 0; tex < 2; ++tex)
                    {
                        k.eclipseShadowCount = shadowCount;
                        k.lightCount = lightCount;
                        k.textures = tex == 0 ? PlanetShaderKey.SurfaceProperty.None : PlanetShaderKey.SurfaceProperty.Diffuse;
                        k.style = PlanetSurfaceStyle.Diffuse;
                        saveToLibrary(k);
                        k.style = PlanetSurfaceStyle.Sky;
                        saveToLibrary(k);
                        k.style = PlanetSurfaceStyle.Specular;
                        saveToLibrary(k);
                        k.style = PlanetSurfaceStyle.SpecularPass;
                        saveToLibrary(k);
                        k.style = PlanetSurfaceStyle.PlanetaryRings;
                        saveToLibrary(k);
                        k.style = PlanetSurfaceStyle.DiffuseAndNight;
                        saveToLibrary(k);
                    }
                }
            }
        }
        /// <summary>
        /// Get the planet shader for the specified shader key. The shader is created
        /// if it's not already in the shader library.
        /// </summary>
        /// <param name="device">Direct3D device</param>
        /// <param name="key">Planet surface shader key</param>
        /// <returns>A Direct3D shader to produce the requested effect.</returns>
        public static PlanetShader11 GetPlanetShader(Device device, PlanetShaderKey key)
        {
            PlanetShader11 shader;

            if (shaderLibrary == null || regenerateShaders)
            {
                shaderLibraryComparer = new PlanetShaderKeyComparer();
                shaderLibrary = new Dictionary<PlanetShaderKey, PlanetShader11>(shaderLibraryComparer);
                regenerateShaders = false;
            }

            // Retrieve the shader from the library of compiled shaders;
            // if the shader isn't in the shader library, create it and
            // add it.
            if (!shaderLibrary.TryGetValue(key, out shader))
            {
                if (shader == null)
                {
                    // Shader was not retrieved from the cache of precompiled shaders
                    shader = new PlanetShader11(key);
                    shader.BuildShader(RenderContext11.VertexProfile, RenderContext11.PixelProfile);
                    shader.Realize(device);

                    shaderLibrary[key] = shader;
                }
            }
            return shader;
        }
        public void Render(RenderContext11 renderContext, float opacity)
        {
            if (dirty && !(ISSLayer))
            {
                Reload();
            }
            Matrix3d oldWorld = renderContext.World;

            Vector3 offset = mesh.BoundingSphere.Center;
            float unitScale = 1.0f;
            if (mesh.BoundingSphere.Radius > 0.0f)
            {
                unitScale = 1.0f / mesh.BoundingSphere.Radius;
            }
            renderContext.World = Matrix3d.Translation(-offset.X, -offset.Y, -offset.Z) * Matrix3d.Scaling(unitScale, unitScale, unitScale) * oldWorld;

            Matrix3d worldView = renderContext.World * renderContext.View;
            Vector3d v = worldView.Transform(Vector3d.Empty);
            double scaleFactor = Math.Sqrt(worldView.M11 * worldView.M11 + worldView.M22 * worldView.M22 + worldView.M33 * worldView.M33) / unitScale;
            double dist = v.Length();
            double radius = scaleFactor;

            // Calculate pixelsPerUnit which is the number of pixels covered
            // by an object 1 AU at the distance of the planet center from
            // the camera. This calculation works regardless of the projection
            // type.
            int viewportHeight = (int)renderContext.ViewPort.Height;
            double p11 = renderContext.Projection.M11;
            double p34 = renderContext.Projection.M34;
            double p44 = renderContext.Projection.M44;
            double w = Math.Abs(p34) * dist + p44;
            float pixelsPerUnit = (float)(p11 / w) * viewportHeight;
            float radiusInPixels = (float)(radius * pixelsPerUnit);
            if (radiusInPixels < 0.5f)
            {
                // Too small to be visible; skip rendering
                return;
            }

            // These colors can be modified by shadows, distance from planet, etc. Restore
            // the original values after rendering.
            var savedSunlightColor = renderContext.SunlightColor;
            var savedReflectedColor = renderContext.ReflectedLightColor;
            var savedHemiColor = renderContext.HemisphereLightColor;

            if (Properties.Settings.Default.SolarSystemLighting)
            {
                SetupLighting(renderContext);
                renderContext.AmbientLightColor = System.Drawing.Color.FromArgb(11, 11, 11);
            }
            else
            {
                // No lighting: set ambient light to white and turn off all other light sources
                renderContext.SunlightColor = System.Drawing.Color.Black;
                renderContext.ReflectedLightColor = System.Drawing.Color.Black;
                renderContext.HemisphereLightColor = System.Drawing.Color.Black;
                renderContext.AmbientLightColor = System.Drawing.Color.White;
            }

            SharpDX.Direct3D11.Device device = renderContext.Device;

            if (mesh == null)
            {
                return;
            }

            //Object3dLayer.sketch.DrawLines(renderContext, 1.0f, System.Drawing.Color.Red);

            renderContext.DepthStencilMode = DepthStencilMode.ZReadWrite;
            renderContext.BlendMode = BlendMode.Alpha;

            int count = meshMaterials.Count;

            mesh.beginDrawing(renderContext);
            if (count > 0)
            {
                for (int i = 0; i < meshMaterials.Count; i++)
                {
                    if (meshMaterials[i].Default)
                    {
                        Material mat = meshMaterials[i];
                        mat.Diffuse = Color;
                        mat.Ambient = Color;
                        meshMaterials[i] = mat;
                    }
                    // Set the material and texture for this subset
                    renderContext.SetMaterial(meshMaterials[i], meshTextures[i], meshSpecularTextures[i], meshNormalMaps[i], opacity);
                    renderContext.PreDraw();
                    renderContext.setSamplerState(0, renderContext.WrapSampler);
                    mesh.drawSubset(renderContext, i);
                }
            }
            else
            {
                renderContext.PreDraw();
                for (int i = 0; i < meshTextures.Count; i++)
                {
                    var key = new PlanetShaderKey(PlanetSurfaceStyle.Diffuse, false, 0);
                    renderContext.SetupPlanetSurfaceEffect(key, 1.0f);
                    if (meshTextures[i] != null)
                    {
                        renderContext.MainTexture = meshTextures[i];
                    }
                    renderContext.PreDraw();
                    mesh.drawSubset(renderContext, i);
                }
            }

            renderContext.setSamplerState(0, renderContext.ClampSampler);

            renderContext.setRasterizerState(TriangleCullMode.CullClockwise);
            renderContext.World = oldWorld;

            renderContext.SunlightColor = savedSunlightColor;
            renderContext.ReflectedLightColor = savedReflectedColor;
            renderContext.HemisphereLightColor = savedHemiColor;
            renderContext.AmbientLightColor = System.Drawing.Color.Black;
        }
 private PlanetShader11(PlanetShaderKey k)
 {
     key = k;
     constants = new PlanetShaderConstants();
 }
 // Returns a shader used to draw the planet surface (or null if no shader was used)
 public PlanetShader11 SetupPlanetSurfaceEffect(PlanetShaderKey key, float opacity)
 {
     return SetupPlanetSurfaceEffectShader(key, opacity);
 }
        private PlanetShader11 SetupPlanetSurfaceEffectShader(PlanetShaderKey key, float opacity)
        {
            PlanetShader11 shader = PlanetShader11.GetPlanetShader(Device, key);

            // If we've got a shader, make it active on the device and set the
            // shader constants.
            if (shader != null)
            {
                shader.use(Device.ImmediateContext);

                // Set the combined world/view/projection matrix in the shader
                Matrix3d worldMatrix = World;
                Matrix3d viewMatrix = View;

                Matrix wvp = (worldMatrix * viewMatrix * Projection).Matrix;
                shader.WVPMatrix = wvp;
                shader.DiffuseColor = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);

                Matrix3d invWorld = worldMatrix;
                invWorld.Invert();

                // For view-dependent lighting (e.g. specular), we need the position of the camera
                // in the planet-fixed coordinate system.
                Matrix3d worldViewMatrix = worldMatrix * viewMatrix;
                Matrix3d invWorldView = worldViewMatrix;
                invWorldView.Invert();
                shader.WorldViewMatrix = worldViewMatrix.Matrix;

                Vector3d cameraPositionObj = Vector3d.TransformCoordinate(new Vector3d(0.0, 0.0, 0.0), invWorldView);
                shader.CameraPosition = cameraPositionObj.Vector3;
            }

            Shader = shader;

            return shader;
        }
        // Set up a shader for the specified material properties and the
        // current lighting environment.
        public void SetMaterial(Material material, Texture11 diffuseTex, Texture11 specularTex, Texture11 normalMap, float opacity)
        {
            PlanetSurfaceStyle surfaceStyle = PlanetSurfaceStyle.Diffuse;
            if (material.Specular != System.Drawing.Color.Black)
            {
                surfaceStyle = PlanetSurfaceStyle.Specular;
            }

            // Force the emissive style when lighting is disabled
            if (!lightingEnabled)
            {
                surfaceStyle = PlanetSurfaceStyle.Emissive;
            }

            PlanetShaderKey key = new PlanetShaderKey(surfaceStyle, false, 0);
            if (reflectedLightColor != System.Drawing.Color.Black)
            {
                key.lightCount = 2;
            }

            key.textures = 0;
            if (diffuseTex != null)
            {
                key.textures |= PlanetShaderKey.SurfaceProperty.Diffuse;
            }

            if (specularTex != null)
            {
                key.textures |= PlanetShaderKey.SurfaceProperty.Specular;
            }

            if (normalMap != null)
            {
                key.textures |= PlanetShaderKey.SurfaceProperty.Normal;
            }

            key.TwoSidedLighting = twoSidedLighting;

            SetupPlanetSurfaceEffect(key, material.Opacity * opacity);

            shader.DiffuseColor = new Vector4(material.Diffuse.R / 255.0f, material.Diffuse.G / 255.0f, material.Diffuse.B / 255.0f, material.Opacity*opacity);
            if (surfaceStyle == PlanetSurfaceStyle.Specular || surfaceStyle == PlanetSurfaceStyle.SpecularPass)
            {
                shader.SpecularColor = new Vector4(material.Specular.R / 255.0f, material.Specular.G / 255.0f, material.Specular.B / 255.0f, 0.0f);
                shader.SpecularPower = material.SpecularSharpness;
            }

            if (diffuseTex != null)
            {
                shader.MainTexture = diffuseTex.ResourceView;
            }

            if (specularTex != null)
            {
                shader.SpecularTexture = specularTex.ResourceView;
            }

            if (normalMap != null)
            {
                shader.NormalTexture = normalMap.ResourceView;
            }
        }
        public void SetupBasicEffect(BasicEffect e, float opacity, System.Drawing.Color color)
        {
            Vector4 correctedColor;
            if (sRGB)
            {
                // sRGB correction for alpha. Even though alpha should be linear, we apply a
                // gamma correction because it's multiplied with color values. The right thing
                // to do is probably to use pre-multiplied alpha throughout WWT and not gamma
                // correct alpha.
                opacity = (float)Math.Pow(opacity, 2.2);
                correctedColor = new Vector4((float)Math.Pow(color.R / 255.0f, 2.2),
                                             (float)Math.Pow(color.G / 255.0f, 2.2),
                                             (float)Math.Pow(color.B / 255.0f, 2.2), opacity);
            }
            else
            {
                correctedColor = new Vector4(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, opacity);
            }

            switch (e)
            {
                case BasicEffect.TextureOnly:
                    {
                        PlanetShaderKey key = new PlanetShaderKey(PlanetSurfaceStyle.Emissive, false, 0);
                        SetupPlanetSurfaceEffect(key, opacity);
                        Shader.DiffuseColor = new Vector4(1.0f, 1.0f, 1.0f, opacity);
                    }
                    break;

                case BasicEffect.ColorOnly:
                    {
                        PlanetShaderKey key = new PlanetShaderKey(PlanetSurfaceStyle.Emissive, false, 0);
                        key.textures = 0;
                        SetupPlanetSurfaceEffect(key, opacity);
                        Shader.DiffuseColor = correctedColor;
                    }
                    break;

                case BasicEffect.TextureColorOpacity:
                    {
                        PlanetShaderKey key = new PlanetShaderKey(PlanetSurfaceStyle.Emissive, false, 0);
                        SetupPlanetSurfaceEffect(key, opacity);
                        Shader.DiffuseColor = correctedColor;
                    }
                    break;

                case BasicEffect.ColoredText:
                    {
                        PlanetShaderKey key = new PlanetShaderKey(PlanetSurfaceStyle.Emissive, false, 0);
                        key.AlphaTexture = true;
                        SetupPlanetSurfaceEffect(key, opacity);
                        Shader.DiffuseColor = correctedColor;
                    }
                    break;

                default:
                    Shader = null;
                    break;
            }
        }
        private static PlanetShader11 SetupPlanetSurfaceEffectShader(RenderContext11 renderContext, PlanetShaderKey key, float opacity)
        {
            var shader = PlanetShader11.GetPlanetShader(renderContext.Device, key);

            // If we've got a shader, make it active on the device and set the
            // shader constants.
            if (shader != null)
            {
                shader.use(renderContext.devContext);

                // Set the combined world/view/projection matrix in the shader
                var worldMatrix = renderContext.World;
                var viewMatrix = renderContext.View;

                var wvp = (worldMatrix * viewMatrix * renderContext.Projection).Matrix11;
                shader.WVPMatrix = wvp;
                shader.DiffuseColor = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);

                var invWorld = worldMatrix;
                invWorld.Invert();

                // For view-dependent lighting (e.g. specular), we need the position of the camera
                // in the planet-fixed coordinate system.
                var worldViewMatrix = worldMatrix * viewMatrix;
                var invWorldView = worldViewMatrix;
                invWorldView.Invert();

                var cameraPositionObj = Vector3d.TransformCoordinate(new Vector3d(0.0, 0.0, 0.0), invWorldView);
                shader.CameraPosition = cameraPositionObj.Vector311;
            }

            renderContext.Shader = shader;

            return shader;
        }
        static void DrawSphere(RenderContext11 renderContext, Texture11 texture, int planetID, int sphereIndex, bool noMultires, bool drawLayers, PlanetShaderKey shaderKey)
        {
            var useMultires = Settings.Active.SolarSystemMultiRes && !noMultires;

            // Let an override layer take the place of the standard layer
            IImageSet defaultLayer = null;
            var defaultLayerColor = Color.White;
            if (drawLayers)
            {
                var referenceFrameName = Enum.GetName(typeof(SolarSystemObjects), (SolarSystemObjects)planetID);
                foreach (var layer in LayerManager.AllMaps[referenceFrameName].Layers)
                {
                    if (layer.Enabled && layer is ImageSetLayer)
                    {
                        if (((ImageSetLayer)layer).OverrideDefaultLayer)
                        {
                            defaultLayer = ((ImageSetLayer)layer).ImageSet;
                            defaultLayerColor = layer.Color;
                            useMultires = true;
                            break;
                        }
                    }
                }
            }

            if (useMultires)
            {
                renderContext.DepthStencilMode = DepthStencilMode.ZReadWrite;

                if (sphereIndex < 4)
                {
                    IImageSet planet = null;

                    if (defaultLayer != null)
                    {
                        planet = defaultLayer;
                    }
                    else
                    {
                        var planetName = GetNameFrom3dId(planetID);
                        var imageSetName = planetName == "Mars" ? "Visible Imagery" : planetName;
                        planet = Earth3d.MainWindow.GetImagesetByName(imageSetName);
                    }

                    if (planet != null)
                    {
                        var normColor = new Vector4(defaultLayerColor.R, defaultLayerColor.G, defaultLayerColor.B, defaultLayerColor.A) * (1.0f / 255.0f);
                        if (RenderContext11.sRGB)
                        {
                            normColor.X = (float) Math.Pow(normColor.X, 2.2);
                            normColor.Y = (float)Math.Pow(normColor.Y, 2.2);
                            normColor.Z = (float)Math.Pow(normColor.Z, 2.2);
                        }
                        renderContext.Shader.DiffuseColor = normColor;
                        renderContext.setRasterizerState(TriangleCullMode.CullClockwise);
                        Earth3d.MainWindow.DrawTiledSphere(planet, 100, Color.White);

                        if (planetID == (int)SolarSystemObjects.Earth && Settings.Active.ShowClouds)
                        {
                            if (CloudTexture != null)
                            {
                                var cloudShaderKey = new PlanetShaderKey(PlanetSurfaceStyle.Diffuse, Settings.Active.ShowEarthSky, 0);
                                cloudShaderKey.eclipseShadowCount = shaderKey.eclipseShadowCount;
                                cloudShaderKey.HasAtmosphere = shaderKey.HasAtmosphere;

                                if (!Settings.Active.SolarSystemLighting)
                                {
                                    cloudShaderKey.style = PlanetSurfaceStyle.Emissive;
                                }

                                SetupPlanetSurfaceEffect(renderContext, cloudShaderKey, 1.0f);
                                SetAtmosphereConstants(renderContext, planetID, 1.0f, CalcSkyGeometryHeight(planetID));

                                renderContext.MainTexture = CloudTexture;

                                var savedWorld = renderContext.World;
                                var cloudScale = 1.0 + (EarthCloudHeightMeters) / 6378100.0;
                                renderContext.World = Matrix3d.Scaling(cloudScale, cloudScale, cloudScale) * renderContext.World;

                                renderContext.setRasterizerState(TriangleCullMode.CullCounterClockwise);
                                renderContext.DepthStencilMode = DepthStencilMode.Off;
                                renderContext.BlendMode = BlendMode.Alpha;

                                DrawFixedResolutionSphere(renderContext, sphereIndex);

                                renderContext.World = savedWorld;

                                renderContext.DepthStencilMode = DepthStencilMode.ZReadWrite;
                                renderContext.BlendMode = BlendMode.None;
                            }
                        }

                        return;
                    }
                }
            }

            renderContext.MainTexture = texture;

            renderContext.Device.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
            renderContext.Device.ImmediateContext.InputAssembler.InputLayout = renderContext.Shader.inputLayout(PlanetShader11.StandardVertexLayout.PositionNormalTex2);

            renderContext.PreDraw();

            renderContext.SetVertexBuffer(sphereVertexBuffers[sphereIndex]);
            renderContext.SetIndexBuffer(sphereIndexBuffers[sphereIndex]);
            renderContext.devContext.DrawIndexed(sphereIndexBuffers[sphereIndex].Count, 0, 0);
        }
        // Various input layouts used in 3D solar system mode
        // TODO Replace with an input layout cache
        static void DrawRings(RenderContext11 renderContext)
        {
            renderContext.setRasterizerState(TriangleCullMode.Off);

            var ringsKey = new PlanetShaderKey(PlanetSurfaceStyle.PlanetaryRings, false, 0);
            SetupPlanetSurfaceEffect(renderContext, ringsKey, 1.0f);
            renderContext.Shader.MainTexture = RingsMap.ResourceView;

            renderContext.devContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip;
            renderContext.Device.ImmediateContext.InputAssembler.InputLayout = renderContext.Shader.inputLayout(PlanetShader11.StandardVertexLayout.PositionNormalTex);

            renderContext.PreDraw();
            renderContext.SetVertexBuffer(ringsVertexBuffer);
            renderContext.devContext.Draw((triangleCountRings+2), 0);

            renderContext.setRasterizerState(TriangleCullMode.CullCounterClockwise);
        }
        private static void DrawPlanet3d(RenderContext11 renderContext, int planetID, Vector3d centerPoint, float opacity)
        {
            // Assume that KML is only used for Earth
            KmlLabels kmlMarkers = null;
            if (planetID == (int)SolarSystemObjects.Earth)
            {
                kmlMarkers = Earth3d.MainWindow.KmlMarkers;
                if (kmlMarkers != null)
                {
                    kmlMarkers.ClearGroundOverlays();
                }
            }

            var matOld = renderContext.World;
            var matOldBase = renderContext.WorldBase;
            var matOldNonRotating = renderContext.WorldBaseNonRotating;

            var radius = GetAdjustedPlanetRadius(planetID);

            SetupPlanetMatrix(renderContext, planetID, centerPoint, true);

            LayerManager.PreDraw(renderContext, 1.0f, false, Enum.GetName(typeof(SolarSystemObjects), (SolarSystemObjects)planetID), true);

            float planetWidth = 1;

            if (planetID == (int)SolarSystemObjects.Saturn)
            {
                planetWidth = 3;
            }

            if (IsPlanetInFrustum(renderContext, planetWidth))
            {
                // Save all matrices modified by SetupMatrix...
                var matOld2 = renderContext.World;
                var matOldBase2 = renderContext.WorldBase;
                var matOldNonRotating2 = renderContext.WorldBaseNonRotating;

                renderContext.World = matOld;
                renderContext.WorldBase = matOldBase;
                renderContext.WorldBaseNonRotating = matOldNonRotating;
                SetupMatrixForPlanetGeometry(renderContext, planetID, centerPoint, true);

                var loc = planet3dLocations[planetID] - centerPoint;
                loc.Subtract(renderContext.CameraPosition);
                var dist = loc.Length();
                var sizeIndexParam = (2 * Math.Atan(.5 * (radius / dist))) / Math.PI * 180;

                // Calculate pixelsPerUnit which is the number of pixels covered
                // by an object 1 AU at the distance of the planet center from
                // the camera. This calculation works regardless of the projection
                // type.
                var viewportHeight = renderContext.ViewPort.Height;
                var p11 = renderContext.Projection.M11;
                var p34 = renderContext.Projection.M34;
                var p44 = renderContext.Projection.M44;
                var w = Math.Abs(p34) * dist + p44;
                var pixelsPerUnit = (float)(p11 / w) * viewportHeight;
                var planetRadiusInPixels = (float)(radius * pixelsPerUnit);

                var sizeIndex = 0;
                if (sizeIndexParam > 10.5)
                {
                    sizeIndex = 0;
                }
                else if (sizeIndexParam > 3.9)
                {
                    sizeIndex = 1;
                }
                else if (sizeIndexParam > .72)
                {
                    sizeIndex = 2;
                }
                else if (sizeIndexParam > 0.057)
                {
                    sizeIndex = 3;
                }
                else
                {
                    sizeIndex = 4;
                }

                var eclipseShadowCount = 0;
                var hasRingShadowsOnPlanet = false;

                // No shadows should be drawn if Solar System Lighting is OFF
                if (Settings.Active.SolarSystemLighting)
                {
                    // Eclipse shadow setup for Earth
                    if (planetID == (int)SolarSystemObjects.Earth)
                    {
                        if (sizeIndex < 2)
                        {
                            var width = Settings.Active.SolarSystemScale * .00001f;

                            SetupShadow(renderContext, centerPoint, width, SolarSystemObjects.Moon, 0);

                            eclipseShadowCount = 1;
                        }
                    }

                    // Eclipse shadow setup for Jupiter
                    // Shadow widths based only on moon diameter in relation to Moon diameter
                    if (planetID == (int)SolarSystemObjects.Jupiter && sizeIndex < 3)
                    {
                        var p = 0;
                        float width;

                        if (planetLocations[(int)SolarSystemObjects.Callisto].Shadow)
                        {
                            width = Settings.Active.SolarSystemScale * .0000139f;
                            SetupShadow(renderContext, centerPoint, width, SolarSystemObjects.Callisto, p++);
                        }

                        if (planetLocations[(int)SolarSystemObjects.Ganymede].Shadow)
                        {
                            width = Settings.Active.SolarSystemScale * .0000152f;
                            SetupShadow(renderContext, centerPoint, width, SolarSystemObjects.Ganymede, p++);
                        }

                        if (planetLocations[(int)SolarSystemObjects.Io].Shadow)
                        {
                            width = Settings.Active.SolarSystemScale * .0000105f;
                            SetupShadow(renderContext, centerPoint, width, SolarSystemObjects.Io, p++);
                        }

                        if (planetLocations[(int)SolarSystemObjects.Europa].Shadow)
                        {
                            width = Settings.Active.SolarSystemScale * .000009f;
                            SetupShadow(renderContext, centerPoint, width, SolarSystemObjects.Europa, p++);
                        }

                        eclipseShadowCount = p;
                    }

                    // Ring shadows on Saturn
                    if (planetID == (int)SolarSystemObjects.Saturn && Settings.Active.SolarSystemLighting)
                    {
                        hasRingShadowsOnPlanet = true;
                    }

                    //ShadowStuff end
                }

                // Get the position of the Sun relative to the planet center; the position is
                // in the world coordinate frame.
                var sunPosition = (planet3dLocations[0] - planet3dLocations[planetID]);
                renderContext.SunPosition = sunPosition;

                if (sizeIndex < 4)
                {
                    var atmosphereOn = (planetID == 19 || planetID == 3) && Settings.Active.ShowEarthSky;

                    if (planetID == 0 && sizeIndex > 1)
                    {
                        //todo11
                        //device.RenderState.Clipping = false;
                        DrawPointPlanet(renderContext, new Vector3d(0, 0, 0), (float)Math.Min(1.6, sizeIndexParam) * 2, planetColors[planetID], true, opacity);

                        //todo11
                        //device.RenderState.Clipping = true;
                    }

                    var surfaceStyle = PlanetSurfaceStyle.Diffuse;
                    if (planetID == (int)SolarSystemObjects.Sun || !Settings.Active.SolarSystemLighting)
                    {
                        surfaceStyle = PlanetSurfaceStyle.Emissive;
                    }
                    else if (planetID == (int)SolarSystemObjects.Moon || planetID == (int)SolarSystemObjects.Mercury)
                    {
                        // Use Lommel-Seeliger photometric model for regolith covered bodies
                        //   surfaceStyle = PlanetSurfaceStyle.LommelSeeliger;
                    }

                    var skyGeometryHeight = CalcSkyGeometryHeight(planetID);

                    var shaderKey = new PlanetShaderKey(surfaceStyle, atmosphereOn, eclipseShadowCount);
                    shaderKey.HasRingShadows = hasRingShadowsOnPlanet;
                    if (kmlMarkers != null)
                    {
                        shaderKey.overlayTextureCount = Math.Min(kmlMarkers.GroundOverlayCount, PlanetShader11.MaxOverlayTextures);
                    }

                    SetupPlanetSurfaceEffect(renderContext, shaderKey, opacity);
                    renderContext.LocalCenter = Vector3d.Empty;

                    // Set up any overlay textures
                    if (shaderKey.overlayTextureCount > 0)
                    {
                        if (renderContext.ShadersEnabled)
                        {
                            kmlMarkers.SetupGroundOverlays(renderContext);
                        }
                    }

                    if (shaderKey.eclipseShadowCount > 0)
                    {
                        renderContext.Shader.EclipseTexture = PlanetShadow.ResourceView;
                    }

                    if (shaderKey.HasRingShadows)
                    {
                        renderContext.Shader.RingTexture = RingsMap.ResourceView;
                    }

                    if (atmosphereOn)
                    {
                        SetAtmosphereConstants(renderContext, planetID, 1.0f, skyGeometryHeight);
                    }

                    // Disable overlays after we're done rendering the planet surface (i.e. we don't want
                    // them on any rings, sky shell, or cloud layer.)
                    shaderKey.overlayTextureCount = 0;

                    renderContext.setRasterizerState(TriangleCullMode.CullCounterClockwise);
                    if (planetID == 19 && !Settings.Active.SolarSystemMultiRes && Settings.Active.SolarSystemLighting)
                    {
                        shaderKey.style = PlanetSurfaceStyle.DiffuseAndNight;
                        SetupPlanetSurfaceEffect(renderContext, shaderKey, opacity);
                        if (atmosphereOn)
                        {
                            SetAtmosphereConstants(renderContext, planetID, 1.0f, skyGeometryHeight);
                        }

                        // Set eclipse constants
                        var eclipseShadowWidth = Settings.Active.SolarSystemScale * .00001f;
                        if (shaderKey.eclipseShadowCount > 0)
                        {
                            SetupShadow(renderContext, centerPoint, eclipseShadowWidth, SolarSystemObjects.Moon, 0);
                            renderContext.Shader.EclipseTexture = PlanetShadow.ResourceView;
                        }

                        renderContext.Shader.NightTexture = planetTexturesMaps[20].ResourceView;

                        renderContext.BlendMode = BlendMode.None;
                        DrawSphere(renderContext, planetTexturesMaps[planetID], planetID, sizeIndex, false, false, shaderKey);

                        // Set up for rendering specular pass
                        shaderKey.style = PlanetSurfaceStyle.SpecularPass;
                        SetupPlanetSurfaceEffect(renderContext, shaderKey, opacity);
                        if (shaderKey.eclipseShadowCount > 0)
                        {
                            SetupShadow(renderContext, centerPoint, eclipseShadowWidth, SolarSystemObjects.Moon, 0);
                            renderContext.Shader.EclipseTexture = PlanetShadow.ResourceView;
                        }
                        if (atmosphereOn)
                        {
                            SetAtmosphereConstants(renderContext, planetID, 1.0f, skyGeometryHeight);
                        }

                        // Set up specular properties; this should eventually be abstracted by RenderContext
                        renderContext.Shader.SpecularPower = 50.0f;
                        renderContext.Shader.SpecularColor = new Vector4(0.5f, 0.5f, 0.5f, 0.0f);

                        renderContext.BlendMode = BlendMode.Additive;
                        DrawSphere(renderContext, planetTexturesMaps[21], planetID, sizeIndex, false, true, shaderKey);
                        renderContext.BlendMode = BlendMode.None;
                    }
                    else
                    {
                        renderContext.DepthStencilMode = DepthStencilMode.ZReadWrite;

                        renderContext.PreDraw();
                        DrawSphere(renderContext, planetTexturesMaps[planetID], planetID, sizeIndex, false, true, shaderKey);
                    }

                    // Render the sky geometry. This is a sphere slightly larger than the planet where the
                    // only light is from atmospheric scattering. We'll render inside of the sphere only.
                    if (atmosphereOn)
                    {
                        // The sky geometry needs to be slightly larger than the planet itself, so adjust the
                        // world matrix by a scale factor a bit greater than 1.0
                        var savedWorld = renderContext.World;
                        var world = renderContext.World;
                        var skyRadius = skyGeometryHeight + 1.0f;
                        world.ScalePrepend(new Vector3d(skyRadius, skyRadius, skyRadius));
                        renderContext.World = world;

                        shaderKey.style = PlanetSurfaceStyle.Sky;
                        var atmosphereShader = SetupPlanetSurfaceEffect(renderContext, shaderKey, 1.0f);
                        renderContext.Shader = atmosphereShader;

                        // Set the shadow texture if there's an eclipse
                        if (shaderKey.eclipseShadowCount > 0)
                        {
                            atmosphereShader.EclipseTexture = PlanetShadow.ResourceView;
                        }

                        // Atmosphere height is relative to the size of the sphere being rendered. Since we're
                        // actually rendering the shell geometry here, we just use a value of 0 for the height
                        // and a lower value for the zero height.
                        SetAtmosphereConstants(renderContext, planetID, 1.0f + skyGeometryHeight, 0.0f);

                        // We're rendering just the atmosphere; there's no contribution from a surface, so set the
                        // diffuse color to black.
                        atmosphereShader.DiffuseColor = new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
                        atmosphereShader.Opacity = 0.0f;

                        //renderContext.BlendMode = BlendMode.Alpha;
                        // Fade out the sky geometry as its screen size gets thin; this prevents terrible
                        // aliasing that occurs.
                        var skyShellPixels = (float)(skyGeometryHeight * radius * pixelsPerUnit);
                        var blendFactor = Math.Min(3.0f, skyShellPixels) / 3.0f;

                        renderContext.BlendMode = BlendMode.BlendFactorInverseAlpha;
                        renderContext.BlendFactor = new Color4(blendFactor, blendFactor, blendFactor, 1.0f);

                        renderContext.DepthStencilMode = DepthStencilMode.ZReadOnly;

                        //Render the _inside_ of the sphere. No need for multires or layers when drawing the sky
                        renderContext.setRasterizerState(TriangleCullMode.CullClockwise);
                        DrawSphere(renderContext, planetTexturesMaps[planetID], planetID, 0/*sizeIndex*/, true, false, shaderKey);

                        // Reset device state
                        renderContext.setRasterizerState(TriangleCullMode.CullCounterClockwise);
                        renderContext.DepthStencilMode = DepthStencilMode.ZReadWrite;
                        renderContext.BlendMode = BlendMode.None;

                        // Restore the world matrix
                        renderContext.World = savedWorld;
                    }

                    RestoreDefaultMaterialState(renderContext);

                    if (planetID == 5)
                    {
                        var ringsKey = new PlanetShaderKey(PlanetSurfaceStyle.PlanetaryRings, false, 0);
                        SetupPlanetSurfaceEffect(renderContext, ringsKey, 1.0f);
                        DrawRings(renderContext);
                        RestoreDefaultMaterialState(renderContext);
                    }
                }
                else
                {
                    if (planetID == 0)
                    {
                        DrawPointPlanet(renderContext, new Vector3d(0, 0, 0), (float)(10 * planetDiameters[planetID]), planetColors[planetID], true, opacity);
                    }
                    else if (planetID < (int)SolarSystemObjects.Moon || planetID == (int)SolarSystemObjects.Earth)
                    {
                        var size = (float)(800 * planetDiameters[planetID]);
                        DrawPointPlanet(renderContext, new Vector3d(0, 0, 0), (float)Math.Max(.05, Math.Min(.1f, size)), planetColors[planetID], true, opacity);
                    }
                    else if (sizeIndexParam > .002)
                    {
                        var size = (float)(800 * planetDiameters[planetID]);
                        DrawPointPlanet(renderContext, new Vector3d(0, 0, 0), (float)Math.Max(.05, Math.Min(.1f, size)), planetColors[planetID], true, opacity);
                    }
                }

                // Restore all matrices modified by SetupMatrix...
                renderContext.World = matOld2;
                renderContext.WorldBase = matOldBase2;
                renderContext.WorldBaseNonRotating = matOldNonRotating2;
            }

            {
                var sunPosition = (planet3dLocations[0] - centerPoint);
                var planetPosition = planet3dLocations[planetID] - centerPoint;
                renderContext.SunPosition = sunPosition;
                renderContext.ReflectedLightPosition = planetPosition;
                if (planetID == (int)SolarSystemObjects.Earth)
                {
                    renderContext.ReflectedLightColor = Color.FromArgb(50, 70, 90);
                    renderContext.HemisphereLightColor = Color.FromArgb(100, 100, 100);
                }
                else
                {
                    renderContext.ReflectedLightColor = Color.Black;
                    renderContext.HemisphereLightColor = Color.Black;
                }

                renderContext.OccludingPlanetPosition = planetPosition;
                renderContext.OccludingPlanetRadius = planetDiameters[planetID] / 2.0;
            }

            LayerManager.Draw(renderContext, 1.0f, false, Enum.GetName(typeof(SolarSystemObjects), (SolarSystemObjects)planetID), true, false);

            // Reset render context state
            renderContext.ReflectedLightColor = Color.Black;
            renderContext.HemisphereLightColor = Color.Black;

            renderContext.World = matOld;
            Earth3d.MainWindow.MakeFrustum();

            RestoreDefaultMaterialState(renderContext);
            renderContext.setRasterizerState(TriangleCullMode.CullClockwise);
        }
 // Returns a shader used to draw the planet surface (or null if no shader was used)
 public static PlanetShader11 SetupPlanetSurfaceEffect(RenderContext11 renderContext, PlanetShaderKey key, float opacity)
 {
     return SetupPlanetSurfaceEffectShader(renderContext, key, opacity);
 }