Fixed the TapeDriveAnimator lights shader and did some minor refactoring.
Fixed the TapeDriveAnimator lights shader and did some minor refactoring.

// //
// Kerbal Engineer Redux // Kerbal Engineer Redux
// //
// Copyright (C) 2014 CYBUTEK // Copyright (C) 2016 CYBUTEK
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
   
#region Using Directives  
   
using UnityEngine;  
   
using Random = System.Random;  
   
#endregion  
   
namespace KerbalEngineer namespace KerbalEngineer
{ {
  using UnityEngine;
  using Random = System.Random;
   
public class TapeDriveAnimator : PartModule public class TapeDriveAnimator : PartModule
{ {
#region Public Fields [KSPField]
  public string Lights1 = string.Empty;
[KSPField] public string Lights1 = "";  
[KSPField] public float Lights1Speed = 0; [KSPField]
[KSPField] public string Lights2 = ""; public float Lights1Speed = 0;
[KSPField] public float Lights2Speed = 0;  
[KSPField] public string Lights3 = ""; [KSPField]
[KSPField] public float Lights3Speed = 0; public string Lights2 = string.Empty;
[KSPField] public string Lights4 = "";  
[KSPField] public float Lights4Speed = 0; [KSPField]
[KSPField] public string Lights5 = ""; public float Lights2Speed = 0;
[KSPField] public float Lights5Speed = 0;  
[KSPField] public string Lights6 = ""; [KSPField]
[KSPField] public float Lights6Speed = 0; public string Lights3 = string.Empty;
[KSPField] public int MaxReelSpeed = 0;  
[KSPField] public int MaxRepeatTime = 0; [KSPField]
[KSPField] public int MinReelSpeed = 0; public float Lights3Speed = 0;
[KSPField] public int MinRepeatTime = 0;  
[KSPField] public string Reel1 = ""; [KSPField]
[KSPField] public float Reel1SpeedRatio = 1; public string Lights4 = string.Empty;
[KSPField] public string Reel2 = "";  
[KSPField] public float Reel2SpeedRatio = 1; [KSPField]
[KSPField] public float RepeatTimeDenominator = 1; public float Lights4Speed = 0;
[KSPField] public float SpeedChangeAmount = 0;  
[KSPField] public float SpeedDeadZone = 0; [KSPField]
[KSPField] public float SpeedStopZone = 0; public string Lights5 = string.Empty;
[KSPField] public bool UseBakedAnimation = false;  
  [KSPField]
#endregion public float Lights5Speed = 0;
   
#region Private Fields [KSPField]
  public string Lights6 = string.Empty;
private float currentTime;  
private float deltaTime; [KSPField]
private Shader lights1ShaderOff; public float Lights6Speed = 0;
private Transform lights1Transform;  
private Shader lights2ShaderOff; [KSPField]
private Transform lights2Transform; public int MaxReelSpeed = 0;
private Shader lights3ShaderOff;  
private Transform lights3Transform; [KSPField]
private Shader lights4ShaderOff; public int MaxRepeatTime = 0;
private Transform lights4Transform;  
private Shader lights5ShaderOff; [KSPField]
private Transform lights5Transform; public int MinReelSpeed = 0;
private Shader lights6ShaderOff;  
private Transform lights6Transform; [KSPField]
private Shader lightsShaderOn; public int MinRepeatTime = 0;
private Random random;  
private Transform reel1Transform; [KSPField]
private Transform reel2Transform; public string Reel1 = string.Empty;
private float repeatTime;  
private bool sceneIsEditor; [KSPField]
private float speed; public float Reel1SpeedRatio = 1;
private float targetSpeed;  
private Renderer renderer; [KSPField]
private Light light; public string Reel2 = string.Empty;
   
#endregion [KSPField]
  public float Reel2SpeedRatio = 1;
#region Properties  
  [KSPField]
private bool isRunning; public float RepeatTimeDenominator = 1;
   
  [KSPField]
  public float SpeedChangeAmount = 0;
   
  [KSPField]
  public float SpeedDeadZone = 0;
   
  [KSPField]
  public float SpeedStopZone = 0;
   
  [KSPField]
  public bool UseBakedAnimation = false;
   
  private Shader m_ButtonLightOffShader;
  private Shader m_ButtonLightOnShader;
  private Material m_ButtonSet1Material;
  private Material m_ButtonSet2Material;
  private Material m_ButtonSet3Material;
  private Material m_ButtonSet4Material;
  private Material m_ButtonSet5Material;
  private Material m_ButtonSet6Material;
  private float m_CurrentTime;
  private float m_DeltaTime;
  private bool m_IsRunning;
  private Random m_Random;
  private Transform m_Reel1Transform;
  private Transform m_Reel2Transform;
  private float m_RepeatTime;
  private bool m_SceneIsEditor;
  private float m_Speed;
  private float m_TargetSpeed;
   
public bool IsRunning public bool IsRunning
{ {
get { return this.isRunning; } get
  {
  return m_IsRunning;
  }
set set
{ {
this.isRunning = value; m_IsRunning = value;
   
if (this.isRunning) if (m_IsRunning)
{ {
if (this.UseBakedAnimation) if (UseBakedAnimation)
{ {
this.StartBakedAnimation(); StartBakedAnimation();
} }
} }
else else
{ {
if (this.UseBakedAnimation) if (UseBakedAnimation)
{ {
this.StopBakedAnimation(); StopBakedAnimation();
} }
} }
} }
} }
   
#endregion  
   
#region Initialisation  
   
public override void OnStart(StartState state) public override void OnStart(StartState state)
{ {
renderer = GetComponent<Renderer>(); m_Random = new Random();
   
this.random = new Random(); StopBakedAnimation();
  IsRunning = false;
this.StopBakedAnimation();  
this.IsRunning = false;  
   
if (HighLogic.LoadedSceneIsEditor) if (HighLogic.LoadedSceneIsEditor)
{ {
this.part.OnEditorAttach += this.OnEditorAttach; part.OnEditorAttach += OnEditorAttach;
this.part.OnEditorDetach += this.OnEditorDetach; part.OnEditorDetach += OnEditorDetach;
   
this.sceneIsEditor = true; m_SceneIsEditor = true;
   
if (this.part.parent != null) if (part.parent != null)
{ {
this.IsRunning = true; IsRunning = true;
} }
} }
else if (HighLogic.LoadedSceneIsFlight) else if (HighLogic.LoadedSceneIsFlight)
{ {
this.IsRunning = true; IsRunning = true;
} }
   
if (!this.UseBakedAnimation) if (UseBakedAnimation == false)
{ {
this.InitialiseReels(); InitialiseReels();
this.InitialiseLights(); InitialiseLights();
} }
  }
   
  public override void OnUpdate()
  {
  if (UseBakedAnimation)
  {
  return;
  }
   
  m_DeltaTime = m_SceneIsEditor ? Time.deltaTime : TimeWarp.deltaTime;
   
  if (TimeWarp.CurrentRate != 1.0f && TimeWarp.WarpMode != TimeWarp.Modes.LOW)
  {
  return;
  }
   
  if (IsRunning)
  {
  UpdateTimerCycle();
  UpdateSpeed();
  UpdateReels();
  UpdateLights();
  }
  else
  {
  m_TargetSpeed = 0;
   
  if (m_Speed != 0)
  {
  UpdateSpeed();
  UpdateReels();
  UpdateLights();
  }
  }
  }
   
  private static void SetShaderOnMaterial(Material material, Shader shader)
  {
  if (material != null && shader != null)
  {
  material.shader = shader;
  }
  }
   
  private Material GetMaterialOnModelTransform(string transformName)
  {
  Transform modelTransform = GetModelTransform(transformName);
  if (modelTransform != null)
  {
  Renderer renderer = modelTransform.GetComponent<Renderer>();
  if (renderer != null)
  {
  return renderer.material;
  }
  }
   
  return null;
  }
   
  private Transform GetModelTransform(string transformName)
  {
  if (string.IsNullOrEmpty(transformName) == false)
  {
  return part.FindModelTransform(transformName);
  }
   
  return null;
  }
   
  private void InitialiseLights()
  {
  m_ButtonSet1Material = GetMaterialOnModelTransform(Lights1);
  m_ButtonSet2Material = GetMaterialOnModelTransform(Lights2);
  m_ButtonSet3Material = GetMaterialOnModelTransform(Lights3);
  m_ButtonSet4Material = GetMaterialOnModelTransform(Lights4);
  m_ButtonSet5Material = GetMaterialOnModelTransform(Lights5);
  m_ButtonSet6Material = GetMaterialOnModelTransform(Lights6);
   
  m_ButtonLightOffShader = Shader.Find("KSP/Specular");
  m_ButtonLightOnShader = Shader.Find("KSP/Unlit");
} }
   
private void InitialiseReels() private void InitialiseReels()
{ {
if (this.Reel1 != "") if (string.IsNullOrEmpty(Reel1) == false)
{ {
this.reel1Transform = this.part.FindModelTransform(this.Reel1); m_Reel1Transform = part.FindModelTransform(Reel1);
} }
   
if (this.Reel2 != "") if (string.IsNullOrEmpty(Reel2) == false)
{ {
this.reel2Transform = this.part.FindModelTransform(this.Reel2); m_Reel2Transform = part.FindModelTransform(Reel2);
} }
} }
   
private void InitialiseLights() private void OnEditorAttach()
{ {
if (this.Lights1 != "") IsRunning = true;
{ }
this.lights1Transform = this.part.FindModelTransform(this.Lights1);  
this.lights1ShaderOff = renderer.material.shader; private void OnEditorDetach()
} {
  IsRunning = false;
if (this.Lights2 != "") }
{  
this.lights2Transform = this.part.FindModelTransform(this.Lights2); private void StartBakedAnimation()
this.lights2ShaderOff = renderer.material.shader; {
} foreach (Animation animator in part.FindModelAnimators())
  {
if (this.Lights3 != "") animator.Play();
{ }
this.lights3Transform = this.part.FindModelTransform(this.Lights3); }
this.lights3ShaderOff = renderer.material.shader;  
} private void StopBakedAnimation()
  {
if (this.Lights4 != "") foreach (Animation animator in part.FindModelAnimators())
{ {
this.lights4Transform = this.part.FindModelTransform(this.Lights4); animator.Stop();
this.lights4ShaderOff = renderer.material.shader; }
} }
   
if (this.Lights5 != "") private void Update()
{ {
this.lights5Transform = this.part.FindModelTransform(this.Lights5); if (m_SceneIsEditor)
this.lights5ShaderOff = renderer.material.shader; {
} OnUpdate();
  }
if (this.Lights6 != "") }
{  
this.lights6Transform = this.part.FindModelTransform(this.Lights6); private void UpdateButtonMaterial(Material material, float targetSpeed)
this.lights6ShaderOff = renderer.material.shader; {
} if (material == null)
  {
this.lightsShaderOn = Shader.Find("Unlit/Texture"); return;
} }
   
#endregion bool lightsOn;
   
#region Updating if (targetSpeed > 0)
  {
public override void OnUpdate() lightsOn = (m_Speed > targetSpeed);
{ }
if (!this.UseBakedAnimation) else if (targetSpeed < 0)
{ {
this.deltaTime = this.sceneIsEditor ? Time.deltaTime : TimeWarp.deltaTime; lightsOn = (m_Speed < targetSpeed);
  }
if (TimeWarp.CurrentRate != 1.0f && TimeWarp.WarpMode != TimeWarp.Modes.LOW) else
{ {
return; lightsOn = (m_Speed == 0);
} }
   
if (this.IsRunning) SetShaderOnMaterial(material, lightsOn ? m_ButtonLightOnShader : m_ButtonLightOffShader);
{ }
this.UpdateTimerCycle();  
this.UpdateSpeed(); private void UpdateLights()
this.UpdateReels(); {
this.UpdateLights(); UpdateButtonMaterial(m_ButtonSet1Material, Lights1Speed);
  UpdateButtonMaterial(m_ButtonSet2Material, Lights2Speed);
  UpdateButtonMaterial(m_ButtonSet3Material, Lights3Speed);
  UpdateButtonMaterial(m_ButtonSet4Material, Lights4Speed);
  UpdateButtonMaterial(m_ButtonSet5Material, Lights5Speed);
  UpdateButtonMaterial(m_ButtonSet6Material, Lights6Speed);
  }
   
  private void UpdateReels()
  {
  if (m_Reel1Transform != null && m_Speed != 0)
  {
  m_Reel1Transform.transform.Rotate(Vector3.right, m_Speed * Reel1SpeedRatio);
  }
   
  if (m_Reel2Transform != null && m_Speed != 0)
  {
  m_Reel2Transform.transform.Rotate(Vector3.right, m_Speed * Reel2SpeedRatio);
  }
  }
   
  private void UpdateSpeed()
  {
  if (m_Speed < m_TargetSpeed)
  {
  if (m_Speed < m_TargetSpeed - SpeedDeadZone)
  {
  m_Speed += SpeedChangeAmount * m_DeltaTime;
} }
else else
{ {
this.targetSpeed = 0; m_Speed = m_TargetSpeed;
  }
if (this.speed != 0) }
{ else if (m_Speed > m_TargetSpeed)
this.UpdateSpeed(); {
this.UpdateReels(); if (m_Speed > m_TargetSpeed + SpeedDeadZone)
this.UpdateLights(); {
} m_Speed -= SpeedChangeAmount * m_DeltaTime;
} }
} else
} {
  m_Speed = m_TargetSpeed;
private void Update() }
{  
if (this.sceneIsEditor)  
{  
this.OnUpdate();  
}  
}  
   
private void OnEditorAttach()  
{  
this.IsRunning = true;  
}  
   
private void OnEditorDetach()  
{  
this.IsRunning = false;  
}  
   
private void StopBakedAnimation()  
{  
foreach (var animator in this.part.FindModelAnimators())  
{  
animator.Stop();  
}  
}  
   
private void StartBakedAnimation()  
{  
foreach (var animator in this.part.FindModelAnimators())  
{  
animator.Play();  
} }
} }
   
private void UpdateTimerCycle() private void UpdateTimerCycle()
{ {
this.currentTime += this.deltaTime; m_CurrentTime += m_DeltaTime;
   
if (this.currentTime >= this.repeatTime) if (m_CurrentTime >= m_RepeatTime)
{ {
this.targetSpeed = this.random.Next(this.MinReelSpeed, this.MaxReelSpeed); m_TargetSpeed = m_Random.Next(MinReelSpeed, MaxReelSpeed);
   
if (this.targetSpeed > -this.SpeedStopZone && this.targetSpeed < this.SpeedStopZone) if (m_TargetSpeed > -SpeedStopZone && m_TargetSpeed < SpeedStopZone)
{ {
this.targetSpeed = 0; m_TargetSpeed = 0;
} }
   
this.repeatTime = this.random.Next(this.MinRepeatTime, this.MaxRepeatTime); m_RepeatTime = m_Random.Next(MinRepeatTime, MaxRepeatTime);
   
if (this.RepeatTimeDenominator != 0) if (RepeatTimeDenominator != 0)
{ {
this.repeatTime /= this.RepeatTimeDenominator; m_RepeatTime /= RepeatTimeDenominator;
} }
   
this.currentTime -= this.repeatTime; m_CurrentTime -= m_RepeatTime;
} }
} }
   
private void UpdateSpeed()  
{  
if (this.speed < this.targetSpeed)  
{  
if (this.speed < this.targetSpeed - this.SpeedDeadZone)  
{  
this.speed += this.SpeedChangeAmount * this.deltaTime;  
}  
else  
{  
this.speed = this.targetSpeed;  
}  
}  
else if (this.speed > this.targetSpeed)  
{  
if (this.speed > this.targetSpeed + this.SpeedDeadZone)  
{  
this.speed -= this.SpeedChangeAmount * this.deltaTime;  
}  
else  
{  
this.speed = this.targetSpeed;  
}  
}  
}  
   
private void UpdateReels()  
{  
if (this.reel1Transform != null && this.speed != 0)  
{  
this.reel1Transform.transform.Rotate(Vector3.right, this.speed * this.Reel1SpeedRatio);  
}  
   
if (this.reel2Transform != null && this.speed != 0)  
{  
this.reel2Transform.transform.Rotate(Vector3.right, this.speed * this.Reel2SpeedRatio);  
}  
}  
   
private void UpdateLights()  
{  
if (this.lights1Transform != null)  
{  
this.UpdateLightTransform(this.lights1Transform, this.lightsShaderOn, this.lights1ShaderOff, this.Lights1Speed);  
}  
if (this.lights2Transform != null)  
{  
this.UpdateLightTransform(this.lights2Transform, this.lightsShaderOn, this.lights2ShaderOff, this.Lights2Speed);  
}  
if (this.lights3Transform != null)  
{  
this.UpdateLightTransform(this.lights3Transform, this.lightsShaderOn, this.lights3ShaderOff, this.Lights3Speed);  
}  
if (this.lights4Transform != null)  
{  
this.UpdateLightTransform(this.lights4Transform, this.lightsShaderOn, this.lights4ShaderOff, this.Lights4Speed);  
}  
if (this.lights5Transform != null)  
{  
this.UpdateLightTransform(this.lights5Transform, this.lightsShaderOn, this.lights5ShaderOff, this.Lights5Speed);  
}  
if (this.lights6Transform != null)  
{  
this.UpdateLightTransform(this.lights6Transform, this.lightsShaderOn, this.lights6ShaderOff, this.Lights6Speed);  
}  
}  
   
private void UpdateLightTransform(Component lights, Shader on, Shader off, float targetSpeed)  
{  
bool lightsOn;  
   
if (targetSpeed > 0)  
{  
lightsOn = (this.speed > targetSpeed);  
}  
else if (targetSpeed < 0)  
{  
lightsOn = (this.speed < targetSpeed);  
}  
else  
{  
lightsOn = (this.speed == 0);  
}  
   
lights.GetComponent<Renderer>().material.shader = lightsOn ? @on : off;  
}  
   
#endregion  
} }
} }