/// <summary> /// A coroutine that updates the scaled space in the background /// </summary> private IEnumerator UpdateScaledSpace() { // Path to the cache String CacheDirectory = "saves/" + HighLogic.SaveFolder + "/diversity/"; for (Int32 a = 0; a < scaledSpaceUpdate.Count; a++) { // Get the body CelestialBody body = scaledSpaceUpdate[a]; current = body.bodyDisplayName; index = a + 1; // Mesh Directory.CreateDirectory(CacheDirectory + "mesh"); Utility.UpdateScaledMesh(body.scaledBody, body.pqsController, body, CacheDirectory + "mesh/"); // Textures Directory.CreateDirectory(CacheDirectory + "textures/" + body.bodyName); String TextureDirectory = CacheDirectory + "textures/" + body.bodyName + "/"; if (File.Exists(TextureDirectory + "color.png") && File.Exists(TextureDirectory + "normal.png")) { Texture2D colorMap = Utility.LoadTexture(TextureDirectory + "color.png", false, true, true); yield return(null); Texture2D normalMap = Utility.LoadTexture(TextureDirectory + "normal.png", false, true, true); yield return(null); // Apply them to the ScaledVersion body.scaledBody.GetComponent <MeshRenderer>().material.SetTexture("_MainTex", colorMap); body.scaledBody.GetComponent <MeshRenderer>().material.SetTexture("_BumpMap", normalMap); yield return(null); } else { // Get PQS PQS pqs = body.pqsController; pqs.SetupExternalRender(); // Get the mods Action <PQS.VertexBuildData> modOnVertexBuildHeight = (Action <PQS.VertexBuildData>)Delegate.CreateDelegate( typeof(Action <PQS.VertexBuildData>), pqs, typeof(PQS).GetMethod("Mod_OnVertexBuildHeight", BindingFlags.Instance | BindingFlags.NonPublic)); Action <PQS.VertexBuildData> modOnVertexBuild = (Action <PQS.VertexBuildData>)Delegate.CreateDelegate( typeof(Action <PQS.VertexBuildData>), pqs, typeof(PQS).GetMethod("Mod_OnVertexBuild", BindingFlags.Instance | BindingFlags.NonPublic)); PQSMod[] mods = pqs.GetComponentsInChildren <PQSMod>().Where(m => m.sphere == pqs && m.modEnabled).ToArray(); // Create the Textures Texture2D colorMap = new Texture2D(pqs.mapFilesize, pqs.mapFilesize / 2, TextureFormat.ARGB32, true); Texture2D heightMap = new Texture2D(pqs.mapFilesize, pqs.mapFilesize / 2, TextureFormat.RGB24, true); // Arrays Color[] colorMapValues = new Color[pqs.mapFilesize * (pqs.mapFilesize / 2)]; Color[] heightMapValues = new Color[pqs.mapFilesize * (pqs.mapFilesize / 2)]; // Wait a some time yield return(null); // Loop through the pixels for (Int32 y = 0; y < (pqs.mapFilesize / 2); y++) { for (Int32 x = 0; x < pqs.mapFilesize; x++) { // Update Message percent = ((Double)((y * pqs.mapFilesize) + x) / ((pqs.mapFilesize / 2) * pqs.mapFilesize)) * 100; // Create a VertexBuildData PQS.VertexBuildData data = new PQS.VertexBuildData { directionFromCenter = (QuaternionD.AngleAxis((360d / pqs.mapFilesize) * x, Vector3d.up) * QuaternionD.AngleAxis(90d - (180d / (pqs.mapFilesize / 2)) * y, Vector3d.right)) * Vector3d.forward, vertHeight = pqs.radius }; // Build from the Mods modOnVertexBuildHeight(data); modOnVertexBuild(data); // Adjust the height Double height = (data.vertHeight - pqs.radius) * (1d / pqs.mapMaxHeight); if (height < 0) { height = 0; } else if (height > 1) { height = 1; } // Adjust the Color Color color = data.vertColor; if (!pqs.mapOcean) { color.a = 1f; } else if (height > pqs.mapOceanHeight) { color.a = 0f; } else { color = pqs.mapOceanColor.A(1f); } // Set the Pixels colorMapValues[(y * pqs.mapFilesize) + x] = color; heightMapValues[(y * pqs.mapFilesize) + x] = new Color((Single)height, (Single)height, (Single)height); } yield return(null); } // Apply the maps colorMap.SetPixels(colorMapValues); colorMap.Apply(); heightMap.SetPixels(heightMapValues); yield return(null); // Close the Renderer pqs.CloseExternalRender(); // Bump to Normal Map Texture2D normalMap = Utility.BumpToNormalMap(heightMap, 7); // Serialize them to disk File.WriteAllBytes(TextureDirectory + "color.png", colorMap.EncodeToPNG()); File.WriteAllBytes(TextureDirectory + "normal.png", normalMap.EncodeToPNG()); yield return(null); // Apply them to the ScaledVersion body.scaledBody.GetComponent <MeshRenderer>().material.SetTexture("_MainTex", colorMap); body.scaledBody.GetComponent <MeshRenderer>().material.SetTexture("_BumpMap", normalMap); yield return(null); } // OnDemand if (Templates.IsKopernicusInstalled) { Type onDemandType = Templates.Types.FirstOrDefault(t => t.Name == "ScaledSpaceOnDemand"); Component onDemand = body.scaledBody.GetComponent(onDemandType); if (onDemand != null) { FieldInfo texture = onDemandType.GetField("texture"); FieldInfo normals = onDemandType.GetField("normals"); String RelativeDirectory = TextureDirectory.Replace(KSPUtil.ApplicationRootPath, "../"); texture.SetValue(onDemand, RelativeDirectory + "color.png"); normals.SetValue(onDemand, RelativeDirectory + "normal.png"); } } percent = 0; yield return(null); } guiEnabled = false; scaledSpaceUpdate.Clear(); FlightDriver.SetPause(false, false); InputLockManager.RemoveControlLock("planetaryDiversityCache"); }
/// <summary> /// Renders the Window /// </summary> protected override void Render(Int32 id) { // Call base base.Render(id); // Check for PQS if (Current.pqsController == null) { Button(Localization.LOC_KITTOPIATECH_PQSEDITOR_ADD, () => { // Create a new PQS GameObject controllerRoot = new GameObject(Current.name); controllerRoot.transform.parent = Current.transform; PQS pqsVersion = controllerRoot.AddComponent <PQS>(); // I am at this time unable to determine some of the magic parameters which cause the PQS to work... (Or just lazy but who cares :P) PSystemBody Laythe = Utility.FindBody(Injector.StockSystemPrefab.rootBody, "Laythe"); Utility.CopyObjectFields(Laythe.pqsVersion, pqsVersion); pqsVersion.surfaceMaterial = Laythe.pqsVersion.surfaceMaterial; // Create the fallback material (always the same shader) pqsVersion.fallbackMaterial = new PQSProjectionFallbackLoader(); pqsVersion.fallbackMaterial.name = Guid.NewGuid().ToString(); // Create the celestial body transform GameObject mod = new GameObject("_CelestialBody"); mod.transform.parent = controllerRoot.transform; PQSMod_CelestialBodyTransform transform = mod.AddComponent <PQSMod_CelestialBodyTransform>(); transform.sphere = pqsVersion; transform.forceActivate = false; transform.deactivateAltitude = 115000; transform.forceRebuildOnTargetChange = false; transform.planetFade = new PQSMod_CelestialBodyTransform.AltitudeFade(); transform.planetFade.fadeFloatName = "_PlanetOpacity"; transform.planetFade.fadeStart = 100000.0f; transform.planetFade.fadeEnd = 110000.0f; transform.planetFade.valueStart = 0.0f; transform.planetFade.valueEnd = 1.0f; transform.planetFade.secondaryRenderers = new List <GameObject>(); transform.secondaryFades = new PQSMod_CelestialBodyTransform.AltitudeFade[0]; transform.requirements = PQS.ModiferRequirements.Default; transform.modEnabled = true; transform.order = 10; // Create the material direction mod = new GameObject("_Material_SunLight"); mod.transform.parent = controllerRoot.gameObject.transform; PQSMod_MaterialSetDirection lightDirection = mod.AddComponent <PQSMod_MaterialSetDirection>(); lightDirection.sphere = pqsVersion; lightDirection.valueName = "_sunLightDirection"; lightDirection.requirements = PQS.ModiferRequirements.Default; lightDirection.modEnabled = true; lightDirection.order = 100; // Create the UV planet relative position mod = new GameObject("_Material_SurfaceQuads"); mod.transform.parent = controllerRoot.transform; PQSMod_UVPlanetRelativePosition uvs = mod.AddComponent <PQSMod_UVPlanetRelativePosition>(); uvs.sphere = pqsVersion; uvs.requirements = PQS.ModiferRequirements.Default; uvs.modEnabled = true; uvs.order = 999999; // Crete the quad mesh colliders mod = new GameObject("QuadMeshColliders"); mod.transform.parent = controllerRoot.gameObject.transform; PQSMod_QuadMeshColliders collider = mod.AddComponent <PQSMod_QuadMeshColliders>(); collider.sphere = pqsVersion; collider.maxLevelOffset = 0; collider.physicsMaterial = new PhysicMaterial(); collider.physicsMaterial.name = "Ground"; collider.physicsMaterial.dynamicFriction = 0.6f; collider.physicsMaterial.staticFriction = 0.8f; collider.physicsMaterial.bounciness = 0.0f; collider.physicsMaterial.frictionCombine = PhysicMaterialCombine.Maximum; collider.physicsMaterial.bounceCombine = PhysicMaterialCombine.Average; collider.requirements = PQS.ModiferRequirements.Default; collider.modEnabled = true; collider.order = 100; // Assing the new PQS Current.pqsController = pqsVersion; pqsVersion.transform.position = Current.transform.position; pqsVersion.transform.localPosition = Vector3.zero; // Set mode _mode = Modes.List; }, new Rect(20, index * distance + 10, 350, 20)); return; } // Mode List if (_mode == Modes.List) { // Get the PQS-Spheres and their mods IEnumerable <PQS> pqsList = Current.GetComponentsInChildren <PQS>(true); IEnumerable <PQSMod> pqsModList = Current.GetComponentsInChildren <PQSMod>(true); // Scroll BeginScrollView(250, (pqsList.Count() + pqsModList.Count()) * distance + distance * 4, 20); // Index index = 0; // Render foreach (PQS pqs in pqsList) { Button(pqs.ToString(), () => { _mode = Modes.PQS; _sphere = pqs; }, new Rect(20, index * distance + 10, 350, 20)); } foreach (PQSMod mod in pqsModList) { Button(mod.ToString(), () => { _mode = Modes.PQSMod; _sphere = mod.sphere; _mod = mod; }, new Rect(20, index * distance + 10, 350, 20)); } index++; Button(Localization.LOC_KITTOPIATECH_PQSEDITOR_ADD_MOD, () => _mode = Modes.AddMod, new Rect(20, index * distance + 10, 350, 20)); if (Current.pqsController.ChildSpheres.All(s => s.name != Current.pqsController.name + "Ocean")) { Button(Localization.LOC_KITTOPIATECH_PQSEDITOR_ADD_OCEAN, () => { // Generate the PQS object GameObject gameObject = new GameObject("Ocean"); gameObject.layer = Constants.GameLayers.LocalSpace; PQS ocean = gameObject.AddComponent <PQS>(); // Setup materials PSystemBody Body = Utility.FindBody(Injector.StockSystemPrefab.rootBody, "Laythe"); foreach (PQS oc in Body.pqsVersion.GetComponentsInChildren <PQS>(true)) { if (oc.name != "LaytheOcean") { continue; } // Copying Laythes Ocean-properties Utility.CopyObjectFields <PQS>(oc, ocean); } // Load our new Material into the PQS ocean.surfaceMaterial = new PQSOceanSurfaceQuadLoader(ocean.surfaceMaterial); ocean.surfaceMaterial.name = Guid.NewGuid().ToString(); // Load fallback material into the PQS ocean.fallbackMaterial = new PQSOceanSurfaceQuadFallbackLoader(ocean.fallbackMaterial); ocean.fallbackMaterial.name = Guid.NewGuid().ToString(); // Create the UV planet relative position GameObject mod = new GameObject("_Material_SurfaceQuads"); mod.transform.parent = gameObject.transform; PQSMod_UVPlanetRelativePosition uvs = mod.AddComponent <PQSMod_UVPlanetRelativePosition>(); uvs.sphere = ocean; uvs.requirements = PQS.ModiferRequirements.Default; uvs.modEnabled = true; uvs.order = 999999; // Create the AerialPerspective Material AerialPerspectiveMaterial mat = new AerialPerspectiveMaterial(); mat.Create(ocean); // Create the OceanFX OceanFX oceanFX = new OceanFX(); oceanFX.Create(ocean); // Apply the Ocean ocean.transform.parent = Current.pqsController.transform; // Add the ocean PQS to the secondary renders of the CelestialBody Transform PQSMod_CelestialBodyTransform transform = Current.pqsController.GetComponentsInChildren <PQSMod_CelestialBodyTransform>(true).FirstOrDefault(mod_ => mod_.transform.parent == Current.pqsController.transform); transform.planetFade.secondaryRenderers.Add(ocean.gameObject); typeof(PQS).GetField("_childSpheres", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(Current.pqsController, null); // Names! ocean.name = Current.pqsController.name + "Ocean"; ocean.gameObject.name = Current.pqsController.name + "Ocean"; ocean.transform.name = Current.pqsController.name + "Ocean"; // Set up the ocean PQS ocean.parentSphere = Current.pqsController; ocean.transform.position = Current.pqsController.transform.position; ocean.transform.localPosition = Vector3.zero; ocean.radius = Current.Radius; }, new Rect(20, index * distance + 10, 350, 20)); } else { Button(Localization.LOC_KITTOPIATECH_PQSEDITOR_REMOVE_OCEAN, () => { // Find atmosphere the ocean PQS PQS ocean = Current.pqsController.GetComponentsInChildren <PQS>(true).First(pqs => pqs != Current.pqsController); PQSMod_CelestialBodyTransform cbt = Current.pqsController.GetComponentsInChildren <PQSMod_CelestialBodyTransform>(true).First(); // Destroy the ocean PQS (this could be bad - destroying the secondary fades...) cbt.planetFade.secondaryRenderers.Remove(ocean.gameObject); typeof(PQS).GetField("_childSpheres", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(Current.pqsController, null); cbt.secondaryFades = new PQSMod_CelestialBodyTransform.AltitudeFade[0]; ocean.transform.parent = null; UnityEngine.Object.Destroy(ocean); }, new Rect(20, index * distance + 10, 350, 20)); } // End Scroll EndScrollView(); } // Mode PQS if (_mode == Modes.PQS) { // Scroll BeginScrollView(250, Utils.GetScrollSize <PQS>() + Utils.GetScrollSize <HazardousOcean>() + distance * 1, 20); // Index index = 0; // Render the PQS RenderObject(_sphere); // If it is an ocean, create an Hazardous Ocean button if (PQSOceanSurfaceQuad.UsesSameShader(_sphere.surfaceMaterial)) { Label("hazardousOcean"); index--; if (_sphere.GetComponent <HazardousOcean>() != null) { Button(Localization.LOC_KITTOPIATECH_EDIT, () => { UIController.Instance.SetEditedObject(KittopiaWindows.Curve, _sphere.GetComponent <HazardousOcean>().heatCurve ?? new FloatCurve(), c => _sphere.GetComponent <HazardousOcean>().heatCurve = c); UIController.Instance.EnableWindow(KittopiaWindows.Curve); }, new Rect(200, index * distance + 10, 75, 20)); index--; Button(Localization.LOC_KITTOPIATECH_REMOVE, () => UnityEngine.Object.DestroyImmediate(_sphere.GetComponent <HazardousOcean>()), new Rect(285, index * distance + 10, 75, 20)); } else { Button(Localization.LOC_KITTOPIATECH_PQSEDITOR_ADD_HAZOCEAN, () => _sphere.gameObject.AddComponent <HazardousOcean>(), new Rect(200, index * distance + 10, 170, 20)); } } index++; // Rebuild Button(Localization.LOC_KITTOPIATECH_PQSEDITOR_REBUILD, () => _sphere.RebuildSphere()); // End Scroll EndScrollView(); } // Mode PQSMod if (_mode == Modes.PQSMod) { // Scroll BeginScrollView(250, Utils.GetScrollSize(_mod.GetType()) + distance * 5, 20); // Index index = 0; // Render the PQS RenderObject(_mod); index++; // Rebuild Button(Localization.LOC_KITTOPIATECH_PQSEDITOR_REBUILD, () => _sphere.RebuildSphere()); // Remove Button(Localization.LOC_KITTOPIATECH_PQSEDITOR_REMOVE_MOD, () => { _mod.sphere = null; UnityEngine.Object.Destroy(_mod); _mod = null; // Hack _sphere.SetupExternalRender(); _sphere.CloseExternalRender(); _mode = Modes.List; }); // End Scroll EndScrollView(); } // Mode AddPQSMod if (_mode == Modes.AddMod) { // Get all PQSMod types List <Type> types = Parser.ModTypes.Where(t => t.IsSubclassOf(typeof(PQSMod))).ToList(); // Begin Scroll BeginScrollView(250, types.Count * distance + 10, 20); // Index index = 0; // Render the possible types foreach (Type t in types) { Button(t.FullName, () => { // Hack^6 GameObject pqsModObject = new GameObject(t.Name); pqsModObject.transform.parent = Current.pqsController.transform; PQSMod mod = pqsModObject.AddComponent(t) as PQSMod; mod.sphere = Current.pqsController; if (t == typeof(PQSMod_VoronoiCraters)) { PQS mun = Utility.FindBody(Injector.StockSystemPrefab.rootBody, "Mun").pqsVersion; PQSMod_VoronoiCraters craters = mun.GetComponentsInChildren <PQSMod_VoronoiCraters>()[0]; PQSMod_VoronoiCraters nc = pqsModObject.GetComponentsInChildren <PQSMod_VoronoiCraters>()[0]; nc.craterColourRamp = craters.craterColourRamp; nc.craterCurve = craters.craterCurve; nc.jitterCurve = craters.jitterCurve; } else if (t == typeof(PQSMod_VertexPlanet)) { PQSMod_VertexPlanet vp = mod as PQSMod_VertexPlanet; vp.landClasses = new [] { new PQSMod_VertexPlanet.LandClass("Class", 0, 1, Color.black, Color.white, 0) }; vp.continental = new PQSMod_VertexPlanet.SimplexWrapper(0, 0, 0, 0); vp.continentalRuggedness = new PQSMod_VertexPlanet.SimplexWrapper(0, 0, 0, 0); vp.continentalSharpness = new PQSMod_VertexPlanet.NoiseModWrapper(0, 0, 0, 0); vp.continentalSharpnessMap = new PQSMod_VertexPlanet.SimplexWrapper(0, 0, 0, 0); vp.terrainType = new PQSMod_VertexPlanet.SimplexWrapper(0, 0, 0, 0); } else if (t == typeof(PQSMod_HeightColorMap)) { (mod as PQSMod_HeightColorMap).landClasses = new [] { new PQSMod_HeightColorMap.LandClass("Class", 0, 1, Color.black, Color.white, 0) }; } else if (t == typeof(PQSMod_HeightColorMap2)) { (mod as PQSMod_HeightColorMap2).landClasses = new[] { new PQSMod_HeightColorMap2.LandClass("Class", 0, 1, Color.black, Color.white, 0) }; } else if (t == typeof(PQSMod_HeightColorMapNoise)) { (mod as PQSMod_HeightColorMapNoise).landClasses = new[] { new PQSMod_HeightColorMapNoise.LandClass("Class", 0, 1, Color.black, Color.white, 0) }; } else if (t == typeof(PQSLandControl)) { PQSLandControl lc = mod as PQSLandControl; lc.altitudeSimplex = new Simplex(); lc.scatters = new PQSLandControl.LandClassScatter[0]; lc.landClasses = new [] { new PQSLandControl.LandClass() { altitudeRange = new PQSLandControl.LerpRange(), coverageSimplex = new Simplex(), longitudeRange = new PQSLandControl.LerpRange(), latitudeDoubleRange = new PQSLandControl.LerpRange(), latitudeRange = new PQSLandControl.LerpRange(), scatter = new PQSLandControl.LandClassScatterAmount[0] } }; lc.latitudeSimplex = new Simplex(); lc.longitudeSimplex = new Simplex(); } // Edit the mod _mod = mod; _sphere = mod.sphere; _mode = Modes.PQSMod; }, new Rect(20, index * distance + 10, 350, 20)); } // End Scroll EndScrollView(); } }
public static IEnumerator UpdateTextures(CelestialBody celestialBody, TextureOptions options) { // Get time DateTime now = DateTime.Now; // If the user wants to export normals, we need height too if (options.ExportNormal) { options.ExportHeight = true; } // Prepare the PQS PQS pqsVersion = celestialBody.pqsController; // If the PQS is null, abort if (pqsVersion == null) { throw new InvalidOperationException(); } // Tell the PQS that we are going to build maps pqsVersion.SetupExternalRender(); // Get the mod building methods from the PQS Action <PQS.VertexBuildData> modOnVertexBuildHeight = (Action <PQS.VertexBuildData>)Delegate.CreateDelegate( typeof(Action <PQS.VertexBuildData>), pqsVersion, typeof(PQS).GetMethod("Mod_OnVertexBuildHeight", BindingFlags.Instance | BindingFlags.NonPublic)); Action <PQS.VertexBuildData> modOnVertexBuild = (Action <PQS.VertexBuildData>)Delegate.CreateDelegate( typeof(Action <PQS.VertexBuildData>), pqsVersion, typeof(PQS).GetMethod("Mod_OnVertexBuild", BindingFlags.Instance | BindingFlags.NonPublic)); // Get all mods the PQS is connected to PQSMod[] mods = pqsVersion.GetComponentsInChildren <PQSMod>() .Where(m => m.sphere == pqsVersion && m.modEnabled).OrderBy(m => m.order).ToArray(); // Prevent the PQS from updating pqsVersion.enabled = false; // Create the Textures Texture2D colorMap = new Texture2D(pqsVersion.mapFilesize, pqsVersion.mapFilesize / 2, TextureFormat.ARGB32, true); Texture2D heightMap = new Texture2D(pqsVersion.mapFilesize, pqsVersion.mapFilesize / 2, TextureFormat.RGB24, true); // Arrays Color[] colorMapValues = new Color[pqsVersion.mapFilesize * (pqsVersion.mapFilesize / 2)]; Color[] heightMapValues = new Color[pqsVersion.mapFilesize * (pqsVersion.mapFilesize / 2)]; // Create a VertexBuildData PQS.VertexBuildData data = new PQS.VertexBuildData(); // Display ScreenMessage message = ScreenMessages.PostScreenMessage("Generating Planet-Maps", Single.MaxValue, ScreenMessageStyle.UPPER_CENTER); yield return(null); // Loop through the pixels for (Int32 y = 0; y < pqsVersion.mapFilesize / 2; y++) { for (Int32 x = 0; x < pqsVersion.mapFilesize; x++) { // Update Message Double percent = (Double)(y * pqsVersion.mapFilesize + x) / (pqsVersion.mapFilesize / 2 * pqsVersion.mapFilesize) * 100; while (CanvasUpdateRegistry.IsRebuildingLayout()) { Thread.Sleep(10); } message.textInstance.text.text = "Generating Planet-Maps: " + percent.ToString("0.00") + "%"; // Update the VertexBuildData data.directionFromCenter = QuaternionD.AngleAxis(360d / pqsVersion.mapFilesize * x, Vector3d.up) * QuaternionD.AngleAxis(90d - 180d / (pqsVersion.mapFilesize / 2f) * y, Vector3d.right) * Vector3d.forward; data.vertHeight = pqsVersion.radius; // Build from the Mods Double height = Double.MinValue; if (options.ExportHeight) { modOnVertexBuildHeight(data); // Adjust the height height = (data.vertHeight - pqsVersion.radius) * (1d / pqsVersion.mapMaxHeight); if (height < 0) { height = 0; } else if (height > 1) { height = 1; } // Set the Pixels heightMapValues[y * pqsVersion.mapFilesize + x] = new Color((Single)height, (Single)height, (Single)height); } if (options.ExportColor) { modOnVertexBuild(data); // Adjust the Color Color color = data.vertColor; if (!pqsVersion.mapOcean) { color.a = 1f; } else if (height > pqsVersion.mapOceanHeight) { color.a = options.TransparentMaps ? 0f : 1f; } else { color = pqsVersion.mapOceanColor.A(1f); } // Set the Pixels colorMapValues[y * pqsVersion.mapFilesize + x] = color; } } yield return(null); } // Serialize the maps to disk String name = "KittopiaTech/PluginData/" + celestialBody.transform.name + "/"; String path = KSPUtil.ApplicationRootPath + "/GameData/" + name; Directory.CreateDirectory(path); // Colormap if (options.ExportColor) { // Save it colorMap.SetPixels(colorMapValues); yield return(null); if (options.SaveToDisk) { File.WriteAllBytes(path + celestialBody.transform.name + "_Color.png", colorMap.EncodeToPNG()); colorMap.name = name + celestialBody.transform.name + "_Color.png"; yield return(null); } // Apply it if (options.ApplyToScaled) { colorMap.Apply(); celestialBody.scaledBody.GetComponent <MeshRenderer>().material.SetTexture("_MainTex", colorMap); } } if (options.ExportHeight) { heightMap.SetPixels(heightMapValues); yield return(null); if (options.SaveToDisk) { File.WriteAllBytes(path + celestialBody.transform.name + "_Height.png", heightMap.EncodeToPNG()); yield return(null); } if (options.ExportNormal) { // Bump to Normal Map Texture2D normalMap = Utility.BumpToNormalMap(heightMap, pqsVersion.radius, options.NormalStrength); yield return(null); if (options.SaveToDisk) { File.WriteAllBytes(path + celestialBody.transform.name + "_Normal.png", normalMap.EncodeToPNG()); normalMap.name = name + celestialBody.transform.name + "_Normal.png"; yield return(null); } // Apply it if (options.ApplyToScaled) { normalMap.Apply(); celestialBody.scaledBody.GetComponent <MeshRenderer>().material .SetTexture("_BumpMap", normalMap); } } } // Close the Renderer pqsVersion.enabled = true; pqsVersion.CloseExternalRender(); // Declare that we're done ScreenMessages.RemoveMessage(message); ScreenMessages.PostScreenMessage("Operation completed in: " + (DateTime.Now - now).TotalMilliseconds + " ms", 2f, ScreenMessageStyle.UPPER_CENTER); }
public static IEnumerator UpdateTextures(CelestialBody celestialBody, TextureOptions options) { // Get time DateTime now = DateTime.Now; // If the user wants to export normals, we need height too if (options.ExportNormal) { options.ExportHeight = true; } // Prepare the PQS PQS pqsVersion = celestialBody.pqsController; // If the PQS is null, abort if (pqsVersion == null) { yield break; } // Tell the PQS that we are going to build maps pqsVersion.SetupExternalRender(); // Get the mod building methods from the PQS #if !KSP131 Action <PQS.VertexBuildData, Boolean> modOnVertexBuildHeight = (Action <PQS.VertexBuildData, Boolean>)Delegate.CreateDelegate( typeof(Action <PQS.VertexBuildData, Boolean>), pqsVersion, typeof(PQS).GetMethod("Mod_OnVertexBuildHeight", BindingFlags.Instance | BindingFlags.NonPublic)); #else Action <PQS.VertexBuildData> modOnVertexBuildHeight = (Action <PQS.VertexBuildData>)Delegate.CreateDelegate( typeof(Action <PQS.VertexBuildData>), pqsVersion, typeof(PQS).GetMethod("Mod_OnVertexBuildHeight", BindingFlags.Instance | BindingFlags.NonPublic)); #endif Action <PQS.VertexBuildData> modOnVertexBuild = (Action <PQS.VertexBuildData>)Delegate.CreateDelegate( typeof(Action <PQS.VertexBuildData>), pqsVersion, typeof(PQS).GetMethod("Mod_OnVertexBuild", BindingFlags.Instance | BindingFlags.NonPublic)); // Get all mods the PQS is connected to PQSMod[] mods = pqsVersion.GetComponentsInChildren <PQSMod>() .Where(m => m.sphere == pqsVersion && m.modEnabled).OrderBy(m => m.order).ToArray(); // Prevent the PQS from updating pqsVersion.enabled = false; // Create the Textures Texture2D colorMap = new Texture2D(options.Resolution, options.Resolution / 2, TextureFormat.ARGB32, true); Texture2D heightMap = new Texture2D(options.Resolution, options.Resolution / 2, TextureFormat.RGB24, true); // Arrays Color[] colorMapValues = new Color[options.Resolution * (options.Resolution / 2)]; Color[] heightMapValues = new Color[options.Resolution * (options.Resolution / 2)]; // Create a VertexBuildData PQS.VertexBuildData data = new PQS.VertexBuildData(); // Display ScreenMessage message = ScreenMessages.PostScreenMessage("Generating terrain data", Single.MaxValue, ScreenMessageStyle.UPPER_CENTER); yield return(null); Double[] heightValues = new Double[options.Resolution * (options.Resolution / 2)]; // Loop through the pixels for (Int32 y = 0; y < options.Resolution / 2; y++) { // Update Message Double percent = y / (options.Resolution / 2d) * 100; while (CanvasUpdateRegistry.IsRebuildingLayout()) { Thread.Sleep(10); } message.textInstance.text.text = "Generating terrain data: " + percent.ToString("0.00") + "%"; for (Int32 x = 0; x < options.Resolution; x++) { // Update the VertexBuildData data.directionFromCenter = QuaternionD.AngleAxis(360d / options.Resolution * x, Vector3d.up) * QuaternionD.AngleAxis(90d - 180d / (options.Resolution / 2f) * y, Vector3d.right) * Vector3d.forward; data.vertHeight = pqsVersion.radius; #if !KSP131 modOnVertexBuildHeight(data, true); #else modOnVertexBuildHeight(data); #endif modOnVertexBuild(data); // Cache the results heightValues[y * options.Resolution + x] = data.vertHeight; colorMapValues[y * options.Resolution + x] = data.vertColor; } yield return(null); } // Update Message while (CanvasUpdateRegistry.IsRebuildingLayout()) { Thread.Sleep(10); } message.textInstance.text.text = "Calculating height difference"; // Figure out the delta radius ourselves Double minHeight = Double.MaxValue; Double maxHeight = Double.MinValue; for (Int32 i = 0; i < heightValues.Length; i++) { if (heightValues[i] > maxHeight) { maxHeight = heightValues[i]; } else if (heightValues[i] < minHeight) { minHeight = heightValues[i]; } } Double deltaRadius = maxHeight - minHeight; yield return(null); // Update Message while (CanvasUpdateRegistry.IsRebuildingLayout()) { Thread.Sleep(10); } message.textInstance.text.text = "Calculating color data"; // Apply the values for (Int32 y = 0; y < options.Resolution / 2; y++) { // Update Message Double percent = y / (options.Resolution / 2d) * 100; while (CanvasUpdateRegistry.IsRebuildingLayout()) { Thread.Sleep(10); } message.textInstance.text.text = "Calculating color data: " + percent.ToString("0.00") + "%"; for (Int32 x = 0; x < options.Resolution; x++) { // Build from the Mods Double height = heightValues[y * options.Resolution + x] - pqsVersion.radius; if (options.ExportColor) { // Adjust the Color Color color = colorMapValues[y * options.Resolution + x]; if (!pqsVersion.mapOcean) { color.a = 1f; } else if (height > pqsVersion.mapOceanHeight) { color.a = options.TransparentMaps ? 0f : 1f; } else { color = pqsVersion.mapOceanColor.A(1f); } // Set the Pixels colorMapValues[y * options.Resolution + x] = color; } if (options.ExportHeight) { // Adjust the height height = height / deltaRadius; if (height < 0) { height = 0; } else if (height > 1) { height = 1; } // Set the Pixels heightMapValues[y * options.Resolution + x] = new Color((Single)height, (Single)height, (Single)height); } } yield return(null); } // Serialize the maps to disk String name = "KittopiaTech/PluginData/" + celestialBody.transform.name + "/" + DateTime.Now.ToString("yyyy-MM-dd_hh-mm-ss") + "/"; String path = KSPUtil.ApplicationRootPath + "/GameData/" + name; Directory.CreateDirectory(path); // Colormap if (options.ExportColor) { // Update Message while (CanvasUpdateRegistry.IsRebuildingLayout()) { Thread.Sleep(10); } message.textInstance.text.text = "Exporting planet maps: Color"; // Save it colorMap.SetPixels(colorMapValues); yield return(null); if (options.SaveToDisk) { File.WriteAllBytes(path + celestialBody.transform.name + "_Color.png", colorMap.EncodeToPNG()); colorMap.name = name + celestialBody.transform.name + "_Color.png"; yield return(null); } // Apply it if (options.ApplyToScaled) { ScaledSpaceOnDemand od = celestialBody.scaledBody.GetComponent <ScaledSpaceOnDemand>(); if (od != null) { od.texture = colorMap.name; UnityEngine.Object.DestroyImmediate(colorMap); if (od.isLoaded) { od.UnloadTextures(); od.LoadTextures(); } } else { colorMap.Apply(); celestialBody.scaledBody.GetComponent <MeshRenderer>().sharedMaterial.SetTexture("_MainTex", colorMap); } } else { UnityEngine.Object.DestroyImmediate(colorMap); } } if (options.ExportHeight) { // Update Message while (CanvasUpdateRegistry.IsRebuildingLayout()) { Thread.Sleep(10); } message.textInstance.text.text = "Exporting planet maps: Height"; heightMap.SetPixels(heightMapValues); yield return(null); if (options.SaveToDisk) { File.WriteAllBytes(path + celestialBody.transform.name + "_Height.png", heightMap.EncodeToPNG()); yield return(null); } if (options.ExportNormal) { // Update Message while (CanvasUpdateRegistry.IsRebuildingLayout()) { Thread.Sleep(10); } message.textInstance.text.text = "Exporting planet maps: Normal"; // Bump to Normal Map Texture2D normalMap = Utility.BumpToNormalMap(heightMap, pqsVersion, options.NormalStrength / 10); yield return(null); if (options.SaveToDisk) { File.WriteAllBytes(path + celestialBody.transform.name + "_Normal.png", normalMap.EncodeToPNG()); normalMap.name = name + celestialBody.transform.name + "_Normal.png"; yield return(null); } // Apply it if (options.ApplyToScaled) { ScaledSpaceOnDemand od = celestialBody.scaledBody.GetComponent <ScaledSpaceOnDemand>(); if (od != null) { od.normals = normalMap.name; UnityEngine.Object.DestroyImmediate(normalMap); if (od.isLoaded) { od.UnloadTextures(); od.LoadTextures(); } } else { normalMap.Apply(); celestialBody.scaledBody.GetComponent <MeshRenderer>().sharedMaterial .SetTexture("_BumpMap", normalMap); } } else { UnityEngine.Object.DestroyImmediate(normalMap); } } UnityEngine.Object.DestroyImmediate(heightMap); } // Close the Renderer pqsVersion.enabled = true; pqsVersion.CloseExternalRender(); // Declare that we're done ScreenMessages.RemoveMessage(message); ScreenMessages.PostScreenMessage("Operation completed in: " + (DateTime.Now - now).TotalMilliseconds + " ms", 2f, ScreenMessageStyle.UPPER_CENTER); }