AxisControl.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. using UnityEngine.InputSystem.LowLevel;
  2. using UnityEngine.InputSystem.Processors;
  3. ////REVIEW: change 'clampToConstant' to simply 'clampToMin'?
  4. namespace UnityEngine.InputSystem.Controls
  5. {
  6. /// <summary>
  7. /// A floating-point axis control.
  8. /// </summary>
  9. /// <remarks>
  10. /// Can optionally be configured to perform normalization.
  11. /// Stored as either a float, a short, a byte, or a single bit.
  12. /// </remarks>
  13. [Scripting.Preserve]
  14. public class AxisControl : InputControl<float>
  15. {
  16. /// <summary>
  17. /// Clamping behavior for an axis control.
  18. /// </summary>
  19. public enum Clamp
  20. {
  21. /// <summary>
  22. /// Do not clamp values.
  23. /// </summary>
  24. None = 0,
  25. /// <summary>
  26. /// Clamp values to <see cref="clampMin"/> and <see cref="clampMax"/>
  27. /// before normalizing the value.
  28. /// </summary>
  29. BeforeNormalize = 1,
  30. /// <summary>
  31. /// Clamp values to <see cref="clampMin"/> and <see cref="clampMax"/>
  32. /// after normalizing the value.
  33. /// </summary>
  34. AfterNormalize = 2,
  35. /// <summary>
  36. /// Clamp values any value below <see cref="clampMin"/> or above <see cref="clampMax"/>
  37. /// to <see cref="clampConstant"/> before normalizing the value.
  38. /// </summary>
  39. ToConstantBeforeNormalize = 3,
  40. }
  41. // These can be added as processors but they are so common that we
  42. // build the functionality right into AxisControl to save us an
  43. // additional object and an additional virtual call.
  44. // NOTE: A number of the parameters here can be expressed in much simpler form.
  45. // E.g. 'scale', 'scaleFactor' and 'invert' could all be rolled into a single
  46. // multiplier. And maybe that's what we should do. However, the one advantage
  47. // of the current setup is that it allows to set these operations up individually.
  48. // For example, a given layout may want to have a very specific scale factor but
  49. // then a derived layout needs the value to be inverted. If it was a single setting,
  50. // the derived layout would have to know the specific scale factor in order to come
  51. // up with a valid multiplier.
  52. /// <summary>
  53. /// Clamping behavior when reading values. <see cref="Clamp.None"/> by default.
  54. /// </summary>
  55. /// <value>Clamping behavior.</value>
  56. /// <remarks>
  57. /// When a value is read from the control's state, it is first converted
  58. /// to a floating-point number.
  59. /// </remarks>
  60. /// <seealso cref="clampMin"/>
  61. /// <seealso cref="clampMax"/>
  62. /// <seealso cref="clampConstant"/>
  63. public Clamp clamp;
  64. /// <summary>
  65. /// Lower end of the clamping range when <see cref="clamp"/> is not
  66. /// <see cref="Clamp.None"/>.
  67. /// </summary>
  68. /// <value>Lower bound of clamping range. Inclusive.</value>
  69. public float clampMin;
  70. /// <summary>
  71. /// Upper end of the clamping range when <see cref="clamp"/> is not
  72. /// <see cref="Clamp.None"/>.
  73. /// </summary>
  74. /// <value>Upper bound of clamping range. Inclusive.</value>
  75. public float clampMax;
  76. /// <summary>
  77. /// When <see cref="clamp"/> is set to <see cref="Clamp.ToConstantBeforeNormalize"/>
  78. /// and the value is outside of the range defined by <see cref="clampMin"/> and
  79. /// <see cref="clampMax"/>, this value is returned.
  80. /// </summary>
  81. /// <value>Constant value to return when value is outside of clamping range.</value>
  82. public float clampConstant;
  83. ////REVIEW: why not just roll this into scaleFactor?
  84. /// <summary>
  85. /// If true, the input value will be inverted, i.e. multiplied by -1. Off by default.
  86. /// </summary>
  87. /// <value>Whether to invert the input value.</value>
  88. public bool invert;
  89. /// <summary>
  90. /// If true, normalize the input value to [0..1] or [-1..1] (depending on the
  91. /// value of <see cref="normalizeZero"/>. Off by default.
  92. /// </summary>
  93. /// <value>Whether to normalize input values or not.</value>
  94. /// <seealso cref="normalizeMin"/>
  95. /// <seealso cref="normalizeMax"/>
  96. public bool normalize;
  97. ////REVIEW: shouldn't these come from the control min/max value by default?
  98. /// <summary>
  99. /// If <see cref="normalize"/> is on, this is the input value that corresponds
  100. /// to 0 of the normalized [0..1] or [-1..1] range.
  101. /// </summary>
  102. /// <value>Input value that should become 0 or -1.</value>
  103. /// <remarks>
  104. /// In other words, with <see cref="normalize"/> on, input values are mapped from
  105. /// the range of [normalizeMin..normalizeMax] to [0..1] or [-1..1] (depending on
  106. /// <see cref="normalizeZero"/>).
  107. /// </remarks>
  108. public float normalizeMin;
  109. /// <summary>
  110. /// If <see cref="normalize"/> is on, this is the input value that corresponds
  111. /// to 1 of the normalized [0..1] or [-1..1] range.
  112. /// </summary>
  113. /// <value>Input value that should become 1.</value>
  114. /// <remarks>
  115. /// In other words, with <see cref="normalize"/> on, input values are mapped from
  116. /// the range of [normalizeMin..normalizeMax] to [0..1] or [-1..1] (depending on
  117. /// <see cref="normalizeZero"/>).
  118. /// </remarks>
  119. public float normalizeMax;
  120. /// <summary>
  121. /// Where to put the zero point of the normalization range. Only relevant
  122. /// if <see cref="normalize"/> is set to true. Defaults to 0.
  123. /// </summary>
  124. /// <value>Zero point of normalization range.</value>
  125. /// <remarks>
  126. /// The value of this property determines where the zero point is located in the
  127. /// range established by <see cref="normalizeMin"/> and <see cref="normalizeMax"/>.
  128. ///
  129. /// If <c>normalizeZero</c> is placed at <see cref="normalizeMin"/>, the normalization
  130. /// returns a value in the [0..1] range mapped from the input value range of
  131. /// <see cref="normalizeMin"/> and <see cref="normalizeMax"/>.
  132. ///
  133. /// If <c>normalizeZero</c> is placed in-between <see cref="normalizeMin"/> and
  134. /// <see cref="normalizeMax"/>, normalization returns a value in the [-1..1] mapped
  135. /// from the input value range of <see cref="normalizeMin"/> and <see cref="normalizeMax"/>
  136. /// and the zero point between the two established by <c>normalizeZero</c>.
  137. /// </remarks>
  138. public float normalizeZero;
  139. ////REVIEW: why not just have a default scaleFactor of 1?
  140. /// <summary>
  141. /// Whether the scale the input value by <see cref="scaleFactor"/>. Off by default.
  142. /// </summary>
  143. /// <value>True if inputs should be scaled by <see cref="scaleFactor"/>.</value>
  144. public bool scale;
  145. /// <summary>
  146. /// Value to multiple input values with. Only applied if <see cref="scale"/> is <c>true</c>.
  147. /// </summary>
  148. /// <value>Multiplier for input values.</value>
  149. public float scaleFactor;
  150. /// <summary>
  151. /// Apply modifications to the given value according to the parameters configured
  152. /// on the control (<see cref="clamp"/>, <see cref="normalize"/>, etc).
  153. /// </summary>
  154. /// <param name="value">Input value.</param>
  155. /// <returns>A processed value (clamped, normalized, etc).</returns>
  156. /// <seealso cref="clamp"/>
  157. /// <seealso cref="normalize"/>
  158. /// <seealso cref="scale"/>
  159. /// <seealso cref="invert"/>
  160. protected float Preprocess(float value)
  161. {
  162. if (scale)
  163. value *= scaleFactor;
  164. if (clamp == Clamp.ToConstantBeforeNormalize)
  165. {
  166. if (value < clampMin || value > clampMax)
  167. value = clampConstant;
  168. }
  169. else if (clamp == Clamp.BeforeNormalize)
  170. value = Mathf.Clamp(value, clampMin, clampMax);
  171. if (normalize)
  172. value = NormalizeProcessor.Normalize(value, normalizeMin, normalizeMax, normalizeZero);
  173. if (clamp == Clamp.AfterNormalize)
  174. value = Mathf.Clamp(value, clampMin, clampMax);
  175. if (invert)
  176. value *= -1.0f;
  177. return value;
  178. }
  179. /// <summary>
  180. /// Default-initialize the control.
  181. /// </summary>
  182. /// <remarks>
  183. /// Defaults the format to <see cref="InputStateBlock.FormatFloat"/>.
  184. /// </remarks>
  185. public AxisControl()
  186. {
  187. m_StateBlock.format = InputStateBlock.FormatFloat;
  188. }
  189. protected override void FinishSetup()
  190. {
  191. base.FinishSetup();
  192. // if we don't have any default state, and we are using normalizeZero, then the default value
  193. // should not be zero. Generate it from normalizeZero.
  194. if (!hasDefaultState && normalize && Mathf.Abs(normalizeZero) > Mathf.Epsilon)
  195. m_DefaultState = stateBlock.FloatToPrimitiveValue(normalizeZero);
  196. }
  197. /// <inheritdoc />
  198. public override unsafe float ReadUnprocessedValueFromState(void* statePtr)
  199. {
  200. var value = stateBlock.ReadFloat(statePtr);
  201. ////REVIEW: this isn't very raw
  202. return Preprocess(value);
  203. }
  204. /// <inheritdoc />
  205. public override unsafe void WriteValueIntoState(float value, void* statePtr)
  206. {
  207. stateBlock.WriteFloat(statePtr, value);
  208. }
  209. /// <inheritdoc />
  210. public override unsafe bool CompareValue(void* firstStatePtr, void* secondStatePtr)
  211. {
  212. var currentValue = ReadValueFromState(firstStatePtr);
  213. var valueInState = ReadValueFromState(secondStatePtr);
  214. return !Mathf.Approximately(currentValue, valueInState);
  215. }
  216. /// <inheritdoc />
  217. public override unsafe float EvaluateMagnitude(void* statePtr)
  218. {
  219. if (m_MinValue.isEmpty || m_MaxValue.isEmpty)
  220. return -1;
  221. var value = ReadValueFromState(statePtr);
  222. var min = m_MinValue.ToSingle();
  223. var max = m_MaxValue.ToSingle();
  224. value = Mathf.Clamp(value, min, max);
  225. // If part of our range is in negative space, evaluate magnitude as two
  226. // separate subspaces.
  227. if (min < 0)
  228. {
  229. if (value < 0)
  230. return NormalizeProcessor.Normalize(Mathf.Abs(value), 0, Mathf.Abs(min), 0);
  231. return NormalizeProcessor.Normalize(value, 0, max, 0);
  232. }
  233. return NormalizeProcessor.Normalize(value, min, max, 0);
  234. }
  235. }
  236. }