// called every screen refresh private void OnWindow(int windowID) { GUILayout.BeginHorizontal(); if (GUILayout.Button(new GUIContent("Asparagus", aspTexture, "Create fuel lines and stage the ship, asparagus-style"), picbutton)) { mystate = ASPState.ADDASP; osd("Adding parts in asparagus style..."); } if (GUILayout.Button(new GUIContent("Onion", onionTexture, "Create fuel lines and stage the ship, onion-style"), picbutton)) { mystate = ASPState.ADDONION; osd("Adding parts in onion style..."); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button(new GUIContent("Delete all " + partsWeCanUse [partToUseIndex].title, nofuelTexture, "Delete all " + partsWeCanUse [partToUseIndex].title + " parts on the ship"), picbutton)) { osd("Deleting parts..."); mystate = ASPState.DELETEFUEL; } GUILayout.EndHorizontal(); if (partsWeCanUse.Count() > 1) { // choose part to use for fuel lines GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); GUILayout.Label("Part to use:", labelstyle); GUILayout.EndVertical(); GUILayout.BeginVertical(); int oldPartToUseIndex = partToUseIndex; partToUseIndex = GUILayout.SelectionGrid(partToUseIndex, partGrid, 1, togglestyle); if (oldPartToUseIndex != partToUseIndex) { // shrink window windowRect.height = 0; windowRect.width = 0; } GUILayout.EndVertical(); GUILayout.EndHorizontal(); } if (partTextureNames [partToUseIndex] != null) { GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); GUILayout.Label("Texture:", labelstyle); GUILayout.EndVertical(); GUILayout.BeginVertical(); int numTextures = partTextureNames [partToUseIndex].Count(); GUIContent[] texSelect = new GUIContent[numTextures]; for (int i = 0; i < numTextures; i++) { texSelect [i] = new GUIContent(partTextureNames [partToUseIndex] [i], partTextures [partToUseIndex] [i]); } textureIndex = GUILayout.SelectionGrid(textureIndex, texSelect, 2, gridstyle); GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); GUILayout.Label("Rainbow:", labelstyle); GUILayout.EndVertical(); GUILayout.BeginVertical(); rainbow = GUILayout.Toggle(rainbow, new GUIContent("Rainbow", rainbowTexture, "Oh, rainBOWs. Yeah I like those!")); GUILayout.EndVertical(); GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); GUILayout.Label("Options:"); GUILayout.EndHorizontal(); if (SmartStageAvailable) { GUILayout.BeginHorizontal(); useSmartStage = GUILayout.Toggle(useSmartStage, new GUIContent(" Use SmartStage", smartstageTexture, "Stage the ship using SmartStage instead of AutoAsparagus"), togglestyle); GUILayout.EndHorizontal(); } if (!useSmartStage) { GUILayout.BeginHorizontal(); stageParachutes = GUILayout.Toggle(stageParachutes, new GUIContent(" Stage parachutes", parachuteTexture, "Stage parachutes to fire with decouplers"), togglestyle); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); stagesepratrons = GUILayout.Toggle(stagesepratrons, new GUIContent(" Stage sepratrons", sepratronTexture, "Stage sepratrons to fire with decouplers"), togglestyle); GUILayout.EndHorizontal(); if (!stageLaunchClamps) { minheight = windowRect.height; minwidth = windowRect.width; } bool oldclamps = stageLaunchClamps; GUILayout.BeginHorizontal(); stageLaunchClamps = GUILayout.Toggle(stageLaunchClamps, new GUIContent(" Stage launch clamps", launchclampTexture, "Move launch clamps to the bottom or next-to-bottom stage"), togglestyle); GUILayout.EndHorizontal(); if (stageLaunchClamps != oldclamps) { if (!stageLaunchClamps) { // shrink window to old dimesions windowRect.height = minheight; windowRect.width = minwidth; } } if (stageLaunchClamps) { GUILayout.BeginHorizontal(); //GUILayout.Label ("Launch clamps:"); launchClampsStage = GUILayout.SelectionGrid(launchClampsStage, launchClampsText, 1, togglestyle); GUILayout.EndHorizontal(); } } GUILayout.BeginHorizontal(); vizualize = GUILayout.Toggle(vizualize, new GUIContent(" Show visualizations", "Show visualizations such as highlights and levels"), togglestyle); GUILayout.EndHorizontal(); #if DEBUG GUILayout.BeginHorizontal(); if (GUILayout.Button("DEV - Reload ship", buttonStyle)) { newReloadShip(); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("DEV - Dump the ship", buttonStyle)) { ASPConsoleStuff.ListTheShip(); tanks = ASPStaging.findFuelTanks(EditorLogic.fetch.ship.Parts); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("DEV - flush output buffer", buttonStyle)) { // flush output buffer for (int i = 1; i <= 20; i++) { print(""); } } GUILayout.EndHorizontal(); #endif GUI.DragWindow(); if (Event.current.type == EventType.Repaint) // why, Unity, why? { tooltip = GUI.tooltip; } }
// called every screen refresh private void OnWindow (int windowID) { GUILayout.BeginHorizontal (); if (GUILayout.Button (new GUIContent ("Asparagus", aspTexture, "Create fuel lines and stage the ship, asparagus-style"), picbutton)) { mystate = ASPState.ADDASP; osd ("Adding parts in asparagus style..."); } if (GUILayout.Button (new GUIContent ("Onion", onionTexture, "Create fuel lines and stage the ship, onion-style"), picbutton)) { mystate = ASPState.ADDONION; osd ("Adding parts in onion style..."); } GUILayout.EndHorizontal (); GUILayout.BeginHorizontal (); if (GUILayout.Button (new GUIContent ("Delete all " + partsWeCanUse [partToUseIndex].title, nofuelTexture, "Delete all " + partsWeCanUse [partToUseIndex].title + " parts on the ship"), picbutton)) { osd ("Deleting parts..."); mystate = ASPState.DELETEFUEL; } GUILayout.EndHorizontal (); if (partsWeCanUse.Count () > 1) { // choose part to use for fuel lines GUILayout.BeginHorizontal (); GUILayout.BeginVertical (); GUILayout.Label ("Part to use:", labelstyle); GUILayout.EndVertical (); GUILayout.BeginVertical (); int oldPartToUseIndex = partToUseIndex; partToUseIndex = GUILayout.SelectionGrid (partToUseIndex, partGrid, 1, togglestyle); if (oldPartToUseIndex != partToUseIndex) { // shrink window windowRect.height = 0; windowRect.width = 0; } GUILayout.EndVertical (); GUILayout.EndHorizontal (); } if (partTextureNames [partToUseIndex] != null) { GUILayout.BeginHorizontal (); GUILayout.BeginVertical (); GUILayout.Label ("Texture:", labelstyle); GUILayout.EndVertical (); GUILayout.BeginVertical (); int numTextures = partTextureNames [partToUseIndex].Count (); GUIContent[] texSelect = new GUIContent[numTextures]; for (int i = 0; i < numTextures; i++) { texSelect [i] = new GUIContent (partTextureNames [partToUseIndex] [i], partTextures [partToUseIndex] [i]); } textureIndex = GUILayout.SelectionGrid (textureIndex, texSelect, 2, gridstyle); GUILayout.EndVertical (); GUILayout.EndHorizontal (); GUILayout.BeginHorizontal (); GUILayout.BeginVertical (); GUILayout.Label ("Rainbow:", labelstyle); GUILayout.EndVertical (); GUILayout.BeginVertical (); rainbow = GUILayout.Toggle (rainbow, new GUIContent ("Rainbow", rainbowTexture, "Oh, rainBOWs. Yeah I like those!")); GUILayout.EndVertical (); GUILayout.EndHorizontal (); } GUILayout.BeginHorizontal (); GUILayout.Label ("Options:"); GUILayout.EndHorizontal (); if (SmartStageAvailable) { GUILayout.BeginHorizontal (); useSmartStage = GUILayout.Toggle (useSmartStage, new GUIContent (" Use SmartStage", smartstageTexture, "Stage the ship using SmartStage instead of AutoAsparagus"), togglestyle); GUILayout.EndHorizontal (); } if (!useSmartStage) { GUILayout.BeginHorizontal (); stageParachutes = GUILayout.Toggle (stageParachutes, new GUIContent (" Stage parachutes", parachuteTexture, "Stage parachutes to fire with decouplers"), togglestyle); GUILayout.EndHorizontal (); GUILayout.BeginHorizontal (); stagesepratrons = GUILayout.Toggle (stagesepratrons, new GUIContent (" Stage sepratrons", sepratronTexture, "Stage sepratrons to fire with decouplers"), togglestyle); GUILayout.EndHorizontal (); if (!stageLaunchClamps) { minheight = windowRect.height; minwidth = windowRect.width; } bool oldclamps = stageLaunchClamps; GUILayout.BeginHorizontal (); stageLaunchClamps = GUILayout.Toggle (stageLaunchClamps, new GUIContent (" Stage launch clamps", launchclampTexture, "Move launch clamps to the bottom or next-to-bottom stage"), togglestyle); GUILayout.EndHorizontal (); if (stageLaunchClamps != oldclamps) { if (!stageLaunchClamps) { // shrink window to old dimesions windowRect.height = minheight; windowRect.width = minwidth; } } if (stageLaunchClamps) { GUILayout.BeginHorizontal (); //GUILayout.Label ("Launch clamps:"); launchClampsStage = GUILayout.SelectionGrid (launchClampsStage, launchClampsText, 1, togglestyle); GUILayout.EndHorizontal (); } } if (aspButton != null) { GUILayout.BeginHorizontal (); useBlizzy = GUILayout.Toggle (useBlizzy, new GUIContent (" Use Blizzy's toolbar", blizzyTexture, "Use Blizzy's toolbar instead of the AppLauncher"), togglestyle); GUILayout.EndHorizontal (); aspButton.Visible = useBlizzy; } if (useBlizzy) { appButton.VisibleInScenes = ApplicationLauncher.AppScenes.NEVER; } else { appButton.VisibleInScenes = ApplicationLauncher.AppScenes.VAB | ApplicationLauncher.AppScenes.SPH; } GUILayout.BeginHorizontal (); vizualize = GUILayout.Toggle (vizualize, new GUIContent (" Show visualizations", "Show visualizations such as highlights and levels"), togglestyle); GUILayout.EndHorizontal (); #if DEBUG GUILayout.BeginHorizontal (); if (GUILayout.Button ("DEV - Reload ship", buttonStyle)) { newReloadShip (); } GUILayout.EndHorizontal (); GUILayout.BeginHorizontal (); if (GUILayout.Button ("DEV - Dump the ship", buttonStyle)) { ASPConsoleStuff.ListTheShip (); tanks = ASPStaging.findFuelTanks (EditorLogic.fetch.ship.Parts); } GUILayout.EndHorizontal (); GUILayout.BeginHorizontal (); if (GUILayout.Button ("DEV - flush output buffer", buttonStyle)) { // flush output buffer for (int i = 1; i <= 20; i++) { print (""); } } GUILayout.EndHorizontal (); #endif GUI.DragWindow (); if (Event.current.type == EventType.Repaint) { // why, Unity, why? tooltip = GUI.tooltip; } }
/*public static class PartIconGenerator * { * private const string IconHiddenTag = "Icon_Hidden"; * private const string KerbalEvaSubstring = "kerbal"; * * private static readonly int GameObjectLayer = LayerMask.NameToLayer ("PartsList_Icons"); * // note to future: if creating icons inside editor, you might want to choose a different layer or translate the camera and object out of frame * * private static Camera CreateCamera (int pixelWidth, int pixelHeight, Color backgroundColor) * { * //var camGo = new GameObject ("PartIconGenerator.Camera", typeof(Camera)); * //var cam = camGo.camera; * Camera cam = new Camera(); * * cam.enabled = false; * cam.cullingMask = (1 << GameObjectLayer); * cam.clearFlags = ~CameraClearFlags.Nothing; * cam.nearClipPlane = 0.1f; * cam.farClipPlane = 10f; * cam.orthographic = true; * cam.backgroundColor = backgroundColor; * cam.aspect = pixelWidth / (float)pixelHeight; * * // Camera Size = x / ((( x / y ) * 2 ) * s ) * cam.orthographicSize = pixelWidth / (((pixelWidth / (float)pixelHeight) * 2f) * pixelHeight); * cam.pixelRect = new Rect (0f, 0f, pixelWidth, pixelHeight); * * return cam; * } * * private static Light CreateLight () * { * var light = new GameObject ("PartIconGenerator.Light").AddComponent<Light> (); * * light.type = LightType.Directional; * light.color = XKCDColors.OffWhite; * light.cullingMask = 1 << GameObjectLayer; * light.intensity = 0.1f; * * return light; * } * * private static GameObject CreateIcon (AvailablePart part) * { * // kerbalEVA doesn't seem to init at origin if we aren't explicit * var go = UnityEngine.Object.Instantiate (part.iconPrefab, Vector3.zero, Quaternion.identity) as GameObject; * * // The kerbals are initially facing along positive Z so we'll be looking at their backs if we don't * // rotate them around * if (part.name.StartsWith (KerbalEvaSubstring)) * go.transform.rotation = Quaternion.AngleAxis (180f, Vector3.up); * * go.SetLayerRecursive (GameObjectLayer); * go.SetActive (true); * return go; * } * * private static void AdjustScaleAndCameraPosition (GameObject icon, Camera camera) * { * // get size of prefab * var bounds = CalculateBounds (icon); * float sphereDiameter = Mathf.Max (bounds.size.x, bounds.size.y, bounds.size.z); * * // rescale to size 1 unit so that object will take up as much viewspace as possible in ortho cam (with ortho size = 0.5) * var currentScale = icon.transform.localScale; * float scaleFactor = 1f / sphereDiameter; * icon.transform.localScale = currentScale * scaleFactor; * * icon.transform.position = -bounds.center * scaleFactor; * * camera.transform.position = Vector3.zero; * * // back out, else we'll be inside the model (which is scaled at 1 unit so this should be plenty) * camera.transform.Translate (new Vector3 (0f, 0f, -5f), Space.Self); * camera.transform.LookAt (Vector3.zero, Vector3.up); * } * * * public static Texture2D Create2D (AvailablePart part, int width, int height, Quaternion orientation, Color backgroundColor) * { * var cam = CreateCamera (width, height, backgroundColor); * var icon = CreateIcon (part); * var light = CreateLight (); * * var texture = new Texture2D (width, height, TextureFormat.ARGB32, false); * var rt = RenderTexture.GetTemporary (width, height, 24); * var prevRt = RenderTexture.active; * * RenderTexture.active = rt; * * icon.transform.rotation = orientation * icon.transform.rotation; * * AdjustScaleAndCameraPosition (icon, cam); * * cam.targetTexture = rt; * cam.pixelRect = new Rect (0f, 0f, width, height); // doc says this should be ignored but doesn't seem to be (?) -- rendered area very small once targetTexture is set * cam.Render (); * * texture.ReadPixels (new Rect (0f, 0f, width, height), 0, 0, false); * texture.Apply (); * * RenderTexture.active = prevRt; * RenderTexture.ReleaseTemporary (rt); * UnityEngine.Object.DestroyImmediate (light); * UnityEngine.Object.DestroyImmediate (cam); * UnityEngine.Object.DestroyImmediate (icon); * * return texture; * } * * private static Bounds CalculateBounds (GameObject go) * { * var renderers = go.GetComponentsInChildren<Renderer> (true).ToList (); * * if (renderers.Count == 0) * return default(Bounds); * * var boundsList = new List<Bounds> (); * * renderers.ForEach (r => { * if (r.tag == IconHiddenTag) * return; * * if (r is SkinnedMeshRenderer) { * var smr = r as SkinnedMeshRenderer; * * // the localBounds of the SkinnedMeshRenderer are initially large enough * // to accomodate all animation frames; they're likely to be far off for * // parts that do a lot of animation-related movement (like solar panels expanding) * // * // We can get correct mesh bounds by baking the current animation into a mesh * // note: vertex positions in baked mesh are relative to smr.transform; any scaling * // is already baked in * var mesh = new Mesh (); * smr.BakeMesh (mesh); * * // while the mesh bounds will now be correct, they don't consider orientation at all. * // If a long part is oriented along the wrong axis in world space, the bounds we'd get * // here could be very wrong. We need to come up with essentially the renderer bounds: * // a bounding box in world space that encompasses the mesh * var m = Matrix4x4.TRS (smr.transform.position, smr.transform.rotation, Vector3.one * // remember scale already factored in! * ); * var vertices = mesh.vertices; * * var smrBounds = new Bounds (m.MultiplyPoint3x4 (vertices [0]), Vector3.zero); * * for (int i = 1; i < vertices.Length; ++i) * smrBounds.Encapsulate (m.MultiplyPoint3x4 (vertices [i])); * * UnityEngine.Object.Destroy (mesh); * * boundsList.Add (smrBounds); * } else if (r is MeshRenderer) { // note: there are ParticleRenderers, LineRenderers, and TrailRenderers * r.gameObject.GetComponent<MeshFilter> ().sharedMesh.RecalculateBounds (); * boundsList.Add (r.bounds); * } * }); * * Bounds bounds = boundsList [0]; * * boundsList.Skip (1).ToList ().ForEach (b => bounds.Encapsulate (b)); * * return bounds; * } * }*/ private void OnGUI() { if (tooltipstyle == null) { setStyles(); } if (osdtime > Time.time) { float osdheight = osdstyle.CalcSize(new GUIContent(osdmessage)).y; GUILayout.BeginArea(new Rect(0, Screen.height * 0.1f, Screen.width, osdheight), osdstyle); GUILayout.Label(osdmessage, osdstyle); GUILayout.EndArea(); } if (visible) { if (refreshwait > 0) { refreshwait = refreshwait - 1; } else { switch (mystate) { case ASPState.IDLE: EditorLogic editor = EditorLogic.fetch; ShipConstruct ship = editor.ship; if (ship != null) { List <Part> parts = ship.parts; if ((parts != null) && (parts.Count > 0) && (parts [0] != null)) { parts [0].SetHighlight(false, true); if (tanks == null) { tanks = ASPStaging.findFuelTanks(parts); } else { if (vizualize) { if ((badDestTank != null) && (badStartTank != null)) { drawLineBetweenBadParts(); } foreach (Part p in parts) { if (p != null) { if ((badStartTank != null) && (p == badStartTank)) { Vector3 position = Camera.main.WorldToScreenPoint(p.transform.position); GUI.Label(new Rect(position.x, Screen.height - position.y, 200, 30), "Start tank"); badStartTank.SetHighlightColor(Color.blue); badStartTank.SetHighlight(true, false); badStartTank.highlightType = Part.HighlightType.AlwaysOn; } else if ((badDestTank != null) && (p == badDestTank)) { Vector3 position = Camera.main.WorldToScreenPoint(p.transform.position); GUI.Label(new Rect(position.x, Screen.height - position.y, 200, 30), "Destination tank"); badDestTank.SetHighlightColor(Color.blue); badDestTank.SetHighlight(true, false); badDestTank.highlightType = Part.HighlightType.AlwaysOn; } else if (blockingTanks.Contains(p)) { Vector3 position = Camera.main.WorldToScreenPoint(p.transform.position); GUI.Label(new Rect(position.x, Screen.height - position.y, 200, 30), "X"); p.SetHighlightColor(Color.red); p.SetHighlight(true, false); p.highlightType = Part.HighlightType.AlwaysOn; } else if (tanks.Contains(p)) { // draw labels on the tanks Vector3 position = Camera.main.WorldToScreenPoint(p.transform.position); string label = "L" + ASPFuelLine.countDecouplersToRoot(p).ToString(); #if DEBUG //label = label+": "+ASPConsoleStuff.getFriendlyName (p.craftID.ToString ()); #endif GUI.Label(new Rect(position.x, Screen.height - position.y, 200, 30), label); if ((p != badStartTank) && (p != badDestTank) && (!blockingTanks.Contains(p))) { p.SetHighlightColor(Color.green); p.SetHighlight(true, false); p.highlightType = Part.HighlightType.AlwaysOn; } } else if (ASPStaging.isDecoupler(p)) { p.SetHighlightColor(Color.magenta); p.SetHighlight(true, false); p.highlightType = Part.HighlightType.AlwaysOn; } else { p.SetHighlight(false, false); } } } } } } windowRect = ClickThruBlocker.GUILayoutWindow(windowID, clampToScreen(windowRect), OnWindow, "AutoAsparagus " + versionString); mousepos = new Vector2(Input.mousePosition.x, Input.mousePosition.y); if ((tooltip != null) && (tooltip.Length > 0)) { GUI.depth = 0; Vector2 size = tooltipstyle.CalcSize(new GUIContent(tooltip)); Rect rect = new Rect(Input.mousePosition.x + 20, (Screen.height - Input.mousePosition.y) + 20, size.x, size.y); rect = clampToScreen(rect); GUILayout.BeginArea(rect); GUILayout.Label(tooltip, tooltipstyle); GUILayout.EndArea(); } } break; case ASPState.ERROR: vizualize = true; mystate = ASPState.IDLE; break; case ASPState.ADDASP: ASPConsoleStuff.ListTheShip(); mystate = ASPState.CONNECT; ASPFuelLine.AddAsparagusFuelLines(partsWeCanUse [partToUseIndex], textureIndex, partTexturePaths [partToUseIndex], partTextureNames [partToUseIndex], rainbow); if (mystate == ASPState.CONNECT) { osd("Connecting parts..."); } refreshwait = 100; break; case ASPState.ADDONION: ASPConsoleStuff.ListTheShip(); mystate = ASPState.CONNECT; ASPFuelLine.AddOnionFuelLines(partsWeCanUse [partToUseIndex], textureIndex, partTexturePaths [partToUseIndex], partTextureNames [partToUseIndex], rainbow); if (mystate == ASPState.CONNECT) { osd("Connecting parts..."); } refreshwait = 100; break; case ASPState.CONNECT: ASPFuelLine.connectFuelLines(); refreshwait = 100; osd("Refreshing ship..."); mystate = ASPState.AFTERCONNECT; break; case ASPState.AFTERCONNECT: newReloadShip(); refreshwait = 100; if (useSmartStage) { mystate = ASPState.SMARTSTAGE; osd("Calling SmartStage..."); ASPConsoleStuff.AAprint("Calling SmartStage"); } else { mystate = ASPState.ADDSTAGES; osd("Adding empty stages..."); } break; case ASPState.ADDSTAGES: ASPStaging.AddEmptyStages(); mystate = ASPState.STAGE; osd("Staging decouplers..."); refreshwait = 10; break; case ASPState.STAGE: ASPStaging.AsaparagusTheShip(partsWeCanUse [partToUseIndex].name); mystate = ASPState.AFTERSTAGE; osd("Decoupler staging done, refreshing..."); refreshwait = 10; break; case ASPState.CLAMPS: if (stageLaunchClamps) { ASPStaging.StageLaunchClamps(launchClampsStage); } mystate = ASPState.FINALREFRESH; osd("Done!"); refreshwait = 10; break; case ASPState.DELETEFUEL: ASPConsoleStuff.ListTheShip(); int count = ASPFuelLine.DeleteAllFuelLines(partsWeCanUse [partToUseIndex].name); newReloadShip(); osd(count.ToString() + " parts deleted."); mystate = ASPState.IDLE; break; case ASPState.FINALREFRESH: newReloadShip(); mystate = ASPState.IDLE; osd("Done!"); #if DEBUG tanks = ASPStaging.findFuelTanks(EditorLogic.fetch.ship.Parts); #endif break; case ASPState.AFTERSTAGE: newReloadShip(); if (stageLaunchClamps) { osd("Staging launch clamps..."); mystate = ASPState.CLAMPS; refreshwait = 10; } else { osd("Done!"); mystate = ASPState.IDLE; } break; case ASPState.SMARTSTAGE: mystate = ASPState.FINALREFRESH; try { computeStagesMethod.Invoke(null, new object[] { }); } catch (Exception e) { UnityEngine.Debug.LogError("Error invoking method\n" + e.StackTrace); } osd("Done!"); break; } } } }
/*public static class PartIconGenerator { private const string IconHiddenTag = "Icon_Hidden"; private const string KerbalEvaSubstring = "kerbal"; private static readonly int GameObjectLayer = LayerMask.NameToLayer ("PartsList_Icons"); // note to future: if creating icons inside editor, you might want to choose a different layer or translate the camera and object out of frame private static Camera CreateCamera (int pixelWidth, int pixelHeight, Color backgroundColor) { //var camGo = new GameObject ("PartIconGenerator.Camera", typeof(Camera)); //var cam = camGo.camera; Camera cam = new Camera(); cam.enabled = false; cam.cullingMask = (1 << GameObjectLayer); cam.clearFlags = ~CameraClearFlags.Nothing; cam.nearClipPlane = 0.1f; cam.farClipPlane = 10f; cam.orthographic = true; cam.backgroundColor = backgroundColor; cam.aspect = pixelWidth / (float)pixelHeight; // Camera Size = x / ((( x / y ) * 2 ) * s ) cam.orthographicSize = pixelWidth / (((pixelWidth / (float)pixelHeight) * 2f) * pixelHeight); cam.pixelRect = new Rect (0f, 0f, pixelWidth, pixelHeight); return cam; } private static Light CreateLight () { var light = new GameObject ("PartIconGenerator.Light").AddComponent<Light> (); light.type = LightType.Directional; light.color = XKCDColors.OffWhite; light.cullingMask = 1 << GameObjectLayer; light.intensity = 0.1f; return light; } private static GameObject CreateIcon (AvailablePart part) { // kerbalEVA doesn't seem to init at origin if we aren't explicit var go = UnityEngine.Object.Instantiate (part.iconPrefab, Vector3.zero, Quaternion.identity) as GameObject; // The kerbals are initially facing along positive Z so we'll be looking at their backs if we don't // rotate them around if (part.name.StartsWith (KerbalEvaSubstring)) go.transform.rotation = Quaternion.AngleAxis (180f, Vector3.up); go.SetLayerRecursive (GameObjectLayer); go.SetActive (true); return go; } private static void AdjustScaleAndCameraPosition (GameObject icon, Camera camera) { // get size of prefab var bounds = CalculateBounds (icon); float sphereDiameter = Mathf.Max (bounds.size.x, bounds.size.y, bounds.size.z); // rescale to size 1 unit so that object will take up as much viewspace as possible in ortho cam (with ortho size = 0.5) var currentScale = icon.transform.localScale; float scaleFactor = 1f / sphereDiameter; icon.transform.localScale = currentScale * scaleFactor; icon.transform.position = -bounds.center * scaleFactor; camera.transform.position = Vector3.zero; // back out, else we'll be inside the model (which is scaled at 1 unit so this should be plenty) camera.transform.Translate (new Vector3 (0f, 0f, -5f), Space.Self); camera.transform.LookAt (Vector3.zero, Vector3.up); } public static Texture2D Create2D (AvailablePart part, int width, int height, Quaternion orientation, Color backgroundColor) { var cam = CreateCamera (width, height, backgroundColor); var icon = CreateIcon (part); var light = CreateLight (); var texture = new Texture2D (width, height, TextureFormat.ARGB32, false); var rt = RenderTexture.GetTemporary (width, height, 24); var prevRt = RenderTexture.active; RenderTexture.active = rt; icon.transform.rotation = orientation * icon.transform.rotation; AdjustScaleAndCameraPosition (icon, cam); cam.targetTexture = rt; cam.pixelRect = new Rect (0f, 0f, width, height); // doc says this should be ignored but doesn't seem to be (?) -- rendered area very small once targetTexture is set cam.Render (); texture.ReadPixels (new Rect (0f, 0f, width, height), 0, 0, false); texture.Apply (); RenderTexture.active = prevRt; RenderTexture.ReleaseTemporary (rt); UnityEngine.Object.DestroyImmediate (light); UnityEngine.Object.DestroyImmediate (cam); UnityEngine.Object.DestroyImmediate (icon); return texture; } private static Bounds CalculateBounds (GameObject go) { var renderers = go.GetComponentsInChildren<Renderer> (true).ToList (); if (renderers.Count == 0) return default(Bounds); var boundsList = new List<Bounds> (); renderers.ForEach (r => { if (r.tag == IconHiddenTag) return; if (r is SkinnedMeshRenderer) { var smr = r as SkinnedMeshRenderer; // the localBounds of the SkinnedMeshRenderer are initially large enough // to accomodate all animation frames; they're likely to be far off for // parts that do a lot of animation-related movement (like solar panels expanding) // // We can get correct mesh bounds by baking the current animation into a mesh // note: vertex positions in baked mesh are relative to smr.transform; any scaling // is already baked in var mesh = new Mesh (); smr.BakeMesh (mesh); // while the mesh bounds will now be correct, they don't consider orientation at all. // If a long part is oriented along the wrong axis in world space, the bounds we'd get // here could be very wrong. We need to come up with essentially the renderer bounds: // a bounding box in world space that encompasses the mesh var m = Matrix4x4.TRS (smr.transform.position, smr.transform.rotation, Vector3.one // remember scale already factored in! ); var vertices = mesh.vertices; var smrBounds = new Bounds (m.MultiplyPoint3x4 (vertices [0]), Vector3.zero); for (int i = 1; i < vertices.Length; ++i) smrBounds.Encapsulate (m.MultiplyPoint3x4 (vertices [i])); UnityEngine.Object.Destroy (mesh); boundsList.Add (smrBounds); } else if (r is MeshRenderer) { // note: there are ParticleRenderers, LineRenderers, and TrailRenderers r.gameObject.GetComponent<MeshFilter> ().sharedMesh.RecalculateBounds (); boundsList.Add (r.bounds); } }); Bounds bounds = boundsList [0]; boundsList.Skip (1).ToList ().ForEach (b => bounds.Encapsulate (b)); return bounds; } }*/ private void OnGUI () { if (tooltipstyle == null) { setStyles (); } if (osdtime > Time.time) { float osdheight = osdstyle.CalcSize (new GUIContent (osdmessage)).y; GUILayout.BeginArea (new Rect (0, Screen.height * 0.1f, Screen.width, osdheight), osdstyle); GUILayout.Label (osdmessage, osdstyle); GUILayout.EndArea (); } if (visible) { if (refreshwait > 0) { refreshwait = refreshwait - 1; } else { switch (mystate) { case ASPState.IDLE: EditorLogic editor = EditorLogic.fetch; ShipConstruct ship = editor.ship; if (ship != null) { List<Part> parts = ship.parts; if ((parts != null) && (parts.Count>0) && (parts [0] != null)) { parts [0].SetHighlight (false, true); if (tanks == null) { tanks = ASPStaging.findFuelTanks (parts); } else { foreach (Part p in parts) { if ((vizualize) && (p != null)) { if ((badStartTank != null) && (p == badStartTank)) { Vector3 position = Camera.main.WorldToScreenPoint (p.transform.position); GUI.Label (new Rect (position.x, Screen.height - position.y, 200, 30), "Start tank"); badStartTank.SetHighlightColor (Color.blue); badStartTank.SetHighlight (true, false); badStartTank.highlightType = Part.HighlightType.AlwaysOn; } else if ((badDestTank != null) && (p == badDestTank)) { Vector3 position = Camera.main.WorldToScreenPoint (p.transform.position); GUI.Label (new Rect (position.x, Screen.height - position.y, 200, 30), "Destination tank"); badDestTank.SetHighlightColor (Color.blue); badDestTank.SetHighlight (true, false); badDestTank.highlightType = Part.HighlightType.AlwaysOn; } else if (blockingTanks.Contains (p)) { Vector3 position = Camera.main.WorldToScreenPoint (p.transform.position); GUI.Label (new Rect (position.x, Screen.height - position.y, 200, 30), "X"); p.SetHighlightColor (Color.red); p.SetHighlight (true, false); p.highlightType = Part.HighlightType.AlwaysOn; } else if (tanks.Contains (p)) { // draw labels on the tanks Vector3 position = Camera.main.WorldToScreenPoint (p.transform.position); string label = "L" + ASPFuelLine.countDecouplersToRoot (p).ToString (); #if DEBUG //label = label+": "+ASPConsoleStuff.getFriendlyName (p.craftID.ToString ()); #endif GUI.Label (new Rect (position.x, Screen.height - position.y, 200, 30), label); if ((p != badStartTank) && (p != badDestTank) && (!blockingTanks.Contains (p))) { p.SetHighlightColor (Color.green); p.SetHighlight (true, false); p.highlightType = Part.HighlightType.AlwaysOn; } } else if (ASPStaging.isDecoupler (p)) { p.SetHighlightColor (Color.magenta); p.SetHighlight (true, false); p.highlightType = Part.HighlightType.AlwaysOn; } else { p.SetHighlight (false, false); } } } } } windowRect = GUILayout.Window (windowID, clampToScreen (windowRect), OnWindow, "AutoAsparagus " + versionString); mousepos = new Vector2 (Input.mousePosition.x, Input.mousePosition.y); if (HighLogic.LoadedSceneIsEditor) { if (windowRect.Contains (mousepos)) { if (editorlocked == false) { EditorLogic.fetch.Lock (true, true, true, "AutoAsparagus"); editorlocked = true; } } else if (editorlocked == true) { EditorLogic.fetch.Unlock ("AutoAsparagus"); editorlocked = false; } } if ((tooltip != null) && (tooltip.Length > 0)) { GUI.depth = 0; Vector2 size = tooltipstyle.CalcSize (new GUIContent (tooltip)); Rect rect = new Rect (Input.mousePosition.x + 20, (Screen.height - Input.mousePosition.y) + 20, size.x, size.y); rect = clampToScreen (rect); GUILayout.BeginArea (rect); GUILayout.Label (tooltip, tooltipstyle); GUILayout.EndArea (); } } break; case ASPState.ERROR: mystate = ASPState.IDLE; break; case ASPState.ADDASP: ASPConsoleStuff.ListTheShip (); mystate = ASPState.CONNECT; ASPFuelLine.AddAsparagusFuelLines (partsWeCanUse [partToUseIndex], textureIndex, partTexturePaths [partToUseIndex], partTextureNames [partToUseIndex], rainbow); if (mystate == ASPState.CONNECT) { osd ("Connecting parts..."); } refreshwait = 100; break; case ASPState.ADDONION: ASPConsoleStuff.ListTheShip (); mystate = ASPState.CONNECT; ASPFuelLine.AddOnionFuelLines (partsWeCanUse [partToUseIndex], textureIndex, partTexturePaths [partToUseIndex], partTextureNames [partToUseIndex], rainbow); if (mystate == ASPState.CONNECT) { osd ("Connecting parts..."); } refreshwait = 100; break; case ASPState.CONNECT: ASPFuelLine.connectFuelLines (); refreshwait = 100; osd ("Refreshing ship..."); mystate = ASPState.AFTERCONNECT; break; case ASPState.AFTERCONNECT: newReloadShip (); refreshwait = 100; if (useSmartStage) { mystate = ASPState.SMARTSTAGE; osd ("Calling SmartStage..."); ASPConsoleStuff.AAprint ("Calling SmartStage"); } else { mystate = ASPState.ADDSTAGES; osd ("Adding empty stages..."); } break; case ASPState.ADDSTAGES: ASPStaging.AddEmptyStages (); mystate = ASPState.STAGE; osd ("Staging decouplers..."); refreshwait = 10; break; case ASPState.STAGE: ASPStaging.AsaparagusTheShip (partsWeCanUse [partToUseIndex].name); mystate = ASPState.AFTERSTAGE; osd ("Decoupler staging done, refreshing..."); refreshwait = 10; break; case ASPState.CLAMPS: if (stageLaunchClamps) { ASPStaging.StageLaunchClamps (launchClampsStage); } mystate = ASPState.FINALREFRESH; osd ("Done!"); refreshwait = 10; break; case ASPState.DELETEFUEL: ASPConsoleStuff.ListTheShip (); int count = ASPFuelLine.DeleteAllFuelLines (partsWeCanUse [partToUseIndex].name); newReloadShip (); osd (count.ToString () + " parts deleted."); mystate = ASPState.IDLE; break; case ASPState.FINALREFRESH: newReloadShip (); mystate = ASPState.IDLE; osd ("Done!"); #if DEBUG tanks = ASPStaging.findFuelTanks (EditorLogic.fetch.ship.Parts); #endif break; case ASPState.AFTERSTAGE: newReloadShip (); if (stageLaunchClamps) { osd ("Staging launch clamps..."); mystate = ASPState.CLAMPS; refreshwait = 10; } else { osd ("Done!"); mystate = ASPState.IDLE; } break; case ASPState.SMARTSTAGE: mystate = ASPState.FINALREFRESH; try { computeStagesMethod.Invoke (null, new object[] { }); } catch (Exception e) { UnityEngine.Debug.LogError ("Error invoking method\n" + e.StackTrace); } osd ("Done!"); break; } } } }