[SuppressMessage("ReSharper", "UnusedMember.Global")] //Because it is used in VertexPlanet.cfg >> Reflection <3 public static Color Dark(Color c) { if ((c.r > 0.5) || (c.g > 0.5) || (c.b > 0.5)) { c = c * new Color(0.5f, 0.5f, 0.5f); } return(c); }
/// <summary> /// Transforms a normal color Int32o the color form Atmosphere from Ground wants /// </summary> public static Color LightColor(Color c) { return(new Color(1 - c.r, 1 - c.g, 1 - c.b, 1)); }
/// <summary> /// Modifies a color so that it becomes a multiplier color /// </summary> public static Color ReColor(Color c, Color average) { // Do some maths.. return(new Color(c.r / average.r, c.g / average.g, c.b / average.b, 1)); }
/// <summary> /// Makes a color a bit different /// </summary> public static Color AlterColor(Color c) { return(new Color((Single)Math.Min(1, c.r * Generator.Random.Range(0.92, 1.02)), (Single)Math.Min(1, c.g * Generator.Random.Range(0.92, 1.02)), (Single)Math.Min(1, c.b * Generator.Random.Range(0.92, 1.02)), c.a)); }
/// <summary> /// Generates a PQS Setup + the Scaled Space Maps needed /// </summary> /// <returns></returns> // ReSharper disable once InconsistentNaming private static void GeneratePQS(ref ConfigNode node, String name, String folder, Planet planet, Color planetColor, out Color average, out List <Color> biomes) { // Log Console.WriteLine("Preparing to load PQS data"); // Create the node ConfigNode pqs = new ConfigNode("PQS"); // TODO: Material Settings? // Create a node for the mods ConfigNode mods = new ConfigNode("Mods"); pqs.AddConfigNode(mods); // Load the PQSDatabase and select a setup ConfigNode pqsDatabase = Utility.Load("pqs"); List <PQSPreset> data = pqsDatabase.nodes.Select(n => Parser.CreateObjectFromConfigNode <PQSPreset>(n)) .ToList(); data = data.Where(d => ((planet.radius * 100) > d.MinRadius) && ((planet.radius * 100) < d.MaxRadius)) .ToList(); PQSPreset setup = data[Random.Next(0, data.Count)]; // Setup the interpreter Interpreter interpreter = new Interpreter() .SetVariable("planet", planet, typeof(Planet)) .SetVariable("pqsVersion", setup, typeof(PQSPreset)) .SetVariable("Random", Random, typeof(Random)) .SetVariable("Seed", Seed, typeof(Int32)) .SetVariable("Color", Utility.GenerateColor(), typeof(Color)) .Reference(typeof(Parser)) .Reference(typeof(Generator)) .Reference(typeof(Utility)) .Reference(typeof(Utils)); // Transfer the mod nodes and evaluate expressions foreach (ConfigNode modNode in setup.Mods.nodes) { mods.AddConfigNode(Utility.Eval(modNode, interpreter)); } // Create a new PQSObject PQS pqsVersion = new PQS(planet.radius * 100); List <PQSMod> patchedmods = new List <PQSMod>(); // Log Console.WriteLine($"Created PQS Object for {name}"); // Get all loaded types List <Type> types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).ToList(); // Load mods from Config foreach (ConfigNode mod in mods.nodes) { // get the mod type if (types.Count(t => t.Name == mod.name) == 0) { continue; } Type loaderType = types.FirstOrDefault(t => t.Name == mod.name); String testName = mod.name != "LandControl" ? "PQSMod_" + mod.name : "PQSLandControl"; Type modType = types.FirstOrDefault(t => t.Name == testName); if ((loaderType == null) || (modType == null)) { continue; } // Do any PQS mods already exist on this PQS matching this mod? IEnumerable <PQSMod> existingmods = pqsVersion.mods.Where(m => m.GetType() == modType); // Create the loader Object loader = Activator.CreateInstance(loaderType); // Reflection, because C# being silly... :/ MethodInfo createNew = loaderType.GetMethod("Create", new[] { typeof(PQS) }); MethodInfo create = loaderType.GetMethod("Create", new[] { modType }); IList <PQSMod> pqsmods = existingmods as IList <PQSMod> ?? existingmods.ToList(); if (pqsmods.Any()) { // Attempt to find a PQS mod we can edit that we have not edited before PQSMod existingMod = pqsmods.FirstOrDefault(m => !patchedmods.Contains(m) && (!mod.HasValue("name") || (mod.HasValue("index") ? (pqsmods.ToList().IndexOf(m) == Int32.Parse(mod.GetValue("index"))) && (m.name == mod.GetValue("name")) : m.name == mod.GetValue("name")))); if (existingMod != null) { create.Invoke(loader, new Object[] { existingMod }); Parser.LoadObjectFromConfigurationNode(loader, mod); patchedmods.Add(existingMod); } else { createNew.Invoke(loader, new Object[] { pqsVersion }); Parser.LoadObjectFromConfigurationNode(loader, mod); } } else { createNew.Invoke(loader, new Object[] { pqsVersion }); Parser.LoadObjectFromConfigurationNode(loader, mod); } // Log Console.WriteLine($"Created a new instance of {loaderType.Name} on {name}"); } // Size Int32 width = pqsVersion.radius >= 600000 ? 4096 : pqsVersion.radius <= 100000 ? 1024 : 2048; // Biome colors int numBiomes = Random.Next(2, 10); biomes = new List <Color>(numBiomes); for (int i = 0; i < numBiomes; i++) { biomes.Add(Utility.GenerateColor()); } // Export ScaledSpace Maps using (UnsafeBitmap diffuse = new UnsafeBitmap(width, width / 2)) { using (UnsafeBitmap height = new UnsafeBitmap(width, width / 2)) { using (UnsafeBitmap biomeMap = new UnsafeBitmap(width, width / 2)) { Console.WriteLine("Exporting Scaled Space maps from the PQS. This could take a while..."); // Iterate over the PQS pqsVersion.SetupSphere(); diffuse.LockBitmap(); height.LockBitmap(); biomeMap.LockBitmap(); for (Int32 i = 0; i < width; i++) { for (Int32 j = 0; j < (width / 2); j++) { // Create a VertexBuildData VertexBuildData builddata = new VertexBuildData { directionFromCenter = Quaternion.CreateFromAngleAxis((360d / width) * i, Vector3.Up) * Quaternion .CreateFromAngleAxis(90d - ((180d / (width / 2.0)) * j), Vector3.Right) * Vector3.Forward, vertHeight = pqsVersion.radius }; // Build the maps pqsVersion.OnVertexBuildHeight(builddata); pqsVersion.OnVertexBuild(builddata); builddata.vertColor.a = 1f; Single h = Mathf.Clamp01((Single)((builddata.vertHeight - pqsVersion.radius) * (1d / pqsVersion.radiusMax))); Single h1 = Mathf.Clamp01((Single)((builddata.vertHeight - pqsVersion.radius) * (1d / (pqsVersion.radiusMax != 0 ? pqsVersion.radiusMax : planet.radius)))); diffuse.SetPixel(i, j, builddata.vertColor); height.SetPixel(i, j, new Color(h, h, h)); biomeMap.SetPixel(i, j, biomes[(int)(h1 * (numBiomes - 1))]); } } diffuse.UnlockBitmap(); height.UnlockBitmap(); biomeMap.UnlockBitmap(); // Save the textures Directory.CreateDirectory(Directory.GetCurrentDirectory() + "/systems/" + folder + "/PluginData/"); using (UnsafeBitmap normals = Utility.BumpToNormalMap(height, 9)) { // TODO: Implement something to make strength dynamic diffuse.Bitmap .Save(Directory.GetCurrentDirectory() + "/systems/" + folder + "/PluginData/" + name + "_Texture.png", ImageFormat.Png); height.Bitmap .Save(Directory.GetCurrentDirectory() + "/systems/" + folder + "/PluginData/" + name + "_Height.png", ImageFormat.Png); // In case you need it :) normals.Bitmap .Save(Directory.GetCurrentDirectory() + "/systems/" + folder + "/PluginData/" + name + "_Normals.png", ImageFormat.Png); biomeMap.Bitmap .Save(Directory.GetCurrentDirectory() + "/systems/" + folder + "/PluginData/" + name + "_Biomes.png", ImageFormat.Png); } } } // Log Console.WriteLine($"Saved maps to {Directory.GetCurrentDirectory() + "/systems/" + folder + "/PluginData/"}"); // Finish node.AddConfigNode(pqs); // Colors average = Utility.GetAverageColor(diffuse.Bitmap); } }
/// <summary> /// Generates the parameters for a planet /// </summary> private static ConfigNode GenerateBody(Planet planet, String folder, String referenceBody = "Sun", String systematicName = null) { String name = systematicName ?? Utility.GenerateName(); ConfigNode node = new ConfigNode("Body"); // Name if (planet != Kerbin) { node.AddValue("name", name); } else { node.AddValue("name", "Kerbin"); node.AddValue("cbNameLater", name); } // Random Main Menu Body node.AddValue("randomMainMenuBody", "" + (referenceBody == "Sun")); // Template ConfigNode template = new ConfigNode("Template"); node.AddConfigNode(template); if (planet != Kerbin) { if (planet.gas_giant) { template.AddValue("name", "Jool"); } else { template.AddValue("name", Utility.GetTemplate(planet.surface_pressure > 0.00001, false)); template.AddValue("removeAllPQSMods", "True"); if (planet.surface_pressure <= 0.00001) { template.AddValue("removeAtmosphere", "True"); } template.AddValue("removeOcean", "True"); // TODO: Handle atmospheres and ocean } } else { template.AddValue("name", "Kerbin"); template.AddValue("removePQSMods", "PQSLandControl, QuadEnhanceCoast, VertexHeightMap, VertexHeightNoiseVertHeightCurve2, VertexRidgedAltitudeCurve, VertexSimplexHeightAbsolute"); template.AddValue("removeAtmosphere", "True"); template.AddValue("removeOcean", "True"); } // Properties ConfigNode properties = new ConfigNode("Properties"); node.AddConfigNode(properties); properties.AddValue("radius", "" + (planet.radius * 100)); properties.AddValue("geeASL", "" + planet.surface_grav); properties.AddValue("rotationPeriod", "" + (planet.day * 60 * 60)); properties.AddValue("tidallyLocked", "" + planet.resonant_period); properties.AddValue("initialRotation", "" + Random.Next(0, 361)); properties.AddValue("albedo", "" + planet.albedo); properties.AddValue("timewarpAltitudeLimits", String.Join(" ", Templates.KerbinTimewarplimits.Select(i => (Int32)(i * ((planet.radius * 100) / 600000))))); //properties.AddValue("useTheInName", "False"); // Log Console.WriteLine($"Generated a planet named {name}. GasGiant: {planet.gas_giant}. Template: {template.GetValue("name")}"); // Color Color planetColor = Utility.GenerateColor(); // Orbit ConfigNode orbit = new ConfigNode("Orbit"); node.AddConfigNode(orbit); orbit.AddValue("referenceBody", referenceBody); orbit.AddValue("eccentricity", "" + planet.e); orbit.AddValue("semiMajorAxis", "" + (planet.a * 100 * Constants.KM_PER_AU)); orbit.AddValue("longitudeOfAscendingNode", "" + Random.Range(0, 181)); orbit.AddValue("meanAnomalyAtEpochD", "" + Random.Range(0, 181)); if (planet.gas_giant) { orbit.AddValue("color", Parser.WriteColor(Utility.AlterColor(planetColor))); } // Inclination orbit.AddValue("inclination", "" + Random.Range(-3, 5)); // Log Console.WriteLine($"Generated orbit around {referenceBody} for {name}"); // Scaled Space ConfigNode scaled = new ConfigNode("ScaledVersion"); node.AddConfigNode(scaled); // Material ConfigNode mat = new ConfigNode("Material"); scaled.AddConfigNode(mat); if (!planet.gas_giant) { mat.AddValue("texture", folder + "/PluginData/" + name + "_Texture.png"); mat.AddValue("normals", folder + "/PluginData/" + name + "_Normals.png"); } if (planet.gas_giant) { // Texture String[] files = Directory.GetFiles(Directory.GetCurrentDirectory() + "/data/textures/"); String texture = Random.Choose(files); String textureName = Path.GetFileNameWithoutExtension(texture) + ".png"; Directory.CreateDirectory(Directory.GetCurrentDirectory() + "/systems/" + folder + "/PluginData/"); File.Copy(texture, Directory.GetCurrentDirectory() + "/systems/" + folder + "/PluginData/" + textureName, true); mat.AddValue("texture", folder + "/PluginData/" + textureName); // Load the Image Color average; using (Bitmap image = new Bitmap(Directory.GetCurrentDirectory() + "/systems/" + folder + "/PluginData/" + textureName)) { average = Utility.GetAverageColor(image); } // Scale mat.AddValue("mainTexScale", (Random.Next(0, 2) == 1 ? 1 : -1) + "," + (Random.Next(0, 2) == 1 ? 1 : -1)); mat.AddValue("color", Parser.WriteColor(Utility.ReColor(Utility.AlterColor(planetColor), average))); ConfigNode gradient = new ConfigNode("Gradient"); mat.AddConfigNode(gradient); gradient.AddValue("0.0", Parser.WriteColor(Utility.AlterColor(planetColor))); gradient.AddValue("0.6", "0.0549,0.0784,0.141,1"); gradient.AddValue("1.0", "0.0196,0.0196,0.0196,1"); } // Log Console.WriteLine($"Generated scaled space for {name}"); // Atmosphere if (planet.surface_pressure > 0.00001) { ConfigNode atmosphere = new ConfigNode("Atmosphere"); node.AddConfigNode(atmosphere); atmosphere.AddValue("enabled", "True"); atmosphere.AddValue("oxygen", "" + Random.Boolean(10)); atmosphere.AddValue("atmosphereDepth", "" + (planet.radius * 100 * Random.Range(0.1, 0.16))); atmosphere.AddValue("atmosphereMolarMass", "" + (planet.molecule_weight / 1000)); atmosphere.AddValue("staticPressureASL", "" + ((planet.surface_pressure / 1000) * 101.324996948242)); atmosphere.AddValue("temperatureSeaLevel", "" + planet.surface_temp); if (planet.gas_giant) { atmosphere.AddValue("ambientColor", Parser.WriteColor(Utility.AlterColor(planetColor))); atmosphere.AddValue("lightColor", Parser.WriteColor(Utility.AlterColor(Utility.LightColor(planetColor)))); } GenerateAtmosphereCurves(ref atmosphere, planet.gas_giant ? "Jool" : Utility.GetTemplate(true, true)); // Log Console.WriteLine($"Generated atmosphere for {name}"); // Ocean if (!planet.gas_giant) { if (planet.surface_temp < planet.boil_point && (Random.Next(0, 100) < 35)) { ConfigNode ocean = new ConfigNode("Ocean"); node.AddConfigNode(ocean); ocean.AddValue("density", "" + planet.hydrosphere * (Random.NextDouble() * 2)); ocean.AddValue("minLevel", "1"); ocean.AddValue("maxLevel", "6"); ocean.AddValue("minDetailDistance", "8"); ocean.AddValue("maxQuadLengthsPerFrame", "0.03"); Color waterColor = Utility.GenerateColor(); ocean.AddValue("oceanColor", Parser.WriteColor(waterColor)); ConfigNode oceanmat = new ConfigNode("Material"); ocean.AddConfigNode(oceanmat); oceanmat.AddValue("colorFromSpace", Parser.WriteColor(waterColor)); oceanmat.AddValue("color", Parser.WriteColor(waterColor)); ConfigNode oceanfallbackmat = new ConfigNode("FallbackMaterial"); ocean.AddConfigNode(oceanfallbackmat); oceanfallbackmat.AddValue("colorFromSpace", Parser.WriteColor(waterColor)); oceanfallbackmat.AddValue("color", Parser.WriteColor(waterColor)); Console.WriteLine($"Generated ocean for {name}"); } } } // Rings :D if (planet.gas_giant && (Random.Next(0, 100) < 5)) { ConfigNode rings = new ConfigNode("Rings"); node.AddConfigNode(rings); ConfigNode ringDatatbase = Utility.Load("rings"); ConfigNode data = Random.Choose(ringDatatbase.nodes); RingPrefab def = Parser.CreateObjectFromConfigNode <RingPrefab>(data); foreach (RingPrefab.Ring r in def.Rings) { ConfigNode ring = new ConfigNode("Ring"); rings.AddConfigNode(ring); ring.AddValue("innerRadius", "" + (planet.radius * 0.1 * r.InnerRadius)); ring.AddValue("outerRadius", "" + (planet.radius * 0.1 * r.OuterRadius)); ring.AddValue("angle", "" + r.Angle); ring.AddValue("color", Parser.WriteColor(Utility.AlterColor(planetColor))); ring.AddValue("lockRotation", "" + r.LockRotation); ring.AddValue("unlit", "False"); } // Log Console.WriteLine($"Generated rings around {name}"); } // PQS if (!planet.gas_giant) { Color average; List <Color> biomes; GeneratePQS(ref node, name, folder, planet, planetColor, out average, out biomes); // Biomes ConfigNode bio = new ConfigNode("Biomes"); properties.AddConfigNode(bio); for (int i = 0; i < biomes.Count; i++) { ConfigNode biome = new ConfigNode("Biome"); bio.AddConfigNode(biome); biome.AddValue("name", "Biome " + (i + 1)); biome.AddValue("value", "1"); biome.AddValue("color", Parser.WriteColor(biomes[i])); } Console.WriteLine($"Generated biomes for {name}"); // Apply colors orbit.AddValue("color", Parser.WriteColor(Utility.AlterColor(average))); if (node.HasNode("Atmosphere")) { ConfigNode atmosphere = node.GetNode("Atmosphere"); atmosphere.AddValue("ambientColor", Parser.WriteColor(Utility.AlterColor(average))); atmosphere.AddValue("lightColor", Parser.WriteColor(Utility.AlterColor(Utility.LightColor(average)))); } ConfigNode gradient = new ConfigNode("Gradient"); mat.AddConfigNode(gradient); gradient.AddValue("0.0", Parser.WriteColor(Utility.AlterColor(average))); gradient.AddValue("0.6", "0.0549,0.0784,0.141,1"); gradient.AddValue("1.0", "0.0196,0.0196,0.0196,1"); } // Log Console.WriteLine($"Generation of body {name} finished!"); Console.WriteLine(); // Return return(node); }