// AntennaRange |
// AntennaRange |
// |
// |
// ARMapRenderer.cs |
// ARMapRenderer.cs |
// |
// |
// Copyright © 2014, toadicus |
// Copyright © 2014, toadicus |
// All rights reserved. |
// All rights reserved. |
// |
// |
// Redistribution and use in source and binary forms, with or without modification, |
// Redistribution and use in source and binary forms, with or without modification, |
// are permitted provided that the following conditions are met: |
// are permitted provided that the following conditions are met: |
// |
// |
// 1. Redistributions of source code must retain the above copyright notice, |
// 1. Redistributions of source code must retain the above copyright notice, |
// this list of conditions and the following disclaimer. |
// this list of conditions and the following disclaimer. |
// |
// |
// 2. Redistributions in binary form must reproduce the above copyright notice, |
// 2. Redistributions in binary form must reproduce the above copyright notice, |
// this list of conditions and the following disclaimer in the documentation and/or other |
// this list of conditions and the following disclaimer in the documentation and/or other |
// materials provided with the distribution. |
// materials provided with the distribution. |
// |
// |
// 3. Neither the name of the copyright holder nor the names of its contributors may be used |
// 3. Neither the name of the copyright holder nor the names of its contributors may be used |
// to endorse or promote products derived from this software without specific prior written permission. |
// to endorse or promote products derived from this software without specific prior written permission. |
// |
// |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
using KSP; |
using KSP; |
using System; |
using System; |
using System.Collections.Generic; |
using System.Collections.Generic; |
using ToadicusTools; |
using ToadicusTools; |
using UnityEngine; |
using UnityEngine; |
|
|
namespace AntennaRange |
namespace AntennaRange |
{ |
{ |
public class ARMapRenderer : MonoBehaviour |
public class ARMapRenderer : MonoBehaviour |
{ |
{ |
#region Fields |
#region Fields |
private Dictionary<Guid, LineRenderer> vesselLineRenderers; |
private Dictionary<Guid, LineRenderer> vesselLineRenderers; |
private Dictionary<Guid, bool> vesselFrameCache; |
|
#endregion |
#endregion |
|
|
#region Properties |
#region Properties |
public LineRenderer this[Guid idx] |
public LineRenderer this[Guid idx] |
{ |
{ |
get |
get |
{ |
{ |
if (this.vesselLineRenderers == null) |
if (this.vesselLineRenderers == null) |
{ |
{ |
this.vesselLineRenderers = new Dictionary<Guid, LineRenderer>(); |
this.vesselLineRenderers = new Dictionary<Guid, LineRenderer>(); |
} |
} |
|
|
if (!this.vesselLineRenderers.ContainsKey(idx)) |
if (!this.vesselLineRenderers.ContainsKey(idx)) |
{ |
{ |
GameObject obj = new GameObject(); |
GameObject obj = new GameObject(); |
obj.layer = 31; |
obj.layer = 31; |
|
|
LineRenderer lr = obj.AddComponent<LineRenderer>(); |
LineRenderer lr = obj.AddComponent<LineRenderer>(); |
|
|
lr.SetColors(Color.green, Color.green); |
lr.SetColors(Color.green, Color.green); |
lr.material = new Material(Shader.Find("Particles/Additive")); |
lr.material = new Material(Shader.Find("Particles/Additive")); |
lr.SetVertexCount(2); |
lr.SetVertexCount(2); |
|
|
this.vesselLineRenderers[idx] = lr; |
this.vesselLineRenderers[idx] = lr; |
} |
} |
|
|
return this.vesselLineRenderers[idx]; |
return this.vesselLineRenderers[idx]; |
} |
} |
} |
} |
#endregion |
#endregion |
|
|
#region MonoBehaviour Lifecycle |
#region MonoBehaviour Lifecycle |
private void Awake() |
private void Awake() |
{ |
{ |
if (ARConfiguration.PrettyLines) |
if (ARConfiguration.PrettyLines) |
{ |
{ |
this.vesselLineRenderers = new Dictionary<Guid, LineRenderer>(); |
this.vesselLineRenderers = new Dictionary<Guid, LineRenderer>(); |
this.vesselFrameCache = new Dictionary<Guid, bool>(); |
|
} |
} |
} |
} |
|
|
private void OnPreCull() |
private void OnPreCull() |
{ |
{ |
if (!HighLogic.LoadedSceneIsFlight || !MapView.MapIsEnabled || !ARConfiguration.PrettyLines) |
if (!HighLogic.LoadedSceneIsFlight || !MapView.MapIsEnabled || !ARConfiguration.PrettyLines) |
{ |
{ |
this.Cleanup(); |
this.Cleanup(); |
|
|
return; |
return; |
} |
} |
|
|
Tools.DebugLogger log = Tools.DebugLogger.New(this); |
Tools.DebugLogger log = Tools.DebugLogger.New(this); |
|
|
try |
try |
{ |
{ |
log.AppendFormat("OnPreCull.\n"); |
log.AppendFormat("OnPreCull.\n"); |
|
|
log.AppendFormat("\tMapView: Draw3DLines: {0}\n" + |
log.AppendFormat("\tMapView: Draw3DLines: {0}\n" + |
"\tMapView.MapCamera.camera.fieldOfView: {1}\n" + |
"\tMapView.MapCamera.camera.fieldOfView: {1}\n" + |
"\tMapView.MapCamera.Distance: {2}\n", |
"\tMapView.MapCamera.Distance: {2}\n", |
MapView.Draw3DLines, |
MapView.Draw3DLines, |
MapView.MapCamera.camera.fieldOfView, |
MapView.MapCamera.camera.fieldOfView, |
MapView.MapCamera.Distance |
MapView.MapCamera.Distance |
); |
); |
|
|
this.vesselFrameCache.Clear(); |
|
|
|
log.AppendLine("vesselFrameCache cleared."); |
log.AppendLine("vesselFrameCache cleared."); |
|
|
if (FlightGlobals.ready && FlightGlobals.Vessels != null) |
if (FlightGlobals.ready && FlightGlobals.Vessels != null) |
{ |
{ |
log.AppendLine("FlightGlobals ready and Vessels list not null."); |
log.AppendLine("FlightGlobals ready and Vessels list not null."); |
|
|
foreach (Vessel vessel in FlightGlobals.Vessels) |
foreach (Vessel vessel in FlightGlobals.Vessels) |
{ |
{ |
if (vessel == null) |
if (vessel == null) |
{ |
{ |
log.AppendFormat("Skipping vessel {0} altogether because it is null.\n"); |
log.AppendFormat("Skipping vessel {0} altogether because it is null.\n"); |
continue; |
continue; |
} |
} |
|
|
log.AppendFormat("Checking vessel {0}.\n", vessel.vesselName); |
log.AppendFormat("Checking vessel {0}.\n", vessel.vesselName); |
|
|
switch (vessel.vesselType) |
switch (vessel.vesselType) |
{ |
{ |
case VesselType.Debris: |
case VesselType.Debris: |
case VesselType.EVA: |
case VesselType.EVA: |
case VesselType.Unknown: |
case VesselType.Unknown: |
case VesselType.SpaceObject: |
case VesselType.SpaceObject: |
log.AppendFormat("\tDiscarded because vessel is of invalid type {0}\n", |
log.AppendFormat("\tDiscarded because vessel is of invalid type {0}\n", |
vessel.vesselType); |
vessel.vesselType); |
continue; |
continue; |
} |
} |
|
|
log.Append("\tChecking connection status...\n"); |
log.Append("\tChecking connection status...\n"); |
|
|
/*if (vessel.HasConnectedRelay()) |
/*if (vessel.HasConnectedRelay()) |
{ |
{ |
log.AppendLine("\tHas a connection, checking for the best relay to use for the line.");*/ |
log.AppendLine("\tHas a connection, checking for the best relay to use for the line.");*/ |
|
|
IAntennaRelay vesselRelay = null; |
IAntennaRelay vesselRelay = null; |
float bestScore = float.PositiveInfinity; |
float bestScore = float.PositiveInfinity; |
float relayScore = float.NaN; |
float relayScore = float.NaN; |
|
|
foreach (IAntennaRelay relay in RelayDatabase.Instance[vessel].Values) |
foreach (IAntennaRelay relay in RelayDatabase.Instance[vessel].Values) |
{ |
{ |
relayScore = (float)relay.transmitDistance / relay.maxTransmitDistance; |
relayScore = (float)relay.transmitDistance / relay.maxTransmitDistance; |
|
|
if (relayScore < bestScore) |
if (relayScore < bestScore) |
{ |
{ |
bestScore = relayScore; |
bestScore = relayScore; |
vesselRelay = relay as IAntennaRelay; |
vesselRelay = relay as IAntennaRelay; |
} |
} |
} |
} |
|
|
if (vesselRelay != null) |
if (vesselRelay != null) |
{ |
{ |
log.AppendFormat("\t...picked relay {0} with a score of {1}", |
log.AppendFormat("\t...picked relay {0} with a score of {1}", |
vesselRelay, relayScore |
vesselRelay, relayScore |
); |
); |
|
|
this.SetRelayVertices(vesselRelay); |
this.SetRelayVertices(vesselRelay); |
} |
} |
/*} |
/*} |
else if (this.vesselLineRenderers.ContainsKey(vessel.id)) |
else if (this.vesselLineRenderers.ContainsKey(vessel.id)) |
{ |
{ |
log.AppendLine("\tDisabling line because vessel has no connection."); |
log.AppendLine("\tDisabling line because vessel has no connection."); |
this[vessel.id].enabled = false; |
this[vessel.id].enabled = false; |
}*/ |
}*/ |
} |
} |
} |
} |
} |
} |
catch (Exception) |
catch (Exception) |
{ |
{ |
this.Cleanup(); |
this.Cleanup(); |
} |
} |
#if DEBUG |
#if DEBUG |
finally |
finally |
{ |
{ |
log.Print(); |
log.Print(); |
} |
} |
#endif |
#endif |
} |
} |
|
|
private void OnDestroy() |
private void OnDestroy() |
{ |
{ |
this.Cleanup(); |
this.Cleanup(); |
|
|
print("ARMapRenderer: Destroyed."); |
print("ARMapRenderer: Destroyed."); |
} |
} |
#endregion |
#endregion |
|
|
private void SetRelayVertices(IAntennaRelay relay) |
private void SetRelayVertices(IAntennaRelay relay) |
{ |
{ |
if (relay == null) |
if (relay == null) |
{ |
{ |
return; |
return; |
} |
} |
|
|
LineRenderer renderer = this[relay.vessel.id]; |
LineRenderer renderer = this[relay.vessel.id]; |
|
|
Vector3d start; |
Vector3d start; |
Vector3d end; |
Vector3d end; |
|
|
renderer.enabled = true; |
renderer.enabled = true; |
|
|
if (!relay.CanTransmit()) |
if (!relay.CanTransmit()) |
{ |
{ |
renderer.SetColors(Color.red, Color.red); |
renderer.SetColors(Color.red, Color.red); |
} |
} |
else |
else |
{ |
{ |
if (relay.transmitDistance < relay.nominalTransmitDistance) |
if (relay.transmitDistance < relay.nominalTransmitDistance) |
{ |
{ |
renderer.SetColors(Color.green, Color.green); |
renderer.SetColors(Color.green, Color.green); |
} |
} |
else |
else |
{ |
{ |
renderer.SetColors(Color.yellow, Color.yellow); |
renderer.SetColors(Color.yellow, Color.yellow); |
} |
} |
} |
} |
|
|
start = ScaledSpace.LocalToScaledSpace(relay.vessel.GetWorldPos3D()); |
start = ScaledSpace.LocalToScaledSpace(relay.vessel.GetWorldPos3D()); |
|
|
if (relay.KerbinDirect) |
if (relay.KerbinDirect) |
{ |
{ |
end = ScaledSpace.LocalToScaledSpace(AntennaRelay.Kerbin.position); |
end = ScaledSpace.LocalToScaledSpace(AntennaRelay.Kerbin.position); |
} |
} |
else |
else |
{ |
{ |
if (relay.targetRelay == null) |
if (relay.targetRelay == null) |
{ |
{ |
return; |
return; |
} |
} |
end = ScaledSpace.LocalToScaledSpace(relay.targetRelay.vessel.GetWorldPos3D()); |
end = ScaledSpace.LocalToScaledSpace(relay.targetRelay.vessel.GetWorldPos3D()); |
} |
} |
|
|
float lineWidth; |
float lineWidth; |
|
|
if (MapView.Draw3DLines) |
if (MapView.Draw3DLines) |
{ |
{ |
lineWidth = 0.004f * MapView.MapCamera.Distance; |
lineWidth = 0.004f * MapView.MapCamera.Distance; |
} |
} |
else |
else |
{ |
{ |
lineWidth = 1f; |
lineWidth = 1f; |
|
|
start = MapView.MapCamera.camera.WorldToScreenPoint(start); |
start = MapView.MapCamera.camera.WorldToScreenPoint(start); |
end = MapView.MapCamera.camera.WorldToScreenPoint(end); |
end = MapView.MapCamera.camera.WorldToScreenPoint(end); |
|
|
float d = Screen.height / 2f + 0.01f; |
float d = Screen.height / 2f + 0.01f; |
start.z = start.z >= 0f ? d : -d; |
start.z = start.z >= 0f ? d : -d; |
end.z = end.z >= 0f ? d : -d; |
end.z = end.z >= 0f ? d : -d; |
} |
} |
|
|
renderer.SetWidth(lineWidth, lineWidth); |
renderer.SetWidth(lineWidth, lineWidth); |
|
|
renderer.SetPosition(0, start); |
renderer.SetPosition(0, start); |
renderer.SetPosition(1, end); |
renderer.SetPosition(1, end); |
} |
} |
|
|
public void Cleanup() |
public void Cleanup() |
{ |
{ |
if (this.vesselLineRenderers != null && this.vesselLineRenderers.Count > 0) |
if (this.vesselLineRenderers != null && this.vesselLineRenderers.Count > 0) |
{ |
{ |
foreach (LineRenderer lineRenderer in this.vesselLineRenderers.Values) |
foreach (LineRenderer lineRenderer in this.vesselLineRenderers.Values) |
{ |
{ |
lineRenderer.enabled = false; |
lineRenderer.enabled = false; |
GameObject.Destroy(lineRenderer.gameObject); |
GameObject.Destroy(lineRenderer.gameObject); |
} |
} |
this.vesselLineRenderers.Clear(); |
this.vesselLineRenderers.Clear(); |
} |
} |
|
|
if (this.vesselFrameCache != null && this.vesselFrameCache.Count > 0) |
|
{ |
|
this.vesselFrameCache.Clear(); |
|
} |
|
} |
} |
} |
} |
} |
} |
|
|
|
|