Skip to content

Commit 29492cf

Browse files
committed
Merge pull request #2 from asarium/develop
Modular light arrays.
2 parents 0be323f + e1dd66b commit 29492cf

24 files changed

Lines changed: 1143 additions & 216 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,6 @@ Generated_Code #added for RIA/Silverlight projects
106106
_UpgradeReport_Files/
107107
Backup*/
108108
UpgradeLog*.XML
109+
110+
### Plugin specific ignores ###
111+
assets/Plugins/
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#region Usings
2+
3+
using System;
4+
using PAPIPlugin.Interfaces;
5+
6+
#endregion
7+
8+
namespace PAPIPlugin.Arrays
9+
{
10+
public abstract class AbstractLightArray : ILightArray
11+
{
12+
private bool _enabled;
13+
14+
protected ILightGroup ParentGroup { get; private set; }
15+
16+
protected ILightArrayManager ParentManager { get; private set; }
17+
18+
protected AbstractLightArray()
19+
{
20+
Enabled = true;
21+
}
22+
23+
#region ILightArray Members
24+
25+
public bool Enabled
26+
{
27+
get { return _enabled; }
28+
set
29+
{
30+
if (Equals(_enabled, value))
31+
{
32+
return;
33+
}
34+
35+
_enabled = value;
36+
37+
OnEnabledChanged();
38+
}
39+
}
40+
41+
public virtual void Initialize(ILightGroup group)
42+
{
43+
ParentGroup = group;
44+
}
45+
46+
public abstract void Update();
47+
48+
public virtual void Destroy()
49+
{
50+
ParentManager = null;
51+
}
52+
53+
public virtual void InitializeDisplay(ILightArrayManager arrayManager)
54+
{
55+
ParentManager = arrayManager;
56+
}
57+
58+
#endregion
59+
60+
protected event EventHandler EnabledChanged;
61+
62+
protected virtual void OnEnabledChanged()
63+
{
64+
var handler = EnabledChanged;
65+
if (handler != null)
66+
{
67+
handler(this, EventArgs.Empty);
68+
}
69+
}
70+
}
71+
}

PAPIPlugin/Arrays/PAPIArray.cs

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
#region Usings
2+
3+
using System;
4+
using PAPIPlugin.Impl;
5+
using PAPIPlugin.Interfaces;
6+
using PAPIPlugin.Internal;
7+
using UnityEngine;
8+
using Object = UnityEngine.Object;
9+
10+
#endregion
11+
12+
namespace PAPIPlugin.Arrays
13+
{
14+
public class PAPIArray : AbstractLightArray, IConfigNode
15+
{
16+
private const int PAPIPartCount = 4;
17+
18+
private const float PAPILightRadius = 10.0f;
19+
20+
private const double DefaultTargetGlidePath = 6;
21+
22+
/// <summary>
23+
/// If the difference of the gliepath from the target is more than this the whole array will show either red or white.
24+
/// </summary>
25+
private const double DefaultBadGlidepathVariance = 1.5;
26+
27+
private static readonly Vector3 PAPILightDifference = Vector3.right * PAPILightRadius * 1.5f;
28+
29+
private GameObject _papiGameObject;
30+
31+
private GameObject[] _partObjects;
32+
33+
private Vector3d _relativeSurfacePosition;
34+
35+
public PAPIArray()
36+
{
37+
TargetGlidePath = DefaultTargetGlidePath;
38+
BadGlidepathVariance = DefaultBadGlidepathVariance;
39+
40+
EnabledChanged += (sender, args) =>
41+
{
42+
if (Enabled)
43+
{
44+
return;
45+
}
46+
47+
foreach (var partObject in _partObjects)
48+
{
49+
partObject.SetActive(false);
50+
}
51+
};
52+
}
53+
54+
public double BadGlidepathVariance { get; set; }
55+
56+
public double TargetGlidePath { get; set; }
57+
58+
public double Longitude { get; set; }
59+
60+
public double Latitude { get; set; }
61+
62+
public double Heading { get; set; }
63+
64+
#region IConfigNode Members
65+
66+
public void Load(ConfigNode node)
67+
{
68+
BadGlidepathVariance = node.ConvertValue("BadGlidepath", DefaultBadGlidepathVariance);
69+
TargetGlidePath = node.ConvertValue("TargetGlidepath", DefaultTargetGlidePath);
70+
71+
try
72+
{
73+
Longitude = node.ConvertValueWithException<double>("Longitude").ClampAndLog(-180, 180);
74+
Latitude = node.ConvertValueWithException<double>("Latitude").ClampAndLog(-90, 90);
75+
76+
var headingDeg = node.ConvertValueWithException<double>("Heading").ClampAndLog(0, 360);
77+
Heading = (headingDeg / 180) * Math.PI;
78+
}
79+
catch (FormatException e)
80+
{
81+
Util.LogWarning(e.Message);
82+
}
83+
}
84+
85+
public void Save(ConfigNode node)
86+
{
87+
throw new NotImplementedException();
88+
}
89+
90+
#endregion
91+
92+
public override void Destroy()
93+
{
94+
foreach (var partObject in _partObjects)
95+
{
96+
Object.Destroy(partObject);
97+
}
98+
99+
Object.Destroy(_papiGameObject);
100+
101+
base.Destroy();
102+
}
103+
104+
public override void Update()
105+
{
106+
if (!Enabled)
107+
{
108+
return;
109+
}
110+
111+
var currentCamera = Camera.main;
112+
113+
var relativePosition = _papiGameObject.transform.InverseTransformPoint(currentCamera.transform.position);
114+
115+
var normalizedPosition = relativePosition.normalized;
116+
// As the local normal is (0, 1, 0), y is the result of normal * normalizedPosition.
117+
var normalDot = normalizedPosition.y;
118+
119+
var directionDot = normalizedPosition.z;
120+
121+
var angle = 90 - Math.Acos(normalDot) * (180 / Math.PI);
122+
123+
var difference = angle - TargetGlidePath;
124+
125+
for (var i = 0; i < PAPIPartCount; i++)
126+
{
127+
if (directionDot <= 0)
128+
{
129+
_partObjects[i].SetActive(false);
130+
}
131+
else
132+
{
133+
_partObjects[i].SetActive(true);
134+
135+
// Use the direction dot for alpha to fade the lights out
136+
UpdatePAPIPart(i, difference, directionDot);
137+
}
138+
}
139+
}
140+
141+
public override void InitializeDisplay(ILightArrayManager arrayManager)
142+
{
143+
base.InitializeDisplay(arrayManager);
144+
145+
InitializePAPIParts(Latitude, Longitude, Heading);
146+
}
147+
148+
public override void Initialize(ILightGroup @group)
149+
{
150+
base.Initialize(@group);
151+
152+
@group.GetOrAddTypeManager<PAPITypeManager>();
153+
}
154+
155+
/// <summary>
156+
/// Initializes the whole array at the given latitude and longitude with the given altitude. The heading is the
157+
/// direction to array looks to and should be in the range [0, 2 * PI).
158+
/// </summary>
159+
/// <param name="lat">The latitude</param>
160+
/// <param name="lon">The longitude</param>
161+
/// <param name="heading">The heading in radians.</param>
162+
private void InitializePAPIParts(double lat, double lon, double heading)
163+
{
164+
var parentBody = ParentGroup.ParentBody;
165+
166+
var pqs = parentBody.pqsController;
167+
168+
var surfaceNormal = parentBody.transform.InverseTransformDirection(parentBody.GetSurfaceNVector(lat, lon));
169+
var zeroAltSurface = pqs.transform.InverseTransformPoint(parentBody.GetWorldSurfacePosition(lat, lon, 0));
170+
171+
var north = Vector3.up * (float) pqs.radius; // We are in local space so up * radius is the north pole
172+
173+
var directionToNorth = (north - zeroAltSurface).normalized;
174+
175+
var orthogonalNorthDir = Orthonormalise(directionToNorth, surfaceNormal);
176+
177+
var anotherVector = Vector3d.Cross(surfaceNormal, orthogonalNorthDir);
178+
179+
var headingVector = orthogonalNorthDir * Math.Cos(heading) + anotherVector * Math.Sin(heading);
180+
181+
_papiGameObject = new GameObject();
182+
_papiGameObject.transform.parent = parentBody.transform;
183+
_papiGameObject.transform.localPosition = zeroAltSurface;
184+
_papiGameObject.transform.localRotation = Quaternion.LookRotation(headingVector, surfaceNormal);
185+
186+
var maxHeight = double.MinValue;
187+
_partObjects = new GameObject[PAPIPartCount];
188+
for (var i = 0; i < PAPIPartCount; i++)
189+
{
190+
var obj = new GameObject();
191+
192+
AddPAPIPart(obj);
193+
194+
obj.transform.parent = _papiGameObject.transform;
195+
obj.transform.localPosition = (i - (PAPIPartCount / 2)) * PAPILightDifference;
196+
197+
maxHeight = Math.Max(maxHeight, parentBody.GetSurfaceHeight(Latitude, Longitude));
198+
199+
_partObjects[i] = obj;
200+
}
201+
202+
maxHeight = Math.Max(0, maxHeight);
203+
_relativeSurfacePosition =
204+
parentBody.transform.InverseTransformPoint(parentBody.GetWorldSurfacePosition(lat, lon, maxHeight + PAPILightRadius * 0.5));
205+
_papiGameObject.transform.localPosition = _relativeSurfacePosition;
206+
}
207+
208+
private static Vector3d Orthonormalise(Vector3d direction, Vector3d firstVector)
209+
{
210+
// This is basically the first step of a Gram–Schmidt process
211+
// See http://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process
212+
213+
return direction - Vector3d.Dot(firstVector, direction) * firstVector;
214+
}
215+
216+
private static void AddPAPIPart(GameObject obj)
217+
{
218+
var lineRenderer = obj.AddComponent<LineRenderer>();
219+
220+
lineRenderer.useWorldSpace = false;
221+
lineRenderer.transform.parent = obj.transform;
222+
lineRenderer.transform.localPosition = Vector3.zero;
223+
lineRenderer.transform.eulerAngles = Vector3.zero;
224+
225+
lineRenderer.material = new Material(Shader.Find("Particles/Additive"));
226+
lineRenderer.SetColors(Color.red, Color.red);
227+
lineRenderer.SetWidth(PAPILightRadius, PAPILightRadius);
228+
lineRenderer.SetVertexCount(2);
229+
lineRenderer.SetPosition(0, Vector3.zero);
230+
lineRenderer.SetPosition(1, Vector3.up * PAPILightRadius);
231+
}
232+
233+
private void UpdatePAPIPart(int index, double difference, float alpha)
234+
{
235+
var gameObj = _partObjects[index];
236+
237+
var lineRenderer = gameObj.GetComponent<LineRenderer>();
238+
239+
var color = GetArrayPartColor(index, difference);
240+
color.a = alpha;
241+
lineRenderer.SetColors(color, color);
242+
}
243+
244+
private Color GetArrayPartColor(int index, double difference)
245+
{
246+
if (difference < -BadGlidepathVariance)
247+
{
248+
return Color.red;
249+
}
250+
if (difference > BadGlidepathVariance)
251+
{
252+
return Color.white;
253+
}
254+
255+
// This should map temp into [-1, 1]
256+
double temp = index - (PAPIPartCount / 2);
257+
temp = temp / (PAPIPartCount / 2);
258+
259+
return temp > difference ? Color.red : Color.white;
260+
}
261+
}
262+
}

PAPIPlugin/ILightArray.cs

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)