123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- #if UNITY_EDITOR
- using UnityEngine;
- using UnityEditor;
- using System.Collections.Generic;
- namespace O3DWB
- {
- public class ObjectPlacementBlockManualConstructionSession
- {
- #region Private Variables
- private ObjectPlacementBlock _block;
- private List<ObjectPlacementBoxStackSegment> _blockSegments;
- private ObjectPlacementExtensionPlane _blockExtensionPlane;
- private ObjectPlacementBlockManualConstructionSettings _manualConstructionSettings;
- private ObjectPlacementBlockPaddingSettings _paddingSettings;
- private ObjectPlacementBlockHeightAdjustmentSettings _heightAdjustmentSettings;
- private ObjectPlacementBlockAutomaticRandomHeightAdjustmentSettings _automaticRandomHeightAdjustmentSettings;
- private ObjectPlacementBlockSubdivisionSettings _subdivisionSettings;
- private Vector3 _segmentExtensionDirection;
- private Vector3 _segmentCollectionExtensionDirection;
- private int _currentManualBlockHeight;
- private GameObject _startObject;
- private OrientedBox _startObjectHierarchyWorldOrientedBox;
- private BlockObjectPlacementDataCalculator _blockObjectPlacementDataCalculator = new BlockObjectPlacementDataCalculator();
- private ObjectPlacementBlockManualHeightAdjuster _manualHeightAdjuster = new ObjectPlacementBlockManualHeightAdjuster();
- private ObjectPlacementBlockAutomaticRandomHeightAdjuster _automaticRandomHeightAdjuster = new ObjectPlacementBlockAutomaticRandomHeightAdjuster();
- private ObjectPlacementBlockSubdivisionApplyOperation _subdivisionApplyOperation = new ObjectPlacementBlockSubdivisionApplyOperation();
- private bool _isActive = false;
- #endregion
- #region Private Properties
- private ObjectPlacementBoxStackSegment FirstSegment { get { return _blockSegments.Count != 0 ? _blockSegments[0] : null; } }
- private ObjectPlacementBoxStackSegment LastSegment { get { return _blockSegments.Count != 0 ? _blockSegments[_blockSegments.Count - 1] : null; } }
- #endregion
- #region Public Properties
- public bool IsActive { get { return _isActive; } }
- #endregion
- #region Public Methods
- public void SetData(ObjectPlacementBlockManualConstructionSessionData sessionData)
- {
- if (!_isActive)
- {
- _block = sessionData.Block;
- _blockSegments = sessionData.BlockSegments;
- _blockExtensionPlane = sessionData.BlockExtensionPlane;
- _startObject = sessionData.StartObject;
- _startObjectHierarchyWorldOrientedBox = _startObject.GetHierarchyWorldOrientedBox();
- _blockObjectPlacementDataCalculator.Block = _block;
- _manualConstructionSettings = _block.Settings.ManualConstructionSettings;
- _heightAdjustmentSettings = _manualConstructionSettings.HeightAdjustmentSettings;
- _automaticRandomHeightAdjustmentSettings = _heightAdjustmentSettings.AutomaticRandomHeightAdjustmentSettings;
- _paddingSettings = _manualConstructionSettings.PaddingSettings;
- _subdivisionSettings = _manualConstructionSettings.SubdivisionSettings;
- }
- }
- public void Begin()
- {
- if(CanBegin())
- {
- _isActive = true;
- _currentManualBlockHeight = 1;
- _blockSegments.Clear();
- _segmentExtensionDirection = _blockExtensionPlane.RightAxis;
- _segmentCollectionExtensionDirection = _blockExtensionPlane.LookAxis;
- CreateFirstSegmentInBlock();
- }
- }
- public List<ObjectPlacementData> End()
- {
- if (_isActive)
- {
- _isActive = false;
- return _blockObjectPlacementDataCalculator.Calculate();
- }
- return new List<ObjectPlacementData>();
- }
- public void Cancel()
- {
- _isActive = false;
- }
- public void ManualRaiseBlock()
- {
- if (CanManualRaiseOrLowerBlock())
- {
- _currentManualBlockHeight = _manualHeightAdjuster.Raise(_block, _currentManualBlockHeight);
- AdjustCornerExclusionHideFlagsForEntireBlock();
- if (_subdivisionSettings.UseSubdivision) _subdivisionApplyOperation.ApplySubdivisionToEntireBlock(_blockSegments, _subdivisionSettings);
- }
- }
- public void ManualLowerBlock()
- {
- if (CanManualRaiseOrLowerBlock())
- {
- _currentManualBlockHeight = _manualHeightAdjuster.Lower(_block, _currentManualBlockHeight);
- AdjustCornerExclusionHideFlagsForEntireBlock();
- if (_subdivisionSettings.UseSubdivision) _subdivisionApplyOperation.ApplySubdivisionToEntireBlock(_blockSegments, _subdivisionSettings);
- }
- }
- public void UpdateForMouseMoveEvent()
- {
- if (_isActive) ExtendOrShrinkBlockAlongExtensionPlane();
- }
- public void OnExcludeCornersSettingsChanged()
- {
- if(_isActive)
- {
- AdjustCornerExclusionHideFlagsForEntireBlock();
- SceneView.RepaintAll();
- }
- }
- public void OnPaddingSettingsChanged()
- {
- if (_isActive)
- {
- ObjectPlacementBoxStackSegmentActions.SetPaddingForSegments(_blockSegments, _paddingSettings.PaddingAlongExtensionPlane, _paddingSettings.PaddingAlongGrowDirection);
- for (int segmentIndex = 1; segmentIndex < _blockSegments.Count; ++segmentIndex)
- {
- AppendSegmentToSegment(_blockSegments[segmentIndex], _blockSegments[segmentIndex - 1]);
- }
- SceneView.RepaintAll();
- }
- }
- public void OnHeightAdjustmentModeChanged()
- {
- if (_isActive)
- {
- AdjustHeightForStackRangeInAllSegments(0);
- if (_manualConstructionSettings.ExcludeCorners) AdjustCornerExclusionHideFlagsForEntireBlock();
- SceneView.RepaintAll();
- }
- }
- public void OnAutomaticRandomHeightAdjustmentSettingsChanged()
- {
- if (_isActive)
- {
- AdjustHeightForStackRangeInAllSegments(0);
- if (_manualConstructionSettings.ExcludeCorners) AdjustCornerExclusionHideFlagsForEntireBlock();
- SceneView.RepaintAll();
- }
- }
- public void OnSubdivisionSettingsChanged()
- {
- if(_isActive)
- {
- if (_subdivisionSettings.UseSubdivision) _subdivisionApplyOperation.ApplySubdivisionToEntireBlock(_blockSegments, _subdivisionSettings);
- else ObjectPlacementBoxStackSegmentActions.ClearHideFlagsForAllStacksInSegments(_blockSegments, ObjectPlacementBoxHideFlags.BlockApplySubdivisions);
- SceneView.RepaintAll();
- }
- }
- #endregion
- #region Private Methods
- private bool CanBegin()
- {
- return !_isActive && IsSessionDataReady();
- }
- private bool CanExcludeCorners()
- {
- return _manualConstructionSettings.ExcludeCorners && _blockSegments.Count >= 3 && FirstSegment.NumberOfStacks >= 3;
- }
- private bool CanManualRaiseOrLowerBlock()
- {
- return _isActive && _heightAdjustmentSettings.HeightAdjustmentMode == ObjectPlacementBlockHeightAdjustmentMode.Manual;
- }
- private bool IsSessionDataReady()
- {
- bool isReady = (_block != null && _blockSegments != null && _startObject != null && _blockExtensionPlane != null);
- if (!isReady) return false;
- OrientedBox hierarchyWorldOrientedBox = _startObject.GetHierarchyWorldOrientedBox();
- float absSizeRight = hierarchyWorldOrientedBox.GetRotatedAndScaledSizeAlongDirection(_blockExtensionPlane.RightAxis);
- float absSizeLook = hierarchyWorldOrientedBox.GetRotatedAndScaledSizeAlongDirection(_blockExtensionPlane.LookAxis);
- if (absSizeRight < 1e-4f || absSizeLook < 1e-4f)
- {
- Debug.LogWarning("Can not begin block construction because the object has a 0 size component along the extention plane axes.");
- isReady = false;
- }
- return isReady;
- }
- private void CreateFirstSegmentInBlock()
- {
- ObjectPlacementBoxStackSegment firstSegmentInBlock = CreateNewSegment();
- firstSegmentInBlock.SetExtensionDirection(_segmentExtensionDirection);
- firstSegmentInBlock.SetFirstStackBasePosition(_startObjectHierarchyWorldOrientedBox.Center);
- }
- private ObjectPlacementBoxStackSegment CreateNewSegment()
- {
- var newSegment = new ObjectPlacementBoxStackSegment();
- newSegment.SetExtensionDirection(_blockExtensionPlane.LookAxis);
- newSegment.SetGrowAxis(_blockExtensionPlane.UpAxis);
- newSegment.SetRotationForAllStacks(_startObjectHierarchyWorldOrientedBox.Rotation);
- newSegment.SetBoxSizeForAllStacks(_startObjectHierarchyWorldOrientedBox.ScaledSize);
- newSegment.SetPaddingAlongStackGrowDirection(_paddingSettings.PaddingAlongGrowDirection);
- newSegment.SetPaddingAlongExtensionDirection(_paddingSettings.PaddingAlongExtensionPlane);
- _blockSegments.Add(newSegment);
- return newSegment;
- }
- private void ExtendOrShrinkBlockAlongExtensionPlane()
- {
- // Construct a new extension plane in order to take into account the block's Y offset
- Plane extensionPlane = _blockExtensionPlane.Plane;
- Vector3 pointOnBlockExtensionPlane = _blockExtensionPlane.PlaneQuad.Center;
- pointOnBlockExtensionPlane += extensionPlane.normal * _manualConstructionSettings.OffsetAlongGrowDirection;
- extensionPlane = new Plane(extensionPlane.normal, pointOnBlockExtensionPlane);
- Vector3 extensionPlaneIntersectionPoint;
- if (MouseCursor.Instance.IntersectsPlane(extensionPlane, out extensionPlaneIntersectionPoint))
- {
- Vector3 toIntersectionPoint = extensionPlaneIntersectionPoint - _blockExtensionPlane.Plane.ProjectPoint(FirstSegment.FirstStackBasePosition);
- if (!FirstSegment.ExtensionDirection.IsPointingInSameGeneralDirection(toIntersectionPoint))
- {
- ObjectPlacementBoxStackSegmentActions.ReverseExtensionDirectionForSegments(_blockSegments);
- _segmentExtensionDirection = FirstSegment.ExtensionDirection;
- }
- if (!toIntersectionPoint.IsPointingInSameGeneralDirection(_segmentCollectionExtensionDirection))
- {
- RemoveLastNumberOfSegments(_blockSegments.Count - 1);
- _segmentCollectionExtensionDirection *= -1.0f;
- }
- // Calculate the number of stacks for all segments
- float adjacentSideLength = FirstSegment.ExtensionDirection.GetAbsDot(toIntersectionPoint);
- float numberOfStacks = adjacentSideLength / (FirstSegment.GetBoxSizeAlongNormalizedDirection(_segmentExtensionDirection) + _paddingSettings.PaddingAlongExtensionPlane);
- int integerNumberOfStacks = (int)numberOfStacks + 1;
- // Calculate the number of segments
- adjacentSideLength = toIntersectionPoint.GetAbsDot(_segmentCollectionExtensionDirection);
- float numberOfSegments = adjacentSideLength / (FirstSegment.GetBoxSizeAlongNormalizedDirection(_segmentCollectionExtensionDirection) + _paddingSettings.PaddingAlongExtensionPlane);
- int integerNumberOfSegments = (int)numberOfSegments + 1;
-
- int newNumberOfStacksInSegments = integerNumberOfStacks;
- int newNumberOfSegmentsInBlock = integerNumberOfSegments;
- if (AllShortcutCombos.Instance.Enable1To1RatioBlockAdjustment.IsActive())
- {
- int min = Mathf.Min(newNumberOfSegmentsInBlock, newNumberOfStacksInSegments);
- newNumberOfStacksInSegments = min;
- newNumberOfSegmentsInBlock = min;
- }
- if (_manualConstructionSettings.ContrainSize)
- {
- newNumberOfStacksInSegments = Mathf.Min(newNumberOfStacksInSegments, _manualConstructionSettings.MaxSize);
- newNumberOfSegmentsInBlock = Mathf.Min(newNumberOfSegmentsInBlock, _manualConstructionSettings.MaxSize);
- }
- // Append or remove stacks from the segments based on the new number of stacks
- int deltaNumberOfStacks = newNumberOfStacksInSegments - FirstSegment.NumberOfStacks;
- AppendOrRemoveStacksToAllSegments(deltaNumberOfStacks);
- // Append or remove segments from the block based on the new number of segments
- int deltaNumberOfSegments = newNumberOfSegmentsInBlock - _blockSegments.Count;
- AppendOrRemoveSegmentsToBlock(deltaNumberOfSegments);
- // Apply any subdivision if necessary and adjust the corner exclusion hide flags. We need to do this every
- // time the block is updated because when the block shrinks or grows, its structure is affected and so is
- // the way in which subdivision and corner exclusion is applied.
- if (_subdivisionSettings.UseSubdivision) _subdivisionApplyOperation.ApplySubdivisionToEntireBlock(_blockSegments, _subdivisionSettings);
- AdjustCornerExclusionHideFlagsForEntireBlock();
- SceneView.RepaintAll();
- }
- }
- private void AppendOrRemoveStacksToAllSegments(int deltaNumberOfStacks)
- {
- if (deltaNumberOfStacks > 0)
- {
- if (CanExcludeCorners())
- {
- LastSegment.GetStackByIndex(0).ClearHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
- LastSegment.GetStackByIndex(LastSegment.NumberOfStacks - 1).ClearHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
- }
- int currentNumberOfStacksInSegments = FirstSegment.NumberOfStacks;
- ObjectPlacementBoxStackSegmentActions.ExtendSegmentsByAmount(_blockSegments, deltaNumberOfStacks);
- AdjustHeightForStackRangeInAllSegments(currentNumberOfStacksInSegments);
- }
- else
- ObjectPlacementBoxStackSegmentActions.ShrinkSegmentsByAmount(_blockSegments, Mathf.Abs(deltaNumberOfStacks));
- }
- private void AppendOrRemoveSegmentsToBlock(int deltaNumberOfSegments)
- {
- if (deltaNumberOfSegments > 0)
- {
- // New segments will be added, so the last segment must have its exclude corners hide flags cleared.
- if (CanExcludeCorners())
- {
- LastSegment.GetStackByIndex(0).ClearHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
- LastSegment.GetStackByIndex(LastSegment.NumberOfStacks - 1).ClearHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
- }
- int currentNumberOfSegmentsInBlock = _blockSegments.Count;
- AppendSegments(deltaNumberOfSegments);
- AdjustHeightForSegmentRange(currentNumberOfSegmentsInBlock);
- }
- else
- {
- int absDelta = Mathf.Abs(deltaNumberOfSegments);
- if (absDelta == _blockSegments.Count) --absDelta; // We always want at least one segment
- RemoveLastNumberOfSegments(absDelta);
- }
- }
- private void AdjustCornerExclusionHideFlagsForEntireBlock()
- {
- ClearCornerExclusionHideFlagsInFirstAndLastSegments();
- if (CanExcludeCorners())
- {
- AdjustCornerExlcusionHideFlagsInSegment(FirstSegment);
- AdjustCornerExlcusionHideFlagsInSegment(LastSegment);
- }
- }
- private void ClearCornerExclusionHideFlagsInFirstAndLastSegments()
- {
- FirstSegment.ClearHideFlagInAllStacks(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
- LastSegment.ClearHideFlagInAllStacks(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
- }
- private void AdjustCornerExlcusionHideFlagsInSegment(ObjectPlacementBoxStackSegment segment)
- {
- segment.GetStackByIndex(0).SetHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
- segment.GetStackByIndex(LastSegment.NumberOfStacks - 1).SetHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
- }
- private void RemoveLastNumberOfSegments(int numberOfSegmentsToRemove)
- {
- int removedSegments = 0;
- while(removedSegments < numberOfSegmentsToRemove)
- {
- _blockSegments.RemoveAt(_blockSegments.Count - 1);
- ++removedSegments;
- }
- }
- private void AppendSegments(int numberOfSegmentsToAppend)
- {
- for(int segmentIndex = 0; segmentIndex < numberOfSegmentsToAppend; ++segmentIndex)
- {
- ObjectPlacementBoxStackSegment lastSegmentInBlock = LastSegment;
- ObjectPlacementBoxStackSegment segmentToAppend = CreateNewSegment();
- segmentToAppend.SetExtensionDirection(_segmentExtensionDirection);
- segmentToAppend.Extend(FirstSegment.NumberOfStacks);
- AppendSegmentToSegment(segmentToAppend, lastSegmentInBlock);
- }
- }
- private void AppendSegmentToSegment(ObjectPlacementBoxStackSegment sourceSegment, ObjectPlacementBoxStackSegment destinationSegment)
- {
- sourceSegment.ConnectFirstStackToFirstStackInSegment(destinationSegment, GetSegmentConnectionOffsetForAppendOperation());
- }
- private Vector3 GetSegmentConnectionOffsetForAppendOperation()
- {
- return _segmentCollectionExtensionDirection * (FirstSegment.GetBoxSizeAlongNormalizedDirection(_segmentCollectionExtensionDirection) + _paddingSettings.PaddingAlongExtensionPlane);
- }
- private void AdjustHeightForStackRangeInAllSegments(int indexOfFirstStackToAdjust)
- {
- ObjectPlacementBlockHeightAdjustmentMode heightAdjustmentMode = _heightAdjustmentSettings.HeightAdjustmentMode;
- if (heightAdjustmentMode == ObjectPlacementBlockHeightAdjustmentMode.Manual) _manualHeightAdjuster.AdjustHeightForSegments(_blockSegments, indexOfFirstStackToAdjust, _currentManualBlockHeight);
- else _automaticRandomHeightAdjuster.AdjustHeightForSegments(_blockSegments, 0, indexOfFirstStackToAdjust, _automaticRandomHeightAdjustmentSettings);
- }
- private void AdjustHeightForSegmentRange(int indexOfFirstSegmentToAdjust)
- {
- ObjectPlacementBlockHeightAdjustmentMode heightAdjustmentMode = _heightAdjustmentSettings.HeightAdjustmentMode;
- if (heightAdjustmentMode == ObjectPlacementBlockHeightAdjustmentMode.Manual) _manualHeightAdjuster.AdjustHeightForSegments(_blockSegments, _currentManualBlockHeight);
- else _automaticRandomHeightAdjuster.AdjustHeightForSegments(_blockSegments, indexOfFirstSegmentToAdjust, 0, _automaticRandomHeightAdjustmentSettings);
- }
- #endregion
- }
- }
- #endif
|