TilingManager.cs 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232
  1. /*
  2. Copyright (c) 2021 Omar Duarte
  3. Unauthorized copying of this file, via any medium is strictly prohibited.
  4. Writen by Omar Duarte, 2021.
  5. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  6. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  8. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  9. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  10. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  11. THE SOFTWARE.
  12. */
  13. using System.Linq;
  14. using UnityEngine;
  15. namespace PluginMaster
  16. {
  17. #region DATA & SETTINGS
  18. [System.Serializable]
  19. public class TilingSettings : PaintOnSurfaceToolSettings, IPaintToolSettings
  20. {
  21. #region TILING SETTINGS
  22. [SerializeField] private TilesUtils.SizeType _cellSizeType = TilesUtils.SizeType.SMALLEST_OBJECT;
  23. [SerializeField] private Vector2 _cellSize = Vector2.one;
  24. [SerializeField] private Quaternion _rotation = Quaternion.identity;
  25. [SerializeField] private Vector2 _spacing = Vector2.zero;
  26. [SerializeField] private AxesUtils.SignedAxis _axisAlignedWithNormal = AxesUtils.SignedAxis.UP;
  27. [SerializeField] private bool _showPreview = true;
  28. public Quaternion rotation
  29. {
  30. get => _rotation;
  31. set
  32. {
  33. if (_rotation == value) return;
  34. var prevRotation = _rotation;
  35. _rotation = value;
  36. OnDataChanged();
  37. }
  38. }
  39. public TilesUtils.SizeType cellSizeType
  40. {
  41. get => _cellSizeType;
  42. set
  43. {
  44. if (_cellSizeType == value) return;
  45. _cellSizeType = value;
  46. UpdateCellSize();
  47. }
  48. }
  49. public Vector2 cellSize
  50. {
  51. get => _cellSize;
  52. set
  53. {
  54. if (_cellSize == value) return;
  55. _cellSize = value;
  56. OnDataChanged();
  57. }
  58. }
  59. public Vector2 spacing
  60. {
  61. get => _spacing;
  62. set
  63. {
  64. if (_spacing == value) return;
  65. _spacing = value;
  66. OnDataChanged();
  67. }
  68. }
  69. public AxesUtils.SignedAxis axisAlignedWithNormal
  70. {
  71. get => _axisAlignedWithNormal;
  72. set
  73. {
  74. if (_axisAlignedWithNormal == value) return;
  75. _axisAlignedWithNormal = value;
  76. UpdateCellSize();
  77. OnDataChanged();
  78. }
  79. }
  80. public bool showPreview
  81. {
  82. get => _showPreview;
  83. set
  84. {
  85. if (_showPreview == value) return;
  86. _showPreview = value;
  87. OnDataChanged();
  88. }
  89. }
  90. public void UpdateCellSize()
  91. {
  92. if (ToolManager.tool != ToolManager.PaintTool.TILING) return;
  93. if (_cellSizeType != TilesUtils.SizeType.CUSTOM)
  94. {
  95. var toolSettings = TilingManager.settings;
  96. BrushSettings brush = PaletteManager.selectedBrush;
  97. if (ToolManager.editMode && brush == null) brush = brushSettings;
  98. else if (toolSettings.overwriteBrushProperties) brush = toolSettings.brushSettings;
  99. if (brush == null) return;
  100. AxesUtils.SignedAxis forwardAxis = AxesUtils.SignedAxis.FORWARD;
  101. if (_axisAlignedWithNormal == AxesUtils.SignedAxis.DOWN) forwardAxis = AxesUtils.SignedAxis.BACK;
  102. else if (_axisAlignedWithNormal == AxesUtils.SignedAxis.RIGHT) forwardAxis = AxesUtils.SignedAxis.UP;
  103. else if (_axisAlignedWithNormal == AxesUtils.SignedAxis.LEFT) forwardAxis = AxesUtils.SignedAxis.DOWN;
  104. else if (_axisAlignedWithNormal == AxesUtils.SignedAxis.FORWARD) forwardAxis = AxesUtils.SignedAxis.RIGHT;
  105. else if (_axisAlignedWithNormal == AxesUtils.SignedAxis.BACK) forwardAxis = AxesUtils.SignedAxis.LEFT;
  106. _cellSize = TilesUtils.GetCellSize(_cellSizeType, brush, _axisAlignedWithNormal,
  107. forwardAxis, _cellSize, tangentSpace: true, quarterTurns: 0);
  108. ToolProperties.RepainWindow();
  109. UnityEditor.SceneView.RepaintAll();
  110. }
  111. OnDataChanged();
  112. }
  113. #endregion
  114. #region ON DATA CHANGED
  115. public TilingSettings() : base()
  116. {
  117. _paintTool.OnDataChanged += DataChanged;
  118. _paintTool.brushSettings.OnDataChangedAction += DataChanged;
  119. }
  120. public override void DataChanged()
  121. {
  122. base.DataChanged();
  123. PWBIO.UpdateStroke();
  124. }
  125. #endregion
  126. #region PAINT TOOL
  127. [SerializeField] private PaintToolSettings _paintTool = new PaintToolSettings();
  128. public Transform parent { get => _paintTool.parent; set => _paintTool.parent = value; }
  129. public bool overwritePrefabLayer
  130. {
  131. get => _paintTool.overwritePrefabLayer;
  132. set => _paintTool.overwritePrefabLayer = value;
  133. }
  134. public int layer { get => _paintTool.layer; set => _paintTool.layer = value; }
  135. public bool autoCreateParent { get => _paintTool.autoCreateParent; set => _paintTool.autoCreateParent = value; }
  136. public bool setSurfaceAsParent { get => _paintTool.setSurfaceAsParent; set => _paintTool.setSurfaceAsParent = value; }
  137. public bool createSubparentPerPalette
  138. {
  139. get => _paintTool.createSubparentPerPalette;
  140. set => _paintTool.createSubparentPerPalette = value;
  141. }
  142. public bool createSubparentPerTool
  143. {
  144. get => _paintTool.createSubparentPerTool;
  145. set => _paintTool.createSubparentPerTool = value;
  146. }
  147. public bool createSubparentPerBrush
  148. {
  149. get => _paintTool.createSubparentPerBrush;
  150. set => _paintTool.createSubparentPerBrush = value;
  151. }
  152. public bool createSubparentPerPrefab
  153. {
  154. get => _paintTool.createSubparentPerPrefab;
  155. set => _paintTool.createSubparentPerPrefab = value;
  156. }
  157. public bool overwriteBrushProperties
  158. {
  159. get => _paintTool.overwriteBrushProperties;
  160. set
  161. {
  162. _paintTool.overwriteBrushProperties = value;
  163. OnDataChanged();
  164. }
  165. }
  166. public BrushSettings brushSettings => _paintTool.brushSettings;
  167. #endregion
  168. public override void Copy(IToolSettings other)
  169. {
  170. var otherTilingSettings = other as TilingSettings;
  171. base.Copy(other);
  172. _paintTool.Copy(otherTilingSettings._paintTool);
  173. _cellSizeType = otherTilingSettings._cellSizeType;
  174. _cellSize = otherTilingSettings._cellSize;
  175. _rotation = otherTilingSettings._rotation;
  176. _spacing = otherTilingSettings._spacing;
  177. _axisAlignedWithNormal = otherTilingSettings._axisAlignedWithNormal;
  178. }
  179. public TilingSettings Clone()
  180. {
  181. var clone = new TilingSettings();
  182. clone.Copy(this);
  183. return clone;
  184. }
  185. }
  186. public class TilingToolName : IToolName { public string value => "Tiling"; }
  187. [System.Serializable]
  188. public class TilingData : PersistentData<TilingToolName, TilingSettings, ControlPoint>
  189. {
  190. [System.NonSerialized]
  191. private System.Collections.Generic.List<Vector3> _tilingCenters
  192. = new System.Collections.Generic.List<Vector3>();
  193. public System.Collections.Generic.List<Vector3> tilingCenters => _tilingCenters;
  194. public TilingData() : base() { }
  195. public TilingData((GameObject, int)[] objects, long initialBrushId, TilingData tilingData)
  196. : base(objects, initialBrushId, tilingData) { }
  197. private static TilingData _instance = null;
  198. public static TilingData instance
  199. {
  200. get
  201. {
  202. if (_instance == null)
  203. {
  204. _instance = new TilingData();
  205. _instance._settings = TilingManager.settings;
  206. }
  207. return _instance;
  208. }
  209. }
  210. protected override void Initialize()
  211. {
  212. base.Initialize();
  213. const int pointCount = 9;
  214. for (int i = 0; i < pointCount; i++) _controlPoints.Add(new ControlPoint());
  215. _pointPositions = new Vector3[pointCount];
  216. }
  217. public TilingData Clone()
  218. {
  219. var clone = new TilingData();
  220. base.Clone(clone);
  221. clone._tilingCenters = _tilingCenters.ToList();
  222. return clone;
  223. }
  224. public Vector3 GetCenter() => GetPoint(8);
  225. }
  226. [System.Serializable]
  227. public class TilingSceneData : SceneData<TilingToolName, TilingSettings, ControlPoint, TilingData>
  228. {
  229. public TilingSceneData() : base() { }
  230. public TilingSceneData(string sceneGUID) : base(sceneGUID) { }
  231. }
  232. [System.Serializable]
  233. public class TilingManager
  234. : PersistentToolManagerBase<TilingToolName, TilingSettings, ControlPoint, TilingData, TilingSceneData>
  235. { }
  236. #endregion
  237. #region PWBIO
  238. public static partial class PWBIO
  239. {
  240. #region HANDLERS
  241. private static void TilingInitializeOnLoad()
  242. {
  243. TilingManager.settings.OnDataChanged += OnTilingSettingsChanged;
  244. BrushSettings.OnBrushSettingsChanged += PreviewSelectedPersistentTilings;
  245. }
  246. private static void OnUndoTiling() => ClearTilingStroke();
  247. private static void OnTilingToolModeChanged()
  248. {
  249. DeselectPersistentItems(TilingManager.instance);
  250. if (!ToolManager.editMode)
  251. {
  252. ToolProperties.RepainWindow();
  253. return;
  254. }
  255. ResetTilingState();
  256. ResetSelectedPersistentObject(TilingManager.instance, ref _editingPersistentTiling, _initialPersistentTilingData);
  257. }
  258. private static void OnTilingSettingsChanged()
  259. {
  260. repaint = true;
  261. if (!ToolManager.editMode)
  262. {
  263. _tilingData.settings = TilingManager.settings;
  264. updateStroke = true;
  265. return;
  266. }
  267. if (_selectedPersistentTilingData == null) return;
  268. _selectedPersistentTilingData.settings.Copy(TilingManager.settings);
  269. PreviewPersistentTiling(_selectedPersistentTilingData);
  270. }
  271. #endregion
  272. #region SPAWN MODE
  273. public static void ResetTilingState(bool askIfWantToSave = true)
  274. {
  275. _initialPersistentTilingData = null;
  276. _selectedPersistentTilingData = null;
  277. _editingPersistentTiling = false;
  278. if (askIfWantToSave)
  279. {
  280. void Save()
  281. {
  282. if (UnityEditor.SceneView.lastActiveSceneView != null)
  283. TilingStrokePreview(UnityEditor.SceneView.lastActiveSceneView.camera, TilingData.nextHexId, true);
  284. CreateTiling();
  285. }
  286. AskIfWantToSave(_tilingData.state, Save);
  287. }
  288. _snappedToVertex = false;
  289. _tilingData.Reset();
  290. _paintStroke.Clear();
  291. }
  292. private static void TilingStateNone(bool in2DMode)
  293. {
  294. if (Event.current.button == 0 && Event.current.type == EventType.MouseDown && !Event.current.alt)
  295. {
  296. _tilingData.state = ToolManager.ToolState.PREVIEW;
  297. TilingManager.settings.UpdateCellSize();
  298. }
  299. if (MouseDot(out Vector3 point, out Vector3 normal, TilingManager.settings.mode, in2DMode,
  300. TilingManager.settings.paintOnPalettePrefabs, TilingManager.settings.paintOnMeshesWithoutCollider, false))
  301. {
  302. point = SnapAndUpdateGridOrigin(point, SnapManager.settings.snappingEnabled,
  303. TilingManager.settings.paintOnPalettePrefabs, TilingManager.settings.paintOnMeshesWithoutCollider,
  304. false, TilingManager.settings.rotation * Vector3.down);
  305. _tilingData.SetPoint(2, point, registerUndo: false, selectAll: false);
  306. _tilingData.SetPoint(0, point, registerUndo: false, selectAll: false);
  307. }
  308. if (_tilingData.pointsCount > 0) DrawDotHandleCap(_tilingData.GetPoint(0));
  309. }
  310. private static void TilingStateRectangle(UnityEditor.SceneView sceneView)
  311. {
  312. var settings = TilingManager.settings;
  313. if (Event.current.button == 0 && Event.current.type == EventType.MouseDown && !Event.current.alt)
  314. {
  315. UpdateMidpoints(_tilingData);
  316. _tilingData.state = ToolManager.ToolState.EDIT;
  317. updateStroke = true;
  318. }
  319. var mouseRay = UnityEditor.HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
  320. var plane = new Plane(settings.rotation * Vector3.up, _tilingData.GetPoint(0));
  321. if (plane.Raycast(mouseRay, out float distance))
  322. {
  323. var point = mouseRay.GetPoint(distance);
  324. point = SnapAndUpdateGridOrigin(point, SnapManager.settings.snappingEnabled,
  325. TilingManager.settings.paintOnPalettePrefabs, TilingManager.settings.paintOnMeshesWithoutCollider,
  326. false, TilingManager.settings.rotation * Vector3.down);
  327. _tilingData.SetPoint(2, point, registerUndo: false, selectAll: false);
  328. var diagonal = point - _tilingData.GetPoint(0);
  329. var tangent = Vector3.Project(diagonal, settings.rotation * Vector3.right);
  330. var bitangent = Vector3.Project(diagonal, settings.rotation * Vector3.forward);
  331. _tilingData.SetPoint(1, _tilingData.GetPoint(0) + tangent, registerUndo: false, selectAll: false);
  332. _tilingData.SetPoint(3, _tilingData.GetPoint(0) + bitangent, registerUndo: false, selectAll: false);
  333. DrawTilingGrid(_tilingData);
  334. TilingInfoText(sceneView);
  335. for (int i = 0; i < 4; ++i) DrawDotHandleCap(_tilingData.GetPoint(i));
  336. return;
  337. }
  338. DrawDotHandleCap(_tilingData.GetPoint(0));
  339. }
  340. private static void TilingInfoText(UnityEditor.SceneView sceneView)
  341. {
  342. if (!PWBCore.staticData.showInfoText) return;
  343. if (_tilingSize == Vector2Int.zero) return;
  344. var labelTexts = new string[]
  345. { $"{_tilingSize.x} x {_tilingSize.y}" };
  346. InfoText.Draw(sceneView, labelTexts);
  347. }
  348. private static void TilingStateEdit(Camera camera)
  349. {
  350. bool mouseDown = Event.current.button == 0 && Event.current.type == EventType.MouseDown;
  351. TilingShortcuts(_tilingData);
  352. if (_rotateTiling90)
  353. {
  354. var rotation = _tilingData.settings.rotation * Quaternion.AngleAxis(90, _rotateTilingAxis);
  355. SetTilingRotation(_tilingData, rotation);
  356. _rotateTiling90 = false;
  357. }
  358. var forceStrokeUpdate = updateStroke;
  359. if (updateStroke)
  360. {
  361. BrushstrokeManager.UpdateTilingBrushstroke(_tilingData.tilingCenters.ToArray());
  362. updateStroke = false;
  363. }
  364. if (TilingManager.settings.showPreview) TilingStrokePreview(camera, TilingData.nextHexId, forceStrokeUpdate);
  365. DrawTilingGrid(_tilingData);
  366. if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
  367. {
  368. if (!TilingManager.settings.showPreview) TilingStrokePreview(camera, TilingData.nextHexId, forceStrokeUpdate);
  369. CreateTiling();
  370. ResetTilingState(false);
  371. }
  372. DrawTilingControlPoints(_tilingData, out bool clickOnPoint, out bool wasEdited, out Vector3 delta);
  373. }
  374. private static void CreateTiling()
  375. {
  376. var nextTilingId = TilingData.nextHexId;
  377. var objDic = Paint(TilingManager.settings, PAINT_CMD, true, false, nextTilingId);
  378. if (objDic.Count != 1) return;
  379. var scenePath = UnityEngine.SceneManagement.SceneManager.GetActiveScene().path;
  380. var sceneGUID = UnityEditor.AssetDatabase.AssetPathToGUID(scenePath);
  381. var initialBrushId = PaletteManager.selectedBrush != null ? PaletteManager.selectedBrush.id : -1;
  382. var objs = objDic[nextTilingId].ToArray();
  383. var persistentData = new TilingData(objs, initialBrushId, _tilingData);
  384. TilingManager.instance.AddPersistentItem(sceneGUID, persistentData);
  385. PWBItemsWindow.RepainWindow();
  386. }
  387. private static void TilingStrokePreview(Camera camera, string hexId, bool forceUpdate)
  388. {
  389. BrushstrokeItem[] brushstroke;
  390. if (PreviewIfBrushtrokestaysTheSame(out brushstroke, camera, forceUpdate)) return;
  391. PWBCore.UpdateTempCollidersIfHierarchyChanged();
  392. _paintStroke.Clear();
  393. var toolSettings = TilingManager.settings;
  394. float maxSurfaceHeight = 0f;
  395. for (int i = 0; i < brushstroke.Length; ++i)
  396. {
  397. var strokeItem = brushstroke[i];
  398. var prefab = strokeItem.settings.prefab;
  399. if (prefab == null) continue;
  400. Bounds bounds = BoundsUtils.GetBoundsRecursive(prefab.transform, prefab.transform.rotation);
  401. BrushSettings brushSettings = strokeItem.settings;
  402. if (toolSettings.overwriteBrushProperties) brushSettings = toolSettings.brushSettings;
  403. if (brushSettings == null) brushSettings = new BrushSettings();
  404. var additionalRotation = Quaternion.Euler(strokeItem.additionalAngle);
  405. var scaleMult = brushSettings.GetScaleMultiplier();
  406. var size = additionalRotation * Vector3.Scale(bounds.size, scaleMult);
  407. size = new Vector3(Mathf.Abs(size.x), Mathf.Abs(size.y), Mathf.Abs(size.z));
  408. var pivotToCenter = prefab.transform.InverseTransformDirection(bounds.center - prefab.transform.position);
  409. pivotToCenter = Vector3.Scale(pivotToCenter, scaleMult);
  410. pivotToCenter = additionalRotation * pivotToCenter;
  411. var itemPosition = strokeItem.tangentPosition;
  412. var height = size.x + size.y + size.z + maxSurfaceHeight
  413. + Vector3.Distance(itemPosition, tilingData.GetCenter())
  414. + Vector3.Distance(tilingData.GetPoint(0), tilingData.GetPoint(2));
  415. var normal = toolSettings.rotation * Vector3.up;
  416. var axisDirection = Vector3.up;
  417. if (toolSettings.axisAlignedWithNormal == AxesUtils.Axis.Z)
  418. {
  419. size.x = bounds.size.y;
  420. size.y = bounds.size.z;
  421. size.z = bounds.size.x;
  422. axisDirection = Vector3.forward;
  423. }
  424. else if (toolSettings.axisAlignedWithNormal == AxesUtils.Axis.X)
  425. {
  426. size.x = bounds.size.z;
  427. size.y = bounds.size.x;
  428. size.z = bounds.size.y;
  429. axisDirection = Vector3.right;
  430. }
  431. var ray = new Ray(itemPosition + normal * height, -normal);
  432. Transform surface = null;
  433. if (toolSettings.mode != TilingSettings.PaintMode.ON_SHAPE)
  434. {
  435. if (MouseRaycast(ray, out RaycastHit itemHit,
  436. out GameObject collider, height * 2f, -1,
  437. toolSettings.paintOnPalettePrefabs, toolSettings.paintOnMeshesWithoutCollider))
  438. {
  439. itemPosition = itemHit.point;
  440. if (brushSettings.rotateToTheSurface) normal = itemHit.normal;
  441. var colObj = PWBCore.GetGameObjectFromTempCollider(collider);
  442. if (colObj != null) surface = colObj.transform;
  443. var surfObj = PWBCore.GetGameObjectFromTempCollider(collider);
  444. var surfSize = BoundsUtils.GetBounds(surfObj.transform).size;
  445. var h = surfSize.x + surfSize.y + surfSize.z;
  446. maxSurfaceHeight = Mathf.Max(h, maxSurfaceHeight);
  447. }
  448. else if (toolSettings.mode == TilingSettings.PaintMode.ON_SURFACE) continue;
  449. }
  450. var itemRotation = toolSettings.rotation;
  451. Vector3 itemTangent = itemRotation * Vector3.forward;
  452. if (brushSettings.rotateToTheSurface
  453. && toolSettings.mode != PaintOnSurfaceToolSettingsBase.PaintMode.ON_SHAPE)
  454. {
  455. itemRotation = Quaternion.LookRotation(itemTangent, normal);
  456. itemPosition += normal * strokeItem.surfaceDistance;
  457. }
  458. else itemPosition += normal * strokeItem.surfaceDistance;
  459. var axisAlignedWithNormal = (Vector3)toolSettings.axisAlignedWithNormal;
  460. itemRotation *= Quaternion.FromToRotation(Vector3.up, axisAlignedWithNormal);
  461. itemRotation *= additionalRotation;
  462. if (brushSettings.rotateToTheSurface && brushSettings.alwaysOrientUp)
  463. {
  464. var fw = itemRotation * Vector3.forward;
  465. const float minMag = 1e-6f;
  466. fw.y = 0;
  467. if (Mathf.Abs(fw.x) < minMag && Mathf.Abs(fw.z) < minMag) fw = Quaternion.Euler(0, 90, 0) * normal;
  468. itemRotation = Quaternion.LookRotation(fw, Vector3.up);
  469. }
  470. itemPosition += itemRotation * (brushSettings.localPositionOffset);
  471. itemPosition -= itemRotation * pivotToCenter;
  472. if (brushSettings.embedInSurface)
  473. {
  474. if (brushSettings.embedAtPivotHeight)
  475. itemPosition += normal * AxesUtils.GetAxisValue(pivotToCenter, toolSettings.axisAlignedWithNormal);
  476. else
  477. itemPosition += normal * (AxesUtils.GetAxisValue(size, toolSettings.axisAlignedWithNormal) / 2);
  478. }
  479. if (brushSettings.embedInSurface
  480. && toolSettings.mode != PaintOnSurfaceToolSettingsBase.PaintMode.ON_SHAPE)
  481. {
  482. if (brushSettings.embedAtPivotHeight)
  483. itemPosition += itemRotation * (axisDirection * strokeItem.settings.bottomMagnitude);
  484. else
  485. {
  486. var TRS = Matrix4x4.TRS(itemPosition, itemRotation,
  487. Vector3.Scale(prefab.transform.localScale, scaleMult));
  488. var bottomDistanceToSurfce = GetBottomDistanceToSurface(strokeItem.settings.bottomVertices,
  489. TRS, Mathf.Abs(strokeItem.settings.bottomMagnitude), toolSettings.paintOnPalettePrefabs,
  490. toolSettings.paintOnMeshesWithoutCollider, out Transform surfaceTransform);
  491. itemPosition += itemRotation * (axisDirection * -bottomDistanceToSurfce);
  492. }
  493. }
  494. var itemScale = Vector3.Scale(prefab.transform.localScale, scaleMult);
  495. var layer = toolSettings.overwritePrefabLayer ? toolSettings.layer : prefab.layer;
  496. Transform parentTransform = toolSettings.parent;
  497. var paintItem = new PaintStrokeItem(prefab, itemPosition, itemRotation,
  498. itemScale, layer, parentTransform, surface, strokeItem.flipX, strokeItem.flipY);
  499. paintItem.persistentParentId = hexId;
  500. _paintStroke.Add(paintItem);
  501. var previewRootToWorld = Matrix4x4.TRS(itemPosition, itemRotation, scaleMult)
  502. * Matrix4x4.Rotate(Quaternion.Inverse(prefab.transform.rotation))
  503. * Matrix4x4.Translate(-prefab.transform.position);
  504. PreviewBrushItem(prefab, previewRootToWorld, layer, camera, false, false, strokeItem.flipX, strokeItem.flipY);
  505. _previewData.Add(new PreviewData(prefab, previewRootToWorld, layer, strokeItem.flipX, strokeItem.flipY));
  506. }
  507. }
  508. #endregion
  509. #region COMMON
  510. private static TilingData _tilingData = TilingData.instance;
  511. private static void ClearTilingStroke()
  512. {
  513. _paintStroke.Clear();
  514. BrushstrokeManager.ClearBrushstroke();
  515. updateStroke = true;
  516. if (ToolManager.editMode)
  517. {
  518. if (!_editingPersistentLine) return;
  519. _selectedPersistentTilingData.UpdatePoses();
  520. PreviewPersistentTiling(_selectedPersistentTilingData);
  521. UnityEditor.SceneView.RepaintAll();
  522. }
  523. else
  524. {
  525. UpdateCellCenters(_tilingData, false);
  526. TilingStrokePreview(UnityEditor.SceneView.lastActiveSceneView.camera, TilingData.nextHexId, true);
  527. }
  528. }
  529. private static void TilingDuringSceneGUI(UnityEditor.SceneView sceneView)
  530. {
  531. if (TilingManager.settings.paintOnMeshesWithoutCollider)
  532. PWBCore.CreateTempCollidersWithinFrustum(sceneView.camera);
  533. if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape)
  534. {
  535. if (_tilingData.state == ToolManager.ToolState.EDIT && _tilingData.selectedPointIdx > 0)
  536. _tilingData.selectedPointIdx = -1;
  537. else if (_tilingData.state == ToolManager.ToolState.NONE) ToolManager.DeselectTool();
  538. else ResetTilingState(false);
  539. }
  540. if (ToolManager.editMode || TilingManager.instance.showPreexistingElements) TilingToolEditMode(sceneView);
  541. if (ToolManager.editMode) return;
  542. switch (_tilingData.state)
  543. {
  544. case ToolManager.ToolState.NONE:
  545. TilingStateNone(sceneView.in2DMode);
  546. break;
  547. case ToolManager.ToolState.PREVIEW:
  548. TilingStateRectangle(sceneView);
  549. break;
  550. case ToolManager.ToolState.EDIT:
  551. TilingStateEdit(sceneView.camera);
  552. break;
  553. }
  554. }
  555. private static void DrawTilingRectangle(TilingData data)
  556. {
  557. var settings = data.settings;
  558. var cornerPoints = new Vector3[] { data.GetPoint(0), data.GetPoint(1),
  559. data.GetPoint(2), data.GetPoint(3), data.GetPoint(0) };
  560. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.7f);
  561. UnityEditor.Handles.DrawAAPolyLine(8, cornerPoints);
  562. UnityEditor.Handles.color = new Color(1f, 1f, 1f, 0.7f);
  563. UnityEditor.Handles.DrawAAPolyLine(4, cornerPoints);
  564. }
  565. private static void UpdateMidpoints(TilingData data)
  566. {
  567. for (int i = 0; i < 4; ++i)
  568. {
  569. var nextI = (i + 1) % 4;
  570. var point = data.GetPoint(i);
  571. var nextPoint = data.GetPoint(nextI);
  572. data.SetPoint(i + 4, point + (nextPoint - point) / 2, registerUndo: false, selectAll: false);
  573. }
  574. data.SetPoint(8, data.GetPoint(0)
  575. + (data.GetPoint(2) - data.GetPoint(0)) / 2, registerUndo: false, selectAll: false);
  576. }
  577. private static void DrawCells(TilingData data) => UpdateCellCenters(data, true);
  578. private static void DrawTilingGrid(TilingData data)
  579. {
  580. DrawCells(data);
  581. DrawTilingRectangle(data);
  582. }
  583. public static TilingData tilingData => ToolManager.editMode ? _selectedPersistentTilingData : _tilingData;
  584. private static void ApplyTilingHandlePosition(TilingData data) => SetTilingSelectedPoint(data, _handlePosition);
  585. private static bool SetTilingSelectedPoint(TilingData data, Vector3 position)
  586. {
  587. if (data.selectedPointIdx < 0) return false;
  588. _handlePosition = position;
  589. var prevPosition = data.selectedPoint;
  590. var snappedPoint = SnapAndUpdateGridOrigin(_handlePosition, SnapManager.settings.snappingEnabled,
  591. data.settings.paintOnPalettePrefabs, data.settings.paintOnMeshesWithoutCollider,
  592. false, Vector3.down);
  593. data.SetPoint(data.selectedPointIdx, snappedPoint, registerUndo: true, selectAll: false);
  594. _handlePosition = data.selectedPoint;
  595. if (prevPosition == data.selectedPoint) return false;
  596. updateStroke = true;
  597. var delta = data.selectedPoint - prevPosition;
  598. if (data.selectedPointIdx < 4)
  599. {
  600. var nextCornerIdx = (data.selectedPointIdx + 1) % 4;
  601. var oppositeCornerIdx = (data.selectedPointIdx + 2) % 4;
  602. var prevCornerIdx = (data.selectedPointIdx + 3) % 4;
  603. var nextVector = data.GetPoint(nextCornerIdx) - prevPosition;
  604. var prevVector = data.GetPoint(prevCornerIdx) - prevPosition;
  605. var deltaNext = Vector3.Project(delta, nextVector);
  606. var deltaPrev = Vector3.Project(delta, prevVector);
  607. var deltaNormal = delta - deltaNext - deltaPrev;
  608. data.AddValue(nextCornerIdx, deltaPrev + deltaNormal);
  609. data.AddValue(prevCornerIdx, deltaNext + deltaNormal);
  610. data.AddValue(oppositeCornerIdx, deltaNormal);
  611. }
  612. else if (data.selectedPointIdx < 8)
  613. {
  614. var prevCornerIdx = data.selectedPointIdx - 4;
  615. var nextCornerIdx = (data.selectedPointIdx - 3) % 4;
  616. var oppositeSideIdx = (data.selectedPointIdx - 2) % 4 + 4;
  617. var parallel = data.GetPoint(nextCornerIdx) - data.GetPoint(prevCornerIdx);
  618. var perpendicular = data.GetPoint(oppositeSideIdx) - prevPosition;
  619. var deltaParallel = Vector3.Project(delta, parallel);
  620. var deltaPerpendicular = Vector3.Project(delta, perpendicular);
  621. var deltaNormal = delta - deltaParallel - deltaPerpendicular;
  622. for (int i = 0; i < 4; ++i) data.AddValue(i, deltaParallel + deltaNormal);
  623. data.AddValue(prevCornerIdx, deltaPerpendicular);
  624. data.AddValue(nextCornerIdx, deltaPerpendicular);
  625. }
  626. else for (int i = 0; i < 4; ++i) data.AddValue(i, delta);
  627. UpdateMidpoints(data);
  628. UpdateCellCenters(data, false);
  629. return true;
  630. }
  631. private static bool SetTilingRotation(TilingData data, Quaternion rotation)
  632. {
  633. var prevRotation = data.settings.rotation;
  634. data.settings.rotation = rotation;
  635. if (data.settings.rotation == prevRotation) return false;
  636. ToolProperties.RegisterUndo(TilingData.COMMAND_NAME);
  637. updateStroke = true;
  638. var delta = rotation * Quaternion.Inverse(prevRotation);
  639. for (int i = 0; i < 8; ++i)
  640. {
  641. var centerToPoint = data.GetPoint(i) - data.GetPoint(8);
  642. var rotatedPos = (delta * centerToPoint) + data.GetPoint(8);
  643. data.SetPoint(i, rotatedPos, registerUndo: false, selectAll: false);
  644. }
  645. DrawCells(data);
  646. ToolProperties.RepainWindow();
  647. UpdateCellCenters(data, false);
  648. return true;
  649. }
  650. public static void UpdateCellSize()
  651. {
  652. if (ToolManager.editMode)
  653. {
  654. if (_selectedPersistentTilingData == null) return;
  655. _selectedPersistentTilingData.settings.UpdateCellSize();
  656. UpdateCellCenters(_selectedPersistentTilingData, true);
  657. }
  658. _tilingData.settings.UpdateCellSize();
  659. UpdateCellCenters(_tilingData, true);
  660. }
  661. private static Vector2Int _tilingSize = Vector2Int.zero;
  662. private static void UpdateCellCenters(TilingData data, bool DrawCells)
  663. {
  664. if (!ToolManager.editMode && data.state == ToolManager.ToolState.NONE) return;
  665. data.tilingCenters.Clear();
  666. var settings = data.settings;
  667. var tangentDir = data.GetPoint(1) - data.GetPoint(0);
  668. var tangentSize = tangentDir.magnitude;
  669. tangentDir.Normalize();
  670. var bitangentDir = data.GetPoint(3) - data.GetPoint(0);
  671. var bitangentSize = bitangentDir.magnitude;
  672. bitangentDir.Normalize();
  673. var cellTangent = tangentDir * Mathf.Abs(settings.cellSize.x);
  674. var cellBitangent = bitangentDir * Mathf.Abs(settings.cellSize.y);
  675. var vertices = new Vector3[] { Vector3.zero, cellTangent, cellTangent + cellBitangent, cellBitangent };
  676. var offset = data.GetPoint(0);
  677. void SetTileCenter()
  678. {
  679. var linePoints = new Vector3[5];
  680. for (int i = 0; i <= 4; ++i) linePoints[i] = vertices[i % 4] + offset;
  681. var cellCenter = linePoints[0] + (linePoints[2] - linePoints[0]) / 2;
  682. data.tilingCenters.Add(cellCenter);
  683. if (!DrawCells) return;
  684. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.3f);
  685. UnityEditor.Handles.DrawAAPolyLine(6, linePoints);
  686. UnityEditor.Handles.color = new Color(1f, 1f, 1f, 0.3f);
  687. UnityEditor.Handles.DrawAAPolyLine(2, linePoints);
  688. }
  689. var minCellSize = settings.cellSize + settings.spacing;
  690. minCellSize = Vector2.Max(minCellSize, Vector2.one * 0.001f);
  691. var cellSize = minCellSize - settings.spacing;
  692. float tangentOffset = 0;
  693. _tilingSize = Vector2Int.zero;
  694. while (Mathf.Abs(tangentOffset) + Mathf.Abs(cellSize.x) <= tangentSize)
  695. {
  696. float bitangentOffset = 0;
  697. ++_tilingSize.x;
  698. var sizeY = 0;
  699. while (Mathf.Abs(bitangentOffset) + Mathf.Abs(cellSize.y) <= bitangentSize)
  700. {
  701. SetTileCenter();
  702. bitangentOffset += minCellSize.y;
  703. offset = data.GetPoint(0) + tangentDir * Mathf.Abs(tangentOffset)
  704. + bitangentDir * Mathf.Abs(bitangentOffset);
  705. ++sizeY;
  706. }
  707. _tilingSize.y = Mathf.Max(_tilingSize.y, sizeY);
  708. tangentOffset += minCellSize.x;
  709. offset = data.GetPoint(0) + tangentDir * Mathf.Abs(tangentOffset);
  710. }
  711. }
  712. private static Vector3 _rotateTilingAxis = Vector3.zero;
  713. private static bool _rotateTiling90 = false;
  714. public static void ShowTilingContextMenu(TilingData data, Vector2 mousePosition)
  715. {
  716. if (!ToolManager.editMode) return;
  717. void Rotate90(Vector3 axis)
  718. {
  719. if (ToolManager.editMode) SelectTiling(data);
  720. _rotateTiling90 = true;
  721. _rotateTilingAxis = axis;
  722. }
  723. var menu = new UnityEditor.GenericMenu();
  724. menu.AddItem(new GUIContent("Rotate 90º around Y ... "
  725. + PWBSettings.shortcuts.selectionRotate90YCW.combination.ToString()), on: false,
  726. () => Rotate90(Vector3.down));
  727. menu.AddItem(new GUIContent("Rotate -90º around Y ... "
  728. + PWBSettings.shortcuts.selectionRotate90YCCW.combination.ToString()), on: false,
  729. () => Rotate90(Vector3.up));
  730. menu.AddItem(new GUIContent("Rotate 90º around X ... "
  731. + PWBSettings.shortcuts.selectionRotate90XCW.combination.ToString()), on: false,
  732. () => Rotate90(Vector3.left));
  733. menu.AddItem(new GUIContent("Rotate -90º around X ... "
  734. + PWBSettings.shortcuts.selectionRotate90XCCW.combination.ToString()), on: false,
  735. () => Rotate90(Vector3.right));
  736. menu.AddItem(new GUIContent("Rotate 90º around Z ... "
  737. + PWBSettings.shortcuts.selectionRotate90ZCW.combination.ToString()), on: false,
  738. () => Rotate90(Vector3.back));
  739. menu.AddItem(new GUIContent("Rotate -90º around Z ... "
  740. + PWBSettings.shortcuts.selectionRotate90ZCCW.combination.ToString()), on: false,
  741. () => Rotate90(Vector3.forward));
  742. menu.AddSeparator(string.Empty);
  743. PersistentItemContextMenu(menu, data, mousePosition);
  744. menu.ShowAsContext();
  745. }
  746. private static bool DrawTilingControlPoints(TilingData data,
  747. out bool clickOnPoint, out bool wasEdited, out Vector3 delta)
  748. {
  749. delta = Vector3.zero;
  750. clickOnPoint = false;
  751. wasEdited = false;
  752. for (int i = 0; i < 9; ++i)
  753. {
  754. var controlId = GUIUtility.GetControlID(FocusType.Passive);
  755. if (!clickOnPoint)
  756. {
  757. float distFromMouse
  758. = UnityEditor.HandleUtility.DistanceToRectangle(data.GetPoint(i), Quaternion.identity, 0f);
  759. UnityEditor.HandleUtility.AddControl(controlId, distFromMouse);
  760. if (Event.current.button == 0 && Event.current.type == EventType.MouseDown
  761. && UnityEditor.HandleUtility.nearestControl == controlId)
  762. {
  763. data.selectedPointIdx = i;
  764. clickOnPoint = true;
  765. Event.current.Use();
  766. }
  767. if (Event.current.button == 1 && Event.current.type == EventType.MouseDown
  768. && !Event.current.control && !Event.current.shift && !Event.current.alt
  769. && UnityEditor.HandleUtility.nearestControl == controlId)
  770. {
  771. ShowTilingContextMenu(data,
  772. UnityEditor.EditorGUIUtility.GUIToScreenPoint(Event.current.mousePosition));
  773. Event.current.Use();
  774. }
  775. }
  776. if (Event.current.type != EventType.Repaint) continue;
  777. DrawDotHandleCap(data.GetPoint(i));
  778. }
  779. if (clickOnPoint) ToolProperties.RepainWindow();
  780. if (data.selectedPointIdx < 0) return false;
  781. var prevPoint = data.selectedPoint;
  782. wasEdited = SetTilingSelectedPoint(data,
  783. UnityEditor.Handles.PositionHandle(data.selectedPoint, data.settings.rotation));
  784. if (prevPoint != data.selectedPoint) ToolProperties.RepainWindow();
  785. if (data.selectedPointIdx == 8)
  786. {
  787. var prevRotation = data.settings.rotation;
  788. wasEdited = wasEdited || SetTilingRotation(data,
  789. UnityEditor.Handles.RotationHandle(data.settings.rotation, data.GetPoint(8)));
  790. if (prevRotation != data.settings.rotation) ToolProperties.RepainWindow();
  791. }
  792. return clickOnPoint || wasEdited;
  793. }
  794. private static bool TilingShortcuts(TilingData data)
  795. {
  796. if (data == null) return false;
  797. var keyCode = Event.current.keyCode;
  798. var spacing1 = PWBSettings.shortcuts.tilingEditSpacing1.Check();
  799. var spacing2 = PWBSettings.shortcuts.tilingEditSpacing2.Check();
  800. if (spacing1 || spacing2)
  801. {
  802. var delta = spacing1 ? PWBSettings.shortcuts.tilingEditSpacing1.combination.delta
  803. : -PWBSettings.shortcuts.tilingEditSpacing2.combination.delta;
  804. var deltaSign = -Mathf.Sign(delta);
  805. var otherAxes = AxesUtils.GetOtherAxes(AxesUtils.Axis.Y);
  806. var spacing = Vector3.zero;
  807. AxesUtils.SetAxisValue(ref spacing, otherAxes[0], data.settings.spacing.x);
  808. AxesUtils.SetAxisValue(ref spacing, otherAxes[1], data.settings.spacing.y);
  809. var axisIdx = spacing1 ? 1 : 0;
  810. var size = data.GetPoint(2) - data.GetPoint(axisIdx);
  811. var axisSize = AxesUtils.GetAxisValue(size, otherAxes[axisIdx]);
  812. AxesUtils.AddValueToAxis(ref spacing, otherAxes[axisIdx], axisSize * deltaSign * 0.005f);
  813. data.settings.spacing = new Vector2(AxesUtils.GetAxisValue(spacing, otherAxes[0]),
  814. AxesUtils.GetAxisValue(spacing, otherAxes[1]));
  815. ToolProperties.RepainWindow();
  816. Event.current.Use();
  817. return true;
  818. }
  819. void Rotate90(Vector3 axis)
  820. {
  821. _rotateTiling90 = true;
  822. _rotateTilingAxis = axis;
  823. }
  824. if (PWBSettings.shortcuts.selectionRotate90XCCW.Check())
  825. {
  826. Rotate90(Vector3.right);
  827. return true;
  828. }
  829. if (PWBSettings.shortcuts.selectionRotate90XCW.Check())
  830. {
  831. Rotate90(Vector3.left);
  832. return true;
  833. }
  834. if (PWBSettings.shortcuts.selectionRotate90YCCW.Check())
  835. {
  836. Rotate90(Vector3.up);
  837. return true;
  838. }
  839. if (PWBSettings.shortcuts.selectionRotate90YCW.Check())
  840. {
  841. Rotate90(Vector3.down);
  842. return true;
  843. }
  844. if (PWBSettings.shortcuts.selectionRotate90ZCCW.Check())
  845. {
  846. Rotate90(Vector3.forward);
  847. return true;
  848. }
  849. if (PWBSettings.shortcuts.selectionRotate90ZCW.Check())
  850. {
  851. Rotate90(Vector3.back);
  852. return true;
  853. }
  854. return false;
  855. }
  856. public static void UpdateTilingRotation(Quaternion rotation)
  857. {
  858. if (tilingData == null) return;
  859. updateStroke = true;
  860. SetTilingRotation(tilingData, rotation);
  861. }
  862. #endregion
  863. #region EDIT MODE
  864. private static TilingData _initialPersistentTilingData = null;
  865. private static TilingData _selectedPersistentTilingData = null;
  866. private static bool _editingPersistentTiling = false;
  867. public static TilingData selectedPersistentTilingData
  868. {
  869. get
  870. {
  871. if (!_editingPersistentTiling) return null;
  872. return _selectedPersistentTilingData;
  873. }
  874. }
  875. public static void SelectTiling(TilingData data)
  876. {
  877. ApplySelectedPersistentTiling(true);
  878. _editingPersistentTiling = true;
  879. data.ClearSelection();
  880. data.selectedPointIdx = 8;
  881. data.isSelected = true;
  882. _selectedPersistentTilingData = data;
  883. if (_initialPersistentTilingData == null) _initialPersistentTilingData = data.Clone();
  884. TilingManager.instance.CopyToolSettings(data.settings);
  885. }
  886. private static void TilingToolEditMode(UnityEditor.SceneView sceneView)
  887. {
  888. var persistentItems = TilingManager.instance.GetPersistentItems();
  889. var deselectedItems = new System.Collections.Generic.List<TilingData>(persistentItems);
  890. bool clickOnAnyPoint = false;
  891. bool selectedItemWasEdited = false;
  892. foreach (var itemData in persistentItems)
  893. {
  894. DrawCells(itemData);
  895. if (!ToolManager.editMode) continue;
  896. DrawTilingRectangle(itemData);
  897. var selectedTilingId = _initialPersistentTilingData == null ? -1 : _initialPersistentTilingData.id;
  898. if (DrawTilingControlPoints(itemData, out bool clickOnPoint, out bool wasEdited, out Vector3 delta))
  899. {
  900. if (clickOnPoint)
  901. {
  902. clickOnAnyPoint = true;
  903. _editingPersistentTiling = true;
  904. if (selectedTilingId != itemData.id)
  905. {
  906. ApplySelectedPersistentTiling(false);
  907. if (selectedTilingId == -1)
  908. _createProfileName = TilingManager.instance.selectedProfileName;
  909. TilingManager.instance.CopyToolSettings(itemData.settings);
  910. itemData.isSelected = true;
  911. _selectedPersistentTilingData = itemData;
  912. _editingPersistentTiling = true;
  913. UpdateCellSize();
  914. }
  915. if (_initialPersistentTilingData == null) _initialPersistentTilingData = itemData.Clone();
  916. else if (_initialPersistentTilingData.id != itemData.id)
  917. _initialPersistentTilingData = itemData.Clone();
  918. deselectedItems.Remove(itemData);
  919. }
  920. if (wasEdited)
  921. {
  922. _editingPersistentTiling = true;
  923. selectedItemWasEdited = true;
  924. _persistentItemWasEdited = true;
  925. }
  926. }
  927. }
  928. if (clickOnAnyPoint)
  929. foreach (var itemData in deselectedItems) itemData.ClearSelection();
  930. if (!ToolManager.editMode) return;
  931. bool skipPreview = _selectedPersistentTilingData != null
  932. && _selectedPersistentTilingData.objectCount > PWBCore.staticData.maxPreviewCountInEditMode;
  933. if (!skipPreview)
  934. {
  935. if (selectedItemWasEdited) PreviewPersistentTiling(_selectedPersistentTilingData);
  936. else if (_editingPersistentTiling && _selectedPersistentTilingData != null)
  937. {
  938. var forceStrokeUpdate = updateStroke;
  939. if (updateStroke)
  940. {
  941. PreviewPersistentTiling(_selectedPersistentTilingData);
  942. updateStroke = false;
  943. PWBCore.SetSavePending();
  944. }
  945. if (_brushstroke != null
  946. && !BrushstrokeManager.BrushstrokeEqual(BrushstrokeManager.brushstroke, _brushstroke))
  947. _paintStroke.Clear();
  948. TilingStrokePreview(sceneView.camera, _selectedPersistentTilingData.hexId, forceStrokeUpdate);
  949. }
  950. }
  951. if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
  952. {
  953. if (skipPreview)
  954. {
  955. PreviewPersistentTiling(_selectedPersistentTilingData);
  956. TilingStrokePreview(sceneView.camera, _selectedPersistentTilingData.hexId, forceUpdate: true);
  957. }
  958. ApplySelectedPersistentTiling(deselectPoint: true);
  959. ToolProperties.RepainWindow();
  960. }
  961. else if (PWBSettings.shortcuts.editModeSelectParent.Check()
  962. && _selectedPersistentTilingData != null)
  963. {
  964. var parent = _selectedPersistentTilingData.GetParent();
  965. if (parent != null) UnityEditor.Selection.activeGameObject = parent;
  966. }
  967. else if (PWBSettings.shortcuts.editModeDeleteItemButNotItsChildren.Check())
  968. TilingManager.instance.DeletePersistentItem(_selectedPersistentTilingData.id, false);
  969. else if (PWBSettings.shortcuts.editModeDeleteItemAndItsChildren.Check())
  970. TilingManager.instance.DeletePersistentItem(_selectedPersistentTilingData.id, true);
  971. else if (PWBSettings.shortcuts.editModeDuplicate.Check()) DuplicateItem(_selectedPersistentTilingData.id);
  972. if (TilingShortcuts(_selectedPersistentTilingData))
  973. {
  974. DrawCells(_selectedPersistentTilingData);
  975. PreviewPersistentTiling(_selectedPersistentTilingData);
  976. repaint = true;
  977. }
  978. if (_rotateTiling90)
  979. {
  980. var rotation = _selectedPersistentTilingData.settings.rotation * Quaternion.AngleAxis(90, _rotateTilingAxis);
  981. SetTilingRotation(_selectedPersistentTilingData, rotation);
  982. PreviewPersistentTiling(_selectedPersistentTilingData);
  983. repaint = true;
  984. _rotateTiling90 = false;
  985. }
  986. }
  987. public static void PreviewSelectedPersistentTilings()
  988. {
  989. if (ToolManager.tool != ToolManager.PaintTool.TILING) return;
  990. var persistentTilings = TilingManager.instance.GetPersistentItems();
  991. foreach (var tilingData in persistentTilings)
  992. {
  993. if (!tilingData.isSelected) continue;
  994. PreviewPersistentTiling(tilingData);
  995. }
  996. }
  997. private static void PreviewPersistentTiling(TilingData data)
  998. {
  999. PWBCore.UpdateTempCollidersIfHierarchyChanged();
  1000. Vector3[] objPos = null;
  1001. var objList = data.objectList;
  1002. var toolSettings = data.settings;
  1003. BrushstrokeManager.UpdatePersistentTilingBrushstroke(data.tilingCenters.ToArray(),
  1004. toolSettings, objList, out objPos, out Vector3[] strokePos);
  1005. _disabledObjects.Clear();
  1006. _disabledObjects.UnionWith(objList);
  1007. var objSet = data.objectSet;
  1008. float maxSurfaceHeight = 0f;
  1009. for (int objIdx = 0; objIdx < objPos.Length; ++objIdx)
  1010. {
  1011. var obj = objList[objIdx];
  1012. if (obj == null)
  1013. {
  1014. data.RemovePose(objIdx);
  1015. continue;
  1016. }
  1017. obj.SetActive(true);
  1018. var itemPosition = objPos[objIdx];
  1019. BrushSettings brushSettings = TilingManager.instance.applyBrushToExisting
  1020. ? (toolSettings.overwriteBrushProperties ? toolSettings.brushSettings : PaletteManager.selectedBrush)
  1021. : PaletteManager.GetBrushById(data.initialBrushId);
  1022. if (brushSettings == null) brushSettings = new BrushSettings();
  1023. var prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(obj);
  1024. var bounds = BoundsUtils.GetBoundsRecursive(prefab.transform, prefab.transform.rotation, ignoreDissabled: true,
  1025. BoundsUtils.ObjectProperty.BOUNDING_BOX, recursive: true, useDictionary: true);
  1026. var scaleMult = brushSettings.GetScaleMultiplier();
  1027. var size = Vector3.Scale(bounds.size, scaleMult);
  1028. var height = size.x + size.y + size.z + maxSurfaceHeight
  1029. + Vector3.Distance(itemPosition, data.GetCenter()) + Vector3.Distance(data.GetPoint(0), data.GetPoint(2));
  1030. var normal = toolSettings.rotation * Vector3.up;
  1031. var ray = new Ray(itemPosition + normal * height, -normal);
  1032. if (toolSettings.mode != PaintOnSurfaceToolSettingsBase.PaintMode.ON_SHAPE)
  1033. {
  1034. if (MouseRaycast(ray, out RaycastHit itemHit,
  1035. out GameObject collider, height * 2f, -1,
  1036. toolSettings.paintOnPalettePrefabs, toolSettings.paintOnMeshesWithoutCollider,
  1037. tags: null, terrainLayers: null, exceptions: objSet))
  1038. {
  1039. itemPosition = itemHit.point;
  1040. if (brushSettings.rotateToTheSurface) normal = itemHit.normal;
  1041. var surfObj = PWBCore.GetGameObjectFromTempCollider(collider);
  1042. var surfSize = BoundsUtils.GetBounds(surfObj.transform).size;
  1043. var h = surfSize.x + surfSize.y + surfSize.z;
  1044. maxSurfaceHeight = Mathf.Max(h, maxSurfaceHeight);
  1045. }
  1046. else if (toolSettings.mode == PaintOnSurfaceToolSettingsBase.PaintMode.ON_SURFACE) continue;
  1047. }
  1048. var itemRotation = toolSettings.rotation;
  1049. Vector3 itemTangent = itemRotation * Vector3.forward;
  1050. if (brushSettings.rotateToTheSurface
  1051. && toolSettings.mode != PaintOnSurfaceToolSettings.PaintMode.ON_SHAPE)
  1052. {
  1053. itemRotation = Quaternion.LookRotation(itemTangent, normal);
  1054. itemPosition += normal * brushSettings.surfaceDistance;
  1055. }
  1056. else itemPosition += normal * brushSettings.surfaceDistance;
  1057. var axisAlignedWithNormal = (Vector3)toolSettings.axisAlignedWithNormal;
  1058. itemRotation *= Quaternion.FromToRotation(Vector3.up, axisAlignedWithNormal);
  1059. if (brushSettings.rotateToTheSurface && brushSettings.alwaysOrientUp)
  1060. {
  1061. var fw = itemRotation * Vector3.forward;
  1062. const float minMag = 1e-6f;
  1063. fw.y = 0;
  1064. if (Mathf.Abs(fw.x) < minMag && Mathf.Abs(fw.z) < minMag) fw = Quaternion.Euler(0, 90, 0) * normal;
  1065. itemRotation = Quaternion.LookRotation(fw, Vector3.up);
  1066. }
  1067. itemPosition += itemRotation * brushSettings.localPositionOffset;
  1068. UnityEditor.Undo.RecordObject(obj.transform, TilingData.COMMAND_NAME);
  1069. obj.transform.rotation = Quaternion.identity;
  1070. obj.transform.position = Vector3.zero;
  1071. obj.transform.rotation = itemRotation;
  1072. var pivotToCenter = prefab.transform.InverseTransformDirection(bounds.center - prefab.transform.position);
  1073. pivotToCenter = Vector3.Scale(pivotToCenter, scaleMult);
  1074. pivotToCenter = itemRotation * pivotToCenter;
  1075. itemPosition -= pivotToCenter;
  1076. if (brushSettings.embedInSurface)
  1077. {
  1078. if (brushSettings.embedAtPivotHeight)
  1079. itemPosition += normal * AxesUtils.GetAxisValue(pivotToCenter, toolSettings.axisAlignedWithNormal);
  1080. else
  1081. itemPosition += normal * (AxesUtils.GetAxisValue(size, toolSettings.axisAlignedWithNormal) / 2);
  1082. }
  1083. var axisDirection = Vector3.up;
  1084. if (toolSettings.axisAlignedWithNormal == AxesUtils.Axis.Z)
  1085. {
  1086. size.x = bounds.size.y;
  1087. size.y = bounds.size.z;
  1088. size.z = bounds.size.x;
  1089. axisDirection = Vector3.forward;
  1090. }
  1091. else if (toolSettings.axisAlignedWithNormal == AxesUtils.Axis.X)
  1092. {
  1093. size.x = bounds.size.z;
  1094. size.y = bounds.size.x;
  1095. size.z = bounds.size.y;
  1096. axisDirection = Vector3.right;
  1097. }
  1098. if (brushSettings.embedInSurface
  1099. && toolSettings.mode != PaintOnSurfaceToolSettingsBase.PaintMode.ON_SHAPE)
  1100. {
  1101. var bottomMagnitude = BoundsUtils.GetBottomMagnitude(obj.transform);
  1102. if (brushSettings.embedAtPivotHeight)
  1103. itemPosition += itemRotation * (axisDirection * bottomMagnitude);
  1104. else
  1105. {
  1106. var TRS = Matrix4x4.TRS(itemPosition, itemRotation, obj.transform.lossyScale);
  1107. var bottomVertices = BoundsUtils.GetBottomVertices(obj.transform);
  1108. var bottomDistanceToSurfce = GetBottomDistanceToSurface(bottomVertices, TRS,
  1109. Mathf.Abs(bottomMagnitude), toolSettings.paintOnPalettePrefabs,
  1110. toolSettings.paintOnMeshesWithoutCollider, out Transform surfaceTransform);
  1111. itemPosition += itemRotation * (axisDirection * -bottomDistanceToSurfce);
  1112. }
  1113. }
  1114. obj.transform.position = itemPosition;
  1115. if (TilingManager.instance.applyBrushToExisting)
  1116. {
  1117. brushSettings = TilingManager.instance.applyBrushToExisting
  1118. ? (toolSettings.overwriteBrushProperties ? toolSettings.brushSettings : PaletteManager.selectedBrush)
  1119. : PaletteManager.GetBrushById(data.initialBrushId);
  1120. if (brushSettings == null) brushSettings = new BrushSettings();
  1121. obj.transform.localScale = Vector3.Scale(prefab.transform.localScale, scaleMult);
  1122. obj.transform.localRotation *= Quaternion.Euler(brushSettings.GetAdditionalAngle());
  1123. obj.transform.position += itemRotation * (axisDirection * brushSettings.GetSurfaceDistance());
  1124. var flipX = brushSettings.GetFlipX();
  1125. var flipY = brushSettings.GetFlipY();
  1126. if (flipX || flipY)
  1127. {
  1128. var spriteRenderers = obj.GetComponentsInChildren<SpriteRenderer>();
  1129. foreach (var spriteRenderer in spriteRenderers)
  1130. {
  1131. UnityEditor.Undo.RecordObject(spriteRenderer, TilingData.COMMAND_NAME);
  1132. spriteRenderer.flipX = flipX;
  1133. spriteRenderer.flipY = flipY;
  1134. }
  1135. }
  1136. }
  1137. _disabledObjects.Remove(obj);
  1138. }
  1139. foreach (var obj in _disabledObjects) if (obj != null) obj.SetActive(false);
  1140. }
  1141. private static void ApplySelectedPersistentTiling(bool deselectPoint)
  1142. {
  1143. if (!_persistentItemWasEdited) return;
  1144. _persistentItemWasEdited = false;
  1145. if (!ApplySelectedPersistentObject(deselectPoint, ref _editingPersistentTiling, ref _initialPersistentTilingData,
  1146. ref _selectedPersistentTilingData, TilingManager.instance)) return;
  1147. if (_initialPersistentTilingData == null) return;
  1148. var selectedTiling = TilingManager.instance.GetItem(_initialPersistentTilingData.id);
  1149. _initialPersistentTilingData = selectedTiling.Clone();
  1150. }
  1151. #endregion
  1152. }
  1153. #endregion
  1154. }