private void CreateWeapon(SS_Texture targetTexture, SS_Point offset, Color baseColor) { // Temporary texture SS_Texture tmpTexture = new SS_Texture(Size, Size, Color.clear); // Keeping the weapons very simple for now // Just draw 4 layers of lines to create the weapon shape (rectangle) for (int y = offset.y - 2; y < offset.y + 2; y++) { int xEnd = offset.x + 8; if (xEnd > Size - 1) { xEnd = Size - 1; } SS_Drawing.Line(tmpTexture, offset.x, y, xEnd, y, baseColor); } // Create Weapon Points WeaponPoint.Add(new SS_Point(offset.x + 8, offset.y)); SS_Drawing.Outline(tmpTexture, SS_StellarSprite.OutlineColor); //Texturize but dont shade (more vibrant) if (!DebugDrawing) { Texturize(tmpTexture, SS_StellarSprite.FillColor, baseColor, false, false); } SS_Drawing.MergeColors(targetTexture, tmpTexture, 0, 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); } } } }
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); } }
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); }
public SS_Cloud(int seed, int size, double frequency, double lacunarity, int octaves, Color tint, float brightness) { // Create sprite texture Sprite = new SS_Texture(size, size, Color.white); // Initialize noise with parameters RidgedMultifractal noise = new RidgedMultifractal(frequency, lacunarity, octaves, seed, QualityMode.Medium); // Create cloud for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { float distance = SS_Point.Distance(new SS_Point(x, y), Sprite.Center); float n = (float)noise.GetValue(x, y, 0); Color pixelColor = tint * n * brightness; float blackness = ((pixelColor.r + pixelColor.g + pixelColor.b) / 3.0f); float fade = distance / (size / 2); pixelColor.a = (1f - fade) * blackness; if (distance > (size / 2)) { pixelColor.a = 0f; } Sprite.SetPixel(x, y, pixelColor); } } }
private void CreateCockpit(SS_Texture targetTexture, Color baseColor) { // Temporary texture SS_Texture tmpTexture = new SS_Texture(Size, Size, Color.clear); // 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(0.1, 2, 0.5, 8, Seed, QualityMode.Medium); // Calculated step points int step = 2; int xStart = Sprite.Center.x + (BodyLength / 2) - (BodyLength / 4) - 2; for (int xCnt = 0; xCnt <= (BodyLength / 4); 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 = xStart + xCnt; int y = (int)(noise * 4); topPoints.Add(new SS_Point(x, Sprite.Center.y + 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 (one side only, the other will be mirrored) 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, new SS_Point(xStart + 1, Sprite.Center.y), SS_StellarSprite.FillColor); // Texturize and shade if (!DebugDrawing) { Texturize(tmpTexture, SS_StellarSprite.FillColor, baseColor, false, true); SS_StellarSprite.ShadeEdge(tmpTexture); } SS_Drawing.MergeColors(targetTexture, tmpTexture, 0, 0); }
public static SS_Point Scale(SS_Point p, SS_Point center, float scaleX, float scaleY) { SS_Point scaledPoint = new SS_Point(); int cX = ((center.x + p.x) / 2); int cY = ((center.y + p.y) / 2); scaledPoint.x = cX + (int)((p.x - cX) * scaleX); scaledPoint.y = cY + (int)((p.y - cY) * scaleY); return(scaledPoint); }
public static void LineStrip(SS_Texture texture, SS_Point[] SS_Points, Color color) { SS_Point p, p2; // Loop through all SS_Points and draw lines between them except for the last one for (int i = 0; i < SS_Points.Length - 1; i++) { p = new SS_Point((short)SS_Points[i].x, (short)SS_Points[i].y); p2 = new SS_Point((short)SS_Points[i + 1].x, (short)SS_Points[i + 1].y); Line(texture, p.x, p.y, p2.x, p2.y, color); } }
void CreatePods(int count, int pW, int pH, int resolution, int distanceFromCenter, double scale, Color baseColor) { SS_Texture tmpTexture = new SS_Texture(Size, Size, Color.clear); int step = 360 / count; // Setup pod positions List <SS_Point> pods = new List <SS_Point>(); for (int a = 0; a < 359; a += step) { int x = Sprite.Center.x + (int)(Mathf.Cos(a * Mathf.Deg2Rad) * distanceFromCenter); int y = Sprite.Center.y + (int)(Mathf.Sin(a * Mathf.Deg2Rad) * distanceFromCenter); pods.Add(new SS_Point(x, y)); } // Draw pods for (int i = 0; i < pods.Count; i++) { SS_Point[] positions = new SS_Point[resolution + 1]; // angle from float angleToStation = Mathf.Atan2(pods[i].y - Sprite.Center.x, pods[i].x - Sprite.Center.x) * Mathf.Rad2Deg; angleToStation += 90; for (int j = 0; j <= resolution; j++) { // Angle from pod Sprite.Center float angleToPod = (float)j / (float)resolution * 2.0f * Mathf.PI; // Set the original pod point float x = pods[i].x + ((short)((pW * scale) * Mathf.Cos(angleToPod))); float y = pods[i].y + ((short)((pH * scale) * Mathf.Sin(angleToPod))); // rotate the point based on it's angle from the Sprite.Center of the pod float xRotated = pods[i].x + (x - pods[i].x) * Mathf.Cos(angleToStation * Mathf.Deg2Rad) - (y - pods[i].y) * Mathf.Sin(angleToStation * Mathf.Deg2Rad); float yRotated = pods[i].y + (x - pods[i].x) * Mathf.Sin(angleToStation * Mathf.Deg2Rad) + (y - pods[i].y) * Mathf.Cos(angleToStation * Mathf.Deg2Rad); positions[j] = new SS_Point((int)xRotated, (int)yRotated); } SS_Drawing.PolygonFill(tmpTexture, positions, SS_StellarSprite.OutlineColor, SS_StellarSprite.FillColor); } Texturize(tmpTexture, SS_StellarSprite.FillColor, baseColor, false, true); SS_StellarSprite.ShadeEdge(tmpTexture); SS_StellarSprite.Mirror(tmpTexture, SS_Mirror.TopRight); SS_Drawing.MergeColors(Sprite, tmpTexture, 0, 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++; } } }
private static void Ellipse(SS_Texture texture, int x, int y, int rW, int rH, int resolution, bool fill, Color colorOutline, Color colorFill) { SS_Point[] positions = new SS_Point[resolution + 1]; for (int i = 0; i <= resolution; i++) { float angle = (float)i / (float)resolution * 2.0f * Mathf.PI; positions[i] = new SS_Point(x + ((short)(rW * Mathf.Cos(angle))), y + ((short)(rH * Mathf.Sin(angle)))); } Polygon(texture, positions, colorOutline); if (fill) { FloodFillArea(texture, new SS_Point(x, y), colorFill); } }
public static SS_Point Rotate(SS_Point p, int cx, int cy, float angle) { float s = Mathf.Sin(angle * Mathf.Deg2Rad); float c = Mathf.Cos(angle * Mathf.Deg2Rad); // translate point back to origin: p.x -= cx; p.y -= cy; // rotate point float rotatedX = p.x * c - p.y * s; float rotatedY = p.x * s + p.y * c; // translate point back: p.x = (int)rotatedX + cx; p.y = (int)rotatedY + cy; return(p); }
private void CreateEngine(SS_Texture targetTexture, int count) { // Temporary texture SS_Texture tmpTexture = new SS_Texture(Size, Size, Color.clear); // Noise generator Perlin perlin = new Perlin(0.1, 2, 0.5, 8, Seed, QualityMode.Medium); int yStep = Size / (1 + count); for (int i = 1; i <= count; i++) { // Data points for body edge List <SS_Point> topPoints = new List <SS_Point>(); List <SS_Point> bottomPoints = new List <SS_Point>(); // Calculated step points int step = 2; int xStart = (Size / 2) - (BodyLength / 2); for (int xCnt = 0; xCnt <= 16; 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 = xStart + xCnt; int y = (int)(noise * 4); int mod = 0; if (count >= 4) { mod = 2; } topPoints.Add(new SS_Point(x, i * yStep + y + mod)); bottomPoints.Add(new SS_Point(x, i * yStep - y - 1 + mod)); } // Draw the body outline (one side only, the other will be mirrored) SS_Drawing.LineStrip(tmpTexture, topPoints.ToArray(), SS_StellarSprite.FillColor); SS_Drawing.LineStrip(tmpTexture, bottomPoints.ToArray(), SS_StellarSprite.FillColor); // Connect both sizes of lines SS_Drawing.Line(tmpTexture, topPoints[0].x, topPoints[0].y, bottomPoints[0].x, bottomPoints[0].y, SS_StellarSprite.FillColor); SS_Drawing.Line(tmpTexture, topPoints[topPoints.Count - 1].x, topPoints[topPoints.Count - 1].y, bottomPoints[bottomPoints.Count - 1].x, bottomPoints[bottomPoints.Count - 1].y, SS_StellarSprite.FillColor); SS_Point centroid = new SS_Point(xStart + 2, i * yStep + 1); // Fill with magenta SS_Drawing.FloodFillArea(tmpTexture, centroid, SS_StellarSprite.FillColor); // Create Exhaust Points ExhaustPoint.Add(new SS_Point(topPoints[0].x, bottomPoints[0].y + ((topPoints[0].y - bottomPoints[0].y) / 2))); } // Draw a bar connecting all the engines (no floaters) if (count > 1) { int top = (Size / 2) + ((count * 8) / 2) + 1; int bottom = (Size / 2) - ((count * 8) / 2) - 1; SS_Drawing.Line(tmpTexture, (Size / 2) - (BodyLength / 2) + 10, bottom, (Size / 2) - (BodyLength / 2) + 10, top, SS_StellarSprite.FillColor); SS_Drawing.Line(tmpTexture, (Size / 2) - (BodyLength / 2) + 11, bottom, (Size / 2) - (BodyLength / 2) + 11, top, SS_StellarSprite.FillColor); SS_Drawing.Line(tmpTexture, (Size / 2) - (BodyLength / 2) + 12, bottom, (Size / 2) - (BodyLength / 2) + 12, top, SS_StellarSprite.FillColor); } // Outline engines SS_Drawing.Outline(tmpTexture, SS_StellarSprite.OutlineColor); // Texturize and shade if (!DebugDrawing) { Texturize(tmpTexture, SS_StellarSprite.FillColor, ColorEngine, false, true); SS_StellarSprite.ShadeEdge(tmpTexture); } SS_Drawing.MergeColors(targetTexture, tmpTexture, 0, 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); } } } } } } } }
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); } }
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); }
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); }
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); }
public static int Distance(SS_Point p1, SS_Point p2) { return((int)Mathf.Sqrt(Mathf.Pow((p2.x - p1.x), 2) + Mathf.Pow((p2.y - p1.y), 2))); }
public static void FloodFillArea(SS_Texture texture, SS_Point pt, Color aColor) { int w = texture.Width; int h = texture.Height; Color[] colors = texture.GetPixels(); Color refCol = colors[pt.x + pt.y * w]; Queue <SS_Point> nodes = new Queue <SS_Point>(); nodes.Enqueue(new SS_Point(pt.x, pt.y)); while (nodes.Count > 0) { SS_Point current = nodes.Dequeue(); for (int i = current.x; i < w; i++) { Color C = colors[i + current.y * w]; if (C != refCol || C == aColor) { break; } colors[i + current.y * w] = aColor; if (current.y + 1 < h) { C = colors[i + current.y * w + w]; if (C == refCol && C != aColor) { nodes.Enqueue(new SS_Point(i, current.y + 1)); } } if (current.y - 1 >= 0) { C = colors[i + current.y * w - w]; if (C == refCol && C != aColor) { nodes.Enqueue(new SS_Point(i, current.y - 1)); } } } for (int i = current.x - 1; i >= 0; i--) { Color C = colors[i + current.y * w]; if (C != refCol || C == aColor) { break; } colors[i + current.y * w] = aColor; if (current.y + 1 < h) { C = colors[i + current.y * w + w]; if (C == refCol && C != aColor) { nodes.Enqueue(new SS_Point(i, current.y + 1)); } } if (current.y - 1 >= 0) { C = colors[i + current.y * w - w]; if (C == refCol && C != aColor) { nodes.Enqueue(new SS_Point(i, current.y - 1)); } } } } texture.SetPixels(colors); }