No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GridPaintPaletteClipboard.cs 43KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  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, TileDragAndDropHoverData> 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. return;
  343. m_PaletteNeedsSave = true;
  344. RefreshAllTiles();
  345. Repaint();
  346. }
  347. private void HandlePanAndZoom()
  348. {
  349. switch (Event.current.type)
  350. {
  351. case EventType.MouseDown:
  352. if (MousePanningEvent() && guiRect.Contains(Event.current.mousePosition) && GUIUtility.hotControl == 0)
  353. {
  354. GUIUtility.hotControl = m_MousePanningID;
  355. Event.current.Use();
  356. }
  357. break;
  358. case EventType.ValidateCommand:
  359. if (Event.current.commandName == EventCommandNames.FrameSelected)
  360. {
  361. Event.current.Use();
  362. }
  363. break;
  364. case EventType.ExecuteCommand:
  365. if (Event.current.commandName == EventCommandNames.FrameSelected)
  366. {
  367. if (m_ActivePick.HasValue)
  368. Frame(m_ActivePick.Value);
  369. else
  370. FrameEntirePalette();
  371. Event.current.Use();
  372. }
  373. break;
  374. case EventType.ScrollWheel:
  375. if (guiRect.Contains(Event.current.mousePosition))
  376. {
  377. float zoomDelta = HandleUtility.niceMouseDeltaZoom * (Event.current.shift ? -9 : -3) * k_ZoomSpeed;
  378. Camera camera = previewUtility.camera;
  379. Vector3 oldLocalPos = ScreenToLocal(Event.current.mousePosition);
  380. camera.orthographicSize = Mathf.Max(.0001f, camera.orthographicSize * (1 + zoomDelta * .001f));
  381. ClampZoomAndPan();
  382. Vector3 newLocalPos = ScreenToLocal(Event.current.mousePosition);
  383. Vector3 localDelta = newLocalPos - oldLocalPos;
  384. camera.transform.position -= localDelta;
  385. ClampZoomAndPan();
  386. Event.current.Use();
  387. }
  388. break;
  389. case EventType.MouseDrag:
  390. if (GUIUtility.hotControl == m_MousePanningID)
  391. {
  392. Vector3 delta = new Vector3(-Event.current.delta.x, Event.current.delta.y, 0f) / LocalToScreenRatio();
  393. previewUtility.camera.transform.Translate(delta);
  394. ClampZoomAndPan();
  395. Event.current.Use();
  396. }
  397. break;
  398. case EventType.MouseMove: // Fix mouse cursor being stuck when panning ended outside our window
  399. if (GUIUtility.hotControl == m_MousePanningID && !MousePanningEvent())
  400. GUIUtility.hotControl = 0;
  401. break;
  402. case EventType.MouseUp:
  403. if (GUIUtility.hotControl == m_MousePanningID)
  404. {
  405. ClampZoomAndPan();
  406. GUIUtility.hotControl = 0;
  407. Event.current.Use();
  408. }
  409. break;
  410. case EventType.KeyDown:
  411. if (GUIUtility.hotControl == 0)
  412. {
  413. switch (Event.current.keyCode)
  414. {
  415. case KeyCode.LeftArrow:
  416. m_KeyboardPanning = new Vector3(-k_KeyboardPanningSpeed, 0f) / LocalToScreenRatio();
  417. GUIUtility.hotControl = m_KeyboardPanningID;
  418. Event.current.Use();
  419. break;
  420. case KeyCode.RightArrow:
  421. m_KeyboardPanning = new Vector3(k_KeyboardPanningSpeed, 0f) / LocalToScreenRatio();
  422. GUIUtility.hotControl = m_KeyboardPanningID;
  423. Event.current.Use();
  424. break;
  425. case KeyCode.UpArrow:
  426. m_KeyboardPanning = new Vector3(0f, k_KeyboardPanningSpeed) / LocalToScreenRatio();
  427. GUIUtility.hotControl = m_KeyboardPanningID;
  428. Event.current.Use();
  429. break;
  430. case KeyCode.DownArrow:
  431. m_KeyboardPanning = new Vector3(0f, -k_KeyboardPanningSpeed) / LocalToScreenRatio();
  432. GUIUtility.hotControl = m_KeyboardPanningID;
  433. Event.current.Use();
  434. break;
  435. }
  436. }
  437. break;
  438. case EventType.KeyUp:
  439. if (GUIUtility.hotControl == m_KeyboardPanningID)
  440. {
  441. m_KeyboardPanning = Vector3.zero;
  442. GUIUtility.hotControl = 0;
  443. Event.current.Use();
  444. }
  445. break;
  446. case EventType.Repaint:
  447. if (GUIUtility.hotControl == m_KeyboardPanningID)
  448. {
  449. previewUtility.camera.transform.Translate(m_KeyboardPanning);
  450. ClampZoomAndPan();
  451. Repaint();
  452. }
  453. if (GUIUtility.hotControl == m_MousePanningID)
  454. EditorGUIUtility.AddCursorRect(guiRect, MouseCursor.Pan);
  455. break;
  456. }
  457. }
  458. private static bool MousePanningEvent()
  459. {
  460. return (Event.current.button == 0 && Event.current.alt || Event.current.button > 0);
  461. }
  462. public void ClampZoomAndPan()
  463. {
  464. float pixelsPerCell = grid.cellSize.y * LocalToScreenRatio();
  465. if (pixelsPerCell < k_MinZoom)
  466. previewUtility.camera.orthographicSize = (grid.cellSize.y * guiRect.height) / (k_MinZoom * 2f);
  467. else if (pixelsPerCell > k_MaxZoom)
  468. previewUtility.camera.orthographicSize = (grid.cellSize.y * guiRect.height) / (k_MaxZoom * 2f);
  469. Camera cam = previewUtility.camera;
  470. float cameraOrthographicSize = cam.orthographicSize;
  471. Rect r = paddedBounds;
  472. Vector3 camPos = cam.transform.position;
  473. Vector2 camMin = camPos - new Vector3(cameraOrthographicSize * (guiRect.width / guiRect.height), cameraOrthographicSize);
  474. Vector2 camMax = camPos + new Vector3(cameraOrthographicSize * (guiRect.width / guiRect.height), cameraOrthographicSize);
  475. if (camMin.x < r.min.x)
  476. {
  477. camPos += new Vector3(r.min.x - camMin.x, 0f, 0f);
  478. }
  479. if (camMin.y < r.min.y)
  480. {
  481. camPos += new Vector3(0f, r.min.y - camMin.y, 0f);
  482. }
  483. if (camMax.x > r.max.x)
  484. {
  485. camPos += new Vector3(r.max.x - camMax.x, 0f, 0f);
  486. }
  487. if (camMax.y > r.max.y)
  488. {
  489. camPos += new Vector3(0f, r.max.y - camMax.y, 0f);
  490. }
  491. camPos.Set(camPos.x, camPos.y, -10f);
  492. cam.transform.position = camPos;
  493. DestroyImmediate(m_GridMesh);
  494. m_GridMesh = null;
  495. }
  496. private void Render()
  497. {
  498. if (m_GridMesh != null && GetGridHash() != m_LastGridHash)
  499. {
  500. ResetPreviewInstance();
  501. ResetPreviewMesh();
  502. }
  503. using (new PreviewInstanceScope(guiRect, previewUtility, paletteInstance, m_Owner.drawGizmos))
  504. {
  505. previewUtility.Render(true);
  506. if (m_Owner.drawGridGizmo)
  507. RenderGrid();
  508. if (m_Owner.drawGizmos)
  509. {
  510. // Set CameraType to SceneView to force Gizmos to be drawn
  511. var storedType = previewUtility.camera.cameraType;
  512. previewUtility.camera.cameraType = CameraType.SceneView;
  513. Handles.Internal_DoDrawGizmos(previewUtility.camera);
  514. previewUtility.camera.cameraType = storedType;
  515. }
  516. }
  517. RenderDragAndDropPreview();
  518. CallOnSceneGUI();
  519. DoBrush();
  520. previewUtility.EndAndDrawPreview(guiRect);
  521. m_LastGridHash = GetGridHash();
  522. }
  523. private int GetGridHash()
  524. {
  525. if (prefabGrid == null)
  526. return 0;
  527. int hash = prefabGrid.GetHashCode();
  528. unchecked
  529. {
  530. hash = hash * 33 + prefabGrid.cellGap.GetHashCode();
  531. hash = hash * 33 + prefabGrid.cellLayout.GetHashCode();
  532. hash = hash * 33 + prefabGrid.cellSize.GetHashCode();
  533. hash = hash * 33 + prefabGrid.cellSwizzle.GetHashCode();
  534. hash = hash * 33 + SceneViewGridManager.sceneViewGridComponentGizmo.Color.GetHashCode();
  535. }
  536. return hash;
  537. }
  538. private void RenderDragAndDropPreview()
  539. {
  540. if (!activeDragAndDrop || m_HoverData == null || m_HoverData.Count == 0)
  541. return;
  542. RectInt rect = TileDragAndDrop.GetMinMaxRect(m_HoverData.Keys.ToList());
  543. rect.position += mouseGridPosition;
  544. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  545. GridEditorUtility.DrawGridMarquee(grid, new BoundsInt(new Vector3Int(rect.xMin, rect.yMin, zPosition), new Vector3Int(rect.width, rect.height, 1)), Color.white);
  546. }
  547. private void RenderGrid()
  548. {
  549. // MeshTopology.Lines doesn't give nice pixel perfect grid so we have to have separate codepath with MeshTopology.Quads specially for palette window here
  550. if (m_GridMesh == null && grid.cellLayout == GridLayout.CellLayout.Rectangle)
  551. m_GridMesh = GridEditorUtility.GenerateCachedGridMesh(grid, k_GridColor, 1f / LocalToScreenRatio(), paddedBoundsInt, MeshTopology.Quads);
  552. GridEditorUtility.DrawGridGizmo(grid, grid.transform, k_GridColor, ref m_GridMesh, ref m_GridMaterial);
  553. }
  554. private void DoBrush()
  555. {
  556. if (activeDragAndDrop)
  557. return;
  558. RenderSelectedBrushMarquee();
  559. CallOnPaintSceneGUI(mouseGridPosition);
  560. }
  561. private class PreviewInstanceScope : IDisposable
  562. {
  563. private readonly PreviewRenderUtility m_PreviewRenderUtility;
  564. private readonly bool m_OldFog;
  565. private readonly bool m_DrawGizmos;
  566. private readonly GameObject m_PaletteInstance;
  567. private readonly Transform[] m_PaletteTransforms;
  568. private readonly Renderer[] m_Renderers;
  569. public PreviewInstanceScope(Rect guiRect, PreviewRenderUtility previewRenderUtility, GameObject paletteInstance, bool drawGizmos)
  570. {
  571. m_PreviewRenderUtility = previewRenderUtility;
  572. m_PaletteInstance = paletteInstance;
  573. m_DrawGizmos = drawGizmos;
  574. m_OldFog = RenderSettings.fog;
  575. m_PreviewRenderUtility.BeginPreview(guiRect, Styles.background);
  576. Unsupported.SetRenderSettingsUseFogNoDirty(false);
  577. if (m_DrawGizmos)
  578. {
  579. m_PaletteTransforms = m_PaletteInstance.GetComponentsInChildren<Transform>();
  580. foreach (var transform in m_PaletteTransforms)
  581. transform.gameObject.hideFlags = HideFlags.None;
  582. // Case 1199516: Set Dirty on palette instance to force a refresh on gizmo drawing
  583. EditorUtility.SetDirty(m_PaletteInstance);
  584. Unsupported.SceneTrackerFlushDirty();
  585. }
  586. m_Renderers = m_PaletteInstance.GetComponentsInChildren<Renderer>();
  587. foreach (var renderer in m_Renderers)
  588. {
  589. renderer.allowOcclusionWhenDynamic = false;
  590. }
  591. m_PreviewRenderUtility.AddManagedGO(m_PaletteInstance);
  592. Handles.DrawCameraImpl(guiRect, m_PreviewRenderUtility.camera, DrawCameraMode.Textured, false, new DrawGridParameters(), true, false);
  593. }
  594. public void Dispose()
  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, tilemap.cellLayout);
  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. var tileSheet = TileDragAndDrop.ConvertToTileSheet(m_HoverData);
  634. int i = 0;
  635. foreach (KeyValuePair<Vector2Int, TileDragAndDropHoverData> item in m_HoverData)
  636. {
  637. if (i >= tileSheet.Count)
  638. break;
  639. var offset = Vector3.zero;
  640. if (item.Value.hasOffset)
  641. {
  642. offset = item.Value.positionOffset - tilemap.tileAnchor;
  643. var cellSize = tilemap.cellSize;
  644. if (wasEmpty)
  645. {
  646. cellSize = item.Value.scaleFactor;
  647. }
  648. offset.x *= cellSize.x;
  649. offset.y *= cellSize.y;
  650. offset.z *= cellSize.z;
  651. }
  652. SetTile(tilemap
  653. , targetPosition + item.Key
  654. , tileSheet[i++]
  655. , Color.white
  656. , Matrix4x4.TRS(offset, Quaternion.identity, Vector3.one));
  657. }
  658. OnPaletteChanged();
  659. m_PaletteNeedsSave = true;
  660. FlushHoverData();
  661. GUI.changed = true;
  662. SavePaletteIfNecessary();
  663. if (wasEmpty)
  664. {
  665. ResetPreviewInstance();
  666. FrameEntirePalette();
  667. }
  668. Event.current.Use();
  669. GUIUtility.ExitGUI();
  670. }
  671. break;
  672. case EventType.Repaint:
  673. // Handled in Render()
  674. break;
  675. }
  676. if (m_HoverData != null && (
  677. Event.current.type == EventType.DragExited ||
  678. Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape))
  679. {
  680. DragAndDrop.visualMode = DragAndDropVisualMode.None;
  681. FlushHoverData();
  682. Event.current.Use();
  683. }
  684. }
  685. public void SetTile(Tilemap tilemapTarget, Vector2Int position, TileBase tile, Color color, Matrix4x4 matrix)
  686. {
  687. Vector3Int pos3 = new Vector3Int(position.x, position.y, zPosition);
  688. tilemapTarget.SetTile(pos3, tile);
  689. tilemapTarget.SetColor(pos3, color);
  690. tilemapTarget.SetTransformMatrix(pos3, matrix);
  691. }
  692. protected override void Paint(Vector3Int position)
  693. {
  694. if (gridBrush == null)
  695. return;
  696. gridBrush.Paint(grid, brushTarget, position);
  697. OnPaletteChanged();
  698. }
  699. protected override void Erase(Vector3Int position)
  700. {
  701. if (gridBrush == null)
  702. return;
  703. gridBrush.Erase(grid, brushTarget, position);
  704. OnPaletteChanged();
  705. }
  706. protected override void BoxFill(BoundsInt position)
  707. {
  708. if (gridBrush == null)
  709. return;
  710. gridBrush.BoxFill(grid, brushTarget, position);
  711. OnPaletteChanged();
  712. }
  713. protected override void BoxErase(BoundsInt position)
  714. {
  715. if (gridBrush == null)
  716. return;
  717. gridBrush.BoxErase(grid, brushTarget, position);
  718. OnPaletteChanged();
  719. }
  720. protected override void FloodFill(Vector3Int position)
  721. {
  722. if (gridBrush == null)
  723. return;
  724. gridBrush.FloodFill(grid, brushTarget, position);
  725. OnPaletteChanged();
  726. }
  727. protected override void PickBrush(BoundsInt position, Vector3Int pickingStart)
  728. {
  729. if (grid == null || gridBrush == null)
  730. return;
  731. gridBrush.Pick(grid, brushTarget, position, pickingStart);
  732. if (!InGridEditMode())
  733. TilemapEditorTool.SetActiveEditorTool(typeof(PaintTool));
  734. m_ActivePick = new RectInt(position.min.x, position.min.y, position.size.x, position.size.y);
  735. }
  736. protected override void Select(BoundsInt position)
  737. {
  738. if (grid)
  739. {
  740. GridSelection.Select(brushTarget, position);
  741. gridBrush.Select(grid, brushTarget, position);
  742. }
  743. }
  744. protected override void Move(BoundsInt from, BoundsInt to)
  745. {
  746. if (grid)
  747. gridBrush.Move(grid, brushTarget, from, to);
  748. }
  749. protected override void MoveStart(BoundsInt position)
  750. {
  751. if (grid)
  752. gridBrush.MoveStart(grid, brushTarget, position);
  753. }
  754. protected override void MoveEnd(BoundsInt position)
  755. {
  756. if (grid)
  757. {
  758. gridBrush.MoveEnd(grid, brushTarget, position);
  759. OnPaletteChanged();
  760. }
  761. }
  762. protected override bool CustomTool(bool isHotControl, TilemapEditorTool tool, Vector3Int position)
  763. {
  764. var executed = false;
  765. if (grid)
  766. {
  767. executed = tool.HandleTool(isHotControl, grid, brushTarget, position);
  768. if (executed)
  769. OnPaletteChanged();
  770. }
  771. return executed;
  772. }
  773. public override void Repaint()
  774. {
  775. m_Owner.Repaint();
  776. }
  777. protected override void ClearGridSelection()
  778. {
  779. GridSelection.Clear();
  780. }
  781. public override bool isActive => grid != null;
  782. protected override void OnBrushPickStarted()
  783. {
  784. }
  785. protected override void OnBrushPickDragged(BoundsInt position)
  786. {
  787. m_ActivePick = new RectInt(position.min.x, position.min.y, position.size.x, position.size.y);
  788. }
  789. protected override void OnBrushPickCancelled()
  790. {
  791. m_ActivePick = null;
  792. }
  793. private void PingTileAsset(RectInt rect)
  794. {
  795. // Only able to ping asset if only one asset is selected
  796. if (rect.size == Vector2Int.zero && tilemap != null)
  797. {
  798. TileBase tile = tilemap.GetTile(new Vector3Int(rect.xMin, rect.yMin, zPosition));
  799. EditorGUIUtility.PingObject(tile);
  800. Selection.activeObject = tile;
  801. }
  802. }
  803. protected override bool ValidateFloodFillPosition(Vector3Int position)
  804. {
  805. return true;
  806. }
  807. protected override bool PickingIsDefaultTool()
  808. {
  809. return !m_Unlocked;
  810. }
  811. protected override bool CanPickOutsideEditMode()
  812. {
  813. return true;
  814. }
  815. protected override GridLayout.CellLayout CellLayout()
  816. {
  817. if (grid != null)
  818. return grid.cellLayout;
  819. return GridLayout.CellLayout.Rectangle;
  820. }
  821. protected override Vector2Int ScreenToGrid(Vector2 screenPosition)
  822. {
  823. Vector2 local = ScreenToLocal(screenPosition);
  824. Vector3Int result3 = grid.LocalToCell(local);
  825. Vector2Int result = new Vector2Int(result3.x, result3.y);
  826. return result;
  827. }
  828. private void RenderSelectedBrushMarquee()
  829. {
  830. if (!unlocked && m_ActivePick.HasValue)
  831. {
  832. DrawSelectionGizmo(m_ActivePick.Value);
  833. }
  834. }
  835. protected void DrawSelectionGizmo(RectInt rect)
  836. {
  837. if (Event.current.type != EventType.Repaint || !GUI.enabled)
  838. return;
  839. Color color = Color.white;
  840. if (isPicking)
  841. color = Color.cyan;
  842. GridEditorUtility.DrawGridMarquee(grid, new BoundsInt(new Vector3Int(rect.xMin, rect.yMin, 0), new Vector3Int(rect.width, rect.height, 1)), color);
  843. }
  844. private void HandleMouseEnterLeave()
  845. {
  846. if (guiRect.Contains(Event.current.mousePosition))
  847. {
  848. if (m_PreviousMousePosition.HasValue && !guiRect.Contains(m_PreviousMousePosition.Value) || !m_PreviousMousePosition.HasValue)
  849. {
  850. if (GridPaintingState.activeBrushEditor != null)
  851. {
  852. GridPaintingState.activeBrushEditor.OnMouseEnter();
  853. }
  854. }
  855. }
  856. else
  857. {
  858. if (m_PreviousMousePosition.HasValue && guiRect.Contains(m_PreviousMousePosition.Value) && !guiRect.Contains(Event.current.mousePosition))
  859. {
  860. if (GridPaintingState.activeBrushEditor != null)
  861. {
  862. GridPaintingState.activeBrushEditor.OnMouseLeave();
  863. Repaint();
  864. }
  865. }
  866. }
  867. }
  868. private void CallOnSceneGUI()
  869. {
  870. var gridLayout = tilemap != null ? tilemap : grid as GridLayout;
  871. bool hasSelection = GridSelection.active && GridSelection.target == brushTarget;
  872. if (hasSelection)
  873. {
  874. var rect = new RectInt(GridSelection.position.xMin, GridSelection.position.yMin, GridSelection.position.size.x, GridSelection.position.size.y);
  875. BoundsInt brushBounds = new BoundsInt(new Vector3Int(rect.x, rect.y, zPosition), new Vector3Int(rect.width, rect.height, 1));
  876. GridBrushEditorBase.OnSceneGUIInternal(gridLayout, brushTarget, brushBounds, EditTypeToBrushTool(UnityEditor.EditorTools.ToolManager.activeToolType), m_MarqueeStart.HasValue || executing);
  877. }
  878. if (GridPaintingState.activeBrushEditor != null)
  879. {
  880. GridPaintingState.activeBrushEditor.OnSceneGUI(gridLayout, brushTarget);
  881. }
  882. }
  883. private void CallOnPaintSceneGUI(Vector2Int position)
  884. {
  885. if (!unlocked && !TilemapEditorTool.IsActive(typeof(SelectTool)) && !TilemapEditorTool.IsActive(typeof(PickingTool)))
  886. return;
  887. bool hasSelection = GridSelection.active && GridSelection.target == brushTarget;
  888. if (!hasSelection && GridPaintingState.activeGrid != this)
  889. return;
  890. GridBrushBase brush = GridPaintingState.gridBrush;
  891. if (brush == null)
  892. return;
  893. var rect = new RectInt(position, new Vector2Int(1, 1));
  894. if (m_MarqueeStart.HasValue)
  895. rect = GridEditorUtility.GetMarqueeRect(position, m_MarqueeStart.Value);
  896. else if (hasSelection)
  897. rect = new RectInt(GridSelection.position.xMin, GridSelection.position.yMin, GridSelection.position.size.x, GridSelection.position.size.y);
  898. var gridLayout = tilemap != null ? tilemap.layoutGrid : grid as GridLayout;
  899. BoundsInt brushBounds = new BoundsInt(new Vector3Int(rect.x, rect.y, zPosition), new Vector3Int(rect.width, rect.height, 1));
  900. if (GridPaintingState.activeBrushEditor != null)
  901. GridPaintingState.activeBrushEditor.OnPaintSceneGUI(gridLayout, brushTarget, brushBounds,
  902. EditTypeToBrushTool(UnityEditor.EditorTools.ToolManager.activeToolType),
  903. m_MarqueeStart.HasValue || executing);
  904. else // Fallback when user hasn't defined custom editor
  905. GridBrushEditorBase.OnPaintSceneGUIInternal(gridLayout, Selection.activeGameObject, brushBounds,
  906. EditTypeToBrushTool(UnityEditor.EditorTools.ToolManager.activeToolType),
  907. m_MarqueeStart.HasValue || executing);
  908. }
  909. protected override void RegisterUndo()
  910. {
  911. if (!invalidClipboard)
  912. {
  913. Undo.RegisterFullObjectHierarchyUndo(paletteInstance, "Edit Palette");
  914. }
  915. }
  916. private void OnPaletteChanged()
  917. {
  918. m_PaletteUsed = true;
  919. m_PaletteNeedsSave = true;
  920. Undo.FlushUndoRecordObjects();
  921. }
  922. public void CheckRevertIfChanged(string[] paths)
  923. {
  924. if (paths != null && m_PaletteNeedsSave && palette != null)
  925. {
  926. var currentPalettePath = AssetDatabase.GetAssetPath(palette);
  927. foreach (var path in paths)
  928. {
  929. if (currentPalettePath == path)
  930. {
  931. m_PaletteNeedsSave = false;
  932. ResetPreviewInstance();
  933. Debug.LogWarningFormat(palette, paletteSavedOutsideClipboard, palette.name);
  934. break;
  935. }
  936. }
  937. }
  938. }
  939. public void SavePaletteIfNecessary()
  940. {
  941. if (m_PaletteNeedsSave)
  942. {
  943. m_Owner.SavePalette();
  944. m_PaletteNeedsSave = false;
  945. }
  946. }
  947. public Vector2 GridToScreen(Vector2 gridPosition)
  948. {
  949. Vector3 gridPosition3 = new Vector3(gridPosition.x, gridPosition.y, 0);
  950. return LocalToScreen(grid.CellToLocalInterpolated(gridPosition3));
  951. }
  952. public Vector2 ScreenToLocal(Vector2 screenPosition)
  953. {
  954. Vector2 viewPosition = previewUtility.camera.transform.position;
  955. screenPosition -= new Vector2(guiRect.xMin, guiRect.yMin);
  956. Vector2 offsetFromCenter = new Vector2(screenPosition.x - guiRect.width * .5f, guiRect.height * .5f - screenPosition.y);
  957. return viewPosition + offsetFromCenter / LocalToScreenRatio();
  958. }
  959. protected Vector2 LocalToScreen(Vector2 localPosition)
  960. {
  961. Vector2 viewPosition = previewUtility.camera.transform.position;
  962. Vector2 offsetFromCenter = new Vector2(localPosition.x - viewPosition.x, viewPosition.y - localPosition.y);
  963. return offsetFromCenter * LocalToScreenRatio() + new Vector2(guiRect.width * .5f + guiRect.xMin, guiRect.height * .5f + guiRect.yMin);
  964. }
  965. private float LocalToScreenRatio()
  966. {
  967. return guiRect.height / (previewUtility.camera.orthographicSize * 2f);
  968. }
  969. private float LocalToScreenRatio(float viewHeight)
  970. {
  971. return viewHeight / (previewUtility.camera.orthographicSize * 2f);
  972. }
  973. private static bool TilemapIsEmpty(Tilemap tilemap)
  974. {
  975. return tilemap.GetUsedTilesCount() == 0;
  976. }
  977. public void UnlockAndEdit()
  978. {
  979. unlocked = true;
  980. m_PaletteNeedsSave = true;
  981. }
  982. }
  983. }