PWBIO.cs 100 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075
  1. /*
  2. Copyright (c) 2020 Omar Duarte
  3. Unauthorized copying of this file, via any medium is strictly prohibited.
  4. Writen by Omar Duarte, 2020.
  5. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  6. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  8. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  9. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  10. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  11. THE SOFTWARE.
  12. */
  13. using System.Linq;
  14. using UnityEngine;
  15. namespace PluginMaster
  16. {
  17. [UnityEditor.InitializeOnLoad]
  18. public static partial class PWBIO
  19. {
  20. #region PWB WINDOWS
  21. public static void CloseAllWindows(bool closeToolbar = true)
  22. {
  23. BrushProperties.CloseWindow();
  24. ToolProperties.CloseWindow();
  25. PrefabPalette.CloseWindow();
  26. if (closeToolbar) PWBToolbar.CloseWindow();
  27. }
  28. #endregion
  29. #region SELECTION
  30. public static void UpdateSelection()
  31. {
  32. if (SelectionManager.topLevelSelection.Length == 0)
  33. {
  34. if (tool == ToolManager.PaintTool.EXTRUDE)
  35. {
  36. _initialExtrudePosition = _extrudeHandlePosition = _selectionSize = Vector3.zero;
  37. _extrudeDirection = Vector3Int.zero;
  38. }
  39. return;
  40. }
  41. if (tool == ToolManager.PaintTool.EXTRUDE)
  42. {
  43. var selectionBounds = ExtrudeManager.settings.space == Space.World
  44. ? BoundsUtils.GetSelectionBounds(SelectionManager.topLevelSelection)
  45. : BoundsUtils.GetSelectionBounds(SelectionManager.topLevelSelection,
  46. ExtrudeManager.settings.rotationAccordingTo == ExtrudeSettings.RotationAccordingTo.FRIST_SELECTED
  47. ? SelectionManager.topLevelSelection.First().transform.rotation
  48. : SelectionManager.topLevelSelection.Last().transform.rotation);
  49. _initialExtrudePosition = _extrudeHandlePosition = selectionBounds.center;
  50. _selectionSize = selectionBounds.size;
  51. _extrudeDirection = Vector3Int.zero;
  52. }
  53. else if (tool == ToolManager.PaintTool.SELECTION)
  54. {
  55. _selectedBoxPointIdx = 10;
  56. _selectionRotation = Quaternion.identity;
  57. _selectionChanged = true;
  58. _editingSelectionHandlePosition = false;
  59. var rotation = GetSelectionRotation();
  60. _selectionBounds = BoundsUtils.GetSelectionBounds(SelectionManager.topLevelSelection, rotation);
  61. _selectionRotation = rotation;
  62. }
  63. }
  64. #endregion
  65. #region UNSAVED CHANGES
  66. private const string UNSAVED_CHANGES_TITLE = "Unsaved Changes";
  67. private const string UNSAVED_CHANGES_MESSAGE = "There are unsaved changes.\nWhat would you like to do?";
  68. private const string UNSAVED_CHANGES_OK = "Save";
  69. private const string UNSAVED_CHANGES_CANCEL = "Don't Save";
  70. private static void DisplaySaveDialog(System.Action Save)
  71. {
  72. if (UnityEditor.EditorUtility.DisplayDialog(UNSAVED_CHANGES_TITLE,
  73. UNSAVED_CHANGES_MESSAGE, UNSAVED_CHANGES_OK, UNSAVED_CHANGES_CANCEL)) Save();
  74. else repaint = true;
  75. }
  76. private static void AskIfWantToSave(ToolManager.ToolState state, System.Action Save)
  77. {
  78. switch (PWBCore.staticData.unsavedChangesAction)
  79. {
  80. case PWBData.UnsavedChangesAction.ASK:
  81. if (state == ToolManager.ToolState.EDIT) DisplaySaveDialog(Save);
  82. break;
  83. case PWBData.UnsavedChangesAction.SAVE:
  84. if (state == ToolManager.ToolState.EDIT) Save();
  85. BrushstrokeManager.ClearBrushstroke();
  86. break;
  87. case PWBData.UnsavedChangesAction.DISCARD:
  88. repaint = true;
  89. return;
  90. }
  91. }
  92. #endregion
  93. #region COMMON
  94. private const float TAU = Mathf.PI * 2;
  95. private static int _controlId;
  96. public static int controlId { set => _controlId = value; }
  97. private static ToolManager.PaintTool tool => ToolManager.tool;
  98. private static UnityEditor.Tool _unityCurrentTool = UnityEditor.Tool.None;
  99. private static Camera _sceneViewCamera = null;
  100. public static bool repaint { get; set; }
  101. static PWBIO()
  102. {
  103. LineData.SetNextId();
  104. SelectionManager.selectionChanged += UpdateSelection;
  105. UnityEditor.Undo.undoRedoPerformed += OnUndoPerformed;
  106. UnityEditor.SceneView.duringSceneGui += DuringSceneGUI;
  107. PaletteManager.OnPaletteChanged += OnPaletteChanged;
  108. PaletteManager.OnBrushSelectionChanged += OnBrushSelectionChanged;
  109. ToolManager.OnToolModeChanged += OnEditModeChanged;
  110. LineInitializeOnLoad();
  111. ShapeInitializeOnLoad();
  112. TilingInitializeOnLoad();
  113. FloorInitializeOnLoad();
  114. WallInitializeOnLoad();
  115. }
  116. private static void OnPaletteChanged()
  117. {
  118. ApplySelectionFilters();
  119. switch (ToolManager.tool)
  120. {
  121. case ToolManager.PaintTool.ERASER:
  122. if (EraserManager.settings.command == ModifierToolSettings.Command.SELECT_PALETTE_PREFABS)
  123. UpdateOctree();
  124. break;
  125. case ToolManager.PaintTool.REPLACER:
  126. if (ReplacerManager.settings.command == ModifierToolSettings.Command.SELECT_PALETTE_PREFABS)
  127. UpdateOctree();
  128. BrushstrokeManager.ClearReplacerDictionary();
  129. break;
  130. case ToolManager.PaintTool.CIRCLE_SELECT:
  131. if (CircleSelectManager.settings.command == ModifierToolSettings.Command.SELECT_PALETTE_PREFABS)
  132. UpdateOctree();
  133. break;
  134. }
  135. }
  136. private static void OnBrushSelectionChanged()
  137. {
  138. switch (ToolManager.tool)
  139. {
  140. case ToolManager.PaintTool.GRAVITY:
  141. InitializeGravityHeight();
  142. break;
  143. case ToolManager.PaintTool.LINE:
  144. ClearLineStroke();
  145. break;
  146. case ToolManager.PaintTool.SHAPE:
  147. ClearShapeStroke();
  148. break;
  149. case ToolManager.PaintTool.TILING:
  150. ClearTilingStroke();
  151. break;
  152. case ToolManager.PaintTool.SELECTION:
  153. ApplySelectionFilters();
  154. break;
  155. case ToolManager.PaintTool.ERASER:
  156. if (EraserManager.settings.command == ModifierToolSettings.Command.SELECT_BRUSH_PREFABS)
  157. UpdateOctree();
  158. break;
  159. case ToolManager.PaintTool.REPLACER:
  160. if (ReplacerManager.settings.command == ModifierToolSettings.Command.SELECT_BRUSH_PREFABS)
  161. UpdateOctree();
  162. BrushstrokeManager.ClearReplacerDictionary();
  163. break;
  164. case ToolManager.PaintTool.CIRCLE_SELECT:
  165. if (CircleSelectManager.settings.command == ModifierToolSettings.Command.SELECT_BRUSH_PREFABS)
  166. UpdateOctree();
  167. break;
  168. case ToolManager.PaintTool.FLOOR:
  169. UpdateFloorSettingsOnBrushChanged();
  170. break;
  171. case ToolManager.PaintTool.WALL:
  172. UpdateWallSettingsOnBrushChanged();
  173. break;
  174. }
  175. }
  176. public static void SaveUnityCurrentTool() => _unityCurrentTool = UnityEditor.Tools.current;
  177. public static bool _wasPickingBrushes = false;
  178. public static void DuringSceneGUI(UnityEditor.SceneView sceneView)
  179. {
  180. if (updateStroke) UnityEditor.SceneView.RepaintAll();
  181. if (sceneView.in2DMode)
  182. {
  183. SnapManager.settings.gridOnZ = true;
  184. PWBToolbar.RepaintWindow();
  185. }
  186. if (repaint)
  187. {
  188. if (tool == ToolManager.PaintTool.SHAPE) BrushstrokeManager.UpdateShapeBrushstroke();
  189. sceneView.Repaint();
  190. repaint = false;
  191. }
  192. GizmosInput();
  193. PaletteInput(sceneView);
  194. _sceneViewCamera = sceneView.camera;
  195. if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape
  196. && (tool == ToolManager.PaintTool.PIN || tool == ToolManager.PaintTool.BRUSH
  197. || tool == ToolManager.PaintTool.GRAVITY || tool == ToolManager.PaintTool.ERASER
  198. || tool == ToolManager.PaintTool.REPLACER || tool == ToolManager.PaintTool.CIRCLE_SELECT
  199. || tool == ToolManager.PaintTool.FLOOR || tool == ToolManager.PaintTool.WALL))
  200. ToolManager.DeselectTool();
  201. var repaintScene = _wasPickingBrushes == PaletteManager.pickingBrushes;
  202. _wasPickingBrushes = PaletteManager.pickingBrushes;
  203. if (PaletteManager.pickingBrushes)
  204. {
  205. UnityEditor.HandleUtility.AddDefaultControl(_controlId);
  206. if (repaintScene) UnityEditor.SceneView.RepaintAll();
  207. if (Event.current.button == 0 && Event.current.type == EventType.MouseDown) Event.current.Use();
  208. return;
  209. }
  210. if (ToolManager.tool != ToolManager.PaintTool.NONE)
  211. {
  212. if (PWBSettings.shortcuts.editModeToggle.Check())
  213. {
  214. switch (tool)
  215. {
  216. case ToolManager.PaintTool.LINE:
  217. case ToolManager.PaintTool.SHAPE:
  218. case ToolManager.PaintTool.TILING:
  219. ToolManager.editMode = !ToolManager.editMode;
  220. _persistentItemWasEdited = false;
  221. ToolProperties.RepainWindow();
  222. break;
  223. default: break;
  224. }
  225. }
  226. if (PaletteManager.selectedBrushIdx == -1 && (tool == ToolManager.PaintTool.PIN
  227. || tool == ToolManager.PaintTool.BRUSH || tool == ToolManager.PaintTool.GRAVITY
  228. || ((tool == ToolManager.PaintTool.LINE || tool == ToolManager.PaintTool.SHAPE
  229. || tool == ToolManager.PaintTool.TILING)
  230. && !ToolManager.editMode)))
  231. {
  232. if (tool == ToolManager.PaintTool.LINE && _lineData != null && _lineData.state != ToolManager.ToolState.NONE)
  233. ResetLineState();
  234. else if (tool == ToolManager.PaintTool.SHAPE
  235. && _shapeData != null && _shapeData.state != ToolManager.ToolState.NONE)
  236. ResetShapeState();
  237. else if (tool == ToolManager.PaintTool.TILING
  238. && _tilingData != null && _tilingData.state != ToolManager.ToolState.NONE)
  239. ResetTilingState();
  240. }
  241. if (Event.current.type == EventType.MouseEnterWindow) _pinned = false;
  242. if (Event.current.type == EventType.MouseMove || Event.current.type == EventType.MouseDrag)
  243. {
  244. sceneView.Focus();
  245. }
  246. else if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.V)
  247. _snapToVertex = true;
  248. else if (Event.current.type == EventType.KeyUp && Event.current.keyCode == KeyCode.V)
  249. _snapToVertex = false;
  250. if (tool == ToolManager.PaintTool.BRUSH || tool == ToolManager.PaintTool.GRAVITY
  251. || tool == ToolManager.PaintTool.ERASER || tool == ToolManager.PaintTool.REPLACER
  252. || tool == ToolManager.PaintTool.CIRCLE_SELECT)
  253. {
  254. var settings = ToolManager.GetSettingsFromTool(tool);
  255. BrushRadiusShortcuts(settings as CircleToolBase);
  256. }
  257. if (PWBCore.staticData.tempCollidersAction == PWBData.TempCollidersAction.CREATE_WITHIN_FRUSTRUM)
  258. PWBCore.CreateTempCollidersWithinFrustum(sceneView.camera);
  259. switch (tool)
  260. {
  261. case ToolManager.PaintTool.PIN:
  262. PinDuringSceneGUI(sceneView);
  263. break;
  264. case ToolManager.PaintTool.BRUSH:
  265. BrushDuringSceneGUI(sceneView);
  266. break;
  267. case ToolManager.PaintTool.GRAVITY:
  268. GravityToolDuringSceneGUI(sceneView);
  269. break;
  270. case ToolManager.PaintTool.LINE:
  271. LineDuringSceneGUI(sceneView);
  272. break;
  273. case ToolManager.PaintTool.SHAPE:
  274. ShapeDuringSceneGUI(sceneView);
  275. break;
  276. case ToolManager.PaintTool.TILING:
  277. TilingDuringSceneGUI(sceneView);
  278. break;
  279. case ToolManager.PaintTool.ERASER:
  280. EraserDuringSceneGUI(sceneView);
  281. break;
  282. case ToolManager.PaintTool.REPLACER:
  283. ReplacerDuringSceneGUI(sceneView);
  284. break;
  285. case ToolManager.PaintTool.SELECTION:
  286. SelectionDuringSceneGUI(sceneView);
  287. break;
  288. case ToolManager.PaintTool.CIRCLE_SELECT:
  289. CircleSelectDuringSceneGUI(sceneView);
  290. break;
  291. case ToolManager.PaintTool.EXTRUDE:
  292. ExtrudeDuringSceneGUI(sceneView);
  293. break;
  294. case ToolManager.PaintTool.MIRROR:
  295. MirrorDuringSceneGUI(sceneView);
  296. break;
  297. case ToolManager.PaintTool.FLOOR:
  298. FloorToolDuringSceneGUI(sceneView);
  299. break;
  300. case ToolManager.PaintTool.WALL:
  301. WallToolDuringSceneGUI(sceneView);
  302. break;
  303. }
  304. if ((tool != ToolManager.PaintTool.EXTRUDE && tool != ToolManager.PaintTool.SELECTION
  305. && tool != ToolManager.PaintTool.MIRROR) && Event.current.type == EventType.Layout
  306. && !ToolManager.editMode)
  307. {
  308. UnityEditor.Tools.current = UnityEditor.Tool.None;
  309. UnityEditor.HandleUtility.AddDefaultControl(_controlId);
  310. }
  311. }
  312. GridDuringSceneGui(sceneView);
  313. }
  314. private static float UpdateRadius(float radius)
  315. => Mathf.Max(radius * (1f + Mathf.Sign(Event.current.delta.y) * 0.05f), 0.05f);
  316. private static Vector3 TangentSpaceToWorld(Vector3 tangent, Vector3 bitangent, Vector2 tangentSpacePos)
  317. => (tangent * tangentSpacePos.x + bitangent * tangentSpacePos.y);
  318. private static void UpdateStrokeDirection(Vector3 hitPoint)
  319. {
  320. var dir = hitPoint - _prevMousePos;
  321. if (dir.sqrMagnitude > 0.3f)
  322. {
  323. _strokeDirection = hitPoint - _prevMousePos;
  324. _prevMousePos = hitPoint;
  325. }
  326. }
  327. public static void ResetUnityCurrentTool() => UnityEditor.Tools.current = _unityCurrentTool;
  328. private static bool MouseDot(out Vector3 point, out Vector3 normal,
  329. PaintOnSurfaceToolSettingsBase.PaintMode mode, bool in2DMode,
  330. bool paintOnPalettePrefabs, bool castOnMeshesWithoutCollider, bool snapOnGrid)
  331. {
  332. point = Vector3.zero;
  333. normal = Vector3.up;
  334. var mousePos = Event.current.mousePosition;
  335. if (mousePos.x < 0 || mousePos.x >= Screen.width || mousePos.y < 0 || mousePos.y >= Screen.height) return false;
  336. var mouseRay = UnityEditor.HandleUtility.GUIPointToWorldRay(mousePos);
  337. Vector3 SnapPoint(Vector3 hitPoint, ref Vector3 snapNormal)
  338. {
  339. if (_snapToVertex)
  340. {
  341. if (SnapToVertex(mouseRay, out RaycastHit snappedHit, in2DMode))
  342. {
  343. _snappedToVertex = true;
  344. hitPoint = snappedHit.point;
  345. snapNormal = snappedHit.normal;
  346. }
  347. }
  348. else if (SnapManager.settings.snappingEnabled)
  349. {
  350. hitPoint = SnapPosition(hitPoint, snapOnGrid, true);
  351. mouseRay.origin = hitPoint - mouseRay.direction;
  352. if (Physics.Raycast(mouseRay, out RaycastHit hitInfo)) snapNormal = hitInfo.normal;
  353. else if (MeshUtils.Raycast(mouseRay, out RaycastHit meshHitInfo, out GameObject c,
  354. octree.GetNearby(mouseRay, 1).Where(o => o != null).ToArray(),
  355. float.MaxValue)) snapNormal = meshHitInfo.normal;
  356. }
  357. return hitPoint;
  358. }
  359. RaycastHit surfaceHit;
  360. bool surfaceFound = MouseRaycast(mouseRay, out surfaceHit, out GameObject collider,
  361. float.MaxValue, -1, paintOnPalettePrefabs, castOnMeshesWithoutCollider);
  362. if (mode != PaintOnSurfaceToolSettingsBase.PaintMode.ON_SHAPE && surfaceFound)
  363. {
  364. normal = surfaceHit.normal;
  365. point = SnapPoint(surfaceHit.point, ref normal);
  366. return true;
  367. }
  368. if (mode != PaintOnSurfaceToolSettingsBase.PaintMode.ON_SURFACE)
  369. {
  370. if (surfaceFound)
  371. {
  372. point = SnapPoint(surfaceHit.point, ref normal);
  373. var direction = SnapManager.settings.rotation * Vector3.down;
  374. var ray = new Ray(point - direction, direction);
  375. if (MouseRaycast(ray, out RaycastHit hitInfo, out collider, float.MaxValue, -1,
  376. paintOnPalettePrefabs, castOnMeshesWithoutCollider)) point = hitInfo.point;
  377. UpdateGridOrigin(point);
  378. return true;
  379. }
  380. if (GridRaycast(mouseRay, out RaycastHit gridHit))
  381. {
  382. point = SnapPoint(gridHit.point, ref normal);
  383. return true;
  384. }
  385. }
  386. return false;
  387. }
  388. private static bool _updateStroke = false;
  389. public static bool updateStroke { get => _updateStroke; set => _updateStroke = value; }
  390. public static void UpdateStroke() => updateStroke = true;
  391. public static void UpdateSelectedPersistentObject()
  392. {
  393. BrushstrokeManager.UpdateBrushstroke(false);
  394. switch (tool)
  395. {
  396. case ToolManager.PaintTool.LINE:
  397. if (_selectedPersistentLineData != null) _editingPersistentLine = true;
  398. break;
  399. case ToolManager.PaintTool.SHAPE:
  400. if (_selectedPersistentShapeData != null) _editingPersistentShape = true;
  401. break;
  402. case ToolManager.PaintTool.TILING:
  403. if (_selectedPersistentTilingData != null) _editingPersistentTiling = true;
  404. break;
  405. }
  406. repaint = true;
  407. }
  408. public static int selectedPointIdx
  409. {
  410. get
  411. {
  412. switch (ToolManager.tool)
  413. {
  414. case ToolManager.PaintTool.TILING:
  415. if (ToolManager.editMode)
  416. {
  417. if (_selectedPersistentTilingData == null) return -1;
  418. return _selectedPersistentTilingData.selectedPointIdx;
  419. }
  420. else if (_tilingData.state == ToolManager.ToolState.EDIT) return _tilingData.selectedPointIdx;
  421. break;
  422. case ToolManager.PaintTool.LINE:
  423. if (ToolManager.editMode)
  424. {
  425. if (_selectedPersistentLineData == null) return -1;
  426. return _selectedPersistentLineData.selectedPointIdx;
  427. }
  428. else if (_lineData.state == ToolManager.ToolState.EDIT) return _lineData.selectedPointIdx;
  429. break;
  430. case ToolManager.PaintTool.SHAPE:
  431. if (ToolManager.editMode)
  432. {
  433. if (_selectedPersistentShapeData == null) return -1;
  434. return _selectedPersistentShapeData.selectedPointIdx;
  435. }
  436. else if (_shapeData.state == ToolManager.ToolState.EDIT) return _shapeData.selectedPointIdx;
  437. break;
  438. }
  439. return -1;
  440. }
  441. }
  442. private static bool _updateHandlePosition = false;
  443. private static Vector3 _handlePosition;
  444. public static void UpdateHandlePosition()
  445. {
  446. _updateHandlePosition = true;
  447. if (tool == ToolManager.PaintTool.TILING && tilingData != null) ApplyTilingHandlePosition(tilingData);
  448. BrushstrokeManager.UpdateBrushstroke(false);
  449. }
  450. public static Vector3 handlePosition { get => _handlePosition; set => _handlePosition = value; }
  451. private static bool _updateHandleRotation = false;
  452. private static Quaternion _handleRotation;
  453. public static void UpdateHandleRotation()
  454. {
  455. _updateHandleRotation = true;
  456. BrushstrokeManager.UpdateBrushstroke(false);
  457. }
  458. public static Quaternion handleRotation { get => _handleRotation; set => _handleRotation = value; }
  459. private static void DrawCircleTool(Vector3 center, Camera camera, Color color, float radius)
  460. {
  461. const float polygonSideSize = 0.3f;
  462. const int minPolygonSides = 8;
  463. const int maxPolygonSides = 60;
  464. var polygonSides = Mathf.Clamp((int)(TAU * radius / polygonSideSize),
  465. minPolygonSides, maxPolygonSides);
  466. var periPoints = new System.Collections.Generic.List<Vector3>();
  467. for (int i = 0; i < polygonSides; ++i)
  468. {
  469. var radians = TAU * i / (polygonSides - 1f);
  470. var tangentDir = new Vector2(Mathf.Cos(radians), Mathf.Sin(radians));
  471. var worldDir = TangentSpaceToWorld(camera.transform.right, camera.transform.up, tangentDir);
  472. periPoints.Add(center + (worldDir * radius));
  473. }
  474. UnityEditor.Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
  475. UnityEditor.Handles.color = new Color(1f, 1f, 1f, 1f);
  476. UnityEditor.Handles.DrawAAPolyLine(5, periPoints.ToArray());
  477. UnityEditor.Handles.color = color;
  478. UnityEditor.Handles.DrawAAPolyLine(5, periPoints.ToArray());
  479. }
  480. private static void GetCircleToolTargets(Ray mouseRay, Camera camera, ISelectionBrushTool selectionBrushTool,
  481. float radius, System.Collections.Generic.HashSet<GameObject> targets)
  482. {
  483. var nearbyObjects = octree.GetNearby(mouseRay, radius).Where(o => o != null);
  484. targets.Clear();
  485. if (selectionBrushTool.outermostPrefabFilter)
  486. {
  487. foreach (var nearby in nearbyObjects)
  488. {
  489. if (nearby == null) continue;
  490. var outermost = UnityEditor.PrefabUtility.GetOutermostPrefabInstanceRoot(nearby);
  491. if (outermost == null) targets.Add(nearby);
  492. else if (!targets.Contains(outermost)) targets.Add(outermost);
  493. }
  494. }
  495. else targets.UnionWith(nearbyObjects);
  496. var toSelect = targets.ToArray();
  497. targets.Clear();
  498. var closestDistSqr = float.MaxValue;
  499. for (int i = 0; i < toSelect.Length; ++i)
  500. {
  501. var obj = toSelect[i];
  502. if (obj == null) continue;
  503. var magnitude = BoundsUtils.GetAverageMagnitude(obj.transform);
  504. if (radius < magnitude / 2) continue;
  505. if (selectionBrushTool.onlyTheClosest)
  506. {
  507. var pos = obj.transform.position;
  508. var distSqr = (pos - camera.transform.position).sqrMagnitude;
  509. if (distSqr < closestDistSqr)
  510. {
  511. closestDistSqr = distSqr;
  512. targets.Clear();
  513. targets.Add(obj);
  514. }
  515. continue;
  516. }
  517. targets.Add(obj);
  518. }
  519. }
  520. #endregion
  521. #region PERSISTENT OBJECTS
  522. public static void OnUndoPerformed()
  523. {
  524. _octree = null;
  525. _boundsOctree = null;
  526. if (tool == ToolManager.PaintTool.LINE && UnityEditor.Undo.GetCurrentGroupName() == LineData.COMMAND_NAME)
  527. {
  528. OnUndoLine();
  529. UpdateStroke();
  530. }
  531. else if (tool == ToolManager.PaintTool.SHAPE && UnityEditor.Undo.GetCurrentGroupName() == ShapeData.COMMAND_NAME)
  532. {
  533. OnUndoShape();
  534. UpdateStroke();
  535. }
  536. else if (tool == ToolManager.PaintTool.TILING && UnityEditor.Undo.GetCurrentGroupName() == TilingData.COMMAND_NAME)
  537. {
  538. OnUndoTiling();
  539. UpdateStroke();
  540. }
  541. if (ToolManager.tool == ToolManager.PaintTool.LINE
  542. || ToolManager.tool == ToolManager.PaintTool.SHAPE
  543. || ToolManager.tool == ToolManager.PaintTool.TILING)
  544. PWBCore.staticData.SaveAndUpdateVersion();
  545. else
  546. {
  547. if (ToolManager.tool == ToolManager.PaintTool.REPLACER) BrushstrokeManager.ClearReplacerDictionary();
  548. BrushstrokeManager.UpdateBrushstroke();
  549. }
  550. UnityEditor.SceneView.RepaintAll();
  551. }
  552. public static void OnToolChange(ToolManager.PaintTool prevTool)
  553. {
  554. switch (prevTool)
  555. {
  556. case ToolManager.PaintTool.LINE:
  557. ResetLineState();
  558. break;
  559. case ToolManager.PaintTool.SHAPE:
  560. ResetShapeState();
  561. break;
  562. case ToolManager.PaintTool.TILING:
  563. ResetTilingState();
  564. break;
  565. case ToolManager.PaintTool.EXTRUDE:
  566. ResetExtrudeState();
  567. break;
  568. case ToolManager.PaintTool.MIRROR:
  569. ResetMirrorState();
  570. break;
  571. default: break;
  572. }
  573. _meshesAndRenderers.Clear();
  574. UnityEditor.SceneView.RepaintAll();
  575. }
  576. private static void OnEditModeChanged()
  577. {
  578. switch (tool)
  579. {
  580. case ToolManager.PaintTool.LINE:
  581. OnLineToolModeChanged();
  582. break;
  583. case ToolManager.PaintTool.SHAPE:
  584. OnShapeToolModeChanged();
  585. break;
  586. case ToolManager.PaintTool.TILING:
  587. OnTilingToolModeChanged();
  588. break;
  589. default: break;
  590. }
  591. }
  592. private static void DeleteDisabledObjects()
  593. {
  594. if (_disabledObjects == null) return;
  595. foreach (var obj in _disabledObjects)
  596. {
  597. if (obj == null) continue;
  598. obj.SetActive(true);
  599. UnityEditor.Undo.DestroyObjectImmediate(obj);
  600. }
  601. }
  602. private static void ResetSelectedPersistentObject<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT, TOOL_DATA, SCENE_DATA>
  603. (PersistentToolManagerBase<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT, TOOL_DATA, SCENE_DATA> manager,
  604. ref bool editingPersistentObject, TOOL_DATA initialPersistentData)
  605. where TOOL_NAME : IToolName, new()
  606. where TOOL_SETTINGS : IToolSettings, new()
  607. where CONTROL_POINT : ControlPoint, new()
  608. where TOOL_DATA : PersistentData<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT>, new()
  609. where SCENE_DATA : SceneData<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT, TOOL_DATA>, new()
  610. {
  611. editingPersistentObject = false;
  612. if (initialPersistentData == null) return;
  613. var selectedItem = manager.GetItem(initialPersistentData.id);
  614. if (selectedItem == null) return;
  615. selectedItem.ResetPoses(initialPersistentData);
  616. selectedItem.ClearSelection();
  617. }
  618. private static void DeselectPersistentItems<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT, TOOL_DATA, SCENE_DATA>
  619. (PersistentToolManagerBase<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT, TOOL_DATA, SCENE_DATA> manager)
  620. where TOOL_NAME : IToolName, new()
  621. where TOOL_SETTINGS : IToolSettings, new()
  622. where CONTROL_POINT : ControlPoint, new()
  623. where TOOL_DATA : PersistentData<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT>, new()
  624. where SCENE_DATA : SceneData<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT, TOOL_DATA>, new()
  625. {
  626. var persitentTilings = manager.GetPersistentItems();
  627. foreach (var i in persitentTilings) i.ClearSelection();
  628. }
  629. private static bool ApplySelectedPersistentObject<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT, TOOL_DATA, SCENE_DATA>
  630. (bool deselectPoint, ref bool editingPersistentObject, ref TOOL_DATA initialPersistentData,
  631. ref TOOL_DATA selectedPersistentData,
  632. PersistentToolManagerBase<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT, TOOL_DATA, SCENE_DATA> manager)
  633. where TOOL_NAME : IToolName, new()
  634. where TOOL_SETTINGS : IToolSettings, new()
  635. where CONTROL_POINT : ControlPoint, new()
  636. where TOOL_DATA : PersistentData<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT>, new()
  637. where SCENE_DATA : SceneData<TOOL_NAME, TOOL_SETTINGS, CONTROL_POINT, TOOL_DATA>, new()
  638. {
  639. editingPersistentObject = false;
  640. if (initialPersistentData == null) return false;
  641. var selected = manager.GetItem(initialPersistentData.id);
  642. if (selected == null)
  643. {
  644. initialPersistentData = null;
  645. selectedPersistentData = null;
  646. return false;
  647. }
  648. selected.UpdatePoses();
  649. if (_paintStroke.Count > 0)
  650. {
  651. var objDic = Paint(selected.settings as IPaintToolSettings, PAINT_CMD, true, true);
  652. foreach (var paintedItem in objDic)
  653. {
  654. var persistentItem = manager.GetItem(paintedItem.Key);
  655. if (persistentItem == null) continue;
  656. persistentItem.AddObjects(paintedItem.Value.ToArray());
  657. }
  658. }
  659. if (deselectPoint)
  660. {
  661. DeselectPersistentItems(manager);
  662. }
  663. DeleteDisabledObjects();
  664. _persistentPreviewData.Clear();
  665. PWBCore.staticData.SaveAndUpdateVersion();
  666. if (!deselectPoint) return true;
  667. var persistentObjects = manager.GetPersistentItems();
  668. foreach (var item in persistentObjects) item.ClearSelection();
  669. return true;
  670. }
  671. static bool _persistentItemWasEdited = false;
  672. public static void DuplicateItem(long itemId)
  673. {
  674. var toolMan = ToolManager.GetCurrentPersistentToolManager();
  675. var clone = toolMan.Duplicate(itemId);
  676. ToolManager.editMode = true;
  677. clone.isSelected = true;
  678. var allItems = toolMan.GetItems();
  679. foreach (var item in allItems)
  680. {
  681. if (item == clone) continue;
  682. item.isSelected = false;
  683. item.ClearSelection();
  684. }
  685. var bounds = clone.GetBounds(1.1f);
  686. UnityEditor.SceneView.lastActiveSceneView.Frame(bounds, false);
  687. if (ToolManager.tool == ToolManager.PaintTool.LINE)
  688. {
  689. LineManager.editModeType = LineManager.EditModeType.LINE_POSE;
  690. PWBIO.SelectLine(clone as LineData);
  691. }
  692. else if (ToolManager.tool == ToolManager.PaintTool.SHAPE) PWBIO.SelectShape(clone as ShapeData);
  693. else if (ToolManager.tool == ToolManager.PaintTool.TILING) PWBIO.SelectTiling(clone as TilingData);
  694. }
  695. public static void PersistentItemContextMenu(UnityEditor.GenericMenu menu,
  696. IPersistentData data, Vector2 mousePosition)
  697. {
  698. void DeleteItem(bool deleteObjects)
  699. {
  700. var toolMan = ToolManager.GetCurrentPersistentToolManager();
  701. toolMan.DeletePersistentItem(data.id, deleteObjects);
  702. UnityEditor.SceneView.RepaintAll();
  703. }
  704. menu.AddItem(new GUIContent("Select parent object ... "
  705. + PWBSettings.shortcuts.editModeSelectParent.combination.ToString()), on: false, () =>
  706. {
  707. var parent = data.GetParent();
  708. if (parent != null) UnityEditor.Selection.activeGameObject = parent;
  709. });
  710. menu.AddItem(new GUIContent("Duplicate ... "
  711. + PWBSettings.shortcuts.editModeDuplicate.combination.ToString()), on: false, () => DuplicateItem(data.id));
  712. menu.AddItem(new GUIContent("Delete item and its children ... "
  713. + PWBSettings.shortcuts.editModeDeleteItemAndItsChildren.combination.ToString()),
  714. on: false, () => DeleteItem(deleteObjects: true));
  715. menu.AddItem(new GUIContent("Delete item but not its children ... "
  716. + PWBSettings.shortcuts.editModeDeleteItemButNotItsChildren.combination.ToString()), on: false,
  717. () => DeleteItem(deleteObjects: false));
  718. menu.AddSeparator(string.Empty);
  719. menu.AddItem(new GUIContent(data.toolName + " properties..."), on: false,
  720. () => ItemPropertiesWindow.ShowItemProperties(data, mousePosition));
  721. }
  722. #endregion
  723. #region OCTREE
  724. private const float MIN_OCTREE_NODE_SIZE = 0.5f;
  725. private static PointOctree<GameObject> _octree = new PointOctree<GameObject>(10, Vector3.zero, MIN_OCTREE_NODE_SIZE);
  726. private static BoundsOctree<GameObject> _boundsOctree = new BoundsOctree<GameObject>(initialWorldSize: 10,
  727. initialWorldPos: Vector3.zero, MIN_OCTREE_NODE_SIZE, MIN_OCTREE_NODE_SIZE);
  728. private static System.Collections.Generic.HashSet<GameObject> _paintedObjects
  729. = new System.Collections.Generic.HashSet<GameObject>();
  730. public static PointOctree<GameObject> octree
  731. {
  732. get
  733. {
  734. if (_octree == null) UpdateOctree();
  735. return _octree;
  736. }
  737. }
  738. public static BoundsOctree<GameObject> boundsOctree
  739. {
  740. get
  741. {
  742. if (_boundsOctree == null) UpdateOctree();
  743. return _boundsOctree;
  744. }
  745. }
  746. public static void UpdateOctree()
  747. {
  748. _octree = new PointOctree<GameObject>(10, Vector3.zero, MIN_OCTREE_NODE_SIZE);
  749. _boundsOctree = new BoundsOctree<GameObject>(initialWorldSize: 10,
  750. initialWorldPos: Vector3.zero, MIN_OCTREE_NODE_SIZE, MIN_OCTREE_NODE_SIZE);
  751. if (PaletteManager.paletteCount == 0) return;
  752. if ((tool == ToolManager.PaintTool.PIN || tool == ToolManager.PaintTool.BRUSH
  753. || tool == ToolManager.PaintTool.GRAVITY) && PaletteManager.selectedBrushIdx < 0) return;
  754. #if UNITY_2022_2_OR_NEWER
  755. var allObjects = GameObject.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
  756. #else
  757. var allObjects = GameObject.FindObjectsOfType<GameObject>();
  758. #endif
  759. _paintedObjects.Clear();
  760. var allPrefabsPaths = new System.Collections.Generic.HashSet<string>();
  761. bool AddPrefabPath(MultibrushItemSettings item)
  762. {
  763. if (item.prefab == null) return false;
  764. var path = UnityEditor.AssetDatabase.GetAssetPath(item.prefab);
  765. if (allPrefabsPaths.Contains(path)) return false;
  766. allPrefabsPaths.Add(path);
  767. return true;
  768. }
  769. if (tool == ToolManager.PaintTool.ERASER || tool == ToolManager.PaintTool.REPLACER
  770. || tool == ToolManager.PaintTool.CIRCLE_SELECT)
  771. {
  772. ISelectionBrushTool SelectionBrushSettings = EraserManager.settings;
  773. if (tool == ToolManager.PaintTool.REPLACER) SelectionBrushSettings = ReplacerManager.settings;
  774. else if (tool == ToolManager.PaintTool.CIRCLE_SELECT) SelectionBrushSettings = CircleSelectManager.settings;
  775. if (SelectionBrushSettings.command == SelectionBrushToolSettings.Command.SELECT_PALETTE_PREFABS)
  776. foreach (var brush in PaletteManager.selectedPalette.brushes)
  777. foreach (var item in brush.items) AddPrefabPath(item);
  778. else if (PaletteManager.selectedBrush != null
  779. && SelectionBrushSettings.command == SelectionBrushToolSettings.Command.SELECT_BRUSH_PREFABS)
  780. foreach (var item in PaletteManager.selectedBrush.items) AddPrefabPath(item);
  781. SelectionManager.UpdateSelection();
  782. bool modifyAll = SelectionBrushSettings.command == SelectionBrushToolSettings.Command.SELECT_ALL;
  783. bool modifyAllButSelected = false;
  784. if (tool == ToolManager.PaintTool.ERASER || tool == ToolManager.PaintTool.REPLACER)
  785. {
  786. IModifierTool modifierSettings = tool == ToolManager.PaintTool.ERASER
  787. ? EraserManager.settings as IModifierTool : ReplacerManager.settings;
  788. modifyAllButSelected = modifierSettings.modifyAllButSelected;
  789. }
  790. foreach (var obj in allObjects)
  791. {
  792. if (!obj.activeInHierarchy) continue;
  793. if (!modifyAll && !UnityEditor.PrefabUtility.IsAnyPrefabInstanceRoot(obj)) continue;
  794. var prefabPath = UnityEditor.PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(obj);
  795. bool isBrush = allPrefabsPaths.Contains(prefabPath);
  796. if (!isBrush && !modifyAll) continue;
  797. if (modifyAllButSelected && SelectionManager.selection.Contains(obj)) continue;
  798. AddPaintedObject(obj);
  799. }
  800. }
  801. else
  802. {
  803. foreach (var brush in PaletteManager.selectedPalette.brushes)
  804. foreach (var item in brush.items) AddPrefabPath(item);
  805. foreach (var obj in allObjects)
  806. {
  807. if (!obj.activeInHierarchy) continue;
  808. if (!UnityEditor.PrefabUtility.IsAnyPrefabInstanceRoot(obj)) continue;
  809. var prefabPath = UnityEditor.PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(obj);
  810. bool isBrush = allPrefabsPaths.Contains(prefabPath);
  811. if (isBrush) AddPaintedObject(obj);
  812. }
  813. }
  814. }
  815. public static void AddPaintedObject(GameObject obj)
  816. {
  817. if (_octree == null) _octree = new PointOctree<GameObject>(10, obj.transform.position, MIN_OCTREE_NODE_SIZE);
  818. _octree.Add(obj, obj.transform.position);
  819. if (_boundsOctree == null) _boundsOctree = new BoundsOctree<GameObject>(initialWorldSize: 10,
  820. initialWorldPos: Vector3.zero, MIN_OCTREE_NODE_SIZE, MIN_OCTREE_NODE_SIZE);
  821. Bounds bounds;
  822. if (ToolManager.tool == ToolManager.PaintTool.FLOOR)
  823. bounds = BoundsUtils.GetBoundsRecursive(obj.transform, SnapManager.settings.rotation);
  824. else bounds = BoundsUtils.GetBoundsRecursive(obj.transform);
  825. _boundsOctree.Add(obj, bounds);
  826. _paintedObjects.Add(obj);
  827. }
  828. public static bool OctreeContains(int objId) => octree.Contains(objId);
  829. #endregion
  830. #region STROKE & PAINT
  831. private const string PWB_OBJ_NAME = "Prefab World Builder";
  832. private static Vector3 _prevMousePos = Vector3.zero;
  833. private static Vector3 _strokeDirection = Vector3.forward;
  834. private static Transform _autoParent = null;
  835. private static System.Collections.Generic.Dictionary<string, Transform> _subParents
  836. = new System.Collections.Generic.Dictionary<string, Transform>();
  837. private static Mesh quadMesh;
  838. private class PaintStrokeItem
  839. {
  840. public readonly GameObject prefab = null;
  841. public readonly Vector3 position = Vector3.zero;
  842. public readonly Quaternion rotation = Quaternion.identity;
  843. public readonly Vector3 scale = Vector3.one;
  844. public readonly int layer = 0;
  845. public readonly bool flipX = false;
  846. public readonly bool flipY = false;
  847. public readonly int index = 0;
  848. private Transform _parent = null;
  849. private string _persistentParentId = string.Empty;
  850. private Transform _surface = null;
  851. public Transform parent { get => _parent; set => _parent = value; }
  852. public string persistentParentId { get => _persistentParentId; set => _persistentParentId = value; }
  853. public Transform surface { get => _surface; set => _surface = value; }
  854. public PaintStrokeItem(GameObject prefab, Vector3 position, Quaternion rotation,
  855. Vector3 scale, int layer, Transform parent, Transform surface, bool flipX, bool flipY, int index = -1)
  856. {
  857. this.prefab = prefab;
  858. this.position = position;
  859. this.rotation = rotation;
  860. this.scale = scale;
  861. this.layer = layer;
  862. this.flipX = flipX;
  863. this.flipY = flipY;
  864. this.index = index;
  865. _parent = parent;
  866. _surface = surface;
  867. }
  868. }
  869. private static System.Collections.Generic.List<PaintStrokeItem> _paintStroke
  870. = new System.Collections.Generic.List<PaintStrokeItem>();
  871. private static void BrushRadiusShortcuts(CircleToolBase settings)
  872. {
  873. if (PWBSettings.shortcuts.brushRadius.Check())
  874. {
  875. var combi = PWBSettings.shortcuts.brushRadius.combination;
  876. var delta = Mathf.Sign(combi.delta);
  877. settings.radius = Mathf.Max(settings.radius * (1f + delta * 0.03f), 0.05f);
  878. if (settings is BrushToolSettings)
  879. {
  880. if (BrushManager.settings.heightType == BrushToolSettings.HeightType.RADIUS)
  881. BrushManager.settings.maxHeightFromCenter = BrushManager.settings.radius;
  882. }
  883. ToolProperties.RepainWindow();
  884. }
  885. }
  886. private static void BrushstrokeMouseEvents(BrushToolBase settings)
  887. {
  888. if (PaletteManager.selectedBrush == null) return;
  889. if (Event.current.button == 0 && !Event.current.alt && Event.current.type == EventType.MouseUp
  890. && PaletteManager.selectedBrush.patternMachine != null
  891. && PaletteManager.selectedBrush.restartPatternForEachStroke)
  892. {
  893. PaletteManager.selectedBrush.patternMachine.Reset();
  894. BrushstrokeManager.UpdateBrushstroke();
  895. }
  896. else if (PWBSettings.shortcuts.brushUpdatebrushstroke.Check())
  897. {
  898. BrushstrokeManager.UpdateBrushstroke();
  899. repaint = true;
  900. }
  901. else if (PWBSettings.shortcuts.brushResetRotation.Check()) _brushAngle = 0;
  902. else if (PWBSettings.shortcuts.brushDensity.Check()
  903. && settings.brushShape != BrushToolBase.BrushShape.POINT)
  904. {
  905. settings.density += (int)Mathf.Sign(PWBSettings.shortcuts.brushDensity.combination.delta);
  906. ToolProperties.RepainWindow();
  907. }
  908. else if (PWBSettings.shortcuts.brushRotate.Check())
  909. _brushAngle -= PWBSettings.shortcuts.brushRotate.combination.delta * 1.8f; //180deg/100px
  910. if (Event.current.button == 1)
  911. {
  912. if (Event.current.type == EventType.MouseDown && (Event.current.control || Event.current.shift))
  913. {
  914. _pinned = true;
  915. _pinMouse = Event.current.mousePosition;
  916. Event.current.Use();
  917. }
  918. else if (Event.current.type == EventType.MouseUp && !Event.current.control && !Event.current.shift)
  919. _pinned = false;
  920. }
  921. if ((Event.current.keyCode == KeyCode.LeftControl || Event.current.keyCode == KeyCode.RightControl
  922. || Event.current.keyCode == KeyCode.RightShift || Event.current.keyCode == KeyCode.LeftShift)
  923. && Event.current.type == EventType.KeyUp) _pinned = false;
  924. }
  925. private struct MeshAndRenderer
  926. {
  927. public Mesh mesh;
  928. public Renderer renderer;
  929. public MeshAndRenderer(Mesh mesh, Renderer renderer)
  930. {
  931. this.mesh = mesh;
  932. this.renderer = renderer;
  933. }
  934. }
  935. private static System.Collections.Generic.Dictionary<int, MeshAndRenderer[]> _meshesAndRenderers
  936. = new System.Collections.Generic.Dictionary<int, MeshAndRenderer[]>();
  937. private static void PreviewBrushItem(GameObject prefab, Matrix4x4 rootToWorld, int layer,
  938. Camera camera, bool redMaterial, bool reverseTriangles, bool flipX, bool flipY)
  939. {
  940. var id = prefab.GetInstanceID();
  941. if (!_meshesAndRenderers.ContainsKey(id))
  942. {
  943. var meshesAndRenderers = new System.Collections.Generic.List<MeshAndRenderer>();
  944. var filters = prefab.GetComponentsInChildren<MeshFilter>();
  945. foreach (var filter in filters)
  946. {
  947. var mesh = filter.sharedMesh;
  948. if (mesh == null) continue;
  949. var renderer = filter.GetComponent<MeshRenderer>();
  950. if (renderer == null) continue;
  951. meshesAndRenderers.Add(new MeshAndRenderer(mesh, renderer));
  952. }
  953. var skinedMeshRenderers = prefab.GetComponentsInChildren<SkinnedMeshRenderer>();
  954. foreach (var renderer in skinedMeshRenderers)
  955. {
  956. var mesh = renderer.sharedMesh;
  957. if (mesh == null) continue;
  958. meshesAndRenderers.Add(new MeshAndRenderer(mesh, renderer));
  959. }
  960. _meshesAndRenderers.Add(id, meshesAndRenderers.ToArray());
  961. }
  962. foreach (var item in _meshesAndRenderers[id])
  963. {
  964. var mesh = item.mesh;
  965. var childToWorld = rootToWorld * item.renderer.transform.localToWorldMatrix;
  966. var matrices = new Matrix4x4[] { childToWorld };
  967. if (!redMaterial)
  968. {
  969. if (item.renderer is SkinnedMeshRenderer)
  970. {
  971. var smr = (SkinnedMeshRenderer)item.renderer;
  972. var rootBone = smr.rootBone;
  973. if (rootBone != null)
  974. {
  975. while (rootBone.parent != null && rootBone.parent != prefab.transform) rootBone = rootBone.parent;
  976. var rotation = rootBone.rotation;
  977. var position = rootBone.position;
  978. position.y = 0f;
  979. var scale = rootBone.localScale;
  980. childToWorld = rootToWorld * Matrix4x4.TRS(position, rotation, scale);
  981. }
  982. }
  983. var materials = item.renderer.sharedMaterials;
  984. if (materials == null && materials.Length > 0 && materials.Length >= mesh.subMeshCount) continue;
  985. for (int subMeshIdx = 0; subMeshIdx < Mathf.Min(mesh.subMeshCount, materials.Length); ++subMeshIdx)
  986. {
  987. var material = materials[subMeshIdx];
  988. if (reverseTriangles)
  989. {
  990. var tempMesh = (Mesh)GameObject.Instantiate(mesh);
  991. tempMesh.SetTriangles(mesh.triangles.Reverse().ToArray(), subMeshIdx);
  992. tempMesh.subMeshCount = mesh.subMeshCount;
  993. int vCount = 0;
  994. for (int i = 0; i < mesh.subMeshCount; ++i)
  995. {
  996. var desc = mesh.GetSubMesh(mesh.subMeshCount - i - 1);
  997. desc.indexStart = vCount;
  998. tempMesh.SetSubMesh(i, desc);
  999. vCount += desc.indexCount;
  1000. }
  1001. material = materials[mesh.subMeshCount - subMeshIdx - 1];
  1002. Graphics.DrawMesh(tempMesh, childToWorld, material, layer, camera, subMeshIdx);
  1003. tempMesh = null;
  1004. }
  1005. else Graphics.DrawMesh(mesh, childToWorld, material, layer, camera, subMeshIdx);
  1006. }
  1007. }
  1008. else
  1009. {
  1010. for (int subMeshIdx = 0; subMeshIdx < mesh.subMeshCount; ++subMeshIdx)
  1011. Graphics.DrawMesh(mesh, childToWorld, transparentRedMaterial, layer, camera, subMeshIdx);
  1012. }
  1013. }
  1014. var SpriteRenderers = prefab.GetComponentsInChildren<SpriteRenderer>()
  1015. .Where(r => r.enabled && r.sprite != null && r.gameObject.activeSelf).ToArray();
  1016. if (SpriteRenderers.Length > 0)
  1017. {
  1018. var bounds = BoundsUtils.GetBoundsRecursive(prefab.transform);
  1019. foreach (var spriteRenderer in SpriteRenderers)
  1020. DrawSprite(spriteRenderer, rootToWorld, camera, bounds, flipX, flipY);
  1021. }
  1022. }
  1023. private static void DrawSprite(SpriteRenderer renderer, Matrix4x4 matrix,
  1024. Camera camera, Bounds objectBounds, bool flipX, bool flipY)
  1025. {
  1026. if (quadMesh == null)
  1027. {
  1028. quadMesh = new Mesh
  1029. {
  1030. vertices = new[] { new Vector3(-.5f, .5f, 0), new Vector3(.5f, .5f, 0),
  1031. new Vector3(-.5f, -.5f, 0), new Vector3(.5f, -.5f, 0) },
  1032. normals = new[] { Vector3.forward, Vector3.forward, Vector3.forward, Vector3.forward },
  1033. triangles = new[] { 0, 2, 3, 3, 1, 0 }
  1034. };
  1035. }
  1036. var minUV = new Vector2(float.MaxValue, float.MaxValue);
  1037. var maxUV = new Vector2(float.MinValue, float.MinValue);
  1038. foreach (var uv in renderer.sprite.uv)
  1039. {
  1040. minUV = Vector2.Min(minUV, uv);
  1041. maxUV = Vector2.Max(maxUV, uv);
  1042. }
  1043. var uvs = new Vector2[] { new Vector2(minUV.x, maxUV.y), new Vector2(maxUV.x, maxUV.y),
  1044. new Vector2(minUV.x, minUV.y), new Vector2(maxUV.x, minUV.y)};
  1045. void ToggleFlip(ref bool flip) => flip = !flip;
  1046. if (renderer.flipX) ToggleFlip(ref flipX);
  1047. if (renderer.flipY) ToggleFlip(ref flipY);
  1048. if (flipX)
  1049. {
  1050. uvs[0].x = maxUV.x;
  1051. uvs[1].x = minUV.x;
  1052. uvs[2].x = maxUV.x;
  1053. uvs[3].x = minUV.x;
  1054. }
  1055. if (flipY)
  1056. {
  1057. uvs[0].y = minUV.y;
  1058. uvs[1].y = minUV.y;
  1059. uvs[2].y = maxUV.y;
  1060. uvs[3].y = maxUV.y;
  1061. }
  1062. quadMesh.uv = uvs;
  1063. var pivotToCenter = (renderer.sprite.rect.size / 2 - renderer.sprite.pivot) / renderer.sprite.pixelsPerUnit;
  1064. if (renderer.flipX) pivotToCenter.x = -pivotToCenter.x;
  1065. if (renderer.flipY) pivotToCenter.y = -pivotToCenter.y;
  1066. var mpb = new MaterialPropertyBlock();
  1067. mpb.SetTexture("_MainTex", renderer.sprite.texture);
  1068. mpb.SetColor("_Color", renderer.color);
  1069. matrix *= Matrix4x4.Translate(pivotToCenter);
  1070. matrix *= renderer.transform.localToWorldMatrix;
  1071. matrix *= Matrix4x4.Scale(new Vector3(
  1072. renderer.sprite.textureRect.width / renderer.sprite.pixelsPerUnit,
  1073. renderer.sprite.textureRect.height / renderer.sprite.pixelsPerUnit, 1));
  1074. Graphics.DrawMesh(quadMesh, matrix, renderer.sharedMaterial, 0, camera, 0, mpb);
  1075. }
  1076. public static bool painting { get; set; }
  1077. private const string PAINT_CMD = "Paint";
  1078. private static System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<(GameObject, int)>>
  1079. Paint(IPaintToolSettings settings, string commandName = PAINT_CMD,
  1080. bool addTempCollider = true, bool persistent = false, string toolObjectId = "")
  1081. {
  1082. painting = true;
  1083. var paintedObjects = new System.Collections.Generic.Dictionary<string,
  1084. System.Collections.Generic.List<(GameObject, int)>>();
  1085. if (_paintStroke.Count == 0)
  1086. {
  1087. if (BrushstrokeManager.brushstroke.Length == 0) BrushstrokeManager.UpdateBrushstroke();
  1088. return paintedObjects;
  1089. }
  1090. foreach (var item in _paintStroke)
  1091. {
  1092. if (item.prefab == null) continue;
  1093. var persistentParentId = persistent ? item.persistentParentId : toolObjectId;
  1094. var type = UnityEditor.PrefabUtility.GetPrefabAssetType(item.prefab);
  1095. GameObject obj = type == UnityEditor.PrefabAssetType.NotAPrefab ? GameObject.Instantiate(item.prefab)
  1096. : (GameObject)UnityEditor.PrefabUtility.InstantiatePrefab
  1097. (UnityEditor.PrefabUtility.IsPartOfPrefabAsset(item.prefab)
  1098. ? item.prefab : UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(item.prefab));
  1099. if (settings.overwritePrefabLayer) obj.layer = settings.layer;
  1100. obj.transform.SetPositionAndRotation(item.position, item.rotation);
  1101. obj.transform.localScale = item.scale;
  1102. var root = UnityEditor.PrefabUtility.GetOutermostPrefabInstanceRoot(obj);
  1103. item.parent = GetParent(settings, item.prefab.name, true, item.surface, persistentParentId);
  1104. if (addTempCollider) PWBCore.AddTempCollider(obj);
  1105. if (!paintedObjects.ContainsKey(persistentParentId))
  1106. paintedObjects.Add(persistentParentId, new System.Collections.Generic.List<(GameObject, int)>());
  1107. paintedObjects[persistentParentId].Add((obj, item.index));
  1108. var spriteRenderers = obj.GetComponentsInChildren<SpriteRenderer>();
  1109. foreach (var spriteRenderer in spriteRenderers)
  1110. {
  1111. var flipX = spriteRenderer.flipX;
  1112. var flipY = spriteRenderer.flipY;
  1113. if (item.flipX) flipX = !flipX;
  1114. if (item.flipY) flipY = !flipY;
  1115. spriteRenderer.flipX = flipX;
  1116. spriteRenderer.flipY = flipY;
  1117. var center = BoundsUtils.GetBoundsRecursive(spriteRenderer.transform,
  1118. spriteRenderer.transform.rotation).center;
  1119. var pivotToCenter = center - spriteRenderer.transform.position;
  1120. var delta = Vector3.zero;
  1121. if (item.flipX) delta.x = pivotToCenter.x * -2;
  1122. if (item.flipY) delta.y = pivotToCenter.y * -2;
  1123. spriteRenderer.transform.position += delta;
  1124. }
  1125. AddPaintedObject(obj);
  1126. UnityEditor.Undo.RegisterCreatedObjectUndo(obj, commandName);
  1127. if (root != null) UnityEditor.Undo.SetTransformParent(root.transform, item.parent, commandName);
  1128. else UnityEditor.Undo.SetTransformParent(obj.transform, item.parent, commandName);
  1129. }
  1130. if (_paintStroke.Count > 0) BrushstrokeManager.UpdateBrushstroke();
  1131. _paintStroke.Clear();
  1132. return paintedObjects;
  1133. }
  1134. public static void ResetAutoParent() => _autoParent = null;
  1135. private const string NO_PALETTE_NAME = "<#PALETTE@>";
  1136. private const string NO_TOOL_NAME = "<#TOOL@>";
  1137. private const string NO_OBJ_ID = "<#ID@>";
  1138. private const string NO_BRUSH_NAME = "<#BRUSH@>";
  1139. private const string NO_PREFAB_NAME = "<#PREFAB@>";
  1140. private const string PARENT_KEY_SEPARATOR = "<#@>";
  1141. public static Transform GetParent(IPaintToolSettings settings, string prefabName,
  1142. bool create, Transform surface, string toolObjectId = "")
  1143. {
  1144. if (!create) return settings.parent;
  1145. if (settings.autoCreateParent)
  1146. {
  1147. var pwbObj = GameObject.Find(PWB_OBJ_NAME);
  1148. if (pwbObj == null) _autoParent = new GameObject(PWB_OBJ_NAME).transform;
  1149. else _autoParent = pwbObj.transform;
  1150. }
  1151. else _autoParent = settings.setSurfaceAsParent ? surface : settings.parent;
  1152. if (!settings.createSubparentPerPalette && !settings.createSubparentPerTool
  1153. && !settings.createSubparentPerBrush && !settings.createSubparentPerPrefab) return _autoParent;
  1154. var _autoParentId = _autoParent == null ? -1 : _autoParent.gameObject.GetInstanceID();
  1155. string GetSubParentKey(int parentId = -1, string palette = NO_PALETTE_NAME,
  1156. string tool = NO_TOOL_NAME, string id = NO_OBJ_ID,
  1157. string brush = NO_BRUSH_NAME, string prefab = NO_PREFAB_NAME)
  1158. => parentId + PARENT_KEY_SEPARATOR + palette + PARENT_KEY_SEPARATOR
  1159. + tool + PARENT_KEY_SEPARATOR + id + PARENT_KEY_SEPARATOR + brush
  1160. + PARENT_KEY_SEPARATOR + prefab;
  1161. string subParentKey = GetSubParentKey(_autoParentId,
  1162. settings.createSubparentPerPalette ? PaletteManager.selectedPalette.name : NO_PALETTE_NAME,
  1163. settings.createSubparentPerTool ? ToolManager.GetToolFromSettings(settings).ToString() : NO_TOOL_NAME,
  1164. string.IsNullOrEmpty(toolObjectId) ? NO_OBJ_ID : toolObjectId,
  1165. settings.createSubparentPerBrush ? PaletteManager.selectedBrush.name : NO_BRUSH_NAME,
  1166. settings.createSubparentPerPrefab ? prefabName : NO_PREFAB_NAME);
  1167. create = !(_subParents.ContainsKey(subParentKey));
  1168. if (!create && _subParents[subParentKey] == null) create = true;
  1169. if (!create) return _subParents[subParentKey];
  1170. Transform CreateSubParent(string key, string name, Transform transformParent)
  1171. {
  1172. Transform subParentTransform = null;
  1173. var subParentIsEmpty = true;
  1174. if (transformParent != null)
  1175. {
  1176. subParentTransform = transformParent.Find(name);
  1177. if (subParentTransform != null)
  1178. subParentIsEmpty = subParentTransform.GetComponents<Component>().Length == 1;
  1179. }
  1180. if (subParentTransform == null || !subParentIsEmpty)
  1181. {
  1182. var obj = new GameObject(name);
  1183. var subParent = obj.transform;
  1184. subParent.SetParent(transformParent);
  1185. subParent.localPosition = Vector3.zero;
  1186. subParent.localRotation = Quaternion.identity;
  1187. subParent.localScale = Vector3.one;
  1188. if (_subParents.ContainsKey(key)) _subParents[key] = subParent;
  1189. else _subParents.Add(key, subParent);
  1190. return subParent;
  1191. }
  1192. return subParentTransform;
  1193. }
  1194. var parent = _autoParent;
  1195. void CreateSubParentIfDoesntExist(string name, string palette = NO_PALETTE_NAME,
  1196. string tool = NO_TOOL_NAME, string id = NO_OBJ_ID, string brush = NO_BRUSH_NAME,
  1197. string prefab = NO_PREFAB_NAME)
  1198. {
  1199. var key = GetSubParentKey(_autoParentId, palette, tool, id, brush, prefab);
  1200. var keyExist = _subParents.ContainsKey(key);
  1201. var subParent = keyExist ? _subParents[key] : null;
  1202. if (subParent != null) parent = subParent;
  1203. if (!keyExist || subParent == null) parent = CreateSubParent(key, name, parent);
  1204. }
  1205. var keySplitted = subParentKey.Split(new string[] { PARENT_KEY_SEPARATOR },
  1206. System.StringSplitOptions.None);
  1207. var keyPlaletteName = keySplitted[1];
  1208. var keyToolName = keySplitted[2];
  1209. var keyToolObjId = keySplitted[3];
  1210. var keyBrushName = keySplitted[4];
  1211. var keyPrefabName = keySplitted[5];
  1212. if (keyPlaletteName != NO_PALETTE_NAME)
  1213. CreateSubParentIfDoesntExist(keyPlaletteName, keyPlaletteName);
  1214. if (keyToolName != NO_TOOL_NAME)
  1215. {
  1216. CreateSubParentIfDoesntExist(keyToolName, keyPlaletteName, keyToolName);
  1217. if (keyToolObjId != NO_OBJ_ID)
  1218. CreateSubParentIfDoesntExist(keyToolObjId, keyPlaletteName, keyToolName, keyToolObjId);
  1219. }
  1220. if (keyBrushName != NO_BRUSH_NAME)
  1221. CreateSubParentIfDoesntExist(keyBrushName, keyPlaletteName, keyToolName,
  1222. keyToolObjId, keyBrushName);
  1223. if (keyPrefabName != NO_PREFAB_NAME)
  1224. CreateSubParentIfDoesntExist(keyPrefabName, keyPlaletteName,
  1225. keyToolName, keyToolObjId, keyBrushName, keyPrefabName);
  1226. return parent;
  1227. }
  1228. private static bool IsVisible(ref GameObject obj)
  1229. {
  1230. if (obj == null) return false;
  1231. var parentRenderer = obj.GetComponentInParent<Renderer>();
  1232. var parentTerrain = obj.GetComponentInParent<Terrain>();
  1233. if (parentRenderer != null) obj = parentRenderer.gameObject;
  1234. else if (parentTerrain != null) obj = parentTerrain.gameObject;
  1235. else
  1236. {
  1237. var parent = obj.transform.parent;
  1238. if (parent != null)
  1239. {
  1240. var siblingRenderer = parent.GetComponentInChildren<Renderer>();
  1241. var siblingTerrain = parent.GetComponentInChildren<Terrain>();
  1242. if (siblingRenderer != null) obj = parent.gameObject;
  1243. else if (siblingTerrain != null) obj = parent.gameObject;
  1244. }
  1245. }
  1246. var renderers = obj.GetComponentsInChildren<Renderer>();
  1247. if (renderers.Length > 0)
  1248. {
  1249. foreach (var renderer in renderers)
  1250. if (renderer.enabled) return true;
  1251. }
  1252. var terrains = obj.GetComponentsInChildren<Terrain>();
  1253. if (terrains.Length > 0)
  1254. {
  1255. foreach (var terrain in terrains)
  1256. if (terrain.enabled) return true;
  1257. }
  1258. return false;
  1259. }
  1260. private static bool IsVisible(GameObject obj)
  1261. {
  1262. obj = PWBCore.GetGameObjectFromTempCollider(obj);
  1263. return IsVisible(ref obj);
  1264. }
  1265. private struct TerrainDataSimple
  1266. {
  1267. public float[,,] alphamaps;
  1268. public Vector3 size;
  1269. public TerrainLayer[] layers;
  1270. public TerrainDataSimple(float[,,] alphamaps, Vector3 size, TerrainLayer[] layers)
  1271. => (this.alphamaps, this.size, this.layers) = (alphamaps, size, layers);
  1272. }
  1273. private static System.Collections.Generic.Dictionary<int, TerrainDataSimple> _terrainAlphamaps
  1274. = new System.Collections.Generic.Dictionary<int, TerrainDataSimple>();
  1275. public static bool MouseRaycast(Ray mouseRay, out RaycastHit mouseHit,
  1276. out GameObject collider, float maxDistance, LayerMask layerMask,
  1277. bool paintOnPalettePrefabs, bool castOnMeshesWithoutCollider, string[] tags = null,
  1278. TerrainLayer[] terrainLayers = null, System.Collections.Generic.HashSet<GameObject> exceptions = null,
  1279. bool sameOriginAsRay = true, Vector3 origin = new Vector3())
  1280. {
  1281. bool IsTempCollider(GameObject obj)
  1282. {
  1283. var hitParent = obj.transform.parent;
  1284. return hitParent != null && hitParent.gameObject.GetInstanceID() == PWBCore.parentColliderId;
  1285. }
  1286. GameObject GetOriginalCollider(GameObject obj)
  1287. {
  1288. if (IsTempCollider(obj)) return PWBCore.GetGameObjectFromTempColliderId(obj.GetInstanceID());
  1289. return obj;
  1290. }
  1291. bool TagFilterPassed(GameObject obj)
  1292. {
  1293. if (tags == null) return true;
  1294. if (tags.Length == 0) return true;
  1295. if (obj.tag == "untagged") return true;
  1296. return tags.Contains(obj.tag);
  1297. }
  1298. bool ExceptionFilterPassed(GameObject obj)
  1299. {
  1300. if (exceptions == null) return true;
  1301. if (exceptions.Count == 0) return true;
  1302. return !exceptions.Contains(obj);
  1303. }
  1304. bool PaletteFilterPassed(GameObject obj)
  1305. {
  1306. if (paintOnPalettePrefabs) return true;
  1307. return !PaletteManager.selectedPalette.ContainsSceneObject(obj);
  1308. }
  1309. bool TerrainFilterPassed(GameObject obj, Vector3 mouseHitPoint)
  1310. {
  1311. if (terrainLayers == null) return true;
  1312. if (terrainLayers.Length == 0) return true;
  1313. var terrain = obj.GetComponent<Terrain>();
  1314. if (terrain == null) return true;
  1315. var instanceId = terrain.GetInstanceID();
  1316. int alphamapW = 0;
  1317. int alphamapH = 0;
  1318. float[,,] alphamaps;
  1319. Vector3 terrainSize;
  1320. TerrainLayer[] layers;
  1321. if (_terrainAlphamaps.ContainsKey(instanceId))
  1322. {
  1323. alphamaps = _terrainAlphamaps[instanceId].alphamaps;
  1324. alphamapW = alphamaps.GetLength(1);
  1325. alphamapH = alphamaps.GetLength(0);
  1326. terrainSize = _terrainAlphamaps[instanceId].size;
  1327. layers = _terrainAlphamaps[instanceId].layers;
  1328. }
  1329. else
  1330. {
  1331. var terrainData = terrain.terrainData;
  1332. if (terrainData == null) return false;
  1333. alphamapW = terrainData.alphamapWidth;
  1334. alphamapH = terrainData.alphamapHeight;
  1335. alphamaps = terrainData.GetAlphamaps(0, 0, alphamapW, alphamapH);
  1336. terrainSize = terrainData.size;
  1337. layers = terrainData.terrainLayers;
  1338. _terrainAlphamaps.Add(instanceId, new TerrainDataSimple(alphamaps, terrainSize, layers));
  1339. }
  1340. var numLayers = alphamaps.GetLength(2);
  1341. var localHit = terrain.transform.InverseTransformPoint(mouseHitPoint);
  1342. var alphaHitX = Mathf.Clamp(Mathf.RoundToInt(localHit.x / terrainSize.x * alphamapW), 0, alphamapW - 1);
  1343. var alphaHitZ = Mathf.Clamp(Mathf.RoundToInt(localHit.z / terrainSize.z * alphamapH), 0, alphamapH - 1);
  1344. int layerUnderCursorIdx = 0;
  1345. for (int k = 1; k < numLayers; k++)
  1346. {
  1347. if (alphamaps[alphaHitZ, alphaHitX, k] > 0.5)
  1348. {
  1349. layerUnderCursorIdx = k;
  1350. break;
  1351. }
  1352. }
  1353. var layerUnderCursor = layers[layerUnderCursorIdx];
  1354. return terrainLayers.Contains(layerUnderCursor);
  1355. }
  1356. bool AllFiltersPassed(ref GameObject obj, Vector3 mouseHitPoint)
  1357. {
  1358. if (obj == null) return false;
  1359. if (!IsVisible(ref obj)) return false;
  1360. if (!TagFilterPassed(obj)) return false;
  1361. if (!ExceptionFilterPassed(obj)) return false;
  1362. if (!PaletteFilterPassed(obj)) return false;
  1363. if (!TerrainFilterPassed(obj, mouseHitPoint)) return false;
  1364. return true;
  1365. }
  1366. mouseHit = new RaycastHit();
  1367. collider = null;
  1368. bool physicsValidHit = Physics.Raycast(mouseRay, out mouseHit,
  1369. maxDistance, layerMask, QueryTriggerInteraction.Ignore);
  1370. if (physicsValidHit && mouseHit.collider != null) collider = mouseHit.collider.gameObject;
  1371. GameObject[] nearbyObjects = null;
  1372. var meshValidHit = false;
  1373. if (castOnMeshesWithoutCollider && octree != null)
  1374. {
  1375. nearbyObjects = octree.GetNearby(mouseRay, 1f);
  1376. if (nearbyObjects.Length > 0)
  1377. {
  1378. nearbyObjects = nearbyObjects.Where(o => o != null).ToArray();
  1379. }
  1380. if (MeshUtils.Raycast(mouseRay, out RaycastHit meshHit, out GameObject meshCollider,
  1381. nearbyObjects, maxDistance, sameOriginAsRay, origin))
  1382. {
  1383. var meshHitDistance = sameOriginAsRay ? meshHit.distance : (meshHit.point - origin).magnitude;
  1384. var mouseHitDistance = sameOriginAsRay ? mouseHit.distance : (mouseHit.point - origin).magnitude;
  1385. if (!physicsValidHit || meshHitDistance < mouseHitDistance)
  1386. {
  1387. mouseHit = meshHit;
  1388. collider = meshCollider;
  1389. meshValidHit = true;
  1390. }
  1391. }
  1392. }
  1393. var hitDictionary = new System.Collections.Generic.Dictionary<GameObject, RaycastHit>();
  1394. if (physicsValidHit)
  1395. {
  1396. var hits = Physics.RaycastAll(mouseRay, maxDistance, layerMask, QueryTriggerInteraction.Ignore);
  1397. if (collider != null && hits.Length == 1)
  1398. {
  1399. var obj = GetOriginalCollider(collider);
  1400. if (AllFiltersPassed(ref obj, mouseHit.point))
  1401. {
  1402. collider = obj;
  1403. return true;
  1404. }
  1405. }
  1406. foreach (var hit in hits)
  1407. {
  1408. var obj = hit.collider.gameObject;
  1409. if (!hitDictionary.ContainsKey(obj)) hitDictionary.Add(obj, hit);
  1410. else
  1411. {
  1412. var hitDistance = sameOriginAsRay ? hit.distance : (hit.point - origin).magnitude;
  1413. var dicDistance = sameOriginAsRay ? hitDictionary[obj].distance
  1414. : (hitDictionary[obj].point - origin).magnitude;
  1415. if (hitDistance < dicDistance) hitDictionary[obj] = hit;
  1416. }
  1417. }
  1418. }
  1419. if (castOnMeshesWithoutCollider && meshValidHit)
  1420. {
  1421. if (MeshUtils.RaycastAll(mouseRay, out RaycastHit[] hitArray, out GameObject[] colliders,
  1422. nearbyObjects, maxDistance))
  1423. {
  1424. for (int i = 0; i < hitArray.Length; ++i)
  1425. {
  1426. var obj = colliders[i];
  1427. var hit = hitArray[i];
  1428. if (!hitDictionary.ContainsKey(obj)) hitDictionary.Add(obj, hit);
  1429. else
  1430. {
  1431. var hitDistance = sameOriginAsRay ? hit.distance : (hit.point - origin).magnitude;
  1432. var dicDistance = sameOriginAsRay ? hitDictionary[obj].distance
  1433. : (hitDictionary[obj].point - origin).magnitude;
  1434. if (hitDistance < dicDistance) hitDictionary[obj] = hit;
  1435. }
  1436. }
  1437. }
  1438. }
  1439. var minDistance = float.MaxValue;
  1440. collider = null;
  1441. var validHit = false;
  1442. foreach (var hitPair in hitDictionary)
  1443. {
  1444. var hitDistance = sameOriginAsRay ? hitPair.Value.distance : (hitPair.Value.point - origin).magnitude;
  1445. var hitCollider = GetOriginalCollider(hitPair.Key);
  1446. if (!AllFiltersPassed(ref hitCollider, mouseHit.point)) continue;
  1447. if (hitDistance < minDistance)
  1448. {
  1449. minDistance = hitDistance;
  1450. mouseHit = hitPair.Value;
  1451. collider = hitCollider;
  1452. validHit = true;
  1453. }
  1454. }
  1455. return validHit;
  1456. }
  1457. public static float GetDistanceToSurface(Vector3[] vertices, Matrix4x4 TRS, Vector3 direction, float magnitude,
  1458. bool paintOnPalettePrefabs, bool castOnMeshesWithoutCollider, out Transform surface, GameObject prefab,
  1459. System.Collections.Generic.HashSet<GameObject> exceptions = null)
  1460. {
  1461. surface = null;
  1462. var positiveDistance = float.MinValue;
  1463. var negativeDistance = float.MaxValue;
  1464. bool noSurfaceFound = true;
  1465. void GetDistance(float height, Vector3 direction, out GameObject collider)
  1466. {
  1467. collider = null;
  1468. foreach (var vertex in vertices)
  1469. {
  1470. var origin = TRS.MultiplyPoint(vertex);
  1471. var ray = new Ray(origin - (direction * height), direction);
  1472. if (MouseRaycast(ray, out RaycastHit hitInfo, out GameObject rayCollider,
  1473. float.MaxValue, -1, paintOnPalettePrefabs, castOnMeshesWithoutCollider,
  1474. tags: null, terrainLayers: null, exceptions, sameOriginAsRay: false, origin))
  1475. {
  1476. var prevPosDistance = positiveDistance;
  1477. var prevNegDistance = negativeDistance;
  1478. var distance = hitInfo.distance - height;
  1479. if (hitInfo.distance >= height) positiveDistance = Mathf.Max(distance, positiveDistance);
  1480. else negativeDistance = Mathf.Min(distance, negativeDistance);
  1481. if (collider == null || prevPosDistance != positiveDistance || prevNegDistance != negativeDistance)
  1482. collider = rayCollider;
  1483. noSurfaceFound = false;
  1484. }
  1485. }
  1486. }
  1487. var scale = TRS.lossyScale;
  1488. var scaleMult = Mathf.Max(scale.x + scale.y + scale.z, 1) * 9;
  1489. float hMult = magnitude * scaleMult;
  1490. GameObject surfaceCollider = null;
  1491. GetDistance(Mathf.Max(magnitude * hMult, hMult), direction, out surfaceCollider);
  1492. if (noSurfaceFound) return 0f;
  1493. surface = surfaceCollider.transform;
  1494. var distance = (positiveDistance >= 0 || Mathf.Approximately(positiveDistance, 0))
  1495. ? positiveDistance : negativeDistance;
  1496. if (Mathf.Approximately(distance, float.MinValue) || Mathf.Approximately(distance, float.MaxValue)) distance = 0;
  1497. return distance;
  1498. }
  1499. public static float GetBottomDistanceToSurface(Vector3[] bottomVertices, Matrix4x4 TRS,
  1500. float bottomMagnitude, bool paintOnPalettePrefabs, bool castOnMeshesWithoutCollider,
  1501. out Transform surface, System.Collections.Generic.HashSet<GameObject> exceptions = null)
  1502. {
  1503. surface = null;
  1504. var positiveDistance = float.MaxValue;
  1505. var negativeDistance = float.MinValue;
  1506. var down = (TRS.rotation * Vector3.down).normalized;
  1507. bool noSurfaceFound = true;
  1508. void GetDistance(float height, Vector3 direction, out GameObject collider)
  1509. {
  1510. collider = null;
  1511. foreach (var vertex in bottomVertices)
  1512. {
  1513. var origin = TRS.MultiplyPoint(vertex);
  1514. var ray = new Ray(origin - (direction * height), direction);
  1515. if (MouseRaycast(ray, out RaycastHit hitInfo, out GameObject rayCollider,
  1516. float.MaxValue, -1, paintOnPalettePrefabs, castOnMeshesWithoutCollider,
  1517. tags: null, terrainLayers: null, exceptions, sameOriginAsRay: false, origin))
  1518. {
  1519. var prevPosDistance = positiveDistance;
  1520. var prevNegDistance = negativeDistance;
  1521. if (hitInfo.distance >= height)
  1522. positiveDistance = Mathf.Min(hitInfo.distance - height, positiveDistance);
  1523. else negativeDistance = Mathf.Max(height - hitInfo.distance, negativeDistance);
  1524. if (prevPosDistance != positiveDistance || prevNegDistance != negativeDistance)
  1525. collider = rayCollider;
  1526. noSurfaceFound = false;
  1527. }
  1528. }
  1529. }
  1530. float hMult = 100f;
  1531. GameObject surfaceCollider = null;
  1532. GetDistance(Mathf.Max(bottomMagnitude * hMult, hMult), down, out surfaceCollider);
  1533. if (noSurfaceFound) return 0f;
  1534. surface = surfaceCollider.transform;
  1535. if (positiveDistance == float.MaxValue) positiveDistance = 0f;
  1536. if (negativeDistance == float.MinValue) negativeDistance = 0f;
  1537. var distance = positiveDistance >= negativeDistance ? positiveDistance : -negativeDistance;
  1538. return distance;
  1539. }
  1540. public static float GetBottomDistanceToSurfaceSigned(Vector3[] bottomVertices, Matrix4x4 TRS,
  1541. float maxDistance, bool paintOnPalettePrefabs, bool castOnMeshesWithoutCollider)
  1542. {
  1543. float distance = 0f;
  1544. var down = Vector3.down;
  1545. foreach (var vertex in bottomVertices)
  1546. {
  1547. var origin = TRS.MultiplyPoint(vertex);
  1548. var ray = new Ray(origin - down * maxDistance, down);
  1549. if (MouseRaycast(ray, out RaycastHit hitInfo, out GameObject collider,
  1550. float.MaxValue, -1, paintOnPalettePrefabs, castOnMeshesWithoutCollider))
  1551. {
  1552. var d = hitInfo.distance - maxDistance;
  1553. if (Mathf.Abs(d) > Mathf.Abs(distance)) distance = d;
  1554. }
  1555. }
  1556. return distance;
  1557. }
  1558. public static float GetPivotDistanceToSurfaceSigned(Vector3 pivot,
  1559. float maxDistance, bool paintOnPalettePrefabs, bool castOnMeshesWithoutCollider)
  1560. {
  1561. var ray = new Ray(pivot + Vector3.up * maxDistance, Vector3.down);
  1562. if (MouseRaycast(ray, out RaycastHit hitInfo, out GameObject collider,
  1563. float.MaxValue, -1, paintOnPalettePrefabs, castOnMeshesWithoutCollider))
  1564. return hitInfo.distance - maxDistance;
  1565. return 0;
  1566. }
  1567. private static BrushstrokeItem[] _brushstroke = null;
  1568. private struct PreviewData
  1569. {
  1570. public readonly GameObject prefab;
  1571. public readonly Matrix4x4 rootToWorld;
  1572. public readonly int layer;
  1573. public readonly bool flipX;
  1574. public readonly bool flipY;
  1575. public PreviewData(GameObject prefab, Matrix4x4 rootToWorld, int layer, bool flipX, bool flipY)
  1576. {
  1577. this.prefab = prefab;
  1578. this.rootToWorld = rootToWorld;
  1579. this.layer = layer;
  1580. this.flipX = flipX;
  1581. this.flipY = flipY;
  1582. }
  1583. }
  1584. private static System.Collections.Generic.List<PreviewData> _previewData
  1585. = new System.Collections.Generic.List<PreviewData>();
  1586. private static bool PreviewIfBrushtrokestaysTheSame(out BrushstrokeItem[] brushstroke,
  1587. Camera camera, bool forceUpdate)
  1588. {
  1589. brushstroke = BrushstrokeManager.brushstroke;
  1590. if (!forceUpdate && _brushstroke != null && BrushstrokeManager.BrushstrokeEqual(brushstroke, _brushstroke))
  1591. {
  1592. foreach (var previewItemData in _previewData)
  1593. PreviewBrushItem(previewItemData.prefab, previewItemData.rootToWorld,
  1594. previewItemData.layer, camera, false, false, previewItemData.flipX, previewItemData.flipY);
  1595. return true;
  1596. }
  1597. _brushstroke = BrushstrokeManager.brushstrokeClone;
  1598. _previewData.Clear();
  1599. return false;
  1600. }
  1601. private static System.Collections.Generic.Dictionary<long, PreviewData[]> _persistentPreviewData
  1602. = new System.Collections.Generic.Dictionary<long, PreviewData[]>();
  1603. private static System.Collections.Generic.Dictionary<long, BrushstrokeItem[]> _persistentLineBrushstrokes
  1604. = new System.Collections.Generic.Dictionary<long, BrushstrokeItem[]>();
  1605. private static void PreviewPersistent(Camera camera)
  1606. {
  1607. foreach (var previewDataArray in _persistentPreviewData.Values)
  1608. foreach (var previewItemData in previewDataArray)
  1609. PreviewBrushItem(previewItemData.prefab, previewItemData.rootToWorld,
  1610. previewItemData.layer, camera, false, false, previewItemData.flipX, previewItemData.flipY);
  1611. }
  1612. #endregion
  1613. #region BRUSH SHAPE INDICATOR
  1614. private static void DrawCricleIndicator(Vector3 hitPoint, Vector3 hitNormal,
  1615. float radius, float height, Vector3 tangent, Vector3 bitangent,
  1616. Vector3 normal, bool paintOnPalettePrefabs, bool castOnMeshesWithoutCollider,
  1617. int layerMask = -1, string[] tags = null, bool drawDropArea = false)
  1618. {
  1619. UnityEditor.Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
  1620. const float normalOffset = 0.01f;
  1621. const float polygonSideSize = 0.3f;
  1622. const int minPolygonSides = 12;
  1623. const int maxPolygonSides = 36;
  1624. var polygonSides = Mathf.Clamp((int)(TAU * radius / polygonSideSize), minPolygonSides, maxPolygonSides);
  1625. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.5f);
  1626. var periPoints = new System.Collections.Generic.List<Vector3>();
  1627. var periPointsShadow = new System.Collections.Generic.List<Vector3>();
  1628. var dropAreaPeriPoints = new System.Collections.Generic.List<Vector3>();
  1629. for (int i = 0; i < polygonSides; ++i)
  1630. {
  1631. var radians = TAU * i / (polygonSides - 1f);
  1632. var tangentDir = new Vector2(Mathf.Cos(radians), Mathf.Sin(radians));
  1633. var worldDir = TangentSpaceToWorld(tangent, bitangent, tangentDir);
  1634. var periPoint = hitPoint + (worldDir * (radius));
  1635. if (drawDropArea) dropAreaPeriPoints.Add(periPoint + Vector3.up * height);
  1636. var periRay = new Ray(periPoint + normal * height, -normal);
  1637. if (MouseRaycast(periRay, out RaycastHit periHit, out GameObject collider,
  1638. height * 2, layerMask, paintOnPalettePrefabs, castOnMeshesWithoutCollider, tags))
  1639. {
  1640. var periHitPoint = periHit.point + hitNormal * normalOffset;
  1641. var shadowPoint = periHitPoint + worldDir * 0.2f;
  1642. periPoints.Add(periHitPoint);
  1643. periPointsShadow.Add(shadowPoint);
  1644. }
  1645. else
  1646. {
  1647. if (periPoints.Count > 0 && i == polygonSides - 1)
  1648. {
  1649. periPoints.Add(periPoints[0]);
  1650. periPointsShadow.Add(periPointsShadow[0]);
  1651. }
  1652. else
  1653. {
  1654. float binSearchRadius = radius;
  1655. float delta = -binSearchRadius / 2;
  1656. for (int j = 0; j < 8; ++j)
  1657. {
  1658. binSearchRadius += delta;
  1659. periPoint = hitPoint + (worldDir * binSearchRadius);
  1660. periRay = new Ray(periPoint + normal * height, -normal);
  1661. if (MouseRaycast(periRay, out RaycastHit binSearchPeriHit,
  1662. out GameObject binSearchCollider, height * 2, layerMask,
  1663. paintOnPalettePrefabs, castOnMeshesWithoutCollider, tags))
  1664. {
  1665. delta = Mathf.Abs(delta) / 2;
  1666. periHit = binSearchPeriHit;
  1667. }
  1668. else delta = -Mathf.Abs(delta) / 2;
  1669. if (Mathf.Abs(delta) < 0.01) break;
  1670. }
  1671. if (periHit.point == Vector3.zero) continue;
  1672. var periHitPoint = periHit.point + hitNormal * normalOffset;
  1673. var shadowPoint = periHitPoint + worldDir * 0.2f;
  1674. periPoints.Add(periHitPoint);
  1675. periPointsShadow.Add(shadowPoint);
  1676. }
  1677. }
  1678. }
  1679. if (periPoints.Count > 0)
  1680. {
  1681. UnityEditor.Handles.color = new Color(1f, 1f, 1f, 0.5f);
  1682. UnityEditor.Handles.DrawAAPolyLine(3, periPoints.ToArray());
  1683. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.5f);
  1684. UnityEditor.Handles.DrawAAPolyLine(6, periPointsShadow.ToArray());
  1685. }
  1686. else
  1687. {
  1688. UnityEditor.Handles.color = new Color(1f, 1f, 1f, 0.5f);
  1689. UnityEditor.Handles.DrawWireDisc(hitPoint + hitNormal * normalOffset, hitNormal, radius);
  1690. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.5f);
  1691. UnityEditor.Handles.DrawWireDisc(hitPoint + hitNormal * normalOffset, hitNormal, radius + 0.2f);
  1692. }
  1693. if (drawDropArea && dropAreaPeriPoints.Count > 0)
  1694. {
  1695. UnityEditor.Handles.color = new Color(1f, 1f, 1f, 0.5f);
  1696. UnityEditor.Handles.DrawAAPolyLine(3, dropAreaPeriPoints.ToArray());
  1697. }
  1698. }
  1699. private static void DrawSquareIndicator(Vector3 hitPoint, Vector3 hitNormal,
  1700. float radius, float height, Vector3 tangent, Vector3 bitangent,
  1701. Vector3 normal, bool paintOnPalettePrefabs, bool castOnMeshesWithoutCollider,
  1702. int layerMask = -1, string[] tags = null, bool drawDropArea = false)
  1703. {
  1704. UnityEditor.Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
  1705. const float normalOffset = 0.01f;
  1706. const int minSideSegments = 4;
  1707. const int maxSideSegments = 15;
  1708. var segmentsPerSide = Mathf.Clamp((int)(radius * 2 / 0.3f), minSideSegments, maxSideSegments);
  1709. var segmentCount = segmentsPerSide * 4;
  1710. float segmentSize = radius * 2f / segmentsPerSide;
  1711. float SQRT2 = Mathf.Sqrt(2f);
  1712. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.5f);
  1713. var periPoints = new System.Collections.Generic.List<Vector3>();
  1714. var dropAreaPeriPoints = new System.Collections.Generic.List<Vector3>();
  1715. for (int i = 0; i < segmentCount; ++i)
  1716. {
  1717. int sideIdx = i / segmentsPerSide;
  1718. int segmentIdx = i % segmentsPerSide;
  1719. var periPoint = hitPoint;
  1720. if (sideIdx == 0) periPoint += tangent * (segmentSize * segmentIdx - radius) + bitangent * radius;
  1721. else if (sideIdx == 1) periPoint += bitangent * (radius - segmentSize * segmentIdx) + tangent * radius;
  1722. else if (sideIdx == 2) periPoint += tangent * (radius - segmentSize * segmentIdx) - bitangent * radius;
  1723. else periPoint += bitangent * (segmentSize * segmentIdx - radius) - tangent * radius;
  1724. if (drawDropArea) dropAreaPeriPoints.Add(periPoint + Vector3.up * height);
  1725. var worldDir = (periPoint - hitPoint).normalized;
  1726. var periRay = new Ray(periPoint + normal * height, -normal);
  1727. if (MouseRaycast(periRay, out RaycastHit periHit, out GameObject collider,
  1728. height * 2, layerMask, paintOnPalettePrefabs, castOnMeshesWithoutCollider, tags))
  1729. {
  1730. var periHitPoint = periHit.point + hitNormal * normalOffset;
  1731. periPoints.Add(periHitPoint);
  1732. }
  1733. else
  1734. {
  1735. float binSearchRadius = radius * SQRT2;
  1736. float delta = -binSearchRadius / 2;
  1737. for (int j = 0; j < 8; ++j)
  1738. {
  1739. binSearchRadius += delta;
  1740. periPoint = hitPoint + (worldDir * binSearchRadius);
  1741. periRay = new Ray(periPoint + normal * height, -normal);
  1742. if (MouseRaycast(periRay, out RaycastHit binSearchPeriHit,
  1743. out GameObject binSearchCollider, height * 2, layerMask,
  1744. paintOnPalettePrefabs, castOnMeshesWithoutCollider, tags))
  1745. {
  1746. delta = Mathf.Abs(delta) / 2;
  1747. periHit = binSearchPeriHit;
  1748. }
  1749. else delta = -Mathf.Abs(delta) / 2;
  1750. if (Mathf.Abs(delta) < 0.01) break;
  1751. }
  1752. if (periHit.point == Vector3.zero)
  1753. continue;
  1754. var periHitPoint = periHit.point + hitNormal * normalOffset;
  1755. var shadowPoint = periHitPoint + worldDir * 0.2f;
  1756. periPoints.Add(periHitPoint);
  1757. }
  1758. }
  1759. if (periPoints.Count > 0)
  1760. {
  1761. periPoints.Add(periPoints[0]);
  1762. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.7f);
  1763. UnityEditor.Handles.DrawAAPolyLine(8, periPoints.ToArray());
  1764. UnityEditor.Handles.color = new Color(1f, 1f, 1f, 0.7f);
  1765. UnityEditor.Handles.DrawAAPolyLine(4, periPoints.ToArray());
  1766. }
  1767. if (drawDropArea && dropAreaPeriPoints.Count > 0)
  1768. {
  1769. dropAreaPeriPoints.Add(dropAreaPeriPoints[0]);
  1770. UnityEditor.Handles.color = new Color(1f, 1f, 1f, 0.5f);
  1771. UnityEditor.Handles.DrawAAPolyLine(3, dropAreaPeriPoints.ToArray());
  1772. }
  1773. }
  1774. #endregion
  1775. #region HANDLES
  1776. private static float _blinkingDelta = 0.05f;
  1777. private static float _blinkingValue = 1f;
  1778. private static void DrawDotHandleCap(Vector3 point, float alpha = 1f,
  1779. float scale = 1f, bool selected = false, bool isPivot = false)
  1780. {
  1781. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.7f * alpha);
  1782. var handleSize = UnityEditor.HandleUtility.GetHandleSize(point);
  1783. var sizeDelta = handleSize * 0.0125f;
  1784. UnityEditor.Handles.DotHandleCap(0, point, Quaternion.identity,
  1785. handleSize * 0.0325f * scale * PWBCore.staticData.controPointSize, EventType.Repaint);
  1786. var fillColor = selected ? PWBCore.staticData.selectedContolPointColor
  1787. : (isPivot ? Color.green : UnityEditor.Handles.preselectionColor);
  1788. fillColor.a *= alpha;
  1789. if (selected && PWBCore.staticData.selectedControlPointBlink)
  1790. {
  1791. fillColor.a *= _blinkingValue;
  1792. if (_blinkingValue >= 1) _blinkingDelta = -Mathf.Abs(_blinkingDelta);
  1793. else if (_blinkingValue <= 0) _blinkingDelta = Mathf.Abs(_blinkingDelta);
  1794. _blinkingValue += _blinkingDelta;
  1795. }
  1796. UnityEditor.Handles.color = fillColor;
  1797. UnityEditor.Handles.DotHandleCap(0, point, Quaternion.identity,
  1798. (handleSize * 0.0325f * scale - sizeDelta) * PWBCore.staticData.controPointSize, EventType.Repaint);
  1799. }
  1800. #endregion
  1801. #region DRAG AND DROP
  1802. public class SceneDragReceiver : ISceneDragReceiver
  1803. {
  1804. private int _brushID = -1;
  1805. public int brushId { get => _brushID; set => _brushID = value; }
  1806. public void PerformDrag(Event evt) { }
  1807. public void StartDrag() { }
  1808. public void StopDrag() { }
  1809. public UnityEditor.DragAndDropVisualMode UpdateDrag(Event evt, EventType eventType)
  1810. {
  1811. PrefabPalette.instance.DeselectAllButThis(_brushID);
  1812. ToolManager.tool = ToolManager.PaintTool.PIN;
  1813. return UnityEditor.DragAndDropVisualMode.Generic;
  1814. }
  1815. }
  1816. private static SceneDragReceiver _sceneDragReceiver = new SceneDragReceiver();
  1817. public static SceneDragReceiver sceneDragReceiver => _sceneDragReceiver;
  1818. #endregion
  1819. #region PALETTE
  1820. public static void ReplaceSelected()
  1821. {
  1822. var replacerSettings = new ReplacerSettings();
  1823. _paintStroke.Clear();
  1824. SelectionManager.UpdateSelection();
  1825. var targets = SelectionManager.topLevelSelection;
  1826. BrushstrokeManager.UpdateReplacerBrushstroke(clearDictionary: true, targets);
  1827. ReplacePreview(UnityEditor.SceneView.lastActiveSceneView.camera, replacerSettings, targets);
  1828. var newObjects = Replace();
  1829. if (newObjects != null)
  1830. if (newObjects.Length > 0) UnityEditor.Selection.objects = newObjects;
  1831. }
  1832. private static void PaletteInput(UnityEditor.SceneView sceneView)
  1833. {
  1834. void Repaint()
  1835. {
  1836. PrefabPalette.RepainWindow();
  1837. sceneView.Repaint();
  1838. repaint = true;
  1839. AsyncRepaint();
  1840. }
  1841. if (PWBSettings.shortcuts.palettePreviousBrush.Check())
  1842. {
  1843. PaletteManager.SelectPreviousBrush();
  1844. Repaint();
  1845. }
  1846. else if (PWBSettings.shortcuts.paletteNextBrush.Check())
  1847. {
  1848. PaletteManager.SelectNextBrush();
  1849. Repaint();
  1850. }
  1851. if (PWBSettings.shortcuts.paletteNextBrushScroll.Check())
  1852. {
  1853. Event.current.Use();
  1854. if (PWBSettings.shortcuts.paletteNextBrushScroll.combination.delta > 0) PaletteManager.SelectNextBrush();
  1855. else PaletteManager.SelectPreviousBrush();
  1856. Repaint();
  1857. }
  1858. if (PWBSettings.shortcuts.paletteNextPaletteScroll.Check())
  1859. {
  1860. Event.current.Use();
  1861. if (Event.current.delta.y > 0) PaletteManager.SelectNextPalette();
  1862. else PaletteManager.SelectPreviousPalette();
  1863. Repaint();
  1864. }
  1865. if (PWBSettings.shortcuts.palettePreviousPalette.Check())
  1866. {
  1867. PaletteManager.SelectPreviousPalette();
  1868. Repaint();
  1869. }
  1870. else if (PWBSettings.shortcuts.paletteNextPalette.Check())
  1871. {
  1872. PaletteManager.SelectNextPalette();
  1873. Repaint();
  1874. }
  1875. if (PWBSettings.shortcuts.paletteReplaceSceneSelection.Check())
  1876. {
  1877. ReplaceSelected();
  1878. }
  1879. var pickShortcutOn = PWBSettings.shortcuts.palettePickBrush.Check();
  1880. var pickBrush = PaletteManager.pickingBrushes && Event.current.button == 0
  1881. && Event.current.type == EventType.MouseDown;
  1882. if (pickShortcutOn || pickBrush)
  1883. {
  1884. var mouseRay = UnityEditor.HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
  1885. if (MouseRaycast(mouseRay, out RaycastHit mouseHit, out GameObject collider,
  1886. float.MaxValue, -1, true, true))
  1887. {
  1888. var target = collider.gameObject;
  1889. var outermostPrefab = UnityEditor.PrefabUtility.GetOutermostPrefabInstanceRoot(target);
  1890. if (outermostPrefab != null) target = outermostPrefab;
  1891. var brushIdx = PaletteManager.selectedPalette.FindBrushIdx(target);
  1892. if (brushIdx >= 0) PaletteManager.SelectBrush(brushIdx);
  1893. else if (outermostPrefab != null)
  1894. {
  1895. var prefabAsset = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(outermostPrefab);
  1896. PrefabPalette.instance.CreateBrushFromSelection(prefabAsset);
  1897. }
  1898. }
  1899. Event.current.Use();
  1900. if (!pickShortcutOn && pickBrush) PaletteManager.pickingBrushes = false;
  1901. }
  1902. if (PWBSettings.shortcuts.palettePickBrush.holdKeysAndClickCombination.holdingChanged)
  1903. PaletteManager.pickingBrushes = PWBSettings.shortcuts.palettePickBrush.holdKeysAndClickCombination.holdingKeys;
  1904. }
  1905. async static void AsyncRepaint()
  1906. {
  1907. await System.Threading.Tasks.Task.Delay(500);
  1908. repaint = true;
  1909. }
  1910. #endregion
  1911. #region TOOLBAR
  1912. public static void ToogleTool(ToolManager.PaintTool tool)
  1913. {
  1914. #if UNITY_2021_2_OR_NEWER
  1915. #else
  1916. if (PWBToolbar.instance == null) PWBToolbar.ShowWindow();
  1917. #endif
  1918. ToolManager.tool = ToolManager.tool == tool ? ToolManager.PaintTool.NONE : tool;
  1919. PWBToolbar.RepaintWindow();
  1920. }
  1921. #endregion
  1922. #region MODULAR
  1923. private static bool _modularDeleteMode = false;
  1924. private static Mesh _cubeMesh = null;
  1925. private static Mesh cubeMesh
  1926. {
  1927. get
  1928. {
  1929. if (_cubeMesh == null) _cubeMesh = Resources.GetBuiltinResource<Mesh>("Cube.fbx");
  1930. return _cubeMesh;
  1931. }
  1932. }
  1933. #endregion
  1934. #region GIZMOS
  1935. private static void GizmosInput()
  1936. {
  1937. if (PWBSettings.shortcuts.gizmosToggleInfotext.Check())
  1938. {
  1939. PWBCore.staticData.ToggleInfoText();
  1940. }
  1941. }
  1942. #endregion
  1943. }
  1944. }