暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

GridPaintPaletteClipboard.cs 62KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEditor.EditorTools;
  4. using UnityEngine;
  5. using UnityEngine.Tilemaps;
  6. using UnityEngine.UIElements;
  7. using Event = UnityEngine.Event;
  8. namespace UnityEditor.Tilemaps
  9. {
  10. [Serializable]
  11. internal class GridPaintPaletteClipboard : PaintableGrid
  12. {
  13. static class Styles
  14. {
  15. public static readonly GUIContent emptyProjectInfo = EditorGUIUtility.TrTextContent("Create a new palette in the dropdown above.");
  16. public static readonly GUIContent emptyPaletteInfo = EditorGUIUtility.TrTextContent("Drag Tile, Sprite or Sprite Texture assets here.");
  17. public static readonly GUIContent invalidPaletteInfo = EditorGUIUtility.TrTextContent("This is an invalid palette. Did you delete the palette asset?");
  18. public static readonly GUIContent invalidGridInfo = EditorGUIUtility.TrTextContent("The palette has an invalid Grid. Did you add a Grid to the palette asset?");
  19. }
  20. private static List<GridPaintPaletteClipboard> s_Instances;
  21. public static List<GridPaintPaletteClipboard> instances
  22. {
  23. get
  24. {
  25. if (s_Instances == null)
  26. s_Instances = new List<GridPaintPaletteClipboard>();
  27. return s_Instances;
  28. }
  29. }
  30. private bool disableOnBrushPicked;
  31. public event Action onBrushPicked;
  32. 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.");
  33. private bool m_PaletteNeedsSave;
  34. private const float k_ZoomSpeed = 7f;
  35. private const float k_MinZoom = 10f; // How many pixels per cell at minimum
  36. private const float k_MaxZoom = 100f; // How many pixels per cell at maximum
  37. private const float k_Padding = 0.75f; // How many percentages of window size is the empty padding around the palette content
  38. private int m_KeyboardPanningID;
  39. private int m_MousePanningID;
  40. private Vector2 m_MouseZoomInitialPosition;
  41. private float k_KeyboardPanningSpeed = 3.0f;
  42. private Vector3 m_KeyboardPanning;
  43. private Rect m_GUIRect = new Rect(0, 0, 200, 200);
  44. public Rect guiRect
  45. {
  46. get => m_GUIRect;
  47. set
  48. {
  49. if (m_GUIRect == value)
  50. return;
  51. var oldValue = m_GUIRect;
  52. m_GUIRect = value;
  53. OnViewSizeChanged(oldValue, m_GUIRect);
  54. }
  55. }
  56. private VisualElement m_VisualElement;
  57. public bool activeDragAndDrop { get { return DragAndDrop.objectReferences.Length > 0 && guiRect.Contains(Event.current.mousePosition); } }
  58. [SerializeField] private bool m_CameraInitializedToBounds;
  59. [SerializeField] public bool m_CameraPositionSaved;
  60. [SerializeField] public Vector3 m_CameraPosition;
  61. [SerializeField] public float m_CameraOrthographicSize;
  62. [SerializeField] public GridLayout.CellSwizzle m_CameraSwizzleView;
  63. private BoundsInt? m_ActivePick;
  64. private Vector3Int m_ActivePivot;
  65. private Dictionary<Vector2Int, TileDragAndDropHoverData> m_HoverData;
  66. private bool m_Unlocked;
  67. private GameObject palette => GridPaintingState.palette;
  68. private GridBrushBase gridBrush => GridPaintingState.gridBrush;
  69. private PreviewRenderUtility m_PreviewUtility;
  70. internal Vector3 cameraPosition
  71. {
  72. get => m_PreviewUtility.camera.transform.position;
  73. set
  74. {
  75. m_PreviewUtility.camera.transform.position = value;
  76. ClampZoomAndPan();
  77. }
  78. }
  79. internal float cameraSize
  80. {
  81. get => m_PreviewUtility.camera.orthographicSize;
  82. set
  83. {
  84. m_PreviewUtility.camera.orthographicSize = value;
  85. ClampZoomAndPan();
  86. }
  87. }
  88. internal TransparencySortMode cameraTransparencySortMode
  89. {
  90. get => m_PreviewUtility.camera.transparencySortMode;
  91. set => m_PreviewUtility.camera.transparencySortMode = value;
  92. }
  93. internal Vector3 cameraTransparencySortAxis
  94. {
  95. get => m_PreviewUtility.camera.transparencySortAxis;
  96. set => m_PreviewUtility.camera.transparencySortAxis = value;
  97. }
  98. [SerializeField] private GameObject m_PaletteInstance;
  99. internal GameObject paletteInstance
  100. {
  101. get
  102. {
  103. if (m_PaletteInstance == null && palette != null && m_PreviewUtility != null)
  104. ResetPreviewInstance();
  105. return m_PaletteInstance;
  106. }
  107. }
  108. private Tilemap tilemap { get { return paletteInstance != null ? paletteInstance.GetComponentInChildren<Tilemap>() : null; } }
  109. private Grid grid { get { return paletteInstance != null ? paletteInstance.GetComponent<Grid>() : null; } }
  110. private Grid prefabGrid { get { return palette != null ? palette.GetComponent<Grid>() : null; } }
  111. private Mesh m_GridMesh;
  112. private int m_LastGridHash;
  113. private Material m_GridMaterial;
  114. private static readonly Color k_GridColor = Color.white.AlphaMultiplied(0.1f);
  115. private static readonly PrefColor tilePaletteBackgroundColor = new PrefColor("2D/Tile Palette Background"
  116. , 118.0f / 255.0f // Light
  117. , 118.0f / 255.0f
  118. , 118.0f / 255.0f
  119. , 127.0f / 255.0f
  120. , 31.0f / 255.0f // Dark
  121. , 31.0f / 255.0f
  122. , 31.0f / 255.0f
  123. , 127.0f / 255.0f);
  124. private bool m_PaletteUsed; // We mark palette used, when it has been changed in any way during being actively open.
  125. private Vector2? m_PreviousMousePosition;
  126. private bool m_DelayedResetPaletteInstance;
  127. internal void DelayedResetPreviewInstance()
  128. {
  129. m_DelayedResetPaletteInstance = true;
  130. }
  131. public TileBase activeTile
  132. {
  133. get
  134. {
  135. if (m_ActivePick.HasValue && m_ActivePick.Value.size == Vector3Int.one && GridPaintingState.defaultBrush != null && GridPaintingState.defaultBrush.cellCount > 0)
  136. return GridPaintingState.defaultBrush.cells[0].tile;
  137. return null;
  138. }
  139. }
  140. private RectInt bounds
  141. {
  142. get
  143. {
  144. RectInt r = default;
  145. if (tilemap == null || TilemapIsEmpty(tilemap))
  146. return r;
  147. tilemap.CompressBounds();
  148. var origin = tilemap.origin;
  149. var size = tilemap.size;
  150. r = new RectInt(origin.x, origin.y, size.x, size.y);
  151. return r;
  152. }
  153. }
  154. // Max area we are ever showing. Depends on the zoom level and content of palette.
  155. private Rect paddedBounds
  156. {
  157. get
  158. {
  159. var GUIAspect = m_GUIRect.width / m_GUIRect.height;
  160. var orthographicSize = m_PreviewUtility.camera.orthographicSize;
  161. var paddingW = orthographicSize * GUIAspect * k_Padding * 2f;
  162. var paddingH = orthographicSize * k_Padding * 2f;
  163. Bounds localBounds = grid.GetBoundsLocal(
  164. new Vector3(bounds.xMin, bounds.yMin, 0.0f),
  165. new Vector3(bounds.size.x, bounds.size.y, 0.0f));
  166. Rect result = new Rect(
  167. new Vector2(localBounds.min.x - paddingW, localBounds.min.y - paddingH),
  168. new Vector2(localBounds.size.x + paddingW * 2f, localBounds.size.y + paddingH * 2f));
  169. return result;
  170. }
  171. }
  172. private RectInt paddedBoundsInt
  173. {
  174. get
  175. {
  176. var min = Vector3Int.FloorToInt(paddedBounds.min);
  177. var max = Vector3Int.CeilToInt(paddedBounds.max);
  178. return new RectInt(min.x, min.y, max.x - min.x, max.y - min.y);
  179. }
  180. }
  181. private GameObject brushTarget
  182. {
  183. get
  184. {
  185. return (tilemap != null) ? tilemap.gameObject : (grid != null) ? grid.gameObject : null;
  186. }
  187. }
  188. public bool unlocked
  189. {
  190. get { return m_Unlocked; }
  191. set
  192. {
  193. if (value == false && m_Unlocked)
  194. {
  195. if (tilemap != null)
  196. tilemap.ClearAllEditorPreviewTiles();
  197. SavePaletteIfNecessary();
  198. }
  199. m_Unlocked = value;
  200. unlockedChanged?.Invoke(m_Unlocked);
  201. }
  202. }
  203. public event Action<bool> unlockedChanged;
  204. public bool isReceivingDragAndDrop { get { return m_HoverData != null && m_HoverData.Count > 0; } }
  205. public bool showNewEmptyClipboardInfo
  206. {
  207. get
  208. {
  209. if (paletteInstance == null)
  210. return false;
  211. if (tilemap == null)
  212. return false;
  213. if (unlocked && inEditMode)
  214. return false;
  215. if (!TilemapIsEmpty(tilemap))
  216. return false;
  217. if (tilemap.transform.childCount > 0)
  218. return false;
  219. if (isReceivingDragAndDrop)
  220. return false;
  221. // If user happens to erase the last content of used palette, we don't want to show the new palette info anymore
  222. if (m_PaletteUsed)
  223. return false;
  224. return true;
  225. }
  226. }
  227. public bool isModified { get { return m_PaletteNeedsSave; } }
  228. public VisualElement attachedVisualElement
  229. {
  230. set { m_VisualElement = value; }
  231. }
  232. public void OnBeforePaletteSelectionChanged()
  233. {
  234. SavePaletteIfNecessary();
  235. DestroyPreviewInstance();
  236. FlushHoverData();
  237. }
  238. private void FlushHoverData()
  239. {
  240. if (m_HoverData != null)
  241. {
  242. m_HoverData.Clear();
  243. m_HoverData = null;
  244. }
  245. }
  246. public void OnAfterPaletteSelectionChanged()
  247. {
  248. m_PaletteUsed = false;
  249. ResetPreviewInstance();
  250. if (palette != null)
  251. ResetPreviewCamera();
  252. }
  253. public void SetupPreviewCameraOnInit()
  254. {
  255. if (m_CameraPositionSaved)
  256. LoadSavedCameraPosition();
  257. else
  258. ResetPreviewCamera();
  259. }
  260. private void LoadSavedCameraPosition()
  261. {
  262. m_PreviewUtility.camera.transform.position = m_CameraPosition;
  263. m_PreviewUtility.camera.orthographicSize = m_CameraOrthographicSize;
  264. m_PreviewUtility.camera.nearClipPlane = 0.01f;
  265. m_PreviewUtility.camera.farClipPlane = 100f;
  266. }
  267. private Vector3 GetCameraPositionFromXYZ(Vector3 xyzPosition)
  268. {
  269. var position = Grid.Swizzle(m_CameraSwizzleView, xyzPosition);
  270. position = GetCameraPosition(position);
  271. return position;
  272. }
  273. private Vector3 GetCameraPosition(Vector3 xyzPosition)
  274. {
  275. var position = xyzPosition;
  276. switch (m_CameraSwizzleView)
  277. {
  278. case GridLayout.CellSwizzle.XZY:
  279. {
  280. position.y = 10f;
  281. }
  282. break;
  283. case GridLayout.CellSwizzle.YZX:
  284. {
  285. position.y = -10f;
  286. }
  287. break;
  288. case GridLayout.CellSwizzle.ZYX:
  289. {
  290. position.x = 10f;
  291. }
  292. break;
  293. case GridLayout.CellSwizzle.ZXY:
  294. {
  295. position.x = -10f;
  296. }
  297. break;
  298. case GridLayout.CellSwizzle.YXZ:
  299. {
  300. position.z = 10f;
  301. }
  302. break;
  303. case GridLayout.CellSwizzle.XYZ:
  304. default:
  305. {
  306. position.z = -10f;
  307. }
  308. break;
  309. }
  310. return position;
  311. }
  312. private void ResetPreviewCamera()
  313. {
  314. var transform = m_PreviewUtility.camera.transform;
  315. transform.position = GetCameraPositionFromXYZ(Vector3.zero);
  316. switch (m_CameraSwizzleView)
  317. {
  318. case GridLayout.CellSwizzle.XZY:
  319. {
  320. transform.rotation = Quaternion.LookRotation(new Vector3(0, -1, 0), new Vector3(0, 0, 1));
  321. }
  322. break;
  323. case GridLayout.CellSwizzle.YZX:
  324. {
  325. transform.rotation = Quaternion.LookRotation(new Vector3(0, 1, 0), new Vector3(1, 0, 0));
  326. }
  327. break;
  328. case GridLayout.CellSwizzle.ZXY:
  329. {
  330. transform.rotation = Quaternion.LookRotation(new Vector3(1, 0, 0), new Vector3(0, 0, 1));
  331. }
  332. break;
  333. case GridLayout.CellSwizzle.ZYX:
  334. {
  335. transform.rotation = Quaternion.LookRotation(new Vector3(-1, 0, 0), new Vector3(0, 1, 0));
  336. }
  337. break;
  338. case GridLayout.CellSwizzle.YXZ:
  339. {
  340. transform.rotation = Quaternion.LookRotation(new Vector3(0, 0, -1), new Vector3(1, 0, 0));
  341. }
  342. break;
  343. case GridLayout.CellSwizzle.XYZ:
  344. default:
  345. {
  346. transform.rotation = Quaternion.identity;
  347. }
  348. break;
  349. }
  350. m_PreviewUtility.camera.nearClipPlane = 0.01f;
  351. m_PreviewUtility.camera.farClipPlane = 100f;
  352. FrameEntirePalette();
  353. }
  354. public void InitPreviewUtility()
  355. {
  356. m_PreviewUtility = new PreviewRenderUtility(true, true);
  357. m_PreviewUtility.camera.orthographic = true;
  358. m_PreviewUtility.camera.orthographicSize = 5f;
  359. m_PreviewUtility.camera.transform.position = new Vector3(0f, 0f, -10f);
  360. m_PreviewUtility.ambientColor = new Color(1f, 1f, 1f, 0);
  361. }
  362. public void ResetPreviewInstance()
  363. {
  364. // Store GridSelection for current Palette Instance
  365. Stack<int> childPositions = null;
  366. BoundsInt previousGridSelectionPosition = default;
  367. if (m_PaletteInstance != null && GridSelection.active && GridSelection.target.transform.IsChildOf(m_PaletteInstance.transform))
  368. {
  369. childPositions = new Stack<int>();
  370. var transform = GridSelection.target.transform;
  371. while (transform != null && transform != m_PaletteInstance.transform)
  372. {
  373. childPositions.Push(transform.GetSiblingIndex());
  374. transform = transform.parent;
  375. }
  376. previousGridSelectionPosition = GridSelection.position;
  377. ClearGridSelection();
  378. }
  379. DestroyPreviewInstance();
  380. if (palette != null)
  381. {
  382. m_PaletteInstance = m_PreviewUtility.InstantiatePrefabInScene(palette);
  383. // Disconnecting prefabs is no longer possible.
  384. // If performance of overrides on palette palette instance turns out to be a problem.
  385. // unpack the prefab instance here, and overwrite the prefab later instead of reconnecting.
  386. PrefabUtility.UnpackPrefabInstance(m_PaletteInstance, PrefabUnpackMode.OutermostRoot, InteractionMode.AutomatedAction);
  387. EditorUtility.InitInstantiatedPreviewRecursive(m_PaletteInstance);
  388. m_PaletteInstance.transform.position = new Vector3(0, 0, 0);
  389. m_PaletteInstance.transform.rotation = Quaternion.identity;
  390. m_PaletteInstance.transform.localScale = Vector3.one;
  391. var paletteAsset = GridPaletteUtility.GetGridPaletteFromPaletteAsset(palette);
  392. if (paletteAsset != null)
  393. {
  394. // Handle Cell Sizing for Palette
  395. if (paletteAsset.cellSizing == GridPalette.CellSizing.Automatic)
  396. {
  397. var paletteGrid = m_PaletteInstance.GetComponent<Grid>();
  398. if (paletteGrid != null)
  399. {
  400. paletteGrid.cellSize = GridPaletteUtility.CalculateAutoCellSize(paletteGrid, paletteGrid.cellSize);
  401. }
  402. else
  403. {
  404. Debug.LogWarning("Grid component not found from: " + palette.name);
  405. }
  406. }
  407. // Handle Transparency Sort Settings
  408. m_PreviewUtility.camera.transparencySortMode = paletteAsset.transparencySortMode;
  409. m_PreviewUtility.camera.transparencySortAxis = paletteAsset.transparencySortAxis;
  410. // Handle Camera View for Grid
  411. m_CameraSwizzleView = GridLayout.CellSwizzle.XYZ;
  412. var instanceGrid = m_PaletteInstance.GetComponent<Grid>();
  413. if (instanceGrid != null)
  414. m_CameraSwizzleView = instanceGrid.cellSwizzle;
  415. }
  416. else
  417. {
  418. Debug.LogWarning("GridPalette subasset not found from: " + palette.name);
  419. m_PreviewUtility.camera.transparencySortMode = TransparencySortMode.Default;
  420. m_PreviewUtility.camera.transparencySortAxis = new Vector3(0f, 0f, 1f);
  421. }
  422. foreach (var transform in m_PaletteInstance.GetComponentsInChildren<Transform>())
  423. transform.gameObject.hideFlags = HideFlags.HideAndDontSave;
  424. // Show all renderers from Palettes from previous versions
  425. PreviewRenderUtility.SetEnabledRecursive(m_PaletteInstance, true);
  426. // Update preview Grid Mesh for new palette instance
  427. ResetPreviewGridMesh();
  428. // Restore GridSelection for new palette instance
  429. if (childPositions != null)
  430. {
  431. var transform = m_PaletteInstance.transform;
  432. while (childPositions.Count > 0)
  433. {
  434. var siblingIndex = childPositions.Pop();
  435. if (siblingIndex < transform.childCount)
  436. transform = transform.GetChild(siblingIndex);
  437. }
  438. GridSelection.Select(transform.gameObject, previousGridSelectionPosition);
  439. }
  440. }
  441. m_DelayedResetPaletteInstance = false;
  442. }
  443. public void DestroyPreviewInstance()
  444. {
  445. if (m_PaletteInstance != null)
  446. {
  447. Undo.ClearUndo(m_PaletteInstance);
  448. if (GridSelection.active && GridSelection.target == tilemap.gameObject)
  449. {
  450. GridSelection.TransferToStandalone(palette);
  451. }
  452. else
  453. {
  454. DestroyImmediate(m_PaletteInstance);
  455. }
  456. m_PaletteInstance = null;
  457. }
  458. }
  459. private void ResetPreviewGridMesh()
  460. {
  461. if (m_GridMesh != null)
  462. {
  463. DestroyImmediate(m_GridMesh);
  464. m_GridMesh = null;
  465. }
  466. m_GridMaterial = null;
  467. }
  468. public void FrameEntirePalette()
  469. {
  470. Frame(bounds);
  471. }
  472. private void Frame(RectInt rect)
  473. {
  474. if (grid == null)
  475. return;
  476. var position = grid.CellToLocalInterpolated(new Vector3(rect.center.x, rect.center.y, 0));
  477. position = GetCameraPosition(position);
  478. var height = (grid.CellToLocal(new Vector3Int(0, rect.yMax, 0)) - grid.CellToLocal(new Vector3Int(0, rect.yMin, 0))).magnitude;
  479. var width = (grid.CellToLocal(new Vector3Int(rect.xMax, 0, 0)) - grid.CellToLocal(new Vector3Int(rect.xMin, 0, 0))).magnitude;
  480. var cellSize = grid.cellSize;
  481. width += cellSize.x;
  482. height += cellSize.y;
  483. var GUIAspect = m_GUIRect.width / m_GUIRect.height;
  484. var contentAspect = width / height;
  485. m_PreviewUtility.camera.transform.position = position;
  486. m_PreviewUtility.camera.orthographicSize = (GUIAspect > contentAspect ? height : width / GUIAspect) / 2f;
  487. ClampZoomAndPan();
  488. }
  489. private void RefreshAllTiles()
  490. {
  491. if (tilemap != null)
  492. tilemap.RefreshAllTiles();
  493. }
  494. protected override void OnEnable()
  495. {
  496. base.OnEnable();
  497. instances.Add(this);
  498. EditorApplication.editorApplicationQuit += EditorApplicationQuit;
  499. PrefabUtility.prefabInstanceUpdated += PrefabInstanceUpdated;
  500. Undo.undoRedoPerformed += UndoRedoPerformed;
  501. m_KeyboardPanningID = GUIUtility.GetPermanentControlID();
  502. m_MousePanningID = GUIUtility.GetPermanentControlID();
  503. InitPreviewUtility();
  504. ResetPreviewInstance();
  505. SetupPreviewCameraOnInit();
  506. }
  507. protected override void OnDisable()
  508. {
  509. SavePaletteIfNecessary();
  510. unlocked = false;
  511. DestroyPreviewInstance();
  512. if (m_PreviewUtility != null && m_PreviewUtility.camera != null)
  513. {
  514. // Save Preview camera coordinates
  515. m_CameraPosition = m_PreviewUtility.camera.transform.position;
  516. m_CameraOrthographicSize = m_PreviewUtility.camera.orthographicSize;
  517. m_CameraPositionSaved = true;
  518. }
  519. if (m_PreviewUtility != null)
  520. m_PreviewUtility.Cleanup();
  521. m_PreviewUtility = null;
  522. Undo.undoRedoPerformed -= UndoRedoPerformed;
  523. PrefabUtility.prefabInstanceUpdated -= PrefabInstanceUpdated;
  524. EditorApplication.editorApplicationQuit -= EditorApplicationQuit;
  525. instances.Remove(this);
  526. base.OnDisable();
  527. }
  528. private void DisplayClipboardText(GUIContent clipboardText, Rect textPosition)
  529. {
  530. Color old = GUI.color;
  531. GUI.color = Color.gray;
  532. var infoSize = GUI.skin.label.CalcSize(clipboardText);
  533. Rect rect = new Rect(textPosition.center.x - infoSize.x * .5f, textPosition.center.y - infoSize.y * .5f, infoSize.x, infoSize.y);
  534. GUI.Label(rect, clipboardText);
  535. GUI.color = old;
  536. }
  537. public void OnClipboardGUI(Rect clipboardPosition)
  538. {
  539. if (Event.current.type != EventType.Layout && clipboardPosition.Contains(Event.current.mousePosition) && GridPaintingState.activeGrid != this && unlocked)
  540. {
  541. GridPaintingState.activeGrid = this;
  542. SceneView.RepaintAll();
  543. }
  544. // Validate palette (case 1017965)
  545. GUIContent paletteError = null;
  546. if (palette == null)
  547. {
  548. if (GridPaintingState.palettes.Count == 0)
  549. paletteError = Styles.emptyProjectInfo;
  550. else
  551. paletteError = Styles.invalidPaletteInfo;
  552. }
  553. else if (palette.GetComponent<Grid>() == null)
  554. {
  555. paletteError = Styles.invalidGridInfo;
  556. }
  557. if (paletteError != null)
  558. {
  559. DisplayClipboardText(paletteError, clipboardPosition);
  560. return;
  561. }
  562. bool oldEnabled = GUI.enabled;
  563. GUI.enabled = !showNewEmptyClipboardInfo || DragAndDrop.objectReferences.Length > 0;
  564. if (Event.current.type == EventType.Repaint)
  565. guiRect = clipboardPosition;
  566. EditorGUI.BeginChangeCheck();
  567. OnGUI();
  568. if (EditorGUI.EndChangeCheck())
  569. Repaint();
  570. GUI.enabled = oldEnabled;
  571. if (showNewEmptyClipboardInfo)
  572. {
  573. DisplayClipboardText(Styles.emptyPaletteInfo, clipboardPosition);
  574. }
  575. }
  576. public override void OnGUI()
  577. {
  578. if (Mathf.Approximately(guiRect.width, 0f) || Mathf.Approximately(guiRect.height, 0f))
  579. return;
  580. UpdateMouseGridPosition();
  581. HandleDragAndDrop();
  582. if (m_DelayedResetPaletteInstance)
  583. {
  584. var originalSwizzleView = m_CameraSwizzleView;
  585. ResetPreviewInstance();
  586. if (palette != null && originalSwizzleView != m_CameraSwizzleView)
  587. ResetPreviewCamera();
  588. }
  589. if (palette == null)
  590. return;
  591. HandlePanAndZoom();
  592. HandleKeyboardMousePick();
  593. if (showNewEmptyClipboardInfo)
  594. return;
  595. if (Event.current.type == EventType.Repaint && !m_CameraInitializedToBounds)
  596. {
  597. Frame(bounds);
  598. m_CameraInitializedToBounds = true;
  599. }
  600. HandleMouseEnterLeave();
  601. if (guiRect.Contains(Event.current.mousePosition) || Event.current.type != EventType.MouseDown)
  602. base.OnGUI();
  603. if (Event.current.type == EventType.Repaint
  604. || (unlocked && (inEditMode || GridSelectionTool.IsActive())))
  605. {
  606. Render();
  607. }
  608. else
  609. {
  610. RenderSelectedBrushMarquee();
  611. CallOnPaintSceneGUI(mouseGridPosition);
  612. }
  613. m_PreviousMousePosition = Event.current.mousePosition;
  614. }
  615. private void OnViewSizeChanged(Rect oldSize, Rect newSize)
  616. {
  617. if (Mathf.Approximately(oldSize.height * oldSize.width * newSize.height * newSize.width, 0f))
  618. return;
  619. Camera cam = m_PreviewUtility.camera;
  620. Vector2 sizeDelta = new Vector2(
  621. newSize.width / LocalToScreenRatio(newSize.height) - oldSize.width / LocalToScreenRatio(oldSize.height),
  622. newSize.height / LocalToScreenRatio(newSize.height) - oldSize.height / LocalToScreenRatio(oldSize.height));
  623. cam.transform.Translate(sizeDelta / 2f);
  624. ClampZoomAndPan();
  625. }
  626. private void EditorApplicationQuit()
  627. {
  628. SavePaletteIfNecessary();
  629. }
  630. private void UndoRedoPerformed()
  631. {
  632. if (!unlocked)
  633. return;
  634. m_PaletteNeedsSave = true;
  635. RefreshAllTiles();
  636. Repaint();
  637. }
  638. private void PrefabInstanceUpdated(GameObject updatedPrefab)
  639. {
  640. // case 947462: Reset the palette instance after its prefab has been updated as it could have been changed
  641. if (m_PaletteInstance != null && PrefabUtility.GetCorrespondingObjectFromSource(updatedPrefab) == palette && !GridPaintingState.savingPalette)
  642. {
  643. m_PaletteNeedsSave = true;
  644. RefreshAllTiles();
  645. Repaint();
  646. }
  647. }
  648. private void HandlePanAndZoom()
  649. {
  650. switch (Event.current.type)
  651. {
  652. case EventType.MouseDown:
  653. if (MousePanningEvent() && guiRect.Contains(Event.current.mousePosition) && GUIUtility.hotControl == 0)
  654. {
  655. GUIUtility.hotControl = m_MousePanningID;
  656. m_MouseZoomInitialPosition = Event.current.mousePosition;
  657. Event.current.Use();
  658. }
  659. break;
  660. case EventType.ValidateCommand:
  661. if (Event.current.commandName == EventCommandNames.FrameSelected)
  662. {
  663. Event.current.Use();
  664. }
  665. break;
  666. case EventType.ExecuteCommand:
  667. if (Event.current.commandName == EventCommandNames.FrameSelected)
  668. {
  669. if (m_ActivePick.HasValue)
  670. {
  671. var rect = new RectInt(m_ActivePick.Value.x, m_ActivePick.Value.y,
  672. m_ActivePick.Value.size.x, m_ActivePick.Value.size.y);
  673. Frame(rect);
  674. }
  675. else
  676. FrameEntirePalette();
  677. Event.current.Use();
  678. }
  679. break;
  680. case EventType.ScrollWheel:
  681. if (guiRect.Contains(Event.current.mousePosition))
  682. {
  683. HandleMouseZoom(Event.current.mousePosition);
  684. Event.current.Use();
  685. }
  686. break;
  687. case EventType.MouseDrag:
  688. if (GUIUtility.hotControl == m_MousePanningID)
  689. {
  690. if (Event.current.alt && Event.current.button == 1)
  691. {
  692. HandleMouseZoom(m_MouseZoomInitialPosition);
  693. }
  694. else
  695. {
  696. Vector3 delta = new Vector3(-Event.current.delta.x, Event.current.delta.y, 0f) / LocalToScreenRatio();
  697. m_PreviewUtility.camera.transform.Translate(delta);
  698. ClampZoomAndPan();
  699. }
  700. Event.current.Use();
  701. }
  702. break;
  703. case EventType.MouseMove: // Fix mouse cursor being stuck when panning ended outside our window
  704. if (GUIUtility.hotControl == m_MousePanningID && !MousePanningEvent())
  705. GUIUtility.hotControl = 0;
  706. break;
  707. case EventType.MouseUp:
  708. if (GUIUtility.hotControl == m_MousePanningID)
  709. {
  710. ClampZoomAndPan();
  711. GUIUtility.hotControl = 0;
  712. Event.current.Use();
  713. }
  714. break;
  715. case EventType.KeyDown:
  716. if ((GUIUtility.hotControl == 0 || GUIUtility.hotControl == m_KeyboardPanningID) && !Event.current.shift)
  717. {
  718. switch (Event.current.keyCode)
  719. {
  720. case KeyCode.LeftArrow:
  721. m_KeyboardPanning.x = -k_KeyboardPanningSpeed / LocalToScreenRatio();
  722. GUIUtility.hotControl = m_KeyboardPanningID;
  723. Event.current.Use();
  724. break;
  725. case KeyCode.RightArrow:
  726. m_KeyboardPanning.x = k_KeyboardPanningSpeed / LocalToScreenRatio();
  727. GUIUtility.hotControl = m_KeyboardPanningID;
  728. Event.current.Use();
  729. break;
  730. case KeyCode.UpArrow:
  731. m_KeyboardPanning.y = k_KeyboardPanningSpeed / LocalToScreenRatio();
  732. GUIUtility.hotControl = m_KeyboardPanningID;
  733. Event.current.Use();
  734. break;
  735. case KeyCode.DownArrow:
  736. m_KeyboardPanning.y = -k_KeyboardPanningSpeed / LocalToScreenRatio();
  737. GUIUtility.hotControl = m_KeyboardPanningID;
  738. Event.current.Use();
  739. break;
  740. }
  741. }
  742. break;
  743. case EventType.KeyUp:
  744. if (GUIUtility.hotControl == m_KeyboardPanningID)
  745. {
  746. m_KeyboardPanning = Vector3.zero;
  747. GUIUtility.hotControl = 0;
  748. Event.current.Use();
  749. }
  750. break;
  751. case EventType.Repaint:
  752. if (GUIUtility.hotControl == m_KeyboardPanningID)
  753. {
  754. m_PreviewUtility.camera.transform.Translate(m_KeyboardPanning);
  755. ClampZoomAndPan();
  756. Repaint();
  757. }
  758. if (GUIUtility.hotControl == m_MousePanningID)
  759. EditorGUIUtility.AddCursorRect(guiRect, MouseCursor.Pan);
  760. break;
  761. }
  762. }
  763. private void HandleMouseZoom(Vector2 currentMousePosition)
  764. {
  765. float zoomDelta = HandleUtility.niceMouseDeltaZoom * (Event.current.shift ? -9 : -3) * k_ZoomSpeed;
  766. Camera camera = m_PreviewUtility.camera;
  767. Vector3 oldLocalPos = ScreenToLocal(currentMousePosition);
  768. camera.orthographicSize = Mathf.Max(.0001f, camera.orthographicSize * (1 + zoomDelta * .001f));
  769. ClampZoomAndPan();
  770. Vector3 newLocalPos = ScreenToLocal(currentMousePosition);
  771. Vector3 localDelta = newLocalPos - oldLocalPos;
  772. camera.transform.position -= localDelta;
  773. ClampZoomAndPan();
  774. }
  775. private void HandleKeyboardMousePick()
  776. {
  777. if (GUIUtility.hotControl == 0 || GUIUtility.hotControl == m_KeyboardPanningID)
  778. {
  779. if (Event.current.type == EventType.KeyDown && Event.current.shift && m_ActivePick.HasValue)
  780. {
  781. var delta = Vector3Int.zero;
  782. switch (Event.current.keyCode)
  783. {
  784. case KeyCode.LeftArrow:
  785. delta = Vector3Int.left;
  786. break;
  787. case KeyCode.RightArrow:
  788. delta = Vector3Int.right;
  789. Event.current.Use();
  790. break;
  791. case KeyCode.UpArrow:
  792. delta = Vector3Int.up;
  793. Event.current.Use();
  794. break;
  795. case KeyCode.DownArrow:
  796. delta = Vector3Int.down;
  797. break;
  798. }
  799. if (delta != Vector3Int.zero)
  800. {
  801. disableOnBrushPicked = true;
  802. PickBrush(new BoundsInt(m_ActivePick.Value.position + delta, m_ActivePick.Value.size),
  803. m_ActivePivot);
  804. disableOnBrushPicked = false;
  805. Event.current.Use();
  806. }
  807. }
  808. }
  809. }
  810. private static bool MousePanningEvent()
  811. {
  812. return (Event.current.button == 0 && Event.current.alt || Event.current.button > 0);
  813. }
  814. private void ClampZoomAndPan()
  815. {
  816. float pixelsPerCell = grid.cellSize.y * LocalToScreenRatio();
  817. if (pixelsPerCell < k_MinZoom)
  818. m_PreviewUtility.camera.orthographicSize = (grid.cellSize.y * guiRect.height) / (k_MinZoom * 2f);
  819. else if (pixelsPerCell > k_MaxZoom)
  820. m_PreviewUtility.camera.orthographicSize = (grid.cellSize.y * guiRect.height) / (k_MaxZoom * 2f);
  821. Camera cam = m_PreviewUtility.camera;
  822. float cameraOrthographicSize = cam.orthographicSize;
  823. Rect r = paddedBounds;
  824. var camPos = cam.transform.position;
  825. var camLimit = Grid.Swizzle(m_CameraSwizzleView, new Vector3(cameraOrthographicSize * (guiRect.width / guiRect.height), cameraOrthographicSize));
  826. var camMin = camPos - camLimit;
  827. var camMax = camPos + camLimit;
  828. var rMin = Grid.Swizzle(m_CameraSwizzleView, r.min);
  829. var rMax = Grid.Swizzle(m_CameraSwizzleView, r.max);
  830. if (m_CameraSwizzleView != GridLayout.CellSwizzle.ZXY && m_CameraSwizzleView != GridLayout.CellSwizzle.ZYX)
  831. {
  832. if (camMin.x < rMin.x)
  833. {
  834. camPos += new Vector3(rMin.x - camMin.x, 0f, 0f);
  835. }
  836. if (camMax.x > rMax.x)
  837. {
  838. camPos += new Vector3(rMax.x - camMax.x, 0f, 0f);
  839. }
  840. }
  841. if (m_CameraSwizzleView != GridLayout.CellSwizzle.XZY && m_CameraSwizzleView != GridLayout.CellSwizzle.YZX)
  842. {
  843. if (camMin.y < rMin.y)
  844. {
  845. camPos += new Vector3(0f, rMin.y - camMin.y, 0f);
  846. }
  847. if (camMax.y > rMax.y)
  848. {
  849. camPos += new Vector3(0f, rMax.y - camMax.y, 0f);
  850. }
  851. }
  852. if (m_CameraSwizzleView != GridLayout.CellSwizzle.XYZ && m_CameraSwizzleView != GridLayout.CellSwizzle.YXZ)
  853. {
  854. if (camMin.z < rMin.z)
  855. {
  856. camPos += new Vector3(0f, 0f, rMin.z - camMin.z);
  857. }
  858. if (camMax.z > rMax.z)
  859. {
  860. camPos += new Vector3(0f, 0f, rMax.z - camMax.z);
  861. }
  862. }
  863. cam.transform.position = camPos;
  864. DestroyImmediate(m_GridMesh);
  865. m_GridMesh = null;
  866. }
  867. private void Render()
  868. {
  869. if (guiRect.width <= 0f || guiRect.height <= 0f)
  870. return;
  871. if (m_GridMesh != null && GetGridHash() != m_LastGridHash)
  872. {
  873. ResetPreviewInstance();
  874. ResetPreviewGridMesh();
  875. }
  876. using (new PreviewInstanceScope(guiRect, m_PreviewUtility, paletteInstance, GridPaintingState.drawGizmos))
  877. {
  878. m_PreviewUtility.Render(true);
  879. if (GridPaintingState.drawGridGizmo)
  880. RenderGrid();
  881. CallOnPaintSceneGUI(mouseGridPosition);
  882. if (GridPaintingState.drawGizmos)
  883. {
  884. // Set CameraType to SceneView to force Gizmos to be drawn
  885. var storedType = m_PreviewUtility.camera.cameraType;
  886. m_PreviewUtility.camera.cameraType = CameraType.SceneView;
  887. Handles.Internal_DoDrawGizmos(m_PreviewUtility.camera);
  888. m_PreviewUtility.camera.cameraType = storedType;
  889. }
  890. }
  891. RenderDragAndDropPreview();
  892. RenderSelectedBrushMarquee();
  893. CallOnSceneGUI();
  894. m_PreviewUtility.EndAndDrawPreview(guiRect);
  895. m_LastGridHash = GetGridHash();
  896. }
  897. private int GetGridHash()
  898. {
  899. var gridToHash = prefabGrid;
  900. if (gridToHash == null)
  901. return 0;
  902. int hash = gridToHash.GetHashCode();
  903. unchecked
  904. {
  905. hash = hash * 33 + gridToHash.cellGap.GetHashCode();
  906. hash = hash * 33 + gridToHash.cellLayout.GetHashCode();
  907. hash = hash * 33 + gridToHash.cellSize.GetHashCode();
  908. hash = hash * 33 + gridToHash.cellSwizzle.GetHashCode();
  909. hash = hash * 33 + SceneViewGridManager.sceneViewGridComponentGizmo.Color.GetHashCode();
  910. }
  911. return hash;
  912. }
  913. private void RenderDragAndDropPreview()
  914. {
  915. if (!activeDragAndDrop || m_HoverData == null || m_HoverData.Count == 0)
  916. return;
  917. var rect = TileDragAndDrop.GetMinMaxRect(m_HoverData.Keys);
  918. rect.position += mouseGridPosition;
  919. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  920. GridEditorUtility.DrawGridMarquee(grid, new BoundsInt(new Vector3Int(rect.xMin, rect.yMin, zPosition), new Vector3Int(rect.width, rect.height, 1)), Color.white);
  921. }
  922. private void RenderGrid()
  923. {
  924. // MeshTopology.Lines doesn't give nice pixel perfect grid so we have to have separate codepath with MeshTopology.Quads specially for palette window here
  925. if (m_GridMesh == null && grid.cellLayout == GridLayout.CellLayout.Rectangle)
  926. {
  927. m_GridMesh = GridEditorUtility.GenerateCachedGridMesh(grid, k_GridColor, 1f / LocalToScreenRatio(), paddedBoundsInt, grid.cellSwizzle == GridLayout.CellSwizzle.XYZ ? MeshTopology.Quads : MeshTopology.Lines);
  928. }
  929. GridEditorUtility.DrawGridGizmo(grid, grid.transform, k_GridColor, ref m_GridMesh, ref m_GridMaterial);
  930. }
  931. private class PreviewInstanceScope : IDisposable
  932. {
  933. private readonly bool m_OldFog;
  934. private readonly bool m_DrawGizmos;
  935. private readonly Transform[] m_PaletteTransforms;
  936. public PreviewInstanceScope(Rect guiRect, PreviewRenderUtility previewRenderUtility, GameObject paletteInstance, bool drawGizmos)
  937. {
  938. m_DrawGizmos = drawGizmos;
  939. m_OldFog = RenderSettings.fog;
  940. previewRenderUtility.BeginPreview(guiRect, null);
  941. // Draw Background here with user preference color
  942. Graphics.DrawTexture(new Rect(0.0f, 0.0f
  943. , (float) 2 * EditorGUIUtility.pixelsPerPoint * guiRect.width
  944. , (float) 2 * EditorGUIUtility.pixelsPerPoint * guiRect.height)
  945. , (Texture) Texture2D.grayTexture, new Rect(0.0f, 0.0f, 1f, 1f)
  946. , 0, 0, 0, 0
  947. , tilePaletteBackgroundColor.Color, (Material) null);
  948. Unsupported.SetRenderSettingsUseFogNoDirty(false);
  949. if (m_DrawGizmos)
  950. {
  951. m_PaletteTransforms = paletteInstance.GetComponentsInChildren<Transform>();
  952. foreach (var transform in m_PaletteTransforms)
  953. transform.gameObject.hideFlags = HideFlags.None;
  954. // Case 1199516: Set Dirty on palette instance to force a refresh on gizmo drawing
  955. EditorUtility.SetDirty(paletteInstance);
  956. Unsupported.SceneTrackerFlushDirty();
  957. }
  958. var renderers = paletteInstance.GetComponentsInChildren<Renderer>();
  959. foreach (var renderer in renderers)
  960. {
  961. renderer.allowOcclusionWhenDynamic = false;
  962. }
  963. previewRenderUtility.AddManagedGO(paletteInstance);
  964. Handles.DrawCameraImpl(guiRect, previewRenderUtility.camera, DrawCameraMode.Textured, false, new DrawGridParameters(), true, false);
  965. }
  966. public void Dispose()
  967. {
  968. if (m_DrawGizmos && m_PaletteTransforms != null)
  969. {
  970. foreach (var transform in m_PaletteTransforms)
  971. transform.gameObject.hideFlags = HideFlags.HideAndDontSave;
  972. }
  973. Unsupported.SetRenderSettingsUseFogNoDirty(m_OldFog);
  974. }
  975. }
  976. private void HandleDragAndDrop()
  977. {
  978. if (DragAndDrop.objectReferences.Length == 0 || !guiRect.Contains(Event.current.mousePosition))
  979. return;
  980. switch (Event.current.type)
  981. {
  982. //TODO: Cache this
  983. case EventType.DragUpdated:
  984. {
  985. List<Texture2D> sheets = TileDragAndDrop.GetValidSpritesheets(DragAndDrop.objectReferences);
  986. List<Sprite> sprites = TileDragAndDrop.GetValidSingleSprites(DragAndDrop.objectReferences);
  987. List<TileBase> tiles = TileDragAndDrop.GetValidTiles(DragAndDrop.objectReferences);
  988. m_HoverData = TileDragAndDrop.CreateHoverData(sheets, sprites, tiles, tilemap.cellLayout);
  989. if (m_HoverData != null && m_HoverData.Count > 0)
  990. {
  991. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  992. Event.current.Use();
  993. GUI.changed = true;
  994. }
  995. }
  996. break;
  997. case EventType.DragPerform:
  998. {
  999. if (m_HoverData == null || m_HoverData.Count == 0)
  1000. return;
  1001. RegisterUndo();
  1002. var wasEmpty = TilemapIsEmpty(tilemap);
  1003. var targetPosition = mouseGridPosition;
  1004. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  1005. var tileSheet = TileDragAndDrop.ConvertToTileSheet(m_HoverData);
  1006. var i = 0;
  1007. foreach (var item in m_HoverData)
  1008. {
  1009. if (i >= tileSheet.Count)
  1010. break;
  1011. var offset = Vector3.zero;
  1012. if (item.Value.hasOffset)
  1013. {
  1014. offset = item.Value.positionOffset - tilemap.tileAnchor;
  1015. var cellSize = tilemap.cellSize;
  1016. if (wasEmpty)
  1017. {
  1018. cellSize = item.Value.scaleFactor;
  1019. }
  1020. offset.x *= cellSize.x;
  1021. offset.y *= cellSize.y;
  1022. offset.z *= cellSize.z;
  1023. }
  1024. SetTile(tilemap
  1025. , targetPosition + item.Key
  1026. , tileSheet[i++]
  1027. , Color.white
  1028. , Matrix4x4.TRS(offset, Quaternion.identity, Vector3.one));
  1029. }
  1030. OnPaletteChanged();
  1031. m_PaletteNeedsSave = true;
  1032. FlushHoverData();
  1033. GUI.changed = true;
  1034. SavePaletteIfNecessary();
  1035. if (wasEmpty)
  1036. {
  1037. ResetPreviewInstance();
  1038. FrameEntirePalette();
  1039. }
  1040. Event.current.Use();
  1041. GUIUtility.ExitGUI();
  1042. }
  1043. break;
  1044. case EventType.Repaint:
  1045. // Handled in Render()
  1046. break;
  1047. }
  1048. if (m_HoverData != null && (
  1049. Event.current.type == EventType.DragExited ||
  1050. Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape))
  1051. {
  1052. DragAndDrop.visualMode = DragAndDropVisualMode.None;
  1053. FlushHoverData();
  1054. Event.current.Use();
  1055. }
  1056. }
  1057. internal void SetTile(Tilemap tilemapTarget, Vector2Int position, TileBase tile, Color color, Matrix4x4 matrix)
  1058. {
  1059. Vector3Int pos3 = new Vector3Int(position.x, position.y, zPosition);
  1060. tilemapTarget.SetTile(pos3, tile);
  1061. tilemapTarget.SetColor(pos3, color);
  1062. tilemapTarget.SetTransformMatrix(pos3, tilemapTarget.GetTransformMatrix(pos3) * matrix);
  1063. }
  1064. protected override void Paint(Vector3Int position)
  1065. {
  1066. if (gridBrush == null)
  1067. return;
  1068. gridBrush.Paint(grid, brushTarget, position);
  1069. OnPaletteChanged();
  1070. }
  1071. protected override void Erase(Vector3Int position)
  1072. {
  1073. if (gridBrush == null)
  1074. return;
  1075. gridBrush.Erase(grid, brushTarget, position);
  1076. OnPaletteChanged();
  1077. }
  1078. protected override void BoxFill(BoundsInt position)
  1079. {
  1080. if (gridBrush == null)
  1081. return;
  1082. gridBrush.BoxFill(grid, brushTarget, position);
  1083. OnPaletteChanged();
  1084. }
  1085. protected override void BoxErase(BoundsInt position)
  1086. {
  1087. if (gridBrush == null)
  1088. return;
  1089. gridBrush.BoxErase(grid, brushTarget, position);
  1090. OnPaletteChanged();
  1091. }
  1092. protected override void FloodFill(Vector3Int position)
  1093. {
  1094. if (gridBrush == null)
  1095. return;
  1096. gridBrush.FloodFill(grid, brushTarget, position);
  1097. OnPaletteChanged();
  1098. }
  1099. protected override void PickBrush(BoundsInt position, Vector3Int pickingStart)
  1100. {
  1101. if (grid == null || gridBrush == null)
  1102. return;
  1103. gridBrush.Pick(grid, brushTarget, position, pickingStart);
  1104. if (!InGridEditMode())
  1105. TilemapEditorTool.SetActiveEditorTool(typeof(PaintTool));
  1106. m_ActivePick = position;
  1107. m_ActivePivot = pickingStart;
  1108. if (!disableOnBrushPicked)
  1109. onBrushPicked?.Invoke();
  1110. }
  1111. protected override void Select(BoundsInt position)
  1112. {
  1113. if (grid)
  1114. {
  1115. GridSelection.Select(brushTarget, position);
  1116. gridBrush.Select(grid, brushTarget, position);
  1117. }
  1118. }
  1119. protected override void Move(BoundsInt from, BoundsInt to)
  1120. {
  1121. if (grid)
  1122. gridBrush.Move(grid, brushTarget, from, to);
  1123. }
  1124. protected override void MoveStart(BoundsInt position)
  1125. {
  1126. if (grid)
  1127. gridBrush.MoveStart(grid, brushTarget, position);
  1128. }
  1129. protected override void MoveEnd(BoundsInt position)
  1130. {
  1131. if (grid)
  1132. {
  1133. gridBrush.MoveEnd(grid, brushTarget, position);
  1134. OnPaletteChanged();
  1135. }
  1136. }
  1137. protected override bool CustomTool(bool isToolHotControl, TilemapEditorTool tool, Vector3Int position)
  1138. {
  1139. var executed = false;
  1140. if (grid)
  1141. {
  1142. executed = tool.HandleTool(isToolHotControl, grid, brushTarget, position);
  1143. if (executed)
  1144. OnPaletteChanged();
  1145. }
  1146. return executed;
  1147. }
  1148. protected override bool IsMouseUpInWindow()
  1149. {
  1150. return Event.current.type == EventType.MouseUp && guiRect.Contains(Event.current.mousePosition);
  1151. }
  1152. public override void Repaint()
  1153. {
  1154. if (m_VisualElement != null)
  1155. m_VisualElement.MarkDirtyRepaint();
  1156. }
  1157. protected override void ClearGridSelection()
  1158. {
  1159. GridSelection.Clear();
  1160. }
  1161. public override bool isActive => grid != null;
  1162. protected override void OnBrushPickStarted()
  1163. {
  1164. }
  1165. protected override void OnBrushPickDragged(BoundsInt position)
  1166. {
  1167. m_ActivePick = position;
  1168. }
  1169. protected override void OnBrushPickCancelled()
  1170. {
  1171. m_ActivePick = null;
  1172. m_ActivePivot = Vector3Int.zero;
  1173. }
  1174. private void PingTileAsset(RectInt rect)
  1175. {
  1176. // Only able to ping asset if only one asset is selected
  1177. if (rect.size == Vector2Int.zero && tilemap != null)
  1178. {
  1179. TileBase tile = tilemap.GetTile(new Vector3Int(rect.xMin, rect.yMin, zPosition));
  1180. EditorGUIUtility.PingObject(tile);
  1181. Selection.activeObject = tile;
  1182. }
  1183. }
  1184. protected override bool ValidateFloodFillPosition(Vector3Int position)
  1185. {
  1186. return true;
  1187. }
  1188. protected override bool PickingIsDefaultTool()
  1189. {
  1190. return !m_Unlocked;
  1191. }
  1192. protected override bool CanPickOutsideEditMode()
  1193. {
  1194. return true;
  1195. }
  1196. protected override GridLayout.CellLayout CellLayout()
  1197. {
  1198. if (grid != null)
  1199. return grid.cellLayout;
  1200. return GridLayout.CellLayout.Rectangle;
  1201. }
  1202. protected override Vector2Int ScreenToGrid(Vector2 screenPosition)
  1203. {
  1204. Vector3 local = ScreenToLocal(screenPosition);
  1205. var localS = Grid.Swizzle(m_CameraSwizzleView, local);
  1206. var result3 = grid.LocalToCell(localS);
  1207. var result = new Vector2Int(result3.x, result3.y);
  1208. return result;
  1209. }
  1210. private void RenderSelectedBrushMarquee()
  1211. {
  1212. if (!activeDragAndDrop && !unlocked && m_ActivePick.HasValue)
  1213. {
  1214. DrawSelectionGizmo(m_ActivePick.Value);
  1215. }
  1216. }
  1217. private void DrawSelectionGizmo(BoundsInt selectionBounds)
  1218. {
  1219. if (Event.current.type != EventType.Repaint || !GUI.enabled)
  1220. return;
  1221. Color color = Color.white;
  1222. if (isPicking)
  1223. color = Color.cyan;
  1224. GridEditorUtility.DrawGridMarquee(grid, new BoundsInt(new Vector3Int(selectionBounds.xMin, selectionBounds.yMin, 0), new Vector3Int(selectionBounds.size.x, selectionBounds.size.y, 1)), color);
  1225. }
  1226. private void HandleMouseEnterLeave()
  1227. {
  1228. if (guiRect.Contains(Event.current.mousePosition))
  1229. {
  1230. if (m_PreviousMousePosition.HasValue && !guiRect.Contains(m_PreviousMousePosition.Value) || !m_PreviousMousePosition.HasValue)
  1231. {
  1232. if (GridPaintingState.activeBrushEditor != null)
  1233. {
  1234. GridPaintingState.activeBrushEditor.OnMouseEnter();
  1235. }
  1236. }
  1237. }
  1238. else
  1239. {
  1240. if (m_PreviousMousePosition.HasValue && guiRect.Contains(m_PreviousMousePosition.Value) && !guiRect.Contains(Event.current.mousePosition))
  1241. {
  1242. if (GridPaintingState.activeBrushEditor != null)
  1243. {
  1244. GridPaintingState.activeBrushEditor.OnMouseLeave();
  1245. Repaint();
  1246. }
  1247. }
  1248. }
  1249. }
  1250. private void CallOnSceneGUI()
  1251. {
  1252. var gridLayout = tilemap != null ? tilemap : grid as GridLayout;
  1253. bool hasSelection = GridSelection.active && GridSelection.target == brushTarget;
  1254. if (hasSelection)
  1255. {
  1256. var rect = new RectInt(GridSelection.position.xMin, GridSelection.position.yMin, GridSelection.position.size.x, GridSelection.position.size.y);
  1257. var brushBounds = new BoundsInt(new Vector3Int(rect.x, rect.y, zPosition), new Vector3Int(rect.width, rect.height, 1));
  1258. GridBrushEditorBase.OnSceneGUIInternal(gridLayout, brushTarget, brushBounds, EditTypeToBrushTool(ToolManager.activeToolType), m_MarqueeStart.HasValue || executing);
  1259. }
  1260. if (GridPaintingState.activeBrushEditor != null)
  1261. {
  1262. GridPaintingState.activeBrushEditor.OnSceneGUI(gridLayout, brushTarget);
  1263. if (hasSelection)
  1264. {
  1265. GridPaintingState.activeBrushEditor.OnSelectionSceneGUI(gridLayout, brushTarget);
  1266. if (GridSelectionTool.IsActive() && unlocked)
  1267. {
  1268. var tool = EditorToolManager.activeTool as GridSelectionTool;
  1269. tool.OnToolGUI();
  1270. }
  1271. }
  1272. }
  1273. }
  1274. private void CallOnPaintSceneGUI(Vector2Int position)
  1275. {
  1276. if (!activeDragAndDrop && !unlocked && !TilemapEditorTool.IsActive(typeof(SelectTool)) && !TilemapEditorTool.IsActive(typeof(PickingTool)))
  1277. return;
  1278. var hasSelection = GridSelection.active && GridSelection.target == brushTarget;
  1279. if (!hasSelection && GridPaintingState.activeGrid != this)
  1280. return;
  1281. var brush = GridPaintingState.gridBrush;
  1282. if (brush == null)
  1283. return;
  1284. var rect = new RectInt(position, new Vector2Int(1, 1));
  1285. if (m_MarqueeStart.HasValue)
  1286. rect = GridEditorUtility.GetMarqueeRect(position, m_MarqueeStart.Value);
  1287. else if (hasSelection)
  1288. rect = new RectInt(GridSelection.position.xMin, GridSelection.position.yMin, GridSelection.position.size.x, GridSelection.position.size.y);
  1289. var gridLayout = tilemap != null ? tilemap.layoutGrid : grid as GridLayout;
  1290. var brushBounds = new BoundsInt(new Vector3Int(rect.x, rect.y, zPosition), new Vector3Int(rect.width, rect.height, 1));
  1291. if (GridPaintingState.activeBrushEditor != null)
  1292. GridPaintingState.activeBrushEditor.OnPaintSceneGUI(gridLayout, brushTarget, brushBounds,
  1293. EditTypeToBrushTool(ToolManager.activeToolType),
  1294. m_MarqueeStart.HasValue || executing);
  1295. else // Fallback when user hasn't defined custom editor
  1296. GridBrushEditorBase.OnPaintSceneGUIInternal(gridLayout, Selection.activeGameObject, brushBounds,
  1297. EditTypeToBrushTool(ToolManager.activeToolType),
  1298. m_MarqueeStart.HasValue || executing);
  1299. }
  1300. protected override void RegisterUndo()
  1301. {
  1302. if (palette != null && paletteInstance != null)
  1303. Undo.RegisterFullObjectHierarchyUndo(paletteInstance, "Edit Palette");
  1304. }
  1305. private void OnPaletteChanged()
  1306. {
  1307. m_PaletteUsed = true;
  1308. m_PaletteNeedsSave = true;
  1309. Undo.FlushUndoRecordObjects();
  1310. }
  1311. public void CheckRevertIfChanged(string[] paths)
  1312. {
  1313. if (paths != null && m_PaletteNeedsSave && palette != null)
  1314. {
  1315. var currentPalettePath = AssetDatabase.GetAssetPath(palette);
  1316. foreach (var path in paths)
  1317. {
  1318. if (currentPalettePath == path)
  1319. {
  1320. m_PaletteNeedsSave = false;
  1321. ResetPreviewInstance();
  1322. Debug.LogWarningFormat(palette, paletteSavedOutsideClipboard, palette.name);
  1323. break;
  1324. }
  1325. }
  1326. }
  1327. }
  1328. public bool SavePaletteIfNecessary()
  1329. {
  1330. bool needsSave = m_PaletteNeedsSave;
  1331. if (needsSave)
  1332. {
  1333. SavePalette();
  1334. m_PaletteNeedsSave = false;
  1335. }
  1336. return needsSave;
  1337. }
  1338. private void SavePalette()
  1339. {
  1340. if (palette != null && paletteInstance != null)
  1341. {
  1342. TilePaletteSaveUtility.SaveTilePalette(palette, paletteInstance);
  1343. ResetPreviewInstance();
  1344. Repaint();
  1345. }
  1346. }
  1347. public Vector2 GridToScreen(Vector2 gridPosition)
  1348. {
  1349. var gridPosition3 = new Vector3(gridPosition.x, gridPosition.y, 0);
  1350. return LocalToScreen(grid.CellToLocalInterpolated(gridPosition3));
  1351. }
  1352. public Vector2 ScreenToLocal(Vector2 screenPosition)
  1353. {
  1354. var viewPosition = m_PreviewUtility.camera.transform.position;
  1355. Vector2 viewXYPosition = Grid.InverseSwizzle(m_CameraSwizzleView, viewPosition);
  1356. screenPosition -= new Vector2(guiRect.xMin, guiRect.yMin);
  1357. var offsetFromCenter = new Vector2(screenPosition.x - guiRect.width * .5f, guiRect.height * .5f - screenPosition.y);
  1358. return viewXYPosition + offsetFromCenter / LocalToScreenRatio();
  1359. }
  1360. protected Vector2 LocalToScreen(Vector2 localPosition)
  1361. {
  1362. var viewPosition = m_PreviewUtility.camera.transform.position;
  1363. Vector2 viewXYPosition = Grid.InverseSwizzle(m_CameraSwizzleView, viewPosition);
  1364. var offsetFromCenter = new Vector2(localPosition.x - viewXYPosition.x, viewXYPosition.y - localPosition.y);
  1365. return offsetFromCenter * LocalToScreenRatio() + new Vector2(guiRect.width * .5f + guiRect.xMin, guiRect.height * .5f + guiRect.yMin);
  1366. }
  1367. private float LocalToScreenRatio()
  1368. {
  1369. return guiRect.height / (m_PreviewUtility.camera.orthographicSize * 2f);
  1370. }
  1371. private float LocalToScreenRatio(float viewHeight)
  1372. {
  1373. return viewHeight / (m_PreviewUtility.camera.orthographicSize * 2f);
  1374. }
  1375. private static bool TilemapIsEmpty(Tilemap tilemap)
  1376. {
  1377. return tilemap.GetUsedTilesCount() == 0;
  1378. }
  1379. public void UnlockAndEdit()
  1380. {
  1381. unlocked = true;
  1382. m_PaletteNeedsSave = true;
  1383. }
  1384. // TODO: Better way of clearing caches than AssetPostprocessor
  1385. public class AssetProcessor : AssetPostprocessor
  1386. {
  1387. public override int GetPostprocessOrder()
  1388. {
  1389. return int.MaxValue;
  1390. }
  1391. private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromPath)
  1392. {
  1393. foreach (var clipboard in instances)
  1394. {
  1395. clipboard.DelayedResetPreviewInstance();
  1396. }
  1397. }
  1398. }
  1399. public class PaletteAssetModificationProcessor : AssetModificationProcessor
  1400. {
  1401. static void OnWillCreateAsset(string assetName)
  1402. {
  1403. SavePalettesIfRequired(null);
  1404. }
  1405. static string[] OnWillSaveAssets(string[] paths)
  1406. {
  1407. SavePalettesIfRequired(paths);
  1408. return paths;
  1409. }
  1410. static void SavePalettesIfRequired(string[] paths)
  1411. {
  1412. if (GridPaintingState.savingPalette)
  1413. return;
  1414. foreach (var clipboard in instances)
  1415. {
  1416. if (clipboard.isModified)
  1417. {
  1418. clipboard.CheckRevertIfChanged(paths);
  1419. clipboard.SavePaletteIfNecessary();
  1420. clipboard.Repaint();
  1421. }
  1422. }
  1423. }
  1424. }
  1425. }
  1426. }