BrushstrokeManager.cs 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551
  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. #region ITEM
  18. public struct BrushstrokeObject : System.IEquatable<BrushstrokeObject>
  19. {
  20. public readonly int objIdx;
  21. public readonly Vector3 objPosition;
  22. public readonly Quaternion objRotation;
  23. public readonly Vector3 additionalAngle;
  24. public readonly Vector3 objScale;
  25. public readonly bool flipX;
  26. public readonly bool flipY;
  27. public readonly float surfaceDistance;
  28. public readonly Vector3 brushstrokeDirection;
  29. public BrushstrokeObject(int objIdx, Vector3 objPosition, Quaternion objRotation, Vector3 additionalAngle,
  30. Vector3 objScale, bool flipX, bool flipY, float surfaceDistance, Vector3 brushstrokeDirection)
  31. {
  32. this.objIdx = objIdx;
  33. this.objPosition = objPosition;
  34. this.objRotation = objRotation;
  35. this.additionalAngle = additionalAngle;
  36. this.objScale = objScale;
  37. this.flipX = flipX;
  38. this.flipY = flipY;
  39. this.surfaceDistance = surfaceDistance;
  40. this.brushstrokeDirection = brushstrokeDirection;
  41. }
  42. public BrushstrokeObject Clone()
  43. {
  44. var clone = new BrushstrokeObject(objIdx, objPosition, objRotation, additionalAngle,
  45. objScale, flipX, flipY, surfaceDistance, brushstrokeDirection);
  46. return clone;
  47. }
  48. public bool Equals(BrushstrokeObject other)
  49. {
  50. return objPosition == other.objPosition && objRotation == other.objRotation
  51. && additionalAngle == other.additionalAngle && objScale == other.objScale
  52. && flipX == other.flipX && flipY == other.flipY && surfaceDistance == other.surfaceDistance
  53. && brushstrokeDirection == other.brushstrokeDirection;
  54. }
  55. public static bool operator ==(BrushstrokeObject lhs, BrushstrokeObject rhs) => lhs.Equals(rhs);
  56. public static bool operator !=(BrushstrokeObject lhs, BrushstrokeObject rhs) => !lhs.Equals(rhs);
  57. public override bool Equals(object obj) => obj is BrushstrokeObject other && Equals(other);
  58. public override int GetHashCode()
  59. {
  60. int hashCode = 861157388;
  61. hashCode = hashCode * -1521134295 + objIdx.GetHashCode();
  62. hashCode = hashCode * -1521134295 + objPosition.GetHashCode();
  63. hashCode = hashCode * -1521134295 + objRotation.GetHashCode();
  64. hashCode = hashCode * -1521134295 + additionalAngle.GetHashCode();
  65. hashCode = hashCode * -1521134295 + objScale.GetHashCode();
  66. hashCode = hashCode * -1521134295 + flipX.GetHashCode();
  67. hashCode = hashCode * -1521134295 + flipY.GetHashCode();
  68. hashCode = hashCode * -1521134295 + surfaceDistance.GetHashCode();
  69. hashCode = hashCode * -1521134295 + brushstrokeDirection.GetHashCode();
  70. return hashCode;
  71. }
  72. }
  73. public struct BrushstrokeItem : System.IEquatable<BrushstrokeItem>
  74. {
  75. public readonly MultibrushItemSettings settings;
  76. public readonly Vector3 tangentPosition;
  77. public readonly Vector3 additionalAngle;
  78. public readonly Vector3 scaleMultiplier;
  79. public Vector3 nextTangentPosition;
  80. public readonly bool flipX;
  81. public readonly bool flipY;
  82. public readonly float surfaceDistance;
  83. public readonly int index;
  84. public readonly int tokenIndex;
  85. public BrushstrokeItem(int index, int tokenIndex, MultibrushItemSettings settings, Vector3 tangentPosition,
  86. Vector3 additionalAngle,Vector3 scaleMultiplier, bool flipX, bool flipY, float surfaceDistance)
  87. {
  88. this.settings = settings;
  89. this.tangentPosition = tangentPosition;
  90. this.additionalAngle = additionalAngle;
  91. this.scaleMultiplier = scaleMultiplier;
  92. nextTangentPosition = tangentPosition;
  93. this.flipX = flipX;
  94. this.flipY = flipY;
  95. this.surfaceDistance = surfaceDistance;
  96. this.index = index;
  97. this.tokenIndex = tokenIndex;
  98. }
  99. public BrushstrokeItem Clone()
  100. {
  101. var clone = new BrushstrokeItem(index, tokenIndex, settings, tangentPosition, additionalAngle,
  102. scaleMultiplier, flipX, flipY, surfaceDistance);
  103. clone.nextTangentPosition = nextTangentPosition;
  104. return clone;
  105. }
  106. public bool Equals(BrushstrokeItem other)
  107. {
  108. return settings == other.settings && tangentPosition == other.tangentPosition
  109. && additionalAngle == other.additionalAngle && scaleMultiplier == other.scaleMultiplier
  110. && nextTangentPosition == other.nextTangentPosition;
  111. }
  112. public static bool operator ==(BrushstrokeItem lhs, BrushstrokeItem rhs) => lhs.Equals(rhs);
  113. public static bool operator !=(BrushstrokeItem lhs, BrushstrokeItem rhs) => !lhs.Equals(rhs);
  114. public override bool Equals(object obj) => obj is BrushstrokeItem other && Equals(other);
  115. public override int GetHashCode()
  116. {
  117. int hashCode = 861157388;
  118. hashCode = hashCode * -1521134295
  119. + System.Collections.Generic.EqualityComparer<MultibrushItemSettings>.Default.GetHashCode(settings);
  120. hashCode = hashCode * -1521134295 + tangentPosition.GetHashCode();
  121. hashCode = hashCode * -1521134295 + additionalAngle.GetHashCode();
  122. hashCode = hashCode * -1521134295 + scaleMultiplier.GetHashCode();
  123. hashCode = hashCode * -1521134295 + nextTangentPosition.GetHashCode();
  124. hashCode = hashCode * -1521134295 + flipX.GetHashCode();
  125. hashCode = hashCode * -1521134295 + flipY.GetHashCode();
  126. hashCode = hashCode * -1521134295 + surfaceDistance.GetHashCode();
  127. return hashCode;
  128. }
  129. }
  130. #endregion
  131. public static class BrushstrokeManager
  132. {
  133. #region COMMON
  134. private static System.Collections.Generic.List<BrushstrokeItem> _brushstroke
  135. = new System.Collections.Generic.List<BrushstrokeItem>();
  136. public static BrushstrokeItem[] brushstroke => _brushstroke.ToArray();
  137. public static int itemCount => _brushstroke.Count;
  138. public static void ClearBrushstroke() => _brushstroke.Clear();
  139. public static BrushstrokeItem[] brushstrokeClone
  140. {
  141. get
  142. {
  143. var clone = new BrushstrokeItem[_brushstroke.Count];
  144. for (int i = 0; i < clone.Length; ++i) clone[i] = _brushstroke[i].Clone();
  145. return clone;
  146. }
  147. }
  148. public static bool BrushstrokeEqual(BrushstrokeItem[] lhs, BrushstrokeItem[] rhs)
  149. {
  150. if (lhs.Length != rhs.Length) return false;
  151. for (int i = 0; i < lhs.Length; ++i)
  152. if (lhs[i] != rhs[i]) return false;
  153. return true;
  154. }
  155. private static void AddBrushstrokeItem(int index, int tokenIndex, Vector3 tangentPosition,
  156. Vector3 angle, Vector3 scale, IPaintToolSettings paintToolSettings)
  157. {
  158. if (index < 0 || index >= PaletteManager.selectedBrush.itemCount) return;
  159. var multiBrushSettings = PaletteManager.selectedBrush;
  160. BrushSettings brushSettings = multiBrushSettings.items[index];
  161. if (paintToolSettings != null && paintToolSettings.overwriteBrushProperties)
  162. brushSettings = paintToolSettings.brushSettings;
  163. var additonalAngle = (Quaternion.Euler(angle) * Quaternion.Euler(brushSettings.GetAdditionalAngle())).eulerAngles;
  164. var flipX = brushSettings.GetFlipX();
  165. var flipY = brushSettings.GetFlipY();
  166. var surfaceDistance = brushSettings.GetSurfaceDistance();
  167. var strokeItem = new BrushstrokeItem(index, tokenIndex,
  168. PaletteManager.selectedBrush.items[index], tangentPosition, additonalAngle,
  169. scale, flipX, flipY, surfaceDistance);
  170. if (_brushstroke.Count > 0)
  171. {
  172. var last = _brushstroke.Last();
  173. last.nextTangentPosition = tangentPosition;
  174. _brushstroke[_brushstroke.Count - 1] = last;
  175. }
  176. _brushstroke.Add(strokeItem);
  177. }
  178. private static Vector3 ScaleMultiplier(int itemIdx, IPaintToolSettings settings)
  179. {
  180. if (settings.overwriteBrushProperties) return settings.brushSettings.GetScaleMultiplier();
  181. if (PaletteManager.selectedBrush != null)
  182. {
  183. var nextItem = PaletteManager.selectedBrush.items[itemIdx];
  184. return nextItem.GetScaleMultiplier();
  185. }
  186. return Vector3.one;
  187. }
  188. public static void UpdateBrushstroke(bool brushChange = false)
  189. {
  190. if (ToolManager.tool == ToolManager.PaintTool.SELECTION) return;
  191. if (ToolManager.tool == ToolManager.PaintTool.LINE
  192. || ToolManager.tool == ToolManager.PaintTool.SHAPE
  193. || ToolManager.tool == ToolManager.PaintTool.TILING)
  194. {
  195. PWBIO.UpdateStroke();
  196. return;
  197. }
  198. if (!brushChange && ToolManager.tool == ToolManager.PaintTool.PIN && PinManager.settings.repeat) return;
  199. _brushstroke.Clear();
  200. if (PaletteManager.selectedBrush == null) return;
  201. if (ToolManager.tool == ToolManager.PaintTool.BRUSH) UpdateBrushBaseStroke(BrushManager.settings);
  202. else if (ToolManager.tool == ToolManager.PaintTool.GRAVITY) UpdateBrushBaseStroke(GravityToolManager.settings);
  203. else if (ToolManager.tool == ToolManager.PaintTool.PIN) UpdateSingleBrushstroke(PinManager.settings);
  204. else if (ToolManager.tool == ToolManager.PaintTool.REPLACER) _brushstroke.Clear();
  205. else if (ToolManager.tool == ToolManager.PaintTool.FLOOR) UpdateFloorBrushstroke(setNextIdx: false);
  206. else if (ToolManager.tool == ToolManager.PaintTool.WALL)
  207. UpdateWallBrushstroke(WallManager.wallLenghtAxis, cellsCount: 1, setNextIdx: false, deleteMode: false);
  208. }
  209. #endregion
  210. #region LINE
  211. public static float _minLineSpacing = float.MaxValue;
  212. public static float GetLineSpacing(int itemIdx, LineSettings settings, Vector3 scaleMult)
  213. {
  214. float spacing = 0;
  215. if (itemIdx >= 0) spacing = settings.spacing;
  216. if (settings.spacingType == LineSettings.SpacingType.BOUNDS && itemIdx >= 0)
  217. {
  218. var item = PaletteManager.selectedBrush.items[itemIdx];
  219. if (item.prefab == null) return spacing;
  220. var bounds = BoundsUtils.GetBoundsRecursive(item.prefab.transform);
  221. var size = Vector3.Scale(bounds.size, scaleMult);
  222. var axis = settings.axisOrientedAlongTheLine;
  223. if (item.isAsset2D && UnityEditor.SceneView.currentDrawingSceneView.in2DMode
  224. && axis == AxesUtils.Axis.Z) axis = AxesUtils.Axis.Y;
  225. spacing = AxesUtils.GetAxisValue(size, axis);
  226. if (spacing <= 0.0001) spacing = 0.5f;
  227. }
  228. spacing += settings.gapSize;
  229. _minLineSpacing = Mathf.Min(spacing, _minLineSpacing);
  230. return spacing;
  231. }
  232. private static void UpdateLineBrushstroke(Vector3[] points, LineSettings settings)
  233. {
  234. _brushstroke.Clear();
  235. if (PaletteManager.selectedBrush == null) return;
  236. float lineLength = 0f;
  237. var lengthFromFirstPoint = new float[points.Length];
  238. var segmentLength = new float[points.Length];
  239. lengthFromFirstPoint[0] = 0f;
  240. for (int i = 1; i < points.Length; ++i)
  241. {
  242. segmentLength[i - 1] = (points[i] - points[i - 1]).magnitude;
  243. lineLength += segmentLength[i - 1];
  244. lengthFromFirstPoint[i] = lineLength;
  245. }
  246. float length = 0f;
  247. int segment = 0;
  248. if (PaletteManager.selectedBrush.patternMachine != null)
  249. PaletteManager.selectedBrush.patternMachine.Reset();
  250. var prefabSpacingDictionary = new System.Collections.Generic.Dictionary<(int, Vector3), float>();
  251. var brush = PaletteManager.selectedBrush;
  252. float Spacing(int itemIdx, Vector3 scale)
  253. {
  254. float spacing = 0;
  255. var item = brush.items[itemIdx];
  256. if (settings.spacingType == LineSettings.SpacingType.BOUNDS)
  257. {
  258. var key = (itemIdx, scale);
  259. if (item.randomScaleMultiplier) spacing = GetLineSpacing(itemIdx, settings, scale);
  260. else if (prefabSpacingDictionary.ContainsKey(key)) spacing = prefabSpacingDictionary[key];
  261. else
  262. {
  263. spacing = GetLineSpacing(itemIdx, settings, scale);
  264. prefabSpacingDictionary.Add(key, spacing);
  265. }
  266. }
  267. else spacing = GetLineSpacing(itemIdx, settings, scale);
  268. return spacing;
  269. }
  270. float endLenght = 0f;
  271. int[] endIndexes = null;
  272. if (brush.frequencyMode == MultibrushSettings.FrequencyMode.PATTERN)
  273. {
  274. endIndexes = brush.patternMachine.GetEndIndexes();
  275. foreach (var i in endIndexes)
  276. {
  277. var idx = i - 1;
  278. var item = brush.items[idx];
  279. var scale = ScaleMultiplier(idx, LineManager.settings);
  280. endLenght += Spacing(idx, scale);
  281. }
  282. }
  283. int currentEndIdx = 0;
  284. bool useEndIndexes = false;
  285. do
  286. {
  287. var nextIdx = brush.nextItemIndex;
  288. if (nextIdx < 0) break;
  289. if (useEndIndexes)
  290. {
  291. if (currentEndIdx >= endIndexes.Length) break;
  292. nextIdx = endIndexes[currentEndIdx] - 1;
  293. ++currentEndIdx;
  294. if (currentEndIdx == 1 && endIndexes.Length > 1)
  295. {
  296. while (endLenght > lineLength - length)
  297. {
  298. nextIdx = endIndexes[currentEndIdx] - 1;
  299. var s = ScaleMultiplier(nextIdx, LineManager.settings);
  300. endLenght -= Spacing(nextIdx, s);
  301. ++currentEndIdx;
  302. if (currentEndIdx >= endIndexes.Length) break;
  303. }
  304. if (currentEndIdx >= endIndexes.Length) break;
  305. }
  306. }
  307. while (lengthFromFirstPoint[segment + 1] < length)
  308. {
  309. ++segment;
  310. if (segment >= points.Length - 1) break;
  311. }
  312. if (segment >= points.Length - 1) break;
  313. var segmentDirection = (points[segment + 1] - points[segment]).normalized;
  314. var distance = length - lengthFromFirstPoint[segment];
  315. var position = points[segment] + segmentDirection * distance;
  316. var scale = ScaleMultiplier(nextIdx, LineManager.settings);
  317. float spacing = Spacing(nextIdx, scale);
  318. var delta = Mathf.Max(spacing, _minLineSpacing);
  319. if (delta <= 0) break;
  320. spacing = Mathf.Max(spacing, _minLineSpacing);
  321. if (!useEndIndexes && brush.frequencyMode == MultibrushSettings.FrequencyMode.PATTERN
  322. && endLenght > 0 && length + spacing > lineLength - endLenght && currentEndIdx == 0)
  323. {
  324. useEndIndexes = true;
  325. continue;
  326. }
  327. length += spacing;
  328. if (length > lineLength) break;
  329. AddBrushstrokeItem(nextIdx, PaletteManager.selectedBrush.GetPatternTokenIndex(), position,
  330. angle: Vector3.zero, scale, settings);
  331. } while (length < lineLength);
  332. }
  333. public static void UpdateLineBrushstroke(Vector3[] pathPoints)
  334. => UpdateLineBrushstroke(pathPoints, LineManager.settings);
  335. private static float GetLineSpacing(Transform transform, LineSettings settings, Vector3 scale, bool useDictionary)
  336. {
  337. float spacing = settings.spacing;
  338. if (settings.spacingType == LineSettings.SpacingType.BOUNDS && transform != null)
  339. {
  340. var bounds = BoundsUtils.GetBoundsRecursive(transform, transform.rotation, ignoreDissabled: false,
  341. BoundsUtils.ObjectProperty.BOUNDING_BOX, recursive: true, useDictionary);
  342. var size = Vector3.Scale(bounds.size, scale);
  343. var axis = settings.axisOrientedAlongTheLine;
  344. if (Utils2D.Is2DAsset(transform.gameObject) && UnityEditor.SceneView.currentDrawingSceneView != null
  345. && UnityEditor.SceneView.currentDrawingSceneView.in2DMode && axis == AxesUtils.Axis.Z)
  346. axis = AxesUtils.Axis.Y;
  347. spacing = AxesUtils.GetAxisValue(size, axis);
  348. }
  349. spacing += settings.gapSize;
  350. _minLineSpacing = Mathf.Min(spacing, _minLineSpacing);
  351. return spacing;
  352. }
  353. public static void UpdatePersistentLineBrushstroke(Vector3[] pathPoints,
  354. LineSettings toolSettings, System.Collections.Generic.List<GameObject> lineObjects,
  355. out BrushstrokeObject[] objPositions, out Vector3[] strokePositions, out int firstNewObjectIdx)
  356. {
  357. _brushstroke.Clear();
  358. firstNewObjectIdx = 0;
  359. var objPositionsList = new System.Collections.Generic.List<BrushstrokeObject>();
  360. var strokePositionsList = new System.Collections.Generic.List<Vector3>();
  361. float lineLength = 0f;
  362. var lengthFromFirstPoint = new float[pathPoints.Length];
  363. var segmentLength = new float[pathPoints.Length];
  364. lengthFromFirstPoint[0] = 0f;
  365. for (int i = 1; i < pathPoints.Length; ++i)
  366. {
  367. segmentLength[i - 1] = (pathPoints[i] - pathPoints[i - 1]).magnitude;
  368. lineLength += segmentLength[i - 1];
  369. lengthFromFirstPoint[i] = lineLength;
  370. }
  371. float length = 0f;
  372. int segment = 0;
  373. if (PaletteManager.selectedBrush != null)
  374. if (PaletteManager.selectedBrush.patternMachine != null)
  375. PaletteManager.selectedBrush.patternMachine.Reset();
  376. int objIdx = 0;
  377. var prefabSpacingDictionary = new System.Collections.Generic.Dictionary<(int, Vector3), float>();
  378. var brush = PaletteManager.selectedBrush;
  379. float endLenght = 0f;
  380. int BeginningObjectCount = lineObjects.Count;
  381. int endingObjectCount = 0;
  382. var brushSettings = toolSettings.overwriteBrushProperties ? toolSettings.brushSettings
  383. : PaletteManager.selectedBrush;
  384. Vector3 BrushScaleMultiplier() => (LineManager.instance.applyBrushToExisting
  385. && PaletteManager.selectedBrush != null) ? brushSettings.GetScaleMultiplier() : Vector3.one;
  386. if (brush != null && brush.frequencyMode == MultibrushSettings.FrequencyMode.PATTERN)
  387. {
  388. var endIndexes = brush.patternMachine.GetEndIndexes();
  389. endingObjectCount = Mathf.Min(endIndexes.Length, lineObjects.Count);
  390. BeginningObjectCount = lineObjects.Count - endingObjectCount;
  391. for (int i = 0; i < endingObjectCount; ++i)
  392. {
  393. var obj = lineObjects[lineObjects.Count - 1 - i];
  394. var prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(obj);
  395. endLenght += GetLineSpacing(prefab.transform, toolSettings, BrushScaleMultiplier(), useDictionary: true);
  396. }
  397. endLenght = Mathf.Min(endLenght, lineLength);
  398. }
  399. var itemCount = 0;
  400. float newItemSpacing(int itemIdx, Vector3 scale)
  401. {
  402. if (PaletteManager.selectedBrush == null)
  403. {
  404. if (Mathf.Approximately(_minLineSpacing, float.MaxValue)) return 0f;
  405. return _minLineSpacing;
  406. }
  407. var item = PaletteManager.selectedBrush.items[itemIdx];
  408. var key = (itemIdx, scale);
  409. if (toolSettings.spacingType == LineSettings.SpacingType.BOUNDS && itemIdx >= 0)
  410. {
  411. if (item.randomScaleMultiplier) return GetLineSpacing(itemIdx, toolSettings, scale);
  412. else if (prefabSpacingDictionary.ContainsKey(key)) return prefabSpacingDictionary[key];
  413. else
  414. {
  415. var spacing = GetLineSpacing(itemIdx, toolSettings, scale);
  416. prefabSpacingDictionary.Add(key, spacing);
  417. return spacing;
  418. }
  419. }
  420. else return GetLineSpacing(itemIdx, toolSettings, scale);
  421. }
  422. var prevAtTheEnd = false;
  423. bool firstNewObjectAdded = false;
  424. do
  425. {
  426. var nextIdx = PaletteManager.selectedBrush != null ? PaletteManager.selectedBrush.nextItemIndex : -1;
  427. while (lengthFromFirstPoint[segment + 1] < length)
  428. {
  429. ++segment;
  430. if (segment >= pathPoints.Length - 1) break;
  431. }
  432. if (segment >= pathPoints.Length - 1) break;
  433. var segmentDirection = (pathPoints[segment + 1] - pathPoints[segment]).normalized;
  434. var distance = length - lengthFromFirstPoint[segment];
  435. var itemScaleMultiplier = ScaleMultiplier(nextIdx, LineManager.settings);
  436. var itemSpacing = newItemSpacing(nextIdx, itemScaleMultiplier);
  437. var isAtTheEnd = lineLength - length - itemSpacing <= endLenght;
  438. if (objIdx < lineObjects.Count && isAtTheEnd && !prevAtTheEnd)
  439. objIdx = lineObjects.Count - endingObjectCount;
  440. prevAtTheEnd = isAtTheEnd;
  441. var addExistingObject = objIdx < lineObjects.Count && (itemCount < BeginningObjectCount || isAtTheEnd);
  442. if (addExistingObject && lineObjects[objIdx] == null) addExistingObject = false;
  443. float spacing = 0;
  444. var objScale = Vector3.one;
  445. if (addExistingObject)
  446. {
  447. var obj = lineObjects[objIdx];
  448. if (LineManager.instance.applyBrushToExisting)
  449. {
  450. var brushScaleMultiplier = BrushScaleMultiplier();
  451. var prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(obj);
  452. spacing = GetLineSpacing(prefab.transform, toolSettings, brushScaleMultiplier, useDictionary: true);
  453. objScale = Vector3.Scale(prefab.transform.localScale, brushScaleMultiplier);
  454. }
  455. else
  456. {
  457. spacing = GetLineSpacing(obj.transform, toolSettings, Vector3.one, useDictionary: true);
  458. objScale = obj.transform.localScale;
  459. }
  460. }
  461. else if (PaletteManager.selectedBrush != null) spacing = itemSpacing;
  462. if (spacing == 0) break;
  463. spacing = Mathf.Max(spacing, _minLineSpacing);
  464. int nearestPathointIdx;
  465. var position = pathPoints[segment] + segmentDirection * distance;
  466. float distanceFromNearestPoint;
  467. var intersection = LineData.NearestPathPoint(segment, position, spacing, pathPoints, out nearestPathointIdx,
  468. out distanceFromNearestPoint);
  469. var startToEnd = intersection - position;
  470. var centerPosition = startToEnd / 2 + position;
  471. if (nearestPathointIdx > segment)
  472. spacing = (pathPoints[nearestPathointIdx] - position).magnitude
  473. + (intersection - pathPoints[nearestPathointIdx]).magnitude;
  474. length = Mathf.Max(length + spacing, lengthFromFirstPoint[nearestPathointIdx] + distanceFromNearestPoint);
  475. if (lineLength < length) break;
  476. if (addExistingObject)
  477. {
  478. var brushAdditionalAngle = Vector3.zero;
  479. bool brushFlipX = false;
  480. bool brushFlipY = false;
  481. var brushSurfaceDistance = 0f;
  482. if (LineManager.instance.applyBrushToExisting)
  483. {
  484. if (PaletteManager.selectedBrush != null)
  485. {
  486. brushAdditionalAngle = brushSettings.GetAdditionalAngle();
  487. brushFlipX = brushSettings.GetFlipX();
  488. brushFlipY = brushSettings.GetFlipY();
  489. brushSurfaceDistance = brushSettings.GetSurfaceDistance();
  490. }
  491. }
  492. var brushstrokeDirection = toolSettings.objectsOrientedAlongTheLine ? startToEnd.normalized : Vector3.left;
  493. objPositionsList.Add(new BrushstrokeObject(objIdx, centerPosition, objRotation: Quaternion.identity,
  494. brushAdditionalAngle, objScale, brushFlipX, brushFlipY, brushSurfaceDistance, brushstrokeDirection));
  495. ++objIdx;
  496. if (isAtTheEnd && objIdx >= lineObjects.Count) break;
  497. }
  498. else if (PaletteManager.selectedBrush == null) break;
  499. else
  500. {
  501. AddBrushstrokeItem(nextIdx, PaletteManager.selectedBrush == null ? 0
  502. : PaletteManager.selectedBrush.GetPatternTokenIndex(), position,
  503. angle: Vector3.zero, itemScaleMultiplier, LineManager.settings);
  504. strokePositionsList.Add(position);
  505. if (!firstNewObjectAdded)
  506. {
  507. firstNewObjectAdded = true;
  508. firstNewObjectIdx = itemCount;
  509. }
  510. }
  511. ++itemCount;
  512. } while (lineLength > length);
  513. objPositions = objPositionsList.ToArray();
  514. strokePositions = strokePositionsList.ToArray();
  515. }
  516. #endregion
  517. #region SHAPE
  518. public static void UpdateShapeBrushstroke()
  519. {
  520. _brushstroke.Clear();
  521. if (PaletteManager.selectedBrush == null) return;
  522. if (ShapeData.instance.state < ToolManager.ToolState.EDIT) return;
  523. var settings = ShapeManager.settings;
  524. var points = new System.Collections.Generic.List<Vector3>();
  525. var firstVertexIdx = ShapeData.instance.firstVertexIdxAfterIntersection;
  526. var lastVertexIdx = ShapeData.instance.lastVertexIdxBeforeIntersection;
  527. int sidesCount = settings.shapeType == ShapeSettings.ShapeType.POLYGON ? settings.sidesCount
  528. : ShapeData.instance.circleSideCount;
  529. int GetNextVertexIdx(int currentIdx) => currentIdx == sidesCount ? 1 : currentIdx + 1;
  530. int GetPrevVertexIdx(int currentIdx) => currentIdx == 1 ? sidesCount : currentIdx - 1;
  531. var firstPrev = GetPrevVertexIdx(firstVertexIdx);
  532. points.Add(ShapeData.instance.GetArcIntersection(0));
  533. if (lastVertexIdx != firstPrev || (lastVertexIdx == firstPrev && ShapeData.instance.arcAngle > 120))
  534. {
  535. var vertexIdx = firstVertexIdx;
  536. var nextVertexIdx = firstVertexIdx;
  537. do
  538. {
  539. vertexIdx = nextVertexIdx;
  540. points.Add(ShapeData.instance.GetPoint(vertexIdx));
  541. nextVertexIdx = GetNextVertexIdx(nextVertexIdx);
  542. } while (vertexIdx != lastVertexIdx);
  543. }
  544. var lastPoint = ShapeData.instance.GetArcIntersection(1);
  545. if (points.Last() != lastPoint) points.Add(lastPoint);
  546. var prefabSpacingDictionary = new System.Collections.Generic.Dictionary<(int, Vector3), float>();
  547. void AddItemsToLine(Vector3 start, Vector3 end, ref int nextIdx)
  548. {
  549. if (nextIdx < 0) nextIdx = PaletteManager.selectedBrush.nextItemIndex;
  550. var startToEnd = end - start;
  551. var lineLength = startToEnd.magnitude;
  552. float itemsSize = 0f;
  553. var items = new System.Collections.Generic.List<(int idx, float size, Vector3 scaleMult)>();
  554. do
  555. {
  556. var nextItem = PaletteManager.selectedBrush.items[nextIdx];
  557. var scaleMult = ScaleMultiplier(nextIdx, ShapeManager.settings);
  558. float itemSize;
  559. var key = (nextIdx, scaleMult);
  560. if (nextItem.randomScaleMultiplier) itemSize = GetLineSpacing(nextIdx, settings, scaleMult);
  561. else if (prefabSpacingDictionary.ContainsKey(key)) itemSize = prefabSpacingDictionary[key];
  562. else
  563. {
  564. itemSize = GetLineSpacing(nextIdx, settings, scaleMult);
  565. prefabSpacingDictionary.Add(key, itemSize);
  566. }
  567. itemSize = Mathf.Max(itemSize, _minLineSpacing);
  568. if (itemsSize + itemSize > lineLength) break;
  569. itemsSize += itemSize;
  570. items.Add((nextIdx, itemSize, scaleMult));
  571. nextIdx = PaletteManager.selectedBrush.nextItemIndex;
  572. } while (itemsSize <= lineLength);
  573. var spacing = (lineLength - itemsSize) / (items.Count + 1);
  574. var distance = spacing;
  575. var direction = startToEnd.normalized;
  576. Vector3 itemDir = (settings.objectsOrientedAlongTheLine && direction != Vector3.zero)
  577. ? direction : Vector3.forward;
  578. if (!settings.perpendicularToTheSurface)
  579. itemDir = Vector3.ProjectOnPlane(itemDir, settings.projectionDirection);
  580. if (itemDir == Vector3.zero) itemDir = settings.projectionDirection;
  581. var lookAt = Quaternion.LookRotation((AxesUtils.SignedAxis)(settings.axisOrientedAlongTheLine), Vector3.up);
  582. var segmentRotation = Quaternion.LookRotation(itemDir, -settings.projectionDirection) * lookAt;
  583. var angle = segmentRotation.eulerAngles;
  584. foreach (var item in items)
  585. {
  586. var brushItem = PaletteManager.selectedBrush.items[item.idx];
  587. if (brushItem.prefab == null) continue;
  588. var position = start + direction * (distance + item.size / 2);
  589. AddBrushstrokeItem(item.idx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  590. position, angle, item.scaleMult, settings);
  591. distance += item.size + spacing;
  592. }
  593. }
  594. int nexItemItemIdx = -1;
  595. if (ShapeManager.settings.shapeType == ShapeSettings.ShapeType.CIRCLE)
  596. {
  597. const float TAU = 2 * Mathf.PI;
  598. var perimeter = TAU * ShapeData.instance.radius;
  599. var items = new System.Collections.Generic.List<(int idx, float size, Vector3 scaleMult)>();
  600. var minspacing = perimeter / 1024f;
  601. float itemsSize = 0f;
  602. var firstLocalArcIntersection = Quaternion.Inverse(ShapeData.instance.planeRotation)
  603. * (ShapeData.instance.GetArcIntersection(0) - ShapeData.instance.center);
  604. var firstLocalAngle = Mathf.Atan2(firstLocalArcIntersection.z, firstLocalArcIntersection.x);
  605. if (firstLocalAngle < 0) firstLocalAngle += TAU;
  606. var secondLocalArcIntersection = Quaternion.Inverse(ShapeData.instance.planeRotation)
  607. * (ShapeData.instance.GetArcIntersection(1) - ShapeData.instance.center);
  608. var secondLocalAngle = Mathf.Atan2(secondLocalArcIntersection.z, secondLocalArcIntersection.x);
  609. if (secondLocalAngle < 0) secondLocalAngle += TAU;
  610. if (secondLocalAngle <= firstLocalAngle) secondLocalAngle += TAU;
  611. var arcDelta = secondLocalAngle - firstLocalAngle;
  612. var arcPerimeter = arcDelta / TAU * perimeter;
  613. if (PaletteManager.selectedBrush.patternMachine != null &&
  614. PaletteManager.selectedBrush.restartPatternForEachStroke)
  615. PaletteManager.selectedBrush.patternMachine.Reset();
  616. do
  617. {
  618. float itemSize = 0;
  619. var nextIdx = PaletteManager.selectedBrush.nextItemIndex;
  620. var nextItem = PaletteManager.selectedBrush.items[nextIdx];
  621. var scaleMult = ScaleMultiplier(nextIdx, ShapeManager.settings);
  622. var key = (nextIdx, scaleMult);
  623. if (nextItem.randomScaleMultiplier) itemSize = GetLineSpacing(nextIdx, settings, scaleMult);
  624. else if (prefabSpacingDictionary.ContainsKey(key)) itemSize = prefabSpacingDictionary[key];
  625. else
  626. {
  627. itemSize = GetLineSpacing(nextIdx, settings, scaleMult);
  628. prefabSpacingDictionary.Add(key, itemSize);
  629. }
  630. itemSize = Mathf.Max(itemSize, minspacing);
  631. if (itemsSize + itemSize > arcPerimeter) break;
  632. itemsSize += itemSize;
  633. items.Add((nextIdx, itemSize, scaleMult));
  634. } while (itemsSize < arcPerimeter);
  635. var spacing = (arcPerimeter - itemsSize) / (items.Count);
  636. if (items.Count == 0) return;
  637. var distance = firstLocalAngle / TAU * perimeter + items[0].size / 2;
  638. for (int i = 0; i < items.Count; ++i)
  639. {
  640. var item = items[i];
  641. var arcAngle = distance / perimeter * TAU;
  642. var LocalRadiusVector = new Vector3(Mathf.Cos(arcAngle), 0f, Mathf.Sin(arcAngle))
  643. * ShapeData.instance.radius;
  644. var radiusVector = ShapeData.instance.planeRotation * LocalRadiusVector;
  645. var position = radiusVector + ShapeData.instance.center;
  646. var itemDir = settings.objectsOrientedAlongTheLine
  647. ? Vector3.Cross(ShapeData.instance.planeRotation * Vector3.up, radiusVector) : Vector3.forward;
  648. if (!settings.perpendicularToTheSurface)
  649. itemDir = Vector3.ProjectOnPlane(itemDir, settings.projectionDirection);
  650. if (itemDir == Vector3.zero) itemDir = settings.projectionDirection;
  651. var lookAt = Quaternion.LookRotation((AxesUtils.SignedAxis)(settings.axisOrientedAlongTheLine),
  652. Vector3.up);
  653. var segmentRotation = Quaternion.LookRotation(itemDir, -settings.projectionDirection) * lookAt;
  654. var angle = segmentRotation.eulerAngles;
  655. AddBrushstrokeItem(item.idx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  656. position, angle, item.scaleMult, settings);
  657. var next_Item = items[(i + 1) % items.Count];
  658. distance += item.size / 2 + next_Item.size / 2 + spacing;
  659. }
  660. }
  661. else
  662. {
  663. if (PaletteManager.selectedBrush.patternMachine != null &&
  664. PaletteManager.selectedBrush.restartPatternForEachStroke)
  665. PaletteManager.selectedBrush.patternMachine.Reset();
  666. for (int i = 0; i < points.Count - 1; ++i)
  667. {
  668. var start = points[i];
  669. var end = points[i + 1];
  670. AddItemsToLine(start, end, ref nexItemItemIdx);
  671. }
  672. }
  673. }
  674. public static void UpdatePersistentShapeBrushstroke(ShapeData data,
  675. System.Collections.Generic.List<GameObject> shapeObjects,
  676. out BrushstrokeObject[] objPoses)
  677. {
  678. _brushstroke.Clear();
  679. var objPosesList = new System.Collections.Generic.List<BrushstrokeObject>();
  680. var settings = data.settings;
  681. var prefabSpacingDictionary = new System.Collections.Generic.Dictionary<(int, Vector3), float>();
  682. int nextItemIdx = -1;
  683. objPoses = objPosesList.ToArray();
  684. var toolSettings = ShapeManager.settings;
  685. var brushSettings = toolSettings.overwriteBrushProperties ? toolSettings.brushSettings
  686. : PaletteManager.selectedBrush;
  687. Vector3 BrushScaleMultiplier() => (ShapeManager.instance.applyBrushToExisting
  688. && PaletteManager.selectedBrush != null) ? brushSettings.GetScaleMultiplier() : Vector3.one;
  689. if (settings.shapeType == ShapeSettings.ShapeType.CIRCLE)
  690. {
  691. const float TAU = 2 * Mathf.PI;
  692. var perimeter = TAU * data.radius;
  693. var items = new System.Collections.Generic.List<(int idx, float size, bool objExist, Vector3 objScale)>();
  694. var minspacing = perimeter / 1024f;
  695. float itemsSize = 0f;
  696. var firstLocalArcIntersection = Quaternion.Inverse(data.planeRotation)
  697. * (data.GetArcIntersection(0) - data.center);
  698. var firstLocalAngle = Mathf.Atan2(firstLocalArcIntersection.z, firstLocalArcIntersection.x);
  699. if (firstLocalAngle < 0) firstLocalAngle += TAU;
  700. var secondLocalArcIntersection = Quaternion.Inverse(data.planeRotation)
  701. * (data.GetArcIntersection(1) - data.center);
  702. var secondLocalAngle = Mathf.Atan2(secondLocalArcIntersection.z, secondLocalArcIntersection.x);
  703. if (secondLocalAngle < 0) secondLocalAngle += TAU;
  704. if (secondLocalAngle <= firstLocalAngle) secondLocalAngle += TAU;
  705. var arcDelta = secondLocalAngle - firstLocalAngle;
  706. var arcPerimeter = arcDelta / TAU * perimeter;
  707. var objIdx = 0;
  708. int GetNextIdx() => PaletteManager.selectedBrush != null ? PaletteManager.selectedBrush.nextItemIndex : -1;
  709. if (nextItemIdx < 0) nextItemIdx = GetNextIdx();
  710. do
  711. {
  712. float itemSize = 0;
  713. var objectExist = objIdx < shapeObjects.Count && shapeObjects[objIdx] != null;
  714. var objScale = Vector3.one;
  715. var brushScaleMultiplier = BrushScaleMultiplier();
  716. if (objectExist)
  717. {
  718. var obj = shapeObjects[objIdx];
  719. if (ShapeManager.instance.applyBrushToExisting)
  720. {
  721. var prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(obj);
  722. itemSize = GetLineSpacing(prefab.transform, toolSettings,
  723. brushScaleMultiplier, useDictionary: true);
  724. objScale = Vector3.Scale(prefab.transform.localScale, brushScaleMultiplier);
  725. }
  726. else
  727. {
  728. itemSize = GetLineSpacing(shapeObjects[objIdx].transform, settings,
  729. Vector3.one, useDictionary: false);
  730. objScale = obj.transform.localScale;
  731. }
  732. }
  733. else if (PaletteManager.selectedBrush != null)
  734. {
  735. var nextItem = PaletteManager.selectedBrush.items[nextItemIdx];
  736. var prefab = nextItem.prefab;
  737. itemSize = GetLineSpacing(prefab.transform, toolSettings,
  738. brushScaleMultiplier, useDictionary: true);
  739. objScale = Vector3.Scale(prefab.transform.localScale, brushScaleMultiplier);
  740. }
  741. else break;
  742. itemSize = Mathf.Max(itemSize, minspacing);
  743. if (itemsSize + itemSize > arcPerimeter) break;
  744. itemsSize += itemSize;
  745. items.Add((objectExist ? objIdx : nextItemIdx, itemSize, objectExist, objScale));
  746. nextItemIdx = GetNextIdx();
  747. if (objectExist) ++objIdx;
  748. } while (itemsSize < arcPerimeter);
  749. var spacing = (arcPerimeter - itemsSize) / (items.Count);
  750. if (items.Count == 0)
  751. {
  752. return;
  753. }
  754. var distance = firstLocalAngle / TAU * perimeter + items[0].size / 2;
  755. int itemCount = 0;
  756. for (int i = 0; i < items.Count; ++i)
  757. {
  758. var item = items[i];
  759. GameObject obj = null;
  760. if (item.objExist) obj = shapeObjects[item.idx];
  761. else if (PaletteManager.selectedBrush != null) obj = PaletteManager.selectedBrush.items[item.idx].prefab;
  762. if (obj == null) continue;
  763. var arcAngle = distance / perimeter * TAU;
  764. var LocalRadiusVector = new Vector3(Mathf.Cos(arcAngle), 0f, Mathf.Sin(arcAngle))
  765. * data.radius;
  766. var radiusVector = data.planeRotation * LocalRadiusVector;
  767. var position = radiusVector + data.center;
  768. var itemDir = settings.objectsOrientedAlongTheLine
  769. ? Vector3.Cross(data.planeRotation * Vector3.up, radiusVector) : Vector3.forward;
  770. if (!settings.perpendicularToTheSurface)
  771. itemDir = Vector3.ProjectOnPlane(itemDir, settings.projectionDirection);
  772. if (itemDir == Vector3.zero) itemDir = settings.projectionDirection;
  773. var lookAt = Quaternion.LookRotation((AxesUtils.SignedAxis)(settings.axisOrientedAlongTheLine),
  774. Vector3.up);
  775. var segmentRotation = Quaternion.LookRotation(itemDir, -settings.projectionDirection) * lookAt;
  776. var angle = segmentRotation.eulerAngles;
  777. if (item.objExist)
  778. {
  779. var brushAdditionalAngle = Vector3.zero;
  780. bool brushFlipX = false;
  781. bool brushFlipY = false;
  782. var brushSurfaceDistance = 0f;
  783. if (ShapeManager.instance.applyBrushToExisting)
  784. {
  785. if (PaletteManager.selectedBrush != null)
  786. {
  787. brushAdditionalAngle = brushSettings.GetAdditionalAngle();
  788. brushFlipX = brushSettings.GetFlipX();
  789. brushFlipY = brushSettings.GetFlipY();
  790. brushSurfaceDistance = brushSettings.GetSurfaceDistance();
  791. }
  792. }
  793. objPosesList.Add(new BrushstrokeObject(item.idx, position, segmentRotation,
  794. brushAdditionalAngle, item.objScale, brushFlipX, brushFlipY, brushSurfaceDistance,
  795. brushstrokeDirection: Vector3.zero));
  796. }
  797. else AddBrushstrokeItem(item.idx, PaletteManager.selectedBrush.GetPatternTokenIndex(), position, angle,
  798. item.objScale, ShapeManager.settings);
  799. var next_Item = items[(i + 1) % items.Count];
  800. distance += item.size / 2 + next_Item.size / 2 + spacing;
  801. ++itemCount;
  802. }
  803. }
  804. else
  805. {
  806. var points = new System.Collections.Generic.List<Vector3>();
  807. var firstVertexIdx = data.firstVertexIdxAfterIntersection;
  808. var lastVertexIdx = data.lastVertexIdxBeforeIntersection;
  809. int sidesCount = settings.shapeType == ShapeSettings.ShapeType.POLYGON ? settings.sidesCount
  810. : data.circleSideCount;
  811. int GetNextVertexIdx(int currentIdx) => currentIdx == sidesCount ? 1 : currentIdx + 1;
  812. int GetPrevVertexIdx(int currentIdx) => currentIdx == 1 ? sidesCount : currentIdx - 1;
  813. var firstPrev = GetPrevVertexIdx(firstVertexIdx);
  814. points.Add(data.GetArcIntersection(0));
  815. if (lastVertexIdx != firstPrev || (lastVertexIdx == firstPrev && data.arcAngle > 120))
  816. {
  817. var vertexIdx = firstVertexIdx;
  818. var nextVertexIdx = firstVertexIdx;
  819. do
  820. {
  821. vertexIdx = nextVertexIdx;
  822. if (vertexIdx >= data.pointsCount || points.Count >= data.pointsCount)
  823. {
  824. ShapeData.instance.Update(true);
  825. return;
  826. }
  827. points.Add(data.GetPoint(vertexIdx));
  828. nextVertexIdx = GetNextVertexIdx(nextVertexIdx);
  829. } while (vertexIdx != lastVertexIdx);
  830. }
  831. var lastPoint = data.GetArcIntersection(1);
  832. if (points.Last() != lastPoint) points.Add(lastPoint);
  833. int firstObjInSegmentIdx = 0;
  834. void AddItemsToLine(Vector3 start, Vector3 end)
  835. {
  836. int GetNextIdx() => PaletteManager.selectedBrush != null
  837. ? PaletteManager.selectedBrush.nextItemIndex : -1;
  838. if (nextItemIdx < 0) nextItemIdx = GetNextIdx();
  839. var startToEnd = end - start;
  840. var lineLength = startToEnd.magnitude;
  841. float itemsSize = 0f;
  842. var items = new System.Collections.Generic.List<(int idx, float size, bool objExist, Vector3 objScale)>();
  843. var minspacing = (lineLength * points.Count) / 1024f;
  844. int objSegmentIdx = 0;
  845. var objIdx = firstObjInSegmentIdx + objSegmentIdx;
  846. do
  847. {
  848. float itemSize = 0;
  849. var objectExist = objIdx < shapeObjects.Count;
  850. var objScale = Vector3.one;
  851. var brushScaleMultiplier = BrushScaleMultiplier();
  852. if (objectExist)
  853. {
  854. var obj = shapeObjects[objIdx];
  855. if (ShapeManager.instance.applyBrushToExisting)
  856. {
  857. var prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(obj);
  858. itemSize = GetLineSpacing(prefab.transform, toolSettings,
  859. brushScaleMultiplier, useDictionary: true);
  860. objScale = Vector3.Scale(prefab.transform.localScale, brushScaleMultiplier);
  861. }
  862. else
  863. {
  864. itemSize = GetLineSpacing(shapeObjects[objIdx].transform, settings,
  865. Vector3.one, useDictionary: false);
  866. objScale = obj.transform.localScale;
  867. }
  868. }
  869. else if (PaletteManager.selectedBrush != null)
  870. {
  871. var nextItem = PaletteManager.selectedBrush.items[nextItemIdx];
  872. var prefab = nextItem.prefab;
  873. itemSize = GetLineSpacing(prefab.transform, toolSettings,
  874. brushScaleMultiplier, useDictionary: true);
  875. objScale = Vector3.Scale(prefab.transform.localScale, brushScaleMultiplier);
  876. }
  877. else break;
  878. itemSize = Mathf.Max(itemSize, minspacing);
  879. if (itemsSize + itemSize > lineLength) break;
  880. itemsSize += itemSize;
  881. items.Add((objectExist ? objIdx : nextItemIdx, itemSize, objectExist, objScale));
  882. nextItemIdx = GetNextIdx();
  883. if (objectExist) ++objIdx;
  884. } while (itemsSize < lineLength);
  885. var spacing = (lineLength - itemsSize) / (items.Count + 1);
  886. var distance = spacing;
  887. var direction = startToEnd.normalized;
  888. Vector3 itemDir = (settings.objectsOrientedAlongTheLine && direction != Vector3.zero)
  889. ? direction : Vector3.forward;
  890. if (!settings.perpendicularToTheSurface)
  891. itemDir = Vector3.ProjectOnPlane(itemDir, settings.projectionDirection);
  892. var lookAt = Quaternion.LookRotation(
  893. (AxesUtils.SignedAxis)(settings.axisOrientedAlongTheLine), Vector3.up);
  894. var segmentRotation = Quaternion.LookRotation(itemDir, -settings.projectionDirection) * lookAt;
  895. var angle = segmentRotation.eulerAngles;
  896. foreach (var item in items)
  897. {
  898. GameObject obj = null;
  899. if (item.objExist) obj = shapeObjects[item.idx];
  900. else if (PaletteManager.selectedBrush != null)
  901. obj = PaletteManager.selectedBrush.items[item.idx].prefab;
  902. if (obj == null) continue;
  903. var position = start + direction * (distance + item.size / 2);
  904. if (item.objExist)
  905. {
  906. var brushAdditionalAngle = Vector3.zero;
  907. bool brushFlipX = false;
  908. bool brushFlipY = false;
  909. var brushSurfaceDistance = 0f;
  910. if (ShapeManager.instance.applyBrushToExisting)
  911. {
  912. if (PaletteManager.selectedBrush != null)
  913. {
  914. brushAdditionalAngle = brushSettings.GetAdditionalAngle();
  915. brushFlipX = brushSettings.GetFlipX();
  916. brushFlipY = brushSettings.GetFlipY();
  917. brushSurfaceDistance = brushSettings.GetSurfaceDistance();
  918. }
  919. }
  920. objPosesList.Add(new BrushstrokeObject(item.idx, position, segmentRotation,
  921. brushAdditionalAngle, item.objScale, brushFlipX, brushFlipY, brushSurfaceDistance,
  922. brushstrokeDirection: Vector3.zero));
  923. }
  924. else AddBrushstrokeItem(item.idx,
  925. PaletteManager.selectedBrush == null ? 0 : PaletteManager.selectedBrush.GetPatternTokenIndex(),
  926. position, angle, item.objScale, settings);
  927. distance += item.size + spacing;
  928. ++firstObjInSegmentIdx;
  929. }
  930. }
  931. for (int i = 0; i < points.Count - 1; ++i)
  932. {
  933. var start = points[i];
  934. var end = points[i + 1];
  935. AddItemsToLine(start, end);
  936. }
  937. }
  938. objPoses = objPosesList.ToArray();
  939. }
  940. #endregion
  941. #region TILING
  942. public static void UpdateTilingBrushstroke(Vector3[] cellCenters)
  943. {
  944. _brushstroke.Clear();
  945. if (PaletteManager.selectedBrush == null) return;
  946. for (int i = 0; i < cellCenters.Length; ++i)
  947. {
  948. var nextIdx = PaletteManager.selectedBrush.nextItemIndex;
  949. AddBrushstrokeItem(nextIdx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  950. cellCenters[i], angle: Vector3.zero, scale: Vector3.one,
  951. TilingManager.settings);
  952. }
  953. ToolProperties.RepainWindow();
  954. }
  955. public static void UpdatePersistentTilingBrushstroke(Vector3[] cellCenters, TilingSettings settings,
  956. System.Collections.Generic.List<GameObject> tilingObjects,
  957. out Vector3[] objPositions, out Vector3[] strokePositions)
  958. {
  959. _brushstroke.Clear();
  960. var objPositionsList = new System.Collections.Generic.List<Vector3>();
  961. var strokePositionsList = new System.Collections.Generic.List<Vector3>();
  962. for (int i = 0; i < cellCenters.Length; ++i)
  963. {
  964. var objectExist = i < tilingObjects.Count;
  965. var position = cellCenters[i];
  966. if (objectExist) objPositionsList.Add(position);
  967. else
  968. {
  969. if (PaletteManager.selectedBrush == null) break;
  970. var nextIdx = PaletteManager.selectedBrush.nextItemIndex;
  971. AddBrushstrokeItem(nextIdx, PaletteManager.selectedBrush == null ? 0
  972. : PaletteManager.selectedBrush.GetPatternTokenIndex(), position,
  973. angle: Vector3.zero, scale: Vector3.one,
  974. settings);
  975. strokePositionsList.Add(position);
  976. }
  977. }
  978. objPositions = objPositionsList.ToArray();
  979. strokePositions = strokePositionsList.ToArray();
  980. }
  981. #endregion
  982. #region PIN
  983. private static int _currentPinIdx = 0;
  984. public static void SetNextPinBrushstroke(int delta)
  985. {
  986. _currentPinIdx = _currentPinIdx + delta;
  987. var mod = _currentPinIdx % PaletteManager.selectedBrush.itemCount;
  988. _currentPinIdx = mod < 0 ? PaletteManager.selectedBrush.itemCount + mod : mod;
  989. _brushstroke.Clear();
  990. AddBrushstrokeItem(_currentPinIdx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  991. tangentPosition: Vector3.zero, angle: Vector3.zero,
  992. ScaleMultiplier(_currentPinIdx, PinManager.settings), PinManager.settings);
  993. }
  994. #endregion
  995. #region BRUSH
  996. private static void UpdateBrushBaseStroke(BrushToolBase brushSettings)
  997. {
  998. if (brushSettings.spacingType == BrushToolBase.SpacingType.AUTO)
  999. {
  1000. var maxSize = 0.1f;
  1001. foreach (var item in PaletteManager.selectedBrush.items)
  1002. {
  1003. if (item.prefab == null) continue;
  1004. var itemSize = BoundsUtils.GetBoundsRecursive(item.prefab.transform).size;
  1005. itemSize = Vector3.Scale(itemSize,
  1006. item.randomScaleMultiplier ? item.maxScaleMultiplier : item.scaleMultiplier);
  1007. maxSize = Mathf.Max(itemSize.x, itemSize.z, maxSize);
  1008. }
  1009. brushSettings.minSpacing = maxSize;
  1010. ToolProperties.RepainWindow();
  1011. }
  1012. if (brushSettings.brushShape == BrushToolSettings.BrushShape.POINT)
  1013. {
  1014. var nextIdx = PaletteManager.selectedBrush.nextItemIndex;
  1015. if (nextIdx == -1) return;
  1016. if (PaletteManager.selectedBrush.frequencyMode == PluginMaster.MultibrushSettings.FrequencyMode.PATTERN
  1017. && nextIdx == -2) return;
  1018. _brushstroke.Clear();
  1019. AddBrushstrokeItem(nextIdx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  1020. tangentPosition: Vector3.zero, angle: Vector3.zero,
  1021. scale: ScaleMultiplier(nextIdx, brushSettings), brushSettings);
  1022. _currentPinIdx = Mathf.Clamp(nextIdx, 0, PaletteManager.selectedBrush.itemCount - 1);
  1023. }
  1024. else
  1025. {
  1026. var radius = brushSettings.radius;
  1027. var radiusSqr = radius * radius;
  1028. var minSpacing = brushSettings.minSpacing * 100f / brushSettings.density;
  1029. if (brushSettings.randomizePositions)
  1030. minSpacing *= Mathf.Max(1 - (Random.value * brushSettings.randomness), 0.5f);
  1031. var delta = minSpacing;
  1032. var maxRandomOffset = delta * brushSettings.randomness;
  1033. int halfSize = (int)Mathf.Ceil(radius / delta) + 1;
  1034. const int MAX_SIZE = 32;
  1035. if (halfSize > MAX_SIZE)
  1036. {
  1037. halfSize = MAX_SIZE;
  1038. delta = radius / MAX_SIZE;
  1039. minSpacing = delta;
  1040. maxRandomOffset = delta * brushSettings.randomness;
  1041. }
  1042. int size = halfSize * 2;
  1043. float col0x = -delta * halfSize;
  1044. float row0y = -delta * halfSize;
  1045. var takedCells = new System.Collections.Generic.HashSet<(int row, int col)>();
  1046. for (int row = 0; row < size; ++row)
  1047. {
  1048. for (int col = 0; col < size; ++col)
  1049. {
  1050. var x = col0x + col * delta;
  1051. var y = row0y + row * delta;
  1052. if (brushSettings.randomizePositions)
  1053. {
  1054. if (Random.value < 0.4 * brushSettings.randomness) continue;
  1055. if (takedCells.Contains((row, col))) continue;
  1056. x += Random.Range(-maxRandomOffset, maxRandomOffset);
  1057. y += Random.Range(-maxRandomOffset, maxRandomOffset);
  1058. var randCol = Mathf.RoundToInt((x - col0x) / delta);
  1059. var randRow = Mathf.RoundToInt((y - row0y) / delta);
  1060. if (randRow < row) continue;
  1061. if (row != randRow || col != randRow) takedCells.Add((randRow, randCol));
  1062. takedCells.RemoveWhere(pair => pair.row <= row);
  1063. }
  1064. if (brushSettings.brushShape == BrushToolBase.BrushShape.CIRCLE)
  1065. {
  1066. var distanceSqr = x * x + y * y;
  1067. if (distanceSqr >= radiusSqr) continue;
  1068. }
  1069. else if (brushSettings.brushShape == BrushToolBase.BrushShape.SQUARE)
  1070. {
  1071. if (Mathf.Abs(x) > radius || Mathf.Abs(y) > radius) continue;
  1072. }
  1073. var nextItemIdx = PaletteManager.selectedBrush.nextItemIndex;
  1074. var position = new Vector3(x, y, 0f);
  1075. if ((PaletteManager.selectedBrush.frequencyMode
  1076. == PluginMaster.MultibrushSettings.FrequencyMode.RANDOM && nextItemIdx == -1)
  1077. || (PaletteManager.selectedBrush.frequencyMode
  1078. == PluginMaster.MultibrushSettings.FrequencyMode.PATTERN && nextItemIdx == -2)) continue;
  1079. var item = PaletteManager.selectedBrush.items[nextItemIdx];
  1080. AddBrushstrokeItem(nextItemIdx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  1081. tangentPosition: position, angle: Vector3.zero,
  1082. ScaleMultiplier(nextItemIdx, brushSettings), brushSettings);
  1083. }
  1084. }
  1085. }
  1086. }
  1087. public static void UpdateSingleBrushstroke(IPaintToolSettings settings)
  1088. {
  1089. _brushstroke.Clear();
  1090. if (PaletteManager.selectedBrush == null) return;
  1091. var nextIdx = PaletteManager.selectedBrush.nextItemIndex;
  1092. if (nextIdx == -1) return;
  1093. if (PaletteManager.selectedBrush.frequencyMode == PluginMaster.MultibrushSettings.FrequencyMode.PATTERN
  1094. && nextIdx == -2)
  1095. {
  1096. if (PaletteManager.selectedBrush.patternMachine != null) PaletteManager.selectedBrush.patternMachine.Reset();
  1097. else return;
  1098. }
  1099. AddBrushstrokeItem(nextIdx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  1100. tangentPosition: Vector3.zero, angle: Vector3.zero,
  1101. scale: ScaleMultiplier(nextIdx, settings), settings);
  1102. const int maxTries = 10;
  1103. int tryCount = 0;
  1104. while (_brushstroke.Count == 0 && ++tryCount < maxTries)
  1105. {
  1106. nextIdx = PaletteManager.selectedBrush.nextItemIndex;
  1107. if (nextIdx >= 0)
  1108. {
  1109. AddBrushstrokeItem(nextIdx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  1110. tangentPosition: Vector3.zero, angle: Vector3.zero,
  1111. scale: ScaleMultiplier(nextIdx, settings), settings);
  1112. break;
  1113. }
  1114. }
  1115. _currentPinIdx = Mathf.Clamp(nextIdx, 0, PaletteManager.selectedBrush.itemCount - 1);
  1116. }
  1117. #endregion
  1118. #region REPLACER
  1119. private static System.Collections.Generic.Dictionary<Transform, BrushstrokeItem> _replacerDictionary
  1120. = new System.Collections.Generic.Dictionary<Transform, BrushstrokeItem>();
  1121. private static System.Collections.Generic.Dictionary<BrushstrokeItem, Transform> _replacerDictionary2
  1122. = new System.Collections.Generic.Dictionary<BrushstrokeItem, Transform>();
  1123. public static void UpdateReplacerBrushstroke(bool clearDictionary, GameObject[] targets)
  1124. {
  1125. _brushstroke.Clear();
  1126. if (clearDictionary) ClearReplacerDictionary();
  1127. var toolSettings = ReplacerManager.settings;
  1128. bool GetStrokeItem(Transform target, int itemIdx, out BrushstrokeItem item)
  1129. {
  1130. item = new BrushstrokeItem();
  1131. if (itemIdx == -1) return false;
  1132. if (PaletteManager.selectedBrush.frequencyMode == PluginMaster.MultibrushSettings.FrequencyMode.PATTERN
  1133. && itemIdx == -2)
  1134. {
  1135. if (PaletteManager.selectedBrush.patternMachine != null)
  1136. PaletteManager.selectedBrush.patternMachine.Reset();
  1137. else return false;
  1138. }
  1139. var multiBrushSettings = PaletteManager.selectedBrush;
  1140. BrushSettings brushSettings = multiBrushSettings.items[itemIdx];
  1141. if (toolSettings.overwriteBrushProperties) brushSettings = toolSettings.brushSettings;
  1142. var flipX = brushSettings.GetFlipX();
  1143. var flipY = brushSettings.GetFlipY();
  1144. var multiBrushItemSettings = PaletteManager.selectedBrush.items[itemIdx];
  1145. var prefab = multiBrushItemSettings.prefab;
  1146. if (prefab == null) return false;
  1147. var itemRotation = target.rotation;
  1148. var targetBounds = BoundsUtils.GetBoundsRecursive(target, target.rotation);
  1149. var strokeRotation = Quaternion.identity;
  1150. var scaleMult = Vector3.one;
  1151. if (toolSettings.overwriteBrushProperties)
  1152. {
  1153. var toolBrushSettings = toolSettings.brushSettings;
  1154. var additonalAngle = toolBrushSettings.addRandomRotation
  1155. ? toolBrushSettings.randomEulerOffset.randomVector : toolBrushSettings.eulerOffset;
  1156. strokeRotation *= Quaternion.Euler(additonalAngle);
  1157. scaleMult = toolBrushSettings.randomScaleMultiplier
  1158. ? toolBrushSettings.randomScaleMultiplierRange.randomVector : toolBrushSettings.scaleMultiplier;
  1159. }
  1160. var inverseStrokeRotation = Quaternion.Inverse(strokeRotation);
  1161. itemRotation *= strokeRotation;
  1162. var itemBounds = BoundsUtils.GetBoundsRecursive(prefab.transform, prefab.transform.rotation * strokeRotation);
  1163. if (toolSettings.keepTargetSize)
  1164. {
  1165. var targetSize = targetBounds.size;
  1166. var itemSize = itemBounds.size;
  1167. if (toolSettings.maintainProportions)
  1168. {
  1169. var targetMagnitude = Mathf.Max(targetSize.x, targetSize.y, targetSize.z);
  1170. var itemMagnitude = Mathf.Max(itemSize.x, itemSize.y, itemSize.z);
  1171. scaleMult = inverseStrokeRotation * (Vector3.one * (targetMagnitude / itemMagnitude));
  1172. }
  1173. else scaleMult = inverseStrokeRotation
  1174. * new Vector3(targetSize.x / itemSize.x, targetSize.y / itemSize.y, targetSize.z / itemSize.z);
  1175. scaleMult = new Vector3(Mathf.Abs(scaleMult.x), Mathf.Abs(scaleMult.y), Mathf.Abs(scaleMult.z));
  1176. }
  1177. var itemScale = Vector3.Scale(prefab.transform.localScale, scaleMult);
  1178. var itemPosition = targetBounds.center;
  1179. Transform replaceSurface = null;
  1180. if (toolSettings.positionMode == ReplacerSettings.PositionMode.ON_SURFACE)
  1181. {
  1182. var TRS = Matrix4x4.TRS(itemPosition, itemRotation, itemScale);
  1183. var bottomDistanceToSurfce = PWBIO.GetBottomDistanceToSurface(multiBrushItemSettings.bottomVertices,
  1184. TRS, Mathf.Abs(multiBrushItemSettings.bottomMagnitude), paintOnPalettePrefabs: true,
  1185. castOnMeshesWithoutCollider: true, out replaceSurface,
  1186. new System.Collections.Generic.HashSet<GameObject> { target.gameObject });
  1187. itemPosition += itemRotation * new Vector3(0f, -bottomDistanceToSurfce, 0f);
  1188. }
  1189. else
  1190. {
  1191. if (toolSettings.positionMode == ReplacerSettings.PositionMode.PIVOT)
  1192. itemPosition = target.position;
  1193. itemPosition -= itemRotation * Vector3.Scale(itemBounds.center - prefab.transform.position, scaleMult);
  1194. }
  1195. item = new BrushstrokeItem(itemIdx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  1196. multiBrushItemSettings, itemPosition, itemRotation.eulerAngles,
  1197. scaleMult, flipX, flipY, surfaceDistance: 0);
  1198. return true;
  1199. }
  1200. void AddItem(Transform target)
  1201. {
  1202. var nextIdx = PaletteManager.selectedBrush.nextItemIndex;
  1203. if (GetStrokeItem(target, nextIdx, out BrushstrokeItem strokeItem))
  1204. {
  1205. _brushstroke.Add(strokeItem);
  1206. _replacerDictionary.Add(target, strokeItem);
  1207. _replacerDictionary2.Add(strokeItem, target);
  1208. }
  1209. }
  1210. foreach(var sceneObj in targets)
  1211. {
  1212. var target = sceneObj.transform;
  1213. BrushstrokeItem item;
  1214. if (_replacerDictionary.ContainsKey(target))
  1215. {
  1216. item = _replacerDictionary[target];
  1217. if (GetStrokeItem(target, item.index, out BrushstrokeItem strokeItem))
  1218. {
  1219. if (item == strokeItem) _brushstroke.Add(item);
  1220. else
  1221. {
  1222. _replacerDictionary.Remove(target);
  1223. _replacerDictionary2.Remove(item);
  1224. AddItem(target);
  1225. }
  1226. }
  1227. }
  1228. else AddItem(target);
  1229. }
  1230. }
  1231. public static void ClearReplacerDictionary()
  1232. {
  1233. _replacerDictionary.Clear();
  1234. _replacerDictionary2.Clear();
  1235. }
  1236. public static Transform GetReplacerTargetFromStrokeItem(BrushstrokeItem item) => _replacerDictionary2[item];
  1237. #endregion
  1238. #region MODULAR TOOLS
  1239. private static void UpdateFirstModularBrushstroke(ModularToolBase settings, bool setNextIdx)
  1240. {
  1241. if (PaletteManager.selectedBrush == null) return;
  1242. _brushstroke.Clear();
  1243. if (PaletteManager.selectedBrush.restartPatternForEachStroke)
  1244. PaletteManager.selectedBrush.ResetCurrentItemIndex();
  1245. else if (setNextIdx) PaletteManager.selectedBrush.SetNextItemIndex();
  1246. var nextIdx = PaletteManager.selectedBrush.currentItemIndex;
  1247. if (nextIdx == -1) return;
  1248. if (PaletteManager.selectedBrush.frequencyMode == MultibrushSettings.FrequencyMode.PATTERN
  1249. && nextIdx == -2)
  1250. {
  1251. if (PaletteManager.selectedBrush.patternMachine != null) PaletteManager.selectedBrush.patternMachine.Reset();
  1252. else return;
  1253. }
  1254. var forwardAxis = settings.forwardAxis;
  1255. if (settings is FloorSettings)
  1256. {
  1257. var floorSettings = (FloorSettings) settings;
  1258. var quarterTurns = FloorManager.quarterTurns;
  1259. if (floorSettings.swapXZ) ++quarterTurns;
  1260. forwardAxis = Quaternion.AngleAxis(-90 * quarterTurns, settings.upwardAxis) * forwardAxis;
  1261. }
  1262. else if (settings is WallSettings && WallManager.halfTurn)
  1263. forwardAxis = Quaternion.AngleAxis(180, settings.upwardAxis) * forwardAxis;
  1264. var angle = AxesUtils.SignedAxis.GetEulerAnglesFromAxes(forwardAxis, settings.upwardAxis);
  1265. angle = (Quaternion.Euler(angle) * SnapManager.settings.rotation).eulerAngles;
  1266. var scale = ScaleMultiplier(nextIdx, settings);
  1267. scale.x = Mathf.Abs(scale.x);
  1268. scale.y = Mathf.Abs(scale.y);
  1269. scale.z = Mathf.Abs(scale.z);
  1270. AddBrushstrokeItem(nextIdx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  1271. tangentPosition: Vector3.zero, angle, scale, settings);
  1272. const int maxTries = 10;
  1273. int tryCount = 0;
  1274. while (_brushstroke.Count == 0 && ++tryCount < maxTries)
  1275. {
  1276. nextIdx = PaletteManager.selectedBrush.nextItemIndex;
  1277. if (nextIdx >= 0)
  1278. {
  1279. AddBrushstrokeItem(nextIdx, PaletteManager.selectedBrush.GetPatternTokenIndex(),
  1280. tangentPosition: Vector3.zero, angle, scale, settings);
  1281. break;
  1282. }
  1283. }
  1284. }
  1285. #region FLOOR
  1286. private static int _cellsCountX = 0;
  1287. private static int _cellsCountZ = 0;
  1288. public static int cellsCountX => _cellsCountX;
  1289. public static int cellsCountZ => _cellsCountZ;
  1290. public static void ResetCellCount()
  1291. {
  1292. _cellsCountX = 1;
  1293. _cellsCountZ = 1;
  1294. }
  1295. public static void UpdateFloorBrushstroke(bool setNextIdx, bool deleteBox = false)
  1296. {
  1297. ResetCellCount();
  1298. if (FloorManager.state == FloorManager.ToolState.FIRST_CORNER)
  1299. {
  1300. UpdateFirstModularBrushstroke(FloorManager.settings, setNextIdx);
  1301. return;
  1302. }
  1303. var settings = FloorManager.settings;
  1304. var diagonal = FloorManager.secondCorner - FloorManager.firstCorner;
  1305. var localDiagonal = Quaternion.Inverse(SnapManager.settings.rotation) * diagonal;
  1306. _cellsCountX = Mathf.RoundToInt(Mathf.Abs(localDiagonal.x / settings.moduleSize.x)) + 1;
  1307. var signX = localDiagonal.x >= 0 ? 1 : -1;
  1308. var dirX = SnapManager.settings.rotation * (Vector3.right * signX);
  1309. var deltaX = dirX * settings.moduleSize.x;
  1310. _cellsCountZ = Mathf.RoundToInt(Mathf.Abs(localDiagonal.z / settings.moduleSize.z)) + 1;
  1311. var signZ = localDiagonal.z >= 0 ? 1 : -1;
  1312. var dirZ = SnapManager.settings.rotation * (Vector3.forward * signZ);
  1313. var deltaZ = dirZ * settings.moduleSize.z;
  1314. var localRotation = Quaternion.FromToRotation(Vector3.up, settings.upwardAxis);
  1315. var rotation = SnapManager.settings.rotation * localRotation;
  1316. var angle = rotation.eulerAngles;
  1317. var prevBrushstroke = _brushstroke.ToArray();
  1318. _brushstroke.Clear();
  1319. if (PaletteManager.selectedBrush.restartPatternForEachStroke)
  1320. PaletteManager.selectedBrush.ResetCurrentItemIndex();
  1321. var floorItemsCount = 0;
  1322. for (int xIdx = 0; xIdx < _cellsCountX; ++xIdx)
  1323. {
  1324. var tangent = deltaX * xIdx;
  1325. for (int zIdx = 0; zIdx < _cellsCountZ; ++zIdx)
  1326. {
  1327. var bitangent = deltaZ * zIdx;
  1328. var cellCenter = FloorManager.firstCorner + tangent + bitangent;
  1329. if (deleteBox)
  1330. {
  1331. var additionalAngle = (Quaternion.Euler(angle)
  1332. * Quaternion.Euler(PaletteManager.selectedBrush.eulerOffset)).eulerAngles;
  1333. var strokeItem = new BrushstrokeItem(index: 0, tokenIndex: 0, settings: null,
  1334. cellCenter, additionalAngle, scaleMultiplier: FloorManager.settings.moduleSize,
  1335. flipX: false, flipY: false, surfaceDistance: 0);
  1336. _brushstroke.Add(strokeItem);
  1337. }
  1338. else
  1339. {
  1340. var idx = PaletteManager.selectedBrush.currentItemIndex;
  1341. var tokenIdx = PaletteManager.selectedBrush.GetPatternTokenIndex();
  1342. if (!PaletteManager.selectedBrush.restartPatternForEachStroke
  1343. && prevBrushstroke.Length > floorItemsCount)
  1344. {
  1345. idx = prevBrushstroke[floorItemsCount].index;
  1346. tokenIdx = prevBrushstroke[floorItemsCount].tokenIndex;
  1347. PaletteManager.selectedBrush.SetPatternTokenIndex(tokenIdx);
  1348. }
  1349. var scale = localRotation * ScaleMultiplier(idx, settings);
  1350. scale.x = Mathf.Abs(scale.x);
  1351. scale.y = Mathf.Abs(scale.y);
  1352. scale.z = Mathf.Abs(scale.z);
  1353. AddBrushstrokeItem(idx, tokenIdx, cellCenter, angle, scale, settings);
  1354. if (setNextIdx) PaletteManager.selectedBrush.SetNextItemIndex();
  1355. }
  1356. ++floorItemsCount;
  1357. }
  1358. }
  1359. }
  1360. #endregion
  1361. #region WALL
  1362. public static void UpdateWallBrushstroke(AxesUtils.Axis segmentAxis, int cellsCount,
  1363. bool setNextIdx, bool deleteMode)
  1364. {
  1365. if (WallManager.state == WallManager.ToolState.FIRST_WALL_PREVIEW)
  1366. {
  1367. UpdateFirstModularBrushstroke(WallManager.settings, setNextIdx);
  1368. return;
  1369. }
  1370. var settings = WallManager.settings;
  1371. var diagonal = WallManager.endPoint - WallManager.startPoint;
  1372. var localDiagonal = Quaternion.Inverse(SnapManager.settings.rotation) * diagonal;
  1373. Vector3 delta;
  1374. if (segmentAxis == AxesUtils.Axis.X)
  1375. {
  1376. var sign = localDiagonal.x >= 0 ? 1 : -1;
  1377. var dir = SnapManager.settings.rotation * (Vector3.right * sign);
  1378. delta = dir * SnapManager.settings.step.x;
  1379. }
  1380. else
  1381. {
  1382. var sign = localDiagonal.z >= 0 ? 1 : -1;
  1383. var dir = SnapManager.settings.rotation * (Vector3.forward * sign);
  1384. delta = dir * SnapManager.settings.step.z;
  1385. }
  1386. var firstPoint = WallManager.endPoint - (delta * (cellsCount - 1));
  1387. var localRotation = Quaternion.Euler(AxesUtils.SignedAxis.GetEulerAnglesFromAxes(settings.forwardAxis,
  1388. settings.upwardAxis));
  1389. var prevBrushstroke = _brushstroke.ToArray();
  1390. _brushstroke.Clear();
  1391. if (PaletteManager.selectedBrush.restartPatternForEachStroke)
  1392. PaletteManager.selectedBrush.ResetCurrentItemIndex();
  1393. var wallItemsCount = 0;
  1394. void AddItem(Vector3 position, AxesUtils.Axis segmentAxis)
  1395. {
  1396. var cellSize = WallManager.settings.moduleSize + WallManager.settings.spacing;
  1397. int nextIdx = 0;
  1398. if (!deleteMode)
  1399. {
  1400. nextIdx = PaletteManager.selectedBrush.currentItemIndex;
  1401. BrushSettings brush = PaletteManager.selectedBrush.GetItemAt(nextIdx);
  1402. if (settings.overwriteBrushProperties) brush = settings.brushSettings;
  1403. cellSize = WallManager.settings.GetCellSize(brush) + WallManager.settings.spacing;
  1404. }
  1405. var wallLenghtAxis = cellSize.x >= cellSize.z ? AxesUtils.Axis.X : AxesUtils.Axis.Z;
  1406. var rotation = SnapManager.settings.rotation * localRotation;
  1407. if (segmentAxis != wallLenghtAxis) rotation *= Quaternion.Euler(0f, 90f, 0f);
  1408. var angle = rotation.eulerAngles;
  1409. if (deleteMode)
  1410. {
  1411. var additionalAngle = (Quaternion.Euler(angle)
  1412. * Quaternion.Euler(PaletteManager.selectedBrush.eulerOffset)).eulerAngles;
  1413. var strokeItem = new BrushstrokeItem(index: 0, tokenIndex: 0, settings: null, position, additionalAngle,
  1414. scaleMultiplier: WallManager.settings.moduleSize, flipX: false, flipY: false, surfaceDistance: 0);
  1415. _brushstroke.Add(strokeItem);
  1416. }
  1417. else
  1418. {
  1419. var tokenIdx = PaletteManager.selectedBrush.GetPatternTokenIndex();
  1420. if (!PaletteManager.selectedBrush.restartPatternForEachStroke && prevBrushstroke.Length > wallItemsCount)
  1421. {
  1422. nextIdx = prevBrushstroke[wallItemsCount].index;
  1423. tokenIdx = prevBrushstroke[wallItemsCount].tokenIndex;
  1424. PaletteManager.selectedBrush.SetPatternTokenIndex(tokenIdx);
  1425. }
  1426. var scale = localRotation * ScaleMultiplier(nextIdx, settings);
  1427. scale.x = Mathf.Abs(scale.x);
  1428. scale.y = Mathf.Abs(scale.y);
  1429. scale.z = Mathf.Abs(scale.z);
  1430. AddBrushstrokeItem(nextIdx, tokenIdx, position, angle, scale, settings);
  1431. if (setNextIdx) PaletteManager.selectedBrush.SetNextItemIndex();
  1432. }
  1433. ++wallItemsCount;
  1434. }
  1435. for (int idx = 0; idx < cellsCount; ++idx)
  1436. {
  1437. var tangent = delta * idx;
  1438. var position = firstPoint + tangent;
  1439. AddItem(position, segmentAxis);
  1440. }
  1441. }
  1442. #endregion
  1443. #endregion
  1444. }
  1445. }