TC_SelectItemGroup.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. using UnityEngine;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. namespace TerrainComposer2
  6. {
  7. public class TC_SelectItemGroup : TC_GroupBehaviour
  8. {
  9. public List<TC_SelectItem> itemList = new List<TC_SelectItem>();
  10. [NonSerialized] public TC_SelectItem refreshRangeItem;
  11. public bool refreshRanges;
  12. public SplatCustom[] splatMixBuffer;
  13. public ColorItem[] colorMixBuffer;
  14. public ItemSettings[] indices; // layerLevel item list
  15. public Transform endT;
  16. public Vector2 scaleMinMaxMulti = Vector2.one;
  17. public float scaleMulti = 1;
  18. public float mix;
  19. public float scale = 1;
  20. public bool linkScaleToMask = true;
  21. public float linkScaleToMaskAmount = 1;
  22. public bool untouched = true;
  23. public int placed;
  24. public override void Awake()
  25. {
  26. if (!firstLoad)
  27. {
  28. t = transform;
  29. GetItems(true, true, false);
  30. if (TC_Settings.instance) linkScaleToMask = TC_Settings.instance.global.linkScaleToMaskDefault;
  31. }
  32. base.Awake();
  33. t.hideFlags = HideFlags.NotEditable | HideFlags.HideInInspector;
  34. }
  35. public override void OnEnable()
  36. {
  37. base.OnEnable();
  38. t.hideFlags = HideFlags.NotEditable | HideFlags.HideInInspector;
  39. }
  40. public override void OnDestroy()
  41. {
  42. if (preview.tex != null)
  43. {
  44. #if UNITY_EDITOR
  45. DestroyImmediate(preview.tex);
  46. #else
  47. Destroy(preview.tex);
  48. #endif
  49. }
  50. base.OnDestroy();
  51. }
  52. public override void CloneSetup()
  53. {
  54. base.CloneSetup();
  55. if (TC_Settings.instance == null) return;
  56. TC_Settings.instance.HasMasterTerrain(); // TODO make solution for this
  57. preview.tex = null;
  58. GetItems(true, true, false);
  59. }
  60. public override void OnTransformChildrenChanged()
  61. {
  62. refreshRanges = true;
  63. base.OnTransformChildrenChanged();
  64. }
  65. public void ResetPlaced()
  66. {
  67. for (int i = 0; i < itemList.Count; i++) itemList[i].placed = 0;
  68. }
  69. public int CalcPlaced()
  70. {
  71. placed = 0;
  72. for (int i = 0; i < itemList.Count; i++) placed += itemList[i].placed;
  73. return placed;
  74. }
  75. public void SetReadWriteTextureItems()
  76. {
  77. for (int i = 0; i < itemList.Count; i++) TC.SetTextureReadWrite(itemList[i].preview.tex);
  78. }
  79. public void ResetObjects()
  80. {
  81. for (int i = 0; i < itemList.Count; i++) itemList[i].ResetObjects();
  82. }
  83. public void CalcPreview(bool calcValues = true)
  84. {
  85. if (!TC_Settings.instance.hasMasterTerrain) return;
  86. if (itemList.Count > 1)
  87. {
  88. int length = TC_Settings.instance.masterTerrain.terrainData.splatPrototypes.Length;
  89. if (outputId == TC.splatOutput)
  90. {
  91. Texture2D[] texArray = new Texture2D[length];
  92. for (int i = 0; i < length; i++)
  93. {
  94. texArray[i] = TC_Settings.instance.masterTerrain.terrainData.splatPrototypes[i].texture;
  95. TC.SetTextureReadWrite(texArray[i]);
  96. }
  97. CalcPreview(texArray);
  98. }
  99. else
  100. {
  101. if (outputId == TC.grassOutput)
  102. {
  103. for (int i = 0; i < itemList.Count; i++) TC.SetTextureReadWrite(itemList[i].preview.tex);
  104. }
  105. CalcPreview(null);
  106. }
  107. }
  108. CreateMixBuffer();
  109. // Debug.Log("CalcPreview");
  110. TC.AutoGenerate();
  111. }
  112. void CalcPreview(Texture2D[] texArray)
  113. {
  114. preview.Init(128);
  115. float resolution = preview.tex.width;
  116. // TC_Reporter.BenchmarkStart();
  117. Color[] splatColors = TC_Settings.instance.global.previewColors;
  118. for (float y = 0; y < resolution; y++)
  119. {
  120. float normY = y / resolution;
  121. for (float x = 0; x < resolution; x++)
  122. {
  123. Color color = Color.black;
  124. float total = 0;
  125. float normX = x / resolution;
  126. if (normX > 0.90f) color = Color.white * normY;
  127. for (int i = 0; i < itemList.Count; i++)
  128. {
  129. TC_SelectItem item = itemList[i];
  130. if (!item.active) continue;
  131. float v = EvaluateItem(item, normY);
  132. if ((normY) < item.range.y + 0.004f && (normY) > item.range.y - 0.004f)
  133. {
  134. color = Color.red;
  135. total = 1;
  136. break;
  137. }
  138. else if (normX > 0.80f && normX <= 0.90f && outputId != TC.colorOutput)
  139. {
  140. float g = (normX - 0.80f) * 50;
  141. if (item.splatCustom)
  142. {
  143. for (int j = 0; j < texArray.Length; j++) color += (item.splatCustomValues[j] / item.splatCustomTotal) * splatColors[j] * v * g;
  144. }
  145. else
  146. {
  147. color += item.color * v * g;
  148. }
  149. total += v * g;
  150. }
  151. if ((v > 0 && normX <= 0.9f) || outputId == TC.colorOutput)
  152. {
  153. if (item.splatCustom)
  154. {
  155. for (int j = 0; j < texArray.Length; j++) color += (item.splatCustomValues[j] / item.splatCustomTotal) * texArray[j].GetPixel(Mathf.RoundToInt(normX * item.preview.tex.width), Mathf.RoundToInt(normY * item.preview.tex.height)) * v;
  156. }
  157. else
  158. {
  159. if (outputId != TC.colorOutput && item.preview.tex != null) color += item.preview.tex.GetPixel(Mathf.RoundToInt(normX * item.preview.tex.width), Mathf.RoundToInt(normY * item.preview.tex.height)) * v * Mathf.Lerp(1, 0, (normX - 0.8f) * 10);
  160. else color += item.color * v * Mathf.Lerp(1, 0, (normX - 0.8f) * 10);
  161. }
  162. total += v * Mathf.Lerp(1, 0, (normX - 0.8f) * 10);
  163. }
  164. }
  165. if (normX <= 0.9f) color /= total;
  166. preview.SetPixelColor(Mathf.RoundToInt(normX * resolution), Mathf.RoundToInt(normY * resolution), color);
  167. }
  168. }
  169. // TC_Reporter.BenchmarkStop();
  170. preview.UploadTexture();
  171. }
  172. public override void GetItems(bool refresh, bool rebuildGlobalLists, bool resetTextures)
  173. {
  174. if (resetTextures) DisposeTextures();
  175. itemList.Clear();
  176. totalActive = 0;
  177. int listIndex = 0;
  178. for (int i = t.childCount - 1; i >= 0; i--)
  179. {
  180. Transform child = t.GetChild(i);
  181. TC_SelectItem selectItem = child.GetComponent<TC_SelectItem>();
  182. if (selectItem == null) TC.MoveToDustbin(child);
  183. else
  184. {
  185. selectItem.SetParameters(this, listIndex);
  186. selectItem.parentItem = this;
  187. selectItem.active = selectItem.visible;
  188. if (outputId == TC.splatOutput && selectItem.splatCustom)
  189. {
  190. if (TC_Settings.instance.hasMasterTerrain)
  191. {
  192. if (selectItem.splatCustomValues == null) selectItem.splatCustomValues = new float[TC_Settings.instance.masterTerrain.terrainData.splatPrototypes.Length];
  193. else if (selectItem.splatCustomValues.Length != TC_Settings.instance.masterTerrain.terrainData.splatPrototypes.Length) selectItem.splatCustomValues = Mathw.ResizeArray(selectItem.splatCustomValues, TC_Settings.instance.masterTerrain.terrainData.splatPrototypes.Length);
  194. }
  195. selectItem.CalcSplatCustomTotal();
  196. }
  197. selectItem.SetPreviewItemTexture(); // Put deactive if listIndex is out of bounds
  198. if (selectItem.active) ++totalActive;
  199. if (outputId == TC.treeOutput)
  200. {
  201. if (selectItem.tree == null) selectItem.tree = new TC_SelectItem.Tree();
  202. if (selectItem.active)
  203. {
  204. bool addToList = true;
  205. List<TC_SelectItem> treeSelectItems = TC_Area2D.current.terrainLayer.treeSelectItems;
  206. if (!rebuildGlobalLists)
  207. {
  208. int index = treeSelectItems.IndexOf(selectItem);
  209. if (index != -1) { addToList = false; selectItem.globalListIndex = index; }
  210. }
  211. if (addToList)
  212. {
  213. treeSelectItems.Add(selectItem);
  214. selectItem.globalListIndex = treeSelectItems.Count - 1;
  215. }
  216. }
  217. }
  218. else if (outputId == TC.objectOutput)
  219. {
  220. if (selectItem.spawnObject == null) selectItem.spawnObject = new TC_SelectItem.SpawnObject();
  221. if (selectItem.spawnObject.go == null
  222. || (selectItem.spawnObject.parentMode == TC_SelectItem.SpawnObject.ParentMode.Existing && selectItem.spawnObject.parentT == null)
  223. || (selectItem.spawnObject.parentMode == TC_SelectItem.SpawnObject.ParentMode.Create && selectItem.spawnObject.parentName == ""))
  224. {
  225. selectItem.active = false;
  226. TC_Area2D.current.terrainLayer.objectSelectItems.Remove(selectItem);
  227. // Debug.Log("Remove from list");
  228. }
  229. if (selectItem.active)
  230. {
  231. bool addToList = true;
  232. TC_Area2D area2D;
  233. if (TC_Area2D.current == null)
  234. {
  235. area2D = FindObjectOfType<TC_Area2D>();
  236. }
  237. else area2D = TC_Area2D.current;
  238. List<TC_SelectItem> objectSelectItems = area2D.terrainLayer.objectSelectItems;
  239. if (!rebuildGlobalLists)
  240. {
  241. int index = objectSelectItems.IndexOf(selectItem);
  242. if (index != -1) { addToList = false; selectItem.globalListIndex = index; }
  243. }
  244. if (addToList)
  245. {
  246. objectSelectItems.Add(selectItem);
  247. selectItem.globalListIndex = objectSelectItems.Count - 1;
  248. }
  249. selectItem.selectIndex = listIndex;
  250. }
  251. }
  252. selectItem.SetPreviewItemTexture();
  253. if (selectItem.outputId != TC.colorOutput) selectItem.SetPreviewColor();
  254. itemList.Add(selectItem);
  255. listIndex++;
  256. }
  257. }
  258. if (refreshRangeItem != null || refreshRanges) {
  259. refreshRanges = false;
  260. RefreshRanges();
  261. refreshRangeItem = null;
  262. }
  263. else if (refresh || TC.refreshPreviewImages) CalcPreview();
  264. }
  265. public void RefreshRanges()
  266. {
  267. if (itemList.Count <= 1) untouched = true;
  268. if (untouched) ResetRanges(); else SetRanges(refreshRangeItem);
  269. }
  270. public void CreateMixBuffer()
  271. {
  272. if (outputId == TC.splatOutput || outputId == TC.grassOutput) CreateSplatMixBuffer();
  273. else if (outputId == TC.colorOutput) CreateColorMixBuffer();
  274. else CreateItemMixBuffer();
  275. }
  276. public void CreateItemMixBuffer()
  277. {
  278. // Debug.Log("Create Item Mix buffer");
  279. if (indices == null) indices = new ItemSettings[totalActive];
  280. else if (indices.Length != itemList.Count) indices = new ItemSettings[totalActive];
  281. int index = 0;
  282. for (int i = 0; i < itemList.Count; i++)
  283. {
  284. TC_SelectItem item = itemList[i];
  285. if (item.active)
  286. {
  287. indices[index++] = new ItemSettings(item.globalListIndex, outputId == TC.treeOutput ? item.tree.randomPosition : item.spawnObject.randomPosition, item.range, item.opacity * opacity);
  288. // Debug.Log(indices[index - 1].randomPosition);
  289. }
  290. }
  291. }
  292. public void CreateColorMixBuffer()
  293. {
  294. if (colorMixBuffer == null) colorMixBuffer = new ColorItem[totalActive];
  295. if (colorMixBuffer.Length != totalActive) colorMixBuffer = new ColorItem[totalActive];
  296. float blend = (mix + 0.001f) / totalActive;
  297. float range = 1 / blend;
  298. int index = 0;
  299. for (int i = 0; i < itemList.Count; i++)
  300. {
  301. TC_SelectItem item = itemList[i];
  302. if (item.active) colorMixBuffer[index++] = new ColorItem(new Vector3(item.range.x - blend, item.range.y, range), item.color);
  303. // Debug.Log(colorMixBuffer[i].select);
  304. }
  305. }
  306. public void CreateSplatMixBuffer()
  307. {
  308. // Debug.Log("Create splat mix buffer");
  309. if (splatMixBuffer == null) splatMixBuffer = new SplatCustom[totalActive];
  310. if (splatMixBuffer.Length != totalActive) splatMixBuffer = new SplatCustom[totalActive];
  311. float splatCustomTotal;
  312. float[] splatCustomValues;
  313. Vector4 custom0, custom1;
  314. float blend = (mix + 0.001f) / totalActive;
  315. float range = 1 / blend;
  316. int index = 0;
  317. for (int i = 0; i < itemList.Count; ++i)
  318. {
  319. TC_SelectItem selectItem = itemList[i];
  320. if (selectItem.active)
  321. {
  322. if (selectItem.splatCustom)
  323. {
  324. splatCustomTotal = selectItem.splatCustomTotal;
  325. splatCustomValues = selectItem.splatCustomValues;
  326. custom0 = new Vector4(splatCustomValues[0] / splatCustomTotal, splatCustomValues[1] / splatCustomTotal, splatCustomValues[2] / splatCustomTotal, splatCustomValues[3] / splatCustomTotal);
  327. custom1 = new Vector4(splatCustomValues[4] / splatCustomTotal, splatCustomValues[5] / splatCustomTotal, splatCustomValues[6] / splatCustomTotal, splatCustomValues[7] / splatCustomTotal);
  328. // Debug.Log(custom0 + " - " + custom1);
  329. }
  330. else
  331. {
  332. custom0 = Vector4.zero;
  333. custom1 = Vector4.zero;
  334. }
  335. splatMixBuffer[index++] = new SplatCustom(new Vector4(selectItem.range.x - blend, selectItem.range.y, range, selectItem.splatCustom ? -1 : selectItem.selectIndex), custom0, custom1, custom0, custom1);
  336. }
  337. }
  338. }
  339. public float EvaluateItem(TC_SelectItem selectItem, float time)
  340. {
  341. float r1, r2, r3;
  342. float blend = (mix + 0.001f) / totalActive;
  343. r2 = selectItem.range.x;
  344. r3 = selectItem.range.y;
  345. r2 += blend / 2;
  346. r3 -= blend / 2;
  347. r1 = r2 - blend;
  348. float range = 1 / blend;
  349. // Debug.Log(r1 + ", " + r2 + ", " + r3);
  350. // Debug.Log(range);
  351. if (time < r3) return Mathf.Lerp(0, 1, Mathf.Clamp01(time - r1) * range);
  352. else return Mathf.Lerp(1, 0, Mathf.Clamp01(time - r3) * range);
  353. }
  354. public void SetRanges(TC_SelectItem changedSelectItem = null, bool resetInActive = false)
  355. {
  356. if (itemList.Count == 0) { untouched = true; return; }
  357. if (changedSelectItem == null) changedSelectItem = itemList[0];
  358. TC_SelectItem selectItem;
  359. int index = changedSelectItem.active ? changedSelectItem.listIndex : 0;
  360. float x = itemList[index].range.x;
  361. float y = itemList[index].range.y;
  362. if (!resetInActive) untouched = false;
  363. for (int i = index + 1; i < itemList.Count; ++i)
  364. {
  365. selectItem = itemList[i];
  366. if (selectItem.active)
  367. {
  368. selectItem.range.x = y;
  369. selectItem.range.y = y = Mathf.Max(selectItem.range.x, selectItem.range.y);
  370. }
  371. }
  372. for (int i = index - 1; i >= 0; --i)
  373. {
  374. selectItem = itemList[i];
  375. if (selectItem.active)
  376. {
  377. selectItem.range.y = x;
  378. selectItem.range.x = x = Mathf.Min(selectItem.range.x, selectItem.range.y);
  379. }
  380. }
  381. selectItem = GetActiveItemUp(0);
  382. if (selectItem != null) selectItem.range.x = 0;
  383. selectItem = GetActiveItemDown(itemList.Count - 1);
  384. if (selectItem != null) selectItem.range.y = 1;
  385. if (resetInActive)
  386. {
  387. TC_SelectItem neighborItem;
  388. for (int i = 0; i < itemList.Count; i++)
  389. {
  390. selectItem = itemList[i];
  391. if (!selectItem.active)
  392. {
  393. neighborItem = GetActiveItemDown(i - 1);
  394. if (neighborItem != null) selectItem.range.y = selectItem.range.x = neighborItem.range.y;
  395. else selectItem.range.y = 0;
  396. neighborItem = GetActiveItemUp(i + 1);
  397. if (neighborItem != null) selectItem.range.x = selectItem.range.y = neighborItem.range.x;
  398. else selectItem.range.x = 1;
  399. }
  400. }
  401. }
  402. CalcPreview();
  403. }
  404. TC_SelectItem GetActiveItemUp(int index)
  405. {
  406. for (int i = index; i < itemList.Count; i++)
  407. {
  408. TC_SelectItem selectItem = itemList[i];
  409. if (selectItem.active) return selectItem;
  410. }
  411. return null;
  412. }
  413. TC_SelectItem GetActiveItemDown(int index)
  414. {
  415. // Debug.Log(index + " " + itemList.Count);
  416. for (int i = index; i >= 0; i--)
  417. {
  418. TC_SelectItem selectItem = itemList[i];
  419. if (selectItem.active) return selectItem;
  420. }
  421. return null;
  422. }
  423. public Vector2 GetInbetweenRange(int index)
  424. {
  425. Vector2 range;
  426. TC_SelectItem item;
  427. item = GetActiveItemUp(index);
  428. if (item != null) range.x = item.range.y; else range.x = 0;
  429. item = GetActiveItemDown(index);
  430. if (item != null) range.y = item.range.x; else range.y = 1;
  431. return range;
  432. }
  433. public void ResetRanges()
  434. {
  435. if (itemList.Count == 0) return;
  436. float average = 1.0f / totalActive;
  437. float x = 0;
  438. for (int i = 0; i < itemList.Count; i++)
  439. {
  440. TC_SelectItem selectItem = itemList[i];
  441. if (selectItem.active)
  442. {
  443. selectItem.range = new Vector2(x, x + average);
  444. x += average;
  445. }
  446. }
  447. SetRanges(itemList[0], true);
  448. }
  449. public void CenterRange(TC_SelectItem changedSelectItem)
  450. {
  451. if (!changedSelectItem.active) return;
  452. float average = 1.0f / totalActive;
  453. float x = 0;
  454. int index = 0;
  455. for (int i = 0; i < itemList.Count; i++)
  456. {
  457. TC_SelectItem selectItem = itemList[i];
  458. if (selectItem == changedSelectItem) { selectItem.range = new Vector2(x, x + average); index = i; break; }
  459. if (selectItem.active) x += average;
  460. }
  461. SetRanges(itemList[index], true);
  462. }
  463. public Vector2[] GetRanges()
  464. {
  465. Vector2[] ranges = new Vector2[itemList.Count];
  466. for (int i = 0; i < itemList.Count; i++) ranges[i] = itemList[i].range;
  467. return ranges;
  468. }
  469. public void SetRanges(Vector2[] ranges)
  470. {
  471. for (int i = 0; i < itemList.Count; i++)
  472. {
  473. if (i < ranges.Length) itemList[i].range = ranges[i];
  474. }
  475. }
  476. public override void SetFirstLoad(bool active)
  477. {
  478. base.SetFirstLoad(active);
  479. for (int i = 0; i < itemList.Count; i++) itemList[i].SetFirstLoad(active);
  480. }
  481. }
  482. //[Serializable]
  483. //public class SelectGroupItem
  484. //{
  485. // public itemGroup itemGroup;
  486. // public item item;
  487. // public SelectGroupItem(itemGroup layerGroup)
  488. // {
  489. // this.itemGroup = layerGroup;
  490. // }
  491. // public SelectGroupItem(item select)
  492. // {
  493. // this.item = select;
  494. // }
  495. //}
  496. [Serializable]
  497. public struct SplatCustom
  498. {
  499. public Vector4 select;
  500. public Vector4 map0;
  501. public Vector4 map1;
  502. public Vector4 map2;
  503. public Vector4 map3;
  504. public SplatCustom(Vector4 select, Vector4 map0, Vector4 map1, Vector4 map2, Vector4 map3)
  505. {
  506. this.select = select;
  507. this.map0 = map0;
  508. this.map1 = map1;
  509. this.map2 = map2;
  510. this.map3 = map3;
  511. }
  512. }
  513. [Serializable]
  514. public struct ColorItem
  515. {
  516. public Vector3 select;
  517. public Vector4 color;
  518. public ColorItem(Vector3 select, Vector4 color)
  519. {
  520. this.select = select;
  521. this.color = color;
  522. }
  523. }
  524. public struct ItemSettings
  525. {
  526. public int index;
  527. public float randomPosition;
  528. public Vector2 range;
  529. public float opacity;
  530. public ItemSettings(int index, float randomPosition, Vector2 range, float opacity)
  531. {
  532. this.index = index;
  533. this.randomPosition = randomPosition;
  534. this.range = range;
  535. this.opacity = opacity;
  536. }
  537. }
  538. }