GridPaintPaletteClipboard.cs 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEngine.Tilemaps;
  6. using Event = UnityEngine.Event;
  7. using Object = UnityEngine.Object;
  8. namespace UnityEditor.Tilemaps
  9. {
  10. internal class GridPaintPaletteClipboard : PaintableGrid
  11. {
  12. static class Styles
  13. {
  14. public static readonly GUIStyle background = "CurveEditorBackground";
  15. }
  16. private static readonly string paletteSavedOutsideClipboard = L10n.Tr("Palette Asset {0} was changed outside of the Tile Palette. All changes in the Tile Palette made will be reverted.");
  17. private bool m_PaletteNeedsSave;
  18. private const float k_ZoomSpeed = 7f;
  19. private const float k_MinZoom = 10f; // How many pixels per cell at minimum
  20. private const float k_MaxZoom = 100f; // How many pixels per cell at maximum
  21. private const float k_Padding = 0.75f; // How many percentages of window size is the empty padding around the palette content
  22. private int m_KeyboardPanningID;
  23. private int m_MousePanningID;
  24. private float k_KeyboardPanningSpeed = 3.0f;
  25. private Vector3 m_KeyboardPanning;
  26. private Rect m_GUIRect = new Rect(0, 0, 200, 200);
  27. private bool m_OldFog;
  28. public Rect guiRect
  29. {
  30. get { return m_GUIRect; }
  31. set
  32. {
  33. if (m_GUIRect != value)
  34. {
  35. Rect oldValue = m_GUIRect;
  36. m_GUIRect = value;
  37. OnViewSizeChanged(oldValue, m_GUIRect);
  38. }
  39. }
  40. }
  41. [SerializeField] private GridPaintPaletteWindow m_Owner;
  42. public bool activeDragAndDrop { get { return DragAndDrop.objectReferences.Length > 0 && guiRect.Contains(Event.current.mousePosition); } }
  43. [SerializeField] private bool m_CameraInitializedToBounds;
  44. [SerializeField] public bool m_CameraPositionSaved;
  45. [SerializeField] public Vector3 m_CameraPosition;
  46. [SerializeField] public float m_CameraOrthographicSize;
  47. private RectInt? m_ActivePick;
  48. private Dictionary<Vector2Int, Object> m_HoverData;
  49. private bool m_Unlocked;
  50. private bool m_PingTileAsset;
  51. public GameObject palette { get { return m_Owner.palette; } }
  52. public GameObject paletteInstance { get { return m_Owner.paletteInstance; } }
  53. public Tilemap tilemap { get { return paletteInstance != null ? paletteInstance.GetComponentInChildren<Tilemap>() : null; } }
  54. private Grid grid { get { return paletteInstance != null ? paletteInstance.GetComponent<Grid>() : null; } }
  55. private Grid prefabGrid { get { return palette != null ? palette.GetComponent<Grid>() : null; } }
  56. public PreviewRenderUtility previewUtility { get { return m_Owner.previewUtility; } }
  57. private GridBrushBase gridBrush { get { return GridPaintingState.gridBrush; } }
  58. private Mesh m_GridMesh;
  59. private int m_LastGridHash;
  60. private Material m_GridMaterial;
  61. private static readonly Color k_GridColor = Color.white.AlphaMultiplied(0.1f);
  62. private bool m_PaletteUsed; // We mark palette used, when it has been changed in any way during being actively open.
  63. private Vector2? m_PreviousMousePosition;
  64. public TileBase activeTile
  65. {
  66. get
  67. {
  68. if (m_ActivePick.HasValue && m_ActivePick.Value.size == Vector2Int.one && GridPaintingState.defaultBrush != null && GridPaintingState.defaultBrush.cellCount > 0)
  69. return GridPaintingState.defaultBrush.cells[0].tile;
  70. return null;
  71. }
  72. }
  73. // TODO: Faster codepath for this
  74. private RectInt bounds
  75. {
  76. get
  77. {
  78. if (tilemap == null)
  79. return new RectInt();
  80. var origin = tilemap.origin;
  81. var size = tilemap.size;
  82. RectInt r = new RectInt(origin.x, origin.y, size.x, size.y);
  83. if (TilemapIsEmpty(tilemap))
  84. return r;
  85. int minX = origin.x + size.x;
  86. int minY = origin.y + size.y;
  87. int maxX = origin.x;
  88. int maxY = origin.y;
  89. foreach (Vector2Int pos in r.allPositionsWithin)
  90. {
  91. if (tilemap.GetTile(new Vector3Int(pos.x, pos.y, 0)) != null)
  92. {
  93. minX = Math.Min(minX, pos.x);
  94. minY = Math.Min(minY, pos.y);
  95. maxX = Math.Max(maxX, pos.x);
  96. maxY = Math.Max(maxY, pos.y);
  97. }
  98. }
  99. return new RectInt(minX, minY, maxX - minX + 1, maxY - minY + 1);
  100. }
  101. }
  102. // Max area we are ever showing. Depends on the zoom level and content of palette.
  103. private Rect paddedBounds
  104. {
  105. get
  106. {
  107. var GUIAspect = m_GUIRect.width / m_GUIRect.height;
  108. var orthographicSize = previewUtility.camera.orthographicSize;
  109. var paddingW = orthographicSize * GUIAspect * k_Padding * 2f;
  110. var paddingH = orthographicSize * k_Padding * 2f;
  111. Bounds localBounds = grid.GetBoundsLocal(
  112. new Vector3(bounds.xMin, bounds.yMin, 0.0f),
  113. new Vector3(bounds.size.x, bounds.size.y, 0.0f));
  114. Rect result = new Rect(
  115. new Vector2(localBounds.min.x - paddingW, localBounds.min.y - paddingH),
  116. new Vector2(localBounds.size.x + paddingW * 2f, localBounds.size.y + paddingH * 2f));
  117. return result;
  118. }
  119. }
  120. private RectInt paddedBoundsInt
  121. {
  122. get
  123. {
  124. Vector3Int min = grid.LocalToCell(paddedBounds.min);
  125. Vector3Int max = grid.LocalToCell(paddedBounds.max) + Vector3Int.one;
  126. return new RectInt(min.x, min.y, max.x - min.x, max.y - min.y);
  127. }
  128. }
  129. private GameObject brushTarget
  130. {
  131. get
  132. {
  133. return (tilemap != null) ? tilemap.gameObject : (grid != null) ? grid.gameObject : null;
  134. }
  135. }
  136. public bool unlocked
  137. {
  138. get { return m_Unlocked; }
  139. set
  140. {
  141. if (value == false && m_Unlocked)
  142. {
  143. if (tilemap != null)
  144. tilemap.ClearAllEditorPreviewTiles();
  145. SavePaletteIfNecessary();
  146. }
  147. m_Unlocked = value;
  148. }
  149. }
  150. public bool pingTileAsset
  151. {
  152. get { return m_PingTileAsset; }
  153. set
  154. {
  155. if (value && !m_PingTileAsset && m_ActivePick.HasValue) { PingTileAsset(m_ActivePick.Value); }
  156. m_PingTileAsset = value;
  157. }
  158. }
  159. public bool invalidClipboard { get { return m_Owner.palette == null; } }
  160. public bool isReceivingDragAndDrop { get { return m_HoverData != null && m_HoverData.Count > 0; } }
  161. public bool showNewEmptyClipboardInfo
  162. {
  163. get
  164. {
  165. if (paletteInstance == null)
  166. return false;
  167. if (tilemap == null)
  168. return false;
  169. if (unlocked && inEditMode)
  170. return false;
  171. if (!TilemapIsEmpty(tilemap))
  172. return false;
  173. if (tilemap.transform.childCount > 0)
  174. return false;
  175. if (isReceivingDragAndDrop)
  176. return false;
  177. // If user happens to erase the last content of used palette, we don't want to show the new palette info anymore
  178. if (m_PaletteUsed)
  179. return false;
  180. return true;
  181. }
  182. }
  183. public bool isModified { get { return m_PaletteNeedsSave; } }
  184. public GridPaintPaletteWindow owner
  185. {
  186. set { m_Owner = value; }
  187. }
  188. public void OnBeforePaletteSelectionChanged()
  189. {
  190. SavePaletteIfNecessary();
  191. DestroyPreviewInstance();
  192. FlushHoverData();
  193. }
  194. private void FlushHoverData()
  195. {
  196. if (m_HoverData != null)
  197. {
  198. m_HoverData.Clear();
  199. m_HoverData = null;
  200. }
  201. }
  202. public void OnAfterPaletteSelectionChanged()
  203. {
  204. m_PaletteUsed = false;
  205. ResetPreviewInstance();
  206. if (palette != null)
  207. ResetPreviewCamera();
  208. }
  209. public void SetupPreviewCameraOnInit()
  210. {
  211. if (m_CameraPositionSaved)
  212. LoadSavedCameraPosition();
  213. else
  214. ResetPreviewCamera();
  215. }
  216. private void LoadSavedCameraPosition()
  217. {
  218. previewUtility.camera.transform.position = m_CameraPosition;
  219. previewUtility.camera.orthographicSize = m_CameraOrthographicSize;
  220. previewUtility.camera.nearClipPlane = 0.01f;
  221. previewUtility.camera.farClipPlane = 100f;
  222. }
  223. private void ResetPreviewCamera()
  224. {
  225. var transform = previewUtility.camera.transform;
  226. transform.position = new Vector3(0, 0, -10f);
  227. transform.rotation = Quaternion.identity;
  228. previewUtility.camera.nearClipPlane = 0.01f;
  229. previewUtility.camera.farClipPlane = 100f;
  230. FrameEntirePalette();
  231. }
  232. private void DestroyPreviewInstance()
  233. {
  234. if (m_Owner != null)
  235. m_Owner.DestroyPreviewInstance();
  236. }
  237. private void ResetPreviewInstance()
  238. {
  239. m_Owner.ResetPreviewInstance();
  240. }
  241. public void ResetPreviewMesh()
  242. {
  243. if (m_GridMesh != null)
  244. {
  245. DestroyImmediate(m_GridMesh);
  246. m_GridMesh = null;
  247. }
  248. m_GridMaterial = null;
  249. }
  250. public void FrameEntirePalette()
  251. {
  252. Frame(bounds);
  253. }
  254. void Frame(RectInt rect)
  255. {
  256. if (grid == null)
  257. return;
  258. var position = grid.CellToLocalInterpolated(new Vector3(rect.center.x, rect.center.y, 0));
  259. position.z = -10f;
  260. previewUtility.camera.transform.position = position;
  261. var height = (grid.CellToLocal(new Vector3Int(0, rect.yMax, 0)) - grid.CellToLocal(new Vector3Int(0, rect.yMin, 0))).magnitude;
  262. var width = (grid.CellToLocal(new Vector3Int(rect.xMax, 0, 0)) - grid.CellToLocal(new Vector3Int(rect.xMin, 0, 0))).magnitude;
  263. var cellSize = grid.cellSize;
  264. width += cellSize.x;
  265. height += cellSize.y;
  266. var GUIAspect = m_GUIRect.width / m_GUIRect.height;
  267. var contentAspect = width / height;
  268. previewUtility.camera.orthographicSize = (GUIAspect > contentAspect ? height : width / GUIAspect) / 2f;
  269. ClampZoomAndPan();
  270. }
  271. private void RefreshAllTiles()
  272. {
  273. if (tilemap != null)
  274. tilemap.RefreshAllTiles();
  275. }
  276. protected override void OnEnable()
  277. {
  278. base.OnEnable();
  279. EditorApplication.editorApplicationQuit += EditorApplicationQuit;
  280. Undo.undoRedoPerformed += UndoRedoPerformed;
  281. m_KeyboardPanningID = GUIUtility.GetPermanentControlID();
  282. m_MousePanningID = GUIUtility.GetPermanentControlID();
  283. }
  284. protected override void OnDisable()
  285. {
  286. if (m_Owner && previewUtility != null && previewUtility.camera != null)
  287. {
  288. // Save Preview camera coordinates
  289. m_CameraPosition = previewUtility.camera.transform.position;
  290. m_CameraOrthographicSize = previewUtility.camera.orthographicSize;
  291. m_CameraPositionSaved = true;
  292. }
  293. SavePaletteIfNecessary();
  294. DestroyPreviewInstance();
  295. Undo.undoRedoPerformed -= UndoRedoPerformed;
  296. EditorApplication.editorApplicationQuit -= EditorApplicationQuit;
  297. base.OnDisable();
  298. }
  299. public override void OnGUI()
  300. {
  301. if (Mathf.Approximately(guiRect.width, 0f) || Mathf.Approximately(guiRect.height, 0f))
  302. return;
  303. UpdateMouseGridPosition();
  304. HandleDragAndDrop();
  305. if (palette == null)
  306. return;
  307. HandlePanAndZoom();
  308. if (showNewEmptyClipboardInfo)
  309. return;
  310. if (Event.current.type == EventType.Repaint && !m_CameraInitializedToBounds)
  311. {
  312. Frame(bounds);
  313. m_CameraInitializedToBounds = true;
  314. }
  315. HandleMouseEnterLeave();
  316. if (guiRect.Contains(Event.current.mousePosition) || Event.current.type != EventType.MouseDown)
  317. base.OnGUI();
  318. if (Event.current.type == EventType.Repaint)
  319. Render();
  320. else
  321. DoBrush();
  322. m_PreviousMousePosition = Event.current.mousePosition;
  323. }
  324. public void OnViewSizeChanged(Rect oldSize, Rect newSize)
  325. {
  326. if (Mathf.Approximately(oldSize.height * oldSize.width * newSize.height * newSize.width, 0f))
  327. return;
  328. Camera cam = previewUtility.camera;
  329. Vector2 sizeDelta = new Vector2(
  330. newSize.width / LocalToScreenRatio(newSize.height) - oldSize.width / LocalToScreenRatio(oldSize.height),
  331. newSize.height / LocalToScreenRatio(newSize.height) - oldSize.height / LocalToScreenRatio(oldSize.height));
  332. cam.transform.Translate(sizeDelta / 2f);
  333. ClampZoomAndPan();
  334. }
  335. private void EditorApplicationQuit()
  336. {
  337. SavePaletteIfNecessary();
  338. }
  339. private void UndoRedoPerformed()
  340. {
  341. if (unlocked)
  342. {
  343. m_PaletteNeedsSave = true;
  344. RefreshAllTiles();
  345. Repaint();
  346. }
  347. }
  348. private void HandlePanAndZoom()
  349. {
  350. switch (Event.current.type)
  351. {
  352. case EventType.MouseDown:
  353. if (MousePanningEvent() && guiRect.Contains(Event.current.mousePosition) && GUIUtility.hotControl == 0)
  354. {
  355. GUIUtility.hotControl = m_MousePanningID;
  356. Event.current.Use();
  357. }
  358. break;
  359. case EventType.ValidateCommand:
  360. if (Event.current.commandName == EventCommandNames.FrameSelected)
  361. {
  362. Event.current.Use();
  363. }
  364. break;
  365. case EventType.ExecuteCommand:
  366. if (Event.current.commandName == EventCommandNames.FrameSelected)
  367. {
  368. if (m_ActivePick.HasValue)
  369. Frame(m_ActivePick.Value);
  370. else
  371. FrameEntirePalette();
  372. Event.current.Use();
  373. }
  374. break;
  375. case EventType.ScrollWheel:
  376. if (guiRect.Contains(Event.current.mousePosition))
  377. {
  378. float zoomDelta = HandleUtility.niceMouseDeltaZoom * (Event.current.shift ? -9 : -3) * k_ZoomSpeed;
  379. Camera camera = previewUtility.camera;
  380. Vector3 oldLocalPos = ScreenToLocal(Event.current.mousePosition);
  381. camera.orthographicSize = Mathf.Max(.0001f, camera.orthographicSize * (1 + zoomDelta * .001f));
  382. ClampZoomAndPan();
  383. Vector3 newLocalPos = ScreenToLocal(Event.current.mousePosition);
  384. Vector3 localDelta = newLocalPos - oldLocalPos;
  385. camera.transform.position -= localDelta;
  386. ClampZoomAndPan();
  387. Event.current.Use();
  388. }
  389. break;
  390. case EventType.MouseDrag:
  391. if (GUIUtility.hotControl == m_MousePanningID)
  392. {
  393. Vector3 delta = new Vector3(-Event.current.delta.x, Event.current.delta.y, 0f) / LocalToScreenRatio();
  394. previewUtility.camera.transform.Translate(delta);
  395. ClampZoomAndPan();
  396. Event.current.Use();
  397. }
  398. break;
  399. case EventType.MouseMove: // Fix mouse cursor being stuck when panning ended outside our window
  400. if (GUIUtility.hotControl == m_MousePanningID && !MousePanningEvent())
  401. GUIUtility.hotControl = 0;
  402. break;
  403. case EventType.MouseUp:
  404. if (GUIUtility.hotControl == m_MousePanningID)
  405. {
  406. ClampZoomAndPan();
  407. GUIUtility.hotControl = 0;
  408. Event.current.Use();
  409. }
  410. break;
  411. case EventType.KeyDown:
  412. if (GUIUtility.hotControl == 0)
  413. {
  414. switch (Event.current.keyCode)
  415. {
  416. case KeyCode.LeftArrow:
  417. m_KeyboardPanning = new Vector3(-k_KeyboardPanningSpeed, 0f) / LocalToScreenRatio();
  418. GUIUtility.hotControl = m_KeyboardPanningID;
  419. Event.current.Use();
  420. break;
  421. case KeyCode.RightArrow:
  422. m_KeyboardPanning = new Vector3(k_KeyboardPanningSpeed, 0f) / LocalToScreenRatio();
  423. GUIUtility.hotControl = m_KeyboardPanningID;
  424. Event.current.Use();
  425. break;
  426. case KeyCode.UpArrow:
  427. m_KeyboardPanning = new Vector3(0f, k_KeyboardPanningSpeed) / LocalToScreenRatio();
  428. GUIUtility.hotControl = m_KeyboardPanningID;
  429. Event.current.Use();
  430. break;
  431. case KeyCode.DownArrow:
  432. m_KeyboardPanning = new Vector3(0f, -k_KeyboardPanningSpeed) / LocalToScreenRatio();
  433. GUIUtility.hotControl = m_KeyboardPanningID;
  434. Event.current.Use();
  435. break;
  436. }
  437. }
  438. break;
  439. case EventType.KeyUp:
  440. if (GUIUtility.hotControl == m_KeyboardPanningID)
  441. {
  442. m_KeyboardPanning = Vector3.zero;
  443. GUIUtility.hotControl = 0;
  444. Event.current.Use();
  445. }
  446. break;
  447. case EventType.Repaint:
  448. if (GUIUtility.hotControl == m_KeyboardPanningID)
  449. {
  450. previewUtility.camera.transform.Translate(m_KeyboardPanning);
  451. ClampZoomAndPan();
  452. Repaint();
  453. }
  454. if (GUIUtility.hotControl == m_MousePanningID)
  455. EditorGUIUtility.AddCursorRect(guiRect, MouseCursor.Pan);
  456. break;
  457. }
  458. }
  459. private static bool MousePanningEvent()
  460. {
  461. return (Event.current.button == 0 && Event.current.alt || Event.current.button > 0);
  462. }
  463. public void ClampZoomAndPan()
  464. {
  465. float pixelsPerCell = grid.cellSize.y * LocalToScreenRatio();
  466. if (pixelsPerCell < k_MinZoom)
  467. previewUtility.camera.orthographicSize = (grid.cellSize.y * guiRect.height) / (k_MinZoom * 2f);
  468. else if (pixelsPerCell > k_MaxZoom)
  469. previewUtility.camera.orthographicSize = (grid.cellSize.y * guiRect.height) / (k_MaxZoom * 2f);
  470. Camera cam = previewUtility.camera;
  471. float cameraOrthographicSize = cam.orthographicSize;
  472. Rect r = paddedBounds;
  473. Vector3 camPos = cam.transform.position;
  474. Vector2 camMin = camPos - new Vector3(cameraOrthographicSize * (guiRect.width / guiRect.height), cameraOrthographicSize);
  475. Vector2 camMax = camPos + new Vector3(cameraOrthographicSize * (guiRect.width / guiRect.height), cameraOrthographicSize);
  476. if (camMin.x < r.min.x)
  477. {
  478. camPos += new Vector3(r.min.x - camMin.x, 0f, 0f);
  479. }
  480. if (camMin.y < r.min.y)
  481. {
  482. camPos += new Vector3(0f, r.min.y - camMin.y, 0f);
  483. }
  484. if (camMax.x > r.max.x)
  485. {
  486. camPos += new Vector3(r.max.x - camMax.x, 0f, 0f);
  487. }
  488. if (camMax.y > r.max.y)
  489. {
  490. camPos += new Vector3(0f, r.max.y - camMax.y, 0f);
  491. }
  492. camPos.Set(camPos.x, camPos.y, -10f);
  493. cam.transform.position = camPos;
  494. DestroyImmediate(m_GridMesh);
  495. m_GridMesh = null;
  496. }
  497. private void Render()
  498. {
  499. if (m_GridMesh != null && GetGridHash() != m_LastGridHash)
  500. {
  501. ResetPreviewInstance();
  502. ResetPreviewMesh();
  503. }
  504. using (new PreviewInstanceScope(guiRect, previewUtility, paletteInstance, m_Owner.drawGizmos))
  505. {
  506. RenderGrid();
  507. previewUtility.Render();
  508. if (m_Owner.drawGizmos)
  509. Handles.Internal_DoDrawGizmos(previewUtility.camera);
  510. }
  511. RenderDragAndDropPreview();
  512. CallOnSceneGUI();
  513. DoBrush();
  514. previewUtility.EndAndDrawPreview(guiRect);
  515. m_LastGridHash = GetGridHash();
  516. }
  517. private int GetGridHash()
  518. {
  519. if (prefabGrid == null)
  520. return 0;
  521. int hash = prefabGrid.GetHashCode();
  522. unchecked
  523. {
  524. hash = hash * 33 + prefabGrid.cellGap.GetHashCode();
  525. hash = hash * 33 + prefabGrid.cellLayout.GetHashCode();
  526. hash = hash * 33 + prefabGrid.cellSize.GetHashCode();
  527. hash = hash * 33 + prefabGrid.cellSwizzle.GetHashCode();
  528. hash = hash * 33 + SceneViewGridManager.sceneViewGridComponentGizmo.Color.GetHashCode();
  529. }
  530. return hash;
  531. }
  532. private void RenderDragAndDropPreview()
  533. {
  534. if (!activeDragAndDrop || m_HoverData == null || m_HoverData.Count == 0)
  535. return;
  536. RectInt rect = TileDragAndDrop.GetMinMaxRect(m_HoverData.Keys.ToList());
  537. rect.position += mouseGridPosition;
  538. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  539. GridEditorUtility.DrawGridMarquee(grid, new BoundsInt(new Vector3Int(rect.xMin, rect.yMin, zPosition), new Vector3Int(rect.width, rect.height, 1)), Color.white);
  540. }
  541. private void RenderGrid()
  542. {
  543. // MeshTopology.Lines doesn't give nice pixel perfect grid so we have to have separate codepath with MeshTopology.Quads specially for palette window here
  544. if (m_GridMesh == null && grid.cellLayout == GridLayout.CellLayout.Rectangle)
  545. m_GridMesh = GridEditorUtility.GenerateCachedGridMesh(grid, k_GridColor, 1f / LocalToScreenRatio(), paddedBoundsInt, MeshTopology.Quads);
  546. GridEditorUtility.DrawGridGizmo(grid, grid.transform, k_GridColor, ref m_GridMesh, ref m_GridMaterial);
  547. }
  548. private void DoBrush()
  549. {
  550. if (activeDragAndDrop)
  551. return;
  552. RenderSelectedBrushMarquee();
  553. CallOnPaintSceneGUI(mouseGridPosition);
  554. }
  555. private class PreviewInstanceScope : IDisposable
  556. {
  557. private readonly PreviewRenderUtility m_PreviewRenderUtility;
  558. private readonly bool m_OldFog;
  559. private readonly bool m_DrawGizmos;
  560. private readonly GameObject m_PaletteInstance;
  561. private readonly Transform[] m_PaletteTransforms;
  562. private readonly Renderer[] m_Renderers;
  563. public PreviewInstanceScope(Rect guiRect, PreviewRenderUtility previewRenderUtility, GameObject paletteInstance, bool drawGizmos)
  564. {
  565. m_PreviewRenderUtility = previewRenderUtility;
  566. m_PaletteInstance = paletteInstance;
  567. m_DrawGizmos = drawGizmos;
  568. m_OldFog = RenderSettings.fog;
  569. m_PreviewRenderUtility.BeginPreview(guiRect, Styles.background);
  570. Unsupported.SetRenderSettingsUseFogNoDirty(false);
  571. if (m_DrawGizmos)
  572. {
  573. m_PaletteTransforms = m_PaletteInstance.GetComponentsInChildren<Transform>();
  574. foreach (var transform in m_PaletteTransforms)
  575. transform.gameObject.hideFlags = HideFlags.None;
  576. // Case 1199516: Set Dirty on palette instance to force a refresh on gizmo drawing
  577. EditorUtility.SetDirty(m_PaletteInstance);
  578. Unsupported.SceneTrackerFlushDirty();
  579. }
  580. m_Renderers = m_PaletteInstance.GetComponentsInChildren<Renderer>();
  581. foreach (var renderer in m_Renderers)
  582. {
  583. renderer.gameObject.layer = Camera.PreviewCullingLayer;
  584. renderer.allowOcclusionWhenDynamic = false;
  585. }
  586. m_PreviewRenderUtility.AddManagedGO(m_PaletteInstance);
  587. Handles.DrawCameraImpl(guiRect, m_PreviewRenderUtility.camera, DrawCameraMode.Textured, false, new DrawGridParameters(), true, false);
  588. }
  589. public void Dispose()
  590. {
  591. if (m_Renderers != null)
  592. {
  593. foreach (var renderer in m_Renderers)
  594. renderer.gameObject.layer = 0;
  595. }
  596. if (m_DrawGizmos && m_PaletteTransforms != null)
  597. {
  598. foreach (var transform in m_PaletteTransforms)
  599. transform.gameObject.hideFlags = HideFlags.HideAndDontSave;
  600. }
  601. Unsupported.SetRenderSettingsUseFogNoDirty(m_OldFog);
  602. }
  603. }
  604. public void HandleDragAndDrop()
  605. {
  606. if (DragAndDrop.objectReferences.Length == 0 || !guiRect.Contains(Event.current.mousePosition))
  607. return;
  608. switch (Event.current.type)
  609. {
  610. //TODO: Cache this
  611. case EventType.DragUpdated:
  612. {
  613. List<Texture2D> sheets = TileDragAndDrop.GetValidSpritesheets(DragAndDrop.objectReferences);
  614. List<Sprite> sprites = TileDragAndDrop.GetValidSingleSprites(DragAndDrop.objectReferences);
  615. List<TileBase> tiles = TileDragAndDrop.GetValidTiles(DragAndDrop.objectReferences);
  616. m_HoverData = TileDragAndDrop.CreateHoverData(sheets, sprites, tiles);
  617. if (m_HoverData != null && m_HoverData.Count > 0)
  618. {
  619. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  620. Event.current.Use();
  621. GUI.changed = true;
  622. }
  623. }
  624. break;
  625. case EventType.DragPerform:
  626. {
  627. if (m_HoverData == null || m_HoverData.Count == 0)
  628. return;
  629. RegisterUndo();
  630. bool wasEmpty = TilemapIsEmpty(tilemap);
  631. Vector2Int targetPosition = mouseGridPosition;
  632. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  633. Dictionary<Vector2Int, TileBase> tileSheet = TileDragAndDrop.ConvertToTileSheet(m_HoverData);
  634. foreach (KeyValuePair<Vector2Int, TileBase> item in tileSheet)
  635. SetTile(tilemap, targetPosition + item.Key, item.Value, Color.white, Matrix4x4.identity);
  636. OnPaletteChanged();
  637. m_PaletteNeedsSave = true;
  638. FlushHoverData();
  639. GUI.changed = true;
  640. SavePaletteIfNecessary();
  641. if (wasEmpty)
  642. {
  643. ResetPreviewInstance();
  644. FrameEntirePalette();
  645. }
  646. Event.current.Use();
  647. GUIUtility.ExitGUI();
  648. }
  649. break;
  650. case EventType.Repaint:
  651. // Handled in Render()
  652. break;
  653. }
  654. if (m_HoverData != null && (
  655. Event.current.type == EventType.DragExited ||
  656. Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape))
  657. {
  658. DragAndDrop.visualMode = DragAndDropVisualMode.None;
  659. FlushHoverData();
  660. Event.current.Use();
  661. }
  662. }
  663. public void SetTile(Tilemap tilemapTarget, Vector2Int position, TileBase tile, Color color, Matrix4x4 matrix)
  664. {
  665. Vector3Int pos3 = new Vector3Int(position.x, position.y, zPosition);
  666. tilemapTarget.SetTile(pos3, tile);
  667. tilemapTarget.SetColor(pos3, color);
  668. tilemapTarget.SetTransformMatrix(pos3, matrix);
  669. }
  670. protected override void Paint(Vector3Int position)
  671. {
  672. if (gridBrush == null)
  673. return;
  674. gridBrush.Paint(grid, brushTarget, position);
  675. OnPaletteChanged();
  676. }
  677. protected override void Erase(Vector3Int position)
  678. {
  679. if (gridBrush == null)
  680. return;
  681. gridBrush.Erase(grid, brushTarget, position);
  682. OnPaletteChanged();
  683. }
  684. protected override void BoxFill(BoundsInt position)
  685. {
  686. if (gridBrush == null)
  687. return;
  688. gridBrush.BoxFill(grid, brushTarget, position);
  689. OnPaletteChanged();
  690. }
  691. protected override void BoxErase(BoundsInt position)
  692. {
  693. if (gridBrush == null)
  694. return;
  695. gridBrush.BoxErase(grid, brushTarget, position);
  696. OnPaletteChanged();
  697. }
  698. protected override void FloodFill(Vector3Int position)
  699. {
  700. if (gridBrush == null)
  701. return;
  702. gridBrush.FloodFill(grid, brushTarget, position);
  703. OnPaletteChanged();
  704. }
  705. protected override void PickBrush(BoundsInt position, Vector3Int pickingStart)
  706. {
  707. if (grid == null || gridBrush == null)
  708. return;
  709. gridBrush.Pick(grid, brushTarget, position, pickingStart);
  710. if (!InGridEditMode())
  711. TilemapEditorTool.SetActiveEditorTool(typeof(PaintTool));
  712. m_ActivePick = new RectInt(position.min.x, position.min.y, position.size.x, position.size.y);
  713. }
  714. protected override void Select(BoundsInt position)
  715. {
  716. if (grid)
  717. {
  718. GridSelection.Select(brushTarget, position);
  719. gridBrush.Select(grid, brushTarget, position);
  720. }
  721. }
  722. protected override void Move(BoundsInt from, BoundsInt to)
  723. {
  724. if (grid)
  725. gridBrush.Move(grid, brushTarget, from, to);
  726. }
  727. protected override void MoveStart(BoundsInt position)
  728. {
  729. if (grid)
  730. gridBrush.MoveStart(grid, brushTarget, position);
  731. }
  732. protected override void MoveEnd(BoundsInt position)
  733. {
  734. if (grid)
  735. {
  736. gridBrush.MoveEnd(grid, brushTarget, position);
  737. OnPaletteChanged();
  738. }
  739. }
  740. public override void Repaint()
  741. {
  742. m_Owner.Repaint();
  743. }
  744. protected override void ClearGridSelection()
  745. {
  746. GridSelection.Clear();
  747. }
  748. protected override void OnBrushPickStarted()
  749. {
  750. }
  751. protected override void OnBrushPickDragged(BoundsInt position)
  752. {
  753. m_ActivePick = new RectInt(position.min.x, position.min.y, position.size.x, position.size.y);
  754. }
  755. protected override void OnBrushPickCancelled()
  756. {
  757. m_ActivePick = null;
  758. }
  759. private void PingTileAsset(RectInt rect)
  760. {
  761. // Only able to ping asset if only one asset is selected
  762. if (rect.size == Vector2Int.zero && tilemap != null)
  763. {
  764. TileBase tile = tilemap.GetTile(new Vector3Int(rect.xMin, rect.yMin, zPosition));
  765. EditorGUIUtility.PingObject(tile);
  766. Selection.activeObject = tile;
  767. }
  768. }
  769. protected override bool ValidateFloodFillPosition(Vector3Int position)
  770. {
  771. return true;
  772. }
  773. protected override bool PickingIsDefaultTool()
  774. {
  775. return !m_Unlocked;
  776. }
  777. protected override bool CanPickOutsideEditMode()
  778. {
  779. return true;
  780. }
  781. protected override GridLayout.CellLayout CellLayout()
  782. {
  783. if (grid != null)
  784. return grid.cellLayout;
  785. return GridLayout.CellLayout.Rectangle;
  786. }
  787. protected override Vector2Int ScreenToGrid(Vector2 screenPosition)
  788. {
  789. Vector2 local = ScreenToLocal(screenPosition);
  790. Vector3Int result3 = grid.LocalToCell(local);
  791. Vector2Int result = new Vector2Int(result3.x, result3.y);
  792. return result;
  793. }
  794. private void RenderSelectedBrushMarquee()
  795. {
  796. if (!unlocked && m_ActivePick.HasValue)
  797. {
  798. DrawSelectionGizmo(m_ActivePick.Value);
  799. }
  800. }
  801. protected void DrawSelectionGizmo(RectInt rect)
  802. {
  803. if (Event.current.type != EventType.Repaint || !GUI.enabled)
  804. return;
  805. Color color = Color.white;
  806. if (isPicking)
  807. color = Color.cyan;
  808. GridEditorUtility.DrawGridMarquee(grid, new BoundsInt(new Vector3Int(rect.xMin, rect.yMin, 0), new Vector3Int(rect.width, rect.height, 1)), color);
  809. }
  810. private void HandleMouseEnterLeave()
  811. {
  812. if (guiRect.Contains(Event.current.mousePosition))
  813. {
  814. if (m_PreviousMousePosition.HasValue && !guiRect.Contains(m_PreviousMousePosition.Value) || !m_PreviousMousePosition.HasValue)
  815. {
  816. if (GridPaintingState.activeBrushEditor != null)
  817. {
  818. GridPaintingState.activeBrushEditor.OnMouseEnter();
  819. }
  820. }
  821. }
  822. else
  823. {
  824. if (m_PreviousMousePosition.HasValue && guiRect.Contains(m_PreviousMousePosition.Value) && !guiRect.Contains(Event.current.mousePosition))
  825. {
  826. if (GridPaintingState.activeBrushEditor != null)
  827. {
  828. GridPaintingState.activeBrushEditor.OnMouseLeave();
  829. Repaint();
  830. }
  831. }
  832. }
  833. }
  834. private void CallOnSceneGUI()
  835. {
  836. var gridLayout = tilemap != null ? tilemap : grid as GridLayout;
  837. bool hasSelection = GridSelection.active && GridSelection.target == brushTarget;
  838. if (hasSelection)
  839. {
  840. var rect = new RectInt(GridSelection.position.xMin, GridSelection.position.yMin, GridSelection.position.size.x, GridSelection.position.size.y);
  841. BoundsInt brushBounds = new BoundsInt(new Vector3Int(rect.x, rect.y, zPosition), new Vector3Int(rect.width, rect.height, 1));
  842. GridBrushEditorBase.OnSceneGUIInternal(gridLayout, brushTarget, brushBounds, EditTypeToBrushTool(UnityEditor.EditorTools.ToolManager.activeToolType), m_MarqueeStart.HasValue || executing);
  843. }
  844. if (GridPaintingState.activeBrushEditor != null)
  845. {
  846. GridPaintingState.activeBrushEditor.OnSceneGUI(gridLayout, brushTarget);
  847. }
  848. }
  849. private void CallOnPaintSceneGUI(Vector2Int position)
  850. {
  851. if (!unlocked && !TilemapEditorTool.IsActive(typeof(SelectTool)) && !TilemapEditorTool.IsActive(typeof(PickingTool)))
  852. return;
  853. bool hasSelection = GridSelection.active && GridSelection.target == brushTarget;
  854. if (!hasSelection && GridPaintingState.activeGrid != this)
  855. return;
  856. GridBrushBase brush = GridPaintingState.gridBrush;
  857. if (brush == null)
  858. return;
  859. var rect = new RectInt(position, new Vector2Int(1, 1));
  860. if (m_MarqueeStart.HasValue)
  861. rect = GridEditorUtility.GetMarqueeRect(position, m_MarqueeStart.Value);
  862. else if (hasSelection)
  863. rect = new RectInt(GridSelection.position.xMin, GridSelection.position.yMin, GridSelection.position.size.x, GridSelection.position.size.y);
  864. var gridLayout = tilemap != null ? tilemap.layoutGrid : grid as GridLayout;
  865. BoundsInt brushBounds = new BoundsInt(new Vector3Int(rect.x, rect.y, zPosition), new Vector3Int(rect.width, rect.height, 1));
  866. if (GridPaintingState.activeBrushEditor != null)
  867. GridPaintingState.activeBrushEditor.OnPaintSceneGUI(gridLayout, brushTarget, brushBounds,
  868. EditTypeToBrushTool(UnityEditor.EditorTools.ToolManager.activeToolType),
  869. m_MarqueeStart.HasValue || executing);
  870. else // Fallback when user hasn't defined custom editor
  871. GridBrushEditorBase.OnPaintSceneGUIInternal(gridLayout, Selection.activeGameObject, brushBounds,
  872. EditTypeToBrushTool(UnityEditor.EditorTools.ToolManager.activeToolType),
  873. m_MarqueeStart.HasValue || executing);
  874. }
  875. protected override void RegisterUndo()
  876. {
  877. if (!invalidClipboard)
  878. {
  879. Undo.RegisterFullObjectHierarchyUndo(paletteInstance, "Edit Palette");
  880. }
  881. }
  882. private void OnPaletteChanged()
  883. {
  884. m_PaletteUsed = true;
  885. m_PaletteNeedsSave = true;
  886. Undo.FlushUndoRecordObjects();
  887. }
  888. public void CheckRevertIfChanged(string[] paths)
  889. {
  890. if (paths != null && m_PaletteNeedsSave && palette != null)
  891. {
  892. var currentPalettePath = AssetDatabase.GetAssetPath(palette);
  893. foreach (var path in paths)
  894. {
  895. if (currentPalettePath == path)
  896. {
  897. m_PaletteNeedsSave = false;
  898. ResetPreviewInstance();
  899. Debug.LogWarningFormat(palette, paletteSavedOutsideClipboard, palette.name);
  900. break;
  901. }
  902. }
  903. }
  904. }
  905. public void SavePaletteIfNecessary()
  906. {
  907. if (m_PaletteNeedsSave)
  908. {
  909. m_Owner.SavePalette();
  910. m_PaletteNeedsSave = false;
  911. }
  912. }
  913. public Vector2 GridToScreen(Vector2 gridPosition)
  914. {
  915. Vector3 gridPosition3 = new Vector3(gridPosition.x, gridPosition.y, 0);
  916. return LocalToScreen(grid.CellToLocalInterpolated(gridPosition3));
  917. }
  918. public Vector2 ScreenToLocal(Vector2 screenPosition)
  919. {
  920. Vector2 viewPosition = previewUtility.camera.transform.position;
  921. screenPosition -= new Vector2(guiRect.xMin, guiRect.yMin);
  922. Vector2 offsetFromCenter = new Vector2(screenPosition.x - guiRect.width * .5f, guiRect.height * .5f - screenPosition.y);
  923. return viewPosition + offsetFromCenter / LocalToScreenRatio();
  924. }
  925. protected Vector2 LocalToScreen(Vector2 localPosition)
  926. {
  927. Vector2 viewPosition = previewUtility.camera.transform.position;
  928. Vector2 offsetFromCenter = new Vector2(localPosition.x - viewPosition.x, viewPosition.y - localPosition.y);
  929. return offsetFromCenter * LocalToScreenRatio() + new Vector2(guiRect.width * .5f + guiRect.xMin, guiRect.height * .5f + guiRect.yMin);
  930. }
  931. private float LocalToScreenRatio()
  932. {
  933. return guiRect.height / (previewUtility.camera.orthographicSize * 2f);
  934. }
  935. private float LocalToScreenRatio(float viewHeight)
  936. {
  937. return viewHeight / (previewUtility.camera.orthographicSize * 2f);
  938. }
  939. private static bool TilemapIsEmpty(Tilemap tilemap)
  940. {
  941. return tilemap.GetUsedTilesCount() == 0;
  942. }
  943. public void UnlockAndEdit()
  944. {
  945. unlocked = true;
  946. m_PaletteNeedsSave = true;
  947. }
  948. }
  949. }