Beispiel #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);
                    }
                }
            }
        }
Beispiel #2
0
        public static void Blur(ref SS_Texture texture)
        {
            SS_Texture tmp = new SS_Texture(texture.Width, texture.Height, Color.clear);

            float v = 1.0f / 9.0f;

            float[,] kernel = { { v, v, v },
                                { v, v, v },
                                { v, v, v } };

            // Loop through every pixel in the image
            for (int y = 1; y < texture.Height - 1; y++)
            {
                for (int x = 1; x < texture.Width - 1; x++)
                {
                    float alpha = texture.GetPixel(x, y).a;

                    Color sum = Color.clear; // Kernel sum for this pixel
                    for (int ky = -1; ky <= 1; ky++)
                    {
                        for (int kx = -1; kx <= 1; kx++)
                        {
                            sum += kernel[ky + 1, kx + 1] * texture.GetPixel(x + kx, y + ky);
                        }
                    }

                    sum.a = alpha;
                    tmp.SetPixel(x, y, sum);
                }
            }

            // Apply changes
            texture = tmp;
        }
Beispiel #3
0
        void Texturize(SS_Texture texture, Color targetColor, Color tint, bool highlights, bool shading)
        {
            Perlin perlin = new Perlin(0.025, 2, 0.5, 8, Seed, QualityMode.Low);

            SS_Texture BaseTexture = SS_StellarSprite.GenerateBaseTexture(Seed, texture.Width, texture.Height, 8 * (random.Range(1, 2)));

            for (int y = texture.Height / 2; y < texture.Height; y++)
            {
                for (int x = texture.Width / 2; x < texture.Width; x++)
                {
                    if (texture.GetPixel(x, y) == targetColor)
                    {
                        Color hullShade = BaseTexture.GetPixel(x, y);

                        // Pixel shade
                        float pixelNoise = (float)perlin.GetValue(x, y, 0);
                        pixelNoise = (pixelNoise + 3.0f) * 0.25f; // 0.5 to 1.0
                        pixelNoise = Mathf.Clamp(pixelNoise, 0.5f, 1f);

                        hullShade *= tint * pixelNoise;

                        if (shading)
                        {
                            SS_StellarSprite.PixelLighting(texture, x, y, ref hullShade);
                        }

                        hullShade.a = 1.0f;
                        texture.SetPixel(x, y, hullShade);
                    }
                }
            }
        }
Beispiel #4
0
        public static void Swirl(SS_Texture texture, int aX, int aY, int radius, float twists)
        {
            SS_Texture tmpTexture = new SS_Texture(texture.Width, texture.Height, Color.clear);

            for (int y = 0; y < texture.Height; y++)
            {
                for (int x = 0; x < texture.Width; x++)
                {
                    // compute the distance and angle from the swirl center:
                    int   pixelX        = x - aX;
                    int   pixelY        = y - aY;
                    float pixelDistance = Mathf.Sqrt((pixelX * pixelX) + (pixelY * pixelY));
                    float pixelAngle    = Mathf.Atan2(pixelY, pixelX);

                    // work out how much of a swirl to apply (1.0 in the center fading out to 0.0 at the radius):

                    float swirlAmount = 1.0f - (pixelDistance / radius);

                    if (swirlAmount > 0.0f)
                    {
                        float twistAngle = twists * swirlAmount * Mathf.PI * 2.0f;

                        // adjust the pixel angle and compute the adjusted pixel co-ordinates:
                        pixelAngle += twistAngle;
                        pixelX      = (int)(Mathf.Cos(pixelAngle) * pixelDistance);
                        pixelY      = (int)(Mathf.Sin(pixelAngle) * pixelDistance);
                    }

                    // read and write the pixel
                    tmpTexture.SetPixel(x, y, texture.GetPixel(aX + pixelX, aY + pixelY));
                }
            }

            texture.SetPixels(tmpTexture.GetPixels());
        }
        // Generate a generally boring metallic-like texture (ships and stations use this)
        public static SS_Texture GenerateBaseTexture(int seed, int textureWidth, int textureHeight, int detail)
        {
            SS_Texture tmpTexture = new SS_Texture(textureWidth, textureHeight, Color.clear);

            Perlin noise = new Perlin(0.005, 2, 0.5, 6, seed, QualityMode.Low);

            int offsetX = tmpTexture.Width / detail;
            int offsetY = tmpTexture.Height / detail;

            for (int y = 0; y < tmpTexture.Height; y += offsetY)
            {
                for (int x = 0; x < tmpTexture.Width; x += offsetX)
                {
                    float n1 = (float)noise.GetValue(x, y, 0);
                    n1 = (n1 + 3.0f) * 0.25f;
                    n1 = Mathf.Clamp(n1, 0.5f, 1f);

                    float n2 = (float)noise.GetValue(x, y, 0);
                    n2 = (n2 + 3.0f) * 0.25f;
                    n2 = Mathf.Clamp(n2, 0.95f, 1f);

                    Color c = new Color(n1, n1, n1, 1f);

                    SS_Drawing.RectangleFill(tmpTexture, x, y, offsetX, offsetY, c, c);

                    Color current = tmpTexture.GetPixel(x, y);
                    Color c3      = new Color(current.r * n2, current.g * n2, current.b * n2);
                    SS_Drawing.Line(tmpTexture, x, y, x, y + detail, c3);
                    SS_Drawing.Line(tmpTexture, x, y, x + detail, y, c3);
                }
            }

            return(tmpTexture);
        }
Beispiel #6
0
        public static void Outline(SS_Texture spriteTexture, Color outlineColor)
        {
            for (int y = 1; y < spriteTexture.Height - 1; y++)
            {
                for (int x = 1; x < spriteTexture.Width - 1; x++)
                {
                    Color c = spriteTexture.GetPixel(x, y);

                    if (c != Color.clear)
                    {
                        Color tL = spriteTexture.GetPixel(x - 1, y - 1);
                        Color tM = spriteTexture.GetPixel(x, y - 1);
                        Color tR = spriteTexture.GetPixel(x + 1, y - 1);

                        Color mL = spriteTexture.GetPixel(x - 1, y);
                        Color mR = spriteTexture.GetPixel(x + 1, y);

                        Color bL = spriteTexture.GetPixel(x - 1, y + 1);
                        Color bM = spriteTexture.GetPixel(x, y + 1);
                        Color bR = spriteTexture.GetPixel(x + 1, y + 1);

                        if (tL == Color.clear || tM == Color.clear || tR == Color.clear ||
                            mL == Color.clear || mR == Color.clear ||
                            bL == Color.clear || bM == Color.clear || bR == Color.clear)
                        {
                            spriteTexture.SetPixel(x, y, outlineColor);
                        }
                    }
                }
            }

            for (int y = 0; y < spriteTexture.Height; y++)
            {
                for (int x = 0; x < spriteTexture.Width; x++)
                {
                    Color c = spriteTexture.GetPixel(x, y);

                    if (c != Color.clear)
                    {
                        if (x == 0 || x == spriteTexture.Width - 1 || y == 0 || y == spriteTexture.Height - 1)
                        {
                            spriteTexture.SetPixel(x, y, outlineColor);
                        }
                    }
                }
            }
        }
Beispiel #7
0
        private void Texturize(SS_Texture texture, Color targetColor, Color tint, bool highlights, bool shading)
        {
            Perlin  perlin            = new Perlin(ColorDetail, 2, 0.5, 8, Seed, QualityMode.High);
            Voronoi hightlightVoronoi = new Voronoi(ColorDetail, 2, Seed, true);

            SS_Texture BaseTexture = SS_StellarSprite.GenerateBaseTexture(Seed, Size, Size, 16);

            for (int y = Size / 2; y < Size; y++)
            {
                for (int x = 0; x < Size; x++)
                {
                    if (texture.GetPixel(x, y) == targetColor)
                    {
                        Color hullShade = BaseTexture.GetPixel(x, y);

                        //Pixel shade
                        float pixelNoise = (float)perlin.GetValue(x, y, 0);
                        pixelNoise = (pixelNoise + 3.0f) * 0.25f; // 0.5 to 1.0
                        pixelNoise = Mathf.Clamp(pixelNoise, 0.5f, 1f);

                        hullShade *= tint * pixelNoise;

                        if (highlights)
                        {
                            // Pixel shade
                            float hightlightNoise = (float)hightlightVoronoi.GetValue(x, y, 0);
                            hightlightNoise = (hightlightNoise + 1.0f) * 0.5f; // 0.0 to 1.0
                            hightlightNoise = Mathf.Clamp(hightlightNoise, 0.0f, 1f);

                            if (hightlightNoise <= 0.75f)
                            {
                                hullShade = ColorBase * pixelNoise;
                            }
                            else
                            {
                                hullShade = ColorHighlight * pixelNoise;
                            }
                        }

                        // Check the current pixel and find when it hits a solid black outline.  if it does
                        // Make the current pixel a bit darker - do for all 4 dirtections
                        if (shading)
                        {
                            SS_StellarSprite.PixelLighting(texture, x, y, ref hullShade);
                        }

                        hullShade.a = 1.0f;
                        texture.SetPixel(x, y, hullShade);
                    }
                }
            }

            // Mirror
            SS_StellarSprite.Mirror(texture, SS_Mirror.Vertical);
        }
Beispiel #8
0
        public static void FloodFill(SS_Texture texture, SS_Point pt, Color targetColor, Color replacementColor)
        {
            targetColor = texture.GetPixel(pt.x, pt.y);
            if (targetColor == replacementColor)
            {
                return;
            }

            Stack <SS_Point> pixels = new Stack <SS_Point>();

            pixels.Push(pt);
            while (pixels.Count != 0)
            {
                SS_Point temp = pixels.Pop();
                int      y1   = temp.y;
                while (y1 >= 0 && texture.GetPixel(temp.x, y1) == targetColor)
                {
                    y1--;
                }
                y1++;
                bool spanLeft  = false;
                bool spanRight = false;
                while (y1 < texture.Height && texture.GetPixel(temp.x, y1) == targetColor)
                {
                    texture.SetPixel(temp.x, y1, replacementColor);

                    if (!spanLeft && temp.x > 0 && texture.GetPixel(temp.x - 1, y1) == targetColor)
                    {
                        pixels.Push(new SS_Point(temp.x - 1, y1));
                        spanLeft = true;
                    }
                    else if (spanLeft && temp.x - 1 == 0 && texture.GetPixel(temp.x - 1, y1) != targetColor)
                    {
                        spanLeft = false;
                    }
                    if (!spanRight && temp.x < texture.Width - 1 && texture.GetPixel(temp.x + 1, y1) == targetColor)
                    {
                        pixels.Push(new SS_Point(temp.x + 1, y1));
                        spanRight = true;
                    }
                    else if (spanRight && temp.x < texture.Width - 1 && texture.GetPixel(temp.x + 1, y1) != targetColor)
                    {
                        spanRight = false;
                    }
                    y1++;
                }
            }
        }
        public static void Mirror(SS_Texture texture, SS_Mirror location)
        {
            // Mirror top right horizontally and vertically
            if (location == SS_Mirror.TopRight)
            {
                // Vertical
                for (int y = (texture.Height / 2); y < texture.Height; y++)
                {
                    for (int x = texture.Width / 2; x < texture.Width; x++)
                    {
                        Color target = texture.GetPixel(x, y);
                        if (target != Color.clear)
                        {
                            int y1 = texture.Height - y - 1;
                            texture.SetPixel(x, y1, texture.GetPixel(x, y));
                        }
                    }
                }

                // Horizontal
                for (int y = 0; y < texture.Height; y++)
                {
                    for (int x = (texture.Width / 2); x < texture.Width; x++)
                    {
                        Color target = texture.GetPixel(x, y);
                        if (target != Color.clear)
                        {
                            int x1 = texture.Width - x - 1;
                            texture.SetPixel(x1, y, texture.GetPixel(x, y));
                        }
                    }
                }
            }
            else if (location == SS_Mirror.Vertical)
            {
                // Vertical
                for (int y = (texture.Height / 2); y < texture.Height; y++)
                {
                    for (int x = 0; x < texture.Width; x++)
                    {
                        Color target = texture.GetPixel(x, y);
                        if (target != Color.clear)
                        {
                            int y1 = texture.Height - y - 1;
                            texture.SetPixel(x, y1, texture.GetPixel(x, y));
                        }
                    }
                }
            }
        }
Beispiel #10
0
        public static Color[] GenerateColorWheelColors(int seed, int count)
        {
            SS_Texture colorWheel = ColorWheel();

            Color[] colors = new Color[count];

            SS_Random random = new SS_Random(seed);

            float angle = random.Range(0f, 360f);

            for (int i = 0; i < count; i++)
            {
                float xPos = (colorWheel.Width / 2) + Mathf.Cos(angle) * 32;
                float yPos = (colorWheel.Height / 2) + Mathf.Sin(angle) * 32;

                colors[i] = colorWheel.GetPixel((int)xPos, (int)yPos);
                angle    += 360 / count;
            }

            return(colors);
        }
Beispiel #11
0
        public static void MergeColors(SS_Texture target, SS_Texture source, int xOffset, int yOffset)
        {
            int x1 = xOffset;
            int y1 = yOffset;

            int x2 = 0;
            int y2 = 0;

            for (int y = y1; y < y1 + source.Height; y++)
            {
                x2 = 0;
                for (int x = x1; x < x1 + source.Width; x++)
                {
                    Color c = source.GetPixel(x2, y2);

                    if (c != Color.clear)
                    {
                        target.SetPixel(x, y, c);
                    }
                    x2++;
                }
                y2++;
            }
        }
Beispiel #12
0
        private void CreateWing(SS_Texture targetTexture, Color baseColor, bool highlights)
        {
            // Temporary texture
            SS_Texture tmpTexture = new SS_Texture(Size, Size, Color.clear);

            // Wing dimensions
            int wingLength  = 64;// (int)(random.RangeEven(32, 64));
            int wingSize    = (int)(random.Range(4, 12));
            int wingCenterX = wingSize / 2;
            int wingOffsetX = random.Range((Size / 2) - (BodyLength / 2), (Size / 2) + wingSize);

            // Data points for body edge
            List <SS_Point> fPoints = new List <SS_Point>();
            List <SS_Point> bPoints = new List <SS_Point>();

            // Noise generators
            RidgedMultifractal fWingNoise = new RidgedMultifractal(WingDetail, 2, 8, Seed, QualityMode.Medium);
            RidgedMultifractal bWingNoise = new RidgedMultifractal(WingDetail, 2, 8, Seed + 1, QualityMode.Medium);

            // Determine if wing has a flat edge
            int fEdgeMod = random.RangeEven(0, 8);
            int bEdgeMod = random.RangeEven(0, 8);

            // Start point of wing (this determinds if the wings are separated or joined
            int startY = 0;

            if (random.NextBool())
            {
                startY = random.RangeEven(2, 8);
            }

            int fEndY = Sprite.Center.y + (wingLength / 2) - fEdgeMod;
            int bEndY = Sprite.Center.y + (wingLength / 2) - bEdgeMod;

            // Calculate steps based on length of modified wing length
            int fStep = (fEndY - Sprite.Center.y) / 4;
            int bStep = (bEndY - Sprite.Center.y) / 4;

            // Front Edge
            for (int y = Sprite.Center.y + startY; y <= fEndY + 1; y += fStep)
            {
                // Get some funky noise value for the back of the wing
                float noise = (float)fWingNoise.GetValue(0, y, 0);
                noise = (noise + 1.0f) * 0.5f; // Convert to 0 to 1
                noise = Mathf.Clamp(noise, 0.05f, 1f);

                int x = (wingOffsetX + wingCenterX) + (int)(noise * wingSize);
                if (x > Size - 1)
                {
                    x = Size - 1;                 // Clamp to bounds
                }
                fPoints.Add(new SS_Point(x, y));
            }

            // Back Edge
            for (int y = Sprite.Center.y + startY; y <= bEndY + 1; y += bStep)
            {
                // Get some funky noise value for the front of the wing
                float noise = (float)bWingNoise.GetValue(0, y, 0);
                noise = (noise + 1.0f) * 0.5f; // Convert to 0 to 1
                noise = Mathf.Clamp(noise, 0.05f, 1f);

                int x = (wingOffsetX - wingCenterX) - (int)(noise * wingSize);
                if (x < 0)
                {
                    x = 0;          // Clamp to bounds
                }
                bPoints.Add(new SS_Point(x, y));
            }

            // Smoothing
            for (int j = 0; j < 2; j++)
            {
                for (int i = 0; i < fPoints.Count - 1; i++)
                {
                    float x = (fPoints[i].x + fPoints[i + 1].x) / 2f;
                    fPoints[i] = new SS_Point((int)x, fPoints[i].y);
                }

                for (int i = 0; i < bPoints.Count - 1; i++)
                {
                    float x = (bPoints[i].x + bPoints[i + 1].x) / 2f;
                    bPoints[i] = new SS_Point((int)x, bPoints[i].y);
                }
            }

            // Build polygon using both sets of points (left and right side)
            List <SS_Point> points = new List <SS_Point>();

            for (int i = 0; i < fPoints.Count; i++)
            {
                points.Add(fPoints[i]);
            }
            // Add the back edge points backwards to the point list to keep the vertex ordering correct
            for (int i = bPoints.Count - 1; i >= 0; i--)
            {
                points.Add(bPoints[i]);
            }

            // Create wing weapons before drawing the actual wing so they appear underneigth
            CreateWeapon(targetTexture, new SS_Point(wingOffsetX + wingCenterX, (Size / 2) + (startY + (wingLength / 4))), Color.yellow);
            CreateWeapon(targetTexture, new SS_Point(wingOffsetX + wingCenterX, (Size / 2) - (startY + (wingLength / 4))), Color.yellow);

            // Draw polygon for the wing
            SS_Drawing.PolygonFill(tmpTexture, points.ToArray(), SS_StellarSprite.FillColor, SS_StellarSprite.FillColor);

            // Mirror Vertically for the bottom/right wing
            int cntr = 1;

            for (int y = Sprite.Center.y; y < Size; y++)
            {
                for (int x = 0; x < Size; x++)
                {
                    int newY = y - cntr;
                    tmpTexture.SetPixel(x, newY, tmpTexture.GetPixel(x, y));
                }
                cntr += 2;
            }

            // Draw the wing(s) outline
            SS_Drawing.Outline(tmpTexture, SS_StellarSprite.OutlineColor);

            // Texturize and shade
            if (!DebugDrawing)
            {
                Texturize(tmpTexture, SS_StellarSprite.FillColor, baseColor, highlights, true);
                SS_StellarSprite.ShadeEdge(tmpTexture);
            }
            SS_Drawing.MergeColors(targetTexture, tmpTexture, 0, 0);
        }
Beispiel #13
0
        public SS_Blackhole(int seed, int size)
        {
            Seed = seed;
            Size = size;

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

            float radius = Size * 0.75f;
            float atmosphereThickness = Size * 0.125f;

            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));
                    int dist = SS_Point.Distance(new SS_Point(x, y), Sprite.Center);

                    if (dist <= (radius / 2))
                    {
                        Sprite.SetPixel(x, y, Color.black);
                    }

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

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

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

            // Calculate the number of light points around the even horizon based on the square root of the size halfed.
            int lightSpecCount = (int)(Mathf.Sqrt(Size) / 2) * Size;

            // Create specs of light around event horizon
            for (int i = 0; i < lightSpecCount; i++)
            {
                int a    = random.Range(0, 359);
                int dist = (short)random.Range(radius * 0.25f, radius * 0.65f);

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

                SS_Point p = new SS_Point(x, y);

                int distToCenter = SS_Point.Distance(p, Sprite.Center);

                float v = 1 - (distToCenter / radius);

                Color c = new Color(v, v, v);

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

            SS_Drawing.Swirl(Sprite, Sprite.Width / 2, Sprite.Height / 2, Sprite.Width / 2, 5f);

            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 * 0.25f))
                    {
                        Color c = Sprite.GetPixel(x, y);
                        c.a = 1 - (dist / (Size / 2));
                        Sprite.SetPixel(x, y, c);
                    }
                }
            }

            SS_Drawing.Ellipse(Sprite, Sprite.Center.x, Sprite.Center.y, (int)(radius * 0.25), (int)(radius * 0.25), 32, Color.white);
        }
        // Light pixels as they approach black borders
        public static void PixelLighting(SS_Texture texture, int x, int y, ref Color hullShade)
        {
            int Width  = texture.Width;
            int Height = texture.Height;

            float eastShading      = 1.5f;
            float westShading      = 1.5f;
            float northShading     = 1.5f;
            float southShading     = 1.5f;
            int   shadingThickness = 4;

            bool hasEastBorder = false;
            int  cntr          = 0;

            while (!hasEastBorder)
            {
                int currentX = x + cntr;
                if (currentX < 0)
                {
                    currentX = 0;
                }
                if (currentX > Width - 1)
                {
                    currentX = Width - 1;
                }
                Color shadingPixel = texture.GetPixel(currentX, y);
                if (shadingPixel == Color.black)
                {
                    hasEastBorder = true;
                }

                cntr++;
                if (cntr > shadingThickness)
                {
                    break;
                }
            }
            if (hasEastBorder)
            {
                hullShade *= eastShading;
            }

            bool hasWestBorder = false;

            cntr = 0;
            while (!hasWestBorder)
            {
                int currentX = x - cntr;
                if (currentX < 0)
                {
                    currentX = 0;
                }
                if (currentX > Width - 1)
                {
                    currentX = Width - 1;
                }
                Color shadingPixel = texture.GetPixel(currentX, y);
                if (shadingPixel == Color.black)
                {
                    hasWestBorder = true;
                }

                cntr++;
                if (cntr > shadingThickness)
                {
                    break;
                }
            }
            if (hasWestBorder)
            {
                hullShade *= westShading;
            }

            bool hasNorthBorder = false;

            cntr = 0;
            while (!hasNorthBorder)
            {
                int currentY = y - cntr;
                if (currentY < 0)
                {
                    currentY = 0;
                }
                if (currentY > Height - 1)
                {
                    currentY = Height - 1;
                }
                Color shadingPixel = texture.GetPixel(x, currentY);
                if (shadingPixel == Color.black)
                {
                    hasNorthBorder = true;
                }

                cntr++;
                if (cntr > shadingThickness)
                {
                    break;
                }
            }
            if (hasNorthBorder)
            {
                hullShade *= northShading;
            }

            bool hasSouthBorder = false;

            cntr = 0;
            while (!hasSouthBorder)
            {
                int currentY = y + cntr;
                if (currentY < 0)
                {
                    currentY = 0;
                }
                if (currentY > Height - 1)
                {
                    currentY = Height - 1;
                }
                Color shadingPixel = texture.GetPixel(x, currentY);
                if (shadingPixel == Color.black)
                {
                    hasSouthBorder = true;
                }

                cntr++;
                if (cntr > shadingThickness)
                {
                    break;
                }
            }
            if (hasSouthBorder)
            {
                hullShade *= southShading;
            }
        }
        // Darken any pixels next the black borders
        public static void ShadeEdge(SS_Texture texture)
        {
            Color[] tmpColors = new Color[texture.Width * texture.Height];
            for (int y = 0; y < texture.Height; y++)
            {
                for (int x = 0; x < texture.Width; x++)
                {
                    tmpColors[x + y * texture.Width] = texture.GetPixel(x, y);
                }
            }

            for (int y = 1; y < texture.Height - 1; y++)
            {
                for (int x = 1; x < texture.Width - 1; x++)
                {
                    Color c = texture.GetPixel(x, y);

                    if (c != Color.clear && c != Color.black)
                    {
                        Color tL = texture.GetPixel(x - 1, y - 1);
                        Color tM = texture.GetPixel(x, y - 1);
                        Color tR = texture.GetPixel(x + 1, y - 1);

                        Color mL = texture.GetPixel(x - 1, y);
                        Color mR = texture.GetPixel(x + 1, y);

                        Color bL = texture.GetPixel(x - 1, y + 1);
                        Color bM = texture.GetPixel(x, y + 1);
                        Color bR = texture.GetPixel(x + 1, y + 1);

                        if ((tL == Color.black || tM == Color.black || tR == Color.black ||
                             mL == Color.black || mR == Color.black ||
                             bL == Color.black || bM == Color.black || bR == Color.black))
                        {
                            c.r *= 0.5f;
                            c.g *= 0.5f;
                            c.b *= 0.5f;

                            tmpColors[x + y * texture.Width] = c;
                        }
                    }
                }
            }

            for (int x = 0; x < texture.Width; x++)
            {
                if (texture.GetPixel(x, 0) != Color.clear)
                {
                    texture.SetPixel(x, 0, Color.black);
                }
                if (texture.GetPixel(x, texture.Height - 1) != Color.clear)
                {
                    texture.SetPixel(x, texture.Height - 1, Color.black);
                }
            }

            texture.SetPixels(tmpColors);
        }
Beispiel #16
0
        private void CreateBody(SS_Texture targetTexture, SS_ShipBody body, int length, int smoothCount, bool highlights)
        {
            // Temporary texture
            SS_Texture tmpTexture = new SS_Texture(Size, Size, Color.clear);

            // Determine type of body to generate
            if (body == SS_ShipBody.Human)
            {
                // Data points for body edge
                List <SS_Point> topPoints    = new List <SS_Point>();
                List <SS_Point> bottomPoints = new List <SS_Point>();

                // Noise generator
                Perlin perlin = new Perlin(BodyDetail, 2, 0.5, 8, Seed, QualityMode.Medium);

                // Calculated step points
                int step = length / GetRandomBodyStep(length);

                for (int xCnt = 0; xCnt <= length; xCnt += step)
                {
                    // Get some funky noise value
                    float noise = (float)perlin.GetValue(xCnt, 0, 0);
                    noise = (noise + 3.0f) * 0.25f; // Convert to 0 to 1
                    noise = Mathf.Clamp(noise, 0.05f, 1f);

                    int x = Sprite.Center.x - (length / 2) + xCnt;
                    if (x > Size - 1)
                    {
                        x = Size - 1;
                    }
                    int y = (int)(noise * (Size / 4));

                    topPoints.Add(new SS_Point(x, Sprite.Center.y + y));
                }

                // Fix first and last points so they are less ugly than a random tip and butt.
                topPoints[0] = new SS_Point(topPoints[0].x, Sprite.Center.y + 4);
                topPoints[topPoints.Count - 1] = new SS_Point(topPoints[topPoints.Count - 1].x, Sprite.Center.y + 2);

                // Loop through all the points and smooth them out a bit
                for (int j = 0; j < smoothCount; j++)
                {
                    for (int i = 0; i < topPoints.Count - 1; i++)
                    {
                        float y = (topPoints[i].y + topPoints[i + 1].y) / 2f;
                        y            = Mathf.Ceil(y);
                        topPoints[i] = new SS_Point(topPoints[i].x, (int)y);
                    }
                }

                // Duplicate top points to bottom points but inverse the Y position
                for (int i = 0; i < topPoints.Count; i++)
                {
                    SS_Point p = topPoints[i];
                    p.y = Size - p.y - 1;
                    bottomPoints.Add(p);
                }

                // Draw the body outline - use lines since they seem to be more symmetric (pixel placement) than my polygon drawing... not sure why.
                SS_Drawing.LineStrip(tmpTexture, topPoints.ToArray(), SS_StellarSprite.OutlineColor);
                SS_Drawing.LineStrip(tmpTexture, bottomPoints.ToArray(), SS_StellarSprite.OutlineColor);

                // Connect both sizes of lines
                SS_Drawing.Line(tmpTexture, topPoints[0].x, topPoints[0].y, topPoints[0].x, (Size - topPoints[0].y), SS_StellarSprite.OutlineColor);
                SS_Drawing.Line(tmpTexture, topPoints[topPoints.Count - 1].x, topPoints[topPoints.Count - 1].y, topPoints[topPoints.Count - 1].x, (Size - topPoints[topPoints.Count - 1].y), SS_StellarSprite.OutlineColor);

                // Fill with magenta
                SS_Drawing.FloodFillArea(tmpTexture, Sprite.Center, SS_StellarSprite.FillColor);

                // Inner detail (same shape as body, but slightly smaller)
                for (int i = 0; i < topPoints.Count; i++)
                {
                    topPoints[i] = SS_Point.Scale(topPoints[i], Sprite.Center, 0.5f, 0.25f);
                }

                for (int i = 0; i < bottomPoints.Count; i++)
                {
                    bottomPoints[i] = SS_Point.Scale(bottomPoints[i], Sprite.Center, 0.5f, 0.25f);
                }

                // Draw the body outline - use lines since they seem to be more symmetric (pixel placement) than my polygon drawing... not sure why.
                SS_Drawing.LineStrip(tmpTexture, topPoints.ToArray(), SS_StellarSprite.OutlineColor);
                SS_Drawing.LineStrip(tmpTexture, bottomPoints.ToArray(), SS_StellarSprite.OutlineColor);

                // Connect both sizes of lines
                SS_Drawing.Line(tmpTexture, topPoints[0].x, topPoints[0].y, topPoints[0].x, (Size - topPoints[0].y), SS_StellarSprite.OutlineColor);
                SS_Drawing.Line(tmpTexture, topPoints[topPoints.Count - 1].x, topPoints[topPoints.Count - 1].y, topPoints[topPoints.Count - 1].x, (Size - topPoints[topPoints.Count - 1].y), SS_StellarSprite.OutlineColor);

                // Texturize and shade
                if (!DebugDrawing)
                {
                    Texturize(tmpTexture, SS_StellarSprite.FillColor, ColorBase, highlights, true);
                    SS_StellarSprite.ShadeEdge(tmpTexture);
                }
                SS_Drawing.MergeColors(targetTexture, tmpTexture, 0, 0);
            }
            else if (body == SS_ShipBody.Alien)
            {
                float bodyAngleSteps = 360.0f / 32;

                List <SS_Point> bodyPoints = new List <SS_Point>();
                for (float angle = 0; angle < 360f; angle += bodyAngleSteps)
                {
                    int px = (int)((Size / 2) + (Mathf.Cos(angle * Mathf.Deg2Rad) * (BodyLength * 0.5)));
                    int py = (int)((Size / 2) + (Mathf.Sin(angle * Mathf.Deg2Rad) * (BodyLength * 0.5)));

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

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

                if (!DebugDrawing)
                {
                    Texturize(tmpTexture, SS_StellarSprite.FillColor, ColorBase, false, true);
                }

                Color ringColor = random.NextColor();
                int   ringMin   = random.RangeEven(12, 18);
                int   ringMax   = random.RangeEven(18, 24);

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

                        if (dist >= ringMin && dist <= ringMax)
                        {
                            tmpTexture.SetPixel(x, y, tmpTexture.GetPixel(x, y) * ringColor);
                        }
                    }
                }

                if (random.NextBool())
                {
                    CreateFlare(tmpTexture, Sprite.Center, 48, true, random.NextColor());
                }
                if (random.NextBool())
                {
                    CreateFlare(tmpTexture, Sprite.Center, 24, true, Color.white);
                }

                if (!DebugDrawing)
                {
                    SS_StellarSprite.ShadeEdge(tmpTexture);
                }
                SS_Drawing.MergeColors(targetTexture, tmpTexture, 0, 0);
            }
        }
Beispiel #17
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);
                        }
                    }
                }
            }
        }
Beispiel #18
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);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }