PinManager.cs 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351
  1. /*
  2. Copyright (c) 2021 Omar Duarte
  3. Unauthorized copying of this file, via any medium is strictly prohibited.
  4. Writen by Omar Duarte, 2021.
  5. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  6. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  8. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  9. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  10. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  11. THE SOFTWARE.
  12. */
  13. using System.Linq;
  14. using UnityEngine;
  15. namespace PluginMaster
  16. {
  17. #region DATA & SETTINGS
  18. [System.Serializable]
  19. public class TerrainFlatteningSettings
  20. {
  21. [SerializeField] private float _hardness = 0f;
  22. [SerializeField] private float _padding = 0f;
  23. [SerializeField] private bool _clearTrees = true;
  24. [SerializeField] private bool _clearDetails = true;
  25. private Vector2 _coreSize = Vector2.one;
  26. private Vector2 _density = Vector2.zero;
  27. private float _angle = 0;
  28. private bool _updateHeightmap = true;
  29. private float[,] _heightmap = null;
  30. public TerrainFlatteningSettings() { }
  31. public float hardness
  32. {
  33. get => _hardness;
  34. set
  35. {
  36. if (_hardness == value) return;
  37. _hardness = value;
  38. _updateHeightmap = true;
  39. PWBCore.SetSavePending();
  40. }
  41. }
  42. public float padding
  43. {
  44. get => _padding;
  45. set
  46. {
  47. value = Mathf.Max(value, 0);
  48. if (_padding == value) return;
  49. _padding = value;
  50. _updateHeightmap = true;
  51. PWBCore.SetSavePending();
  52. }
  53. }
  54. public bool clearTrees
  55. {
  56. get => _clearTrees;
  57. set
  58. {
  59. if (_clearTrees == value) return;
  60. _clearTrees = value;
  61. PWBCore.SetSavePending();
  62. }
  63. }
  64. public bool clearDetails
  65. {
  66. get => _clearDetails;
  67. set
  68. {
  69. if (_clearDetails == value) return;
  70. _clearDetails = value;
  71. PWBCore.SetSavePending();
  72. }
  73. }
  74. public Vector2 size
  75. {
  76. get => _coreSize;
  77. set
  78. {
  79. if (_coreSize == value) return;
  80. _coreSize = value;
  81. _updateHeightmap = true;
  82. }
  83. }
  84. public Vector2 density
  85. {
  86. set
  87. {
  88. if (_density == value) return;
  89. _density = value;
  90. _updateHeightmap = true;
  91. }
  92. }
  93. public float angle
  94. {
  95. get => _angle;
  96. set
  97. {
  98. if (_angle == value) return;
  99. _angle = value;
  100. _updateHeightmap = true;
  101. }
  102. }
  103. public float[,] heightmap
  104. {
  105. get
  106. {
  107. if (_updateHeightmap || _heightmap == null) UpdateHeightmap();
  108. return _heightmap;
  109. }
  110. }
  111. private void UpdateHeightmap()
  112. {
  113. _updateHeightmap = false;
  114. var cornerSize = (_coreSize.x + _coreSize.y) / 2 * (1 - _hardness);
  115. if (_hardness < 0.8) cornerSize = Mathf.Max(cornerSize, 10f / Mathf.Min(_density.x, _density.y));
  116. var coreWithPaddingSize = _coreSize + Vector2.one * _padding * 2;
  117. var size = coreWithPaddingSize + Vector2.one * (cornerSize * 2);
  118. var unrotatedSize = new Vector2Int(Mathf.RoundToInt(size.x * _density.x),
  119. Mathf.RoundToInt(size.y * _density.y));
  120. var coreMapSize = new Vector2Int(Mathf.RoundToInt(coreWithPaddingSize.x * _density.x),
  121. Mathf.RoundToInt(coreWithPaddingSize.y * _density.y));
  122. var cornerMapSize = new Vector2Int(Mathf.RoundToInt(_density.x * cornerSize),
  123. Mathf.RoundToInt(_density.y * cornerSize));
  124. var unrotatedMap = new float[unrotatedSize.x, unrotatedSize.y];
  125. var minCore = new Vector2Int(Mathf.Max(cornerMapSize.x - 1, 0), Mathf.Max(cornerMapSize.y - 1, 0));
  126. var maxCoreI = Mathf.Min(coreMapSize.y + cornerMapSize.y + 1, unrotatedSize.y);
  127. var maxCoreJ = Mathf.Min(coreMapSize.x + cornerMapSize.x + 1, unrotatedSize.x);
  128. for (int i = minCore.y; i < maxCoreI; ++i)
  129. for (int j = minCore.x; j < maxCoreJ; ++j)
  130. unrotatedMap[j, i] = 1f;
  131. float ParametricBlend(float t)
  132. {
  133. if (t > 1) return 1;
  134. if (t < 0) return 0;
  135. float tSquared = t * t;
  136. return tSquared / (2.0f * (tSquared - t) + 1.0f);
  137. }
  138. for (int i = 0; i < cornerMapSize.x; ++i)
  139. {
  140. var i1 = unrotatedSize.x - 1 - i;
  141. var iDistance = (cornerMapSize.x - i) / _density.x;
  142. for (int j = 0; j < cornerMapSize.y; ++j)
  143. {
  144. var j1 = unrotatedSize.y - 1 - j;
  145. var jDistance = (cornerMapSize.y - j) / _density.y;
  146. var distance = 1 - Mathf.Sqrt(iDistance * iDistance + jDistance * jDistance) / cornerSize;
  147. var h = ParametricBlend(distance);
  148. unrotatedMap[i, j] = unrotatedMap[i1, j] = unrotatedMap[i, j1] = unrotatedMap[i1, j1] = h;
  149. }
  150. var distanceNorm = 1 - (float)iDistance / cornerSize;
  151. var iH = ParametricBlend(distanceNorm);
  152. for (int j = minCore.y; j < maxCoreI; ++j) unrotatedMap[i, j] = unrotatedMap[i1, j] = iH;
  153. }
  154. for (int j = 0; j < cornerMapSize.y; ++j)
  155. {
  156. var j1 = unrotatedSize.y - 1 - j;
  157. var jDistance = (cornerMapSize.y - j) / _density.y;
  158. var distanceNorm = 1 - (float)jDistance / cornerSize;
  159. var jH = ParametricBlend(distanceNorm);
  160. for (int i = minCore.x; i < maxCoreJ; ++i) unrotatedMap[i, j] = unrotatedMap[i, j1] = jH;
  161. }
  162. if (_angle == 0)
  163. {
  164. _heightmap = unrotatedMap;
  165. return;
  166. }
  167. var angleRad = _angle * Mathf.Deg2Rad;
  168. var cos = Mathf.Cos(angleRad);
  169. var sin = Mathf.Sin(angleRad);
  170. var aspect = _density.x / _density.y;
  171. Vector2Int RotatePoint(Vector2 centerToPoint)
  172. {
  173. if (_angle == 0) return new Vector2Int(Mathf.RoundToInt(centerToPoint.x), Mathf.RoundToInt(centerToPoint.y));
  174. var result = Vector2Int.zero;
  175. centerToPoint.y = centerToPoint.y * aspect;
  176. result.x = Mathf.RoundToInt((centerToPoint.x * cos - centerToPoint.y * sin));
  177. result.y = Mathf.RoundToInt((centerToPoint.x * sin + centerToPoint.y * cos) / aspect);
  178. return result;
  179. }
  180. var centerToCorner1 = new Vector2Int(Mathf.CeilToInt(unrotatedSize.x / 2f), Mathf.CeilToInt(unrotatedSize.y / 2f));
  181. var rotatedCorner1 = RotatePoint(centerToCorner1);
  182. rotatedCorner1 = new Vector2Int(Mathf.Abs(rotatedCorner1.x), Mathf.Abs(rotatedCorner1.y));
  183. var centerToCorner2 = new Vector2Int(-Mathf.CeilToInt(unrotatedSize.x / 2f),
  184. Mathf.CeilToInt(unrotatedSize.y / 2f));
  185. var rotatedCorner2 = RotatePoint(centerToCorner2);
  186. rotatedCorner2 = new Vector2Int(Mathf.Abs(rotatedCorner2.x), Mathf.Abs(rotatedCorner2.y));
  187. var rotatedCorner = Vector2Int.Max(rotatedCorner1, rotatedCorner2);
  188. var rotationPadding = Vector2Int.Max(rotatedCorner - centerToCorner1, Vector2Int.zero);
  189. var rotatedHeightmapSize = unrotatedSize + rotationPadding * 2;
  190. _heightmap = new float[rotatedHeightmapSize.x, rotatedHeightmapSize.y];
  191. Vector2Int ClampPoint(Vector2Int point) => new Vector2Int(Mathf.Clamp(point.x, 0, rotatedHeightmapSize.x - 1),
  192. Mathf.Clamp(point.y, 0, rotatedHeightmapSize.y - 1));
  193. void SetHeight(Vector2Int point, float value)
  194. {
  195. var clampPoint = ClampPoint(point);
  196. _heightmap[clampPoint.x, clampPoint.y] = value;
  197. var points = new Vector2Int[] { ClampPoint(point + Vector2Int.up), ClampPoint(point + Vector2Int.down),
  198. ClampPoint(point + Vector2Int.left), ClampPoint(point + Vector2Int.right)};
  199. foreach (var p in points)
  200. _heightmap[p.x, p.y] = _heightmap[p.x, p.y] < 0.0001 ? value : (_heightmap[p.x, p.y] * 6 + value) / 7;
  201. }
  202. var unrotatedCenter = new Vector2Int(Mathf.FloorToInt(unrotatedSize.x / 2f),
  203. Mathf.FloorToInt(unrotatedSize.y / 2f));
  204. var center = new Vector2Int(Mathf.FloorToInt(rotatedHeightmapSize.x / 2f),
  205. Mathf.FloorToInt(rotatedHeightmapSize.y / 2f));
  206. for (int i = 0; i < unrotatedSize.y; ++i)
  207. {
  208. for (int j = 0; j < unrotatedSize.x; ++j)
  209. {
  210. var h = unrotatedMap[j, i];
  211. var point = new Vector2(j, i);
  212. var centerToPoint = point - unrotatedCenter;
  213. var rotatedPoint = RotatePoint(centerToPoint) + center;
  214. SetHeight(rotatedPoint, h);
  215. }
  216. }
  217. var smoothMap = new float[rotatedHeightmapSize.x, rotatedHeightmapSize.y];
  218. for (int i = 0; i < rotatedHeightmapSize.x; ++i)
  219. {
  220. for (int j = 0; j < rotatedHeightmapSize.y; ++j)
  221. {
  222. var count = 0;
  223. var sum = 0f;
  224. var corners = new float[] { i == 0 || j == 0 ? 0 : _heightmap[i-1, j-1],
  225. i == rotatedHeightmapSize.x-1 || j == 0? 0 :_heightmap[i+1, j -1],
  226. i == 0 || j == rotatedHeightmapSize.y-1 ? 0 :_heightmap[i-1, j+1],
  227. i == rotatedHeightmapSize.x-1 || j == rotatedHeightmapSize.y-1 ? 0 : _heightmap[i+1, j+1] };
  228. for (int n = 0; n < 4; ++n)
  229. {
  230. if (corners[n] < 0.0001) continue;
  231. ++count;
  232. sum += corners[n];
  233. }
  234. var neighbors = new float[] { i == 0 ? 0 : _heightmap[i - 1, j],
  235. i == rotatedHeightmapSize.x -1 ? 0 :_heightmap[i + 1, j],
  236. j == 0 ? 0 :_heightmap[i, j - 1], j == rotatedHeightmapSize.y -1 ? 0 : _heightmap[i, j + 1] };
  237. for (int n = 0; n < 4; ++n)
  238. {
  239. if (neighbors[n] < 0.0001) continue;
  240. count += 2;
  241. sum += neighbors[n] * 2;
  242. }
  243. if (count == 0)
  244. {
  245. smoothMap[i, j] = _heightmap[i, j];
  246. continue;
  247. }
  248. if (!(_heightmap[i, j] < 0.0001 && ((neighbors[0] > 0.0001 && neighbors[1] > 0.0001)
  249. || (neighbors[2] > 0.0001 && neighbors[3] > 0.0001))))
  250. {
  251. sum += _heightmap[i, j] * 3;
  252. count += 3;
  253. }
  254. var avg = sum / count;
  255. smoothMap[i, j] = avg;
  256. }
  257. }
  258. _heightmap = smoothMap;
  259. }
  260. }
  261. [System.Serializable]
  262. public class PinSettings : PaintOnSurfaceToolSettings, IPaintToolSettings
  263. {
  264. [SerializeField] private bool _repeat = false;
  265. [SerializeField] private TerrainFlatteningSettings _flatteningSettings = new TerrainFlatteningSettings();
  266. [SerializeField] private bool _flattenTerrain = false;
  267. [SerializeField] private bool _avoidOverlapping = false;
  268. [SerializeField] private bool _snapRotationToGrid = false;
  269. public bool repeat
  270. {
  271. get => _repeat;
  272. set
  273. {
  274. if (_repeat == value) return;
  275. _repeat = value;
  276. OnDataChanged();
  277. }
  278. }
  279. public TerrainFlatteningSettings flatteningSettings => _flatteningSettings;
  280. public bool flattenTerrain
  281. {
  282. get => _flattenTerrain;
  283. set
  284. {
  285. if (_flattenTerrain == value) return;
  286. _flattenTerrain = value;
  287. PWBCore.SetSavePending();
  288. }
  289. }
  290. public bool avoidOverlapping
  291. {
  292. get => _avoidOverlapping;
  293. set
  294. {
  295. if (_avoidOverlapping == value) return;
  296. _avoidOverlapping = value;
  297. OnDataChanged();
  298. }
  299. }
  300. public bool snapRotationToGrid
  301. {
  302. get => _snapRotationToGrid;
  303. set
  304. {
  305. if (_snapRotationToGrid == value) return;
  306. _snapRotationToGrid = value;
  307. OnDataChanged();
  308. }
  309. }
  310. #region PAINT TOOL
  311. [SerializeField] private PaintToolSettings _paintTool = new PaintToolSettings();
  312. public Transform parent { get => _paintTool.parent; set => _paintTool.parent = value; }
  313. public bool overwritePrefabLayer
  314. {
  315. get => _paintTool.overwritePrefabLayer;
  316. set => _paintTool.overwritePrefabLayer = value;
  317. }
  318. public int layer { get => _paintTool.layer; set => _paintTool.layer = value; }
  319. public bool autoCreateParent { get => _paintTool.autoCreateParent; set => _paintTool.autoCreateParent = value; }
  320. public bool setSurfaceAsParent { get => _paintTool.setSurfaceAsParent; set => _paintTool.setSurfaceAsParent = value; }
  321. public bool createSubparentPerPalette
  322. {
  323. get => _paintTool.createSubparentPerPalette;
  324. set => _paintTool.createSubparentPerPalette = value;
  325. }
  326. public bool createSubparentPerTool
  327. {
  328. get => _paintTool.createSubparentPerTool;
  329. set => _paintTool.createSubparentPerTool = value;
  330. }
  331. public bool createSubparentPerBrush
  332. {
  333. get => _paintTool.createSubparentPerBrush;
  334. set => _paintTool.createSubparentPerBrush = value;
  335. }
  336. public bool createSubparentPerPrefab
  337. {
  338. get => _paintTool.createSubparentPerPrefab;
  339. set => _paintTool.createSubparentPerPrefab = value;
  340. }
  341. public bool overwriteBrushProperties
  342. {
  343. get => _paintTool.overwriteBrushProperties;
  344. set => _paintTool.overwriteBrushProperties = value;
  345. }
  346. public BrushSettings brushSettings => _paintTool.brushSettings;
  347. public PinSettings() : base() => _paintTool.OnDataChanged += DataChanged;
  348. #endregion
  349. public override void Copy(IToolSettings other)
  350. {
  351. var otherPinSettings = other as PinSettings;
  352. if (otherPinSettings == null) return;
  353. base.Copy(other);
  354. _paintTool.Copy(otherPinSettings._paintTool);
  355. _repeat = otherPinSettings._repeat;
  356. _flattenTerrain = otherPinSettings._flattenTerrain;
  357. _snapRotationToGrid = otherPinSettings._snapRotationToGrid;
  358. }
  359. public override void DataChanged()
  360. {
  361. base.DataChanged();
  362. BrushstrokeManager.UpdateBrushstroke();
  363. }
  364. }
  365. [System.Serializable]
  366. public class PinManager : ToolManagerBase<PinSettings>
  367. {
  368. private static float _rotationSnapValueStatic = 5f;
  369. [SerializeField] private float _rotationSnapValue = _rotationSnapValueStatic;
  370. public static float rotationSnapValue
  371. {
  372. get => _rotationSnapValueStatic;
  373. set
  374. {
  375. if (_rotationSnapValueStatic == value) return;
  376. _rotationSnapValueStatic = value;
  377. PWBCore.staticData.SaveAndUpdateVersion();
  378. }
  379. }
  380. public override void OnBeforeSerialize()
  381. {
  382. base.OnBeforeSerialize();
  383. _rotationSnapValue = _rotationSnapValueStatic;
  384. }
  385. public override void OnAfterDeserialize()
  386. {
  387. base.OnAfterDeserialize();
  388. _rotationSnapValueStatic = _rotationSnapValue;
  389. }
  390. }
  391. #endregion
  392. #region PWBIO
  393. public static partial class PWBIO
  394. {
  395. private static bool _pinned = false;
  396. private static Vector3 _pinMouse = Vector3.zero;
  397. private static RaycastHit _pinHit = new RaycastHit();
  398. private static Vector3 _pinAngle = Vector3.zero;
  399. private static Vector3 _previousPinAngle = Vector3.zero;
  400. private static float _pinScale = 1f;
  401. private static Vector3 _pinOffset = Vector3.zero;
  402. private static System.Collections.Generic.List<System.Collections.Generic.List<Vector3>> _initialPinBoundPoints
  403. = new System.Collections.Generic.List<System.Collections.Generic.List<Vector3>>();
  404. private static System.Collections.Generic.List<System.Collections.Generic.List<Vector3>> _pinBoundPoints
  405. = new System.Collections.Generic.List<System.Collections.Generic.List<Vector3>>();
  406. private static int _pinBoundPointIdx = 0;
  407. private static int _pinBoundLayerIdx = 0;
  408. private static bool _snapToVertex = false;
  409. private static float _pinDistanceFromSurface = 0f;
  410. private static Vector2 _flatteningSize = Vector2.zero;
  411. private static Vector3 _flatteningCenter = Vector3.zero;
  412. private static Vector3 _pinProjectionDirection = Vector3.down;
  413. private static bool _pinFlipX = false;
  414. private static void UpdatePinScale()
  415. {
  416. for (int l = 0; l < _pinBoundPoints.Count; ++l)
  417. for (int p = 0; p < _pinBoundPoints[l].Count; ++p)
  418. _pinBoundPoints[l][p] = _initialPinBoundPoints[l][p] * _pinScale;
  419. _pinOffset = _pinBoundPoints[_pinBoundLayerIdx][_pinBoundPointIdx];
  420. }
  421. private static void UpdatePinScale(float value)
  422. {
  423. if (_pinScale == value) return;
  424. _pinScale = value;
  425. UpdatePinScale();
  426. UnityEditor.SceneView.RepaintAll();
  427. }
  428. private static Vector3 pivotBoundPoint
  429. {
  430. get
  431. {
  432. _pinBoundPointIdx = 0;
  433. return _pinBoundPoints[_pinBoundLayerIdx][_pinBoundPointIdx];
  434. }
  435. }
  436. private static Vector3 nextBoundPoint
  437. {
  438. get
  439. {
  440. ++_pinBoundPointIdx;
  441. if (_pinBoundPointIdx >= _pinBoundPoints[_pinBoundLayerIdx].Count) _pinBoundPointIdx = 0;
  442. return _pinBoundPoints[_pinBoundLayerIdx][_pinBoundPointIdx];
  443. }
  444. }
  445. private static Vector3 prevBoundPoint
  446. {
  447. get
  448. {
  449. --_pinBoundPointIdx;
  450. if (_pinBoundPointIdx < 0) _pinBoundPointIdx = _pinBoundPoints[_pinBoundLayerIdx].Count - 1;
  451. return _pinBoundPoints[_pinBoundLayerIdx][_pinBoundPointIdx];
  452. }
  453. }
  454. private static Vector3 nextBoundLayer
  455. {
  456. get
  457. {
  458. ++_pinBoundLayerIdx;
  459. if (_pinBoundLayerIdx >= _pinBoundPoints.Count) _pinBoundLayerIdx = 0;
  460. return _pinBoundPoints[_pinBoundLayerIdx][_pinBoundPointIdx];
  461. }
  462. }
  463. private static Vector3 prevBoundLayer
  464. {
  465. get
  466. {
  467. --_pinBoundLayerIdx;
  468. if (_pinBoundLayerIdx < 0) _pinBoundLayerIdx = _pinBoundPoints.Count - 1;
  469. return _pinBoundPoints[_pinBoundLayerIdx][_pinBoundPointIdx];
  470. }
  471. }
  472. private static void SetPinValues(Quaternion additionRotation)
  473. {
  474. var strokeItem = BrushstrokeManager.brushstroke[0];
  475. var prefab = strokeItem.settings.prefab;
  476. if (prefab == null) return;
  477. var isSprite = prefab.GetComponentsInChildren<SpriteRenderer>()
  478. .Where(r => r.enabled && r.sprite != null && r.gameObject.activeSelf).ToArray().Length > 0;
  479. var bounds = BoundsUtils.GetBoundsRecursive(prefab.transform, prefab.transform.rotation);
  480. _pinBoundPoints.Clear();
  481. _initialPinBoundPoints.Clear();
  482. var centerToPivot = Vector3.Scale(prefab.transform.position - bounds.center, strokeItem.scaleMultiplier);
  483. var pointRotation = additionRotation;
  484. var xProjection = Vector3.Project(_pinHit.normal, additionRotation * Vector3.right);
  485. var yProjection = Vector3.Project(_pinHit.normal, additionRotation * Vector3.up);
  486. var zProjection = Vector3.Project(_pinHit.normal, additionRotation * Vector3.forward);
  487. var xProjectionMagnitude = xProjection.magnitude;
  488. var yProjectionMagnitude = yProjection.magnitude;
  489. var zProjectionMagnitude = zProjection.magnitude;
  490. var nearestAxisToSurfaceNormal = AxesUtils.Axis.Y;
  491. var maxProjectionMagnitude = yProjectionMagnitude;
  492. if (xProjectionMagnitude > maxProjectionMagnitude)
  493. {
  494. nearestAxisToSurfaceNormal = AxesUtils.Axis.X;
  495. maxProjectionMagnitude = xProjectionMagnitude;
  496. }
  497. if (zProjectionMagnitude > maxProjectionMagnitude) nearestAxisToSurfaceNormal = AxesUtils.Axis.Z;
  498. var halfSize = Vector3.Scale(bounds.size, strokeItem.scaleMultiplier) * 0.5f;
  499. int l = 0;
  500. var pointsNormalized = new Vector2[] { new Vector2(0,0),
  501. new Vector2(-1,0), new Vector2(0,1), new Vector2(1,0), new Vector2(0,-1),
  502. new Vector2(-1,-1), new Vector2(-1,1), new Vector2(1,1), new Vector2(1,-1)};
  503. if (nearestAxisToSurfaceNormal == AxesUtils.Axis.Y)
  504. {
  505. var sign = 1;
  506. if (!strokeItem.settings.rotateToTheSurface) sign = Vector3.Dot(Vector3.up, yProjection) > 0 ? 1 : -1;
  507. _pinProjectionDirection = additionRotation * (Vector3.down * sign);
  508. for (int y = -1; y <= 1; y += 2)
  509. {
  510. _pinBoundPoints.Add(new System.Collections.Generic.List<Vector3>());
  511. _initialPinBoundPoints.Add(new System.Collections.Generic.List<Vector3>());
  512. _pinBoundPoints[l].Add(Vector3.zero);
  513. _initialPinBoundPoints[l].Add(Vector3.zero);
  514. foreach (var n in pointsNormalized)
  515. {
  516. var point = isSprite ? new Vector3(n.x, n.y, -y) : new Vector3(n.x, -y * sign, n.y);
  517. point = Vector3.Scale(point, halfSize) + centerToPivot;
  518. point = pointRotation * point;
  519. _pinBoundPoints[l].Add(point);
  520. _initialPinBoundPoints[l].Add(point);
  521. }
  522. ++l;
  523. }
  524. }
  525. else if (nearestAxisToSurfaceNormal == AxesUtils.Axis.X)
  526. {
  527. var sign = 1;
  528. if (!strokeItem.settings.rotateToTheSurface) sign = Vector3.Dot(Vector3.right, xProjection) > 0 ? 1 : -1;
  529. _pinProjectionDirection = additionRotation * (Vector3.left * sign);
  530. for (int x = -1; x <= 1; x += 2)
  531. {
  532. _pinBoundPoints.Add(new System.Collections.Generic.List<Vector3>());
  533. _initialPinBoundPoints.Add(new System.Collections.Generic.List<Vector3>());
  534. _pinBoundPoints[l].Add(Vector3.zero);
  535. _initialPinBoundPoints[l].Add(Vector3.zero);
  536. foreach (var n in pointsNormalized)
  537. {
  538. var point = isSprite ? new Vector3(n.x, n.y, -x) : new Vector3(-x * sign, n.y, n.x);
  539. point = Vector3.Scale(point, halfSize) + centerToPivot;
  540. point = pointRotation * point;
  541. _pinBoundPoints[l].Add(point);
  542. _initialPinBoundPoints[l].Add(point);
  543. }
  544. ++l;
  545. }
  546. }
  547. else if (nearestAxisToSurfaceNormal == AxesUtils.Axis.Z)
  548. {
  549. var sign = 1;
  550. if (!strokeItem.settings.rotateToTheSurface) sign = Vector3.Dot(Vector3.forward, zProjection) > 0 ? 1 : -1;
  551. _pinProjectionDirection = additionRotation * (Vector3.back * sign);
  552. for (int z = -1; z <= 1; z += 2)
  553. {
  554. _pinBoundPoints.Add(new System.Collections.Generic.List<Vector3>());
  555. _initialPinBoundPoints.Add(new System.Collections.Generic.List<Vector3>());
  556. _pinBoundPoints[l].Add(Vector3.zero);
  557. _initialPinBoundPoints[l].Add(Vector3.zero);
  558. foreach (var n in pointsNormalized)
  559. {
  560. var point = isSprite ? new Vector3(n.x, n.y, -z) : new Vector3(n.x, n.y, -z * sign);
  561. point = Vector3.Scale(point, halfSize) + centerToPivot;
  562. point = pointRotation * point;
  563. _pinBoundPoints[l].Add(point);
  564. _initialPinBoundPoints[l].Add(point);
  565. }
  566. ++l;
  567. }
  568. }
  569. }
  570. public static void ResetPinValues()
  571. {
  572. _pinned = false;
  573. _pinMouse = Vector3.zero;
  574. _pinHit = new RaycastHit();
  575. _pinAngle = Vector3.zero;
  576. _pinScale = 1f;
  577. _pinDistanceFromSurface = 0f;
  578. if (BrushstrokeManager.brushstroke.Length == 0) return;
  579. var strokeItem = BrushstrokeManager.brushstroke[0];
  580. SetPinValues(Quaternion.Euler(strokeItem.additionalAngle));
  581. BrushSettings brushSettings = strokeItem.settings;
  582. if (PinManager.settings.overwriteBrushProperties) brushSettings = PinManager.settings.brushSettings;
  583. repaint = true;
  584. _pinOffset = _pinBoundPoints[_pinBoundLayerIdx][_pinBoundPointIdx];
  585. UnityEditor.SceneView.RepaintAll();
  586. }
  587. public static void UpdatePinValues(GameObject prefab, Quaternion rotation)
  588. {
  589. if (prefab == null) return;
  590. var isSprite = prefab.GetComponentsInChildren<SpriteRenderer>()
  591. .Where(r => r.enabled && r.sprite != null && r.gameObject.activeSelf).ToArray().Length > 0;
  592. var additionalRotation = rotation;
  593. float RoundToStraightAngle(float angle) => Mathf.Round(angle / 90f) * 90f;
  594. var up = additionalRotation * Vector3.up;
  595. var fromUpToNormalRotation = Quaternion.FromToRotation(up, _pinHit.normal);
  596. Vector3 RoundEulerToStraightAngles(Vector3 euler)
  597. => new Vector3(RoundToStraightAngle(euler.x), RoundToStraightAngle(euler.y), RoundToStraightAngle(euler.z));
  598. var fromUpToNormalEulerRounded = RoundEulerToStraightAngles(fromUpToNormalRotation.eulerAngles);
  599. fromUpToNormalRotation = Quaternion.Euler(fromUpToNormalEulerRounded);
  600. SetPinValues(additionalRotation);
  601. var layerIdx = Mathf.Clamp(_pinBoundLayerIdx, 0, _pinBoundPoints.Count - 1);
  602. var pointIdx = Mathf.Clamp(_pinBoundPointIdx, 0, _pinBoundPoints[layerIdx].Count - 1);
  603. UpdatePinScale();
  604. repaint = true;
  605. UnityEditor.SceneView.RepaintAll();
  606. }
  607. private static Transform _pinSurface = null;
  608. private static void PinDuringSceneGUI(UnityEditor.SceneView sceneView)
  609. {
  610. if (PinManager.settings.paintOnMeshesWithoutCollider)
  611. PWBCore.CreateTempCollidersWithinFrustum(sceneView.camera);
  612. PinInput(sceneView);
  613. if (Event.current.type != EventType.Repaint && Event.current.type != EventType.Layout) return;
  614. var mouseRay = UnityEditor.HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
  615. bool snappedToVertex = false;
  616. var closestVertexInfo = new RaycastHit();
  617. var settings = PinManager.settings;
  618. if (_snapToVertex)
  619. snappedToVertex = SnapToVertex(mouseRay, out closestVertexInfo, sceneView.in2DMode);
  620. if (snappedToVertex)
  621. DrawPin(sceneView, closestVertexInfo, false);
  622. else
  623. {
  624. if (settings.mode == PinSettings.PaintMode.ON_SHAPE)
  625. {
  626. if (GridRaycast(mouseRay, out RaycastHit planeHit))
  627. DrawPin(sceneView, planeHit, SnapManager.settings.snappingEnabled);
  628. else _paintStroke.Clear();
  629. }
  630. else
  631. {
  632. if (MouseRaycast(mouseRay, out RaycastHit mouseHit, out GameObject collider, float.MaxValue,
  633. -1, settings.paintOnPalettePrefabs, settings.paintOnMeshesWithoutCollider))
  634. {
  635. DrawPin(sceneView, mouseHit, SnapManager.settings.snappingEnabled);
  636. _pinSurface = collider.transform;
  637. }
  638. else if (_pinned) DrawPin(sceneView, _pinHit, SnapManager.settings.snappingEnabled);
  639. else if (settings.mode == PinSettings.PaintMode.AUTO)
  640. {
  641. if (GridRaycast(mouseRay, out RaycastHit planeHit))
  642. DrawPin(sceneView, planeHit, SnapManager.settings.snappingEnabled);
  643. }
  644. else _paintStroke.Clear();
  645. }
  646. }
  647. PinInfoText(sceneView);
  648. }
  649. private static void PinInfoText(UnityEditor.SceneView sceneView)
  650. {
  651. if (!PWBCore.staticData.showInfoText) return;
  652. if (_paintStroke.Count == 0) return;
  653. var p = _paintStroke[0].position;
  654. var r = _paintStroke[0].rotation.eulerAngles;
  655. var s = _paintStroke[0].scale;
  656. var labelTexts = new string[]
  657. { _paintStroke[0].prefab.name,
  658. $"P: {p.x.ToString("F2")}, {p.y.ToString("F2")}, {p.z.ToString("F2")}",
  659. $"R: {r.x.ToString("F2")}, {r.y.ToString("F2")}, {r.z.ToString("F2")}",
  660. $"S: {s.x.ToString("F2")}, {s.y.ToString("F2")}, {s.z.ToString("F2")}"};
  661. InfoText.Draw(sceneView, labelTexts);
  662. }
  663. private static Vector3 _prevPinHitNormal = Vector3.zero;
  664. private static void DrawPin(UnityEditor.SceneView sceneView, RaycastHit hit,
  665. bool snapToGrid)
  666. {
  667. if (PaletteManager.selectedBrush == null) return;
  668. PWBCore.UpdateTempCollidersIfHierarchyChanged();
  669. if (!_pinned)
  670. {
  671. hit.point = SnapAndUpdateGridOrigin(hit.point, snapToGrid,
  672. PinManager.settings.paintOnPalettePrefabs, PinManager.settings.paintOnMeshesWithoutCollider,
  673. PinManager.settings.mode == PaintOnSurfaceToolSettings.PaintMode.ON_SHAPE, -hit.normal);
  674. _pinHit = hit;
  675. }
  676. PinPreview(sceneView.camera);
  677. }
  678. private static bool snapPinRotationToGrid = false;
  679. private static Vector3 GetPinAngleSnappedToGrid(Vector3 position, Quaternion rotation)
  680. {
  681. var gridRotation = Quaternion.identity;
  682. if (SnapManager.settings.radialGridEnabled)
  683. {
  684. var gridLocalNormal = (Vector3)(AxesUtils.SignedAxis)SnapManager.settings.gridAxis;
  685. var gridNormal = SnapManager.settings.rotation * gridLocalNormal;
  686. var posOnPlane = Vector3.ProjectOnPlane(position, gridNormal) - SnapManager.settings.origin;
  687. gridRotation = Quaternion.Inverse(rotation) * Quaternion.LookRotation(posOnPlane, gridNormal);
  688. }
  689. else gridRotation = Quaternion.Inverse(rotation) * SnapManager.settings.rotation;
  690. Vector3 GetSnappedToGrid(Vector3 v)
  691. {
  692. var xProj = Vector3.Project(v, gridRotation * Vector3.right);
  693. var yProj = Vector3.Project(v, gridRotation * Vector3.up);
  694. var zProj = Vector3.Project(v, gridRotation * Vector3.forward);
  695. var xMag = xProj.magnitude;
  696. var yMag = yProj.magnitude;
  697. var zMag = zProj.magnitude;
  698. if (xMag >= yMag && xMag >= zMag) return xProj;
  699. else if (yMag >= xMag && yMag >= zMag) return yProj;
  700. else return zProj;
  701. }
  702. var pinRotation = Quaternion.Euler(_pinAngle);
  703. var snappedUp = GetSnappedToGrid(pinRotation * Vector3.up);
  704. var snappedFw = GetSnappedToGrid(pinRotation * Vector3.forward);
  705. return Quaternion.LookRotation(snappedFw, snappedUp).eulerAngles;
  706. }
  707. private static void PinPreview(Camera camera)
  708. {
  709. _paintStroke.Clear();
  710. if (BrushstrokeManager.brushstroke.Length == 0) return;
  711. var strokeItem = BrushstrokeManager.brushstroke[0].Clone();
  712. var prefab = strokeItem.settings.prefab;
  713. if (prefab == null) return;
  714. BrushSettings brushSettings = strokeItem.settings;
  715. if (PinManager.settings.overwriteBrushProperties) brushSettings = PinManager.settings.brushSettings;
  716. var itemRotation = Quaternion.identity;
  717. var itemPosition = _pinHit.point;
  718. if (brushSettings.rotateToTheSurface && !PinManager.settings.flattenTerrain)
  719. {
  720. if (_pinHit.normal == Vector3.zero) _pinHit.normal = Vector3.up;
  721. var itemTangent = Vector3.Cross(_pinHit.normal, Vector3.left);
  722. if (itemTangent.sqrMagnitude < 0.000001) itemTangent = Vector3.Cross(_pinHit.normal, Vector3.back);
  723. itemTangent = itemTangent.normalized;
  724. if (_pinHit.collider == null)
  725. itemRotation = Quaternion.LookRotation(Vector3.forward, Vector3.up);
  726. else
  727. {
  728. itemRotation = Quaternion.LookRotation(itemTangent, _pinHit.normal);
  729. if (strokeItem.settings.isAsset2D) itemRotation *= Quaternion.Euler(90, 0, 0);
  730. }
  731. }
  732. if (_pinHit.collider != null)
  733. {
  734. var obj = _pinHit.collider.gameObject;
  735. var hitParent = _pinHit.collider.transform.parent;
  736. if (hitParent != null && hitParent.gameObject.GetInstanceID() == PWBCore.parentColliderId)
  737. obj = PWBCore.GetGameObjectFromTempColliderId(obj.GetInstanceID());
  738. }
  739. GameObject objUnderMouse = null;
  740. if (_pinHit.collider != null)
  741. {
  742. var parentUnderMouse = _pinHit.collider.transform.parent;
  743. if (parentUnderMouse != null
  744. && parentUnderMouse.gameObject.GetInstanceID() == PWBCore.parentColliderId)
  745. objUnderMouse = PWBCore.GetGameObjectFromTempColliderId(
  746. _pinHit.collider.gameObject.GetInstanceID());
  747. else objUnderMouse = _pinHit.collider.gameObject;
  748. }
  749. if (PinManager.settings.paintOnSelectedOnly && objUnderMouse != null
  750. && !SelectionManager.selection.Contains(objUnderMouse)) return;
  751. itemRotation *= Quaternion.Euler(strokeItem.additionalAngle);
  752. var pinAngle = _pinAngle;
  753. if (PinManager.settings.snapRotationToGrid || snapPinRotationToGrid)
  754. {
  755. pinAngle = GetPinAngleSnappedToGrid(itemPosition, itemRotation);
  756. if (snapPinRotationToGrid)
  757. {
  758. _pinAngle = pinAngle;
  759. snapPinRotationToGrid = false;
  760. }
  761. }
  762. itemRotation *= Quaternion.Euler(pinAngle);
  763. if (brushSettings.rotateToTheSurface && brushSettings.alwaysOrientUp && !strokeItem.settings.isAsset2D)
  764. {
  765. var fw = (Quaternion.Euler(strokeItem.additionalAngle) * Quaternion.Euler(_pinAngle)) * _pinHit.normal;
  766. fw.y = 0;
  767. const float minMag = 1e-6f;
  768. if (Mathf.Abs(fw.x) > minMag || Mathf.Abs(fw.z) > minMag)
  769. itemRotation = Quaternion.LookRotation(fw, Vector3.up);
  770. }
  771. itemPosition += itemRotation * brushSettings.localPositionOffset;
  772. var scaleMult = strokeItem.scaleMultiplier * _pinScale;
  773. var itemScale = Vector3.Scale(prefab.transform.localScale, scaleMult);
  774. UpdatePinValues(prefab, itemRotation * prefab.transform.rotation);
  775. var previewPinOffset = _pinOffset;
  776. previewPinOffset.x /= scaleMult.x;
  777. previewPinOffset.y /= scaleMult.y;
  778. previewPinOffset.z /= scaleMult.z;
  779. var strokePinOffset = _pinOffset;
  780. if (brushSettings.embedInSurface && PinManager.settings.mode != PaintOnSurfaceToolSettingsBase.PaintMode.ON_SHAPE)
  781. {
  782. if (brushSettings.embedAtPivotHeight)
  783. itemPosition += _pinBoundPoints[_pinBoundLayerIdx][0] - _pinOffset;
  784. else
  785. {
  786. var TRS = Matrix4x4.TRS(itemPosition + _pinOffset, itemRotation,
  787. Vector3.Scale(prefab.transform.localScale, scaleMult));
  788. float magnitudeInDirection;
  789. var localDirection = Quaternion.Inverse(itemRotation) * _pinProjectionDirection;
  790. var furthestVertices = strokeItem.settings.GetFurthestVerticesInDirection(localDirection,
  791. out magnitudeInDirection);
  792. var distanceTosurface = GetDistanceToSurface(furthestVertices, TRS, _pinProjectionDirection,
  793. Mathf.Abs(magnitudeInDirection), PinManager.settings.paintOnPalettePrefabs,
  794. PinManager.settings.paintOnMeshesWithoutCollider, out Transform surfaceTransform, prefab);
  795. itemPosition += _pinProjectionDirection * distanceTosurface;
  796. }
  797. }
  798. itemPosition -= _pinProjectionDirection * (strokeItem.surfaceDistance + _pinDistanceFromSurface);
  799. var layer = PinManager.settings.overwritePrefabLayer ? PinManager.settings.layer : prefab.layer;
  800. Transform parentTransform = GetParent(PinManager.settings, prefab.name, false, _pinSurface);
  801. if (PinManager.settings.avoidOverlapping)
  802. {
  803. var itemBounds = BoundsUtils.GetBoundsRecursive(prefab.transform, Quaternion.identity);
  804. var pivotToCenter = itemBounds.center - prefab.transform.position;
  805. pivotToCenter = Vector3.Scale(pivotToCenter, scaleMult);
  806. pivotToCenter = itemRotation * pivotToCenter;
  807. var itemCenter = itemPosition + pivotToCenter;
  808. var itemHalfExtends = Vector3.Scale(itemBounds.size * 0.499f, strokeItem.scaleMultiplier);
  809. var overlaped = Physics.OverlapBox(itemCenter, itemHalfExtends,
  810. itemRotation, -1, QueryTriggerInteraction.Ignore).
  811. Where(c => c != _pinHit.collider && IsVisible(c.gameObject)).ToArray();
  812. if (overlaped.Length > 0)
  813. {
  814. DrawPinHandles(new Color(1f, 0f, 0f, 0.7f));
  815. return;
  816. }
  817. }
  818. var flipX = strokeItem.flipX ^ _pinFlipX;
  819. _paintStroke.Add(new PaintStrokeItem(prefab, itemPosition + strokePinOffset,
  820. itemRotation * prefab.transform.rotation,
  821. itemScale, layer, parentTransform, _pinSurface, flipX, strokeItem.flipY));
  822. var translateMatrix = Matrix4x4.Translate(Quaternion.Inverse(itemRotation) * previewPinOffset
  823. - prefab.transform.position);
  824. var rootToWorld = Matrix4x4.TRS(itemPosition, itemRotation, scaleMult) * translateMatrix;
  825. PreviewBrushItem(prefab, rootToWorld, layer, camera, false, false, flipX, strokeItem.flipY);
  826. if (!brushSettings.isAsset2D && _prevPinHitNormal != _pinHit.normal) _prevPinHitNormal = _pinHit.normal;
  827. DrawPinHandles(new Color(1f, 1f, 1f, 0.7f));
  828. _pinSurface = null;
  829. }
  830. private static void FlatenTerrain()
  831. {
  832. var terrain = _pinHit.collider.GetComponent<Terrain>();
  833. if (terrain == null) return;
  834. var terrainData = terrain.terrainData;
  835. terrainData.SetTerrainLayersRegisterUndo(terrainData.terrainLayers, "Paint");
  836. var resolution = terrainData.heightmapResolution;
  837. var heighMap = terrainData.GetHeights(0, 0, resolution, resolution);
  838. var transformScale = terrain.transform.localScale;
  839. terrain.transform.localScale = Vector3.one;
  840. var localCenter = terrain.transform.InverseTransformPoint(_flatteningCenter);
  841. var localHit = terrain.transform.InverseTransformPoint(_pinHit.point);
  842. terrain.transform.localScale = transformScale;
  843. var density = new Vector2(1 / terrainData.heightmapScale.x, 1 / terrainData.heightmapScale.z);
  844. var mapCenterX = Mathf.RoundToInt(localCenter.x * density.x);
  845. var mapCenterZ = Mathf.RoundToInt(localCenter.z * density.y);
  846. var mapHitX = Mathf.RoundToInt(localHit.x * density.x);
  847. var mapHitZ = Mathf.RoundToInt(localHit.z * density.y);
  848. var hitHmapVal = heighMap[mapHitZ, mapHitX];
  849. var flattenSettings = PinManager.settings.flatteningSettings;
  850. flattenSettings.density = density;
  851. flattenSettings.angle = -_pinAngle.y;
  852. var paintItem = _paintStroke[0];
  853. var itemSize = BoundsUtils.GetBoundsRecursive(paintItem.prefab.transform).size * _pinScale;
  854. flattenSettings.size = new Vector2(itemSize.x, itemSize.z);
  855. var itemHeighmap = flattenSettings.heightmap;
  856. var itemHeighmapH = itemHeighmap.GetLength(0);
  857. var itemHeighmapW = itemHeighmap.GetLength(1);
  858. int itemMinX = Mathf.Max(itemHeighmapH / 2 - mapCenterX, 0);
  859. int itemMinZ = Mathf.Max(itemHeighmapW / 2 - mapCenterZ, 0);
  860. int itemMaxX = itemHeighmapH;
  861. if (Mathf.CeilToInt(itemHeighmapH / 2) + mapCenterX > resolution)
  862. itemMaxX -= (Mathf.CeilToInt(itemHeighmapH / 2) + mapCenterX) - resolution + 1;
  863. int itemMaxZ = itemHeighmapW;
  864. if (Mathf.CeilToInt(itemHeighmapW / 2) + mapCenterZ > resolution)
  865. itemMaxZ -= (Mathf.CeilToInt(itemHeighmapW / 2) + mapCenterZ) - resolution + 1;
  866. int w = itemMaxZ - itemMinZ;
  867. int h = itemMaxX - itemMinX;
  868. var heights = new float[w, h];
  869. int terrHmapMinX = Mathf.Max(mapCenterX - itemHeighmapH / 2, 0);
  870. int terrHmapMinZ = Mathf.Max(mapCenterZ - itemHeighmapW / 2, 0);
  871. for (int x = itemMinX; x < itemMaxX; ++x)
  872. {
  873. for (int z = itemMinZ; z < itemMaxZ; ++z)
  874. {
  875. var terrHmapI = Mathf.Clamp(mapCenterZ - Mathf.CeilToInt(itemHeighmapW / 2) + z, 0, resolution - 1);
  876. var terrHmapJ = Mathf.Clamp(mapCenterX - Mathf.CeilToInt(itemHeighmapH / 2) + x, 0, resolution - 1);
  877. var terrHmapVal = heighMap[terrHmapI, terrHmapJ];
  878. var itemI = z - itemMinZ;
  879. var itemJ = x - itemMinX;
  880. var itemHmapVal = itemHeighmap[x, z];
  881. heights[itemI, itemJ] = terrHmapVal * (1 - itemHmapVal) + hitHmapVal * itemHmapVal;
  882. }
  883. }
  884. terrainData.SetHeights(terrHmapMinX, terrHmapMinZ, heights);
  885. ////////////////////
  886. if (flattenSettings.clearDetails)
  887. {
  888. var heightToDetail = (float)terrainData.detailResolution / terrainData.heightmapResolution;
  889. var heightToDetailInt = Mathf.CeilToInt(heightToDetail) + 1;
  890. var terrainDetailLayers = new System.Collections.Generic.List<int[,]>();
  891. var detailLayers = new System.Collections.Generic.List<int[,]>();
  892. var densityInt = new Vector2Int(Mathf.CeilToInt(density.x), Mathf.CeilToInt(density.y));
  893. var detailsW = Mathf.CeilToInt(w * heightToDetail) + 4 * densityInt.y;
  894. var detailsH = Mathf.CeilToInt(h * heightToDetail) + 4 * densityInt.x;
  895. var terrDetailMinX = Mathf.RoundToInt((localCenter.x * density.x - itemHeighmapH / 2f) * heightToDetail)
  896. - 2 * densityInt.x;
  897. var terrDetailMinY = Mathf.RoundToInt((localCenter.z * density.y - itemHeighmapW / 2f) * heightToDetail)
  898. - 2 * densityInt.y;
  899. void SetDetailToZero(int layer, int i, int j)
  900. {
  901. detailLayers[layer][i, j] = 0;
  902. for (int k = 1; k <= heightToDetailInt; ++k)
  903. {
  904. if (i - k >= 0)
  905. {
  906. detailLayers[layer][i - k, j] = 0;
  907. if (j - k >= 0) detailLayers[layer][i - k, j - k] = 0;
  908. else if (j + k < detailsH - 1) detailLayers[layer][i - k, j + k] = 0;
  909. }
  910. else if (i + k < detailsW - 1)
  911. {
  912. detailLayers[layer][i + k, j] = 0;
  913. if (j - k >= 0) detailLayers[layer][i + k, j - k] = 0;
  914. else if (j + k < detailsH - 1) detailLayers[layer][i + k, j + k] = 0;
  915. }
  916. else
  917. {
  918. if (j - k >= 0) detailLayers[layer][i, j - k] = 0;
  919. else if (j + k < detailsH - 1) detailLayers[layer][i, j + k] = 0;
  920. }
  921. }
  922. }
  923. for (int k = 0; k < terrainData.detailPrototypes.Length; ++k)
  924. {
  925. terrainDetailLayers.Add(terrainData.GetDetailLayer(0, 0,
  926. terrainData.detailWidth, terrainData.detailHeight, k));
  927. detailLayers.Add(new int[detailsW, detailsH]);
  928. for (int itemDetailI = 0; itemDetailI < detailsW; ++itemDetailI)
  929. {
  930. for (int itemDetailJ = 0; itemDetailJ < detailsH; ++itemDetailJ)
  931. {
  932. var terrDetailI = Mathf.Clamp(terrDetailMinY + itemDetailI, 0, terrainData.detailWidth - 1);
  933. var terrDetailJ = Mathf.Clamp(terrDetailMinX + itemDetailJ, 0, terrainData.detailHeight - 1);
  934. var layerValue = terrainDetailLayers[k][terrDetailI, terrDetailJ];
  935. detailLayers[k][itemDetailI, itemDetailJ] = layerValue;
  936. var itemHmapX = Mathf.Clamp(Mathf.RoundToInt((itemDetailJ - 2 * densityInt.y)
  937. / heightToDetail), 0, itemHeighmapH - 1);
  938. var itemHmapZ = Mathf.Clamp(Mathf.RoundToInt((itemDetailI - 2 * densityInt.x)
  939. / heightToDetail), 0, itemHeighmapW - 1);
  940. var itemHmapVal = itemHeighmap[itemHmapX, itemHmapZ];
  941. if (itemHmapVal > 0.9) SetDetailToZero(k, itemDetailI, itemDetailJ);
  942. }
  943. }
  944. terrainData.SetDetailLayer(terrDetailMinX, terrDetailMinY, k, detailLayers[k]);
  945. }
  946. }
  947. if (flattenSettings.clearTrees)
  948. {
  949. for (int k = 0; k < terrainData.detailPrototypes.Length; ++k)
  950. {
  951. var treeInstances = new System.Collections.Generic.List<TreeInstance>();
  952. foreach (var treeInstance in terrainData.treeInstances)
  953. {
  954. var hmapX = Mathf.RoundToInt(treeInstance.position.x * resolution);
  955. var hmapZ = Mathf.RoundToInt(treeInstance.position.z * resolution);
  956. var itemHmapX = hmapX - terrHmapMinX;
  957. var itemHmapZ = hmapZ - terrHmapMinZ;
  958. if (itemHmapX < 0 || itemHmapX >= itemHeighmapH || itemHmapZ < 0 || itemHmapZ >= itemHeighmapW)
  959. {
  960. treeInstances.Add(treeInstance);
  961. continue;
  962. }
  963. var itemHmapVal = itemHeighmap[itemHmapX, itemHmapZ];
  964. if (itemHmapVal < 0.9) treeInstances.Add(treeInstance);
  965. }
  966. terrainData.treeInstances = treeInstances.ToArray();
  967. }
  968. }
  969. //////////////////
  970. }
  971. private static void PinInput(UnityEditor.SceneView sceneView)
  972. {
  973. if (PaletteManager.selectedBrush == null) return;
  974. var keyCode = Event.current.keyCode;
  975. if (Event.current.button == 0)
  976. {
  977. if (Event.current.type == EventType.MouseUp && !Event.current.alt)
  978. {
  979. if (PinManager.settings.flattenTerrain) FlatenTerrain();
  980. Paint(PinManager.settings);
  981. _pinned = false;
  982. Event.current.Use();
  983. }
  984. if (Event.current.type == EventType.KeyDown)
  985. {
  986. if (PWBSettings.shortcuts.pinMoveHandlesUp.Check()) _pinOffset = nextBoundLayer;
  987. else if (PWBSettings.shortcuts.pinMoveHandlesDown.Check()) _pinOffset = prevBoundLayer;
  988. else if (PWBSettings.shortcuts.pinSelectNextHandle.Check()) _pinOffset = nextBoundPoint;
  989. else if (PWBSettings.shortcuts.pinSelectPrevHandle.Check()) _pinOffset = prevBoundPoint;
  990. else if (PWBSettings.shortcuts.pinSelectPivotHandle.Check()) _pinOffset = pivotBoundPoint;
  991. //add rotation around Y
  992. else if (PWBSettings.shortcuts.pinRotate90YCW.Check()) _pinAngle.y = (_pinAngle.y + 90) % 360;
  993. else if (PWBSettings.shortcuts.pinRotate90YCCW.Check()) _pinAngle.y = (_pinAngle.y - 90) % 360;
  994. else if (PWBSettings.shortcuts.pinRotateAStepYCW.Check()) _pinAngle.y -= PinManager.rotationSnapValue;
  995. else if (PWBSettings.shortcuts.pinRotateAStepYCCW.Check()) _pinAngle.y += PinManager.rotationSnapValue;
  996. //add rotation around X
  997. else if (PWBSettings.shortcuts.pinRotate90XCW.Check()) _pinAngle.x = (_pinAngle.x + 90) % 360;
  998. else if (PWBSettings.shortcuts.pinRotate90XCCW.Check()) _pinAngle.x = (_pinAngle.x - 90) % 360;
  999. else if (PWBSettings.shortcuts.pinRotateAStepXCW.Check()) _pinAngle.x -= PinManager.rotationSnapValue;
  1000. else if (PWBSettings.shortcuts.pinRotateAStepXCCW.Check()) _pinAngle.x += PinManager.rotationSnapValue;
  1001. //add rotation around Z
  1002. else if (PWBSettings.shortcuts.pinRotate90ZCW.Check()) _pinAngle.z = (_pinAngle.z + 90) % 360;
  1003. else if (PWBSettings.shortcuts.pinRotate90ZCCW.Check()) _pinAngle.z = (_pinAngle.z - 90) % 360;
  1004. else if (PWBSettings.shortcuts.pinRotateAStepZCW.Check()) _pinAngle.z -= PinManager.rotationSnapValue;
  1005. else if (PWBSettings.shortcuts.pinRotateAStepZCCW.Check()) _pinAngle.z += PinManager.rotationSnapValue;
  1006. //reset rotation
  1007. else if (PWBSettings.shortcuts.pinResetRotation.Check()) _pinAngle = Vector3.zero;
  1008. else if (PWBSettings.shortcuts.pinSnapRotationToGrid.Check())
  1009. {
  1010. snapPinRotationToGrid = true;
  1011. sceneView.Repaint();
  1012. repaint = true;
  1013. }
  1014. //distance to surface
  1015. else if (PWBSettings.shortcuts.pinSubtract1UnitFromSurfDist.Check()) _pinDistanceFromSurface -= 1f;
  1016. else if (PWBSettings.shortcuts.pinAdd1UnitToSurfDist.Check()) _pinDistanceFromSurface += 1f;
  1017. else if (PWBSettings.shortcuts.pinSubtract01UnitFromSurfDist.Check()) _pinDistanceFromSurface -= 0.1f;
  1018. else if (PWBSettings.shortcuts.pinAdd01UnitToSurfDist.Check()) _pinDistanceFromSurface += 0.1f;
  1019. else if (PWBSettings.shortcuts.pinResetSurfDist.Check()) _pinDistanceFromSurface = 0;
  1020. else if (PWBSettings.shortcuts.pinResetScale.Check()) UpdatePinScale(1f);
  1021. //Flip
  1022. else if (PWBSettings.shortcuts.pinFlipX.Check()) _pinFlipX = !_pinFlipX;
  1023. else if (PWBSettings.shortcuts.pinToggleRepeatItem.Check())
  1024. {
  1025. PinManager.settings.repeat = !PinManager.settings.repeat;
  1026. ToolProperties.RepainWindow();
  1027. }
  1028. else if (PWBSettings.shortcuts.pinSelectPreviousItem.Check())
  1029. {
  1030. BrushstrokeManager.SetNextPinBrushstroke(-1);
  1031. sceneView.Repaint();
  1032. repaint = true;
  1033. }
  1034. else if (PWBSettings.shortcuts.pinSelectNextItem.Check())
  1035. {
  1036. BrushstrokeManager.SetNextPinBrushstroke(1);
  1037. sceneView.Repaint();
  1038. repaint = true;
  1039. }
  1040. }
  1041. }
  1042. else
  1043. {
  1044. if (Event.current.type == EventType.MouseDown && Event.current.control)
  1045. {
  1046. _pinned = true;
  1047. _pinMouse = Event.current.mousePosition;
  1048. _previousPinAngle = _pinAngle;
  1049. Event.current.Use();
  1050. }
  1051. else if (Event.current.type == EventType.MouseUp && !Event.current.control) _pinned = false;
  1052. }
  1053. const float DEG_PER_PIXEL = 1.8f; //180deg/100px
  1054. if (PWBSettings.shortcuts.pinSelectNextItemScroll.Check())
  1055. {
  1056. var scrollSign = Mathf.Sign(Event.current.delta.y);
  1057. Event.current.Use();
  1058. BrushstrokeManager.SetNextPinBrushstroke((int)scrollSign);
  1059. sceneView.Repaint();
  1060. repaint = true;
  1061. }
  1062. else if (PWBSettings.shortcuts.pinRotateAroundY.Check())
  1063. {
  1064. var combi = PWBSettings.shortcuts.pinRotateAroundY.combination;
  1065. if (combi.mouseEvent == PWBMouseCombination.MouseEvents.SCROLL_WHEEL) _pinAngle.y += combi.delta;
  1066. else if (combi.isMouseDragEvent) _pinAngle.y -= combi.delta * DEG_PER_PIXEL;
  1067. _previousPinAngle = _pinAngle;
  1068. }
  1069. else if (PWBSettings.shortcuts.pinRotateAroundYSnaped.Check())
  1070. {
  1071. var combi = PWBSettings.shortcuts.pinRotateAroundYSnaped.combination;
  1072. if (combi.mouseEvent == PWBMouseCombination.MouseEvents.SCROLL_WHEEL)
  1073. {
  1074. var scrollSign = Mathf.Sign(Event.current.delta.y);
  1075. _pinAngle.y += scrollSign * PinManager.rotationSnapValue;
  1076. }
  1077. else if (combi.isMouseDragEvent)
  1078. {
  1079. _pinAngle.y = _previousPinAngle.y - combi.delta * DEG_PER_PIXEL;
  1080. _previousPinAngle.y = _pinAngle.y;
  1081. if (PinManager.rotationSnapValue > 0)
  1082. _pinAngle.y = Mathf.Round(_pinAngle.y / PinManager.rotationSnapValue) * PinManager.rotationSnapValue;
  1083. }
  1084. }
  1085. else if (PWBSettings.shortcuts.pinRotateAroundX.Check())
  1086. {
  1087. var combi = PWBSettings.shortcuts.pinRotateAroundX.combination;
  1088. if (combi.mouseEvent == PWBMouseCombination.MouseEvents.SCROLL_WHEEL) _pinAngle.x += Event.current.delta.y;
  1089. else if (combi.isMouseDragEvent) _pinAngle.x -= combi.delta * DEG_PER_PIXEL;
  1090. _previousPinAngle = _pinAngle;
  1091. }
  1092. else if (PWBSettings.shortcuts.pinRotateAroundXSnaped.Check())
  1093. {
  1094. var combi = PWBSettings.shortcuts.pinRotateAroundXSnaped.combination;
  1095. if (combi.mouseEvent == PWBMouseCombination.MouseEvents.SCROLL_WHEEL)
  1096. {
  1097. var scrollSign = Mathf.Sign(Event.current.delta.y);
  1098. _pinAngle.x += scrollSign * PinManager.rotationSnapValue;
  1099. }
  1100. else if (combi.isMouseDragEvent)
  1101. {
  1102. _pinAngle.x = _previousPinAngle.x + combi.delta * DEG_PER_PIXEL;
  1103. _previousPinAngle.x = _pinAngle.x;
  1104. if (PinManager.rotationSnapValue > 0)
  1105. _pinAngle.x = Mathf.Round(_pinAngle.x / PinManager.rotationSnapValue) * PinManager.rotationSnapValue;
  1106. }
  1107. }
  1108. else if (PWBSettings.shortcuts.pinRotateAroundZ.Check())
  1109. {
  1110. var combi = PWBSettings.shortcuts.pinRotateAroundZ.combination;
  1111. if (combi.mouseEvent == PWBMouseCombination.MouseEvents.SCROLL_WHEEL) _pinAngle.z += Event.current.delta.y;
  1112. else if (combi.isMouseDragEvent) _pinAngle.z -= combi.delta * DEG_PER_PIXEL;
  1113. _previousPinAngle = _pinAngle;
  1114. }
  1115. else if (PWBSettings.shortcuts.pinRotateAroundZSnaped.Check())
  1116. {
  1117. var combi = PWBSettings.shortcuts.pinRotateAroundZSnaped.combination;
  1118. if (combi.mouseEvent == PWBMouseCombination.MouseEvents.SCROLL_WHEEL)
  1119. {
  1120. var scrollSign = Mathf.Sign(Event.current.delta.y);
  1121. _pinAngle.z += scrollSign * PinManager.rotationSnapValue;
  1122. }
  1123. else if (combi.isMouseDragEvent)
  1124. {
  1125. _pinAngle.z = _previousPinAngle.z + combi.delta * DEG_PER_PIXEL;
  1126. _previousPinAngle.z = _pinAngle.z;
  1127. if (PinManager.rotationSnapValue > 0)
  1128. _pinAngle.z = Mathf.Round(_pinAngle.z / PinManager.rotationSnapValue) * PinManager.rotationSnapValue;
  1129. }
  1130. }
  1131. else if (PWBSettings.shortcuts.pinSurfDist.Check())
  1132. {
  1133. var combi = PWBSettings.shortcuts.pinSurfDist.combination;
  1134. if (combi.mouseEvent == PWBMouseCombination.MouseEvents.SCROLL_WHEEL)
  1135. _pinDistanceFromSurface += Event.current.delta.y * 0.04f;
  1136. else if (combi.isMouseDragEvent) _pinDistanceFromSurface += combi.delta * 0.04f;
  1137. }
  1138. else if (PWBSettings.shortcuts.pinScale.Check())
  1139. {
  1140. if (PWBSettings.shortcuts.pinScale.combination.mouseEvent == PWBMouseCombination.MouseEvents.SCROLL_WHEEL)
  1141. {
  1142. var scrollSign = Mathf.Sign(Event.current.delta.y);
  1143. UpdatePinScale(Mathf.Max(_pinScale * (1f + scrollSign * 0.05f), 0.01f));
  1144. sceneView.Repaint();
  1145. repaint = true;
  1146. }
  1147. else if (PWBSettings.shortcuts.pinScale.combination.isMouseDragEvent)
  1148. {
  1149. UpdatePinScale(Mathf.Max(_pinScale * (1f + PWBSettings.shortcuts.pinScale.combination.delta * 0.003f),
  1150. 0.01f));
  1151. sceneView.Repaint();
  1152. repaint = true;
  1153. }
  1154. }
  1155. if ((keyCode == KeyCode.LeftControl || keyCode == KeyCode.RightControl)
  1156. && Event.current.type == EventType.KeyUp) _pinned = false;
  1157. }
  1158. private static void DrawPinHandles(Color color)
  1159. {
  1160. if (BrushstrokeManager.brushstroke.Length == 0) return;
  1161. var strokeItem = BrushstrokeManager.brushstroke[0];
  1162. var prefab = strokeItem.settings.prefab;
  1163. if (prefab == null) return;
  1164. var pos = Vector3.zero;
  1165. var prevPos = Vector3.zero;
  1166. var pos0 = Vector3.zero;
  1167. var handlePoints = new System.Collections.Generic.List<Vector3>();
  1168. UnityEditor.Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
  1169. if (_pinBoundPoints.Count == 0) ResetPinValues();
  1170. var flatteningPoints = new System.Collections.Generic.List<Vector3>();
  1171. var layerIdx = Mathf.Clamp(_pinBoundLayerIdx, 0, _pinBoundPoints.Count - 1);
  1172. var pivotPos = Vector3.zero;
  1173. for (int i = 0; i < _pinBoundPoints[layerIdx].Count; ++i)
  1174. {
  1175. prevPos = pos;
  1176. pos = _pinOffset - _pinBoundPoints[layerIdx][i] + _pinHit.point;
  1177. if (i > _pinBoundPoints[layerIdx].Count - 5)
  1178. {
  1179. if (i == _pinBoundPoints[layerIdx].Count - 4) pos0 = pos;
  1180. else if (i < _pinBoundPoints[layerIdx].Count)
  1181. {
  1182. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.7f);
  1183. UnityEditor.Handles.DrawAAPolyLine(6, new Vector3[] { prevPos, pos });
  1184. UnityEditor.Handles.color = color;
  1185. UnityEditor.Handles.DrawAAPolyLine(2, new Vector3[] { prevPos, pos });
  1186. }
  1187. }
  1188. flatteningPoints.Add(pos);
  1189. if (i == 0) pivotPos = pos;
  1190. if (_pinBoundPointIdx == i) continue;
  1191. handlePoints.Add(pos);
  1192. }
  1193. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.7f);
  1194. UnityEditor.Handles.DrawAAPolyLine(6, new Vector3[] { pos, pos0 });
  1195. UnityEditor.Handles.color = color;
  1196. UnityEditor.Handles.DrawAAPolyLine(2, new Vector3[] { pos, pos0 });
  1197. if (PinManager.settings.flattenTerrain && _pinHit.collider != null
  1198. && _pinHit.collider.GetComponent<Terrain>() != null)
  1199. {
  1200. Vector3 p0, p1, p2, p3;
  1201. var n = flatteningPoints.Count;
  1202. var side1_2 = flatteningPoints[n - 3] - flatteningPoints[n - 4];
  1203. var side2_3 = flatteningPoints[n - 2] - flatteningPoints[n - 3];
  1204. var dir1_2 = side1_2.normalized;
  1205. var dir2_3 = side2_3.normalized;
  1206. p0 = flatteningPoints[n - 4] + (-dir1_2 - dir2_3) * PinManager.settings.flatteningSettings.padding;
  1207. p1 = flatteningPoints[n - 3] + (dir1_2 - dir2_3) * PinManager.settings.flatteningSettings.padding;
  1208. p2 = flatteningPoints[n - 2] + (dir1_2 + dir2_3) * PinManager.settings.flatteningSettings.padding;
  1209. p3 = flatteningPoints[n - 1] + (-dir1_2 + dir2_3) * PinManager.settings.flatteningSettings.padding;
  1210. p0.y = p1.y = p2.y = p3.y = _pinHit.point.y;
  1211. _flatteningCenter = (p2 - p0) / 2 + p0;
  1212. UnityEditor.Handles.color = new Color(0.5f, 0f, 1f, 0.7f);
  1213. UnityEditor.Handles.DrawAAPolyLine(6, new Vector3[] { p0, p1, p2, p3, p0 });
  1214. UnityEditor.Handles.color = new Color(0f, 0.5f, 1f, 0.7f);
  1215. UnityEditor.Handles.DrawAAPolyLine(2, new Vector3[] { p0, p1, p2, p3, p0 });
  1216. }
  1217. foreach (var handlePoint in handlePoints)
  1218. {
  1219. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.7f);
  1220. UnityEditor.Handles.DotHandleCap(795, handlePoint, Quaternion.identity,
  1221. UnityEditor.HandleUtility.GetHandleSize(pos) * 0.0325f * PWBCore.staticData.controPointSize,
  1222. EventType.Repaint);
  1223. UnityEditor.Handles.color = UnityEditor.Handles.preselectionColor;
  1224. UnityEditor.Handles.DotHandleCap(795, handlePoint, Quaternion.identity,
  1225. UnityEditor.HandleUtility.GetHandleSize(pos) * 0.02f * PWBCore.staticData.controPointSize,
  1226. EventType.Repaint);
  1227. }
  1228. var pinHitPoint = _pinHit.point;
  1229. UnityEditor.Handles.color = new Color(0f, 0f, 0f, 0.7f);
  1230. UnityEditor.Handles.DotHandleCap(418, pinHitPoint, Quaternion.identity,
  1231. UnityEditor.HandleUtility.GetHandleSize(pinHitPoint) * 0.0425f * PWBCore.staticData.controPointSize,
  1232. EventType.Repaint);
  1233. if (pinHitPoint != pivotPos)
  1234. {
  1235. UnityEditor.Handles.color = UnityEditor.Handles.selectedColor;
  1236. UnityEditor.Handles.DotHandleCap(418, pinHitPoint, Quaternion.identity,
  1237. UnityEditor.HandleUtility.GetHandleSize(pinHitPoint) * 0.03f * PWBCore.staticData.controPointSize,
  1238. EventType.Repaint);
  1239. }
  1240. UnityEditor.Handles.color = Color.green;
  1241. UnityEditor.Handles.DotHandleCap(418, pivotPos, Quaternion.identity,
  1242. UnityEditor.HandleUtility.GetHandleSize(pivotPos) * (pinHitPoint == pivotPos ? 0.03f : 0.02f)
  1243. * PWBCore.staticData.controPointSize, EventType.Repaint);
  1244. }
  1245. }
  1246. #endregion
  1247. }