/// <summary> /// Generates a thumbnail for the planet /// </summary> public static Texture2D GetPlanetThumbnail(CelestialBody body) { // Config RuntimePreviewGenerator.TransparentBackground = true; RuntimePreviewGenerator.BackgroundColor = Color.clear; RuntimePreviewGenerator.PreviewDirection = Vector3.forward; RuntimePreviewGenerator.Padding = -0.15f; ScaledSpaceOnDemand od = body.scaledBody.GetComponent <ScaledSpaceOnDemand>(); Boolean isLoaded = true; if (od != null) { isLoaded = od.isLoaded; if (!isLoaded) { od.LoadTextures(); } } GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); sphere.GetComponentInChildren <MeshFilter>().sharedMesh = body.scaledBody.GetComponent <MeshFilter>().sharedMesh; sphere.GetComponentInChildren <MeshRenderer>().sharedMaterial = body.scaledBody.GetComponent <MeshRenderer>().sharedMaterial; Texture2D finalTexture = RuntimePreviewGenerator.GenerateModelPreview(sphere.transform, 256, 256); Object.DestroyImmediate(sphere); if (!isLoaded) { od.UnloadTextures(); } return(finalTexture); }
// Update the menu body void Start() { if (Templates.kopernicusMainMenu) { // Select a random body? if (Templates.randomMainMenuBodies.Any()) { Templates.menuBody = Templates.randomMainMenuBodies[new System.Random().Next(0, Templates.randomMainMenuBodies.Count)]; } // Grab the main body CelestialBody planetCB = PSystemManager.Instance.localBodies.Find(b => b.transform.name == Templates.menuBody); PSystemBody planet = Utility.FindBody(PSystemManager.Instance.systemPrefab.rootBody, Templates.menuBody); if (planetCB == null || planet == null) { planet = Utility.FindHomeBody(PSystemManager.Instance.systemPrefab.rootBody); planetCB = PSystemManager.Instance.localBodies.Find(b => b.isHomeWorld); } if (planet == null || planetCB == null) { Debug.LogError("[Kopernicus] Could not find homeworld!"); return; } // Load Textures OnDemand.OnDemandStorage.EnableBody(Templates.menuBody); // Get the MainMenu-Logic MainMenu main = FindObjectOfType <MainMenu>(); if (main == null) { Debug.LogError("[Kopernicus] No main menu object!"); return; } MainMenuEnvLogic logic = main.envLogic; // Set it to Space, because the Mun-Area won't work with sth else than Mun if (logic.areas.Length < 2) { Debug.LogError("[Kopernicus] Not enough bodies"); return; } // Get our active Space GameObject space = logic.areas[1]; // Deactivate Kerbins Transform Transform kerbin = space.transform.Find("Kerbin"); if (kerbin == null) { Debug.LogError("[Kopernicus] No Kerbin transform!"); return; } kerbin.gameObject.SetActive(false); // Deactivate Muns Transform Transform mun = space.transform.Find("MunPivot"); if (mun == null) { Debug.LogError("[Kopernicus] No MunPivot transform!"); return; } mun.gameObject.SetActive(false); // Activate the textures ScaledSpaceOnDemand od = planet.scaledVersion.GetComponentInChildren <ScaledSpaceOnDemand>(); if (od != null) { od.Start(); od.LoadTextures(); } // Clone the scaledVersion and attach it to the Scene GameObject menuPlanet = Instantiate(planet.scaledVersion) as GameObject; menuPlanet.transform.parent = space.transform; // Destroy stuff DestroyImmediate(menuPlanet.GetComponent <ScaledSpaceFader>()); DestroyImmediate(menuPlanet.GetComponent <SphereCollider>()); DestroyImmediate(menuPlanet.GetComponentInChildren <AtmosphereFromGround>()); DestroyImmediate(menuPlanet.GetComponent <MaterialSetDirection>()); // That sounds funny Rotato planetRotato = menuPlanet.AddComponent <Rotato>(); Rotato planetRefRotato = kerbin.GetComponent <Rotato>(); planetRotato.speed = (planetRefRotato.speed / 9284.50070356553f) * (Single)planetCB.orbitDriver.orbit.orbitalSpeed; // calc.exe for the win // Scale the body menuPlanet.transform.localScale = kerbin.localScale; menuPlanet.transform.localPosition = kerbin.localPosition; menuPlanet.transform.position = kerbin.position; // And set it to layer 0 menuPlanet.layer = 0; // Patch the material, because Mods like TextureReplacer run post spawn, and we'd overwrite their changes menuPlanet.GetComponent <Renderer>().sharedMaterial = planetCB.scaledBody.GetComponent <Renderer>().sharedMaterial; // Copy EVE 7.4 clouds / Rings for (Int32 i = 0; i < planetCB.scaledBody.transform.childCount; i++) { // Just clone everything Transform t = planetCB.scaledBody.transform.GetChild(i); if (t.gameObject.GetComponent <AtmosphereFromGround>()) { continue; } GameObject newT = Instantiate(t.gameObject) as GameObject; newT.transform.parent = menuPlanet.transform; newT.layer = 0; newT.transform.localPosition = Vector3.zero; newT.transform.localRotation = Quaternion.identity; newT.transform.localScale = (Single)(1008 / planetCB.Radius) * Vector3.one; } // And now, create the moons foreach (PSystemBody moon in planet.children) { // Grab the CeletialBody of the moon CelestialBody moonCB = PSystemManager.Instance.localBodies.Find(b => b.GetTransform().name == moon.name); // Create the Rotation-Transforms GameObject menuMoonPivot = new GameObject(moon.name + " Pivot"); menuMoonPivot.gameObject.layer = 0; menuMoonPivot.transform.position = menuPlanet.transform.position; // Still funny... Rotato munRotato = menuMoonPivot.AddComponent <Rotato>(); Rotato refRotato = mun.GetComponent <Rotato>(); munRotato.speed = (refRotato.speed / 542.494239600754f) * (Single)moonCB.GetOrbit().getOrbitalSpeedAtDistance(moonCB.GetOrbit().semiMajorAxis); // Activate the textures ScaledSpaceOnDemand odMoon = moon.scaledVersion.GetComponentInChildren <ScaledSpaceOnDemand>(); if (odMoon != null) { odMoon.Start(); odMoon.LoadTextures(); } // Clone the scaledVersion and attach it to the pivot GameObject menuMoon = Instantiate(moon.scaledVersion) as GameObject; menuMoon.transform.parent = menuMoonPivot.transform; // Move and scale the menuMoon correctly menuMoon.transform.localPosition = new Vector3(-5000f * (Single)(moonCB.GetOrbit().semiMajorAxis / 12000000.0), 0f, 0f); menuMoon.transform.localScale *= 7f; // Destroy stuff DestroyImmediate(menuMoon.GetComponent <ScaledSpaceFader>()); DestroyImmediate(menuMoon.GetComponent <SphereCollider>()); DestroyImmediate(menuMoon.GetComponentInChildren <AtmosphereFromGround>()); DestroyImmediate(menuMoon.GetComponent <MaterialSetDirection>()); // More Rotato Rotato moonRotato = menuMoon.AddComponent <Rotato>(); moonRotato.speed = -0.005f / (Single)(moonCB.rotationPeriod / 400.0); // Apply orbital stuff menuMoon.transform.Rotate(0f, (Single)moonCB.orbitDriver.orbit.LAN, 0f); menuMoon.transform.Rotate(0f, 0f, (Single)moonCB.orbitDriver.orbit.inclination); menuMoon.transform.Rotate(0f, (Single)moonCB.orbitDriver.orbit.argumentOfPeriapsis, 0f); // And set the layer to 0 menuMoon.layer = 0; // Patch the material, because Mods like TextureReplacer run post spawn, and we'd overwrite their changes menuMoon.GetComponent <Renderer>().sharedMaterial = moonCB.scaledBody.GetComponent <Renderer>().sharedMaterial; // Copy EVE 7.4 clouds / Rings for (Int32 i = 0; i < moonCB.scaledBody.transform.childCount; i++) { Transform t = moonCB.scaledBody.transform.GetChild(i); if (t.gameObject.GetComponent <AtmosphereFromGround>()) { continue; } GameObject newT = Instantiate(t.gameObject) as GameObject; newT.transform.parent = menuMoon.transform; newT.layer = 0; newT.transform.localPosition = Vector3.zero; newT.transform.localRotation = Quaternion.identity; newT.transform.localScale = (Single)(1008 / moonCB.Radius) * Vector3.one; } } Events.OnRuntimeUtilityUpdateMenu.Fire(); } }
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); }
// Update the menu body private void Start() { if (!Templates.KopernicusMainMenu) { return; } // Select a random body? if (Templates.RandomMainMenuBodies.Any()) { Templates.MenuBody = Templates.RandomMainMenuBodies[new Random().Next(0, Templates.RandomMainMenuBodies.Count)]; } // Grab the main body CelestialBody planetCb = UBI.GetBody(Templates.MenuBody); if (planetCb == null) { planetCb = PSystemManager.Instance.localBodies.Find(b => b.isHomeWorld); } if (planetCb == null) { Debug.LogError("[Kopernicus] Could not find home world!"); return; } // Load Textures OnDemandStorage.EnableBody(Templates.MenuBody); // Get the MainMenu-Logic MainMenu main = FindObjectOfType <MainMenu>(); if (main == null) { Debug.LogError("[Kopernicus] No main menu object!"); return; } MainMenuEnvLogic logic = main.envLogic; // Set it to Space, because the Mun-Area won't work with sth else than Mun if (logic.areas.Length < 2) { Debug.LogError("[Kopernicus] Not enough bodies"); return; } // Get our active Space GameObject space = logic.areas[1]; // Deactivate Kerbins Transform Transform kerbin = space.transform.Find("Kerbin"); if (kerbin == null) { Debug.LogError("[Kopernicus] No Kerbin transform!"); return; } kerbin.gameObject.SetActive(false); // Deactivate Muns Transform Transform munPivot = space.transform.Find("MunPivot"); if (munPivot == null) { Debug.LogError("[Kopernicus] No MunPivot transform!"); return; } munPivot.gameObject.SetActive(false); // Activate the textures ScaledSpaceOnDemand od = planetCb.scaledBody.GetComponentInChildren <ScaledSpaceOnDemand>(); if (od != null) { od.Start(); od.LoadTextures(); } // Clone the scaledVersion and attach it to the Scene GameObject menuPlanet = Utility.Instantiate(Utility .FindBody(PSystemManager.Instance.systemPrefab.rootBody, planetCb.transform.name).scaledVersion, space.transform, true); menuPlanet.name = planetCb.transform.name; // Destroy stuff DestroyImmediate(menuPlanet.GetComponent <ScaledSpaceFader>()); DestroyImmediate(menuPlanet.GetComponent <SphereCollider>()); DestroyImmediate(menuPlanet.GetComponentInChildren <AtmosphereFromGround>()); DestroyImmediate(menuPlanet.GetComponent <MaterialSetDirection>()); // That sounds funny Rotato planetRotato = menuPlanet.AddComponent <Rotato>(); Rotato planetRefRotato = kerbin.GetComponent <Rotato>(); planetRotato.speed = planetRefRotato.speed * ((Single)planetCb.rotationPeriod / KERBIN_ROTATION_PERIOD); menuPlanet.transform.Rotate(0f, (Single)planetCb.initialRotation, 0f); // Scale the body menuPlanet.transform.localScale = kerbin.localScale; menuPlanet.transform.localPosition = kerbin.localPosition; menuPlanet.transform.position = kerbin.position; // And set it to layer 0 menuPlanet.layer = 0; Events.OnRuntimeUtilityUpdateMenu.Fire(); }