ObjectPlacementBlockManualConstructionSession.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. #if UNITY_EDITOR
  2. using UnityEngine;
  3. using UnityEditor;
  4. using System.Collections.Generic;
  5. namespace O3DWB
  6. {
  7. public class ObjectPlacementBlockManualConstructionSession
  8. {
  9. #region Private Variables
  10. private ObjectPlacementBlock _block;
  11. private List<ObjectPlacementBoxStackSegment> _blockSegments;
  12. private ObjectPlacementExtensionPlane _blockExtensionPlane;
  13. private ObjectPlacementBlockManualConstructionSettings _manualConstructionSettings;
  14. private ObjectPlacementBlockPaddingSettings _paddingSettings;
  15. private ObjectPlacementBlockHeightAdjustmentSettings _heightAdjustmentSettings;
  16. private ObjectPlacementBlockAutomaticRandomHeightAdjustmentSettings _automaticRandomHeightAdjustmentSettings;
  17. private ObjectPlacementBlockSubdivisionSettings _subdivisionSettings;
  18. private Vector3 _segmentExtensionDirection;
  19. private Vector3 _segmentCollectionExtensionDirection;
  20. private int _currentManualBlockHeight;
  21. private GameObject _startObject;
  22. private OrientedBox _startObjectHierarchyWorldOrientedBox;
  23. private BlockObjectPlacementDataCalculator _blockObjectPlacementDataCalculator = new BlockObjectPlacementDataCalculator();
  24. private ObjectPlacementBlockManualHeightAdjuster _manualHeightAdjuster = new ObjectPlacementBlockManualHeightAdjuster();
  25. private ObjectPlacementBlockAutomaticRandomHeightAdjuster _automaticRandomHeightAdjuster = new ObjectPlacementBlockAutomaticRandomHeightAdjuster();
  26. private ObjectPlacementBlockSubdivisionApplyOperation _subdivisionApplyOperation = new ObjectPlacementBlockSubdivisionApplyOperation();
  27. private bool _isActive = false;
  28. #endregion
  29. #region Private Properties
  30. private ObjectPlacementBoxStackSegment FirstSegment { get { return _blockSegments.Count != 0 ? _blockSegments[0] : null; } }
  31. private ObjectPlacementBoxStackSegment LastSegment { get { return _blockSegments.Count != 0 ? _blockSegments[_blockSegments.Count - 1] : null; } }
  32. #endregion
  33. #region Public Properties
  34. public bool IsActive { get { return _isActive; } }
  35. #endregion
  36. #region Public Methods
  37. public void SetData(ObjectPlacementBlockManualConstructionSessionData sessionData)
  38. {
  39. if (!_isActive)
  40. {
  41. _block = sessionData.Block;
  42. _blockSegments = sessionData.BlockSegments;
  43. _blockExtensionPlane = sessionData.BlockExtensionPlane;
  44. _startObject = sessionData.StartObject;
  45. _startObjectHierarchyWorldOrientedBox = _startObject.GetHierarchyWorldOrientedBox();
  46. _blockObjectPlacementDataCalculator.Block = _block;
  47. _manualConstructionSettings = _block.Settings.ManualConstructionSettings;
  48. _heightAdjustmentSettings = _manualConstructionSettings.HeightAdjustmentSettings;
  49. _automaticRandomHeightAdjustmentSettings = _heightAdjustmentSettings.AutomaticRandomHeightAdjustmentSettings;
  50. _paddingSettings = _manualConstructionSettings.PaddingSettings;
  51. _subdivisionSettings = _manualConstructionSettings.SubdivisionSettings;
  52. }
  53. }
  54. public void Begin()
  55. {
  56. if(CanBegin())
  57. {
  58. _isActive = true;
  59. _currentManualBlockHeight = 1;
  60. _blockSegments.Clear();
  61. _segmentExtensionDirection = _blockExtensionPlane.RightAxis;
  62. _segmentCollectionExtensionDirection = _blockExtensionPlane.LookAxis;
  63. CreateFirstSegmentInBlock();
  64. }
  65. }
  66. public List<ObjectPlacementData> End()
  67. {
  68. if (_isActive)
  69. {
  70. _isActive = false;
  71. return _blockObjectPlacementDataCalculator.Calculate();
  72. }
  73. return new List<ObjectPlacementData>();
  74. }
  75. public void Cancel()
  76. {
  77. _isActive = false;
  78. }
  79. public void ManualRaiseBlock()
  80. {
  81. if (CanManualRaiseOrLowerBlock())
  82. {
  83. _currentManualBlockHeight = _manualHeightAdjuster.Raise(_block, _currentManualBlockHeight);
  84. AdjustCornerExclusionHideFlagsForEntireBlock();
  85. if (_subdivisionSettings.UseSubdivision) _subdivisionApplyOperation.ApplySubdivisionToEntireBlock(_blockSegments, _subdivisionSettings);
  86. }
  87. }
  88. public void ManualLowerBlock()
  89. {
  90. if (CanManualRaiseOrLowerBlock())
  91. {
  92. _currentManualBlockHeight = _manualHeightAdjuster.Lower(_block, _currentManualBlockHeight);
  93. AdjustCornerExclusionHideFlagsForEntireBlock();
  94. if (_subdivisionSettings.UseSubdivision) _subdivisionApplyOperation.ApplySubdivisionToEntireBlock(_blockSegments, _subdivisionSettings);
  95. }
  96. }
  97. public void UpdateForMouseMoveEvent()
  98. {
  99. if (_isActive) ExtendOrShrinkBlockAlongExtensionPlane();
  100. }
  101. public void OnExcludeCornersSettingsChanged()
  102. {
  103. if(_isActive)
  104. {
  105. AdjustCornerExclusionHideFlagsForEntireBlock();
  106. SceneView.RepaintAll();
  107. }
  108. }
  109. public void OnPaddingSettingsChanged()
  110. {
  111. if (_isActive)
  112. {
  113. ObjectPlacementBoxStackSegmentActions.SetPaddingForSegments(_blockSegments, _paddingSettings.PaddingAlongExtensionPlane, _paddingSettings.PaddingAlongGrowDirection);
  114. for (int segmentIndex = 1; segmentIndex < _blockSegments.Count; ++segmentIndex)
  115. {
  116. AppendSegmentToSegment(_blockSegments[segmentIndex], _blockSegments[segmentIndex - 1]);
  117. }
  118. SceneView.RepaintAll();
  119. }
  120. }
  121. public void OnHeightAdjustmentModeChanged()
  122. {
  123. if (_isActive)
  124. {
  125. AdjustHeightForStackRangeInAllSegments(0);
  126. if (_manualConstructionSettings.ExcludeCorners) AdjustCornerExclusionHideFlagsForEntireBlock();
  127. SceneView.RepaintAll();
  128. }
  129. }
  130. public void OnAutomaticRandomHeightAdjustmentSettingsChanged()
  131. {
  132. if (_isActive)
  133. {
  134. AdjustHeightForStackRangeInAllSegments(0);
  135. if (_manualConstructionSettings.ExcludeCorners) AdjustCornerExclusionHideFlagsForEntireBlock();
  136. SceneView.RepaintAll();
  137. }
  138. }
  139. public void OnSubdivisionSettingsChanged()
  140. {
  141. if(_isActive)
  142. {
  143. if (_subdivisionSettings.UseSubdivision) _subdivisionApplyOperation.ApplySubdivisionToEntireBlock(_blockSegments, _subdivisionSettings);
  144. else ObjectPlacementBoxStackSegmentActions.ClearHideFlagsForAllStacksInSegments(_blockSegments, ObjectPlacementBoxHideFlags.BlockApplySubdivisions);
  145. SceneView.RepaintAll();
  146. }
  147. }
  148. #endregion
  149. #region Private Methods
  150. private bool CanBegin()
  151. {
  152. return !_isActive && IsSessionDataReady();
  153. }
  154. private bool CanExcludeCorners()
  155. {
  156. return _manualConstructionSettings.ExcludeCorners && _blockSegments.Count >= 3 && FirstSegment.NumberOfStacks >= 3;
  157. }
  158. private bool CanManualRaiseOrLowerBlock()
  159. {
  160. return _isActive && _heightAdjustmentSettings.HeightAdjustmentMode == ObjectPlacementBlockHeightAdjustmentMode.Manual;
  161. }
  162. private bool IsSessionDataReady()
  163. {
  164. bool isReady = (_block != null && _blockSegments != null && _startObject != null && _blockExtensionPlane != null);
  165. if (!isReady) return false;
  166. OrientedBox hierarchyWorldOrientedBox = _startObject.GetHierarchyWorldOrientedBox();
  167. float absSizeRight = hierarchyWorldOrientedBox.GetRotatedAndScaledSizeAlongDirection(_blockExtensionPlane.RightAxis);
  168. float absSizeLook = hierarchyWorldOrientedBox.GetRotatedAndScaledSizeAlongDirection(_blockExtensionPlane.LookAxis);
  169. if (absSizeRight < 1e-4f || absSizeLook < 1e-4f)
  170. {
  171. Debug.LogWarning("Can not begin block construction because the object has a 0 size component along the extention plane axes.");
  172. isReady = false;
  173. }
  174. return isReady;
  175. }
  176. private void CreateFirstSegmentInBlock()
  177. {
  178. ObjectPlacementBoxStackSegment firstSegmentInBlock = CreateNewSegment();
  179. firstSegmentInBlock.SetExtensionDirection(_segmentExtensionDirection);
  180. firstSegmentInBlock.SetFirstStackBasePosition(_startObjectHierarchyWorldOrientedBox.Center);
  181. }
  182. private ObjectPlacementBoxStackSegment CreateNewSegment()
  183. {
  184. var newSegment = new ObjectPlacementBoxStackSegment();
  185. newSegment.SetExtensionDirection(_blockExtensionPlane.LookAxis);
  186. newSegment.SetGrowAxis(_blockExtensionPlane.UpAxis);
  187. newSegment.SetRotationForAllStacks(_startObjectHierarchyWorldOrientedBox.Rotation);
  188. newSegment.SetBoxSizeForAllStacks(_startObjectHierarchyWorldOrientedBox.ScaledSize);
  189. newSegment.SetPaddingAlongStackGrowDirection(_paddingSettings.PaddingAlongGrowDirection);
  190. newSegment.SetPaddingAlongExtensionDirection(_paddingSettings.PaddingAlongExtensionPlane);
  191. _blockSegments.Add(newSegment);
  192. return newSegment;
  193. }
  194. private void ExtendOrShrinkBlockAlongExtensionPlane()
  195. {
  196. // Construct a new extension plane in order to take into account the block's Y offset
  197. Plane extensionPlane = _blockExtensionPlane.Plane;
  198. Vector3 pointOnBlockExtensionPlane = _blockExtensionPlane.PlaneQuad.Center;
  199. pointOnBlockExtensionPlane += extensionPlane.normal * _manualConstructionSettings.OffsetAlongGrowDirection;
  200. extensionPlane = new Plane(extensionPlane.normal, pointOnBlockExtensionPlane);
  201. Vector3 extensionPlaneIntersectionPoint;
  202. if (MouseCursor.Instance.IntersectsPlane(extensionPlane, out extensionPlaneIntersectionPoint))
  203. {
  204. Vector3 toIntersectionPoint = extensionPlaneIntersectionPoint - _blockExtensionPlane.Plane.ProjectPoint(FirstSegment.FirstStackBasePosition);
  205. if (!FirstSegment.ExtensionDirection.IsPointingInSameGeneralDirection(toIntersectionPoint))
  206. {
  207. ObjectPlacementBoxStackSegmentActions.ReverseExtensionDirectionForSegments(_blockSegments);
  208. _segmentExtensionDirection = FirstSegment.ExtensionDirection;
  209. }
  210. if (!toIntersectionPoint.IsPointingInSameGeneralDirection(_segmentCollectionExtensionDirection))
  211. {
  212. RemoveLastNumberOfSegments(_blockSegments.Count - 1);
  213. _segmentCollectionExtensionDirection *= -1.0f;
  214. }
  215. // Calculate the number of stacks for all segments
  216. float adjacentSideLength = FirstSegment.ExtensionDirection.GetAbsDot(toIntersectionPoint);
  217. float numberOfStacks = adjacentSideLength / (FirstSegment.GetBoxSizeAlongNormalizedDirection(_segmentExtensionDirection) + _paddingSettings.PaddingAlongExtensionPlane);
  218. int integerNumberOfStacks = (int)numberOfStacks + 1;
  219. // Calculate the number of segments
  220. adjacentSideLength = toIntersectionPoint.GetAbsDot(_segmentCollectionExtensionDirection);
  221. float numberOfSegments = adjacentSideLength / (FirstSegment.GetBoxSizeAlongNormalizedDirection(_segmentCollectionExtensionDirection) + _paddingSettings.PaddingAlongExtensionPlane);
  222. int integerNumberOfSegments = (int)numberOfSegments + 1;
  223. int newNumberOfStacksInSegments = integerNumberOfStacks;
  224. int newNumberOfSegmentsInBlock = integerNumberOfSegments;
  225. if (AllShortcutCombos.Instance.Enable1To1RatioBlockAdjustment.IsActive())
  226. {
  227. int min = Mathf.Min(newNumberOfSegmentsInBlock, newNumberOfStacksInSegments);
  228. newNumberOfStacksInSegments = min;
  229. newNumberOfSegmentsInBlock = min;
  230. }
  231. if (_manualConstructionSettings.ContrainSize)
  232. {
  233. newNumberOfStacksInSegments = Mathf.Min(newNumberOfStacksInSegments, _manualConstructionSettings.MaxSize);
  234. newNumberOfSegmentsInBlock = Mathf.Min(newNumberOfSegmentsInBlock, _manualConstructionSettings.MaxSize);
  235. }
  236. // Append or remove stacks from the segments based on the new number of stacks
  237. int deltaNumberOfStacks = newNumberOfStacksInSegments - FirstSegment.NumberOfStacks;
  238. AppendOrRemoveStacksToAllSegments(deltaNumberOfStacks);
  239. // Append or remove segments from the block based on the new number of segments
  240. int deltaNumberOfSegments = newNumberOfSegmentsInBlock - _blockSegments.Count;
  241. AppendOrRemoveSegmentsToBlock(deltaNumberOfSegments);
  242. // Apply any subdivision if necessary and adjust the corner exclusion hide flags. We need to do this every
  243. // time the block is updated because when the block shrinks or grows, its structure is affected and so is
  244. // the way in which subdivision and corner exclusion is applied.
  245. if (_subdivisionSettings.UseSubdivision) _subdivisionApplyOperation.ApplySubdivisionToEntireBlock(_blockSegments, _subdivisionSettings);
  246. AdjustCornerExclusionHideFlagsForEntireBlock();
  247. SceneView.RepaintAll();
  248. }
  249. }
  250. private void AppendOrRemoveStacksToAllSegments(int deltaNumberOfStacks)
  251. {
  252. if (deltaNumberOfStacks > 0)
  253. {
  254. if (CanExcludeCorners())
  255. {
  256. LastSegment.GetStackByIndex(0).ClearHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
  257. LastSegment.GetStackByIndex(LastSegment.NumberOfStacks - 1).ClearHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
  258. }
  259. int currentNumberOfStacksInSegments = FirstSegment.NumberOfStacks;
  260. ObjectPlacementBoxStackSegmentActions.ExtendSegmentsByAmount(_blockSegments, deltaNumberOfStacks);
  261. AdjustHeightForStackRangeInAllSegments(currentNumberOfStacksInSegments);
  262. }
  263. else
  264. ObjectPlacementBoxStackSegmentActions.ShrinkSegmentsByAmount(_blockSegments, Mathf.Abs(deltaNumberOfStacks));
  265. }
  266. private void AppendOrRemoveSegmentsToBlock(int deltaNumberOfSegments)
  267. {
  268. if (deltaNumberOfSegments > 0)
  269. {
  270. // New segments will be added, so the last segment must have its exclude corners hide flags cleared.
  271. if (CanExcludeCorners())
  272. {
  273. LastSegment.GetStackByIndex(0).ClearHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
  274. LastSegment.GetStackByIndex(LastSegment.NumberOfStacks - 1).ClearHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
  275. }
  276. int currentNumberOfSegmentsInBlock = _blockSegments.Count;
  277. AppendSegments(deltaNumberOfSegments);
  278. AdjustHeightForSegmentRange(currentNumberOfSegmentsInBlock);
  279. }
  280. else
  281. {
  282. int absDelta = Mathf.Abs(deltaNumberOfSegments);
  283. if (absDelta == _blockSegments.Count) --absDelta; // We always want at least one segment
  284. RemoveLastNumberOfSegments(absDelta);
  285. }
  286. }
  287. private void AdjustCornerExclusionHideFlagsForEntireBlock()
  288. {
  289. ClearCornerExclusionHideFlagsInFirstAndLastSegments();
  290. if (CanExcludeCorners())
  291. {
  292. AdjustCornerExlcusionHideFlagsInSegment(FirstSegment);
  293. AdjustCornerExlcusionHideFlagsInSegment(LastSegment);
  294. }
  295. }
  296. private void ClearCornerExclusionHideFlagsInFirstAndLastSegments()
  297. {
  298. FirstSegment.ClearHideFlagInAllStacks(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
  299. LastSegment.ClearHideFlagInAllStacks(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
  300. }
  301. private void AdjustCornerExlcusionHideFlagsInSegment(ObjectPlacementBoxStackSegment segment)
  302. {
  303. segment.GetStackByIndex(0).SetHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
  304. segment.GetStackByIndex(LastSegment.NumberOfStacks - 1).SetHideFlagForAllBoxes(ObjectPlacementBoxHideFlags.BlockExcludeCorners);
  305. }
  306. private void RemoveLastNumberOfSegments(int numberOfSegmentsToRemove)
  307. {
  308. int removedSegments = 0;
  309. while(removedSegments < numberOfSegmentsToRemove)
  310. {
  311. _blockSegments.RemoveAt(_blockSegments.Count - 1);
  312. ++removedSegments;
  313. }
  314. }
  315. private void AppendSegments(int numberOfSegmentsToAppend)
  316. {
  317. for(int segmentIndex = 0; segmentIndex < numberOfSegmentsToAppend; ++segmentIndex)
  318. {
  319. ObjectPlacementBoxStackSegment lastSegmentInBlock = LastSegment;
  320. ObjectPlacementBoxStackSegment segmentToAppend = CreateNewSegment();
  321. segmentToAppend.SetExtensionDirection(_segmentExtensionDirection);
  322. segmentToAppend.Extend(FirstSegment.NumberOfStacks);
  323. AppendSegmentToSegment(segmentToAppend, lastSegmentInBlock);
  324. }
  325. }
  326. private void AppendSegmentToSegment(ObjectPlacementBoxStackSegment sourceSegment, ObjectPlacementBoxStackSegment destinationSegment)
  327. {
  328. sourceSegment.ConnectFirstStackToFirstStackInSegment(destinationSegment, GetSegmentConnectionOffsetForAppendOperation());
  329. }
  330. private Vector3 GetSegmentConnectionOffsetForAppendOperation()
  331. {
  332. return _segmentCollectionExtensionDirection * (FirstSegment.GetBoxSizeAlongNormalizedDirection(_segmentCollectionExtensionDirection) + _paddingSettings.PaddingAlongExtensionPlane);
  333. }
  334. private void AdjustHeightForStackRangeInAllSegments(int indexOfFirstStackToAdjust)
  335. {
  336. ObjectPlacementBlockHeightAdjustmentMode heightAdjustmentMode = _heightAdjustmentSettings.HeightAdjustmentMode;
  337. if (heightAdjustmentMode == ObjectPlacementBlockHeightAdjustmentMode.Manual) _manualHeightAdjuster.AdjustHeightForSegments(_blockSegments, indexOfFirstStackToAdjust, _currentManualBlockHeight);
  338. else _automaticRandomHeightAdjuster.AdjustHeightForSegments(_blockSegments, 0, indexOfFirstStackToAdjust, _automaticRandomHeightAdjustmentSettings);
  339. }
  340. private void AdjustHeightForSegmentRange(int indexOfFirstSegmentToAdjust)
  341. {
  342. ObjectPlacementBlockHeightAdjustmentMode heightAdjustmentMode = _heightAdjustmentSettings.HeightAdjustmentMode;
  343. if (heightAdjustmentMode == ObjectPlacementBlockHeightAdjustmentMode.Manual) _manualHeightAdjuster.AdjustHeightForSegments(_blockSegments, _currentManualBlockHeight);
  344. else _automaticRandomHeightAdjuster.AdjustHeightForSegments(_blockSegments, indexOfFirstSegmentToAdjust, 0, _automaticRandomHeightAdjustmentSettings);
  345. }
  346. #endregion
  347. }
  348. }
  349. #endif