更新到0.6.0.2

This commit is contained in:
2026-07-06 08:47:33 +08:00
parent e29a5178b7
commit 97d41a1385
473 changed files with 156342 additions and 5 deletions
@@ -0,0 +1,12 @@
namespace DrawXXL
{
using UnityEngine;
public class BezierSplineDrawerBase : VisualizerParent
{
[SerializeField] protected Color color = DrawBasics.defaultColor;
[SerializeField] protected float lineWidth = 0.0f;
[SerializeField] protected int straightSubDivisionsPerSegment = 50;
protected float textSize = 0.1f;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b97f2527d9d101a4bb1d9d042e866f70
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,83 @@
namespace DrawXXL
{
using UnityEngine;
/// <summary>
/// 可序列化的 CustomVector3 配置项,替代 VisualizerParent 中重复的 4 组独立字段。
/// </summary>
[System.Serializable]
public struct CustomVector3Config
{
public VisualizerParent.CustomVector3Source source;
public Vector3 clipboardForManualInput;
public GameObject targetGameObject;
public bool hasForcedAbsLength;
public bool picker_isOutfolded;
public float forcedAbsLength;
[Range(0.1f, 10.0f)] public float lengthRelScaleFactor;
public VisualizerParent.VectorInterpretation vectorInterpretation;
public DrawBasics.CameraForAutomaticOrientation observerCamera;
public CustomVector3Config(VisualizerParent.CustomVector3Source source, Vector3 clipboard, GameObject target, bool hasForcedAbs, bool pickerOutfolded, float forcedLen, float relScale, VisualizerParent.VectorInterpretation vecInterpretation, DrawBasics.CameraForAutomaticOrientation cam)
{
this.source = source;
this.clipboardForManualInput = clipboard;
this.targetGameObject = target;
this.hasForcedAbsLength = hasForcedAbs;
this.picker_isOutfolded = pickerOutfolded;
this.forcedAbsLength = forcedLen;
this.lengthRelScaleFactor = relScale;
this.vectorInterpretation = vecInterpretation;
this.observerCamera = cam;
}
public static CustomVector3Config Default()
{
return new CustomVector3Config
{
source = (VisualizerParent.CustomVector3Source)(-1),
clipboardForManualInput = Vector3.zero,
targetGameObject = null,
hasForcedAbsLength = false,
picker_isOutfolded = false,
forcedAbsLength = 1.0f,
lengthRelScaleFactor = 1.0f,
vectorInterpretation = VisualizerParent.VectorInterpretation.globalSpace,
observerCamera = DrawBasics.CameraForAutomaticOrientation.sceneViewCamera
};
}
}
/// <summary>
/// 可序列化的 CustomVector2 配置项,替代 VisualizerParent 中重复的 4 组独立字段。
/// </summary>
[System.Serializable]
public struct CustomVector2Config
{
public VisualizerParent.CustomVector2Source source;
public Vector2 clipboardForManualInput;
public GameObject targetGameObject;
public bool hasForcedAbsLength;
public bool picker_isOutfolded;
[Range(-360.0f, 360.0f)] public float rotationFromRight;
public float forcedAbsLength;
[Range(0.1f, 10.0f)] public float lengthRelScaleFactor;
public VisualizerParent.VectorInterpretation vectorInterpretation;
public static CustomVector2Config Default()
{
return new CustomVector2Config
{
source = (VisualizerParent.CustomVector2Source)(-1),
clipboardForManualInput = Vector2.zero,
targetGameObject = null,
hasForcedAbsLength = false,
picker_isOutfolded = false,
rotationFromRight = 0.0f,
forcedAbsLength = 1.0f,
lengthRelScaleFactor = 1.0f,
vectorInterpretation = VisualizerParent.VectorInterpretation.globalSpace
};
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b5e4f2b3e473e17499602464b5b4dc9e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,374 @@
namespace DrawXXL
{
using UnityEngine;
[HelpURL("https://www.symphonygames.net/drawxxldocumentation/index.html")]
[AddComponentMenu("Xeric Library/DebugDrawLibrary/Internal Not For Manual Creation/Draw XXL Spline 2D Connection")]
[ExecuteInEditMode]
public class DrawXXLSpline2DConnection : MonoBehaviour
{
Quaternion lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf; //-> other than the position the spline control points don't save a "rotation" but only a "direction", so there is an extra member to care for the synchronisation here
public BezierSplineDrawer2D bezierSplineDrawer_thatHasReferencedThisGameobject;
//public InternalDXXL_BezierControlSubPoint2D bezierSubPoint_thatHasReferencedThisGameobject; //this is not suitable as reference, because in the serialized context "InternalDXXL_BezierControlSubPoint" acts as value type, not as reference type.
public bool componentHasBeenManuallyCreated = true;
public int i_ofControlPointTriplet_thisGameobjectIsBoundTo;
public InternalDXXL_BezierControlSubPoint.SubPointType subPointType_whereThisGameobjectIsBoundTo;
void OnDestroy()
{
//-> calling "Undo.RegisterCompleteObjectUndo(bezierSplineDrawer_thatHasReferencedThisGameobject, "undoName")" also doesn't solve the bug, that the connectionReference cannot be restored via "Editor/Undo" after this connection component has been deleted. But it at least prevents the bool-comparison-error described in "TryEarlyReturnAndSelfDeleteBecauseReferenceGotLost()". Though this error can also be prevented with an additional bool-check.
//-> Moreover calling "Undo.RegisterCompleteObjectUndo(bezierSplineDrawer_thatHasReferencedThisGameobject, "undoName")" may lead to confusting undo states, because this connection component gets destroyed (and therewith this "OnDestroy()" here gets called) not only when the user deletes it (or the carrying boundGameobject), but also when the spline component gets destroyed (specifically this connection component is destroyed inside "OnDestroy()" of the spline component). So the spline most likely already has an "Undo.DestroyImmediate()" registered for itself through the spline deletion the was triggerd by manual control in the Editor. Then it would be saved into the undo state once more here. That seems to risky since the undo system can have obscure errors when used in such hacky ways, which can even crash the Unity Editor.
}
void Update()
{
if (TryDestroyThisComponentIfItWasManuallyCreated()) { return; }
if (TryEarlyReturnAndSelfDeleteBecauseReferenceGotLost()) { return; }
//No "register undo for spline" is done here before changed transform values get written to the spline:
//-> It is unclear how this gameobject changed it's transform. Has the "changer" already filed an "Undo" or should it be filed here? If it has already been filed is it harmful when it is filed twice into the undo state?
//-> It is not necessary: since the transform of this boundGameobject is authoritative for the spline shape, the spline shape will follow the undo as soon as the transform is reverted via an Undo.
//-> So the changer of this transform is responsible for caring for the undo entry registration. In most cases the transform will be changed via the Scene view handles or the Transform inspector, in which cases Unity already automatically registers the Undo entry.
if (Get_bezierSubPoint_thatHasReferencedThisGameobject().isUsed)
{
if (false == UtilitiesDXXL_Math.CheckIf_twoVectorsAreExactlyEqual((Vector2)transform.position, Get_bezierSubPoint_thatHasReferencedThisGameobject().GetPos_inUnitsOfGlobalSpace()))
{
//Note: A position change of this bound gameobject has never effect on the direction of the control sub point, so this will not "come back via forwarding to dependent sub points" and set this gameobjects rotation.
Transfer_position_fromBoundGameobject_toSpline();
}
}
if (subPointType_whereThisGameobjectIsBoundTo == InternalDXXL_BezierControlSubPoint.SubPointType.anchor)
{
if (Get_bezierSubPoint_thatHasReferencedThisGameobject().Get_sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked() != InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.independentFromGameobject)
{
//-> only anchor points can arrive here, but no helper points
//-> anchor points cannot be unused (meaning "isUsed == true" is guarateed here)
if (false == UtilitiesDXXL_Math.CheckIf_twoQuaternionsAreExactlyEqual(transform.rotation, lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf))
{
//Note: A rotation change of this bound gameobject has never effect on the position of the control sub point, so this will not "come back via forwarding to dependent sub points" and set this gameobjects position.
Transfer_aTransformDirection_fromBoundGameobject_toSpline();
}
}
}
}
InternalDXXL_BezierControlSubPoint2D Get_bezierSubPoint_thatHasReferencedThisGameobject()
{
//Serialized lists containing other lists and containing custom classes with cross references don't work well in Unity, even when using the [SerializeReference] attribute. Functions like this try to keep the convenience of a real reference tree. The only "real" reference is the monobehavior-inherited spline component. Everything has to start from there.
if (bezierSplineDrawer_thatHasReferencedThisGameobject != null)
{
if (i_ofControlPointTriplet_thisGameobjectIsBoundTo < bezierSplineDrawer_thatHasReferencedThisGameobject.listOfControlPointTriplets.Count)
{
return bezierSplineDrawer_thatHasReferencedThisGameobject.listOfControlPointTriplets[i_ofControlPointTriplet_thisGameobjectIsBoundTo].GetASubPoint(subPointType_whereThisGameobjectIsBoundTo);
}
else
{
return null;
}
}
else
{
return null;
}
}
public void Transfer_position_fromBoundGameobject_toSpline()
{
if (CheckIf_thisConnectionComponentIsActive())
{
Get_bezierSubPoint_thatHasReferencedThisGameobject().SetPos_inUnitsOfGlobalSpace(transform.position, true, this.gameObject);
}
}
public void Transfer_aTransformDirection_fromBoundGameobject_toSpline()
{
if (CheckIf_thisConnectionComponentIsActive())
{
if (subPointType_whereThisGameobjectIsBoundTo != InternalDXXL_BezierControlSubPoint.SubPointType.anchor)
{
UtilitiesDXXL_Log.PrintErrorCode("69");
}
InternalDXXL_BezierControlSubPoint2D anchorPoint = Get_bezierSubPoint_thatHasReferencedThisGameobject(); //-> only for code readability
if (anchorPoint.GetJunctureType() == InternalDXXL_BezierControlAnchorSubPoint.JunctureType.kinked)
{
if (anchorPoint.GetBackwardHelper().isUsed == true)
{
if (anchorPoint.GetBackwardHelper().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture != InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.independentFromGameobject)
{
Vector2 newDirection_toBackwardHelper_inUnitsOfGlobalSpace_normalized = GetDirectionNormalizedFromRotation(anchorPoint.GetBackwardHelper().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture);
anchorPoint.Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(newDirection_toBackwardHelper_inUnitsOfGlobalSpace_normalized, true, this.gameObject);
lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf = transform.rotation;
}
}
if (anchorPoint.GetForwardHelper().isUsed == true)
{
if (anchorPoint.GetForwardHelper().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture != InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.independentFromGameobject)
{
Vector2 newDirection_toForwardHelper_inUnitsOfGlobalSpace_normalized = GetDirectionNormalizedFromRotation(anchorPoint.GetForwardHelper().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture);
anchorPoint.Set_direction_toForward_inUnitsOfGlobalSpace_normalized(newDirection_toForwardHelper_inUnitsOfGlobalSpace_normalized, true, this.gameObject);
lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf = transform.rotation;
}
}
}
else
{
if (anchorPoint.Get_sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked() != InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.independentFromGameobject)
{
Vector2 newDirection_toForwardHelper_inUnitsOfGlobalSpace_normalized = GetDirectionNormalizedFromRotation(anchorPoint.Get_sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked());
anchorPoint.Set_direction_toForward_inUnitsOfGlobalSpace_normalized(newDirection_toForwardHelper_inUnitsOfGlobalSpace_normalized, true, this.gameObject);
lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf = transform.rotation;
}
}
}
}
Vector2 GetDirectionNormalizedFromRotation(InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D directionSource)
{
switch (directionSource)
{
case InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.independentFromGameobject:
UtilitiesDXXL_Log.PrintErrorCode("58");
return Vector2.right;
case InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.gameobjectsUp:
return ConvertDirectionV3_toDirectionV2Normalized(transform.up);
case InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.gameobjectsRight:
return ConvertDirectionV3_toDirectionV2Normalized(transform.right);
case InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.gameobjectsDown:
return ConvertDirectionV3_toDirectionV2Normalized(-transform.up);
case InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.gameobjectsLeft:
return ConvertDirectionV3_toDirectionV2Normalized(-transform.right);
default:
UtilitiesDXXL_Log.PrintErrorCode("59");
return Vector2.right;
}
}
Vector2 ConvertDirectionV3_toDirectionV2Normalized(Vector3 directionV3_toConvert)
{
Vector2 direction_projectedPerpOntoXYPlane = UtilitiesDXXL_DrawBasics2D.xyPlane_throughZero.Get_projectionOfVectorOntoPlane(directionV3_toConvert);
Vector2 direction_projectedPerpOntoXYPlane_normalized = UtilitiesDXXL_Math.GetNormalized_afterScalingIntoRegionOfFloatPrecicion(direction_projectedPerpOntoXYPlane);
if (UtilitiesDXXL_Math.CheckIfNormalizationFailed_meaningLineStayedTooShort(direction_projectedPerpOntoXYPlane_normalized))
{
return Vector2.right;
}
else
{
return direction_projectedPerpOntoXYPlane_normalized;
}
}
public void Transfer_newDirectionToAHelperPointInUnitsOfGlobalSpaceNormalized_fromSpline_toBoundGameobject(Vector2 newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized, InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D directionSource_thatTheNewDirectionDescribes, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
if (CheckIf_thisConnectionComponentIsActive())
{
if (subPointType_whereThisGameobjectIsBoundTo != InternalDXXL_BezierControlSubPoint.SubPointType.anchor)
{
UtilitiesDXXL_Log.PrintErrorCode("70");
}
if (this.gameObject != boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls) //-> this should prevent "continuous slow drifting of the values". The values the get set here could otherwise be converted somehow in the sub points and then be written back to the transform of this gameobject. The therewith calculated value can be slightly different (due to float calculation imprecision).
{
switch (directionSource_thatTheNewDirectionDescribes)
{
case InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.independentFromGameobject:
UtilitiesDXXL_Log.PrintErrorCode("60");
break;
case InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.gameobjectsUp:
AssignNewTransformUp(newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized);
break;
case InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.gameobjectsRight:
AssignNewTransformRight(newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized);
break;
case InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.gameobjectsDown:
AssignNewTransformUp(-newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized);
break;
case InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.gameobjectsLeft:
AssignNewTransformRight(-newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized);
break;
default:
break;
}
lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf = transform.rotation;
}
}
}
void AssignNewTransformUp(Vector2 newUp_normalized_insideXYPlane)
{
Vector3 newUp_normalized_insideXYPlane_asV3 = UtilitiesDXXL_DrawBasics2D.Direction_V2toV3(newUp_normalized_insideXYPlane);
Vector3 oldUpOfTransform_projectedOntoXYPlane = UtilitiesDXXL_DrawBasics2D.xyPlane_throughZero.Get_projectionOfVectorOntoPlane(transform.up);
Vector3 oldUpOfTransform_projectedOntoXYPlane_normalized = UtilitiesDXXL_Math.GetNormalized_afterScalingIntoRegionOfFloatPrecicion(oldUpOfTransform_projectedOntoXYPlane);
if (UtilitiesDXXL_Math.CheckIfNormalizationFailed_meaningLineStayedTooShort(oldUpOfTransform_projectedOntoXYPlane_normalized) == false)
{
Quaternion rotationIncrement = Quaternion.FromToRotation(oldUpOfTransform_projectedOntoXYPlane_normalized, newUp_normalized_insideXYPlane_asV3);
transform.rotation = rotationIncrement * transform.rotation;
}
}
void AssignNewTransformRight(Vector2 newRight_normalized_insideXYPlane)
{
Vector3 newRight_normalized_insideXYPlane_asV3 = UtilitiesDXXL_DrawBasics2D.Direction_V2toV3(newRight_normalized_insideXYPlane);
Vector3 oldRightOfTransform_projectedOntoXYPlane = UtilitiesDXXL_DrawBasics2D.xyPlane_throughZero.Get_projectionOfVectorOntoPlane(transform.right);
Vector3 oldRightOfTransform_projectedOntoXYPlane_normalized = UtilitiesDXXL_Math.GetNormalized_afterScalingIntoRegionOfFloatPrecicion(oldRightOfTransform_projectedOntoXYPlane);
if (UtilitiesDXXL_Math.CheckIfNormalizationFailed_meaningLineStayedTooShort(oldRightOfTransform_projectedOntoXYPlane_normalized) == false)
{
Quaternion rotationIncrement = Quaternion.FromToRotation(oldRightOfTransform_projectedOntoXYPlane_normalized, newRight_normalized_insideXYPlane_asV3);
transform.rotation = rotationIncrement * transform.rotation;
}
}
bool TryDestroyThisComponentIfItWasManuallyCreated()
{
if (componentHasBeenManuallyCreated)
{
Debug.LogError("'DrawXXLSpline2DConnection' should not be created manually. It will be automatically created and destroyed by the 'Bezier Spline Drawer 2D' component.");
DestroyThisComponent(false);
return true;
}
else
{
return false;
}
}
bool TryEarlyReturnAndSelfDeleteBecauseReferenceGotLost()
{
if (bezierSplineDrawer_thatHasReferencedThisGameobject == null)
{
//-> "bezierSplineDrawer_thatHasReferencedThisGameobject" has been deleted
//-> actually this component could also be deleted now, but the problem is: If the deletion of "bezierSplineDrawer_thatHasReferencedThisGameobject" is reverted via the editors "Undo"-functionality, then the retrieved bezierSplineDrawer doesn't have this spline connection anymore and the "undo" is not complete in this regard.
//-> see also more detialled explantation in "subPoint.SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled()"
//-> The connection component here stays inactive as long as it doesn't have a "bezierSplineDrawer_thatHasReferencedThisGameobject"
DestroyThisComponent(false);
return true;
}
else
{
InternalDXXL_BezierControlSubPoint2D bezierSubPoint = Get_bezierSubPoint_thatHasReferencedThisGameobject();
if (bezierSubPoint == null)
{
UtilitiesDXXL_Log.PrintErrorCode("76-" + bezierSplineDrawer_thatHasReferencedThisGameobject.listOfControlPointTriplets.Count + "-" + i_ofControlPointTriplet_thisGameobjectIsBoundTo);
DestroyThisComponent(false);
return true;
}
else
{
if (bezierSubPoint.bezierSplineDrawer_thisSubPointIsPartOf != bezierSplineDrawer_thatHasReferencedThisGameobject)
{
UtilitiesDXXL_Log.PrintErrorCode("77-" + bezierSubPoint.bezierSplineDrawer_thisSubPointIsPartOf + "-" + bezierSplineDrawer_thatHasReferencedThisGameobject);
DestroyThisComponent(false);
return true;
}
else
{
if (bezierSubPoint.boundGameobject != this.gameObject)
{
//-> case 1: the gameobject that carries this connection-component has been copied.
//-> case 2: connection-component has been manually copied to another gameobject
//-> the connection gets deleted here. It stays only at the pre-copy-gameobject
//-> case 3: some "copy spline component -> undo -> redo" to-and-fro arrives here, see also
//-> see also more detialled explantation in "subPoint.SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled()"
DestroyThisComponent(false);
return true;
}
else
{
//The following "if (bezierSubPoint.connectionComponent_onBoundGameobject != this)"-check gives false evaluations in some cases.
//Observed case:
//-> Add boundGamobject(this) to a spline control point.
//-> Then delete the bound gameobject.
//-> Then the deletion via the editors "undo"-functionality.
//-> Then "bezierSubPoint.connectionComponent_onBoundGameobject" is "null" (probably due to the Unity bug, see explanation in "subPoint.SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled()"
//-> Despite "bezierSubPoint.connectionComponent_onBoundGameobject" beeing "null" and "this" not beeing "null" the check "if (bezierSubPoint.connectionComponent_onBoundGameobject != this)" results in "is the same".
//-> It has probably to do with Unitys way of serialization and undo
if (bezierSubPoint.connectionComponent_onBoundGameobject != this)
{
//-> this connection component has been manually copied as duplicate to the same gameobject
//-> some delete/undo/redo-to and fro may also arrive here
DestroyThisComponent(false);
return true;
}
else
{
if (bezierSubPoint.connectionComponent_onBoundGameobject == null) //-> additional check as double bottom that fixes the comparison error described above
{
DestroyThisComponent(false);
return true;
}
else
{
if (bezierSubPoint.i_ofContainingControlPoint_insideControlPointsList != i_ofControlPointTriplet_thisGameobjectIsBoundTo)
{
UtilitiesDXXL_Log.PrintErrorCode("78-" + bezierSplineDrawer_thatHasReferencedThisGameobject.listOfControlPointTriplets.Count + "-" + i_ofControlPointTriplet_thisGameobjectIsBoundTo + "-" + bezierSubPoint.i_ofContainingControlPoint_insideControlPointsList);
DestroyThisComponent(false);
return true;
}
else
{
if (bezierSubPoint.subPointType != subPointType_whereThisGameobjectIsBoundTo)
{
UtilitiesDXXL_Log.PrintErrorCode("79-" + bezierSplineDrawer_thatHasReferencedThisGameobject.listOfControlPointTriplets.Count + "-" + i_ofControlPointTriplet_thisGameobjectIsBoundTo + "-" + bezierSubPoint.subPointType + "-" + subPointType_whereThisGameobjectIsBoundTo);
DestroyThisComponent(false);
return true;
}
else
{
return false;
}
}
}
}
}
}
}
}
}
void DestroyThisComponent(bool withDestructionUndo)
{
//Destroying only the component, but keeping the gameObject and all other components:
if (Application.isPlaying)
{
Destroy(this);
}
else
{
if (withDestructionUndo)
{
#if UNITY_EDITOR
UnityEditor.Undo.DestroyObjectImmediate(this);
#else
//How can the code arrive here?
UtilitiesDXXL_Log.PrintErrorCode("84-"+ Application.isPlaying);
Destroy(this);
#endif
}
else
{
DestroyImmediate(this);
}
}
}
bool CheckIf_thisConnectionComponentIsActive()
{
if (bezierSplineDrawer_thatHasReferencedThisGameobject != null) //this is only due to the undo-mechanic-selfDestruction-delay
{
return isActiveAndEnabled;
}
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5a3859fc5b45a9a46a4ebb2fd6f7ba14
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,377 @@
namespace DrawXXL
{
using UnityEngine;
[HelpURL("https://www.symphonygames.net/drawxxldocumentation/index.html")]
[AddComponentMenu("Xeric Library/DebugDrawLibrary/Internal Not For Manual Creation/Draw XXL Spline Connection")]
[ExecuteInEditMode]
public class DrawXXLSplineConnection : MonoBehaviour
{
Quaternion lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf; //-> other than the position the spline control points don't save a "rotation" but only a "direction", so there is an extra member to care for the synchronisation here
public BezierSplineDrawer bezierSplineDrawer_thatHasReferencedThisGameobject;
//public InternalDXXL_BezierControlSubPoint bezierSubPoint_thatHasReferencedThisGameobject; //this is not suitable as reference, because in the serialized context "InternalDXXL_BezierControlSubPoint" acts as value type, not as reference type.
public bool componentHasBeenManuallyCreated = true;
public int i_ofControlPointTriplet_thisGameobjectIsBoundTo;
public InternalDXXL_BezierControlSubPoint.SubPointType subPointType_whereThisGameobjectIsBoundTo;
void OnDestroy()
{
//-> calling "Undo.RegisterCompleteObjectUndo(bezierSplineDrawer_thatHasReferencedThisGameobject, "undoName")" also doesn't solve the bug, that the connectionReference cannot be restored via "Editor/Undo" after this connection component has been deleted. But it at least prevents the bool-comparison-error described in "TryEarlyReturnAndSelfDeleteBecauseReferenceGotLost()". Though this error can also be prevented with an additional bool-check.
//-> Moreover calling "Undo.RegisterCompleteObjectUndo(bezierSplineDrawer_thatHasReferencedThisGameobject, "undoName")" may lead to confusting undo states, because this connection component gets destroyed (and therewith this "OnDestroy()" here gets called) not only when the user deletes it (or the carrying boundGameobject), but also when the spline component gets destroyed (specifically this connection component is destroyed inside "OnDestroy()" of the spline component). So the spline most likely already has an "Undo.DestroyImmediate()" registered for itself through the spline deletion the was triggerd by manual control in the Editor. Then it would be saved into the undo state once more here. That seems to risky since the undo system can have obscure errors when used in such hacky ways, which can even crash the Unity Editor.
}
void Update()
{
if (TryDestroyThisComponentIfItWasManuallyCreated()) { return; }
if (TryEarlyReturnAndSelfDeleteBecauseReferenceGotLost()) { return; }
//No "register undo for spline" is done here before changed transform values get written to the spline:
//-> It is unclear how this gameobject changed it's transform. Has the "changer" already filed an "Undo" or should it be filed here? If it has already been filed is it harmful when it is filed twice into the undo state?
//-> It is not necessary: since the transform of this boundGameobject is authoritative for the spline shape, the spline shape will follow the undo as soon as the transform is reverted via an Undo.
//-> So the changer of this transform is responsible for caring for the undo entry registration. In most cases the transform will be changed via the Scene view handles or the Transform inspector, in which cases Unity already automatically registers the Undo entry.
if (Get_bezierSubPoint_thatHasReferencedThisGameobject().isUsed)
{
if (false == UtilitiesDXXL_Math.CheckIf_twoVectorsAreExactlyEqual(transform.position, Get_bezierSubPoint_thatHasReferencedThisGameobject().GetPos_inUnitsOfGlobalSpace()))
{
//Note: A position change of this bound gameobject has never effect on the direction of the control sub point, so this will not "come back via forwarding to dependent sub points" and set this gameobjects rotation.
Transfer_position_fromBoundGameobject_toSpline();
}
}
if (subPointType_whereThisGameobjectIsBoundTo == InternalDXXL_BezierControlSubPoint.SubPointType.anchor)
{
if (Get_bezierSubPoint_thatHasReferencedThisGameobject().Get_sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked() != InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.independentFromGameobject)
{
//-> only anchor points can arrive here, but no helper points
//-> anchor points cannot be unused (meaning "isUsed == true" is guarateed here)
if (false == UtilitiesDXXL_Math.CheckIf_twoQuaternionsAreExactlyEqual(transform.rotation, lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf))
{
//Note: A rotation change of this bound gameobject has never effect on the position of the control sub point, so this will not "come back via forwarding to dependent sub points" and set this gameobjects position.
Transfer_aTransformDirection_fromBoundGameobject_toSpline();
}
}
}
}
InternalDXXL_BezierControlSubPoint Get_bezierSubPoint_thatHasReferencedThisGameobject()
{
//Serialized lists containing other lists and containing custom classes with cross references don't work well in Unity, even when using the [SerializeReference] attribute. Functions like this try to keep the convenience of a real reference tree. The only "real" reference is the monobehavior-inherited spline component. Everything has to start from there.
if (bezierSplineDrawer_thatHasReferencedThisGameobject != null)
{
if (i_ofControlPointTriplet_thisGameobjectIsBoundTo < bezierSplineDrawer_thatHasReferencedThisGameobject.listOfControlPointTriplets.Count)
{
return bezierSplineDrawer_thatHasReferencedThisGameobject.listOfControlPointTriplets[i_ofControlPointTriplet_thisGameobjectIsBoundTo].GetASubPoint(subPointType_whereThisGameobjectIsBoundTo);
}
else
{
return null;
}
}
else
{
return null;
}
}
public void Transfer_position_fromBoundGameobject_toSpline()
{
if (CheckIf_thisConnectionComponentIsActive())
{
Get_bezierSubPoint_thatHasReferencedThisGameobject().SetPos_inUnitsOfGlobalSpace(transform.position, true, this.gameObject);
}
}
public void Transfer_aTransformDirection_fromBoundGameobject_toSpline()
{
if (CheckIf_thisConnectionComponentIsActive())
{
if (subPointType_whereThisGameobjectIsBoundTo != InternalDXXL_BezierControlSubPoint.SubPointType.anchor)
{
UtilitiesDXXL_Log.PrintErrorCode("45");
}
InternalDXXL_BezierControlSubPoint anchorPoint = Get_bezierSubPoint_thatHasReferencedThisGameobject(); //-> only for code readability
if (anchorPoint.GetJunctureType() == InternalDXXL_BezierControlAnchorSubPoint.JunctureType.kinked)
{
if (anchorPoint.GetBackwardHelper().isUsed == true)
{
if (anchorPoint.GetBackwardHelper().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture != InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.independentFromGameobject)
{
Vector3 newDirection_toBackwardHelper_inUnitsOfGlobalSpace_normalized = GetDirectionFromRotation(anchorPoint.GetBackwardHelper().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture);
anchorPoint.Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(newDirection_toBackwardHelper_inUnitsOfGlobalSpace_normalized, true, this.gameObject);
lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf = transform.rotation;
}
}
if (anchorPoint.GetForwardHelper().isUsed == true)
{
if (anchorPoint.GetForwardHelper().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture != InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.independentFromGameobject)
{
Vector3 newDirection_toForwardHelper_inUnitsOfGlobalSpace_normalized = GetDirectionFromRotation(anchorPoint.GetForwardHelper().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture);
anchorPoint.Set_direction_toForward_inUnitsOfGlobalSpace_normalized(newDirection_toForwardHelper_inUnitsOfGlobalSpace_normalized, true, this.gameObject);
lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf = transform.rotation;
}
}
}
else
{
if (anchorPoint.Get_sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked() != InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.independentFromGameobject)
{
Vector3 newDirection_toForwardHelper_inUnitsOfGlobalSpace_normalized = GetDirectionFromRotation(anchorPoint.Get_sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked());
anchorPoint.Set_direction_toForward_inUnitsOfGlobalSpace_normalized(newDirection_toForwardHelper_inUnitsOfGlobalSpace_normalized, true, this.gameObject);
lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf = transform.rotation;
}
}
}
}
Vector3 GetDirectionFromRotation(InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper directionSource)
{
switch (directionSource)
{
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.independentFromGameobject:
UtilitiesDXXL_Log.PrintErrorCode("34");
return Vector3.forward;
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsForward:
return transform.forward;
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsUp:
return transform.up;
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsRight:
return transform.right;
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsBack:
return (-transform.forward);
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsDown:
return (-transform.up);
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsLeft:
return (-transform.right);
default:
UtilitiesDXXL_Log.PrintErrorCode("35");
return Vector3.forward;
}
}
public void Transfer_newDirectionToAHelperPointInUnitsOfGlobalSpaceNormalized_fromSpline_toBoundGameobject(Vector3 newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized, InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper directionSource_thatTheNewDirectionDescribes, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
if (CheckIf_thisConnectionComponentIsActive())
{
if (subPointType_whereThisGameobjectIsBoundTo != InternalDXXL_BezierControlSubPoint.SubPointType.anchor)
{
UtilitiesDXXL_Log.PrintErrorCode("46");
}
if (this.gameObject != boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls) //-> this should prevent "continuous slow drifting of the values". The values the get set here could otherwise be converted somehow in the sub points and then be written back to the transform of this gameobject. The therewith calculated value can be slightly different (due to float calculation imprecision).
{
Quaternion newRotation;
switch (directionSource_thatTheNewDirectionDescribes)
{
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.independentFromGameobject:
UtilitiesDXXL_Log.PrintErrorCode("36");
break;
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsForward:
newRotation = Quaternion.LookRotation(newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized, transform.up);
transform.rotation = newRotation;
break;
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsUp:
AssignNewTransformUp(newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized);
break;
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsRight:
AssignNewTransformRight(newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized);
break;
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsBack:
newRotation = Quaternion.LookRotation(-newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized, transform.up);
transform.rotation = newRotation;
break;
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsDown:
AssignNewTransformUp(-newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized);
break;
case InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.gameobjectsLeft:
AssignNewTransformRight(-newDirection_toAHelperPoint_inUnitsOfGlobalSpace_normalized);
break;
default:
break;
}
lastGlobalRotationOfThisGameobject_thatTheSplineKnowsOf = transform.rotation;
}
}
}
void AssignNewTransformUp(Vector3 newUp_normalized)
{
Vector3 newForward = UtilitiesDXXL_Math.Get_vector_projectedAlongOtherVectorToPerpToOtherVector(transform.forward, newUp_normalized, false);
newForward = UtilitiesDXXL_Math.ScaleNonZeroVectorIntoRegionOfFloatPrecision(newForward);
if (UtilitiesDXXL_Math.GetBiggestAbsComponent(newForward) > 0.0001f)
{
Quaternion newRotation = Quaternion.LookRotation(newForward, newUp_normalized);
transform.rotation = newRotation;
}
else
{
transform.up = newUp_normalized;
}
}
void AssignNewTransformRight(Vector3 newRight_normalized)
{
Vector3 newForward = UtilitiesDXXL_Math.Get_vector_projectedAlongOtherVectorToPerpToOtherVector(transform.forward, newRight_normalized, false);
newForward = UtilitiesDXXL_Math.ScaleNonZeroVectorIntoRegionOfFloatPrecision(newForward);
if (UtilitiesDXXL_Math.GetBiggestAbsComponent(newForward) > 0.0001f)
{
Vector3 newUp = Vector3.Cross(newForward, newRight_normalized);
Quaternion newRotation = Quaternion.LookRotation(newForward, newUp);
transform.rotation = newRotation;
}
else
{
transform.right = newRight_normalized;
}
}
bool TryDestroyThisComponentIfItWasManuallyCreated()
{
if (componentHasBeenManuallyCreated)
{
Debug.LogError("'DrawXXLSplineConnection' should not be created manually. It will be automatically created and destroyed by the 'Bezier Spline Drawer' component.");
DestroyThisComponent(false);
return true;
}
else
{
return false;
}
}
bool TryEarlyReturnAndSelfDeleteBecauseReferenceGotLost()
{
if (bezierSplineDrawer_thatHasReferencedThisGameobject == null)
{
//-> "bezierSplineDrawer_thatHasReferencedThisGameobject" has been deleted
//-> actually this component could also be deleted now, but the problem is: If the deletion of "bezierSplineDrawer_thatHasReferencedThisGameobject" is reverted via the editors "Undo"-functionality, then the retrieved bezierSplineDrawer doesn't have this spline connection anymore and the "undo" is not complete in this regard.
//-> see also more detialled explantation in "subPoint.SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled()"
//-> The connection component here stays inactive as long as it doesn't have a "bezierSplineDrawer_thatHasReferencedThisGameobject"
DestroyThisComponent(false);
return true;
}
else
{
InternalDXXL_BezierControlSubPoint bezierSubPoint = Get_bezierSubPoint_thatHasReferencedThisGameobject();
if (bezierSubPoint == null)
{
UtilitiesDXXL_Log.PrintErrorCode("52-" + bezierSplineDrawer_thatHasReferencedThisGameobject.listOfControlPointTriplets.Count + "-" + i_ofControlPointTriplet_thisGameobjectIsBoundTo);
DestroyThisComponent(false);
return true;
}
else
{
if (bezierSubPoint.bezierSplineDrawer_thisSubPointIsPartOf != bezierSplineDrawer_thatHasReferencedThisGameobject)
{
UtilitiesDXXL_Log.PrintErrorCode("53-" + bezierSubPoint.bezierSplineDrawer_thisSubPointIsPartOf + "-" + bezierSplineDrawer_thatHasReferencedThisGameobject);
DestroyThisComponent(false);
return true;
}
else
{
if (bezierSubPoint.boundGameobject != this.gameObject)
{
//-> case 1: the gameobject that carries this connection-component has been copied.
//-> case 2: connection-component has been manually copied to another gameobject
//-> the connection gets deleted here. It stays only at the pre-copy-gameobject
//-> case 3: some "copy spline component -> undo -> redo" to-and-fro arrives here, see also
//-> see also more detialled explantation in "subPoint.SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled()"
DestroyThisComponent(false);
return true;
}
else
{
//The following "if (bezierSubPoint.connectionComponent_onBoundGameobject != this)"-check gives false evaluations in some cases.
//Observed case:
//-> Add boundGamobject(this) to a spline control point.
//-> Then delete the bound gameobject.
//-> Then the deletion via the editors "undo"-functionality.
//-> Then "bezierSubPoint.connectionComponent_onBoundGameobject" is "null" (probably due to the Unity bug, see explanation in "subPoint.SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled()"
//-> Despite "bezierSubPoint.connectionComponent_onBoundGameobject" beeing "null" and "this" not beeing "null" the check "if (bezierSubPoint.connectionComponent_onBoundGameobject != this)" results in "is the same".
//-> It has probably to do with Unitys way of serialization and undo
if (bezierSubPoint.connectionComponent_onBoundGameobject != this)
{
//-> this connection component has been manually copied as duplicate to the same gameobject
//-> some delete/undo/redo-to and fro may also arrive here
DestroyThisComponent(false);
return true;
}
else
{
if (bezierSubPoint.connectionComponent_onBoundGameobject == null) //-> additional check as double bottom that fixes the comparison error described above
{
DestroyThisComponent(false);
return true;
}
else
{
if (bezierSubPoint.i_ofContainingControlPoint_insideControlPointsList != i_ofControlPointTriplet_thisGameobjectIsBoundTo)
{
UtilitiesDXXL_Log.PrintErrorCode("54-" + bezierSplineDrawer_thatHasReferencedThisGameobject.listOfControlPointTriplets.Count + "-" + i_ofControlPointTriplet_thisGameobjectIsBoundTo + "-" + bezierSubPoint.i_ofContainingControlPoint_insideControlPointsList);
DestroyThisComponent(false);
return true;
}
else
{
if (bezierSubPoint.subPointType != subPointType_whereThisGameobjectIsBoundTo)
{
UtilitiesDXXL_Log.PrintErrorCode("55-" + bezierSplineDrawer_thatHasReferencedThisGameobject.listOfControlPointTriplets.Count + "-" + i_ofControlPointTriplet_thisGameobjectIsBoundTo + "-" + bezierSubPoint.subPointType + "-" + subPointType_whereThisGameobjectIsBoundTo);
DestroyThisComponent(false);
return true;
}
else
{
return false;
}
}
}
}
}
}
}
}
}
void DestroyThisComponent(bool withDestructionUndo)
{
//Destroying only the component, but keeping the gameObject and all other components:
if (Application.isPlaying)
{
Destroy(this);
}
else
{
if (withDestructionUndo)
{
#if UNITY_EDITOR
UnityEditor.Undo.DestroyObjectImmediate(this);
#else
//How can the code arrive here?
UtilitiesDXXL_Log.PrintErrorCode("83-"+ Application.isPlaying);
Destroy(this);
#endif
}
else
{
DestroyImmediate(this);
}
}
}
bool CheckIf_thisConnectionComponentIsActive()
{
if (bezierSplineDrawer_thatHasReferencedThisGameobject != null) //this is only due to the undo-mechanic-selfDestruction-delay
{
return isActiveAndEnabled;
}
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 166f076e426504e47a75ca709be57ce8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 410bf39d2f8b8a543b01a7f40cf65b22
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 43995da0c5deada479d25647709b2854
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,628 @@
namespace DrawXXL
{
using System;
using UnityEngine;
[Serializable]
public class InternalDXXL_BezierControlAnchorSubPoint : InternalDXXL_BezierControlSubPoint
{
public enum JunctureType { kinked, aligned, mirrored };
[SerializeField] public JunctureType junctureType;
public enum SourceOf_directionToHelper { independentFromGameobject, gameobjectsForward, gameobjectsUp, gameobjectsRight, gameobjectsBack, gameobjectsDown, gameobjectsLeft };
public enum SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers { directionFromPointCenterToThisWeightIsIndependentFromTheRotationOfTheGameobjectThatIsBoundToTheCenterPosition, directionFromPointCenterToThisWeightIsTheForwardDirectionOfTheGameobjectThatIsBoundToTheCenterPosition, directionFromPointCenterToThisWeightIsTheUpDirectionOfTheGameobjectThatIsBoundToTheCenterPosition, directionFromPointCenterToThisWeightIsTheRightDirectionOfTheGameobjectThatIsBoundToTheCenterPosition, directionFromPointCenterToThisWeightIsTheBackDirectionOfTheGameobjectThatIsBoundToTheCenterPosition, directionFromPointCenterToThisWeightIsTheDownDirectionOfTheGameobjectThatIsBoundToTheCenterPosition, directionFromPointCenterToThisWeightIsTheLeftDirectionOfTheGameobjectThatIsBoundToTheCenterPosition };
[SerializeField] public SourceOf_directionToHelper sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked; //-> is only used when a "boundGameobject" is assigned
public int controlID_ofCustomHandles_sphere;
public int controlID_ofCustomHandles_forwardCone;
public int controlID_ofCustomHandles_backwardCone;
public Quaternion rotation_ofRotationHandle_thatIsIndependentFromSplineDir_butDefinedByDrawSpaceOrientation;
public Quaternion rotation_ofRotationHandleDuringRotationDragPhases;
public bool recalc_rotation_ofRotationHandleDuringRotationDragPhases_duringNextOnSceneGUI = true;
public Vector3 directionForHandles_forwardCone_inUnitsOfGlobalSpace_normalized = Vector3.forward;
public Vector3 directionForHandles_backwardCone_inUnitsOfGlobalSpace_normalized = Vector3.back;
public bool recalc_directionForHandles_forwardCone_duringNextOnSceneGUI = true;
public bool recalc_directionForHandles_backwardCone_duringNextOnSceneGUI = true;
public override void InitializeValuesThatAreIndependentFromOtherSubPoints(InternalDXXL_BezierControlPointTriplet controlPoint_thisSubPointIsPartOf)
{
base.InitializeValuesThatAreIndependentFromOtherSubPoints(controlPoint_thisSubPointIsPartOf);
sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked = SourceOf_directionToHelper.independentFromGameobject;
}
public InternalDXXL_BezierControlHelperSubPoint GetForwardHelperPoint()
{
//Serialized lists containing other lists and containing custom classes with cross references don't work well in Unity, even when using the [SerializeReference] attribute. Functions like this try to keep the convenience of a real reference tree. The only "real" reference is the monobehavior-inherited spline component. Everything has to start from there.
return bezierSplineDrawer_thisSubPointIsPartOf.listOfControlPointTriplets[i_ofContainingControlPoint_insideControlPointsList].forwardHelperPoint;
}
public InternalDXXL_BezierControlHelperSubPoint GetBackwardHelperPoint()
{
//Serialized lists containing other lists and containing custom classes with cross references don't work well in Unity, even when using the [SerializeReference] attribute. Functions like this try to keep the convenience of a real reference tree. The only "real" reference is the monobehavior-inherited spline component. Everything has to start from there.
return bezierSplineDrawer_thisSubPointIsPartOf.listOfControlPointTriplets[i_ofContainingControlPoint_insideControlPointsList].backwardHelperPoint;
}
public override void ResetDirectionSourceToIndependent()
{
sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked = SourceOf_directionToHelper.independentFromGameobject;
}
public override void TryTransferBoundGameobjectsRotationToAnchorPointsDirection()
{
//-> during no-gameobject-assigned-phases the "sourceOf_direction*'s" are forced to "independentFromGameobject", so here only cases where the assignment changed from one gameobject to another gameobject cause an action inside "connectionComponent_onBoundGameobject.Transfer_aTransformDirection_fromBoundGameobject_toSpline()":
connectionComponent_onBoundGameobject.Transfer_aTransformDirection_fromBoundGameobject_toSpline();
}
public void ProcessChanging_sourceOfDirectionToHelper(SourceOf_directionToHelper newSourceOfDirection)
{
if (newSourceOfDirection != sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked)
{
sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked = newSourceOfDirection;
if (newSourceOfDirection != SourceOf_directionToHelper.independentFromGameobject)
{
TryTransfer_newTransformDirection_fromBoundGameobject_toSpline_afterDirectionSourceChange();
}
}
}
public void TryTransfer_newTransformDirection_fromBoundGameobject_toSpline_afterDirectionSourceChange()
{
SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled();
if (boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled)
{
connectionComponent_onBoundGameobject.Transfer_aTransformDirection_fromBoundGameobject_toSpline();
}
}
public void SetJunctureType(JunctureType newJunctureType)
{
if (newJunctureType != junctureType)
{
JunctureType oldJunctureType = junctureType;
junctureType = newJunctureType;
if (oldJunctureType == JunctureType.kinked)
{
TrySwitchBothHelpersTo_isUsed();
//<- if at least one helperPoint was unused before, then the helperPoints are now already cleanly converted to the new juncture type (meaning: they are now "both used", "parallel", "same absDistance from anchor" and "on differnt sides of the anchor")
//-> if both helperPoints were already used before, then the above didn't have any effect, and the following "forcing to parallel/sameAbsDistance" (inside the "newJuncture == nonKinked"-threads) finishes the conversion. This "forcing to parallel/sameAbsDistance" doesn't harm if the two helpers are already "parallel/sameAbsDistance".
}
if (newJunctureType == JunctureType.kinked)
{
//this "set isUsed-states" is actually only needed for "change AWAY from kinked", and then during non-kinked-phases the isUsed-state will anyway not change so it will arrive at the next "change TO kinked" still with "all are used". But in order to not having to care what happens in non-kinked-phases and still being sure that kinked-phases always start with "all are used" it is explicitly called here. Besides that it may act as double bottom if the states still get confused somehow.
TrySwitchBothHelpersTo_isUsed();
}
if (newJunctureType == JunctureType.aligned)
{
MirrorDirection_from_toForward_to_toBackward();
Get_controlPointTriplet_thisSubPointIsPartOf().alignedHelperPoints_areOnTheSameSideOfTheAnchor = false; //-> this field is only used by "aligned" anchorPoints
}
if (newJunctureType == JunctureType.mirrored)
{
MirrorDirection_from_toForward_to_toBackward();
MirrorDistance_from_toForward_to_toBackward();
}
}
}
void TrySwitchBothHelpersTo_isUsed()
{
//the order of the helperPointActivation here only matters for cases where BOTH helperPoints have been unused during the kinked-phase and are now set to used, because a non-kinked juncture-phase follows. The first activated helperPoint then dictates the shape of the second activated helperPoint. Therefore "forward" comes first.
if (false == GetForwardHelperPoint().IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
GetForwardHelperPoint().ChangeUsedState(true, false);
}
if (false == GetBackwardHelperPoint().IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
GetBackwardHelperPoint().ChangeUsedState(true, false);
}
}
void MirrorDirection_from_toForward_to_toBackward()
{
GetBackwardHelperPoint().Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(-GetForwardHelperPoint().Get_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(), true, null);
}
void MirrorDistance_from_toForward_to_toBackward()
{
GetBackwardHelperPoint().Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(GetForwardHelperPoint().Get_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(), true, null);
}
public Vector3 Get_aDirection_inUnitsOfGlobalSpace_normalized(bool requestedDirection_isForward_notBackward)
{
if (requestedDirection_isForward_notBackward)
{
return Get_direction_toForward_inUnitsOfGlobalSpace_normalized();
}
else
{
return Get_direction_toBackward_inUnitsOfGlobalSpace_normalized();
}
}
public Vector3 Get_aDirection_inUnitsOfActiveDrawSpace_normalized(bool requestedDirection_isForward_notBackward)
{
if (requestedDirection_isForward_notBackward)
{
return Get_direction_toForward_inUnitsOfActiveDrawSpace_normalized();
}
else
{
return Get_direction_toBackward_inUnitsOfActiveDrawSpace_normalized();
}
}
public Vector3 Get_direction_toForward_inUnitsOfGlobalSpace_normalized()
{
return GetForwardHelperPoint().Get_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized();
}
public Vector3 Get_direction_toForward_inUnitsOfActiveDrawSpace_normalized()
{
return GetForwardHelperPoint().Get_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfActiveDrawSpace_normalized();
}
public Vector3 Get_direction_toBackward_inUnitsOfGlobalSpace_normalized()
{
return GetBackwardHelperPoint().Get_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized();
}
public Vector3 Get_direction_toBackward_inUnitsOfActiveDrawSpace_normalized()
{
return GetBackwardHelperPoint().Get_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfActiveDrawSpace_normalized();
}
public void Set_aDirection_inUnitsOfGlobalSpace_normalized(bool requestedDirection_isForward_notBackward, Vector3 newDirection_inUnitsOfGlobalSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
if (requestedDirection_isForward_notBackward)
{
Set_direction_toForward_inUnitsOfGlobalSpace_normalized(newDirection_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
else
{
Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(newDirection_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
public void Set_aDirection_inUnitsOfActiveDrawSpace_normalized(bool requestedDirection_isForward_notBackward, Vector3 newDirection_inUnitsOfActiveDrawSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
if (requestedDirection_isForward_notBackward)
{
Set_direction_toForward_inUnitsOfActiveDrawSpace_normalized(newDirection_inUnitsOfActiveDrawSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
else
{
Set_direction_toBackward_inUnitsOfActiveDrawSpace_normalized(newDirection_inUnitsOfActiveDrawSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
public override JunctureType GetJunctureType()
{
return junctureType;
}
public override InternalDXXL_BezierControlHelperSubPoint GetForwardHelper()
{
return GetForwardHelperPoint();
}
public override InternalDXXL_BezierControlHelperSubPoint GetBackwardHelper()
{
return GetBackwardHelperPoint();
}
public override SourceOf_directionToHelper Get_sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked()
{
return sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked;
}
public bool CheckIf_boundGameobjectInfluencesRotation()
{
SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled();
if (boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled)
{
if (junctureType == JunctureType.kinked)
{
if (GetBackwardHelperPoint().isUsed == true)
{
if (GetBackwardHelperPoint().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture != SourceOf_directionToHelper.independentFromGameobject)
{
return true;
}
}
if (GetForwardHelperPoint().isUsed == true)
{
if (GetForwardHelperPoint().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture != SourceOf_directionToHelper.independentFromGameobject)
{
return true;
}
}
}
else
{
return (sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked != SourceOf_directionToHelper.independentFromGameobject);
}
}
return false;
}
public override void Set_direction_toForward_inUnitsOfGlobalSpace_normalized(Vector3 newDirection_toForward_inUnitsOfGlobalSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
GetForwardHelperPoint().Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(newDirection_toForward_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void Set_direction_toForward_inUnitsOfActiveDrawSpace_normalized(Vector3 newDirection_toForward_inUnitsOfActiveDrawSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
GetForwardHelperPoint().Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfActiveDrawSpace_normalized(newDirection_toForward_inUnitsOfActiveDrawSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public override void Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(Vector3 newDirection_toBackward_inUnitsOfGlobalSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
GetBackwardHelperPoint().Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(newDirection_toBackward_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void Set_direction_toBackward_inUnitsOfActiveDrawSpace_normalized(Vector3 newDirection_toBackward_inUnitsOfActiveDrawSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
GetBackwardHelperPoint().Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfActiveDrawSpace_normalized(newDirection_toBackward_inUnitsOfActiveDrawSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void TryPassOnNew_directionToHelper_unifiedTowardsForwardForCaseNonKinked_inUnitsOfGlobalSpace_normalized_toBoundGameobject(Vector3 newDirection_unifiedToForward_inUnitsOfGlobalSpace_normalized, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
if (sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked != SourceOf_directionToHelper.independentFromGameobject)
{
connectionComponent_onBoundGameobject.Transfer_newDirectionToAHelperPointInUnitsOfGlobalSpaceNormalized_fromSpline_toBoundGameobject(newDirection_unifiedToForward_inUnitsOfGlobalSpace_normalized, sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
public Vector3 ConvertGivenDirectionToHelper_to_alingedDirectionToOtherHelper(Vector3 givenDirectionToHelper)
{
if ((junctureType == JunctureType.aligned) && Get_controlPointTriplet_thisSubPointIsPartOf().alignedHelperPoints_areOnTheSameSideOfTheAnchor)
{
return givenDirectionToHelper;
}
else
{
return (-givenDirectionToHelper);
}
}
public void AddRotation_toForwardDirection(Quaternion rotationIncrement, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector3 new_direction_toForward_inUnitsOfGlobalSpace_normalized = rotationIncrement * Get_direction_toForward_inUnitsOfGlobalSpace_normalized();
Set_direction_toForward_inUnitsOfGlobalSpace_normalized(new_direction_toForward_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void AddRotation_toBackwardDirection(Quaternion rotationIncrement, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector3 new_direction_toBackward_inUnitsOfGlobalSpace_normalized = rotationIncrement * Get_direction_toBackward_inUnitsOfGlobalSpace_normalized();
Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(new_direction_toBackward_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public override void SetPos_inUnitsOfGlobalSpace(Vector3 newPos_inUnitsOfGlobalSpace, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector3 offset_fromPrevious_toNewPosition = SetPos_inUnitsOfGlobalSpace_butIgnoreDependentValues_nonRecursively(newPos_inUnitsOfGlobalSpace, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
if (updateDependentValuesOnControlPointTriplet)
{
if ((junctureType == JunctureType.kinked) && (Get_controlPointTriplet_thisSubPointIsPartOf().IsEndPointToVoid_atStartOrEndOfAnUnclosedSpline() == false))
{
if (GetForwardHelperPoint().isUsed == true)
{
if (GetForwardHelperPoint().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture == SourceOf_directionToHelper.independentFromGameobject)
{
Vector3 newDirection_fromAnchorPoint_toForwardHelper_inUnitsOfGlobalSpace_notNormalized = GetForwardHelperPoint().GetPos_inUnitsOfGlobalSpace() - newPos_inUnitsOfGlobalSpace;
float newAbsDistance_toForwardHelper_inUnitsOfGlobalSpace = newDirection_fromAnchorPoint_toForwardHelper_inUnitsOfGlobalSpace_notNormalized.magnitude;
GetForwardHelperPoint().Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(newAbsDistance_toForwardHelper_inUnitsOfGlobalSpace, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
if (UtilitiesDXXL_Math.ApproximatelyZero(newAbsDistance_toForwardHelper_inUnitsOfGlobalSpace) == false) //-> no change of the direction for zero-distances
{
Vector3 newDirection_fromAnchorPoint_toForwardHelper_inUnitsOfGlobalSpace_normalized = newDirection_fromAnchorPoint_toForwardHelper_inUnitsOfGlobalSpace_notNormalized / newAbsDistance_toForwardHelper_inUnitsOfGlobalSpace;
Set_direction_toForward_inUnitsOfGlobalSpace_normalized(newDirection_fromAnchorPoint_toForwardHelper_inUnitsOfGlobalSpace_normalized, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
else
{
GetForwardHelperPoint().AddPosOffset_inUnitsOfGlobalSpace(offset_fromPrevious_toNewPosition, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
if (GetBackwardHelperPoint().isUsed == true)
{
if (GetBackwardHelperPoint().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture == SourceOf_directionToHelper.independentFromGameobject)
{
Vector3 newDirection_fromAnchorPoint_toBackwardHelper_inUnitsOfGlobalSpace_notNormalized = GetBackwardHelperPoint().GetPos_inUnitsOfGlobalSpace() - newPos_inUnitsOfGlobalSpace;
float newAbsDistance_toBackwardHelper_inUnitsOfGlobalSpace = newDirection_fromAnchorPoint_toBackwardHelper_inUnitsOfGlobalSpace_notNormalized.magnitude;
GetBackwardHelperPoint().Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(newAbsDistance_toBackwardHelper_inUnitsOfGlobalSpace, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
if (UtilitiesDXXL_Math.ApproximatelyZero(newAbsDistance_toBackwardHelper_inUnitsOfGlobalSpace) == false) //-> no change of the direction for zero-distances
{
Vector3 newDirection_fromAnchorPoint_toBackwardHelper_inUnitsOfGlobalSpace_normalized = newDirection_fromAnchorPoint_toBackwardHelper_inUnitsOfGlobalSpace_notNormalized / newAbsDistance_toBackwardHelper_inUnitsOfGlobalSpace;
Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(newDirection_fromAnchorPoint_toBackwardHelper_inUnitsOfGlobalSpace_normalized, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
else
{
GetBackwardHelperPoint().AddPosOffset_inUnitsOfGlobalSpace(offset_fromPrevious_toNewPosition, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
}
else
{
//-> the helperPoints have always "isUsed=true" here, since the junctureType is "not kinked". Reminder: endPoints of non-closed splines are always forced to "kinked" and therefore also don't arrive here
GetForwardHelperPoint().AddPosOffset_inUnitsOfGlobalSpace(offset_fromPrevious_toNewPosition, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
GetBackwardHelperPoint().AddPosOffset_inUnitsOfGlobalSpace(offset_fromPrevious_toNewPosition, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
}
public InternalDXXL_BezierControlHelperSubPoint GetAHelperPoint(bool requestedHelperPoint_isForward_notBackward)
{
if (requestedHelperPoint_isForward_notBackward)
{
return GetForwardHelperPoint();
}
else
{
return GetBackwardHelperPoint();
}
}
public override InternalDXXL_BezierControlSubPoint GetNextSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
return GetForwardHelperPoint();
}
public override InternalDXXL_BezierControlSubPoint GetPreviousSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
return GetBackwardHelperPoint();
}
public override InternalDXXL_BezierControlSubPoint GetNextUsedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
if (GetForwardHelperPoint().isUsed)
{
return GetForwardHelperPoint();
}
else
{
InternalDXXL_BezierControlPointTriplet next_controlPoint = Get_controlPointTriplet_thisSubPointIsPartOf().GetNextControlPointTripletAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
if (next_controlPoint != null)
{
if (next_controlPoint.backwardHelperPoint.isUsed)
{
return next_controlPoint.backwardHelperPoint;
}
else
{
return next_controlPoint.anchorPoint;
}
}
else
{
return null;
}
}
}
public override InternalDXXL_BezierControlSubPoint GetPreviousUsedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
if (GetBackwardHelperPoint().isUsed)
{
return GetBackwardHelperPoint();
}
else
{
InternalDXXL_BezierControlPointTriplet previous_controlPoint = Get_controlPointTriplet_thisSubPointIsPartOf().GetPreviousControlPointTripletAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
if (previous_controlPoint != null)
{
if (previous_controlPoint.forwardHelperPoint.isUsed)
{
return previous_controlPoint.forwardHelperPoint;
}
else
{
return previous_controlPoint.anchorPoint;
}
}
else
{
return null;
}
}
}
public override Vector3 GetDirectionAlongSplineForwardBasedOnNeighborPoints_inUnitsOfGlobalSpace()
{
if (GetForwardHelperPoint().isUsed)
{
return Get_direction_toForward_inUnitsOfGlobalSpace_normalized();
}
else
{
if (GetBackwardHelperPoint().isUsed)
{
return (-Get_direction_toBackward_inUnitsOfGlobalSpace_normalized());
}
else
{
InternalDXXL_BezierControlSubPoint nextUsedNonSuperimposedSubPointAlongSplineDir = GetNextUsedNonSuperimposedSubPointAlongSplineDir(false);
if (nextUsedNonSuperimposedSubPointAlongSplineDir != null)
{
return (nextUsedNonSuperimposedSubPointAlongSplineDir.GetPos_inUnitsOfGlobalSpace() - GetPos_inUnitsOfGlobalSpace());
}
else
{
InternalDXXL_BezierControlSubPoint previousUsedNonSuperimposedSubPointAlongSplineDir = GetPreviousUsedNonSuperimposedSubPointAlongSplineDir(false);
if (previousUsedNonSuperimposedSubPointAlongSplineDir != null)
{
return (GetPos_inUnitsOfGlobalSpace() - previousUsedNonSuperimposedSubPointAlongSplineDir.GetPos_inUnitsOfGlobalSpace());
}
else
{
return bezierSplineDrawer_thisSubPointIsPartOf.Get_forward_ofActiveDrawSpace_inUnitsOfGlobalSpace_normalized();
}
}
}
}
}
public override bool IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid()
{
return false;
}
public static SourceOf_directionToHelper ConvertDirectionSource_fromWordedVersion_toUsedVersion(SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers wordedVersion_toConvert)
{
switch (wordedVersion_toConvert)
{
case SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsIndependentFromTheRotationOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper.independentFromGameobject;
case SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheForwardDirectionOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper.gameobjectsForward;
case SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheUpDirectionOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper.gameobjectsUp;
case SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheRightDirectionOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper.gameobjectsRight;
case SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheBackDirectionOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper.gameobjectsBack;
case SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheDownDirectionOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper.gameobjectsDown;
case SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheLeftDirectionOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper.gameobjectsLeft;
default:
return SourceOf_directionToHelper.independentFromGameobject;
}
}
public static SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers ConvertDirectionSource_fromUsedVersion_toWordedVersion(SourceOf_directionToHelper usedVersion_toConvert)
{
switch (usedVersion_toConvert)
{
case SourceOf_directionToHelper.independentFromGameobject:
return SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsIndependentFromTheRotationOfTheGameobjectThatIsBoundToTheCenterPosition;
case SourceOf_directionToHelper.gameobjectsForward:
return SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheForwardDirectionOfTheGameobjectThatIsBoundToTheCenterPosition;
case SourceOf_directionToHelper.gameobjectsUp:
return SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheUpDirectionOfTheGameobjectThatIsBoundToTheCenterPosition;
case SourceOf_directionToHelper.gameobjectsRight:
return SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheRightDirectionOfTheGameobjectThatIsBoundToTheCenterPosition;
case SourceOf_directionToHelper.gameobjectsBack:
return SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheBackDirectionOfTheGameobjectThatIsBoundToTheCenterPosition;
case SourceOf_directionToHelper.gameobjectsDown:
return SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheDownDirectionOfTheGameobjectThatIsBoundToTheCenterPosition;
case SourceOf_directionToHelper.gameobjectsLeft:
return SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheLeftDirectionOfTheGameobjectThatIsBoundToTheCenterPosition;
default:
return SourceOf_directionToHelper_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsIndependentFromTheRotationOfTheGameobjectThatIsBoundToTheCenterPosition;
}
}
SourceOf_directionToHelper sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked_afterInspectorInput;
JunctureType junctureType_afterInspectorInput;
public void DrawValuesToInspector(Rect rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings)
{
FillingIsUsedFieldsWithDefaultValues_forInspector();
float currentHeightOffset = 0.0f;
DrawPositionLine_forInspector(RecalcCurrentRect_forInspector(rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, currentHeightOffset), new GUIContent("Position", Get_tooltip_explainingWheatherUnitsAreInGlobalOrInLocalSpace_forInspector()));
currentHeightOffset += UtilitiesDXXL_Components.Get_inspector_singleLineHeightInclSpacingBetweenLines();
DrawBoundGameobjectLine_forInspector(RecalcCurrentRect_forInspector(rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, currentHeightOffset), new GUIContent("Bind to gameobject"));
TryDrawDirectionSourceLine_forInspector(ref currentHeightOffset, rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings);
currentHeightOffset += UtilitiesDXXL_Components.Get_inspector_singleLineHeightInclSpacingBetweenLines();
DrawJunctureTypeLine_forInspector(rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, currentHeightOffset);
}
void FillingIsUsedFieldsWithDefaultValues_forInspector()
{
//This is for cases where the fields are not displayed or greyed out. They are used for an "hasChanged"-check afterwards:
position_inUnitsOfActiveDrawSpace_afterInspectorInput = position_inUnitsOfActiveDrawSpace;
boundGameobject_afterInspectorInput = boundGameobject;
sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked_afterInspectorInput = sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked;
junctureType_afterInspectorInput = junctureType;
}
void TryDrawDirectionSourceLine_forInspector(ref float currentHeightOffset, Rect rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings)
{
#if UNITY_EDITOR
if (boundGameobject != null) //-> could be improved: there is no check whether the "boundGameobject" is "inactive" or the connection component on it is "disabled". Also "GetPropertyHeightForInspectorList()" may be affected by a fix.
{
if (junctureType != JunctureType.kinked)
{
currentHeightOffset += UtilitiesDXXL_Components.Get_inspector_singleLineHeightInclSpacingBetweenLines();
sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked_afterInspectorInput = (SourceOf_directionToHelper)UnityEditor.EditorGUI.EnumPopup(RecalcCurrentRect_forInspector(rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, currentHeightOffset), new GUIContent("Direction Source"), sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked);
}
}
#endif
}
void DrawJunctureTypeLine_forInspector(Rect rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, float currentHeightOffset)
{
#if UNITY_EDITOR
bool isEndPointToVoid_atStartOrEndOfAnUnclosedSpline = Get_controlPointTriplet_thisSubPointIsPartOf().IsEndPointToVoid_atStartOrEndOfAnUnclosedSpline();
string tooltip_forJunctureType;
if (isEndPointToVoid_atStartOrEndOfAnUnclosedSpline)
{
tooltip_forJunctureType = "Not adjustable at end points of non-ring splines.";
}
else
{
tooltip_forJunctureType = "";
}
UnityEditor.EditorGUI.BeginDisabledGroup(isEndPointToVoid_atStartOrEndOfAnUnclosedSpline); //note: end points of non-closed splines are always forced to "kinked" so that their helperPoints can be deactivated/activated.
junctureType_afterInspectorInput = (JunctureType)UnityEditor.EditorGUI.EnumPopup(RecalcCurrentRect_forInspector(rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, currentHeightOffset), new GUIContent("Juncture type", tooltip_forJunctureType), junctureType);
UnityEditor.EditorGUI.EndDisabledGroup();
#endif
}
public bool TryApplyChangesAfterInspectorInput()
{
//The checks here are more reliable than "EditorGUI.BeginChangeCheck/EndChangeCheck()", which also reports "change" only due to mouse selection, even when the value didn't change yet.
if (UtilitiesDXXL_Math.CheckIf_twoVectorsAreExactlyEqual(position_inUnitsOfActiveDrawSpace_afterInspectorInput, position_inUnitsOfActiveDrawSpace) == false)
{
bezierSplineDrawer_thisSubPointIsPartOf.RegisterStateForUndo("Change Spline Position", true, true);
SetPos_inUnitsOfActiveDrawSpace(position_inUnitsOfActiveDrawSpace_afterInspectorInput, true, null);
return true;
}
if (boundGameobject_afterInspectorInput != boundGameobject)
{
//bezierSplineDrawer_thisSubPointIsPartOf.RegisterStateForUndo("Change Spline Gameobject Ref", true, true); //not needed here, because it is cared for inside "ProcessNewGameobjectAssignment"
ProcessNewGameobjectAssignment(boundGameobject_afterInspectorInput);
return true;
}
if (sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked_afterInspectorInput != sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked)
{
bezierSplineDrawer_thisSubPointIsPartOf.RegisterStateForUndo("Change Spline Direction Source", true, true);
ProcessChanging_sourceOfDirectionToHelper(sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked_afterInspectorInput);
return true;
}
if (junctureType_afterInspectorInput != junctureType)
{
bezierSplineDrawer_thisSubPointIsPartOf.RegisterStateForUndo("Change Spline Juncture", true, true);
SetJunctureType(junctureType_afterInspectorInput);
return true;
}
return false;
}
public override float GetPropertyHeightForInspectorList()
{
int linesForDirectionSource = ((boundGameobject != null) && (junctureType != JunctureType.kinked)) ? 1 : 0;
float height_forAllContentLines = (3.0f + linesForDirectionSource) * UtilitiesDXXL_Components.Get_inspector_singleLineHeightInclSpacingBetweenLines();
return height_forAllContentLines;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de19abe59c0664449963ce0339d4e666
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,620 @@
namespace DrawXXL
{
using System;
using UnityEngine;
[Serializable]
public class InternalDXXL_BezierControlAnchorSubPoint2D : InternalDXXL_BezierControlSubPoint2D
{
[SerializeField] public InternalDXXL_BezierControlAnchorSubPoint.JunctureType junctureType;
public enum SourceOf_directionToHelper2D { independentFromGameobject, gameobjectsUp, gameobjectsRight, gameobjectsDown, gameobjectsLeft };
public enum SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers { directionFromPointCenterToThisWeightIsIndependentFromTheRotationOfTheGameobjectThatIsBoundToTheCenterPosition, directionFromPointCenterToThisWeightIsTheUpDirectionOfTheGameobjectThatIsBoundToTheCenterPosition, directionFromPointCenterToThisWeightIsTheRightDirectionOfTheGameobjectThatIsBoundToTheCenterPosition, directionFromPointCenterToThisWeightIsTheDownDirectionOfTheGameobjectThatIsBoundToTheCenterPosition, directionFromPointCenterToThisWeightIsTheLeftDirectionOfTheGameobjectThatIsBoundToTheCenterPosition };
[SerializeField] public SourceOf_directionToHelper2D sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked; //-> is only used when a "boundGameobject" is assigned
public int controlID_ofCustomHandles_sphere;
public int controlID_ofCustomHandles_forwardCone;
public int controlID_ofCustomHandles_backwardCone;
public int controlID_ofUnityStyleRotationHandle2D;
public Quaternion rotation_ofRotationHandleDuringRotationDragPhases;
public bool recalc_rotation_ofRotationHandleDuringRotationDragPhases_duringNextOnSceneGUI = true;
public Vector3 directionForHandles_forwardCone_inUnitsOfGlobalSpace_normalized = Vector3.right;
public Vector3 directionForHandles_backwardCone_inUnitsOfGlobalSpace_normalized = Vector3.left;
public bool recalc_directionForHandles_forwardCone_duringNextOnSceneGUI = true;
public bool recalc_directionForHandles_backwardCone_duringNextOnSceneGUI = true;
public override void InitializeValuesThatAreIndependentFromOtherSubPoints(InternalDXXL_BezierControlPointTriplet2D controlPoint_thisSubPointIsPartOf)
{
base.InitializeValuesThatAreIndependentFromOtherSubPoints(controlPoint_thisSubPointIsPartOf);
sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked = SourceOf_directionToHelper2D.independentFromGameobject;
}
public InternalDXXL_BezierControlHelperSubPoint2D GetForwardHelperPoint()
{
//Serialized lists containing other lists and containing custom classes with cross references don't work well in Unity, even when using the [SerializeReference] attribute. Functions like this try to keep the convenience of a real reference tree. The only "real" reference is the monobehavior-inherited spline component. Everything has to start from there.
return bezierSplineDrawer_thisSubPointIsPartOf.listOfControlPointTriplets[i_ofContainingControlPoint_insideControlPointsList].forwardHelperPoint;
}
public InternalDXXL_BezierControlHelperSubPoint2D GetBackwardHelperPoint()
{
//Serialized lists containing other lists and containing custom classes with cross references don't work well in Unity, even when using the [SerializeReference] attribute. Functions like this try to keep the convenience of a real reference tree. The only "real" reference is the monobehavior-inherited spline component. Everything has to start from there.
return bezierSplineDrawer_thisSubPointIsPartOf.listOfControlPointTriplets[i_ofContainingControlPoint_insideControlPointsList].backwardHelperPoint;
}
public override void ResetDirectionSourceToIndependent()
{
sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked = SourceOf_directionToHelper2D.independentFromGameobject;
}
public override void TryTransferBoundGameobjectsRotationToAnchorPointsDirection()
{
//-> during no-gameobject-assigned-phases the "sourceOf_direction*'s" are forced to "independentFromGameobject", so here only cases where the assignment changed from one gameobject to another gameobject cause an action inside "connectionComponent_onBoundGameobject.Transfer_aTransformDirection_fromBoundGameobject_toSpline()":
connectionComponent_onBoundGameobject.Transfer_aTransformDirection_fromBoundGameobject_toSpline();
}
public void ProcessChanging_sourceOfDirectionToHelper(SourceOf_directionToHelper2D newSourceOfDirection)
{
if (newSourceOfDirection != sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked)
{
sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked = newSourceOfDirection;
if (newSourceOfDirection != SourceOf_directionToHelper2D.independentFromGameobject)
{
TryTransfer_newTransformDirection_fromBoundGameobject_toSpline_afterDirectionSourceChange();
}
}
}
public void TryTransfer_newTransformDirection_fromBoundGameobject_toSpline_afterDirectionSourceChange()
{
SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled();
if (boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled)
{
connectionComponent_onBoundGameobject.Transfer_aTransformDirection_fromBoundGameobject_toSpline();
}
}
public void SetJunctureType(InternalDXXL_BezierControlAnchorSubPoint.JunctureType newJunctureType)
{
if (newJunctureType != junctureType)
{
InternalDXXL_BezierControlAnchorSubPoint.JunctureType oldJunctureType = junctureType;
junctureType = newJunctureType;
if (oldJunctureType == InternalDXXL_BezierControlAnchorSubPoint.JunctureType.kinked)
{
TrySwitchBothHelpersTo_isUsed();
//<- if at least one helperPoint was unused before, then the helperPoints are now already cleanly converted to the new juncture type (meaning: they are now "both used", "parallel", "same absDistance from anchor" and "on differnt sides of the anchor")
//-> if both helperPoints were already used before, then the above didn't have any effect, and the following "forcing to parallel/sameAbsDistance" (inside the "newJuncture == nonKinked"-threads) finishes the conversion. This "forcing to parallel/sameAbsDistance" doesn't harm if the two helpers are already "parallel/sameAbsDistance".
}
if (newJunctureType == InternalDXXL_BezierControlAnchorSubPoint.JunctureType.kinked)
{
//this "set isUsed-states" is actually only needed for "change AWAY from kinked", and then during non-kinked-phases the isUsed-state will anyway not change so it will arrive at the next "change TO kinked" still with "all are used". But in order to not having to care what happens in non-kinked-phases and still being sure that kinked-phases always start with "all are used" it is explicitly called here. Besides that it may act as double bottom if the states still get confused somehow.
TrySwitchBothHelpersTo_isUsed();
}
if (newJunctureType == InternalDXXL_BezierControlAnchorSubPoint.JunctureType.aligned)
{
MirrorDirection_from_toForward_to_toBackward();
Get_controlPointTriplet_thisSubPointIsPartOf().alignedHelperPoints_areOnTheSameSideOfTheAnchor = false; //-> this field is only used by "aligned" anchorPoints
}
if (newJunctureType == InternalDXXL_BezierControlAnchorSubPoint.JunctureType.mirrored)
{
MirrorDirection_from_toForward_to_toBackward();
MirrorDistance_from_toForward_to_toBackward();
}
}
}
void TrySwitchBothHelpersTo_isUsed()
{
//the order of the helperPointActivation here only matters for cases where BOTH helperPoints have been unused during the kinked-phase and are now set to used, because a non-kinked juncture-phase follows. The first activated helperPoint then dictates the shape of the second activated helperPoint. Therefore "forward" comes first.
if (false == GetForwardHelperPoint().IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
GetForwardHelperPoint().ChangeUsedState(true, false);
}
if (false == GetBackwardHelperPoint().IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
GetBackwardHelperPoint().ChangeUsedState(true, false);
}
}
void MirrorDirection_from_toForward_to_toBackward()
{
GetBackwardHelperPoint().Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(-GetForwardHelperPoint().Get_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(), true, null);
}
void MirrorDistance_from_toForward_to_toBackward()
{
GetBackwardHelperPoint().Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(GetForwardHelperPoint().Get_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(), true, null);
}
public Vector2 Get_aDirection_inUnitsOfGlobalSpace_normalized(bool requestedDirection_isForward_notBackward)
{
if (requestedDirection_isForward_notBackward)
{
return Get_direction_toForward_inUnitsOfGlobalSpace_normalized();
}
else
{
return Get_direction_toBackward_inUnitsOfGlobalSpace_normalized();
}
}
public Vector2 Get_aDirection_inUnitsOfActiveDrawSpace_normalized(bool requestedDirection_isForward_notBackward)
{
if (requestedDirection_isForward_notBackward)
{
return Get_direction_toForward_inUnitsOfActiveDrawSpace_normalized();
}
else
{
return Get_direction_toBackward_inUnitsOfActiveDrawSpace_normalized();
}
}
public Vector2 Get_direction_toForward_inUnitsOfGlobalSpace_normalized()
{
return GetForwardHelperPoint().Get_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized();
}
public Vector2 Get_direction_toForward_inUnitsOfActiveDrawSpace_normalized()
{
return GetForwardHelperPoint().Get_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfActiveDrawSpace_normalized();
}
public Vector2 Get_direction_toBackward_inUnitsOfGlobalSpace_normalized()
{
return GetBackwardHelperPoint().Get_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized();
}
public Vector2 Get_direction_toBackward_inUnitsOfActiveDrawSpace_normalized()
{
return GetBackwardHelperPoint().Get_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfActiveDrawSpace_normalized();
}
public void Set_aDirection_inUnitsOfGlobalSpace_normalized(bool requestedDirection_isForward_notBackward, Vector2 newDirection_inUnitsOfGlobalSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
if (requestedDirection_isForward_notBackward)
{
Set_direction_toForward_inUnitsOfGlobalSpace_normalized(newDirection_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
else
{
Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(newDirection_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
public void Set_aDirection_inUnitsOfActiveDrawSpace_normalized(bool requestedDirection_isForward_notBackward, Vector2 newDirection_inUnitsOfActiveDrawSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
if (requestedDirection_isForward_notBackward)
{
Set_direction_toForward_inUnitsOfActiveDrawSpace_normalized(newDirection_inUnitsOfActiveDrawSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
else
{
Set_direction_toBackward_inUnitsOfActiveDrawSpace_normalized(newDirection_inUnitsOfActiveDrawSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
public override InternalDXXL_BezierControlAnchorSubPoint.JunctureType GetJunctureType()
{
return junctureType;
}
public override InternalDXXL_BezierControlHelperSubPoint2D GetForwardHelper()
{
return GetForwardHelperPoint();
}
public override InternalDXXL_BezierControlHelperSubPoint2D GetBackwardHelper()
{
return GetBackwardHelperPoint();
}
public override SourceOf_directionToHelper2D Get_sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked()
{
return sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked;
}
public bool CheckIf_boundGameobjectInfluencesRotation()
{
SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled();
if (boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled)
{
if (junctureType == InternalDXXL_BezierControlAnchorSubPoint.JunctureType.kinked)
{
if (GetBackwardHelperPoint().isUsed == true)
{
if (GetBackwardHelperPoint().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture != SourceOf_directionToHelper2D.independentFromGameobject)
{
return true;
}
}
if (GetForwardHelperPoint().isUsed == true)
{
if (GetForwardHelperPoint().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture != SourceOf_directionToHelper2D.independentFromGameobject)
{
return true;
}
}
}
else
{
return (sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked != SourceOf_directionToHelper2D.independentFromGameobject);
}
}
return false;
}
public override void Set_direction_toForward_inUnitsOfGlobalSpace_normalized(Vector2 newDirection_toForward_inUnitsOfGlobalSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
GetForwardHelperPoint().Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(newDirection_toForward_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void Set_direction_toForward_inUnitsOfActiveDrawSpace_normalized(Vector2 newDirection_toForward_inUnitsOfActiveDrawSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
GetForwardHelperPoint().Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfActiveDrawSpace_normalized(newDirection_toForward_inUnitsOfActiveDrawSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public override void Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(Vector2 newDirection_toBackward_inUnitsOfGlobalSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
GetBackwardHelperPoint().Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(newDirection_toBackward_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void Set_direction_toBackward_inUnitsOfActiveDrawSpace_normalized(Vector2 newDirection_toBackward_inUnitsOfActiveDrawSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
GetBackwardHelperPoint().Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfActiveDrawSpace_normalized(newDirection_toBackward_inUnitsOfActiveDrawSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void TryPassOnNew_directionToHelper_unifiedTowardsForwardForCaseNonKinked_inUnitsOfGlobalSpace_normalized_toBoundGameobject(Vector2 newDirection_unifiedToForward_inUnitsOfGlobalSpace_normalized, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
if (sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked != SourceOf_directionToHelper2D.independentFromGameobject)
{
connectionComponent_onBoundGameobject.Transfer_newDirectionToAHelperPointInUnitsOfGlobalSpaceNormalized_fromSpline_toBoundGameobject(newDirection_unifiedToForward_inUnitsOfGlobalSpace_normalized, sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
public Vector2 ConvertGivenDirectionToHelper_to_alingedDirectionToOtherHelper(Vector2 givenDirectionToHelper)
{
if ((junctureType == InternalDXXL_BezierControlAnchorSubPoint.JunctureType.aligned) && Get_controlPointTriplet_thisSubPointIsPartOf().alignedHelperPoints_areOnTheSameSideOfTheAnchor)
{
return givenDirectionToHelper;
}
else
{
return (-givenDirectionToHelper);
}
}
public void AddRotation_toForwardDirection(Quaternion rotationIncrement, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector3 new_direction_toForward_inUnitsOfGlobalSpace_normalized = rotationIncrement * Get_direction_toForward_inUnitsOfGlobalSpace_normalized();
Set_direction_toForward_inUnitsOfGlobalSpace_normalized(new_direction_toForward_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void AddRotation_toBackwardDirection(Quaternion rotationIncrement, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector3 new_direction_toBackward_inUnitsOfGlobalSpace_normalized = rotationIncrement * Get_direction_toBackward_inUnitsOfGlobalSpace_normalized();
Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(new_direction_toBackward_inUnitsOfGlobalSpace_normalized, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public override void SetPos_inUnitsOfGlobalSpace(Vector2 newPos_inUnitsOfGlobalSpace, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector2 offset_fromPrevious_toNewPosition = SetPos_inUnitsOfGlobalSpace_butIgnoreDependentValues_nonRecursively(newPos_inUnitsOfGlobalSpace, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
if (updateDependentValuesOnControlPointTriplet)
{
if ((junctureType == InternalDXXL_BezierControlAnchorSubPoint.JunctureType.kinked) && (Get_controlPointTriplet_thisSubPointIsPartOf().IsEndPointToVoid_atStartOrEndOfAnUnclosedSpline() == false))
{
if (GetForwardHelperPoint().isUsed == true)
{
if (GetForwardHelperPoint().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture == SourceOf_directionToHelper2D.independentFromGameobject)
{
Vector2 newDirection_fromAnchorPoint_toForwardHelper_inUnitsOfGlobalSpace_notNormalized = GetForwardHelperPoint().GetPos_inUnitsOfGlobalSpace() - newPos_inUnitsOfGlobalSpace;
float newAbsDistance_toForwardHelper_inUnitsOfGlobalSpace = newDirection_fromAnchorPoint_toForwardHelper_inUnitsOfGlobalSpace_notNormalized.magnitude;
GetForwardHelperPoint().Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(newAbsDistance_toForwardHelper_inUnitsOfGlobalSpace, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
if (UtilitiesDXXL_Math.ApproximatelyZero(newAbsDistance_toForwardHelper_inUnitsOfGlobalSpace) == false) //-> no change of the direction for zero-distances
{
Vector2 newDirection_fromAnchorPoint_toForwardHelper_inUnitsOfGlobalSpace_normalized = newDirection_fromAnchorPoint_toForwardHelper_inUnitsOfGlobalSpace_notNormalized / newAbsDistance_toForwardHelper_inUnitsOfGlobalSpace;
Set_direction_toForward_inUnitsOfGlobalSpace_normalized(newDirection_fromAnchorPoint_toForwardHelper_inUnitsOfGlobalSpace_normalized, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
else
{
GetForwardHelperPoint().AddPosOffset_inUnitsOfGlobalSpace(offset_fromPrevious_toNewPosition, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
if (GetBackwardHelperPoint().isUsed == true)
{
if (GetBackwardHelperPoint().sourceOf_directionFromAnchorToThisHelper_caseKinkedJuncture == SourceOf_directionToHelper2D.independentFromGameobject)
{
Vector2 newDirection_fromAnchorPoint_toBackwardHelper_inUnitsOfGlobalSpace_notNormalized = GetBackwardHelperPoint().GetPos_inUnitsOfGlobalSpace() - newPos_inUnitsOfGlobalSpace;
float newAbsDistance_toBackwardHelper_inUnitsOfGlobalSpace = newDirection_fromAnchorPoint_toBackwardHelper_inUnitsOfGlobalSpace_notNormalized.magnitude;
GetBackwardHelperPoint().Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(newAbsDistance_toBackwardHelper_inUnitsOfGlobalSpace, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
if (UtilitiesDXXL_Math.ApproximatelyZero(newAbsDistance_toBackwardHelper_inUnitsOfGlobalSpace) == false) //-> no change of the direction for zero-distances
{
Vector2 newDirection_fromAnchorPoint_toBackwardHelper_inUnitsOfGlobalSpace_normalized = newDirection_fromAnchorPoint_toBackwardHelper_inUnitsOfGlobalSpace_notNormalized / newAbsDistance_toBackwardHelper_inUnitsOfGlobalSpace;
Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(newDirection_fromAnchorPoint_toBackwardHelper_inUnitsOfGlobalSpace_normalized, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
else
{
GetBackwardHelperPoint().AddPosOffset_inUnitsOfGlobalSpace(offset_fromPrevious_toNewPosition, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
}
else
{
//-> the helperPoints have always "isUsed=true" here, since the junctureType is "not kinked". Reminder: endPoints of non-closed splines are always forced to "kinked" and therefore also don't arrive here
GetForwardHelperPoint().AddPosOffset_inUnitsOfGlobalSpace(offset_fromPrevious_toNewPosition, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
GetBackwardHelperPoint().AddPosOffset_inUnitsOfGlobalSpace(offset_fromPrevious_toNewPosition, false, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
}
}
public InternalDXXL_BezierControlHelperSubPoint2D GetAHelperPoint(bool requestedHelperPoint_isForward_notBackward)
{
if (requestedHelperPoint_isForward_notBackward)
{
return GetForwardHelperPoint();
}
else
{
return GetBackwardHelperPoint();
}
}
public override InternalDXXL_BezierControlSubPoint2D GetNextSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
return GetForwardHelperPoint();
}
public override InternalDXXL_BezierControlSubPoint2D GetPreviousSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
return GetBackwardHelperPoint();
}
public override InternalDXXL_BezierControlSubPoint2D GetNextUsedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
if (GetForwardHelperPoint().isUsed)
{
return GetForwardHelperPoint();
}
else
{
InternalDXXL_BezierControlPointTriplet2D next_controlPoint = Get_controlPointTriplet_thisSubPointIsPartOf().GetNextControlPointTripletAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
if (next_controlPoint != null)
{
if (next_controlPoint.backwardHelperPoint.isUsed)
{
return next_controlPoint.backwardHelperPoint;
}
else
{
return next_controlPoint.anchorPoint;
}
}
else
{
return null;
}
}
}
public override InternalDXXL_BezierControlSubPoint2D GetPreviousUsedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
if (GetBackwardHelperPoint().isUsed)
{
return GetBackwardHelperPoint();
}
else
{
InternalDXXL_BezierControlPointTriplet2D previous_controlPoint = Get_controlPointTriplet_thisSubPointIsPartOf().GetPreviousControlPointTripletAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
if (previous_controlPoint != null)
{
if (previous_controlPoint.forwardHelperPoint.isUsed)
{
return previous_controlPoint.forwardHelperPoint;
}
else
{
return previous_controlPoint.anchorPoint;
}
}
else
{
return null;
}
}
}
public override Vector2 GetDirectionAlongSplineForwardBasedOnNeighborPoints_inUnitsOfGlobalSpace()
{
if (GetForwardHelperPoint().isUsed)
{
return Get_direction_toForward_inUnitsOfGlobalSpace_normalized();
}
else
{
if (GetBackwardHelperPoint().isUsed)
{
return (-Get_direction_toBackward_inUnitsOfGlobalSpace_normalized());
}
else
{
InternalDXXL_BezierControlSubPoint2D nextUsedNonSuperimposedSubPointAlongSplineDir = GetNextUsedNonSuperimposedSubPointAlongSplineDir(false);
if (nextUsedNonSuperimposedSubPointAlongSplineDir != null)
{
return (nextUsedNonSuperimposedSubPointAlongSplineDir.GetPos_inUnitsOfGlobalSpace() - GetPos_inUnitsOfGlobalSpace());
}
else
{
InternalDXXL_BezierControlSubPoint2D previousUsedNonSuperimposedSubPointAlongSplineDir = GetPreviousUsedNonSuperimposedSubPointAlongSplineDir(false);
if (previousUsedNonSuperimposedSubPointAlongSplineDir != null)
{
return (GetPos_inUnitsOfGlobalSpace() - previousUsedNonSuperimposedSubPointAlongSplineDir.GetPos_inUnitsOfGlobalSpace());
}
else
{
return bezierSplineDrawer_thisSubPointIsPartOf.Get_right_ofActiveDrawSpace_inUnitsOfGlobalSpace_normalized();
}
}
}
}
}
public override bool IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid()
{
return false;
}
public static SourceOf_directionToHelper2D ConvertDirectionSource_fromWordedVersion_toUsedVersion(SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers wordedVersion_toConvert)
{
switch (wordedVersion_toConvert)
{
case SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsIndependentFromTheRotationOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper2D.independentFromGameobject;
case SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheUpDirectionOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper2D.gameobjectsUp;
case SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheRightDirectionOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper2D.gameobjectsRight;
case SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheDownDirectionOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper2D.gameobjectsDown;
case SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheLeftDirectionOfTheGameobjectThatIsBoundToTheCenterPosition:
return SourceOf_directionToHelper2D.gameobjectsLeft;
default:
return SourceOf_directionToHelper2D.independentFromGameobject;
}
}
public static SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers ConvertDirectionSource_fromUsedVersion_toWordedVersion(SourceOf_directionToHelper2D usedVersion_toConvert)
{
switch (usedVersion_toConvert)
{
case SourceOf_directionToHelper2D.independentFromGameobject:
return SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsIndependentFromTheRotationOfTheGameobjectThatIsBoundToTheCenterPosition;
case SourceOf_directionToHelper2D.gameobjectsUp:
return SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheUpDirectionOfTheGameobjectThatIsBoundToTheCenterPosition;
case SourceOf_directionToHelper2D.gameobjectsRight:
return SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheRightDirectionOfTheGameobjectThatIsBoundToTheCenterPosition;
case SourceOf_directionToHelper2D.gameobjectsDown:
return SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheDownDirectionOfTheGameobjectThatIsBoundToTheCenterPosition;
case SourceOf_directionToHelper2D.gameobjectsLeft:
return SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsTheLeftDirectionOfTheGameobjectThatIsBoundToTheCenterPosition;
default:
return SourceOf_directionToHelper2D_wordedForInspectorDisplayAtHelpers.directionFromPointCenterToThisWeightIsIndependentFromTheRotationOfTheGameobjectThatIsBoundToTheCenterPosition;
}
}
SourceOf_directionToHelper2D sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked_afterInspectorInput;
InternalDXXL_BezierControlAnchorSubPoint.JunctureType junctureType_afterInspectorInput;
public void DrawValuesToInspector(Rect rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings)
{
FillingIsUsedFieldsWithDefaultValues_forInspector();
float currentHeightOffset = 0.0f;
DrawPositionLine_forInspector(RecalcCurrentRect_forInspector(rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, currentHeightOffset), new GUIContent("Position", Get_tooltip_explainingWheatherUnitsAreInGlobalOrInLocalSpace_forInspector()));
currentHeightOffset += UtilitiesDXXL_Components.Get_inspector_singleLineHeightInclSpacingBetweenLines();
DrawBoundGameobjectLine_forInspector(RecalcCurrentRect_forInspector(rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, currentHeightOffset), new GUIContent("Bind to gameobject"));
TryDrawDirectionSourceLine_forInspector(ref currentHeightOffset, rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings);
currentHeightOffset += UtilitiesDXXL_Components.Get_inspector_singleLineHeightInclSpacingBetweenLines();
DrawJunctureTypeLine_forInspector(rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, currentHeightOffset);
}
void FillingIsUsedFieldsWithDefaultValues_forInspector()
{
//This is for cases where the fields are not displayed or greyed out. They are used for an "hasChanged"-check afterwards:
position_inUnitsOfActiveDrawSpace_afterInspectorInput = position_inUnitsOfActiveDrawSpace;
boundGameobject_afterInspectorInput = boundGameobject;
sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked_afterInspectorInput = sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked;
junctureType_afterInspectorInput = junctureType;
}
void TryDrawDirectionSourceLine_forInspector(ref float currentHeightOffset, Rect rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings)
{
#if UNITY_EDITOR
if (boundGameobject != null) //-> could be improved: there is no check whether the "boundGameobject" is "inactive" or the connection component on it is "disabled". Also "GetPropertyHeightForInspectorList()" may be affected by a fix.
{
if (junctureType != InternalDXXL_BezierControlAnchorSubPoint.JunctureType.kinked)
{
currentHeightOffset += UtilitiesDXXL_Components.Get_inspector_singleLineHeightInclSpacingBetweenLines();
sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked_afterInspectorInput = (SourceOf_directionToHelper2D)UnityEditor.EditorGUI.EnumPopup(RecalcCurrentRect_forInspector(rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, currentHeightOffset), new GUIContent("Direction Source"), sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked);
}
}
#endif
}
void DrawJunctureTypeLine_forInspector(Rect rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, float currentHeightOffset)
{
#if UNITY_EDITOR
bool isEndPointToVoid_atStartOrEndOfAnUnclosedSpline = Get_controlPointTriplet_thisSubPointIsPartOf().IsEndPointToVoid_atStartOrEndOfAnUnclosedSpline();
string tooltip_forJunctureType;
if (isEndPointToVoid_atStartOrEndOfAnUnclosedSpline)
{
tooltip_forJunctureType = "Not adjustable at end points of non-ring splines.";
}
else
{
tooltip_forJunctureType = "";
}
UnityEditor.EditorGUI.BeginDisabledGroup(isEndPointToVoid_atStartOrEndOfAnUnclosedSpline); //note: end points of non-closed splines are always forced to "kinked" so that their helperPoints can be deactivated/activated.
junctureType_afterInspectorInput = (InternalDXXL_BezierControlAnchorSubPoint.JunctureType)UnityEditor.EditorGUI.EnumPopup(RecalcCurrentRect_forInspector(rectForOnlyTheContentLines_alreadyClearedFromAnyColorBoxPaddings, currentHeightOffset), new GUIContent("Juncture type", tooltip_forJunctureType), junctureType);
UnityEditor.EditorGUI.EndDisabledGroup();
#endif
}
public bool TryApplyChangesAfterInspectorInput()
{
//The checks here are more reliable than "EditorGUI.BeginChangeCheck/EndChangeCheck()", which also reports "change" only due to mouse selection, even when the value didn't change yet.
if (UtilitiesDXXL_Math.CheckIf_twoVectorsAreExactlyEqual(position_inUnitsOfActiveDrawSpace_afterInspectorInput, position_inUnitsOfActiveDrawSpace) == false)
{
bezierSplineDrawer_thisSubPointIsPartOf.RegisterStateForUndo("Change Spline Position", true, true);
SetPos_inUnitsOfActiveDrawSpace(position_inUnitsOfActiveDrawSpace_afterInspectorInput, true, null);
return true;
}
if (boundGameobject_afterInspectorInput != boundGameobject)
{
//bezierSplineDrawer_thisSubPointIsPartOf.RegisterStateForUndo("Change Spline Gameobject Ref", true, true); //not needed here, because it is cared for inside "ProcessNewGameobjectAssignment"
ProcessNewGameobjectAssignment(boundGameobject_afterInspectorInput);
return true;
}
if (sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked_afterInspectorInput != sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked)
{
bezierSplineDrawer_thisSubPointIsPartOf.RegisterStateForUndo("Change Spline Direction Source", true, true);
ProcessChanging_sourceOfDirectionToHelper(sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked_afterInspectorInput);
return true;
}
if (junctureType_afterInspectorInput != junctureType)
{
bezierSplineDrawer_thisSubPointIsPartOf.RegisterStateForUndo("Change Spline Juncture", true, true);
SetJunctureType(junctureType_afterInspectorInput);
return true;
}
return false;
}
public override float GetPropertyHeightForInspectorList()
{
int linesForDirectionSource = ((boundGameobject != null) && (junctureType != InternalDXXL_BezierControlAnchorSubPoint.JunctureType.kinked)) ? 1 : 0;
float height_forAllContentLines = (3.0f + linesForDirectionSource) * UtilitiesDXXL_Components.Get_inspector_singleLineHeightInclSpacingBetweenLines();
return height_forAllContentLines;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 96c4eb1b6ea5e484283989bd614eeefb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0bc7695778ef65743b49c30705043aab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ad7d7ad7f6e25d744a6e1788d616441c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,796 @@
namespace DrawXXL
{
using System;
using UnityEngine;
[Serializable]
public class InternalDXXL_BezierControlPointTriplet
{
public static float alpha_ofInspectorBackgroundColor_highlighted = 1.0f;
public static float alpha_ofInspectorBackgroundColor_nonHighlighted = 0.5f;
public bool isHighlighted;
public int i_ofThisPoint_insideControlPointsList;
public BezierSplineDrawer bezierSplineDrawer_thisPointIsPartOf;
[SerializeField] public bool alignedHelperPoints_areOnTheSameSideOfTheAnchor;
[SerializeField] public float progress0to1_ofPlusButtonPosition_inUpcomingBezierSegment;
public InternalDXXL_BezierControlAnchorSubPoint anchorPoint;
public InternalDXXL_BezierControlHelperSubPoint forwardHelperPoint;
public InternalDXXL_BezierControlHelperSubPoint backwardHelperPoint;
InternalDXXL_BezierPointShapeConfig pointShape_afterSpaceChange_inUnitsOfGlobalSpace;
InternalDXXL_BezierPointShapeConfig pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace;
public Rect inspectorRect_reservedForThisTriplet;
public bool minusButtonAtThisListItem_hasBeenClickedInInspector = false;
public void Initialize(BezierSplineDrawer containingSplineDrawer, Vector3 initialPos_inUnitsOfGlobalSpace, Vector3 initialForwardDir_inUnitsOfGlobalSpace_normalized, InternalDXXL_BezierControlAnchorSubPoint.JunctureType junctureType)
{
bezierSplineDrawer_thisPointIsPartOf = containingSplineDrawer;
isHighlighted = false; //-> the caller has to decide whether and take care of highlighting newly created control points after this initialization
alignedHelperPoints_areOnTheSameSideOfTheAnchor = false;
progress0to1_ofPlusButtonPosition_inUpcomingBezierSegment = 0.5f;
anchorPoint = new InternalDXXL_BezierControlAnchorSubPoint();
anchorPoint.InitializeValuesThatAreIndependentFromOtherSubPoints(this);
anchorPoint.subPointType = InternalDXXL_BezierControlSubPoint.SubPointType.anchor;
anchorPoint.isUsed = true;
anchorPoint.junctureType = junctureType;
anchorPoint.SetPos_inUnitsOfGlobalSpace(initialPos_inUnitsOfGlobalSpace, false, null);
forwardHelperPoint = new InternalDXXL_BezierControlHelperSubPoint();
forwardHelperPoint.InitializeValuesThatAreIndependentFromOtherSubPoints(this);
forwardHelperPoint.subPointType = InternalDXXL_BezierControlSubPoint.SubPointType.forwardHelper;
forwardHelperPoint.isForward_notBackward = true;
forwardHelperPoint.isUsed = true;
forwardHelperPoint.Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(initialForwardDir_inUnitsOfGlobalSpace_normalized, false, null);
float initial_forwardWeightDistance_inUnitsOfGlobalSpace = bezierSplineDrawer_thisPointIsPartOf.TransformLength_fromUnitsOfActiveDrawSpace_toGlobalSpace(bezierSplineDrawer_thisPointIsPartOf.forwardWeightDistance_ofNewlyCreatedPoints_inUnitsOfActiveDrawSpace);
Vector3 initialPos_ofForwardHelperPoint_inUnitsOfGlobalSpace = initialPos_inUnitsOfGlobalSpace + initialForwardDir_inUnitsOfGlobalSpace_normalized * initial_forwardWeightDistance_inUnitsOfGlobalSpace;
forwardHelperPoint.SetPos_inUnitsOfGlobalSpace(initialPos_ofForwardHelperPoint_inUnitsOfGlobalSpace, false, null);
forwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(initial_forwardWeightDistance_inUnitsOfGlobalSpace, false, null);
backwardHelperPoint = new InternalDXXL_BezierControlHelperSubPoint();
backwardHelperPoint.InitializeValuesThatAreIndependentFromOtherSubPoints(this);
backwardHelperPoint.subPointType = InternalDXXL_BezierControlSubPoint.SubPointType.backwardHelper;
backwardHelperPoint.isForward_notBackward = false;
backwardHelperPoint.isUsed = true;
backwardHelperPoint.Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(-initialForwardDir_inUnitsOfGlobalSpace_normalized, false, null);
float initial_backwardWeightDistance_inUnitsOfGlobalSpace = bezierSplineDrawer_thisPointIsPartOf.TransformLength_fromUnitsOfActiveDrawSpace_toGlobalSpace(bezierSplineDrawer_thisPointIsPartOf.backwardWeightDistance_ofNewlyCreatedPoints_inUnitsOfActiveDrawSpace);
Vector3 initialPos_ofBackwardHelperPoint_inUnitsOfGlobalSpace = initialPos_inUnitsOfGlobalSpace - initialForwardDir_inUnitsOfGlobalSpace_normalized * initial_backwardWeightDistance_inUnitsOfGlobalSpace;
backwardHelperPoint.SetPos_inUnitsOfGlobalSpace(initialPos_ofBackwardHelperPoint_inUnitsOfGlobalSpace, false, null);
backwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(initial_backwardWeightDistance_inUnitsOfGlobalSpace, false, null);
}
public void ReassignIndexInsideControlPointsList(int new_i)
{
i_ofThisPoint_insideControlPointsList = new_i;
if (anchorPoint != null) //-> skipping newly created points (whose sub points don't exist yet). They get the value in the "controlPointTriplet.Initialize()" function
{
anchorPoint.ReassignIndexInsideControlPointsList(new_i);
}
if (forwardHelperPoint != null) //-> skipping newly created points (whose sub points don't exist yet). They get the value in the "controlPointTriplet.Initialize()" function
{
forwardHelperPoint.ReassignIndexInsideControlPointsList(new_i);
}
if (backwardHelperPoint != null) //-> skipping newly created points (whose sub points don't exist yet). They get the value in the "controlPointTriplet.Initialize()" function
{
backwardHelperPoint.ReassignIndexInsideControlPointsList(new_i);
}
}
public InternalDXXL_BezierControlHelperSubPoint GetAHelperPoint(bool requestedHelperPoint_isForward_notBackward)
{
if (requestedHelperPoint_isForward_notBackward)
{
return forwardHelperPoint;
}
else
{
return backwardHelperPoint;
}
}
public InternalDXXL_BezierControlSubPoint GetASubPoint(InternalDXXL_BezierControlSubPoint.SubPointType typeOfRequestedSubPoint)
{
switch (typeOfRequestedSubPoint)
{
case InternalDXXL_BezierControlSubPoint.SubPointType.backwardHelper:
return backwardHelperPoint;
case InternalDXXL_BezierControlSubPoint.SubPointType.anchor:
return anchorPoint;
case InternalDXXL_BezierControlSubPoint.SubPointType.forwardHelper:
return forwardHelperPoint;
default:
return anchorPoint;
}
}
public bool IsFirstControlPoint()
{
return bezierSplineDrawer_thisPointIsPartOf.IsFirstControlPoint(this);
}
public bool IsLastControlPoint()
{
return bezierSplineDrawer_thisPointIsPartOf.IsLastControlPoint(this);
}
public InternalDXXL_BezierControlPointTriplet GetNextControlPointTripletAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
return bezierSplineDrawer_thisPointIsPartOf.GetNextControlPointTriplet(this, allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
public InternalDXXL_BezierControlPointTriplet GetPreviousControlPointTripletAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
return bezierSplineDrawer_thisPointIsPartOf.GetPreviousControlPointTriplet(this, allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
public void Save_currentPosConfigInUnitsOfGlobalSpace_as_posConfigAfterSpaceChangeInUnitsOfGlobalSpace()
{
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.anchorPos = anchorPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toForward_normalized = anchorPoint.Get_direction_toForward_inUnitsOfGlobalSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toBackward_normalized = anchorPoint.Get_direction_toBackward_inUnitsOfGlobalSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.forwardHelperPos = forwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToForwardAnchorPoint = forwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.backwardHelperPos = backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToBackwardAnchorPoint = backwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfGlobalSpace();
}
public void Save_currentPosConfigInUnitsOfActiveDrawSpace_as_posConfigAfterSpaceChangeInUnitsOfActiveDrawSpace()
{
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.anchorPos = anchorPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toForward_normalized = anchorPoint.Get_direction_toForward_inUnitsOfActiveDrawSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toBackward_normalized = anchorPoint.Get_direction_toBackward_inUnitsOfActiveDrawSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.forwardHelperPos = forwardHelperPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToForwardAnchorPoint = forwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.backwardHelperPos = backwardHelperPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToBackwardAnchorPoint = backwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace();
}
public void Save_currentPosConfigInUnitsOfActiveDrawSpace_as_posConfigAfterSpaceChangeInUnitsOfGlobalSpace()
{
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.anchorPos = anchorPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toForward_normalized = anchorPoint.Get_direction_toForward_inUnitsOfActiveDrawSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toBackward_normalized = anchorPoint.Get_direction_toBackward_inUnitsOfActiveDrawSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.forwardHelperPos = forwardHelperPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToForwardAnchorPoint = forwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.backwardHelperPos = backwardHelperPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToBackwardAnchorPoint = backwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace();
}
public void Save_currentPosConfigInUnitsOfGlobalSpace_as_posConfigAfterSpaceChangeInUnitsOfActiveDrawSpace()
{
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.anchorPos = anchorPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toForward_normalized = anchorPoint.Get_direction_toForward_inUnitsOfGlobalSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toBackward_normalized = anchorPoint.Get_direction_toBackward_inUnitsOfGlobalSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.forwardHelperPos = forwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToForwardAnchorPoint = forwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.backwardHelperPos = backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToBackwardAnchorPoint = backwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfGlobalSpace();
}
public void ApplySaved_posConfigAfterSpaceChangeInUnitsOfGlobalSpace()
{
anchorPoint.SetPos_inUnitsOfGlobalSpace(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.anchorPos, false, null);
anchorPoint.Set_direction_toForward_inUnitsOfGlobalSpace_normalized(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toForward_normalized, false, null);
anchorPoint.Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toBackward_normalized, false, null);
forwardHelperPoint.SetPos_inUnitsOfGlobalSpace(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.forwardHelperPos, false, null);
forwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToForwardAnchorPoint, false, null);
backwardHelperPoint.SetPos_inUnitsOfGlobalSpace(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.backwardHelperPos, false, null);
backwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToBackwardAnchorPoint, false, null);
}
public void ApplySaved_posConfigAfterSpaceChangeInUnitsOfActiveDrawSpace()
{
anchorPoint.SetPos_inUnitsOfActiveDrawSpace(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.anchorPos, false, null);
anchorPoint.Set_direction_toForward_inUnitsOfActiveDrawSpace_normalized(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toForward_normalized, false, null);
anchorPoint.Set_direction_toBackward_inUnitsOfActiveDrawSpace_normalized(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toBackward_normalized, false, null);
forwardHelperPoint.SetPos_inUnitsOfActiveDrawSpace(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.forwardHelperPos, false, null);
forwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToForwardAnchorPoint, false, null);
backwardHelperPoint.SetPos_inUnitsOfActiveDrawSpace(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.backwardHelperPos, false, null);
backwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToBackwardAnchorPoint, false, null);
}
public bool IsEndPointToVoid_atStartOrEndOfAnUnclosedSpline()
{
if (bezierSplineDrawer_thisPointIsPartOf.gapFromEndToStart_isClosed == false)
{
if (IsFirstControlPoint() || IsLastControlPoint())
{
return true;
}
}
return false;
}
public bool IsPartOfThisTriplet(InternalDXXL_BezierControlSubPoint subPointToCheckIfItIsPartOfThisTriplet)
{
if (subPointToCheckIfItIsPartOfThisTriplet == backwardHelperPoint)
{
return true;
}
if (subPointToCheckIfItIsPartOfThisTriplet == anchorPoint)
{
return true;
}
if (subPointToCheckIfItIsPartOfThisTriplet == forwardHelperPoint)
{
return true;
}
return false;
}
public bool CheckIf_foldableHelperPoints_areUnfolded_inTheInspectorList()
{
if (backwardHelperPoint.IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
//-> not foldable
}
else
{
if (backwardHelperPoint.isOutfoldedInInspector == false)
{
return false;
}
}
if (forwardHelperPoint.IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
//-> not foldable
}
else
{
if (forwardHelperPoint.isOutfoldedInInspector == false)
{
return false;
}
}
return true;
}
public bool CheckIf_foldableHelperPoints_areCollapsed_inTheInspectorList()
{
if (backwardHelperPoint.IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
//-> not foldable
}
else
{
if (backwardHelperPoint.isOutfoldedInInspector)
{
return false;
}
}
if (forwardHelperPoint.IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
//-> not foldable
}
else
{
if (forwardHelperPoint.isOutfoldedInInspector)
{
return false;
}
}
return true;
}
public void UnfoldBothHelperPointInTheInspectorList()
{
backwardHelperPoint.isOutfoldedInInspector = true;
forwardHelperPoint.isOutfoldedInInspector = true;
}
public void CollapseBothHelperPointInTheInspectorList()
{
backwardHelperPoint.isOutfoldedInInspector = false;
forwardHelperPoint.isOutfoldedInInspector = false;
}
public Vector3 GetPosAtPlusButton_onUpcomingBezierSegment_inUnitsOfGlobalSpace()
{
return GetAPos_onUpcomingBezierSegment_inUnitsOfGlobalSpace(progress0to1_ofPlusButtonPosition_inUpcomingBezierSegment);
}
public Vector3 GetAPos_onUpcomingBezierSegment_inUnitsOfGlobalSpace(float progress0to1_inUpcomingBezierSegment)
{
InternalDXXL_BezierControlPointTriplet nextControlPointTriplet = GetNextControlPointTripletAlongSplineDir(true);
if (nextControlPointTriplet == null)
{
return anchorPoint.GetPos_inUnitsOfGlobalSpace();
}
else
{
Vector3 segmentStartPos = anchorPoint.GetPos_inUnitsOfGlobalSpace();
Vector3 segmentEndPos = nextControlPointTriplet.anchorPoint.GetPos_inUnitsOfGlobalSpace();
if (forwardHelperPoint.isUsed == true)
{
Vector3 firstControlPosInBetween = forwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
if (nextControlPointTriplet.backwardHelperPoint.isUsed == true)
{
Vector3 secondControlPosInBetween = nextControlPointTriplet.backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
return GetPos_onCubicBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, firstControlPosInBetween, secondControlPosInBetween, segmentEndPos);
}
else
{
return GetPos_onQuadraticBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, firstControlPosInBetween, segmentEndPos);
}
}
else
{
if (nextControlPointTriplet.backwardHelperPoint.isUsed == true)
{
Vector3 theSingleControlPosInBetween = nextControlPointTriplet.backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
return GetPos_onQuadraticBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, theSingleControlPosInBetween, segmentEndPos);
}
else
{
//straight line:
Vector3 fromStart_toEnd = segmentEndPos - segmentStartPos;
return (segmentStartPos + fromStart_toEnd * progress0to1_inUpcomingBezierSegment);
}
}
}
}
Vector3 GetPos_onQuadraticBezierSegment(float progress_0to1, Vector3 segmentStartPos, Vector3 controlPosInBetween, Vector3 segmentEndPos)
{
float oneMinusProgress0to1 = 1.0f - progress_0to1;
float factor1 = oneMinusProgress0to1 * oneMinusProgress0to1;
float factor2 = 2.0f * oneMinusProgress0to1 * progress_0to1;
float factor3 = progress_0to1 * progress_0to1;
return (factor1 * segmentStartPos + factor2 * controlPosInBetween + factor3 * segmentEndPos);
}
Vector3 GetPos_onCubicBezierSegment(float progress_0to1, Vector3 segmentStartPos, Vector3 firstControlPosInBetween, Vector3 secondControlPosInBetween, Vector3 segmentEndPos)
{
float progress_0to1_sqr = progress_0to1 * progress_0to1;
float oneMinusProgress0to1 = 1.0f - progress_0to1;
float oneMinusProgress0to1_sqr = oneMinusProgress0to1 * oneMinusProgress0to1;
float factor1 = oneMinusProgress0to1 * oneMinusProgress0to1_sqr;
float factor2 = 3.0f * oneMinusProgress0to1_sqr * progress_0to1;
float factor3 = 3.0f * oneMinusProgress0to1 * progress_0to1_sqr;
float factor4 = progress_0to1 * progress_0to1_sqr;
return (factor1 * segmentStartPos + factor2 * firstControlPosInBetween + factor3 * secondControlPosInBetween + factor4 * segmentEndPos);
}
public Vector3 GetTangentAtPlusButton_onUpcomingBezierSegment_inUnitsOfGlobalSpace(bool normalized)
{
return GetATangent_onUpcomingBezierSegment_inUnitsOfGlobalSpace(progress0to1_ofPlusButtonPosition_inUpcomingBezierSegment, normalized);
}
public Vector3 GetATangent_onUpcomingBezierSegment_inUnitsOfGlobalSpace(float progress0to1_inUpcomingBezierSegment, bool normalized)
{
InternalDXXL_BezierControlPointTriplet nextControlPointTriplet = GetNextControlPointTripletAlongSplineDir(true);
if (nextControlPointTriplet == null)
{
return bezierSplineDrawer_thisPointIsPartOf.Get_forwardTangent_ofControlPointThatDoesntKnowOfANextOne_inUnitsOfGlobalSpace_normalized(this);
}
else
{
Vector3 tangent_notNormalized;
Vector3 segmentStartPos = anchorPoint.GetPos_inUnitsOfGlobalSpace();
Vector3 segmentEndPos = nextControlPointTriplet.anchorPoint.GetPos_inUnitsOfGlobalSpace();
if (forwardHelperPoint.isUsed == true)
{
Vector3 firstControlPosInBetween = forwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
if (nextControlPointTriplet.backwardHelperPoint.isUsed == true)
{
Vector3 secondControlPosInBetween = nextControlPointTriplet.backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
tangent_notNormalized = GetTangent_onCubicBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, firstControlPosInBetween, secondControlPosInBetween, segmentEndPos);
}
else
{
tangent_notNormalized = GetTangent_onQuadraticBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, firstControlPosInBetween, segmentEndPos);
}
}
else
{
if (nextControlPointTriplet.backwardHelperPoint.isUsed == true)
{
Vector3 theSingleControlPosInBetween = nextControlPointTriplet.backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
tangent_notNormalized = GetTangent_onQuadraticBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, theSingleControlPosInBetween, segmentEndPos);
}
else
{
//straight line:
Vector3 fromStart_toEnd = segmentEndPos - segmentStartPos;
if (UtilitiesDXXL_Math.ApproximatelyZero(fromStart_toEnd))
{
return bezierSplineDrawer_thisPointIsPartOf.Get_forwardTangent_ofControlPointThatDoesntKnowOfANextOne_inUnitsOfGlobalSpace_normalized(this);
}
else
{
tangent_notNormalized = fromStart_toEnd;
}
}
}
if (normalized)
{
Vector3 tangent_normalized = UtilitiesDXXL_Math.GetNormalized_afterScalingIntoRegionOfFloatPrecicion(tangent_notNormalized);
if (UtilitiesDXXL_Math.CheckIfNormalizationFailed_meaningLineStayedTooShort(tangent_normalized))
{
return bezierSplineDrawer_thisPointIsPartOf.Get_forward_ofActiveDrawSpace_inUnitsOfGlobalSpace_normalized();
}
else
{
return tangent_normalized;
}
}
else
{
return tangent_notNormalized;
}
}
}
Vector3 GetTangent_onQuadraticBezierSegment(float progress_0to1, Vector3 segmentStartPos, Vector3 controlPosInBetween, Vector3 segmentEndPos)
{
return (2.0f * (1.0f - progress_0to1) * (controlPosInBetween - segmentStartPos) + 2.0f * progress_0to1 * (segmentEndPos - controlPosInBetween));
}
Vector3 GetTangent_onCubicBezierSegment(float progress_0to1, Vector3 segmentStartPos, Vector3 firstControlPosInBetween, Vector3 secondControlPosInBetween, Vector3 segmentEndPos)
{
float progress_0to1_sqr = progress_0to1 * progress_0to1;
float oneMinusProgress0to1 = 1.0f - progress_0to1;
return (3.0f * oneMinusProgress0to1 * oneMinusProgress0to1 * (firstControlPosInBetween - segmentStartPos) + (6.0f * oneMinusProgress0to1 * progress_0to1) * (secondControlPosInBetween - firstControlPosInBetween) + 3.0f * progress_0to1_sqr * (segmentEndPos - secondControlPosInBetween));
}
public void Invert_alignedHelperPoints_areOnTheSameSideOfTheAnchor()
{
alignedHelperPoints_areOnTheSameSideOfTheAnchor = !alignedHelperPoints_areOnTheSameSideOfTheAnchor;
}
public void DrawValuesToInspector()
{
TryHighlightThisControlPoint_dueToMouseClickOnItInInspector();
DrawBackgroundArea_forInspector();
DrawSubPoints_forInspector();
}
void TryHighlightThisControlPoint_dueToMouseClickOnItInInspector()
{
Event currentEvent = Event.current;
if (currentEvent.type == EventType.MouseDown)
{
if (inspectorRect_reservedForThisTriplet.Contains(currentEvent.mousePosition))
{
bezierSplineDrawer_thisPointIsPartOf.SetSelectedListSlot(i_ofThisPoint_insideControlPointsList);
bezierSplineDrawer_thisPointIsPartOf.SheduleSceneViewRepaint();
}
}
}
void DrawBackgroundArea_forInspector()
{
Rect space_ofBigBackgroundColorRect = new Rect(Get_xPos_ofBackgroundRect(inspectorRect_reservedForThisTriplet), Get_yPos_ofBackgroundRect(inspectorRect_reservedForThisTriplet), Get_width_ofBackgroundRect(inspectorRect_reservedForThisTriplet), inspectorRect_reservedForThisTriplet.height - 2.0f * Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() - Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint());
float alphaFactor_ofBackgroundColor = isHighlighted ? alpha_ofInspectorBackgroundColor_highlighted : alpha_ofInspectorBackgroundColor_nonHighlighted;
Color backgroundColor = UtilitiesDXXL_Colors.Get_color_butWithAdjustedAlpha(bezierSplineDrawer_thisPointIsPartOf.color_ofAnchorPoints, alphaFactor_ofBackgroundColor);
DrawBackgroundColor_forInspector(space_ofBigBackgroundColorRect, backgroundColor);
//See also "Get_xPos_ofPlusAndMinusButtonRect()":
//float y_of_minusButton = position.y + position.height - inspectorVertSpace_from_mainRect_to_backgroundColorBox - inspectorVertSpace_ofMinusButtonOnEachControlPoint; //-> float calculation imprecision errors seems to introduce overlap offsets of 1 pixel when calculated like this
//float y_of_minusButton = space_ofBigBackgroundColorRect.y + space_ofBigBackgroundColorRect.height; //-> this also is not solving the 1 pixel overlap offset
//float y_of_minusButton = space_ofBigBackgroundColorRect.yMax; //-> this also is not solving the 1 pixel overlap offset
float y_of_minusButton = space_ofBigBackgroundColorRect.yMax + 1.0f; //-> fixing it manually (with the risk of adding an empty pixel line if there are situations where the problem doesn't occur)
DrawMinusButton_forInspector(backgroundColor, y_of_minusButton);
DrawIndexNumber_forInspector(backgroundColor, y_of_minusButton);
}
void DrawBackgroundColor_forInspector(Rect space_ofBigBackgroundColorRect, Color backgroundColor)
{
#if UNITY_EDITOR
UnityEditor.EditorGUI.DrawRect(space_ofBigBackgroundColorRect, backgroundColor);
#endif
}
void DrawMinusButton_forInspector(Color backgroundColor, float y_of_minusButton)
{
#if UNITY_EDITOR
Rect space_ofMinusButtonBackground = new Rect(Get_xPos_ofPlusAndMinusButtonRect(inspectorRect_reservedForThisTriplet), y_of_minusButton, Get_width_ofPlusAndMinusButtons(), Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint());
UnityEditor.EditorGUI.DrawRect(space_ofMinusButtonBackground, backgroundColor);
GUIContent minusSymbolIcon = UnityEditor.EditorGUIUtility.TrIconContent("Toolbar Minus", "Delete control point");
GUIStyle style_ofMinusButton = "RL FooterButton";
minusButtonAtThisListItem_hasBeenClickedInInspector = GUI.Button(space_ofMinusButtonBackground, minusSymbolIcon, style_ofMinusButton);
#endif
}
void DrawIndexNumber_forInspector(Color backgroundColor, float y_of_minusButton)
{
#if UNITY_EDITOR
float horizSpace_betweenSlotIndexNumber_and_minusButton = 0.5f * UnityEditor.EditorGUIUtility.singleLineHeight;
float horizPadding_besideIndexNumberInsideNumberRect_perSide = 0.5f * UnityEditor.EditorGUIUtility.singleLineHeight;
float horizPadding_besideIndexNumberInsideNumberRect_forBothSides = 2.0f * horizPadding_besideIndexNumberInsideNumberRect_perSide;
float width_perNumberDigit = 0.6f * UnityEditor.EditorGUIUtility.singleLineHeight;
float width_ofSlotIndexNumberRect = horizPadding_besideIndexNumberInsideNumberRect_forBothSides + width_perNumberDigit * GetNumberOfDigitsInIndexNumber();
Rect space_ofSlotIndexNumberBackground = new Rect(inspectorRect_reservedForThisTriplet.x + inspectorRect_reservedForThisTriplet.width - Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() - Get_width_ofPlusAndMinusButtons() - horizSpace_betweenSlotIndexNumber_and_minusButton - width_ofSlotIndexNumberRect, y_of_minusButton, width_ofSlotIndexNumberRect, Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint());
UnityEditor.EditorGUI.DrawRect(space_ofSlotIndexNumberBackground, backgroundColor);
GUIStyle style_ofNumber = new GUIStyle();
Color color_ofNumber;
if (isHighlighted)
{
color_ofNumber = UtilitiesDXXL_Colors.GetSimilarColorWithOtherBrightnessValue(bezierSplineDrawer_thisPointIsPartOf.color_ofAnchorPoints, 0.375f);
}
else
{
color_ofNumber = UtilitiesDXXL_Colors.Get_color_butWithAdjustedAlpha(bezierSplineDrawer_thisPointIsPartOf.color_ofAnchorPoints, 0.725f);
}
string textString_ofNumber = "<size=16><color=#" + ColorUtility.ToHtmlStringRGBA(color_ofNumber) + "><b>" + i_ofThisPoint_insideControlPointsList + "</b></color></size>";
float y_offset_ofSlotIndexNumber = -0.1f * UnityEditor.EditorGUIUtility.singleLineHeight;
Rect space_ofSlotIndexNumber = new Rect(space_ofSlotIndexNumberBackground.x + horizPadding_besideIndexNumberInsideNumberRect_perSide, space_ofSlotIndexNumberBackground.y + y_offset_ofSlotIndexNumber, space_ofSlotIndexNumberBackground.width - horizPadding_besideIndexNumberInsideNumberRect_forBothSides, space_ofSlotIndexNumberBackground.height);
UnityEditor.EditorGUI.LabelField(space_ofSlotIndexNumber, textString_ofNumber, style_ofNumber);
#endif
}
int GetNumberOfDigitsInIndexNumber()
{
if (i_ofThisPoint_insideControlPointsList >= 10000)
{
return 5;
}
else
{
if (i_ofThisPoint_insideControlPointsList >= 1000)
{
return 4;
}
else
{
if (i_ofThisPoint_insideControlPointsList >= 100)
{
return 3;
}
else
{
if (i_ofThisPoint_insideControlPointsList >= 10)
{
return 2;
}
else
{
return 1;
}
}
}
}
}
void DrawSubPoints_forInspector()
{
float height_ofBackwardHelper = backwardHelperPoint.GetPropertyHeightForInspectorList();
float height_ofAnchor = anchorPoint.GetPropertyHeightForInspectorList();
float height_ofForwardHelper = forwardHelperPoint.GetPropertyHeightForInspectorList();
float x_ofHelperPointsColorBox = inspectorRect_reservedForThisTriplet.x + Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge();
float width_ofHelperPointsColorBox = inspectorRect_reservedForThisTriplet.width - 2.0f * Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() - 2.0f * Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge();
float currentHeightOffset = 0.0f;
currentHeightOffset += Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox();
currentHeightOffset += Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge();
Rect rect_of_backwardHelperPoint = new Rect(x_ofHelperPointsColorBox, inspectorRect_reservedForThisTriplet.y + currentHeightOffset, width_ofHelperPointsColorBox, height_ofBackwardHelper);
currentHeightOffset += height_ofBackwardHelper;
currentHeightOffset += Get_inspectorVertSpace_betweenSubPoints();
float x_ofAnchorPointsSubProperty = inspectorRect_reservedForThisTriplet.x + Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge() + InternalDXXL_BezierControlHelperSubPoint.Get_inspectorHorizSpace_between_subPointColorBoxEdge_and_actualContenFields();
float width_ofAnchorPointsSubProperty = inspectorRect_reservedForThisTriplet.width - 2.0f * Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() - 2.0f * Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge() - 2.0f * InternalDXXL_BezierControlHelperSubPoint.Get_inspectorHorizSpace_between_subPointColorBoxEdge_and_actualContenFields();
Rect rect_of_anchorPoint = new Rect(x_ofAnchorPointsSubProperty, inspectorRect_reservedForThisTriplet.y + currentHeightOffset, width_ofAnchorPointsSubProperty, height_ofAnchor);
currentHeightOffset += height_ofAnchor;
currentHeightOffset += Get_inspectorVertSpace_betweenSubPoints();
Rect rect_of_forwardHelperPoint = new Rect(x_ofHelperPointsColorBox, inspectorRect_reservedForThisTriplet.y + currentHeightOffset, width_ofHelperPointsColorBox, height_ofForwardHelper);
backwardHelperPoint.DrawValuesToInspector(rect_of_backwardHelperPoint);
anchorPoint.DrawValuesToInspector(rect_of_anchorPoint);
forwardHelperPoint.DrawValuesToInspector(rect_of_forwardHelperPoint);
}
public bool TryApplyChangesAfterInspectorInput()
{
bool didChangeSomething;
didChangeSomething = backwardHelperPoint.TryApplyChangesAfterInspectorInput();
if (didChangeSomething) { return true; }
didChangeSomething = anchorPoint.TryApplyChangesAfterInspectorInput();
if (didChangeSomething) { return true; }
didChangeSomething = forwardHelperPoint.TryApplyChangesAfterInspectorInput();
if (didChangeSomething) { return true; }
return false;
}
public float GetPropertyHeightForInspectorList()
{
float height_ofBackwardHelper = backwardHelperPoint.GetPropertyHeightForInspectorList();
float height_ofAnchor = anchorPoint.GetPropertyHeightForInspectorList();
float height_ofForwardHelper = forwardHelperPoint.GetPropertyHeightForInspectorList();
float additionalHeight = Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge() + Get_inspectorVertSpace_betweenSubPoints() + Get_inspectorVertSpace_betweenSubPoints() + Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge() + Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint() + Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox();
return (height_ofBackwardHelper + height_ofAnchor + height_ofForwardHelper + additionalHeight);
}
public static void DrawEmptyControlPointHoldingOnlyAPlusButton_forInspector(out bool plusButtonBelowListOfControlPoints_hasBeenClicked, out bool unfoldAllWeightsBelowListOfControlPoints_hasBeenClicked, out bool collapseAllWeightsBelowListOfControlPoints_hasBeenClicked, Rect position, Color color_ofAnchorPoints, GUIContent plusSymbolIcon, bool greyOutUnfoldAllButton, bool greyOutCollapseAllButton)
{
#if UNITY_EDITOR
Color backgroundColor = UtilitiesDXXL_Colors.Get_color_butWithAdjustedAlpha(color_ofAnchorPoints, alpha_ofInspectorBackgroundColor_nonHighlighted);
Rect rect_ofEmptyLine = new Rect(Get_xPos_ofBackgroundRect(position), Get_yPos_ofBackgroundRect(position), Get_width_ofBackgroundRect(position), Get_inspectorVertSpace_ofEmptyLineOfEmptyControlPointHoldingOnlyAPlusButton());
UnityEditor.EditorGUI.DrawRect(rect_ofEmptyLine, backgroundColor);
Rect rect_ofPlusButtonBelowEmptyLine = new Rect(Get_xPos_ofPlusAndMinusButtonRect(position), position.y + Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorVertSpace_ofEmptyLineOfEmptyControlPointHoldingOnlyAPlusButton(), Get_width_ofPlusAndMinusButtons(), Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint());
UnityEditor.EditorGUI.DrawRect(rect_ofPlusButtonBelowEmptyLine, backgroundColor);
GUIStyle style_ofMinusButton = "RL FooterButton";
plusButtonBelowListOfControlPoints_hasBeenClicked = GUI.Button(rect_ofPlusButtonBelowEmptyLine, plusSymbolIcon, style_ofMinusButton);
Rect rect_ofBothFoldAllButtons = new Rect(Get_xPos_ofBackgroundRect(position), position.y + Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorVertSpace_ofEmptyLineOfEmptyControlPointHoldingOnlyAPlusButton() + Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint() + Get_additionalInspectorVertSpace_belowEmptyPlusLine_tillFoldAllButtons(), Get_width_ofBackgroundRect(position), Get_inspectorVertSpace_forFoldAllButtons());
float halfHorizSpaceBetweenButtons = 0.5f * Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox();
Rect rect_ofUnfoldAllButton = new Rect(rect_ofBothFoldAllButtons.x, rect_ofBothFoldAllButtons.y, rect_ofBothFoldAllButtons.width * 0.5f - halfHorizSpaceBetweenButtons, rect_ofBothFoldAllButtons.height);
Rect rect_ofCollapseAllButton = new Rect(rect_ofBothFoldAllButtons.x + rect_ofBothFoldAllButtons.width * 0.5f + halfHorizSpaceBetweenButtons, rect_ofBothFoldAllButtons.y, rect_ofBothFoldAllButtons.width * 0.5f - halfHorizSpaceBetweenButtons, rect_ofBothFoldAllButtons.height);
GUIStyle style_ofUnfoldAllButtons = new GUIStyle(style_ofMinusButton);
style_ofUnfoldAllButtons.fontStyle = FontStyle.Normal;
Color color_ofAGreyedOut_foldAllButton = UtilitiesDXXL_Colors.Get_color_butWithAdjustedAlpha(backgroundColor, 0.5f);
Color color_ofUnfoldAllButton = greyOutUnfoldAllButton ? color_ofAGreyedOut_foldAllButton : backgroundColor;
UnityEditor.EditorGUI.DrawRect(rect_ofUnfoldAllButton, color_ofUnfoldAllButton);
UnityEditor.EditorGUI.BeginDisabledGroup(greyOutUnfoldAllButton);
unfoldAllWeightsBelowListOfControlPoints_hasBeenClicked = GUI.Button(rect_ofUnfoldAllButton, "Unfold all weights", style_ofUnfoldAllButtons);
UnityEditor.EditorGUI.EndDisabledGroup();
Color color_ofCollapseAllButton = greyOutCollapseAllButton ? color_ofAGreyedOut_foldAllButton : backgroundColor;
UnityEditor.EditorGUI.DrawRect(rect_ofCollapseAllButton, color_ofCollapseAllButton);
UnityEditor.EditorGUI.BeginDisabledGroup(greyOutCollapseAllButton);
collapseAllWeightsBelowListOfControlPoints_hasBeenClicked = GUI.Button(rect_ofCollapseAllButton, "Collapse all weights", style_ofUnfoldAllButtons);
UnityEditor.EditorGUI.EndDisabledGroup();
#else
plusButtonBelowListOfControlPoints_hasBeenClicked = false;
unfoldAllWeightsBelowListOfControlPoints_hasBeenClicked = false;
collapseAllWeightsBelowListOfControlPoints_hasBeenClicked = false;
#endif
}
public static float GetPropertyHeightForEmptyControlPointHoldingOnlyAPlusButtonAndFoldAllButtons()
{
return (Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorVertSpace_ofEmptyLineOfEmptyControlPointHoldingOnlyAPlusButton() + Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint() + Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() + Get_additionalInspectorVertSpace_belowEmptyPlusLine_tillFoldAllButtons() + Get_inspectorVertSpace_forFoldAllButtons() + Get_emptyInspectorVertSpace_belowFoldAllButtons());
}
static float Get_xPos_ofBackgroundRect(Rect inspectorRect_reservedForThisTriplet)
{
return (inspectorRect_reservedForThisTriplet.x + Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox());
}
static float Get_yPos_ofBackgroundRect(Rect inspectorRect_reservedForThisTriplet)
{
return (inspectorRect_reservedForThisTriplet.y + Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox());
}
static float Get_width_ofBackgroundRect(Rect inspectorRect_reservedForThisTriplet)
{
return (inspectorRect_reservedForThisTriplet.width - 2.0f * Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox());
}
static float Get_xPos_ofPlusAndMinusButtonRect(Rect inspectorRect_reservedForThisTriplet)
{
//-> similar problem as described in "DrawBackgroundArea()", where the yPos is shifted by 1 pixel.
//-> in this case the x-position is shifted by 1 pixel to the left.
float offsetForFixingTheOnePixelOffset = 1.0f; //-> fixing it manually (with the risk of introducing a horizontal one pixel offset if there are situations where the problem doesn't occur)
return (inspectorRect_reservedForThisTriplet.x + inspectorRect_reservedForThisTriplet.width - Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() - Get_width_ofPlusAndMinusButtons() + offsetForFixingTheOnePixelOffset);
}
static float Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge()
{
#if UNITY_EDITOR
return (0.2f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox()
{
#if UNITY_EDITOR
return (0.2f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorVertSpace_betweenSubPoints()
{
#if UNITY_EDITOR
return (2.0f * Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge());
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint()
{
#if UNITY_EDITOR
return (UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorVertSpace_ofEmptyLineOfEmptyControlPointHoldingOnlyAPlusButton()
{
#if UNITY_EDITOR
return (UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_additionalInspectorVertSpace_belowEmptyPlusLine_tillFoldAllButtons()
{
#if UNITY_EDITOR
return (0.5f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorVertSpace_forFoldAllButtons()
{
#if UNITY_EDITOR
return (UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_emptyInspectorVertSpace_belowFoldAllButtons()
{
#if UNITY_EDITOR
return (0.0f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_width_ofPlusAndMinusButtons()
{
#if UNITY_EDITOR
return (1.5f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox()
{
#if UNITY_EDITOR
return (0.2f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d578c9820a2e3104c889df00fc8d3bdf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,793 @@
namespace DrawXXL
{
using System;
using UnityEngine;
[Serializable]
public class InternalDXXL_BezierControlPointTriplet2D
{
public bool isHighlighted;
public int i_ofThisPoint_insideControlPointsList;
public BezierSplineDrawer2D bezierSplineDrawer_thisPointIsPartOf;
[SerializeField] public bool alignedHelperPoints_areOnTheSameSideOfTheAnchor;
[SerializeField] public float progress0to1_ofPlusButtonPosition_inUpcomingBezierSegment;
public InternalDXXL_BezierControlAnchorSubPoint2D anchorPoint;
public InternalDXXL_BezierControlHelperSubPoint2D forwardHelperPoint;
public InternalDXXL_BezierControlHelperSubPoint2D backwardHelperPoint;
InternalDXXL_BezierPointShapeConfig2D pointShape_afterSpaceChange_inUnitsOfGlobalSpace;
InternalDXXL_BezierPointShapeConfig2D pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace;
public Rect inspectorRect_reservedForThisTriplet;
public bool minusButtonAtThisListItem_hasBeenClickedInInspector = false;
public void Initialize(BezierSplineDrawer2D containingSplineDrawer, Vector2 initialPos_inUnitsOfGlobalSpace, Vector2 initialForwardDir_inUnitsOfGlobalSpace_normalized, InternalDXXL_BezierControlAnchorSubPoint.JunctureType junctureType)
{
bezierSplineDrawer_thisPointIsPartOf = containingSplineDrawer;
isHighlighted = false; //-> the caller has to decide whether and take care of highlighting newly created control points after this initialization
alignedHelperPoints_areOnTheSameSideOfTheAnchor = false;
progress0to1_ofPlusButtonPosition_inUpcomingBezierSegment = 0.5f;
anchorPoint = new InternalDXXL_BezierControlAnchorSubPoint2D();
anchorPoint.InitializeValuesThatAreIndependentFromOtherSubPoints(this);
anchorPoint.subPointType = InternalDXXL_BezierControlSubPoint.SubPointType.anchor;
anchorPoint.isUsed = true;
anchorPoint.junctureType = junctureType;
anchorPoint.SetPos_inUnitsOfGlobalSpace(initialPos_inUnitsOfGlobalSpace, false, null);
forwardHelperPoint = new InternalDXXL_BezierControlHelperSubPoint2D();
forwardHelperPoint.InitializeValuesThatAreIndependentFromOtherSubPoints(this);
forwardHelperPoint.subPointType = InternalDXXL_BezierControlSubPoint.SubPointType.forwardHelper;
forwardHelperPoint.isForward_notBackward = true;
forwardHelperPoint.isUsed = true;
forwardHelperPoint.Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(initialForwardDir_inUnitsOfGlobalSpace_normalized, false, null);
float initial_forwardWeightDistance_inUnitsOfGlobalSpace = bezierSplineDrawer_thisPointIsPartOf.TransformLength_fromUnitsOfActiveDrawSpace_toGlobalSpace(bezierSplineDrawer_thisPointIsPartOf.forwardWeightDistance_ofNewlyCreatedPoints_inUnitsOfActiveDrawSpace);
Vector2 initialPos_ofForwardHelperPoint_inUnitsOfGlobalSpace = initialPos_inUnitsOfGlobalSpace + initialForwardDir_inUnitsOfGlobalSpace_normalized * initial_forwardWeightDistance_inUnitsOfGlobalSpace;
forwardHelperPoint.SetPos_inUnitsOfGlobalSpace(initialPos_ofForwardHelperPoint_inUnitsOfGlobalSpace, false, null);
forwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(initial_forwardWeightDistance_inUnitsOfGlobalSpace, false, null);
backwardHelperPoint = new InternalDXXL_BezierControlHelperSubPoint2D();
backwardHelperPoint.InitializeValuesThatAreIndependentFromOtherSubPoints(this);
backwardHelperPoint.subPointType = InternalDXXL_BezierControlSubPoint.SubPointType.backwardHelper;
backwardHelperPoint.isForward_notBackward = false;
backwardHelperPoint.isUsed = true;
backwardHelperPoint.Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized(-initialForwardDir_inUnitsOfGlobalSpace_normalized, false, null);
float initial_backwardWeightDistance_inUnitsOfGlobalSpace = bezierSplineDrawer_thisPointIsPartOf.TransformLength_fromUnitsOfActiveDrawSpace_toGlobalSpace(bezierSplineDrawer_thisPointIsPartOf.backwardWeightDistance_ofNewlyCreatedPoints_inUnitsOfActiveDrawSpace);
Vector2 initialPos_ofBackwardHelperPoint_inUnitsOfGlobalSpace = initialPos_inUnitsOfGlobalSpace - initialForwardDir_inUnitsOfGlobalSpace_normalized * initial_backwardWeightDistance_inUnitsOfGlobalSpace;
backwardHelperPoint.SetPos_inUnitsOfGlobalSpace(initialPos_ofBackwardHelperPoint_inUnitsOfGlobalSpace, false, null);
backwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(initial_backwardWeightDistance_inUnitsOfGlobalSpace, false, null);
}
public void ReassignIndexInsideControlPointsList(int new_i)
{
i_ofThisPoint_insideControlPointsList = new_i;
if (anchorPoint != null) //-> skipping newly created points (whose sub points don't exist yet). They get the value in the "controlPointTriplet.Initialize()" function
{
anchorPoint.ReassignIndexInsideControlPointsList(new_i);
}
if (forwardHelperPoint != null) //-> skipping newly created points (whose sub points don't exist yet). They get the value in the "controlPointTriplet.Initialize()" function
{
forwardHelperPoint.ReassignIndexInsideControlPointsList(new_i);
}
if (backwardHelperPoint != null) //-> skipping newly created points (whose sub points don't exist yet). They get the value in the "controlPointTriplet.Initialize()" function
{
backwardHelperPoint.ReassignIndexInsideControlPointsList(new_i);
}
}
public InternalDXXL_BezierControlHelperSubPoint2D GetAHelperPoint(bool requestedHelperPoint_isForward_notBackward)
{
if (requestedHelperPoint_isForward_notBackward)
{
return forwardHelperPoint;
}
else
{
return backwardHelperPoint;
}
}
public InternalDXXL_BezierControlSubPoint2D GetASubPoint(InternalDXXL_BezierControlSubPoint.SubPointType typeOfRequestedSubPoint)
{
switch (typeOfRequestedSubPoint)
{
case InternalDXXL_BezierControlSubPoint.SubPointType.backwardHelper:
return backwardHelperPoint;
case InternalDXXL_BezierControlSubPoint.SubPointType.anchor:
return anchorPoint;
case InternalDXXL_BezierControlSubPoint.SubPointType.forwardHelper:
return forwardHelperPoint;
default:
return anchorPoint;
}
}
public bool IsFirstControlPoint()
{
return bezierSplineDrawer_thisPointIsPartOf.IsFirstControlPoint(this);
}
public bool IsLastControlPoint()
{
return bezierSplineDrawer_thisPointIsPartOf.IsLastControlPoint(this);
}
public InternalDXXL_BezierControlPointTriplet2D GetNextControlPointTripletAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
return bezierSplineDrawer_thisPointIsPartOf.GetNextControlPointTriplet(this, allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
public InternalDXXL_BezierControlPointTriplet2D GetPreviousControlPointTripletAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
return bezierSplineDrawer_thisPointIsPartOf.GetPreviousControlPointTriplet(this, allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
public void Save_currentPosConfigInUnitsOfGlobalSpace_as_posConfigAfterSpaceChangeInUnitsOfGlobalSpace()
{
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.anchorPos = anchorPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toForward_normalized = anchorPoint.Get_direction_toForward_inUnitsOfGlobalSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toBackward_normalized = anchorPoint.Get_direction_toBackward_inUnitsOfGlobalSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.forwardHelperPos = forwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToForwardAnchorPoint = forwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.backwardHelperPos = backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToBackwardAnchorPoint = backwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfGlobalSpace();
}
public void Save_currentPosConfigInUnitsOfActiveDrawSpace_as_posConfigAfterSpaceChangeInUnitsOfActiveDrawSpace()
{
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.anchorPos = anchorPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toForward_normalized = anchorPoint.Get_direction_toForward_inUnitsOfActiveDrawSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toBackward_normalized = anchorPoint.Get_direction_toBackward_inUnitsOfActiveDrawSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.forwardHelperPos = forwardHelperPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToForwardAnchorPoint = forwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.backwardHelperPos = backwardHelperPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToBackwardAnchorPoint = backwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace();
}
public void Save_currentPosConfigInUnitsOfActiveDrawSpace_as_posConfigAfterSpaceChangeInUnitsOfGlobalSpace()
{
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.anchorPos = anchorPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toForward_normalized = anchorPoint.Get_direction_toForward_inUnitsOfActiveDrawSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toBackward_normalized = anchorPoint.Get_direction_toBackward_inUnitsOfActiveDrawSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.forwardHelperPos = forwardHelperPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToForwardAnchorPoint = forwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.backwardHelperPos = backwardHelperPoint.GetPos_inUnitsOfActiveDrawSpace();
pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToBackwardAnchorPoint = backwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace();
}
public void Save_currentPosConfigInUnitsOfGlobalSpace_as_posConfigAfterSpaceChangeInUnitsOfActiveDrawSpace()
{
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.anchorPos = anchorPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toForward_normalized = anchorPoint.Get_direction_toForward_inUnitsOfGlobalSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toBackward_normalized = anchorPoint.Get_direction_toBackward_inUnitsOfGlobalSpace_normalized();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.forwardHelperPos = forwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToForwardAnchorPoint = forwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.backwardHelperPos = backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToBackwardAnchorPoint = backwardHelperPoint.Get_absDistanceToAnchorPoint_inUnitsOfGlobalSpace();
}
public void ApplySaved_posConfigAfterSpaceChangeInUnitsOfGlobalSpace()
{
anchorPoint.SetPos_inUnitsOfGlobalSpace(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.anchorPos, false, null);
anchorPoint.Set_direction_toForward_inUnitsOfGlobalSpace_normalized(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toForward_normalized, false, null);
anchorPoint.Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.direction_toBackward_normalized, false, null);
forwardHelperPoint.SetPos_inUnitsOfGlobalSpace(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.forwardHelperPos, false, null);
forwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToForwardAnchorPoint, false, null);
backwardHelperPoint.SetPos_inUnitsOfGlobalSpace(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.backwardHelperPos, false, null);
backwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfGlobalSpace(pointShape_afterSpaceChange_inUnitsOfGlobalSpace.absDistanceToBackwardAnchorPoint, false, null);
}
public void ApplySaved_posConfigAfterSpaceChangeInUnitsOfActiveDrawSpace()
{
anchorPoint.SetPos_inUnitsOfActiveDrawSpace(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.anchorPos, false, null);
anchorPoint.Set_direction_toForward_inUnitsOfActiveDrawSpace_normalized(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toForward_normalized, false, null);
anchorPoint.Set_direction_toBackward_inUnitsOfActiveDrawSpace_normalized(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.direction_toBackward_normalized, false, null);
forwardHelperPoint.SetPos_inUnitsOfActiveDrawSpace(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.forwardHelperPos, false, null);
forwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToForwardAnchorPoint, false, null);
backwardHelperPoint.SetPos_inUnitsOfActiveDrawSpace(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.backwardHelperPos, false, null);
backwardHelperPoint.Set_absDistanceToAnchorPoint_inUnitsOfActiveDrawSpace(pointShape_afterSpaceChange_inUnitsOfActiveDrawSpace.absDistanceToBackwardAnchorPoint, false, null);
}
public bool IsEndPointToVoid_atStartOrEndOfAnUnclosedSpline()
{
if (bezierSplineDrawer_thisPointIsPartOf.gapFromEndToStart_isClosed == false)
{
if (IsFirstControlPoint() || IsLastControlPoint())
{
return true;
}
}
return false;
}
public bool IsPartOfThisTriplet(InternalDXXL_BezierControlSubPoint2D subPointToCheckIfItIsPartOfThisTriplet)
{
if (subPointToCheckIfItIsPartOfThisTriplet == backwardHelperPoint)
{
return true;
}
if (subPointToCheckIfItIsPartOfThisTriplet == anchorPoint)
{
return true;
}
if (subPointToCheckIfItIsPartOfThisTriplet == forwardHelperPoint)
{
return true;
}
return false;
}
public bool CheckIf_foldableHelperPoints_areUnfolded_inTheInspectorList()
{
if (backwardHelperPoint.IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
//-> not foldable
}
else
{
if (backwardHelperPoint.isOutfoldedInInspector == false)
{
return false;
}
}
if (forwardHelperPoint.IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
//-> not foldable
}
else
{
if (forwardHelperPoint.isOutfoldedInInspector == false)
{
return false;
}
}
return true;
}
public bool CheckIf_foldableHelperPoints_areCollapsed_inTheInspectorList()
{
if (backwardHelperPoint.IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
//-> not foldable
}
else
{
if (backwardHelperPoint.isOutfoldedInInspector)
{
return false;
}
}
if (forwardHelperPoint.IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid())
{
//-> not foldable
}
else
{
if (forwardHelperPoint.isOutfoldedInInspector)
{
return false;
}
}
return true;
}
public void UnfoldBothHelperPointInTheInspectorList()
{
backwardHelperPoint.isOutfoldedInInspector = true;
forwardHelperPoint.isOutfoldedInInspector = true;
}
public void CollapseBothHelperPointInTheInspectorList()
{
backwardHelperPoint.isOutfoldedInInspector = false;
forwardHelperPoint.isOutfoldedInInspector = false;
}
public Vector2 GetPosAtPlusButton_onUpcomingBezierSegment_inUnitsOfGlobalSpace()
{
return GetAPos_onUpcomingBezierSegment_inUnitsOfGlobalSpace(progress0to1_ofPlusButtonPosition_inUpcomingBezierSegment);
}
public Vector2 GetAPos_onUpcomingBezierSegment_inUnitsOfGlobalSpace(float progress0to1_inUpcomingBezierSegment)
{
InternalDXXL_BezierControlPointTriplet2D nextControlPointTriplet = GetNextControlPointTripletAlongSplineDir(true);
if (nextControlPointTriplet == null)
{
return anchorPoint.GetPos_inUnitsOfGlobalSpace();
}
else
{
Vector2 segmentStartPos = anchorPoint.GetPos_inUnitsOfGlobalSpace();
Vector2 segmentEndPos = nextControlPointTriplet.anchorPoint.GetPos_inUnitsOfGlobalSpace();
if (forwardHelperPoint.isUsed == true)
{
Vector2 firstControlPosInBetween = forwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
if (nextControlPointTriplet.backwardHelperPoint.isUsed == true)
{
Vector2 secondControlPosInBetween = nextControlPointTriplet.backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
return GetPos_onCubicBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, firstControlPosInBetween, secondControlPosInBetween, segmentEndPos);
}
else
{
return GetPos_onQuadraticBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, firstControlPosInBetween, segmentEndPos);
}
}
else
{
if (nextControlPointTriplet.backwardHelperPoint.isUsed == true)
{
Vector2 theSingleControlPosInBetween = nextControlPointTriplet.backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
return GetPos_onQuadraticBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, theSingleControlPosInBetween, segmentEndPos);
}
else
{
//straight line:
Vector2 fromStart_toEnd = segmentEndPos - segmentStartPos;
return (segmentStartPos + fromStart_toEnd * progress0to1_inUpcomingBezierSegment);
}
}
}
}
Vector2 GetPos_onQuadraticBezierSegment(float progress_0to1, Vector2 segmentStartPos, Vector2 controlPosInBetween, Vector2 segmentEndPos)
{
float oneMinusProgress0to1 = 1.0f - progress_0to1;
float factor1 = oneMinusProgress0to1 * oneMinusProgress0to1;
float factor2 = 2.0f * oneMinusProgress0to1 * progress_0to1;
float factor3 = progress_0to1 * progress_0to1;
return (factor1 * segmentStartPos + factor2 * controlPosInBetween + factor3 * segmentEndPos);
}
Vector2 GetPos_onCubicBezierSegment(float progress_0to1, Vector2 segmentStartPos, Vector2 firstControlPosInBetween, Vector2 secondControlPosInBetween, Vector2 segmentEndPos)
{
float progress_0to1_sqr = progress_0to1 * progress_0to1;
float oneMinusProgress0to1 = 1.0f - progress_0to1;
float oneMinusProgress0to1_sqr = oneMinusProgress0to1 * oneMinusProgress0to1;
float factor1 = oneMinusProgress0to1 * oneMinusProgress0to1_sqr;
float factor2 = 3.0f * oneMinusProgress0to1_sqr * progress_0to1;
float factor3 = 3.0f * oneMinusProgress0to1 * progress_0to1_sqr;
float factor4 = progress_0to1 * progress_0to1_sqr;
return (factor1 * segmentStartPos + factor2 * firstControlPosInBetween + factor3 * secondControlPosInBetween + factor4 * segmentEndPos);
}
public Vector2 GetTangentAtPlusButton_onUpcomingBezierSegment_inUnitsOfGlobalSpace(bool normalized)
{
return GetATangent_onUpcomingBezierSegment_inUnitsOfGlobalSpace(progress0to1_ofPlusButtonPosition_inUpcomingBezierSegment, normalized);
}
public Vector2 GetATangent_onUpcomingBezierSegment_inUnitsOfGlobalSpace(float progress0to1_inUpcomingBezierSegment, bool normalized)
{
InternalDXXL_BezierControlPointTriplet2D nextControlPointTriplet = GetNextControlPointTripletAlongSplineDir(true);
if (nextControlPointTriplet == null)
{
return bezierSplineDrawer_thisPointIsPartOf.Get_forwardTangent_ofControlPointThatDoesntKnowOfANextOne_inUnitsOfGlobalSpace_normalized(this);
}
else
{
Vector2 tangent_notNormalized;
Vector2 segmentStartPos = anchorPoint.GetPos_inUnitsOfGlobalSpace();
Vector2 segmentEndPos = nextControlPointTriplet.anchorPoint.GetPos_inUnitsOfGlobalSpace();
if (forwardHelperPoint.isUsed == true)
{
Vector2 firstControlPosInBetween = forwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
if (nextControlPointTriplet.backwardHelperPoint.isUsed == true)
{
Vector2 secondControlPosInBetween = nextControlPointTriplet.backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
tangent_notNormalized = GetTangent_onCubicBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, firstControlPosInBetween, secondControlPosInBetween, segmentEndPos);
}
else
{
tangent_notNormalized = GetTangent_onQuadraticBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, firstControlPosInBetween, segmentEndPos);
}
}
else
{
if (nextControlPointTriplet.backwardHelperPoint.isUsed == true)
{
Vector2 theSingleControlPosInBetween = nextControlPointTriplet.backwardHelperPoint.GetPos_inUnitsOfGlobalSpace();
tangent_notNormalized = GetTangent_onQuadraticBezierSegment(progress0to1_inUpcomingBezierSegment, segmentStartPos, theSingleControlPosInBetween, segmentEndPos);
}
else
{
//straight line:
Vector2 fromStart_toEnd = segmentEndPos - segmentStartPos;
if (UtilitiesDXXL_Math.ApproximatelyZero(fromStart_toEnd))
{
return bezierSplineDrawer_thisPointIsPartOf.Get_forwardTangent_ofControlPointThatDoesntKnowOfANextOne_inUnitsOfGlobalSpace_normalized(this);
}
else
{
tangent_notNormalized = fromStart_toEnd;
}
}
}
if (normalized)
{
Vector2 tangent_normalized = UtilitiesDXXL_Math.GetNormalized_afterScalingIntoRegionOfFloatPrecicion(tangent_notNormalized);
if (UtilitiesDXXL_Math.CheckIfNormalizationFailed_meaningLineStayedTooShort(tangent_normalized))
{
return bezierSplineDrawer_thisPointIsPartOf.Get_right_ofActiveDrawSpace_inUnitsOfGlobalSpace_normalized();
}
else
{
return tangent_normalized;
}
}
else
{
return tangent_notNormalized;
}
}
}
Vector2 GetTangent_onQuadraticBezierSegment(float progress_0to1, Vector2 segmentStartPos, Vector2 controlPosInBetween, Vector2 segmentEndPos)
{
return (2.0f * (1.0f - progress_0to1) * (controlPosInBetween - segmentStartPos) + 2.0f * progress_0to1 * (segmentEndPos - controlPosInBetween));
}
Vector2 GetTangent_onCubicBezierSegment(float progress_0to1, Vector2 segmentStartPos, Vector2 firstControlPosInBetween, Vector2 secondControlPosInBetween, Vector2 segmentEndPos)
{
float progress_0to1_sqr = progress_0to1 * progress_0to1;
float oneMinusProgress0to1 = 1.0f - progress_0to1;
return (3.0f * oneMinusProgress0to1 * oneMinusProgress0to1 * (firstControlPosInBetween - segmentStartPos) + (6.0f * oneMinusProgress0to1 * progress_0to1) * (secondControlPosInBetween - firstControlPosInBetween) + 3.0f * progress_0to1_sqr * (segmentEndPos - secondControlPosInBetween));
}
public void Invert_alignedHelperPoints_areOnTheSameSideOfTheAnchor()
{
alignedHelperPoints_areOnTheSameSideOfTheAnchor = !alignedHelperPoints_areOnTheSameSideOfTheAnchor;
}
public void DrawValuesToInspector()
{
TryHighlightThisControlPoint_dueToMouseClickOnItInInspector();
DrawBackgroundArea_forInspector();
DrawSubPoints_forInspector();
}
void TryHighlightThisControlPoint_dueToMouseClickOnItInInspector()
{
Event currentEvent = Event.current;
if (currentEvent.type == EventType.MouseDown)
{
if (inspectorRect_reservedForThisTriplet.Contains(currentEvent.mousePosition))
{
bezierSplineDrawer_thisPointIsPartOf.SetSelectedListSlot(i_ofThisPoint_insideControlPointsList);
bezierSplineDrawer_thisPointIsPartOf.SheduleSceneViewRepaint();
}
}
}
void DrawBackgroundArea_forInspector()
{
Rect space_ofBigBackgroundColorRect = new Rect(Get_xPos_ofBackgroundRect(inspectorRect_reservedForThisTriplet), Get_yPos_ofBackgroundRect(inspectorRect_reservedForThisTriplet), Get_width_ofBackgroundRect(inspectorRect_reservedForThisTriplet), inspectorRect_reservedForThisTriplet.height - 2.0f * Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() - Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint());
float alphaFactor_ofBackgroundColor = isHighlighted ? InternalDXXL_BezierControlPointTriplet.alpha_ofInspectorBackgroundColor_highlighted : InternalDXXL_BezierControlPointTriplet.alpha_ofInspectorBackgroundColor_nonHighlighted;
Color backgroundColor = UtilitiesDXXL_Colors.Get_color_butWithAdjustedAlpha(bezierSplineDrawer_thisPointIsPartOf.color_ofAnchorPoints, alphaFactor_ofBackgroundColor);
DrawBackgroundColor_forInspector(space_ofBigBackgroundColorRect, backgroundColor);
//See also "Get_xPos_ofPlusAndMinusButtonRect()":
//float y_of_minusButton = position.y + position.height - inspectorVertSpace_from_mainRect_to_backgroundColorBox - inspectorVertSpace_ofMinusButtonOnEachControlPoint; //-> float calculation imprecision errors seems to introduce overlap offsets of 1 pixel when calculated like this
//float y_of_minusButton = space_ofBigBackgroundColorRect.y + space_ofBigBackgroundColorRect.height; //-> this also is not solving the 1 pixel overlap offset
//float y_of_minusButton = space_ofBigBackgroundColorRect.yMax; //-> this also is not solving the 1 pixel overlap offset
float y_of_minusButton = space_ofBigBackgroundColorRect.yMax + 1.0f; //-> fixing it manually (with the risk of adding an empty pixel line if there are situations where the problem doesn't occur)
DrawMinusButton_forInspector(backgroundColor, y_of_minusButton);
DrawIndexNumber_forInspector(backgroundColor, y_of_minusButton);
}
void DrawBackgroundColor_forInspector(Rect space_ofBigBackgroundColorRect, Color backgroundColor)
{
#if UNITY_EDITOR
UnityEditor.EditorGUI.DrawRect(space_ofBigBackgroundColorRect, backgroundColor);
#endif
}
void DrawMinusButton_forInspector(Color backgroundColor, float y_of_minusButton)
{
#if UNITY_EDITOR
Rect space_ofMinusButtonBackground = new Rect(Get_xPos_ofPlusAndMinusButtonRect(inspectorRect_reservedForThisTriplet), y_of_minusButton, Get_width_ofPlusAndMinusButtons(), Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint());
UnityEditor.EditorGUI.DrawRect(space_ofMinusButtonBackground, backgroundColor);
GUIContent minusSymbolIcon = UnityEditor.EditorGUIUtility.TrIconContent("Toolbar Minus", "Delete control point");
GUIStyle style_ofMinusButton = "RL FooterButton";
minusButtonAtThisListItem_hasBeenClickedInInspector = GUI.Button(space_ofMinusButtonBackground, minusSymbolIcon, style_ofMinusButton);
#endif
}
void DrawIndexNumber_forInspector(Color backgroundColor, float y_of_minusButton)
{
#if UNITY_EDITOR
float horizSpace_betweenSlotIndexNumber_and_minusButton = 0.5f * UnityEditor.EditorGUIUtility.singleLineHeight;
float horizPadding_besideIndexNumberInsideNumberRect_perSide = 0.5f * UnityEditor.EditorGUIUtility.singleLineHeight;
float horizPadding_besideIndexNumberInsideNumberRect_forBothSides = 2.0f * horizPadding_besideIndexNumberInsideNumberRect_perSide;
float width_perNumberDigit = 0.6f * UnityEditor.EditorGUIUtility.singleLineHeight;
float width_ofSlotIndexNumberRect = horizPadding_besideIndexNumberInsideNumberRect_forBothSides + width_perNumberDigit * GetNumberOfDigitsInIndexNumber();
Rect space_ofSlotIndexNumberBackground = new Rect(inspectorRect_reservedForThisTriplet.x + inspectorRect_reservedForThisTriplet.width - Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() - Get_width_ofPlusAndMinusButtons() - horizSpace_betweenSlotIndexNumber_and_minusButton - width_ofSlotIndexNumberRect, y_of_minusButton, width_ofSlotIndexNumberRect, Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint());
UnityEditor.EditorGUI.DrawRect(space_ofSlotIndexNumberBackground, backgroundColor);
GUIStyle style_ofNumber = new GUIStyle();
Color color_ofNumber;
if (isHighlighted)
{
color_ofNumber = UtilitiesDXXL_Colors.GetSimilarColorWithOtherBrightnessValue(bezierSplineDrawer_thisPointIsPartOf.color_ofAnchorPoints, 0.375f);
}
else
{
color_ofNumber = UtilitiesDXXL_Colors.Get_color_butWithAdjustedAlpha(bezierSplineDrawer_thisPointIsPartOf.color_ofAnchorPoints, 0.725f);
}
string textString_ofNumber = "<size=16><color=#" + ColorUtility.ToHtmlStringRGBA(color_ofNumber) + "><b>" + i_ofThisPoint_insideControlPointsList + "</b></color></size>";
float y_offset_ofSlotIndexNumber = -0.1f * UnityEditor.EditorGUIUtility.singleLineHeight;
Rect space_ofSlotIndexNumber = new Rect(space_ofSlotIndexNumberBackground.x + horizPadding_besideIndexNumberInsideNumberRect_perSide, space_ofSlotIndexNumberBackground.y + y_offset_ofSlotIndexNumber, space_ofSlotIndexNumberBackground.width - horizPadding_besideIndexNumberInsideNumberRect_forBothSides, space_ofSlotIndexNumberBackground.height);
UnityEditor.EditorGUI.LabelField(space_ofSlotIndexNumber, textString_ofNumber, style_ofNumber);
#endif
}
int GetNumberOfDigitsInIndexNumber()
{
if (i_ofThisPoint_insideControlPointsList >= 10000)
{
return 5;
}
else
{
if (i_ofThisPoint_insideControlPointsList >= 1000)
{
return 4;
}
else
{
if (i_ofThisPoint_insideControlPointsList >= 100)
{
return 3;
}
else
{
if (i_ofThisPoint_insideControlPointsList >= 10)
{
return 2;
}
else
{
return 1;
}
}
}
}
}
void DrawSubPoints_forInspector()
{
float height_ofBackwardHelper = backwardHelperPoint.GetPropertyHeightForInspectorList();
float height_ofAnchor = anchorPoint.GetPropertyHeightForInspectorList();
float height_ofForwardHelper = forwardHelperPoint.GetPropertyHeightForInspectorList();
float x_ofHelperPointsColorBox = inspectorRect_reservedForThisTriplet.x + Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge();
float width_ofHelperPointsColorBox = inspectorRect_reservedForThisTriplet.width - 2.0f * Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() - 2.0f * Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge();
float currentHeightOffset = 0.0f;
currentHeightOffset += Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox();
currentHeightOffset += Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge();
Rect rect_of_backwardHelperPoint = new Rect(x_ofHelperPointsColorBox, inspectorRect_reservedForThisTriplet.y + currentHeightOffset, width_ofHelperPointsColorBox, height_ofBackwardHelper);
currentHeightOffset += height_ofBackwardHelper;
currentHeightOffset += Get_inspectorVertSpace_betweenSubPoints();
float x_ofAnchorPointsSubProperty = inspectorRect_reservedForThisTriplet.x + Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge() + InternalDXXL_BezierControlHelperSubPoint.Get_inspectorHorizSpace_between_subPointColorBoxEdge_and_actualContenFields();
float width_ofAnchorPointsSubProperty = inspectorRect_reservedForThisTriplet.width - 2.0f * Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() - 2.0f * Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge() - 2.0f * InternalDXXL_BezierControlHelperSubPoint.Get_inspectorHorizSpace_between_subPointColorBoxEdge_and_actualContenFields();
Rect rect_of_anchorPoint = new Rect(x_ofAnchorPointsSubProperty, inspectorRect_reservedForThisTriplet.y + currentHeightOffset, width_ofAnchorPointsSubProperty, height_ofAnchor);
currentHeightOffset += height_ofAnchor;
currentHeightOffset += Get_inspectorVertSpace_betweenSubPoints();
Rect rect_of_forwardHelperPoint = new Rect(x_ofHelperPointsColorBox, inspectorRect_reservedForThisTriplet.y + currentHeightOffset, width_ofHelperPointsColorBox, height_ofForwardHelper);
backwardHelperPoint.DrawValuesToInspector(rect_of_backwardHelperPoint);
anchorPoint.DrawValuesToInspector(rect_of_anchorPoint);
forwardHelperPoint.DrawValuesToInspector(rect_of_forwardHelperPoint);
}
public bool TryApplyChangesAfterInspectorInput()
{
bool didChangeSomething;
didChangeSomething = backwardHelperPoint.TryApplyChangesAfterInspectorInput();
if (didChangeSomething) { return true; }
didChangeSomething = anchorPoint.TryApplyChangesAfterInspectorInput();
if (didChangeSomething) { return true; }
didChangeSomething = forwardHelperPoint.TryApplyChangesAfterInspectorInput();
if (didChangeSomething) { return true; }
return false;
}
public float GetPropertyHeightForInspectorList()
{
float height_ofBackwardHelper = backwardHelperPoint.GetPropertyHeightForInspectorList();
float height_ofAnchor = anchorPoint.GetPropertyHeightForInspectorList();
float height_ofForwardHelper = forwardHelperPoint.GetPropertyHeightForInspectorList();
float additionalHeight = Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge() + Get_inspectorVertSpace_betweenSubPoints() + Get_inspectorVertSpace_betweenSubPoints() + Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge() + Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint() + Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox();
return (height_ofBackwardHelper + height_ofAnchor + height_ofForwardHelper + additionalHeight);
}
public static void DrawEmptyControlPointHoldingOnlyAPlusButton_forInspector(out bool plusButtonBelowListOfControlPoints_hasBeenClicked, out bool unfoldAllWeightsBelowListOfControlPoints_hasBeenClicked, out bool collapseAllWeightsBelowListOfControlPoints_hasBeenClicked, Rect position, Color color_ofAnchorPoints, GUIContent plusSymbolIcon, bool greyOutUnfoldAllButton, bool greyOutCollapseAllButton)
{
#if UNITY_EDITOR
Color backgroundColor = UtilitiesDXXL_Colors.Get_color_butWithAdjustedAlpha(color_ofAnchorPoints, InternalDXXL_BezierControlPointTriplet.alpha_ofInspectorBackgroundColor_nonHighlighted);
Rect rect_ofEmptyLine = new Rect(Get_xPos_ofBackgroundRect(position), Get_yPos_ofBackgroundRect(position), Get_width_ofBackgroundRect(position), Get_inspectorVertSpace_ofEmptyLineOfEmptyControlPointHoldingOnlyAPlusButton());
UnityEditor.EditorGUI.DrawRect(rect_ofEmptyLine, backgroundColor);
Rect rect_ofPlusButtonBelowEmptyLine = new Rect(Get_xPos_ofPlusAndMinusButtonRect(position), position.y + Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorVertSpace_ofEmptyLineOfEmptyControlPointHoldingOnlyAPlusButton(), Get_width_ofPlusAndMinusButtons(), Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint());
UnityEditor.EditorGUI.DrawRect(rect_ofPlusButtonBelowEmptyLine, backgroundColor);
GUIStyle style_ofMinusButton = "RL FooterButton";
plusButtonBelowListOfControlPoints_hasBeenClicked = GUI.Button(rect_ofPlusButtonBelowEmptyLine, plusSymbolIcon, style_ofMinusButton);
Rect rect_ofBothFoldAllButtons = new Rect(Get_xPos_ofBackgroundRect(position), position.y + Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorVertSpace_ofEmptyLineOfEmptyControlPointHoldingOnlyAPlusButton() + Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint() + Get_additionalInspectorVertSpace_belowEmptyPlusLine_tillFoldAllButtons(), Get_width_ofBackgroundRect(position), Get_inspectorVertSpace_forFoldAllButtons());
float halfHorizSpaceBetweenButtons = 0.5f * Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox();
Rect rect_ofUnfoldAllButton = new Rect(rect_ofBothFoldAllButtons.x, rect_ofBothFoldAllButtons.y, rect_ofBothFoldAllButtons.width * 0.5f - halfHorizSpaceBetweenButtons, rect_ofBothFoldAllButtons.height);
Rect rect_ofCollapseAllButton = new Rect(rect_ofBothFoldAllButtons.x + rect_ofBothFoldAllButtons.width * 0.5f + halfHorizSpaceBetweenButtons, rect_ofBothFoldAllButtons.y, rect_ofBothFoldAllButtons.width * 0.5f - halfHorizSpaceBetweenButtons, rect_ofBothFoldAllButtons.height);
GUIStyle style_ofUnfoldAllButtons = new GUIStyle(style_ofMinusButton);
style_ofUnfoldAllButtons.fontStyle = FontStyle.Normal;
Color color_ofAGreyedOut_foldAllButton = UtilitiesDXXL_Colors.Get_color_butWithAdjustedAlpha(backgroundColor, 0.5f);
Color color_ofUnfoldAllButton = greyOutUnfoldAllButton ? color_ofAGreyedOut_foldAllButton : backgroundColor;
UnityEditor.EditorGUI.DrawRect(rect_ofUnfoldAllButton, color_ofUnfoldAllButton);
UnityEditor.EditorGUI.BeginDisabledGroup(greyOutUnfoldAllButton);
unfoldAllWeightsBelowListOfControlPoints_hasBeenClicked = GUI.Button(rect_ofUnfoldAllButton, "Unfold all weights", style_ofUnfoldAllButtons);
UnityEditor.EditorGUI.EndDisabledGroup();
Color color_ofCollapseAllButton = greyOutCollapseAllButton ? color_ofAGreyedOut_foldAllButton : backgroundColor;
UnityEditor.EditorGUI.DrawRect(rect_ofCollapseAllButton, color_ofCollapseAllButton);
UnityEditor.EditorGUI.BeginDisabledGroup(greyOutCollapseAllButton);
collapseAllWeightsBelowListOfControlPoints_hasBeenClicked = GUI.Button(rect_ofCollapseAllButton, "Collapse all weights", style_ofUnfoldAllButtons);
UnityEditor.EditorGUI.EndDisabledGroup();
#else
plusButtonBelowListOfControlPoints_hasBeenClicked = false;
unfoldAllWeightsBelowListOfControlPoints_hasBeenClicked = false;
collapseAllWeightsBelowListOfControlPoints_hasBeenClicked = false;
#endif
}
public static float GetPropertyHeightForEmptyControlPointHoldingOnlyAPlusButtonAndFoldAllButtons()
{
return (Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() + Get_inspectorVertSpace_ofEmptyLineOfEmptyControlPointHoldingOnlyAPlusButton() + Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint() + Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox() + Get_additionalInspectorVertSpace_belowEmptyPlusLine_tillFoldAllButtons() + Get_inspectorVertSpace_forFoldAllButtons() + Get_emptyInspectorVertSpace_belowFoldAllButtons());
}
static float Get_xPos_ofBackgroundRect(Rect inspectorRect_reservedForThisTriplet)
{
return (inspectorRect_reservedForThisTriplet.x + Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox());
}
static float Get_yPos_ofBackgroundRect(Rect inspectorRect_reservedForThisTriplet)
{
return (inspectorRect_reservedForThisTriplet.y + Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox());
}
static float Get_width_ofBackgroundRect(Rect inspectorRect_reservedForThisTriplet)
{
return (inspectorRect_reservedForThisTriplet.width - 2.0f * Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox());
}
static float Get_xPos_ofPlusAndMinusButtonRect(Rect inspectorRect_reservedForThisTriplet)
{
//-> similar problem as described in "DrawBackgroundArea()", where the yPos is shifted by 1 pixel.
//-> in this case the x-position is shifted by 1 pixel to the left.
float offsetForFixingTheOnePixelOffset = 1.0f; //-> fixing it manually (with the risk of introducing a horizontal one pixel offset if there are situations where the problem doesn't occur)
return (inspectorRect_reservedForThisTriplet.x + inspectorRect_reservedForThisTriplet.width - Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox() - Get_width_ofPlusAndMinusButtons() + offsetForFixingTheOnePixelOffset);
}
static float Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge()
{
#if UNITY_EDITOR
return (0.2f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorVertSpace_from_mainRect_to_backgroundColorBox()
{
#if UNITY_EDITOR
return (0.2f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorVertSpace_betweenSubPoints()
{
#if UNITY_EDITOR
return (2.0f * Get_inspectorSpace_fromOutsideColorBoxEdge_toInsideColorBoxEdge());
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorVertSpace_ofMinusButtonOnEachControlPoint()
{
#if UNITY_EDITOR
return (UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorVertSpace_ofEmptyLineOfEmptyControlPointHoldingOnlyAPlusButton()
{
#if UNITY_EDITOR
return (UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_additionalInspectorVertSpace_belowEmptyPlusLine_tillFoldAllButtons()
{
#if UNITY_EDITOR
return (0.5f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorVertSpace_forFoldAllButtons()
{
#if UNITY_EDITOR
return (UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_emptyInspectorVertSpace_belowFoldAllButtons()
{
#if UNITY_EDITOR
return (0.0f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_width_ofPlusAndMinusButtons()
{
#if UNITY_EDITOR
return (1.5f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
static float Get_inspectorHorizSpace_from_mainRect_to_backgroundColorBox()
{
#if UNITY_EDITOR
return (0.2f * UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return 16.0f; //-> not used
#endif
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1d9634370ba98d947b85834f62524d7f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,519 @@
namespace DrawXXL
{
using System;
using UnityEngine;
[Serializable]
public class InternalDXXL_BezierControlSubPoint
{
public enum SubPointType { backwardHelper, anchor, forwardHelper };
[SerializeField] public bool isUsed; //can be disabled by the user in the control points list inspector (only for kinked junctures), or is automatically disabled for endPoints of non-closed splines
[SerializeField] public Vector3 position_inUnitsOfActiveDrawSpace;
[SerializeField] Vector3 position_inUnitsOfGlobalSpace;
public BezierSplineDrawer bezierSplineDrawer_thisSubPointIsPartOf;
[SerializeField] public int i_ofContainingControlPoint_insideControlPointsList;
public SubPointType subPointType;
public GameObject boundGameobject;
public DrawXXLSplineConnection connectionComponent_onBoundGameobject;
public bool boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled;
public bool boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled;
public Quaternion globalRotation_ofPositionHandle = Quaternion.identity;
public bool recalc_globalRotation_ofPositionHandle_duringNextOnSceneGUI = true;
public virtual void InitializeValuesThatAreIndependentFromOtherSubPoints(InternalDXXL_BezierControlPointTriplet controlPoint_thisSubPointIsPartOf)
{
boundGameobject = null;
connectionComponent_onBoundGameobject = null;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = false;
i_ofContainingControlPoint_insideControlPointsList = controlPoint_thisSubPointIsPartOf.i_ofThisPoint_insideControlPointsList;
bezierSplineDrawer_thisSubPointIsPartOf = controlPoint_thisSubPointIsPartOf.bezierSplineDrawer_thisPointIsPartOf;
}
public void ReassignIndexInsideControlPointsList(int new_i)
{
SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled(); //-> function is dependent on the "old" i.
if (boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled)
{
connectionComponent_onBoundGameobject.i_ofControlPointTriplet_thisGameobjectIsBoundTo = new_i;
}
i_ofContainingControlPoint_insideControlPointsList = new_i;
}
public InternalDXXL_BezierControlPointTriplet Get_controlPointTriplet_thisSubPointIsPartOf()
{
//Serialized lists containing other lists and containing custom classes with cross references don't work well in Unity, even when using the [SerializeReference] attribute. Functions like this try to keep the convenience of a real reference tree. The only "real" reference is the monobehavior-inherited spline component. Everything has to start from there.
return bezierSplineDrawer_thisSubPointIsPartOf.listOfControlPointTriplets[i_ofContainingControlPoint_insideControlPointsList];
}
public void SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled()
{
///De-assigning connectionComponents is not trivial as soon as it has to comply with the build-in Undo-System.
//Problems:
//The spline-component and the connection-component should only exist together, but they are on independent gameobjects, which the user can delete or copy independently.
//When the spline-component is deleted then also all corresponding connection-componenets should be deleted.
//-> It could be done in "spline.OnDestroy()", but this is not fired always when a component gets destroyed. The Unity docu says the it is not fired when the carrying gameobject is inactive. Though testing it in the Unity Editor showed: It is often called, even when the gameobject is inactive, but it is sometimes omited, even when the gameobject is active. So overall: Not fully reliable. Orphaned connection-components may still remain in the scene, which is not desired.
//-> More reliable than "spline.OnDestroy()" is "spline.OnDisable()", but we don't want to destroy the connection reference just because some disabled a participating component (maybe with the intention to enabled it sometime later)
//-> So the connection components should handle their deletion self contained, as soon as the referncing spline is not there anymore.
//-> This is working fine as long as "Undo" doesn't come into play.
//-> If a boundGameobject gets deleted and then the deletion is reverted via "Editor/Undo", then the two partners (spline-component and connection-component) don't recognize each other anymore as "referenced partners". The reference is lost. This seems to be a Unity bug, see here: https://forum.unity.com/threads/monobehaviour-references-are-lost-on-undo.587011/ and here: https://issuetracker.unity3d.com/issues/gameobject-isnt-set-as-public-variable-after-undo-operation It's an unconvenience but since Unity itself accepts this bug it's hopefully indeed "acceptable".
//-> It can be fixed in the case of spline-deletion (because in "spline.OnDestroy()" the connectionComponents can be deleted by the spline itself (so not following the mentioned "self contained deletion" way)), and along with that the spline can register "Undo.DestroyImmediate()" for the connection-components: In this case the references are correctly reverted after Undo. A similar construction inside "connectionComponent.OnDestroy()" doesn't have the same fixing effect though (see note there).
//-> Another approach would be to not immediately destroy the connection components after spline-deletion, but delay the self contained destruction with a timer, so that the undo-process doesn't have to "recreate them as new instance from serialized data" in the hope that they are then still the "correct reference". But tests showed: It is not the case. It makes no difference and the reference is still lost.
//-> Another approach would be to somehow search the formerly reference component and recreate the reference "OnUndoExecuted". The problem with that is that it is quiete non-intended from Unities paradigm of doing things. Such "hacky interventions" sometimes lead to Editor crashes when shuffling around "Undo/Redo" to and fro. It seems unwieldly and to risky.
//-> Another case where the reference gets lost: "Assign boundGameobject in the inspector" -> "Undo assign" -> "Redo assign" -> reference is lost.
if (boundGameobject == null)
{
//cases that arrive here:
//-> "boundGameobject" hasnn't been assigned yet
//-> "boundGameobject" was regularly deassgined
//-> "boundGameobject" has been independently deleted (but may come back via "Undo")
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = false;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = false;
}
else
{
if (connectionComponent_onBoundGameobject == null)
{
//cases that arrive here:
//-> the "connectionComponent_onBoundGameobject"-component has been independently deleted from the (still existing) "boundGameobject" (but it may come back via "Undo")
//-> also after "Undo" it sometimes doesn't come back due to the reference lost error described above in this function
//-> assign boundGameobject to a controlSubPoint -> Undo assign -> Redo assign -> connection is not retrieved
boundGameobject = null;
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = false;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = false;
}
else
{
if (connectionComponent_onBoundGameobject.bezierSplineDrawer_thatHasReferencedThisGameobject != bezierSplineDrawer_thisSubPointIsPartOf)
{
//-> The spline component (e.g. along with it's carrying gameobject) has been copied. Both the old spline component and the new spline component here reference the single connection-component on the boundGameobject
//-> The new spline here creates his own additonal connection component on the boundGameobject now:
CreateConnectionComponentOnBoundGameobject("Auto-create connection after spline copy");
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = true;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = connectionComponent_onBoundGameobject.isActiveAndEnabled;
}
else
{
// if (connectionComponent_onBoundGameobject.bezierSubPoint_thatHasReferencedThisGameobject != this) //this is not suitable as reference, because in the serialized context "InternalDXXL_BezierControlSubPoint" acts as value type, not as reference type.
if (connectionComponent_onBoundGameobject.i_ofControlPointTriplet_thisGameobjectIsBoundTo != i_ofContainingControlPoint_insideControlPointsList)
{
bezierSplineDrawer_thisSubPointIsPartOf.DeleteConnectionComponentOfBoundGameobject_onControlSubPoint(i_ofContainingControlPoint_insideControlPointsList, subPointType);
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = false;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = false;
UtilitiesDXXL_Log.PrintErrorCode("50-" + connectionComponent_onBoundGameobject.i_ofControlPointTriplet_thisGameobjectIsBoundTo + "-" + i_ofContainingControlPoint_insideControlPointsList + "-" + bezierSplineDrawer_thisSubPointIsPartOf.listOfControlPointTriplets.Count);
}
else
{
if (connectionComponent_onBoundGameobject.subPointType_whereThisGameobjectIsBoundTo != subPointType)
{
bezierSplineDrawer_thisSubPointIsPartOf.DeleteConnectionComponentOfBoundGameobject_onControlSubPoint(i_ofContainingControlPoint_insideControlPointsList, subPointType);
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = false;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = false;
UtilitiesDXXL_Log.PrintErrorCode("51-" + connectionComponent_onBoundGameobject.subPointType_whereThisGameobjectIsBoundTo + "-" + subPointType + "-" + bezierSplineDrawer_thisSubPointIsPartOf.listOfControlPointTriplets.Count);
}
else
{
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = true;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = connectionComponent_onBoundGameobject.isActiveAndEnabled;
}
}
}
}
}
}
public void ProcessNewGameobjectAssignment(GameObject newlyAssignedGameobject)
{
if (newlyAssignedGameobject != boundGameobject)
{
if (bezierSplineDrawer_thisSubPointIsPartOf.CheckIf_gameobjectToAssign_isAlreadyAssignedAtAnotherSubPointOfTheSpline(newlyAssignedGameobject, out int i_ofTripletThatContainsTheSubPointThatAlreadyHasTheGameobjectAssigned, out SubPointType subPointThatAlreadyHasTheGameobjectAssigned))
{
//This restriction is done to prevent tangled unwieldy cross-dependencies between subPoints. Otherwise numerous cases would need special consideration, e.g.: A gameobject could be bound not only to the backward helper, but also to the forward helper of the same controlPoint triplet.
//Already without this restriction there are overdefined situations: E.g. when different gameobjects are bound to all three subPoints of a triplet, junctureType=kinked, and both helperPoint bind their direction to the same transform direction of the boundGameobject at the center point.
Debug.LogError("Assignment of gameobject (" + newlyAssignedGameobject.name + ") denied, because a gameobject can only be assinged once per spline. It is already assinged at the " + GetSubPointTypeAsString(subPointThatAlreadyHasTheGameobjectAssigned) + " of control point " + i_ofTripletThatContainsTheSubPointThatAlreadyHasTheGameobjectAssigned + ".");
}
else
{
string nameOfUndoEntry = "Change Spline Gameobject Ref";
bezierSplineDrawer_thisSubPointIsPartOf.RegisterStateForUndo(nameOfUndoEntry, true, true);
if (boundGameobject != null)
{
//Deassign old gameobject:
if (connectionComponent_onBoundGameobject != null)
{
#if UNITY_EDITOR
UnityEditor.Undo.DestroyObjectImmediate(connectionComponent_onBoundGameobject);
#endif
}
boundGameobject = null;
connectionComponent_onBoundGameobject = null;
}
boundGameobject = newlyAssignedGameobject;
if (newlyAssignedGameobject != null)
{
//Assign new gameobject:
CreateConnectionComponentOnBoundGameobject(nameOfUndoEntry);
}
else
{
ResetDirectionSourceToIndependent();
}
}
}
}
void CreateConnectionComponentOnBoundGameobject(string nameOfUndoEntry_forNewlyCreatedComponent)
{
#if UNITY_EDITOR
connectionComponent_onBoundGameobject = UnityEditor.Undo.AddComponent<DrawXXLSplineConnection>(boundGameobject);
UnityEditor.Undo.RegisterCompleteObjectUndo(connectionComponent_onBoundGameobject, nameOfUndoEntry_forNewlyCreatedComponent);
#else
connectionComponent_onBoundGameobject = boundGameobject.AddComponent<DrawXXLSplineConnection>();
#endif
connectionComponent_onBoundGameobject.componentHasBeenManuallyCreated = false;
connectionComponent_onBoundGameobject.bezierSplineDrawer_thatHasReferencedThisGameobject = bezierSplineDrawer_thisSubPointIsPartOf;
connectionComponent_onBoundGameobject.i_ofControlPointTriplet_thisGameobjectIsBoundTo = i_ofContainingControlPoint_insideControlPointsList;
connectionComponent_onBoundGameobject.subPointType_whereThisGameobjectIsBoundTo = subPointType;
SetPos_inUnitsOfGlobalSpace(boundGameobject.transform.position, true, boundGameobject);
TryTransferBoundGameobjectsRotationToAnchorPointsDirection();
}
public virtual void ResetDirectionSourceToIndependent()
{
}
public virtual void TryTransferBoundGameobjectsRotationToAnchorPointsDirection()
{
}
public Vector3 GetPos_inUnitsOfGlobalSpace()
{
return position_inUnitsOfGlobalSpace;
}
public Vector3 GetPos_inUnitsOfActiveDrawSpace()
{
return position_inUnitsOfActiveDrawSpace;
}
public virtual void SetPos_inUnitsOfGlobalSpace(Vector3 newPos_inUnitsOfGlobalSpace, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
//all children override this
}
public Vector3 SetPos_inUnitsOfGlobalSpace_butIgnoreDependentValues_nonRecursively(Vector3 newPos_inUnitsOfGlobalSpace, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
//"_nonRecursively" indicates: This function is reserved to be called inside the overrides of "SetPos_inUnitsOfGlobalSpace". In all other cases use "SetPos_inUnitsOfGlobalSpace(..., false)"
Vector3 offset_fromPrevious_toNewPosition_inUnitsOfGlobalSpace = newPos_inUnitsOfGlobalSpace - position_inUnitsOfGlobalSpace;
position_inUnitsOfGlobalSpace = newPos_inUnitsOfGlobalSpace;
position_inUnitsOfActiveDrawSpace = bezierSplineDrawer_thisSubPointIsPartOf.TransformPos_fromGlobalSpace_toUnitsOfActiveDrawSpace(newPos_inUnitsOfGlobalSpace);
SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled();
if (boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled)
{
if (boundGameobject != boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
boundGameobject.transform.position = newPos_inUnitsOfGlobalSpace;
}
}
return offset_fromPrevious_toNewPosition_inUnitsOfGlobalSpace;
}
public void SetPos_inUnitsOfActiveDrawSpace(Vector3 newPos_inUnitsOfActiveDrawSpace, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector3 newPos_inUnitsOfGlobalSpace = bezierSplineDrawer_thisSubPointIsPartOf.TransformPos_fromUnitsOfActiveDrawSpace_toGlobalSpace(newPos_inUnitsOfActiveDrawSpace);
SetPos_inUnitsOfGlobalSpace(newPos_inUnitsOfGlobalSpace, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void AddPosOffset_inUnitsOfGlobalSpace(Vector3 posOffset_inUnitsOfGlobalSpace, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector3 newPos_inUnitsOfGlobalSpace = GetPos_inUnitsOfGlobalSpace() + posOffset_inUnitsOfGlobalSpace;
SetPos_inUnitsOfGlobalSpace(newPos_inUnitsOfGlobalSpace, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void AddPosOffset_inUnitsOfActiveDrawSpace(Vector3 posOffset_inUnitsOfActiveDrawSpace, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector3 newPos_inUnitsOfActiveDrawSpace = GetPos_inUnitsOfActiveDrawSpace() + posOffset_inUnitsOfActiveDrawSpace;
SetPos_inUnitsOfActiveDrawSpace(newPos_inUnitsOfActiveDrawSpace, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public virtual void Set_direction_toForward_inUnitsOfGlobalSpace_normalized(Vector3 newDirection_toForward_inUnitsOfGlobalSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
//-> is not intended to be called for non-overriding helperPoints. Use "helperPoint.Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized()" instead
UtilitiesDXXL_Log.PrintErrorCode("37");
}
public virtual void Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(Vector3 newDirection_toBackward_inUnitsOfGlobalSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
//-> is not intended to be called for non-overriding helperPoints. Use "helperPoint.Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized()" instead
UtilitiesDXXL_Log.PrintErrorCode("38");
}
public virtual InternalDXXL_BezierControlAnchorSubPoint.JunctureType GetJunctureType()
{
//-> is not intended to be called for non-overriding helperPoints
UtilitiesDXXL_Log.PrintErrorCode("39");
return InternalDXXL_BezierControlAnchorSubPoint.JunctureType.aligned;
}
public virtual InternalDXXL_BezierControlHelperSubPoint GetForwardHelper()
{
//-> is not intended to be called for non-overriding helperPoints
UtilitiesDXXL_Log.PrintErrorCode("40");
return null;
}
public virtual InternalDXXL_BezierControlHelperSubPoint GetBackwardHelper()
{
//-> is not intended to be called for non-overriding helperPoints
UtilitiesDXXL_Log.PrintErrorCode("41");
return null;
}
public virtual InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper Get_sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked()
{
//-> is not intended to be called for non-overriding helperPoints
UtilitiesDXXL_Log.PrintErrorCode("42");
return InternalDXXL_BezierControlAnchorSubPoint.SourceOf_directionToHelper.independentFromGameobject;
}
public virtual InternalDXXL_BezierControlSubPoint GetNextSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
//-> all children override this
return null;
}
public virtual InternalDXXL_BezierControlSubPoint GetPreviousSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
//-> all children override this
return null;
}
public virtual InternalDXXL_BezierControlSubPoint GetNextUsedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
//-> all children override this
return null;
}
public virtual InternalDXXL_BezierControlSubPoint GetPreviousUsedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
//-> all children override this
return null;
}
public InternalDXXL_BezierControlSubPoint GetNextUsedNonSuperimposedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
InternalDXXL_BezierControlSubPoint currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir = GetNextSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet); //-> cannot use "GetNext-USED-SubPointAlongSplineDir()" here in this function, because then an endless-loop-prevention-check is not possible for cases, where this function is called on subPoints which are iself "isUsed=false".
int maxAttempts = 100;
for (int i = 0; i < maxAttempts; i++)
{
if (currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir != null)
{
if (currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir != this) //-> prevent endless loops around closed splines
{
if (currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir.isUsed == true)
{
if (UtilitiesDXXL_Math.CheckIf_twoVectorsAreApproximatelyEqual(GetPos_inUnitsOfGlobalSpace(), currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir.GetPos_inUnitsOfGlobalSpace()))
{
currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir = currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir.GetNextSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
else
{
return currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir;
}
}
else
{
currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir = currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir.GetNextSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
}
else
{
return null;
}
}
else
{
return null;
}
}
return null;
}
public InternalDXXL_BezierControlSubPoint GetPreviousUsedNonSuperimposedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
InternalDXXL_BezierControlSubPoint currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir = GetPreviousSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet); //-> cannot use "GetPrevious-USED-SubPointAlongSplineDir()" here in this function, because then an endless-loop-prevention-check is not possible for cases, where this function is called on subPoints which are iself "isUsed=false".
int maxAttempts = 100;
for (int i = 0; i < maxAttempts; i++)
{
if (currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir != null)
{
if (currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir != this) //-> prevent endless loops around closed splines
{
if (currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir.isUsed == true)
{
if (UtilitiesDXXL_Math.CheckIf_twoVectorsAreApproximatelyEqual(GetPos_inUnitsOfGlobalSpace(), currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir.GetPos_inUnitsOfGlobalSpace()))
{
currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir = currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir.GetPreviousSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
else
{
return currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir;
}
}
else
{
currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir = currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir.GetPreviousSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
}
else
{
return null;
}
}
else
{
return null;
}
}
return null;
}
public virtual Vector3 GetDirectionAlongSplineForwardBasedOnNeighborPoints_inUnitsOfGlobalSpace()
{
//-> all children override this
//-> not guaranteed normalized
//-> not to be consued with "anchor.Get_direction_to*Helper*()"
return Vector3.forward;
}
public virtual bool IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid()
{
//-> all children override this
return false;
}
public static string GetSubPointTypeAsString(SubPointType subPointType_toGetAsString)
{
switch (subPointType_toGetAsString)
{
case SubPointType.backwardHelper:
return "backward weight point";
case SubPointType.anchor:
return "center point";
case SubPointType.forwardHelper:
return "forward weight point";
default:
return "unknown sub point";
}
}
public Rect RecalcCurrentRect_forInspector(Rect reducedRectForOnlyContentLines, float currentHeightOffset)
{
#if UNITY_EDITOR
return new Rect(reducedRectForOnlyContentLines.x, reducedRectForOnlyContentLines.y + currentHeightOffset, reducedRectForOnlyContentLines.width, UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return default;
#endif
}
public Vector3 Draw_Vector3Field_withoutLineBreak_forInspector(Rect position, GUIContent label, Vector3 value, bool allowRichText = false)
{
return Draw_Vector3Field_withoutLineBreak_forInspector(position, out Rect rectForOnlyThePrefixLabel, label, value, allowRichText);
}
public Vector3 Draw_Vector3Field_withoutLineBreak_forInspector(Rect position, out Rect rectForOnlyThePrefixLabel, GUIContent label, Vector3 value, bool allowRichText = false)
{
#if UNITY_EDITOR
//"EditorGUI.Vector3Field" makes a line break and expands to two lines if the inspector window gets narrow. Therefore this modified version without the line break.
Rect position_forOnlyTheContentValues;
if (allowRichText)
{
GUIStyle styleWithRichText = new GUIStyle(UnityEditor.EditorStyles.label);
styleWithRichText.richText = true;
position_forOnlyTheContentValues = UnityEditor.EditorGUI.PrefixLabel(position, label, styleWithRichText);
}
else
{
position_forOnlyTheContentValues = UnityEditor.EditorGUI.PrefixLabel(position, label);
}
rectForOnlyThePrefixLabel = new Rect(position.x, position.y, position.width - position_forOnlyTheContentValues.width, position.height);
Vector3 value_after = UnityEditor.EditorGUI.Vector3Field(position_forOnlyTheContentValues, GUIContent.none, value);
return value_after;
#else
rectForOnlyThePrefixLabel = default;
return default;
#endif
}
public Vector3 position_inUnitsOfActiveDrawSpace_afterInspectorInput;
public void DrawPositionLine_forInspector(Rect rect, GUIContent guiContent)
{
position_inUnitsOfActiveDrawSpace_afterInspectorInput = Draw_Vector3Field_withoutLineBreak_forInspector(rect, guiContent, position_inUnitsOfActiveDrawSpace);
}
public GameObject boundGameobject_afterInspectorInput;
public void DrawBoundGameobjectLine_forInspector(Rect rect, GUIContent guiContent)
{
#if UNITY_EDITOR
SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled();
bool boundGameobjectConnetionExists_butIsNotActiveRespEnabled = ((boundGameobject != null) && (connectionComponent_onBoundGameobject != null) && ((boundGameobject.activeInHierarchy == false) || (connectionComponent_onBoundGameobject.enabled == false)));
if (boundGameobjectConnetionExists_butIsNotActiveRespEnabled)
{
Rect rect_forGameobjectPickerAndInactiveNotifier = UnityEditor.EditorGUI.PrefixLabel(rect, guiContent);
float posOfSeparation_0to1 = 0.5f;
Rect rect_gameobjectPickerWithoutLabel = new Rect(rect_forGameobjectPickerAndInactiveNotifier.x, rect_forGameobjectPickerAndInactiveNotifier.y, posOfSeparation_0to1 * rect_forGameobjectPickerAndInactiveNotifier.width, rect_forGameobjectPickerAndInactiveNotifier.height);
Rect rect_forInactiveRespDisabledNotifier = new Rect(rect_forGameobjectPickerAndInactiveNotifier.x + posOfSeparation_0to1 * rect_forGameobjectPickerAndInactiveNotifier.width, rect_forGameobjectPickerAndInactiveNotifier.y, (1.0f - posOfSeparation_0to1) * rect_forGameobjectPickerAndInactiveNotifier.width, rect_forGameobjectPickerAndInactiveNotifier.height);
boundGameobject_afterInspectorInput = (UnityEngine.GameObject)UnityEditor.EditorGUI.ObjectField(rect_gameobjectPickerWithoutLabel, GUIContent.none, boundGameobject, typeof(UnityEngine.GameObject), true);
if (boundGameobject.activeInHierarchy == false)
{
UnityEditor.EditorGUI.LabelField(rect_forInactiveRespDisabledNotifier, new GUIContent(" is inactive", "The bound gameobject or any of it's parents is set to inactive. As long as this is the case the tieing will not be updated."));
}
else
{
UnityEditor.EditorGUI.LabelField(rect_forInactiveRespDisabledNotifier, new GUIContent(" is disabled", "The connection component on the bound gameobject is disabled. As long as this is the case the tieing will not be updated."));
}
}
else
{
boundGameobject_afterInspectorInput = (UnityEngine.GameObject)UnityEditor.EditorGUI.ObjectField(rect, guiContent, boundGameobject, typeof(UnityEngine.GameObject), true);
}
#endif
}
public string Get_tooltip_explainingWheatherUnitsAreInGlobalOrInLocalSpace_forInspector()
{
switch (bezierSplineDrawer_thisSubPointIsPartOf.drawSpace)
{
case BezierSplineDrawer.DrawSpace.global:
return "This value display is in units of the active draw space, which is currently the global space.";
case BezierSplineDrawer.DrawSpace.localDefinedByThisGameobject:
return "This value display is in units of the active draw space, which is currently the local space defined by the gameobject that holds this spline component.";
default:
return "";
}
}
public virtual float GetPropertyHeightForInspectorList()
{
//-> all children override this
return 16.0f;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18f2b3ad5533c3b40bcc75e5750a8d0b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,510 @@
namespace DrawXXL
{
using System;
using UnityEngine;
[Serializable]
public class InternalDXXL_BezierControlSubPoint2D
{
[SerializeField] public bool isUsed; //can be disabled by the user in the control points list inspector (only for kinked junctures), or is automatically disabled for endPoints of non-closed splines
[SerializeField] public Vector2 position_inUnitsOfActiveDrawSpace;
[SerializeField] Vector2 position_inUnitsOfGlobalSpace;
public BezierSplineDrawer2D bezierSplineDrawer_thisSubPointIsPartOf;
[SerializeField] public int i_ofContainingControlPoint_insideControlPointsList;
public InternalDXXL_BezierControlSubPoint.SubPointType subPointType;
public GameObject boundGameobject;
public DrawXXLSpline2DConnection connectionComponent_onBoundGameobject;
public bool boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled;
public bool boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled;
public Quaternion globalRotation_ofPositionHandle = Quaternion.identity;
public bool recalc_globalRotation_ofPositionHandle_duringNextOnSceneGUI = true;
public int controlID_ofUnityStylePositionHandleUp;
public int controlID_ofUnityStylePositionHandleRight;
public virtual void InitializeValuesThatAreIndependentFromOtherSubPoints(InternalDXXL_BezierControlPointTriplet2D controlPoint_thisSubPointIsPartOf)
{
boundGameobject = null;
connectionComponent_onBoundGameobject = null;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = false;
i_ofContainingControlPoint_insideControlPointsList = controlPoint_thisSubPointIsPartOf.i_ofThisPoint_insideControlPointsList;
bezierSplineDrawer_thisSubPointIsPartOf = controlPoint_thisSubPointIsPartOf.bezierSplineDrawer_thisPointIsPartOf;
}
public void ReassignIndexInsideControlPointsList(int new_i)
{
SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled(); //-> function is dependent on the "old" i.
if (boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled)
{
connectionComponent_onBoundGameobject.i_ofControlPointTriplet_thisGameobjectIsBoundTo = new_i;
}
i_ofContainingControlPoint_insideControlPointsList = new_i;
}
public InternalDXXL_BezierControlPointTriplet2D Get_controlPointTriplet_thisSubPointIsPartOf()
{
//Serialized lists containing other lists and containing custom classes with cross references don't work well in Unity, even when using the [SerializeReference] attribute. Functions like this try to keep the convenience of a real reference tree. The only "real" reference is the monobehavior-inherited spline component. Everything has to start from there.
return bezierSplineDrawer_thisSubPointIsPartOf.listOfControlPointTriplets[i_ofContainingControlPoint_insideControlPointsList];
}
public void SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled()
{
///De-assigning connectionComponents is not trivial as soon as it has to comply with the build-in Undo-System.
//Problems:
//The spline-component and the connection-component should only exist together, but they are on independent gameobjects, which the user can delete or copy independently.
//When the spline-component is deleted then also all corresponding connection-componenets should be deleted.
//-> It could be done in "spline.OnDestroy()", but this is not fired always when a component gets destroyed. The Unity docu says the it is not fired when the carrying gameobject is inactive. Though testing it in the Unity Editor showed: It is often called, even when the gameobject is inactive, but it is sometimes omited, even when the gameobject is active. So overall: Not fully reliable. Orphaned connection-components may still remain in the scene, which is not desired.
//-> More reliable than "spline.OnDestroy()" is "spline.OnDisable()", but we don't want to destroy the connection reference just because some disabled a participating component (maybe with the intention to enabled it sometime later)
//-> So the connection components should handle their deletion self contained, as soon as the referncing spline is not there anymore.
//-> This is working fine as long as "Undo" doesn't come into play.
//-> If a boundGameobject gets deleted and then the deletion is reverted via "Editor/Undo", then the two partners (spline-component and connection-component) don't recognize each other anymore as "referenced partners". The reference is lost. This seems to be a Unity bug, see here: https://forum.unity.com/threads/monobehaviour-references-are-lost-on-undo.587011/ and here: https://issuetracker.unity3d.com/issues/gameobject-isnt-set-as-public-variable-after-undo-operation It's an unconvenience but since Unity itself accepts this bug it's hopefully indeed "acceptable".
//-> It can be fixed in the case of spline-deletion (because in "spline.OnDestroy()" the connectionComponents can be deleted by the spline itself (so not following the mentioned "self contained deletion" way)), and along with that the spline can register "Undo.DestroyImmediate()" for the connection-components: In this case the references are correctly reverted after Undo. A similar construction inside "connectionComponent.OnDestroy()" doesn't have the same fixing effect though (see note there).
//-> Another approach would be to not immediately destroy the connection components after spline-deletion, but delay the self contained destruction with a timer, so that the undo-process doesn't have to "recreate them as new instance from serialized data" in the hope that they are then still the "correct reference". But tests showed: It is not the case. It makes no difference and the reference is still lost.
//-> Another approach would be to somehow search the formerly reference component and recreate the reference "OnUndoExecuted". The problem with that is that it is quiete non-intended from Unities paradigm of doing things. Such "hacky interventions" sometimes lead to Editor crashes when shuffling around "Undo/Redo" to and fro. It seems unwieldly and to risky.
//-> Another case where the reference gets lost: "Assign boundGameobject in the inspector" -> "Undo assign" -> "Redo assign" -> reference is lost.
if (boundGameobject == null)
{
//cases that arrive here:
//-> "boundGameobject" hasnn't been assigned yet
//-> "boundGameobject" was regularly deassgined
//-> "boundGameobject" has been independently deleted (but may come back via "Undo")
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = false;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = false;
}
else
{
if (connectionComponent_onBoundGameobject == null)
{
//cases that arrive here:
//-> the "connectionComponent_onBoundGameobject"-component has been independently deleted from the (still existing) "boundGameobject" (but it may come back via "Undo")
//-> also after "Undo" it sometimes doesn't come back due to the reference lost error described above in this function
//-> assign boundGameobject to a controlSubPoint -> Undo assign -> Redo assign -> connection is not retrieved
boundGameobject = null;
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = false;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = false;
}
else
{
if (connectionComponent_onBoundGameobject.bezierSplineDrawer_thatHasReferencedThisGameobject != bezierSplineDrawer_thisSubPointIsPartOf)
{
//-> The spline component (e.g. along with it's carrying gameobject) has been copied. Both the old spline component and the new spline component here reference the single connection-component on the boundGameobject
//-> The new spline here creates his own additonal connection component on the boundGameobject now:
CreateConnectionComponentOnBoundGameobject("Auto-create connection after spline copy");
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = true;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = connectionComponent_onBoundGameobject.isActiveAndEnabled;
}
else
{
// if (connectionComponent_onBoundGameobject.bezierSubPoint_thatHasReferencedThisGameobject != this) //this is not suitable as reference, because in the serialized context "InternalDXXL_BezierControlSubPoint" acts as value type, not as reference type.
if (connectionComponent_onBoundGameobject.i_ofControlPointTriplet_thisGameobjectIsBoundTo != i_ofContainingControlPoint_insideControlPointsList)
{
bezierSplineDrawer_thisSubPointIsPartOf.DeleteConnectionComponentOfBoundGameobject_onControlSubPoint(i_ofContainingControlPoint_insideControlPointsList, subPointType);
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = false;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = false;
UtilitiesDXXL_Log.PrintErrorCode("74-" + connectionComponent_onBoundGameobject.i_ofControlPointTriplet_thisGameobjectIsBoundTo + "-" + i_ofContainingControlPoint_insideControlPointsList + "-" + bezierSplineDrawer_thisSubPointIsPartOf.listOfControlPointTriplets.Count);
}
else
{
if (connectionComponent_onBoundGameobject.subPointType_whereThisGameobjectIsBoundTo != subPointType)
{
bezierSplineDrawer_thisSubPointIsPartOf.DeleteConnectionComponentOfBoundGameobject_onControlSubPoint(i_ofContainingControlPoint_insideControlPointsList, subPointType);
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = false;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = false;
UtilitiesDXXL_Log.PrintErrorCode("75-" + connectionComponent_onBoundGameobject.subPointType_whereThisGameobjectIsBoundTo + "-" + subPointType + "-" + bezierSplineDrawer_thisSubPointIsPartOf.listOfControlPointTriplets.Count);
}
else
{
boundGameobjectInclConnectionComponent_isAssignedButMayBeInactiveOrDisabled = true;
boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled = connectionComponent_onBoundGameobject.isActiveAndEnabled;
}
}
}
}
}
}
public void ProcessNewGameobjectAssignment(GameObject newlyAssignedGameobject)
{
if (newlyAssignedGameobject != boundGameobject)
{
if (bezierSplineDrawer_thisSubPointIsPartOf.CheckIf_gameobjectToAssign_isAlreadyAssignedAtAnotherSubPointOfTheSpline(newlyAssignedGameobject, out int i_ofTripletThatContainsTheSubPointThatAlreadyHasTheGameobjectAssigned, out InternalDXXL_BezierControlSubPoint.SubPointType subPointThatAlreadyHasTheGameobjectAssigned))
{
//This restriction is done to prevent tangled unwieldy cross-dependencies between subPoints. Otherwise numerous cases would need special consideration, e.g.: A gameobject could be bound not only to the backward helper, but also to the forward helper of the same controlPoint triplet.
//Already without this restriction there are overdefined situations: E.g. when different gameobjects are bound to all three subPoints of a triplet, junctureType=kinked, and both helperPoint bind their direction to the same transform direction of the boundGameobject at the center point.
Debug.LogError("Assignment of gameobject (" + newlyAssignedGameobject.name + ") denied, because a gameobject can only be assinged once per spline. It is already assinged at the " + InternalDXXL_BezierControlSubPoint.GetSubPointTypeAsString(subPointThatAlreadyHasTheGameobjectAssigned) + " of control point " + i_ofTripletThatContainsTheSubPointThatAlreadyHasTheGameobjectAssigned + ".");
}
else
{
string nameOfUndoEntry = "Change Spline Gameobject Ref";
bezierSplineDrawer_thisSubPointIsPartOf.RegisterStateForUndo(nameOfUndoEntry, true, true);
if (boundGameobject != null)
{
//Deassign old gameobject:
if (connectionComponent_onBoundGameobject != null)
{
#if UNITY_EDITOR
UnityEditor.Undo.DestroyObjectImmediate(connectionComponent_onBoundGameobject);
#endif
}
boundGameobject = null;
connectionComponent_onBoundGameobject = null;
}
boundGameobject = newlyAssignedGameobject;
if (newlyAssignedGameobject != null)
{
//Assign new gameobject:
CreateConnectionComponentOnBoundGameobject(nameOfUndoEntry);
}
else
{
ResetDirectionSourceToIndependent();
}
}
}
}
void CreateConnectionComponentOnBoundGameobject(string nameOfUndoEntry_forNewlyCreatedComponent)
{
#if UNITY_EDITOR
connectionComponent_onBoundGameobject = UnityEditor.Undo.AddComponent<DrawXXLSpline2DConnection>(boundGameobject);
UnityEditor.Undo.RegisterCompleteObjectUndo(connectionComponent_onBoundGameobject, nameOfUndoEntry_forNewlyCreatedComponent);
#else
connectionComponent_onBoundGameobject = boundGameobject.AddComponent<DrawXXLSpline2DConnection>();
#endif
connectionComponent_onBoundGameobject.componentHasBeenManuallyCreated = false;
connectionComponent_onBoundGameobject.bezierSplineDrawer_thatHasReferencedThisGameobject = bezierSplineDrawer_thisSubPointIsPartOf;
connectionComponent_onBoundGameobject.i_ofControlPointTriplet_thisGameobjectIsBoundTo = i_ofContainingControlPoint_insideControlPointsList;
connectionComponent_onBoundGameobject.subPointType_whereThisGameobjectIsBoundTo = subPointType;
SetPos_inUnitsOfGlobalSpace(boundGameobject.transform.position, true, boundGameobject);
TryTransferBoundGameobjectsRotationToAnchorPointsDirection();
}
public virtual void ResetDirectionSourceToIndependent()
{
}
public virtual void TryTransferBoundGameobjectsRotationToAnchorPointsDirection()
{
}
public Vector2 GetPos_inUnitsOfGlobalSpace()
{
return position_inUnitsOfGlobalSpace;
}
public Vector3 GetPos_inUnitsOfGlobalSpace_asV3DrawPos()
{
return UtilitiesDXXL_DrawBasics2D.Position_V2toV3(position_inUnitsOfGlobalSpace, bezierSplineDrawer_thisSubPointIsPartOf.GetZPos_global_for2D());
}
public Vector2 GetPos_inUnitsOfActiveDrawSpace()
{
return position_inUnitsOfActiveDrawSpace;
}
public virtual void SetPos_inUnitsOfGlobalSpace(Vector2 newPos_inUnitsOfGlobalSpace, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
//all children override this
}
public Vector2 SetPos_inUnitsOfGlobalSpace_butIgnoreDependentValues_nonRecursively(Vector2 newPos_inUnitsOfGlobalSpace, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
//"_nonRecursively" indicates: This function is reserved to be called inside the overrides of "SetPos_inUnitsOfGlobalSpace". In all other cases use "SetPos_inUnitsOfGlobalSpace(..., false)"
Vector2 offset_fromPrevious_toNewPosition_inUnitsOfGlobalSpace = newPos_inUnitsOfGlobalSpace - position_inUnitsOfGlobalSpace;
position_inUnitsOfGlobalSpace = newPos_inUnitsOfGlobalSpace;
position_inUnitsOfActiveDrawSpace = bezierSplineDrawer_thisSubPointIsPartOf.TransformPos_fromGlobalSpace_toUnitsOfActiveDrawSpace(newPos_inUnitsOfGlobalSpace);
SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled();
if (boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled)
{
if (boundGameobject != boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
boundGameobject.transform.position = new Vector3(newPos_inUnitsOfGlobalSpace.x, newPos_inUnitsOfGlobalSpace.y, boundGameobject.transform.position.z);
}
}
return offset_fromPrevious_toNewPosition_inUnitsOfGlobalSpace;
}
public void SetPos_inUnitsOfActiveDrawSpace(Vector2 newPos_inUnitsOfActiveDrawSpace, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector2 newPos_inUnitsOfGlobalSpace = bezierSplineDrawer_thisSubPointIsPartOf.TransformPos_fromUnitsOfActiveDrawSpace_toGlobalSpace(newPos_inUnitsOfActiveDrawSpace);
SetPos_inUnitsOfGlobalSpace(newPos_inUnitsOfGlobalSpace, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void AddPosOffset_inUnitsOfGlobalSpace(Vector2 posOffset_inUnitsOfGlobalSpace, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector2 newPos_inUnitsOfGlobalSpace = GetPos_inUnitsOfGlobalSpace() + posOffset_inUnitsOfGlobalSpace;
SetPos_inUnitsOfGlobalSpace(newPos_inUnitsOfGlobalSpace, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public void AddPosOffset_inUnitsOfActiveDrawSpace(Vector2 posOffset_inUnitsOfActiveDrawSpace, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
Vector2 newPos_inUnitsOfActiveDrawSpace = GetPos_inUnitsOfActiveDrawSpace() + posOffset_inUnitsOfActiveDrawSpace;
SetPos_inUnitsOfActiveDrawSpace(newPos_inUnitsOfActiveDrawSpace, updateDependentValuesOnControlPointTriplet, boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls);
}
public virtual void Set_direction_toForward_inUnitsOfGlobalSpace_normalized(Vector2 newDirection_toForward_inUnitsOfGlobalSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
//-> is not intended to be called for non-overriding helperPoints. Use "helperPoint.Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized()" instead
UtilitiesDXXL_Log.PrintErrorCode("61");
}
public virtual void Set_direction_toBackward_inUnitsOfGlobalSpace_normalized(Vector2 newDirection_toBackward_inUnitsOfGlobalSpace_normalized, bool updateDependentValuesOnControlPointTriplet, GameObject boundGameobjectThatTriggeredThisPosOrDirChange_independentlyFromSplineControls)
{
//-> is not intended to be called for non-overriding helperPoints. Use "helperPoint.Set_direction_fromMountingAnchorToThisHelperPoint_inUnitsOfGlobalSpace_normalized()" instead
UtilitiesDXXL_Log.PrintErrorCode("62");
}
public virtual InternalDXXL_BezierControlAnchorSubPoint.JunctureType GetJunctureType()
{
//-> is not intended to be called for non-overriding helperPoints
UtilitiesDXXL_Log.PrintErrorCode("63");
return InternalDXXL_BezierControlAnchorSubPoint.JunctureType.aligned;
}
public virtual InternalDXXL_BezierControlHelperSubPoint2D GetForwardHelper()
{
//-> is not intended to be called for non-overriding helperPoints
UtilitiesDXXL_Log.PrintErrorCode("64");
return null;
}
public virtual InternalDXXL_BezierControlHelperSubPoint2D GetBackwardHelper()
{
//-> is not intended to be called for non-overriding helperPoints
UtilitiesDXXL_Log.PrintErrorCode("65");
return null;
}
public virtual InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D Get_sourceOf_directionToHelper_unifiedTowardsForwardForCaseNonKinked()
{
//-> is not intended to be called for non-overriding helperPoints
UtilitiesDXXL_Log.PrintErrorCode("66");
return InternalDXXL_BezierControlAnchorSubPoint2D.SourceOf_directionToHelper2D.independentFromGameobject;
}
public virtual InternalDXXL_BezierControlSubPoint2D GetNextSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
//-> all children override this
return null;
}
public virtual InternalDXXL_BezierControlSubPoint2D GetPreviousSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
//-> all children override this
return null;
}
public virtual InternalDXXL_BezierControlSubPoint2D GetNextUsedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
//-> all children override this
return null;
}
public virtual InternalDXXL_BezierControlSubPoint2D GetPreviousUsedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
//-> all children override this
return null;
}
public InternalDXXL_BezierControlSubPoint2D GetNextUsedNonSuperimposedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
InternalDXXL_BezierControlSubPoint2D currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir = GetNextSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet); //-> cannot use "GetNext-USED-SubPointAlongSplineDir()" here in this function, because then an endless-loop-prevention-check is not possible for cases, where this function is called on subPoints which are iself "isUsed=false".
int maxAttempts = 100;
for (int i = 0; i < maxAttempts; i++)
{
if (currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir != null)
{
if (currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir != this) //-> prevent endless loops around closed splines
{
if (currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir.isUsed == true)
{
if (UtilitiesDXXL_Math.CheckIf_twoVectorsAreApproximatelyEqual(GetPos_inUnitsOfGlobalSpace(), currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir.GetPos_inUnitsOfGlobalSpace()))
{
currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir = currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir.GetNextSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
else
{
return currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir;
}
}
else
{
currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir = currentCandidateFor_nextUsedNonSuperimposedSubPointAlongSplineDir.GetNextSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
}
else
{
return null;
}
}
else
{
return null;
}
}
return null;
}
public InternalDXXL_BezierControlSubPoint2D GetPreviousUsedNonSuperimposedSubPointAlongSplineDir(bool allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet)
{
InternalDXXL_BezierControlSubPoint2D currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir = GetPreviousSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet); //-> cannot use "GetPrevious-USED-SubPointAlongSplineDir()" here in this function, because then an endless-loop-prevention-check is not possible for cases, where this function is called on subPoints which are iself "isUsed=false".
int maxAttempts = 100;
for (int i = 0; i < maxAttempts; i++)
{
if (currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir != null)
{
if (currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir != this) //-> prevent endless loops around closed splines
{
if (currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir.isUsed == true)
{
if (UtilitiesDXXL_Math.CheckIf_twoVectorsAreApproximatelyEqual(GetPos_inUnitsOfGlobalSpace(), currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir.GetPos_inUnitsOfGlobalSpace()))
{
currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir = currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir.GetPreviousSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
else
{
return currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir;
}
}
else
{
currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir = currentCandidateFor_previousUsedNonSuperimposedSubPointAlongSplineDir.GetPreviousSubPointAlongSplineDir(allowRequestingControlPointAsResult_inCaseOfRingSplineOfOnlyOneControlPointTriplet);
}
}
else
{
return null;
}
}
else
{
return null;
}
}
return null;
}
public virtual Vector2 GetDirectionAlongSplineForwardBasedOnNeighborPoints_inUnitsOfGlobalSpace()
{
//-> all children override this
//-> not guaranteed normalized
//-> not to be consued with "anchor.Get_direction_to*Helper*()"
return Vector2.right;
}
public virtual bool IsUnusedHelperPointAtStartOrEndOfUnclosedSplines_onTheControlPointSideTowardsVoid()
{
//-> all children override this
return false;
}
public Rect RecalcCurrentRect_forInspector(Rect reducedRectForOnlyContentLines, float currentHeightOffset)
{
#if UNITY_EDITOR
return new Rect(reducedRectForOnlyContentLines.x, reducedRectForOnlyContentLines.y + currentHeightOffset, reducedRectForOnlyContentLines.width, UnityEditor.EditorGUIUtility.singleLineHeight);
#else
return default;
#endif
}
public Vector2 Draw_Vector2Field_withoutLineBreak_forInspector(Rect position, GUIContent label, Vector2 value, bool allowRichText = false)
{
return Draw_Vector2Field_withoutLineBreak_forInspector(position, out Rect rectForOnlyThePrefixLabel, label, value, allowRichText);
}
public Vector2 Draw_Vector2Field_withoutLineBreak_forInspector(Rect position, out Rect rectForOnlyThePrefixLabel, GUIContent label, Vector2 value, bool allowRichText = false)
{
#if UNITY_EDITOR
//"EditorGUI.Vector2Field" makes a line break and expands to two lines if the inspector window gets narrow. Therefore this modified version without the line break.
Rect position_forOnlyTheContentValues;
if (allowRichText)
{
GUIStyle styleWithRichText = new GUIStyle(UnityEditor.EditorStyles.label);
styleWithRichText.richText = true;
position_forOnlyTheContentValues = UnityEditor.EditorGUI.PrefixLabel(position, label, styleWithRichText);
}
else
{
position_forOnlyTheContentValues = UnityEditor.EditorGUI.PrefixLabel(position, label);
}
rectForOnlyThePrefixLabel = new Rect(position.x, position.y, position.width - position_forOnlyTheContentValues.width, position.height);
Vector2 value_after = UnityEditor.EditorGUI.Vector2Field(position_forOnlyTheContentValues, GUIContent.none, value);
return value_after;
#else
rectForOnlyThePrefixLabel = default;
return default;
#endif
}
public Vector2 position_inUnitsOfActiveDrawSpace_afterInspectorInput;
public void DrawPositionLine_forInspector(Rect rect, GUIContent guiContent)
{
position_inUnitsOfActiveDrawSpace_afterInspectorInput = Draw_Vector2Field_withoutLineBreak_forInspector(rect, guiContent, position_inUnitsOfActiveDrawSpace);
}
public GameObject boundGameobject_afterInspectorInput;
public void DrawBoundGameobjectLine_forInspector(Rect rect, GUIContent guiContent)
{
#if UNITY_EDITOR
SetBoolOf_boundGameobjectInclConnectionComponent_isAssignedActiveAndEnabled();
bool boundGameobjectConnetionExists_butIsNotActiveRespEnabled = ((boundGameobject != null) && (connectionComponent_onBoundGameobject != null) && ((boundGameobject.activeInHierarchy == false) || (connectionComponent_onBoundGameobject.enabled == false)));
if (boundGameobjectConnetionExists_butIsNotActiveRespEnabled)
{
Rect rect_forGameobjectPickerAndInactiveNotifier = UnityEditor.EditorGUI.PrefixLabel(rect, guiContent);
float posOfSeparation_0to1 = 0.5f;
Rect rect_gameobjectPickerWithoutLabel = new Rect(rect_forGameobjectPickerAndInactiveNotifier.x, rect_forGameobjectPickerAndInactiveNotifier.y, posOfSeparation_0to1 * rect_forGameobjectPickerAndInactiveNotifier.width, rect_forGameobjectPickerAndInactiveNotifier.height);
Rect rect_forInactiveRespDisabledNotifier = new Rect(rect_forGameobjectPickerAndInactiveNotifier.x + posOfSeparation_0to1 * rect_forGameobjectPickerAndInactiveNotifier.width, rect_forGameobjectPickerAndInactiveNotifier.y, (1.0f - posOfSeparation_0to1) * rect_forGameobjectPickerAndInactiveNotifier.width, rect_forGameobjectPickerAndInactiveNotifier.height);
boundGameobject_afterInspectorInput = (UnityEngine.GameObject)UnityEditor.EditorGUI.ObjectField(rect_gameobjectPickerWithoutLabel, GUIContent.none, boundGameobject, typeof(UnityEngine.GameObject), true);
if (boundGameobject.activeInHierarchy == false)
{
UnityEditor.EditorGUI.LabelField(rect_forInactiveRespDisabledNotifier, new GUIContent(" is inactive", "The bound gameobject or any of it's parents is set to inactive. As long as this is the case the tieing will not be updated."));
}
else
{
UnityEditor.EditorGUI.LabelField(rect_forInactiveRespDisabledNotifier, new GUIContent(" is disabled", "The connection component on the bound gameobject is disabled. As long as this is the case the tieing will not be updated."));
}
}
else
{
boundGameobject_afterInspectorInput = (UnityEngine.GameObject)UnityEditor.EditorGUI.ObjectField(rect, guiContent, boundGameobject, typeof(UnityEngine.GameObject), true);
}
#endif
}
public string Get_tooltip_explainingWheatherUnitsAreInGlobalOrInLocalSpace_forInspector()
{
switch (bezierSplineDrawer_thisSubPointIsPartOf.drawSpace)
{
case BezierSplineDrawer.DrawSpace.global:
return "This value display is in units of the active draw space, which is currently the global space.";
case BezierSplineDrawer.DrawSpace.localDefinedByThisGameobject:
return "This value display is in units of the active draw space, which is currently the local space defined by the gameobject that holds this spline component.";
default:
return "";
}
}
public virtual float GetPropertyHeightForInspectorList()
{
//-> all children override this
return 16.0f;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d39fe386fc63a5040986d0ecd2cf7c87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,104 @@
namespace DrawXXL
{
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
public class InternalDXXL_BezierHandles
{
static float valueToSlide_duringMouseDown;
static Vector3 direction_duringMouseDown;
static Vector2 currentMousePosition;
static Vector2 mousePosition_duringMouseDown;
public static float ValueSliderAlongCurve(float valueToSlide, Vector3 position, Quaternion rotation, Vector3 direction_duringMouseDown, float size, Handles.CapFunction capFunction, float snap)
{
int control_ID = GUIUtility.GetControlID(FocusType.Passive);
Event currentEvent = Event.current;
switch (currentEvent.GetTypeForControl(control_ID))
{
case EventType.MouseDown:
if ((HandleUtility.nearestControl == control_ID) && (currentEvent.button == 0) && (currentEvent.alt == false))
{
GUIUtility.hotControl = control_ID;
valueToSlide_duringMouseDown = valueToSlide;
mousePosition_duringMouseDown = currentEvent.mousePosition;
currentMousePosition = currentEvent.mousePosition;
InternalDXXL_BezierHandles.direction_duringMouseDown = direction_duringMouseDown;
currentEvent.Use();
EditorGUIUtility.SetWantsMouseJumping(1);
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == control_ID)
{
GUIUtility.hotControl = 0;
currentEvent.Use();
EditorGUIUtility.SetWantsMouseJumping(0);
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == control_ID)
{
currentMousePosition = currentMousePosition + currentEvent.delta;
float travelledDistance_alongDirection = HandleUtility.CalcLineTranslation(mousePosition_duringMouseDown, currentMousePosition, position, InternalDXXL_BezierHandles.direction_duringMouseDown) / size;
float slideSpeed = 0.1f;
valueToSlide = (Handles.SnapValue(travelledDistance_alongDirection * slideSpeed, snap) + 1.0f) * valueToSlide_duringMouseDown;
GUI.changed = true;
currentEvent.Use();
}
break;
case EventType.Repaint:
Color color_before = Handles.color;
if (control_ID == GUIUtility.hotControl)
{
Handles.color = Handles.selectedColor;
}
else
{
if (IsHovering(control_ID, currentEvent))
{
Handles.color = Handles.preselectionColor;
}
}
capFunction(control_ID, position, rotation, size, EventType.Repaint);
Handles.color = color_before;
break;
case EventType.Layout:
capFunction(control_ID, position, rotation, size, EventType.Layout);
break;
default:
break;
}
return valueToSlide;
}
static bool IsHovering(int control_ID, Event currentEvent)
{
return ((GUIUtility.hotControl == 0) && (control_ID == HandleUtility.nearestControl) && (currentEvent.alt == false));
}
public static bool PlusButton(Vector3 position_inUnitsOfGlobalSpace, float sizeScaleFactor, Color color, Vector3 buttonPlaneNormalAwayFromObserver_normalized, Vector3 buttonPlaneUp_normalized, Vector3 buttonPlaneRight_normalized, GUIContent plusSymbolIcon)
{
Quaternion rotation_ofButton = Quaternion.LookRotation(buttonPlaneNormalAwayFromObserver_normalized, Vector3.zero);
float unmodified_handleSize = HandleUtility.GetHandleSize(position_inUnitsOfGlobalSpace);
float radius_ofButton = 0.5f * sizeScaleFactor * unmodified_handleSize; //"0.5f" factor because "Handles.CircleHandleCap" as a 2D cap seems to interpret the specified size as "radius" differently form the 3D caps that interpret it as "diameter".
Handles.color = color;
Handles.DrawSolidDisc(position_inUnitsOfGlobalSpace, buttonPlaneNormalAwayFromObserver_normalized, radius_ofButton);
float shiftOffset_ofPlusSign = 0.09375f * unmodified_handleSize;
Vector3 posOfPlusSign_inUnitsOfGlobalSpace = position_inUnitsOfGlobalSpace + shiftOffset_ofPlusSign * buttonPlaneUp_normalized - shiftOffset_ofPlusSign * buttonPlaneRight_normalized;
Handles.Label(posOfPlusSign_inUnitsOfGlobalSpace, plusSymbolIcon);
Handles.color = UtilitiesDXXL_Colors.GetSimilarColorWithOtherBrightnessValue(color);
bool buttonHasBeenClicked = Handles.Button(position_inUnitsOfGlobalSpace, rotation_ofButton, radius_ofButton, radius_ofButton, Handles.CircleHandleCap);
return buttonHasBeenClicked;
}
}
#endif
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 726506d8e0118b84b87cf0c292ef0dd5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
namespace DrawXXL
{
using UnityEngine;
public struct InternalDXXL_BezierPointShapeConfig
{
public Vector3 anchorPos;
public Vector3 direction_toForward_normalized;
public Vector3 direction_toBackward_normalized;
public Vector3 forwardHelperPos;
public float absDistanceToForwardAnchorPoint;
public Vector3 backwardHelperPos;
public float absDistanceToBackwardAnchorPoint;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 79065652a54ba324ba727f6328bf5481
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
namespace DrawXXL
{
using UnityEngine;
public struct InternalDXXL_BezierPointShapeConfig2D
{
public Vector2 anchorPos;
public Vector2 direction_toForward_normalized;
public Vector2 direction_toBackward_normalized;
public Vector2 forwardHelperPos;
public float absDistanceToForwardAnchorPoint;
public Vector2 backwardHelperPos;
public float absDistanceToBackwardAnchorPoint;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cd1c9a582882a384ab476c5943ed8da3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,34 @@
namespace DrawXXL
{
using System;
using UnityEngine;
[Serializable]
public struct InternalDXXL_TaggedScreenspaceObject
{
[SerializeField] public GameObject previousGameobject;
[SerializeField] public GameObject gameobject;
[SerializeField] public Color color;
[SerializeField] public string text;
public void TryUseSeededColorFromGameobjectID()
{
if (gameobject != null)
{
if (previousGameobject == null)
{
color = SeededColorGenerator.ColorOfGameobjectID(gameobject);
}
else
{
if (gameobject != previousGameobject)
{
color = SeededColorGenerator.ColorOfGameobjectID(gameobject);
}
}
}
previousGameobject = gameobject;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8387cf011e2b3aa448179012ee17f256
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,5 @@
namespace DrawXXL
{
public enum CollisionType { cast, overlap }
public enum WantedHits { onlyFirst, all }
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ab3fba1529d5b72409dd80db32977a1d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,186 @@
namespace DrawXXL
{
using UnityEngine;
using System.Collections.Generic;
public class UtilitiesDXXL_Components
{
public static int frameCount_forWhichAnEditorFrameStep_hasBeenSheduled_byAChart = -10; //this could also be a member of the chart components itself, but then multiple frame steps will be executed onPause if multiple charts exist in the scene.
public static int frameCount_forWhichAnEditorFrameStep_hasBeenSheduled_byADrawerComponent = -10; //this could also be a member of the drawer components itself, but then multiple frame steps will be executed onPause if multiple drawer components exist in the scene.
public static void TryProceedOneSheduledFrameStep()
{
#if UNITY_EDITOR
//sidenote:
//-> it seems that "EditorApplication.Step()" cannot be called from inside "OnDrawGizmos". Unity prints several errors surrounding the problem "recursive OnGUI rendering".
//-> it works without errors when called from a "EditorApplication.update"-delegate
//-> multiple components that call this function still result in only one frame step, because after "UnityEditor.EditorApplication.Step()" the "Time.frameCount" is not the same any more.
if (UnityEditor.EditorApplication.isPlaying && UnityEditor.EditorApplication.isPaused)
{
bool hasAlreadyStepped_dueToTheFlagConcerningCharts = false;
if (DrawCharts.chartInspectorComponentsAutomaticallyProceedOneFrameStepOnPauseStarts_toPreventFrozenOverlayDraw)
{
if (frameCount_forWhichAnEditorFrameStep_hasBeenSheduled_byAChart == Time.frameCount)
{
hasAlreadyStepped_dueToTheFlagConcerningCharts = true;
UnityEditor.EditorApplication.Step();
}
}
if (DrawBasics.drawerComponentsAutomaticallyProceedOneFrameStepOnPauseStarts_toPreventFrozenOverlayDraw)
{
if (hasAlreadyStepped_dueToTheFlagConcerningCharts == false)
{
if (frameCount_forWhichAnEditorFrameStep_hasBeenSheduled_byADrawerComponent == Time.frameCount)
{
UnityEditor.EditorApplication.Step();
}
}
}
}
#endif
}
public static float Get_inspector_singleLineHeightInclSpacingBetweenLines()
{
#if UNITY_EDITOR
return (UnityEditor.EditorGUIUtility.singleLineHeight + UnityEditor.EditorGUIUtility.standardVerticalSpacing);
#else
return 18.0f;
#endif
}
static List<int> id_ofMonobehavioursThatDrawViaOnDrawGizmos = new List<int>();
#if UNITY_EDITOR
static int highestUsed_i_inMonoBList_sinceLastDrawnLinesCounterReset = -1;
#endif
public static bool currentVirtualOnDrawGizmoCycle_shouldRepaintAllViews = false;
public static int virtualGizmoCycleCount;
public static void ReportOnDrawGizmosCycleOfAMonoBehaviour(int id_ofReportingMonoB)
{
#if UNITY_EDITOR
///Problem:
//The maxLinesPerFrame-limit to prevent editor freezing during playmode depends on "Time.frameCount"
//outside playmode or inside playmodePauses "Time.frameCount" is not reliable
//These are the currently known options for an maxLinesPerFrame-limit outside (nonPaused)playmode:
///Using "Time.frameCount"
//-> it is not incremented in pause phases
//-> it is sometimes incremented in edit mode, and sometimes not. Is not reliable and not documented by Unity for edit mode.
///Using "Time.renderedFrameCount"
//-> according to forum posts this is incremented in pause phases. I couldn't reproduce this: It didn't increment during pauses in my case
//-> it is not documented by Unity and could change it's behaviour without notice, or even disappear completely
///Using "EditorApplication.timeSinceStartup"
//-> as "Time.realtimeSinceStartup" it is dependent from the platform and may sometimes not update regularly.
//-> doesn't help anyway, because it measures "time", but doesn't say anything about when a new OnDrawGizmos-cycle starts. E.g. allowing a limitedNumberOfLines(L) inside a timespan(x) doesn't prevent Editor freeze, because the drawnLines itself can raise the OnDrawGizmos-executionTime, and then after the timespan(x) has passed (but still inside the same OnDrawGizmo) a new set of limitedNumberOfLines(L) is allowed to be drawn, raising the execution time of the current OnDrawGizmo once again. This can endlessly repeat in the same OnDrawGizmos and freeze the Editor.
///Using a registered callback from "EditorApplication.update"
//-> EditorApplication.update has no guaranteed frequency and can (according to Unitys documentation) be called multiple times per frame update.
//-> It would still need a managing object that oversees all drawing MonoBehaviours (like this class here)
//-> Cannot be used for static-only drawing, but needs a MonoBehaviour in the scene. Or doesn't it? -> https://docs.unity3d.com/Manual/RunningEditorCodeOnLaunch.html
///Each drawing MonoBehaviour resets the counter after his own draw operation
//-> is at least SOME protection, because
//---> it will work if a single drawnObject exceeds the limit by itself
//---> it will not work if multiple drawnObject exceeds the limit with their cumulated lines
//---> though in most cases new drawingBehaviours will get added "gradually", so the editor slow down is also gradually and the user will notice that something is going wrong, so he can at least react. That may be acceptable, because the maxLines-limit is not for preventing slowdown, but for preventing freeze that forces the user to forceQuit the whole Unity application.
//It is similar in the special case of Charts:
//-> "OnDrawGizmos()" gets called for every existing "DrawXXLChartInspector"-gameObject in the scene, so the maxAllowedLinesPerFrame get summed up and become "maxLinesPerFrameLimit * chartsThatAreCurrentlyInspectedViaComponent"
//-> In many cases this should be no problem, because if a user calls "CreateChartInspectionGameobject(true)" for multiple charts at once then he has drawn them before the pause already all inside "Update()" (where the maxLinesPerFrame-limit works correctly), so the maxLinesPerFrame-limit would have spoken already.
//-> The loophole is this:
//---> The maxLinesLimit has not spoken before the pause because only a small section of the lines were displayed. Then during pause the user zooms out to display more.
//---> But there is still a security:
//-----> 1) If the user raises the linesPerChart very fast for 1 chart: Then the maxLinesLimit kicks in for this chart and prevents performance freezing.
//-----> 2) If he raises the linesPerChart for one chart after another to slighly below the maxLinesPerFrame limit, then it's a "gradual performance slowdown". He will realize it and stop the process before the whole system freezes.
///Central MonoBehaviour-OnDrawGizmosCalls-managingClass [= implemented solution below]
//-> the linesCounter gets reset as soon as any drawing MonoBehaviour comes back for a second draw (each MonoBehaviour reports only once inside its OnDrawGizmos. Custom MonoBehaviours from users don't participate in this, but are represented by the "DrawXXL_LinesManager"-singleton). In the meantime other drawing MonoBehaviour may have drawn. This is in most cases one OnDrawGizmo-cycle
//-> the execution order of different MonoBehaviour types stays the same according to https://docs.unity3d.com/Manual/class-MonoManager.html
//-> if there is still a mixup of the order of MonoBehaviours then the introduced error is not big, assumed to be not more than factor 2. This is still ok in respect of the purpose of the whole maxLines-mechanic, which is not preventing "editor-slowdown" (which is annoying but can be handled), but preventing "editor-freeze" (which may force the user to force-quit the whole Unity application).
//-> using only the DrawXXL_LinesManager may be not sufficient, since its "OnDrawGizmos()" event is not guaranteed to be fired always. (sidenote: It may be guaranteed due to "ExpandComponentInInspector")
for (int i = 0; i <= highestUsed_i_inMonoBList_sinceLastDrawnLinesCounterReset; i++)
{
if (id_ofMonobehavioursThatDrawViaOnDrawGizmos[i] == id_ofReportingMonoB)
{
highestUsed_i_inMonoBList_sinceLastDrawnLinesCounterReset = -1;
InitializeNewVirtualOnDrawGizmoCycle();
break;
}
}
highestUsed_i_inMonoBList_sinceLastDrawnLinesCounterReset++;
if (id_ofMonobehavioursThatDrawViaOnDrawGizmos.Count <= highestUsed_i_inMonoBList_sinceLastDrawnLinesCounterReset)
{
id_ofMonobehavioursThatDrawViaOnDrawGizmos.Add(id_ofReportingMonoB);
}
else
{
id_ofMonobehavioursThatDrawViaOnDrawGizmos[highestUsed_i_inMonoBList_sinceLastDrawnLinesCounterReset] = id_ofReportingMonoB;
}
#endif
}
static void InitializeNewVirtualOnDrawGizmoCycle()
{
TryRepaintAllViews(); //this is called BEFORE "ResetLinesPerFrameCounter()", because it needs an uncleared "DrawnLinesSinceFrameStart" value
DXXLWrapperForUntiysBuildInDrawLines.ResetLinesPerFrameCounter();
virtualGizmoCycleCount++;
if (Application.isPlaying == false) { virtualGizmoCycleCount = 0; } //-> not used outside playmode
}
static void TryRepaintAllViews()
{
#if UNITY_EDITOR
//-> The scene view and game view windows are continuously repainted during playmode
//-> Though during edit mode or game pauses they are not
//-> The drawn shapes should continuously be updated on the screen, also outside playmode: Think of a "BoolDisplayer". It should always show the most current value. Also any simple line can change its position and should appear with its current shape.
//-> It is expensive, but doing it inside "InitializeNewVirtualOnDrawGizmoCycle()" at least ensures that it is called only once per OnDrawGizmo-cycle.
//-> And "currentVirtualOnDrawGizmoCycle_shouldRepaintAllViews" prevents some more repaints, mostly by detecting if the drawn lines came from user code calls and not by drawer components. Drawer components anyway automatically repaint the views, but only if their drawn shape as changed/one of their inspector values has changed.
if (currentVirtualOnDrawGizmoCycle_shouldRepaintAllViews)
{
if ((UnityEditor.EditorApplication.isPlaying == false) || UnityEditor.EditorApplication.isPaused)
{
if (DXXLWrapperForUntiysBuildInDrawLines.DrawnLinesSinceFrameStart > 0)
{
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
}
}
currentVirtualOnDrawGizmoCycle_shouldRepaintAllViews = false;
#endif
}
public static void ExpandComponentInInspector(MonoBehaviour componentToExpand)
{
//Reference: https://answers.unity.com/questions/801692/query-whether-inspector-is-folded.html
//-> The problem is that "OnDrawGizmos()" (and along with it all Gizmo lines) is only fired when the component is expanded in the inspector. The gameobject doesn't have to be selected, but the component has to be expanded (that means you have to "leave" the selected gameobject (via selecting an other gameobject) also in a moment where the component is expanded).
//-> This disturbs drawing in edit mode. The components already have toggles for "enable/disable" and "draw only if selected", but on top of this the user has to be aware of this "component has to be expanded"-requirement, and may be irritated why his drawer component stops working sometimes.
//-> It gets more irritating for the user if the DrawXXL_LinesManager component is collapsed due to whatever reason, because then the user isn't event working with components but only with static code calls.
//-> The reference link above describes two approaches how to force a component to "expanded": One is via "UnityEditorInternal.InternalEditorUtility.SetIsInspectorExpanded()", the other is more complicated via reflection.
//-> Luckily it turns out that: The "UnityEditorInternal.InternalEditorUtility.SetIsInspectorExpanded()" function doesn't work for it's "actual task", that means it doesn't expand the components, BUT: It seems to do something in the background, which solves the actual problem here: Despite the components expanded state seeming to be not affected in the visual appearance of the inspector, the "OnDrawGizmos()"-function DOES think that it is expanded and does fire.
//-> This is even better than forcing the visual appearance in the inspector, because now the ability for the user to collapse or expand the component is preserved.
//-> There seem to be situations, where this "hidden" expanded state does transform to be "really expanding the components also visually". One such situation is when a new additional component (of any (other) type) is added to the gameobject. This may be a downside of the solution: It could annoy the user that he has to manually collapse the components over and over again, when he wants them to not take display space in the inspector.
//---> One such situation is when a new additional component (of any (other) type) is added to the gameobject
//---> Also when a component is removed
//---> Restarting the Unity Editor (which by the way means, that this "hidden expanded state" is preserved even when the Unity Editor is closed)
//-> This "hidden expanded" state seems also not to get overwritten when the component is collapsed via mouse click on the small triangle symbol in the top left corner of the component inspector window. Or else it could be that it does get overwritten in this case, but "OnDrawGizmos" may get called one last time and rescues the expanded state by once again calling "ExpandComponentInInspector()"
//-> Though some uncertainty remains if this solution will always work, also in future versions of Unity, because it's an undocumented feaure.
#if UNITY_EDITOR
UnityEditorInternal.InternalEditorUtility.SetIsInspectorExpanded(componentToExpand, true);
#endif
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 43f29088c00ea5440949ad9ee2895f37
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 747465b5900df494a8064194e81a3a4b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
namespace DrawXXL
{
using UnityEngine;
[HelpURL("https://www.symphonygames.net/drawxxldocumentation/index.html")]
[AddComponentMenu("Xeric Library/DebugDrawLibrary/Internal Not For Manual Creation/Visualizer Screenspace Parent")]
[DefaultExecutionOrder(31000)] //negative numers are early, positive numbers are late. Range is till 32000 to both negative and positive direction.
public class VisualizerScreenspaceParent : VisualizerParent
{
public enum ScreenspaceDefiningCameras { cameraAtThisGameobject, manuallyAssignedCamera, automaticallySearchForMainGameViewCamera, sceneViewCamera };
[SerializeField] public ScreenspaceDefiningCameras screenspaceDefiningCamera = ScreenspaceDefiningCameras.cameraAtThisGameobject;
ScreenspaceDefiningCameras screenspaceDefiningCamera_duringLastCall = ScreenspaceDefiningCameras.cameraAtThisGameobject;
Camera cameraComponentOnThisGameobject;
Camera sceneViewCamera_thatStaysEvenIfTheFocusChangesToAnotherSceneViewWindow;
[SerializeField] public Camera manuallyAssignedCamera;
[SerializeField] public bool alwaysChangeToCurrentlyActiveSceneView_insteadOfStayingAtTheSelectedOne = false;
Camera usedCamera;
[SerializeField] public bool usedCameraIsAvailable;
public Vector2 positionInsideViewport0to1 = new Vector2(0.5f, 0.5f);
public Vector2 positionInsideViewport0to1_v2 = new Vector2(0.5f, 0.5f);
public void TryFetchCamOnThisGO_andDecideScreenspaceDefiningCamera()
{
//-> is also called when components or gameobjects (containing this component) get copied und therefore the reference is updated to the new camera component on the new gameobject
if (screenspaceDefiningCamera == ScreenspaceDefiningCameras.cameraAtThisGameobject)
{
this.TryGetComponent(out cameraComponentOnThisGameobject);
if (cameraComponentOnThisGameobject == null)
{
screenspaceDefiningCamera = ScreenspaceDefiningCameras.automaticallySearchForMainGameViewCamera;
screenspaceDefiningCamera_duringLastCall = ScreenspaceDefiningCameras.automaticallySearchForMainGameViewCamera;
}
}
}
public Camera Get_usedCamera(string nameOfComponentForErrorLog)
{
switch (screenspaceDefiningCamera)
{
case ScreenspaceDefiningCameras.cameraAtThisGameobject:
if (cameraComponentOnThisGameobject == null)
{
//this is for the case when a camera component is created at the gameobject AFTER the drawer component has been created
//it is accepted to call "TryGetComponent" here frequently (per Update-loop), because it is anyway only during an invalid case ("no camera found") on which the user gets notified to fix it via inspector help box.
this.TryGetComponent(out cameraComponentOnThisGameobject);
}
usedCamera = cameraComponentOnThisGameobject;
break;
case ScreenspaceDefiningCameras.manuallyAssignedCamera:
usedCamera = manuallyAssignedCamera;
break;
case ScreenspaceDefiningCameras.automaticallySearchForMainGameViewCamera:
UtilitiesDXXL_Screenspace.GetAutomaticCameraForDrawing(out usedCamera, nameOfComponentForErrorLog, true);
break;
case ScreenspaceDefiningCameras.sceneViewCamera:
#if UNITY_EDITOR
if (UnityEditor.SceneView.lastActiveSceneView != null)
{
if (sceneViewCamera_thatStaysEvenIfTheFocusChangesToAnotherSceneViewWindow == null) { sceneViewCamera_thatStaysEvenIfTheFocusChangesToAnotherSceneViewWindow = UnityEditor.SceneView.lastActiveSceneView.camera; }
if ((screenspaceDefiningCamera_duringLastCall != ScreenspaceDefiningCameras.sceneViewCamera) || (alwaysChangeToCurrentlyActiveSceneView_insteadOfStayingAtTheSelectedOne == true))
{
sceneViewCamera_thatStaysEvenIfTheFocusChangesToAnotherSceneViewWindow = UnityEditor.SceneView.lastActiveSceneView.camera;
}
if (alwaysChangeToCurrentlyActiveSceneView_insteadOfStayingAtTheSelectedOne == false)
{
usedCamera = sceneViewCamera_thatStaysEvenIfTheFocusChangesToAnotherSceneViewWindow;
}
else
{
usedCamera = UnityEditor.SceneView.lastActiveSceneView.camera;
}
}
else
{
usedCamera = null;
}
#else
UtilitiesDXXL_Screenspace.GetAutomaticCameraForDrawing(out usedCamera, nameOfComponentForErrorLog, true);
#endif
break;
default:
usedCamera = null;
break;
}
screenspaceDefiningCamera_duringLastCall = screenspaceDefiningCamera;
usedCameraIsAvailable = (usedCamera != null);
return usedCamera;
}
public bool CheckIf_usedCameraIsActiveAndEnabled()
{
if (usedCamera != null)
{
bool isSceneViewCamera = false;
#if UNITY_EDITOR
if (UnityEditor.SceneView.lastActiveSceneView != null)
{
isSceneViewCamera = (usedCamera == UnityEditor.SceneView.lastActiveSceneView.camera);
}
#endif
return (isSceneViewCamera || usedCamera.isActiveAndEnabled);
}
else
{
return false;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 652dc1e2204fe18489ba53c3044899bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: