예제 #1
0
        void CreateFlare(SS_Texture texture, SS_Point lightPoint, int radius, bool customTint, Color tint)
        {
            Color flareColor = tint;

            if (!customTint)
            {
                flareColor = new Color(random.Range(0f, 1f), random.Range(0f, 1f), random.Range(0f, 1f));
            }

            int hRad = radius / 2;

            int xMin = lightPoint.x - hRad;
            int yMin = lightPoint.y - hRad;
            int xMax = lightPoint.x + hRad;
            int yMax = lightPoint.y + hRad;

            for (int y = yMin; y < yMax; y++)
            {
                for (int x = xMin; x < xMax; x++)
                {
                    float distance = SS_Point.Distance(lightPoint, new SS_Point(x, y));

                    if (distance < hRad)
                    {
                        Color c = SS_Utilities.Blend(flareColor, texture.GetPixel(x, y), 1.0f - ((distance - 0) / (hRad - 0)));
                        if (texture.GetPixel(x, y).a == 0f)
                        {
                            c.a = 1f;
                        }
                        texture.SetPixel(x, y, c);
                    }
                }
            }
        }
예제 #2
0
        public static void Polygon(SS_Texture texture, SS_Point[] points, bool fill, Color outlineColor, Color fillColor)
        {
            SS_Point p, p2;

            // Loop through all SS_Points and draw lines between them except for the last one
            for (int i = 0; i < points.Length - 1; i++)
            {
                p  = new SS_Point((short)points[i].x, (short)points[i].y);
                p2 = new SS_Point((short)points[i + 1].x, (short)points[i + 1].y);

                Line(texture, p.x, p.y, p2.x, p2.y, outlineColor);
            }

            // Last SS_Point connects to first SS_Point (order is important)
            p  = new SS_Point((short)points[0].x, (short)points[0].y);
            p2 = new SS_Point((short)points[points.Length - 1].x, (short)points[points.Length - 1].y);

            Line(texture, p.x, p.y, p2.x, p2.y, outlineColor);

            if (fill)
            {
                SS_Point centroid = SS_Utilities.Centroid(points);
                FloodFillArea(texture, centroid, fillColor);
            }
        }
예제 #3
0
        public static void LineThick(SS_Texture texture, SS_Point start, SS_Point end, int width, Color outlineColor, Color fillColor)
        {
            SS_Texture tmpTexture = new SS_Texture(texture.Width, texture.Height, Color.clear);

            SS_Point[] points = new SS_Point[4];

            float angle = Mathf.Atan2(end.y - start.y, end.x - start.x) * Mathf.Rad2Deg;

            points[0] = new SS_Point(
                (int)(start.x + Mathf.Cos((angle - 90f) * Mathf.Deg2Rad) * (width / 2)),
                (int)(start.y + Mathf.Sin((angle - 90f) * Mathf.Deg2Rad) * (width / 2)));

            points[1] = new SS_Point(
                (int)(start.x + Mathf.Cos((angle + 90f) * Mathf.Deg2Rad) * (width / 2)),
                (int)(start.y + Mathf.Sin((angle + 90f) * Mathf.Deg2Rad) * (width / 2)));

            points[2] = new SS_Point(
                (int)(end.x + Mathf.Cos((angle + 90f) * Mathf.Deg2Rad) * (width / 2)),
                (int)(end.y + Mathf.Sin((angle + 90f) * Mathf.Deg2Rad) * (width / 2)));

            points[3] = new SS_Point(
                (int)(end.x + Mathf.Cos((angle - 90f) * Mathf.Deg2Rad) * (width / 2)),
                (int)(end.y + Mathf.Sin((angle - 90f) * Mathf.Deg2Rad) * (width / 2)));

            LineStripClosed(tmpTexture, points, outlineColor);
            FloodFillArea(tmpTexture, SS_Utilities.Centroid(points), fillColor);

            MergeColors(texture, tmpTexture, 0, 0);
        }
예제 #4
0
        public SS_Moon(int seed, int size, float frequency, float lacunarity, int octaves, float roughness, Color[] colors, float lightAngle)
        {
            Seed = seed;
            Size = size;

            Sprite         = new SS_Texture(size, size, Color.clear);
            gradientColors = SS_Utilities.CreateGradient(colors, 16, 32);

            Perlin             shapeNoise = new Perlin(0.01, 2, 0.5, 8, seed, QualityMode.High);
            RidgedMultifractal noise      = new RidgedMultifractal(frequency, lacunarity, octaves, seed, QualityMode.Low);

            Vector2 lightPosition = new Vector2(
                Sprite.Center.x + (Mathf.Cos(lightAngle * Mathf.Deg2Rad) * (Size / 4)),
                Sprite.Center.y + (Mathf.Sin(lightAngle * Mathf.Deg2Rad) * (Size / 4)));

            for (int y = 0; y < Size; y++)
            {
                for (int x = 0; x < Size; x++)
                {
                    float dist      = Vector2.Distance(new Vector2(x, y), new Vector2(Sprite.Center.x, Sprite.Center.y));
                    float edgeNoise = (float)shapeNoise.GetValue(x, y, 0);
                    edgeNoise  = (edgeNoise + 1.0f) * 0.5f;
                    edgeNoise  = Mathf.Clamp(edgeNoise, 0f, 1f);
                    edgeNoise *= (8 * roughness);

                    if (dist < (Size / 2) - edgeNoise)
                    {
                        float pixelNoise = (float)noise.GetValue(x, y, 0);
                        pixelNoise = (pixelNoise + 1.0f) * 0.5f;
                        pixelNoise = Mathf.Clamp(pixelNoise, 0f, 1f);

                        float n = pixelNoise * (gradientColors.Length - 1);

                        // Generate color and noise so land doesn't look to smooth
                        Color pixelColor = gradientColors[(int)n];
                        pixelColor.a = 1.0f;

                        Sprite.SetPixel(x, y, pixelColor);

                        // Shadow
                        float lightDistance = Vector2.Distance(new Vector2(x, y), lightPosition);
                        lightDistance = 1.25f - (lightDistance / (Size / 2));
                        if (lightDistance < 0.025f)
                        {
                            lightDistance = 0.025f;
                        }

                        pixelColor.r *= lightDistance;
                        pixelColor.g *= lightDistance;
                        pixelColor.b *= lightDistance;
                        Sprite.SetPixel(x, y, pixelColor);
                    }
                }
            }
        }
예제 #5
0
        public SS_Station(int seed, SS_StationType stationType, Color tint, int numberOfPods)
        {
            Seed = seed;

            random = new SS_Random(Seed);
            Sprite = new SS_Texture(Size, Size, Color.clear);

            if (stationType == SS_StationType.Cool)
            {
                CreateRing(random.Range(0.85f, 1.0f), random.Range(1, 4), true, random.NextColor(), false);
                CreateRing(random.Range(0.5f, 0.75f), random.Range(1, 4), true, random.NextColor(), true);

                // Draw lights
                for (int i = 0; i < LightPoints.Count; i++)
                {
                    CreateFlare(Sprite, LightPoints[i], 16, true, Color.white);
                }

                int podCount    = random.RangeEven(2, 8);
                int podWidth    = random.RangeEven(24, 32);
                int podHeight   = random.RangeEven(12, 24);
                int podDistance = random.RangeEven(64, Size / 2 - 32);
                CreatePods(podCount, podWidth, podHeight, 8, podDistance, 1.0, Color.grey);
                CreatePods(podCount, podWidth, podHeight, 8, podDistance, 0.75, Color.grey);

                Color[] flareColors = SS_Utilities.GenerateColorWheelColors(Seed, 3);
                CreateFlare(Sprite, new SS_Point(Sprite.Center.x, Sprite.Center.y), 128, true, flareColors[0]);
                CreateFlare(Sprite, new SS_Point(Sprite.Center.x, Sprite.Center.y), 64, true, flareColors[1]);
                CreateFlare(Sprite, new SS_Point(Sprite.Center.x, Sprite.Center.y), 32, true, flareColors[2]);
            }
            else if (stationType == SS_StationType.Pod)
            {
                int podCount    = numberOfPods;
                int podSize     = 64;
                int step        = 360 / podCount;
                int bridgeWidth = random.RangeEven(8, 16);

                // Setup pod positions
                List <SS_Point> podPositions = new List <SS_Point>();
                for (int a = 0; a < 359; a += step)
                {
                    int x = Sprite.Center.x + (int)(Mathf.Cos(a * Mathf.Deg2Rad) * 96);
                    int y = Sprite.Center.y + (int)(Mathf.Sin(a * Mathf.Deg2Rad) * 96);

                    podPositions.Add(new SS_Point(x, y));
                }

                for (int i = 0; i < podPositions.Count; i++)
                {
                    SS_Texture      tmpBridgeTexture = new SS_Texture(Size, Size, Color.clear);
                    List <SS_Point> points           = new List <SS_Point>();

                    int px1 = podPositions[i].x + (int)(Mathf.Cos((i * step - 90) * Mathf.Deg2Rad) * bridgeWidth);
                    int py1 = podPositions[i].y + (int)(Mathf.Sin((i * step - 90) * Mathf.Deg2Rad) * bridgeWidth);
                    int px2 = podPositions[i].x + (int)(Mathf.Cos((i * step + 90) * Mathf.Deg2Rad) * bridgeWidth);
                    int py2 = podPositions[i].y + (int)(Mathf.Sin((i * step + 90) * Mathf.Deg2Rad) * bridgeWidth);

                    int cx1 = Sprite.Center.x + (int)(Mathf.Cos((i * step - 90) * Mathf.Deg2Rad) * bridgeWidth);
                    int cy1 = Sprite.Center.y + (int)(Mathf.Sin((i * step - 90) * Mathf.Deg2Rad) * bridgeWidth);
                    int cx2 = Sprite.Center.x + (int)(Mathf.Cos((i * step + 90) * Mathf.Deg2Rad) * bridgeWidth);
                    int cy2 = Sprite.Center.y + (int)(Mathf.Sin((i * step + 90) * Mathf.Deg2Rad) * bridgeWidth);

                    points.Add(new SS_Point(cx1, cy1));
                    points.Add(new SS_Point(px1, py1));
                    points.Add(new SS_Point(px2, py2));
                    points.Add(new SS_Point(cx2, cy2));

                    SS_Drawing.PolygonFill(tmpBridgeTexture, points.ToArray(), SS_StellarSprite.FillColor, SS_StellarSprite.FillColor);
                    SS_Drawing.MergeColors(Sprite, tmpBridgeTexture, 0, 0);
                }

                int numPoints = random.RangeEven(6, 10);
                for (int i = 0; i < podPositions.Count; i++)
                {
                    float angleStep = 360.0f / numPoints;

                    List <SS_Point> controlPoints = new List <SS_Point>();
                    for (float angle = 0; angle < 360f; angle += angleStep)
                    {
                        int px = (int)(podPositions[i].x + (Mathf.Cos(angle * Mathf.Deg2Rad) * (podSize * 0.5)));
                        int py = (int)(podPositions[i].y + (Mathf.Sin(angle * Mathf.Deg2Rad) * (podSize * 0.5)));

                        controlPoints.Add(new SS_Point(px, py));
                    }

                    SS_Texture tmpPodTexture = new SS_Texture(Size, Size, Color.clear);
                    SS_Drawing.PolygonFill(tmpPodTexture, controlPoints.ToArray(), SS_StellarSprite.OutlineColor, SS_StellarSprite.FillColor);
                    SS_Drawing.MergeColors(Sprite, tmpPodTexture, 0, 0);

                    List <SS_Point> controlPoints2 = new List <SS_Point>();
                    for (float angle = 0; angle < 360f; angle += angleStep)
                    {
                        int px = (int)(podPositions[i].x + (Mathf.Cos(angle * Mathf.Deg2Rad) * (podSize * 0.4)));
                        int py = (int)(podPositions[i].y + (Mathf.Sin(angle * Mathf.Deg2Rad) * (podSize * 0.4)));

                        controlPoints2.Add(new SS_Point(px, py));
                        LightPoints.Add(new SS_Point(px, py));
                    }

                    SS_Texture tmpPodTexture2 = new SS_Texture(Size, Size, Color.clear);
                    SS_Drawing.PolygonFill(tmpPodTexture2, controlPoints2.ToArray(), SS_StellarSprite.OutlineColor, SS_StellarSprite.FillColor);
                    SS_Drawing.MergeColors(Sprite, tmpPodTexture2, 0, 0);
                }

                int hubSize      = random.RangeEven(64, 128);
                int numHubPoints = random.RangeEven(6, 10);

                float hubAngleSteps = 360.0f / numHubPoints;

                List <SS_Point> hubPoints = new List <SS_Point>();
                for (float angle = 0; angle < 360f; angle += hubAngleSteps)
                {
                    int px = (int)(Sprite.Center.x + (Mathf.Cos(angle * Mathf.Deg2Rad) * (hubSize * 0.5)));
                    int py = (int)(Sprite.Center.y + (Mathf.Sin(angle * Mathf.Deg2Rad) * (hubSize * 0.5)));

                    hubPoints.Add(new SS_Point(px, py));
                }

                SS_Texture tmpHub = new SS_Texture(Size, Size, Color.clear);
                SS_Drawing.PolygonFill(tmpHub, hubPoints.ToArray(), SS_StellarSprite.OutlineColor, SS_StellarSprite.FillColor);
                SS_Drawing.MergeColors(Sprite, tmpHub, 0, 0);

                List <SS_Point> hubPoints2 = new List <SS_Point>();
                for (float angle = 0; angle < 360f; angle += hubAngleSteps)
                {
                    int px = (int)(Sprite.Center.x + (Mathf.Cos(angle * Mathf.Deg2Rad) * (hubSize * 0.4)));
                    int py = (int)(Sprite.Center.y + (Mathf.Sin(angle * Mathf.Deg2Rad) * (hubSize * 0.4)));

                    hubPoints2.Add(new SS_Point(px, py));
                }

                SS_Texture tmpHub2 = new SS_Texture(Size, Size, Color.clear);
                SS_Drawing.PolygonFill(tmpHub2, hubPoints2.ToArray(), SS_StellarSprite.OutlineColor, SS_StellarSprite.FillColor);
                SS_Drawing.MergeColors(Sprite, tmpHub2, 0, 0);

                SS_Drawing.Outline(Sprite, Color.black);
                Texturize(Sprite, Color.magenta, tint, false, true);
                SS_StellarSprite.ShadeEdge(Sprite);

                SS_StellarSprite.Mirror(Sprite, SS_Mirror.TopRight);

                foreach (SS_Point p in podPositions)
                {
                    CreateFlare(Sprite, p, 32, false, Color.white);
                }

                foreach (SS_Point p in LightPoints)
                {
                    CreateFlare(Sprite, p, 16, true, Color.white);
                }

                CreateFlare(Sprite, Sprite.Center, hubSize, false, Color.white);
            }
        }
예제 #6
0
        void CreateRing(float scale, int sectionsPerQuarter, bool details, Color detailColor, bool lights)
        {
            //  Only draws top right quarter, the rest is mirrored
            List <SS_Point> DetailPoints = new List <SS_Point>();

            SS_Texture tmpTexture = new SS_Texture(Size, Size, Color.clear);

            int innerRadius = (int)((Size / 8) * scale);
            int outerRadius = (int)(((Size / 2) - 4) * scale);

            List <SS_Point> innerPoints = new List <SS_Point>();
            List <SS_Point> outerPoints = new List <SS_Point>();

            int step = 90 / sectionsPerQuarter;

            for (int a = 0; a <= 90; a += step)
            {
                int innerX = Sprite.Center.x + (int)(Mathf.Cos(a * Mathf.Deg2Rad) * innerRadius);
                int innerY = Sprite.Center.y + (int)(Mathf.Sin(a * Mathf.Deg2Rad) * innerRadius);

                innerPoints.Add(new SS_Point(innerX, innerY));

                int outerX = Sprite.Center.x + (int)(Mathf.Cos(a * Mathf.Deg2Rad) * outerRadius);
                int outerY = Sprite.Center.y + (int)(Mathf.Sin(a * Mathf.Deg2Rad) * outerRadius);

                outerPoints.Add(new SS_Point(outerX, outerY));

                if (lights)
                {
                    LightPoints.Add(new SS_Point(outerX, outerY));
                    LightPoints.Add(new SS_Point(Size - outerX, outerY));
                    LightPoints.Add(new SS_Point(Size - outerX, Size - outerY));
                    LightPoints.Add(new SS_Point(outerX, Size - outerY));
                }
            }

            // Determine centroids (detail points) for each ring section
            for (int i = 0; i < innerPoints.Count - 1; i++)
            {
                SS_Point[] points = new SS_Point[4];

                int j  = i;
                int j2 = i + 1;
                if (i == innerPoints.Count - 1)
                {
                    j2 = 0;
                }

                points[0] = innerPoints[j];
                points[1] = outerPoints[j];
                points[2] = outerPoints[j2];
                points[3] = innerPoints[j2];

                SS_Point centroid = SS_Utilities.Centroid(points);

                if (random.NextBool())
                {
                    DetailPoints.Add(centroid);
                }
            }

            List <SS_Point> ringPoints = new List <SS_Point>();

            for (int i = 0; i < innerPoints.Count; i++)
            {
                ringPoints.Add(innerPoints[i]);
            }

            for (int i = outerPoints.Count - 1; i >= 0; i--)
            {
                ringPoints.Add(outerPoints[i]);
            }

            SS_Drawing.PolygonFill(tmpTexture, ringPoints.ToArray(), SS_StellarSprite.OutlineColor, SS_StellarSprite.FillColor);

            // Add borders between sectons
            float colorVal      = 0;// random.Range(0.25f, 1f);
            Color sectionBorder = new Color(colorVal, colorVal, colorVal);

            for (int i = 0; i < innerPoints.Count; i++)
            {
                SS_Drawing.Line(tmpTexture, innerPoints[i].x, innerPoints[i].y, outerPoints[i].x, outerPoints[i].y, sectionBorder);
            }

            if (details)
            {
                for (int i = 0; i < DetailPoints.Count; i++)
                {
                    SS_Drawing.EllipseFill(tmpTexture, DetailPoints[i].x, DetailPoints[i].y, 8, 8, 12, SS_StellarSprite.OutlineColor, detailColor);
                }
            }

            // Texture the section
            Texturize(tmpTexture, SS_StellarSprite.FillColor, Color.grey, false, true);

            SS_StellarSprite.ShadeEdge(tmpTexture);
            SS_StellarSprite.Mirror(tmpTexture, SS_Mirror.TopRight);

            SS_Drawing.MergeColors(Sprite, tmpTexture, 0, 0);
        }
예제 #7
0
        public SS_Sun(int seed, int size, Color mainColor)
        {
            Seed = seed;
            Size = size;

            Sprite = new SS_Texture(Size, Size, Color.clear);

            Perlin noise     = new Perlin(0.05, 2, 0.5, 8, Seed, QualityMode.Low);
            Perlin noiseGlow = new Perlin(0.005, 2, 0.5, 6, Seed, QualityMode.Low);

            float radius = Size * 0.75f;

            Color[] tmp = new Color[3];
            tmp[0] = Color.white;
            tmp[1] = mainColor;
            tmp[2] = new Color(255f / 255f, 102f / 255f, 0f);

            Color[] gradient = SS_Utilities.CreateGradient(tmp, 8, 32);

            float atmosphereThickness = Size * 0.125f;
            Color hotnessColor        = Color.white;

            for (int y = 0; y < Size; y++)
            {
                for (int x = 0; x < Size; x++)
                {
                    float dist = Vector2.Distance(new Vector2(x, y), new Vector2(Sprite.Center.x, Sprite.Center.y));

                    if (dist <= (radius / 2))
                    {
                        float n = (float)noise.GetValue(x, y, 0);
                        n  = (n + 1.0f) * 0.5f;
                        n  = Mathf.Clamp(n, 0f, 1f);
                        n *= (gradient.Length - 1);

                        Color baseColor = gradient[(int)n];

                        // Edge Hotness
                        hotnessColor.a  = dist / (radius / 2);
                        hotnessColor.a += 0.0025f;

                        Color c = baseColor;
                        c.r = Mathf.Clamp(c.r + (hotnessColor.r * hotnessColor.a), 0, 1);
                        c.g = Mathf.Clamp(c.g + (hotnessColor.g * hotnessColor.a), 0, 1);
                        c.b = Mathf.Clamp(c.b + (hotnessColor.b * hotnessColor.a), 0, 1);

                        Sprite.SetPixel(x, y, c);
                    }

                    // Create glow
                    Color currentPixel = Sprite.GetPixel(x, y);

                    Color atmosphereColor = Color.white;
                    if (currentPixel == Color.clear)
                    {
                        atmosphereColor.a = 1;
                        float distToEdge = Vector2.Distance(new Vector2(x, y), new Vector2(Sprite.Center.x, Sprite.Center.y));
                        if (distToEdge < (radius / 2) + atmosphereThickness &&
                            distToEdge > (radius / 2))
                        {
                            float dist2 = dist - (radius / 2);
                            dist2 = (atmosphereThickness - dist2) / atmosphereThickness;

                            float glowNoise = (float)noiseGlow.GetValue(x, y, 0);
                            glowNoise         = (glowNoise + 1.0f) * 0.5f;
                            glowNoise         = Mathf.Clamp(glowNoise, 0f, 1f);
                            atmosphereColor.a = Mathf.Pow(dist2, 2) * glowNoise;

                            Sprite.SetPixel(x, y, atmosphereColor);
                        }
                    }
                }
            }
        }
예제 #8
0
        public SS_Asteroid(int seed, int size, Color[] colors, bool minerals, Color mineralColor, float lightAngle)
        {
            // Set Seed and Size
            Seed = seed;
            Size = size;

            // Create sprite texture
            Sprite = new SS_Texture(Size, Size, Color.clear);

            // Generate a color gradient
            Color[] gradientColors = SS_Utilities.CreateGradient(colors, 4, 8);

            // Initialize noise with parameters
            Perlin  perlin       = new Perlin(0.01, 2, 0.5, 8, Seed, QualityMode.Low);
            Voronoi mineralNoise = new Voronoi(0.1, 0.25, Seed + 1, true);

            // Set the light position based on the angle parameter
            Vector2 lightPosition = new Vector2(
                Sprite.Center.x + (Mathf.Cos(lightAngle * Mathf.Deg2Rad) * (Size / 4)),
                Sprite.Center.y + (Mathf.Sin(lightAngle * Mathf.Deg2Rad) * (Size / 4)));

            // Begin generating color data
            for (int y = 0; y < Size; y++)
            {
                for (int x = 0; x < Size; x++)
                {
                    // Distance of current pixel to the center of the sprite
                    float dist = Vector2.Distance(new Vector2(x, y), new Vector2(Sprite.Center.x, Sprite.Center.y));

                    // Get a noise value for the edge of the asteroid - adds roughness instead of a perfect circle
                    float edgeNoise = (float)perlin.GetValue(x, y, 0);
                    edgeNoise  = (edgeNoise + 1.0f) * 0.5f;
                    edgeNoise  = Mathf.Clamp(edgeNoise, 0f, 1f);
                    edgeNoise *= 16;

                    if (dist < (Size / 2) - edgeNoise)
                    {
                        float pixelNoise = (float)perlin.GetValue(x, y, 0);
                        pixelNoise = (pixelNoise + 1.0f) * 0.5f;
                        pixelNoise = Mathf.Clamp(pixelNoise, 0f, 1f);

                        float n = pixelNoise * (gradientColors.Length - 1);

                        // Generate color and noise so land doesn't look to smooth
                        Color pixelColor = gradientColors[(int)n];
                        pixelColor.a = 1.0f;

                        // Minerals
                        if (minerals)
                        {
                            float mineralAlpha = (float)mineralNoise.GetValue(x, y, 0);
                            mineralAlpha = (1.0f + mineralAlpha) * 0.5f;
                            mineralAlpha = Mathf.Clamp(mineralAlpha, 0.0f, 1.0f);
                            if (mineralAlpha > 0.65f)
                            {
                                pixelColor.r = mineralAlpha * mineralColor.r + (1 - mineralAlpha) * pixelColor.r;
                                pixelColor.g = mineralAlpha * mineralColor.g + (1 - mineralAlpha) * pixelColor.g;
                                pixelColor.b = mineralAlpha * mineralColor.b + (1 - mineralAlpha) * pixelColor.b;
                                pixelColor.a = 1f;
                            }
                        }

                        // Shadow
                        float lightDistance = Vector2.Distance(new Vector2(x, y), lightPosition);
                        lightDistance = 1.25f - (lightDistance / (Size / 2));
                        if (lightDistance < 0.025f)
                        {
                            lightDistance = 0.025f;
                        }
                        pixelColor.r *= lightDistance;
                        pixelColor.g *= lightDistance;
                        pixelColor.b *= lightDistance;

                        Sprite.SetPixel(x, y, pixelColor);
                    }
                }
            }
        }
예제 #9
0
        public SS_Planet(int seed, int size, Color[] colors, SS_PlanetType planetType, double frequency, double lacunarity, double persistence, int octaves, bool oceans, bool clouds, float cloudDensity, float cloudTransparency, bool atmosphere, bool city, float cityDensity, bool ring, float ringDetail, float lightAngle)
        {
            Seed = seed;

            if (ring)
            {
                Width = size * 2;
            }
            else
            {
                Width = size;
            }
            Height = size;

            // randomize based on seed
            random = new SS_Random(seed);

            // Create the sprite texture
            Sprite = new SS_Texture(Width, Height, Color.clear);

            // Create a gradient using the supplid colors and between 16 and 32 steps
            gradientColors = SS_Utilities.CreateGradient(colors, 16, 32);

            // Generate Perlin Noise
            //Perlin noise = new Perlin(frequency, 2, 0.5, 8, seed, QualityMode.High);
            Perlin noise      = new Perlin(frequency, lacunarity, persistence, octaves, seed, QualityMode.High);
            Perlin cloudNoise = new Perlin(0.02, 2, 0.5, 12, seed + 1, QualityMode.Low);

            // Radius of planet - only use 90% to make room for the atmosphere
            float radius = Height * 0.9f;

            // Oceans levels - determines how much water/terrain is visible
            float settleLevel = 0.4f;                   //random.Range(0.25f, 0.75f);

            // Thickeness of atmosphere - between 8-16 pixels
            int atmosphereThickness = random.Range((int)(Height * 0.01f), (int)(Height * 0.05f));

            atmosphereThickness = Mathf.Clamp(atmosphereThickness, 8, 16);

            // Calculate light position based on supplied lightAngle (degrees)
            Vector2 lightPosition = new Vector2(
                Sprite.Center.x + (Mathf.Cos(lightAngle * Mathf.Deg2Rad) * (radius * 0.8f)),
                Sprite.Center.y + (Mathf.Sin(lightAngle * Mathf.Deg2Rad) * (radius * 0.8f)));

            if (lightPosition.y < 0)
            {
                lightPosition.y = 0;
            }
            if (lightPosition.y > Height - 1)
            {
                lightPosition.y = Height - 1;
            }

            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    // Get distance of current point to the center of the sprite
                    float dist = Vector2.Distance(new Vector2(x, y), Sprite.Center.ToVector2);

                    // Check to see if this point is within the planets radius
                    if (dist <= (radius / 2))
                    {
                        // Get noise value for current point and clamp it between 0 and 1
                        float planetNoise = (float)noise.GetValue(x, y, 0);
                        planetNoise = (planetNoise + 1.0f) * 0.5f;
                        planetNoise = Mathf.Clamp(planetNoise, 0f, 1f);

                        // Gas Giant
                        if (planetType == SS_PlanetType.Gas_Giant)
                        {
                            // Get distance of the current point to the top-center of the sprite
                            float distNorthPole = Vector2.Distance(new Vector2(x, Height - 1), Sprite.Center.ToVector2);

                            // Generate gassy noise
                            float n = (float)noise.GetValue(dist / 10 + (planetNoise * 10f), y - (distNorthPole / 5) + (planetNoise * 10f), 0);
                            n  = (n + 1.0f) * 0.5f;
                            n  = Mathf.Clamp(n, 0f, 1f);
                            n *= (gradientColors.Length - 1);
                            Sprite.SetPixel(x, y, gradientColors[(int)n]);
                        }
                        // Terrestrial
                        else if (planetType == SS_PlanetType.Terrestrial)
                        {
                            Color pixelColor = new Color();

                            if (oceans)
                            {
                                if (planetNoise > settleLevel)
                                {
                                    float n = planetNoise * (gradientColors.Length - 1);

                                    // Generate color and noise so land doesn't look to smooth
                                    pixelColor   = gradientColors[(int)n];
                                    pixelColor  *= planetNoise;
                                    pixelColor.a = 1.0f;
                                }
                                else
                                {
                                    float n = planetNoise * ((gradientColors.Length - 1) / colors.Length);

                                    // solid ocean color
                                    pixelColor = gradientColors[(int)n];
                                }
                            }
                            else
                            {
                                float n = planetNoise * (gradientColors.Length - 1);

                                // Generate color and noise so land doesn't look to smooth
                                pixelColor = gradientColors[(int)n];
                            }

                            pixelColor.a = 1.0f;
                            Sprite.SetPixel(x, y, pixelColor);

                            if (clouds)
                            {
                                float cloud = (float)cloudNoise.GetValue(x, y, 0);
                                cloud = (cloud + 1.0f) * 0.5f;
                                cloud = Mathf.Clamp(cloud, 0f, 1f);

                                if (cloud >= cloudDensity)
                                {
                                    Color cloudColor  = Color.white;
                                    Color planetColor = Sprite.GetPixel(x, y);

                                    float alpha    = cloudTransparency * cloud;
                                    Color newColor = new Color();
                                    newColor.r = alpha * cloudColor.r + (1 - alpha) * planetColor.r;
                                    newColor.g = alpha * cloudColor.g + (1 - alpha) * planetColor.g;
                                    newColor.b = alpha * cloudColor.b + (1 - alpha) * planetColor.b;
                                    newColor.a = 1f;
                                    Sprite.SetPixel(x, y, newColor);
                                }
                            }
                        }
                        else if (planetType == SS_PlanetType.Barren)
                        {
                            // Generate gassy noise
                            float n = planetNoise;
                            n  = (n + 1.0f) * 0.5f;
                            n  = Mathf.Clamp(n, 0f, 1f);
                            n *= (gradientColors.Length - 1);
                            Sprite.SetPixel(x, y, gradientColors[(int)n]);
                        }
                    }

                    // Create inner atmosphere
                    if (atmosphere)
                    {
                        Color atmosphereColor = gradientColors[0];
                        atmosphereColor.a = 1f;

                        if (dist < (radius / 2) && dist > (radius / 2) - atmosphereThickness)
                        {
                            float d = Mathf.Abs(dist - (radius / 2));
                            float a = (atmosphereThickness - d) / atmosphereThickness;

                            Color newColor = SS_Utilities.Blend(atmosphereColor, Sprite.GetPixel(x, y), a);
                            Sprite.SetPixel(x, y, newColor);
                        }
                    }
                }
            }

            // Ring
            SS_Texture tmpRingRotated = new SS_Texture(Width, Height, Color.clear);
            SS_Texture tmpRing        = new SS_Texture(Width, Height, Color.clear);

            if (ring)
            {
                Perlin perlinRing = new Perlin(ringDetail, 2, 0.5, 8, seed, QualityMode.High);

                // Create a gradient using the supplid colors and between 16 and 32 steps
                Color[] ringColors = SS_Utilities.GenerateColorWheelColors(seed, 6);
                ringColors[1] = Color.black;
                ringColors[4] = Color.black;
                Color[] ringGradient = SS_Utilities.CreateGradient(ringColors, 8, 16);

                float ringW      = (int)(radius * 0.6);
                float ringH      = (int)(radius * random.Range(0.05f, 0.2f));
                int   resolution = 360;

                // Basically we are drawing a bunch of ellipses that get bigger
                for (int i = 0; i < (radius / 2) - 16; i++)
                {
                    // I'm spicy and confusing because my programmer is a douche.
                    // I'll explain
                    // get some noise and normalize it from 0-1
                    float ringNoise = (float)perlinRing.GetValue(i, 0, 0);
                    ringNoise = (ringNoise + 1.0f) * 0.5f;
                    ringNoise = Mathf.Clamp(ringNoise, 0.0f, 1f);

                    // multiple said 0.0-1 value by the number of colors available for the ring to get an int value for what color to use of the array
                    Color c = ringGradient[(int)(ringNoise * (ringGradient.Length - 1))];

                    // The darkness of the color value also sets the alpha value (darker values are more transparent)
                    c.a = (c.r + c.g + c.b) / 3f;

                    SS_Drawing.Ellipse(tmpRing, Sprite.Center.x, Sprite.Center.y, (int)ringW, (int)ringH, resolution * 4, c);

                    ringW += 1f;
                    ringH += 0.5f;
                }

                // rotate ring
                float ringAngle = random.Range(-3f, 3f);
                for (int y = 0; y < Height; y++)
                {
                    for (int x = 0; x < Width; x++)
                    {
                        SS_Point rotatedPoint = SS_Point.Rotate(new SS_Point(x, y), Sprite.Center.x, Sprite.Center.y, ringAngle);

                        tmpRingRotated.SetPixel(x, y, tmpRing.GetPixel(rotatedPoint.x, rotatedPoint.y));
                    }
                }

                //SS_Drawing.Blur(ref tmpRingRotated);

                // Copy Ring data to Planet Sprite ignoring the parts "behind" the planet.
                for (int y = 0; y < Height; y++)
                {
                    for (int x = 0; x < Width; x++)
                    {
                        // Bottom (in front of planet)
                        if (y <= (Height / 2))
                        {
                            // Make sure we have a ring pixel
                            if (tmpRingRotated.GetPixel(x, y) != Color.clear)
                            {
                                // if the pixel behind the ring pixel is clear, then just copy the data as is
                                if (Sprite.GetPixel(x, y) == Color.clear)
                                {
                                    Sprite.SetPixel(x, y, tmpRingRotated.GetPixel(x, y));
                                }
                                // if the pixel behind the ring pixel IS NOT clear, then we have to blend the two pixels
                                // using the ring's alpha for the blend factor
                                else
                                {
                                    Color newColor = SS_Utilities.Blend(tmpRingRotated.GetPixel(x, y), Sprite.GetPixel(x, y), tmpRingRotated.GetPixel(x, y).a);
                                    Sprite.SetPixel(x, y, newColor);
                                }
                            }
                        }
                        // Top (behind planet)
                        else
                        {
                            // no blending here, so just copy the pixel (ignoring pixels that already have a value)
                            if (Sprite.GetPixel(x, y) == Color.clear)
                            {
                                Sprite.SetPixel(x, y, tmpRingRotated.GetPixel(x, y));
                            }
                        }
                    }
                }
            }

            // Atmosphere and Shadows depend on ring
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    // Get distance of current point to the center of the sprite
                    float dist = Vector2.Distance(new Vector2(x, y), Sprite.Center.ToVector2);

                    // Create outer atmosphere
                    if (atmosphere)
                    {
                        Color currentPixel    = Sprite.GetPixel(x, y);
                        Color atmosphereColor = gradientColors[0];
                        atmosphereColor.a = 1f;

                        if (dist < (radius / 2) + atmosphereThickness && dist > (radius / 2))
                        {
                            float d = Mathf.Abs(dist - (radius / 2));
                            atmosphereColor.a = (atmosphereThickness - d) / atmosphereThickness;

                            if (currentPixel == Color.clear)
                            {
                                Sprite.SetPixel(x, y, atmosphereColor);
                            }
                            else
                            {
                                Color newColor = SS_Utilities.Blend(atmosphereColor, Sprite.GetPixel(x, y), atmosphereColor.a);
                                Sprite.SetPixel(x, y, newColor);
                            }
                        }
                    }

                    // Shadow
                    float lightDistance = Vector2.Distance(new Vector2(x, y), lightPosition);

                    lightDistance = 1.15f - SS_Utilities.Normalize(lightDistance, 0, Height);
                    if (lightDistance < 0.025f)
                    {
                        lightDistance = 0.025f;
                    }

                    Color lightingColor = Sprite.GetPixel(x, y);
                    lightingColor.r *= lightDistance;
                    lightingColor.g *= lightDistance;
                    lightingColor.b *= lightDistance;
                    Sprite.SetPixel(x, y, lightingColor);

                    // City lights
                    if (city)
                    {
                        if (dist <= (radius / 2))
                        {
                            float pixelNoise = (float)noise.GetValue(x, y, 0);
                            pixelNoise = (pixelNoise + 1.0f) * 0.5f;
                            pixelNoise = Mathf.Clamp(pixelNoise, 0f, 1f);

                            if (Sprite.GetPixel(x, y).grayscale < 0.025f)
                            {
                                // Find land edges
                                if (pixelNoise > settleLevel && pixelNoise < settleLevel + 0.05f)
                                {
                                    if (random.Range(0f, 1f) > cityDensity)
                                    {
                                        // I don't know - i just wrotes numbers beside some colors and hoped for the best.
                                        // Hurray for laziness!
                                        Color newColor = (Color.white * 0.65f + Color.yellow * 0.85f) * 0.8f;
                                        newColor.a = 1;

                                        // Blend the city light with the ring if there is one
                                        Color ringColor = tmpRingRotated.GetPixel(x, y);
                                        if (ring && ringColor != Color.clear)
                                        {
                                            newColor = SS_Utilities.Blend(newColor, ringColor, ringColor.a);
                                        }

                                        Sprite.SetPixel(x, y, newColor);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }