1671 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			1671 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C#
		
	
	
	
/*
 | 
						|
	Tom's Terrain Tools for Unity 3D 
 | 
						|
	Version 2.6 (2015)
 | 
						|
	(C)2015 by Tom Vogt <tom@lemuria.org> & Unitycoder.com <support@unitycoder.com>
 | 
						|
	http://lemuria.org/Unity/TTT/
 | 
						|
	http://unitycoder.com/blog/2014/08/14/asset-store-terrain-tools/
 | 
						|
*/
 | 
						|
 | 
						|
using UnityEditor;
 | 
						|
using UnityEngine;
 | 
						|
using System.Collections;
 | 
						|
using System.IO;
 | 
						|
 | 
						|
namespace TTT
 | 
						|
{
 | 
						|
	public class TerrainTools : EditorWindow 
 | 
						|
	{
 | 
						|
		public Terrain myTerrain;
 | 
						|
 | 
						|
		private Object splatMap;
 | 
						|
		private bool defaultsDone = false;
 | 
						|
		private Texture2D[] splatTextures = new Texture2D[4];
 | 
						|
		private int tileSizeX=8;
 | 
						|
		private int tileSizeY=8;
 | 
						|
		private Texture2D[] splatTexNormals = new Texture2D[4];
 | 
						|
		private GameObject[] treeObjects = new GameObject[3];
 | 
						|
		private Texture2D[] grassTextures = new Texture2D[3];
 | 
						|
		private GameObject[] detailObjects = new GameObject[3]; // bushes, stones
 | 
						|
 | 
						|
		public Texture2D splatA;
 | 
						|
		public Texture2D splatB;
 | 
						|
 | 
						|
		public Texture2D treemap;
 | 
						|
		public bool resetTrees = true;
 | 
						|
		public float treeDensity = 0.4f;
 | 
						|
		public float treeThreshold = 0.1f;
 | 
						|
		public float treeSize = 1f;
 | 
						|
		public float sizeVariation = 0.2f;
 | 
						|
 | 
						|
		public Texture2D grassmap;
 | 
						|
		public Texture2D bushmap;
 | 
						|
		public float grassDensity = 0.15f;
 | 
						|
		public float grassclumping = 0.5f;
 | 
						|
		public float bushDensity = 0.02f;
 | 
						|
		
 | 
						|
		public Texture2D overlayMap;
 | 
						|
		public float overlayThreshold = 0.1f;
 | 
						|
		public Texture2D overlayTexture;
 | 
						|
		public int tileSize = 15;
 | 
						|
		public bool clearTrees = false;
 | 
						|
		public float clearRadius = 1.0f;
 | 
						|
		public bool clearGrass = true;
 | 
						|
		public float changeTerrain = 0.0f;
 | 
						|
 | 
						|
		// internal variables
 | 
						|
		GUIStyle boldTitleStyle;
 | 
						|
		Vector2 scrollPosition = new Vector2(0,0);
 | 
						|
		bool toggleSplat = true;
 | 
						|
		bool toggleTrees = true;
 | 
						|
		bool toggleGrass = true;
 | 
						|
		bool toggleOverlay=false;
 | 
						|
		bool toggleAutoMagic=false;
 | 
						|
		bool toggleAdvanced=false;
 | 
						|
 | 
						|
		// default terrain settings
 | 
						|
		int terrainInitWidth=2000;
 | 
						|
		int terrainInitLength=2000;
 | 
						|
		int terrainInitHeight=200;
 | 
						|
		float windSettingsSpeed = 0.2f;
 | 
						|
		float windSettingsSize = 0.2f;
 | 
						|
		float windSettingsBending = 0.2f;
 | 
						|
 | 
						|
		bool assignNormalMapsIfFounded=true; // checks if texture has normals map in same folder: texturename.png & texturename_normal.png
 | 
						|
 | 
						|
		string[] texturePackOptionTitles = new string[] {"Default", "Plain colors#1", "Debug"};
 | 
						|
		int selectedTexturePack = 0; // which texture pack is selected (file names are hardcoded at AutoMagicDefaults()
 | 
						|
 | 
						|
		System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); // timer for timing method durations
 | 
						|
 | 
						|
 | 
						|
		bool timeStampFileNames=false; // if enabled, every time you generate, new terrain is saved with a new name (as new terrain)
 | 
						|
 | 
						|
		[MenuItem("Window/Terrain Tools/Terrain Tools",false,0)]
 | 
						|
		static void Init() 
 | 
						|
		{
 | 
						|
			TerrainTools window = (TerrainTools)EditorWindow.GetWindow(typeof(TerrainTools));
 | 
						|
			window.titleContent = new GUIContent("TerrainTools");
 | 
						|
			window.minSize = new Vector2(410,400);
 | 
						|
			window.Show();
 | 
						|
		}
 | 
						|
 | 
						|
		void OnInspectorUpdate() 
 | 
						|
		{
 | 
						|
			Repaint();
 | 
						|
		}
 | 
						|
 | 
						|
		void OnGUI() 
 | 
						|
		{
 | 
						|
			EditorGUILayout.BeginVertical(GUI.skin.box, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
 | 
						|
			scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
 | 
						|
 | 
						|
			DrawTitleGUI();
 | 
						|
 | 
						|
			boldTitleStyle = new GUIStyle(EditorStyles.foldout);
 | 
						|
			boldTitleStyle.fontStyle = FontStyle.Bold;
 | 
						|
 | 
						|
			EditorGUILayout.Separator();
 | 
						|
			GUILayout.BeginHorizontal();
 | 
						|
				GUILayout.Label("Terrain");
 | 
						|
				myTerrain = (Terrain)EditorGUILayout.ObjectField("", myTerrain, typeof(Terrain),true);
 | 
						|
			GUILayout.EndHorizontal();
 | 
						|
			EditorGUILayout.Separator();
 | 
						|
 | 
						|
			DrawAutoMagicGUI();
 | 
						|
			DrawTexturingGUI(); 
 | 
						|
			DrawTreeDistributionGUI(); 
 | 
						|
			DrawGrassGUI(); 
 | 
						|
			DrawOverlayGUI(); 
 | 
						|
 | 
						|
			EditorGUILayout.EndScrollView();
 | 
						|
			EditorGUILayout.EndVertical();
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		static void DrawTitleGUI ()
 | 
						|
		{
 | 
						|
			GUILayout.BeginHorizontal ();
 | 
						|
			GUILayout.Label ("Terrain Tools v2.6", EditorStyles.boldLabel);
 | 
						|
			GUILayout.FlexibleSpace ();
 | 
						|
			if (GUILayout.Button ("Read Manual")) {
 | 
						|
				Help.BrowseURL ("http://lemuria.org/Unity/TTT/");
 | 
						|
			}
 | 
						|
			GUILayout.EndHorizontal ();
 | 
						|
			EditorGUILayout.Separator ();
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		void DrawAutoMagicGUI()
 | 
						|
		{
 | 
						|
			toggleAutoMagic = EditorGUILayout.Foldout (toggleAutoMagic, "AutoMagic", boldTitleStyle);
 | 
						|
			if (toggleAutoMagic) 
 | 
						|
			{
 | 
						|
				if (!defaultsDone) AutoMagicDefaults ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				splatMap = EditorGUILayout.ObjectField (new GUIContent ("Splatmap Object", "Heightmap, Splatmap, Treemap, Grassmap"), splatMap, typeof(Object), false);
 | 
						|
				GUILayout.EndHorizontal();
 | 
						|
				GUILayout.BeginHorizontal();
 | 
						|
				EditorGUILayout.PrefixLabel("Textures");
 | 
						|
				GUILayout.FlexibleSpace();
 | 
						|
				splatTextures[0] = (Texture2D)EditorGUILayout.ObjectField (splatTextures [0], typeof(Texture2D), false, GUILayout.Height (48));
 | 
						|
				splatTextures[1] = (Texture2D)EditorGUILayout.ObjectField (splatTextures [1], typeof(Texture2D), false, GUILayout.Height (48));
 | 
						|
				splatTextures[2] = (Texture2D)EditorGUILayout.ObjectField (splatTextures [2], typeof(Texture2D), false, GUILayout.Height (48));
 | 
						|
				splatTextures[3] = (Texture2D)EditorGUILayout.ObjectField (splatTextures [3], typeof(Texture2D), false, GUILayout.Height (48));
 | 
						|
				GUILayout.EndHorizontal();
 | 
						|
				GUILayout.BeginHorizontal();
 | 
						|
				EditorGUILayout.PrefixLabel("Trees");
 | 
						|
				GUILayout.FlexibleSpace();
 | 
						|
				treeObjects[0] = (GameObject)EditorGUILayout.ObjectField (treeObjects [0], typeof(GameObject), false);
 | 
						|
				treeObjects[1] = (GameObject)EditorGUILayout.ObjectField (treeObjects [1], typeof(GameObject), false);
 | 
						|
				treeObjects[2] = (GameObject)EditorGUILayout.ObjectField (treeObjects [2], typeof(GameObject), false);
 | 
						|
				GUILayout.EndHorizontal();
 | 
						|
 | 
						|
				GUILayout.BeginHorizontal();
 | 
						|
				EditorGUILayout.PrefixLabel ("Grass");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				grassTextures[0] = (Texture2D)EditorGUILayout.ObjectField (grassTextures [0], typeof(Texture2D), false, GUILayout.Height (32));
 | 
						|
				grassTextures[1] = (Texture2D)EditorGUILayout.ObjectField (grassTextures [1], typeof(Texture2D), false, GUILayout.Height (32));
 | 
						|
				grassTextures[2] = (Texture2D)EditorGUILayout.ObjectField (grassTextures [2], typeof(Texture2D), false, GUILayout.Height (32));
 | 
						|
				GUILayout.EndHorizontal();
 | 
						|
				EditorGUILayout.Separator();
 | 
						|
 | 
						|
				GUILayout.BeginHorizontal();
 | 
						|
				EditorGUILayout.PrefixLabel("Detail meshes");
 | 
						|
				GUILayout.FlexibleSpace();
 | 
						|
				detailObjects[0] = (GameObject)EditorGUILayout.ObjectField (detailObjects[0], typeof(GameObject), false);
 | 
						|
				detailObjects[1] = (GameObject)EditorGUILayout.ObjectField (detailObjects[1], typeof(GameObject), false);
 | 
						|
				detailObjects[2] = (GameObject)EditorGUILayout.ObjectField (detailObjects[2], typeof(GameObject), false);
 | 
						|
				GUILayout.EndHorizontal();
 | 
						|
				EditorGUILayout.Separator();
 | 
						|
 | 
						|
 | 
						|
				GUILayout.BeginHorizontal();
 | 
						|
				GUILayout.FlexibleSpace();
 | 
						|
 | 
						|
				if (GUILayout.Button ("Run AutoMagic", GUILayout.Width (200), GUILayout.Height (32)))
 | 
						|
				{
 | 
						|
					AutoMagic();
 | 
						|
				}
 | 
						|
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
 | 
						|
 | 
						|
				toggleAdvanced = EditorGUILayout.Foldout(toggleAdvanced, "Advanced Settings", boldTitleStyle);
 | 
						|
				if (toggleAdvanced) 
 | 
						|
				{
 | 
						|
					// texture pack selection
 | 
						|
					GUI.changed = false;
 | 
						|
					selectedTexturePack = EditorGUILayout.Popup("Texture pack",selectedTexturePack, texturePackOptionTitles);
 | 
						|
					if (GUI.changed) 
 | 
						|
					{
 | 
						|
						AutoMagicDefaults(); // reload texture on change
 | 
						|
					}else{
 | 
						|
					}
 | 
						|
					GUILayout.BeginHorizontal();
 | 
						|
					GUILayout.FlexibleSpace ();
 | 
						|
					if (GUILayout.Button ("Apply Textures to Terrain", GUILayout.Width (200), GUILayout.Height (22)))
 | 
						|
					{
 | 
						|
						ApplySelectedTexturesToTerrain();
 | 
						|
					}
 | 
						|
					GUILayout.EndHorizontal ();
 | 
						|
					EditorGUILayout.Separator();
 | 
						|
 | 
						|
					// create timestamped filenames for terrain (unique terrains for each generation)
 | 
						|
					timeStampFileNames = EditorGUILayout.Toggle("Unique terrain files",timeStampFileNames);
 | 
						|
					EditorGUILayout.Separator();
 | 
						|
 | 
						|
					// terrain default settings
 | 
						|
					terrainInitWidth = EditorGUILayout.IntSlider ("Terrain Width",terrainInitWidth,100,8000);
 | 
						|
					terrainInitLength = EditorGUILayout.IntSlider ("Terrain Length",terrainInitLength,100,8000);
 | 
						|
					terrainInitHeight = EditorGUILayout.IntSlider ("Terrain Height",terrainInitHeight,100,8000);
 | 
						|
					tileSizeY = EditorGUILayout.IntField("Texture Tiling Y",(int)Mathf.Clamp(tileSizeY,1,9999));
 | 
						|
					tileSizeX = EditorGUILayout.IntField("Texture Tiling X",(int)Mathf.Clamp(tileSizeX,1,9999));
 | 
						|
					EditorGUILayout.Separator();
 | 
						|
 | 
						|
					// misc options
 | 
						|
					assignNormalMapsIfFounded = EditorGUILayout.Toggle("Use normal maps if founded",assignNormalMapsIfFounded);
 | 
						|
 | 
						|
 | 
						|
				}
 | 
						|
			}
 | 
						|
			GUILayout.FlexibleSpace ();
 | 
						|
			EditorGUILayout.Separator ();
 | 
						|
		}
 | 
						|
 | 
						|
		void DrawTexturingGUI ()
 | 
						|
		{
 | 
						|
			toggleSplat = EditorGUILayout.Foldout (toggleSplat, "Texturing", boldTitleStyle);
 | 
						|
			if (toggleSplat) {
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				EditorGUILayout.PrefixLabel ("First Splatmap");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				splatA = (Texture2D)EditorGUILayout.ObjectField ("", splatA, typeof(Texture2D), false);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				EditorGUILayout.Separator ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Second Splatmap (optional)");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				splatB = (Texture2D)EditorGUILayout.ObjectField ("", splatB, typeof(Texture2D), false);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				if (GUILayout.Button ("Apply Splatmap(s)", GUILayout.Width (200), GUILayout.Height (32))) {
 | 
						|
					if (CheckSplatmap())
 | 
						|
					{
 | 
						|
						ApplySplatmap();
 | 
						|
					}else{
 | 
						|
						Debug.LogError("No first splatmap assigned");
 | 
						|
					}
 | 
						|
				}
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
			}
 | 
						|
			EditorGUILayout.Separator ();
 | 
						|
		}
 | 
						|
 | 
						|
		void DrawTreeDistributionGUI ()
 | 
						|
		{
 | 
						|
			toggleTrees = EditorGUILayout.Foldout (toggleTrees, "Tree Distribution", boldTitleStyle);
 | 
						|
			if (toggleTrees) {
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Tree map");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				treemap = (Texture2D)EditorGUILayout.ObjectField ("", treemap, typeof(Texture2D), false);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Clear Existing Trees?");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				resetTrees = EditorGUILayout.Toggle ("remove trees", resetTrees);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				EditorGUILayout.Separator ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Tree Density");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				treeDensity = EditorGUILayout.Slider (treeDensity, 0.05f, 3f);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Threshold");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				treeThreshold = EditorGUILayout.Slider (treeThreshold, 0.01f, 0.99f);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Tree Size");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				treeSize = EditorGUILayout.Slider (treeSize, 0.2f, 5f);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Size Variation");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				sizeVariation = EditorGUILayout.Slider (sizeVariation, 0f, 1f);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				if (GUILayout.Button ("Generate Trees", GUILayout.Width (200), GUILayout.Height (32))) 
 | 
						|
				{
 | 
						|
					if (CheckTreemap())	ApplyTreemap();
 | 
						|
				}
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
			}
 | 
						|
			EditorGUILayout.Separator ();
 | 
						|
		}
 | 
						|
 | 
						|
		void DrawGrassGUI ()
 | 
						|
		{
 | 
						|
			toggleGrass = EditorGUILayout.Foldout (toggleGrass, "Grass and Details", boldTitleStyle);
 | 
						|
			if (toggleGrass) {
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Grass map");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				grassmap = (Texture2D)EditorGUILayout.ObjectField ("", grassmap, typeof(Texture2D), false);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				EditorGUILayout.Separator ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Bush/Detail map");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				bushmap = (Texture2D)EditorGUILayout.ObjectField ("", bushmap, typeof(Texture2D), false);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Grass Density");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				grassDensity = EditorGUILayout.Slider (grassDensity, 0.01f, 3f);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Grass Clumping");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				grassclumping = EditorGUILayout.Slider (grassclumping, 0f, 1f);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Bush/Detail Density");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				bushDensity = EditorGUILayout.Slider (bushDensity, 0.01f, 2f);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				if (GUILayout.Button ("Generate Grass and Details", GUILayout.Width (200), GUILayout.Height (32))) 
 | 
						|
				{
 | 
						|
					if (CheckGrassmap ()) ApplyGrassmap();
 | 
						|
				}
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
			}
 | 
						|
			EditorGUILayout.Separator ();
 | 
						|
		}
 | 
						|
 | 
						|
		void DrawOverlayGUI ()
 | 
						|
		{
 | 
						|
			toggleOverlay = EditorGUILayout.Foldout (toggleOverlay, "Overlays (roads, rivers, etc)", boldTitleStyle);
 | 
						|
			if (toggleOverlay) 
 | 
						|
			{
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Overlay map");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				overlayMap = (Texture2D)EditorGUILayout.ObjectField ("", overlayMap, typeof(Texture2D), false);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Threshold");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				overlayThreshold = EditorGUILayout.Slider (overlayThreshold, 0.1f, 0.9f);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Overlay texture");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				overlayTexture = (Texture2D)EditorGUILayout.ObjectField ("", overlayTexture, typeof(Texture2D), false);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Tile size");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				tileSize = EditorGUILayout.IntSlider (tileSize, 3, 127);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Clear trees");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				clearTrees = EditorGUILayout.Toggle ("", clearTrees);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Clear tree radius");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				clearRadius = EditorGUILayout.Slider (clearRadius, 0.5f, 10.0f);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Clear grass/detail");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				clearGrass = EditorGUILayout.Toggle ("", clearGrass);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.Label ("Raise/lower terrain");
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				changeTerrain = EditorGUILayout.Slider (changeTerrain, -50f, 50f);
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
				GUILayout.BeginHorizontal ();
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				if (GUILayout.Button ("Generate Overlay", GUILayout.Width (200), GUILayout.Height (32))) 
 | 
						|
				{
 | 
						|
					if (CheckOverlaymap()) ApplyOverlaymap ();
 | 
						|
				}
 | 
						|
				GUILayout.FlexibleSpace ();
 | 
						|
				GUILayout.EndHorizontal ();
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		public void FixTextureSettings(Texture2D texture) 
 | 
						|
		{
 | 
						|
			if (texture==null) {Debug.LogError("FixFormat failed - Texture is null"); return;}
 | 
						|
 | 
						|
			string path = AssetDatabase.GetAssetPath(texture);
 | 
						|
 | 
						|
			if (string.IsNullOrEmpty(path)) {Debug.LogError("FixFormat failed - Texture path is null"); return;}
 | 
						|
 | 
						|
			
 | 
						|
			TextureImporter textureImporter = AssetImporter.GetAtPath(path) as TextureImporter;
 | 
						|
 | 
						|
			if (!textureImporter.isReadable) 
 | 
						|
			{
 | 
						|
				Debug.Log("File:"+path+" needs fixing: wrong texture format or not marked as read/write allowed");
 | 
						|
				textureImporter.mipmapEnabled = false;
 | 
						|
				textureImporter.isReadable = true;
 | 
						|
				AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
 | 
						|
			}
 | 
						|
 | 
						|
		}
 | 
						|
		
 | 
						|
		public static string Reverse(string text) 
 | 
						|
		{
 | 
						|
		   if (text == null) return null;
 | 
						|
 | 
						|
		   // this was posted by petebob as well 
 | 
						|
		   char[] array = text.ToCharArray();
 | 
						|
		   System.Array.Reverse(array);
 | 
						|
	      return new string(array);
 | 
						|
		}
 | 
						|
 | 
						|
		public string FindFile(string basename) 
 | 
						|
		{
 | 
						|
			string[] extensions = {"tif", "tiff", "png", "jpg", "jpeg","TIF", "TIFF", "PNG", "JPG", "JPEG"};
 | 
						|
			foreach (string ext in extensions) 
 | 
						|
			{
 | 
						|
				string filename = basename + "." + ext;
 | 
						|
 | 
						|
//				Debug.Log(filename);
 | 
						|
				if (File.Exists(filename)) 
 | 
						|
				{
 | 
						|
					return filename;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return null;
 | 
						|
			
 | 
						|
		}
 | 
						|
		
 | 
						|
		void AutoMagic() 
 | 
						|
		{
 | 
						|
			if (splatMap == null) {Debug.LogError("No splatmap assigned"); return;}
 | 
						|
			if (!ValidateAutomagicTextures()) {Debug.LogError("Not all textures are assigned"); return;}
 | 
						|
			if (!ValidateAutomagicTrees()) {Debug.LogError("Not all trees are assigned"); return;}
 | 
						|
			// TODO: validate grass and bushes?
 | 
						|
 | 
						|
			string origPath = AssetDatabase.GetAssetPath(splatMap);
 | 
						|
			string pathrev = Reverse(Path.GetFileNameWithoutExtension(origPath));
 | 
						|
			string[] parts = pathrev.Split(new char[] { '-' }, 2);
 | 
						|
 | 
						|
			if (parts==null || parts.Length<2) {Debug.LogError("Filenames must start with \"number\" and \"-\" character. Example: 1-splatmap.tif"); return;}
 | 
						|
 | 
						|
			string basename = Reverse(parts[1]);
 | 
						|
			string dirname = Path.GetDirectoryName(origPath);
 | 
						|
			string fixedPath = Path.Combine(dirname, basename);
 | 
						|
 | 
						|
			string splatmap_name = FindFile(fixedPath+"-splatmap");
 | 
						|
 | 
						|
			if (!File.Exists(splatmap_name)) {Debug.LogError("Splatmap file not found:"+splatmap_name+" \n Make sure that your filenames start with \"number\" and \"-\" character. Example: 1-splatmap.tif"); return;}
 | 
						|
			splatA = AssetDatabase.LoadAssetAtPath(splatmap_name, typeof(Texture2D)) as Texture2D;
 | 
						|
			CheckSplatmap();
 | 
						|
 | 
						|
			string treemap_name = FindFile(fixedPath+"-treemap");
 | 
						|
			if (File.Exists(treemap_name)) 
 | 
						|
			{
 | 
						|
				//Debug.LogError("Treemap file not found:"+treemap_name+" \n Make sure that your filenames start with \"number\" and \"-\" character. Example: 1-splatmap.tif"); return;}
 | 
						|
				treemap = AssetDatabase.LoadAssetAtPath(treemap_name, typeof(Texture2D)) as Texture2D;
 | 
						|
				CheckTreemap();
 | 
						|
			}else{
 | 
						|
				treemap_name=null;
 | 
						|
			}
 | 
						|
 | 
						|
			string grassmap_name = FindFile(fixedPath+"-grassmap");
 | 
						|
			if (File.Exists(grassmap_name)) {
 | 
						|
				//Debug.LogError("Grassmap file not found:"+grassmap_name+" \n Make sure that your filenames start with \"number\" and \"-\" character. Example: 1-splatmap.tif"); return;}
 | 
						|
				grassmap = AssetDatabase.LoadAssetAtPath(grassmap_name, typeof(Texture2D)) as Texture2D;
 | 
						|
				CheckGrassmap();
 | 
						|
			}else{
 | 
						|
				grassmap_name=null;
 | 
						|
			}
 | 
						|
 | 
						|
			string bushmap_name = FindFile(fixedPath+"-bushmap");
 | 
						|
			if (File.Exists(bushmap_name)) {
 | 
						|
				//Debug.LogError("Grassmap file not found:"+grassmap_name+" \n Make sure that your filenames start with \"number\" and \"-\" character. Example: 1-splatmap.tif"); return;}
 | 
						|
				bushmap = AssetDatabase.LoadAssetAtPath(bushmap_name, typeof(Texture2D)) as Texture2D;
 | 
						|
				CheckGrassmap();
 | 
						|
			}else{
 | 
						|
				grassmap_name=null;
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			CreateTerrain(fixedPath, splatA.width);
 | 
						|
 | 
						|
			if (myTerrain.terrainData==null) {Debug.LogError("Terrain generation failed.."); return;};
 | 
						|
 | 
						|
			string heightmap_name = fixedPath+"-heightmap.raw";
 | 
						|
			myTerrain.terrainData.SetHeights(0, 0, ReadRawHeightMap(heightmap_name, splatA.width+1,myTerrain.terrainData.heightmapResolution,myTerrain.terrainData.heightmapResolution));
 | 
						|
 | 
						|
			ApplySelectedTexturesToTerrain();
 | 
						|
			ApplySplatmap();
 | 
						|
 | 
						|
			if (treemap_name!=null)
 | 
						|
			{
 | 
						|
				myTerrain.terrainData.treePrototypes = SetupTrees();
 | 
						|
				myTerrain.terrainData.RefreshPrototypes();
 | 
						|
				ApplyTreemap();
 | 
						|
			}
 | 
						|
 | 
						|
			if (grassmap_name!=null)
 | 
						|
			{
 | 
						|
				myTerrain.terrainData.detailPrototypes = SetupGrassAndDetails();
 | 
						|
				myTerrain.terrainData.RefreshPrototypes();
 | 
						|
				ApplyGrassmap();
 | 
						|
			}
 | 
						|
			/*
 | 
						|
			if (bushmap_name!=null)
 | 
						|
			{
 | 
						|
				myTerrain.terrainData.detailPrototypes = SetupDetailMeshes();
 | 
						|
				myTerrain.terrainData.RefreshPrototypes();
 | 
						|
				ApplyBushmap();
 | 
						|
			}*/
 | 
						|
 | 
						|
		}
 | 
						|
		
 | 
						|
		void AutoMagicDefaults() 
 | 
						|
		{
 | 
						|
			// TODO: add normals also, for now just clear them
 | 
						|
			for (int i = 0; i < splatTexNormals.Length; i++) {
 | 
						|
				splatTexNormals[i]=null;
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
			string tempFilePath = "";
 | 
						|
			string tempFileName = "";
 | 
						|
			switch (selectedTexturePack)
 | 
						|
			{
 | 
						|
			// Default texture set #1
 | 
						|
			case 0:
 | 
						|
				tempFilePath = "Assets/Terrain Assets/Textures/";
 | 
						|
				tempFileName = "Grass (Meadows).jpg";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[0] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				tempFileName = "Grass (Hill).jpg";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[1] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				tempFileName = "Grass&Rock.jpg";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[2] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				tempFileName = "Grass (Muddy).jpg";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[3] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				break;
 | 
						|
 | 
						|
			// Default texture set #2
 | 
						|
			case 1:
 | 
						|
				tempFilePath = "Assets/Terrain Assets/Textures/SingleColor/";
 | 
						|
				tempFileName = "green_color_tile-1.png";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[0] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				tempFileName = "brown_color_tile-2.png";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[1] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				tempFileName = "lite_green_color_tile-3.png";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[2] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				tempFileName = "lite_green2_color_tile-4.png";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[3] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				break;
 | 
						|
 | 
						|
			// Default texture set #3
 | 
						|
			case 2:
 | 
						|
				tempFilePath = "Assets/Terrain Assets/Textures/Debug/";
 | 
						|
				tempFileName = "debug_red.png";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[0] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				tempFileName = "debug_green.png";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[1] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				tempFileName = "debug_blue.png";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[2] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				tempFileName = "debug_white.png";
 | 
						|
				if (File.Exists(tempFilePath+tempFileName)) splatTextures[3] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				Debug.LogError("Invalid selectedTexturePack value : "+selectedTexturePack);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			// default trees
 | 
						|
			tempFilePath = "Assets/Terrain Assets/Trees Ambient-Occlusion/";
 | 
						|
			tempFileName = "Alder.fbx";
 | 
						|
			if (File.Exists(tempFilePath+tempFileName)) treeObjects[0] = (GameObject)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(GameObject));
 | 
						|
 | 
						|
			tempFileName = "Sycamore.fbx";
 | 
						|
			if (File.Exists(tempFilePath+tempFileName)) treeObjects[1] = (GameObject)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(GameObject));
 | 
						|
 | 
						|
			tempFileName = "Mimosa.fbx";
 | 
						|
			if (File.Exists(tempFilePath+tempFileName)) treeObjects[2] = (GameObject)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(GameObject));
 | 
						|
 | 
						|
			// default grass
 | 
						|
			tempFilePath = "Assets/Standard Assets/Environment/TerrainAssets/BillboardTextures/";
 | 
						|
			tempFileName = "GrassFrond01AlbedoAlpha.psd";
 | 
						|
			if (File.Exists(tempFilePath+tempFileName)) grassTextures[0] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
 | 
						|
			tempFilePath = "Assets/Terrain Assets/Grass/";
 | 
						|
			tempFileName = "Fern.psd";
 | 
						|
			if (File.Exists(tempFilePath+tempFileName)) grassTextures[1] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
 | 
						|
			tempFilePath = "Assets/Standard Assets/Environment/TerrainAssets/BillboardTextures/";
 | 
						|
			tempFileName = "GrassFrond02AlbedoAlpha.psd";
 | 
						|
			if (File.Exists(tempFilePath+tempFileName)) grassTextures[2] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(Texture2D));
 | 
						|
 | 
						|
 | 
						|
			// default detail meshes
 | 
						|
			tempFilePath = "Assets/Terrain Assets/Bushes/";
 | 
						|
			tempFileName = "Bush5.fbx";
 | 
						|
			if (File.Exists(tempFilePath+tempFileName)) 
 | 
						|
			{
 | 
						|
				detailObjects[0] = (GameObject)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(GameObject));
 | 
						|
			}else{
 | 
						|
				Debug.LogWarning("Default object missing : "+tempFilePath+tempFileName);
 | 
						|
			}
 | 
						|
			tempFileName = "Bush7.fbx";
 | 
						|
			if (File.Exists(tempFilePath+tempFileName)) {
 | 
						|
				detailObjects[1] = (GameObject)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(GameObject));
 | 
						|
			}else{
 | 
						|
				Debug.LogWarning("Default object missing : "+tempFilePath+tempFileName);
 | 
						|
			}
 | 
						|
			tempFilePath = "Assets/Terrain Assets/Rocks/";
 | 
						|
			tempFileName = "RockMesh.fbx";
 | 
						|
			if (File.Exists(tempFilePath+tempFileName)) {
 | 
						|
					detailObjects[2] = (GameObject)AssetDatabase.LoadAssetAtPath(tempFilePath+tempFileName, typeof(GameObject));
 | 
						|
			}else{
 | 
						|
				Debug.LogWarning("Default object missing : "+tempFilePath+tempFileName);
 | 
						|
			}
 | 
						|
 | 
						|
			defaultsDone = true;
 | 
						|
		}
 | 
						|
 | 
						|
		bool ValidateAutomagicTextures()
 | 
						|
		{
 | 
						|
			if (splatTextures[0]==null || splatTextures[1]==null || splatTextures[2]==null || splatTextures[3]==null) return false;
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		bool ValidateAutomagicTrees()
 | 
						|
		{
 | 
						|
			if (treeObjects[0]==null || treeObjects[1]==null || treeObjects[2]==null) return false;
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		SplatPrototype[] SetupTextures() 
 | 
						|
		{
 | 
						|
			SetupTextureNormals();
 | 
						|
 | 
						|
			//Vector2 tilesize = new Vector2(40f, 40f);
 | 
						|
 | 
						|
			SplatPrototype[] Splat = new SplatPrototype[4];
 | 
						|
 | 
						|
			for (int i = 0; i < 4; i++) 
 | 
						|
			{
 | 
						|
				Splat[i] = new SplatPrototype();
 | 
						|
				Splat[i].texture = splatTextures[i];
 | 
						|
				if (assignNormalMapsIfFounded) Splat[i].normalMap = splatTexNormals[i];
 | 
						|
				Splat[i].tileSize = new Vector2(tileSizeX,tileSizeY);
 | 
						|
			}
 | 
						|
 | 
						|
			return Splat;
 | 
						|
		}
 | 
						|
 | 
						|
		void SetupTextureNormals()
 | 
						|
		{
 | 
						|
			for (int i = 0; i < 4; i++) 
 | 
						|
			{
 | 
						|
				string tempFileName = AssetDatabase.GetAssetPath(splatTextures[i]);
 | 
						|
				string tempFileWithoutExtension = Path.GetFileNameWithoutExtension(tempFileName);
 | 
						|
				if (assignNormalMapsIfFounded)
 | 
						|
				{
 | 
						|
					string tempNormalMapFile = Path.GetDirectoryName(tempFileName)+Path.DirectorySeparatorChar+tempFileWithoutExtension+"_normal"+Path.GetExtension(tempFileName);
 | 
						|
					if (File.Exists(tempNormalMapFile)) splatTexNormals[i] = (Texture2D)AssetDatabase.LoadAssetAtPath(tempNormalMapFile, typeof(Texture2D));
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		TreePrototype[] SetupTrees() {
 | 
						|
			TreePrototype[] trees = new TreePrototype[3];
 | 
						|
			trees[0] = new TreePrototype();
 | 
						|
			trees[0].prefab = treeObjects[0];
 | 
						|
			trees[1] = new TreePrototype();
 | 
						|
			trees[1].prefab = treeObjects[1];
 | 
						|
			trees[2] = new TreePrototype();
 | 
						|
			trees[2].prefab = treeObjects[2];
 | 
						|
			return trees;
 | 
						|
		}
 | 
						|
		
 | 
						|
		DetailPrototype[] SetupGrassAndDetails() 
 | 
						|
		{
 | 
						|
			// TODO: only take used amount from automagic, skip nulls
 | 
						|
			DetailPrototype[] details = new DetailPrototype[6];
 | 
						|
 | 
						|
 | 
						|
			// grass
 | 
						|
			details[0] = new DetailPrototype();
 | 
						|
			if (grassTextures[0]!=null)
 | 
						|
			{
 | 
						|
				details[0].prototypeTexture = grassTextures[0];
 | 
						|
				details[0].renderMode = DetailRenderMode.Grass;
 | 
						|
				details[0].usePrototypeMesh=false;
 | 
						|
				details[0].minHeight = 0.55f;
 | 
						|
				details[0].maxHeight = 0.77f;
 | 
						|
				details[0].healthyColor = Color.white;
 | 
						|
				details[0].dryColor = Color.gray;
 | 
						|
 | 
						|
			}
 | 
						|
			details[1] = new DetailPrototype();
 | 
						|
			if (grassTextures[1]!=null)
 | 
						|
			{
 | 
						|
				details[1].prototypeTexture = grassTextures[1];
 | 
						|
				details[1].renderMode = DetailRenderMode.Grass;
 | 
						|
				details[1].usePrototypeMesh=false;
 | 
						|
				details[1].minHeight = 0.66f;
 | 
						|
				details[1].maxHeight = 0.88f;
 | 
						|
				details[1].healthyColor = Color.white;
 | 
						|
				details[1].dryColor = Color.gray;
 | 
						|
			}
 | 
						|
			details[2] = new DetailPrototype();
 | 
						|
			if (grassTextures[2]!=null)
 | 
						|
			{
 | 
						|
				details[2].prototypeTexture = grassTextures[2];
 | 
						|
				details[2].renderMode = DetailRenderMode.Grass;
 | 
						|
				details[2].usePrototypeMesh=false;
 | 
						|
				details[2].minHeight = 0.77f;
 | 
						|
				details[2].maxHeight = 0.99f;
 | 
						|
				details[2].healthyColor = Color.white;
 | 
						|
				details[2].dryColor = Color.gray;
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			// meshes
 | 
						|
			details[3] = new DetailPrototype();
 | 
						|
			if (detailObjects[0]!=null)
 | 
						|
			{
 | 
						|
				details[3].prototype = detailObjects[0];
 | 
						|
				details[3].renderMode = DetailRenderMode.Grass; // for default grass
 | 
						|
				details[3].usePrototypeMesh=true; 
 | 
						|
				details[3].healthyColor = Color.white;
 | 
						|
				details[3].dryColor = Color.gray;
 | 
						|
			}
 | 
						|
 | 
						|
			details[4] = new DetailPrototype();
 | 
						|
			if (detailObjects[1]!=null)
 | 
						|
			{
 | 
						|
				details[4].prototype = detailObjects[1];
 | 
						|
				details[4].renderMode = DetailRenderMode.Grass; // for default grass
 | 
						|
				details[4].usePrototypeMesh=true;
 | 
						|
				details[4].healthyColor = Color.white;
 | 
						|
				details[4].dryColor = Color.gray;
 | 
						|
			}
 | 
						|
 | 
						|
			details[5] = new DetailPrototype();
 | 
						|
			if (detailObjects[2]!=null)
 | 
						|
			{
 | 
						|
				details[5].prototype = detailObjects[2];
 | 
						|
				details[5].renderMode = DetailRenderMode.VertexLit; // for default mesh rock
 | 
						|
				details[5].usePrototypeMesh=true;  
 | 
						|
				details[5].healthyColor = Color.white;
 | 
						|
				details[5].dryColor = Color.gray;
 | 
						|
			}
 | 
						|
 | 
						|
			return details;
 | 
						|
		}
 | 
						|
 | 
						|
		/*
 | 
						|
		DetailPrototype[] SetupDetailMeshes() 
 | 
						|
		{
 | 
						|
			// if we already have some details keep them, for now just skip default 3 grass details
 | 
						|
			DetailPrototype[] detailMeshes = new DetailPrototype[3];
 | 
						|
 | 
						|
			detailMeshes[0] = new DetailPrototype();
 | 
						|
			detailMeshes[0].prototype = detailObjects[0];
 | 
						|
			detailMeshes[1] = new DetailPrototype();
 | 
						|
			if (detailMeshes[1]!=null)
 | 
						|
			{
 | 
						|
				detailMeshes[1].prototype = detailObjects[1];
 | 
						|
			}
 | 
						|
			detailMeshes[2] = new DetailPrototype();
 | 
						|
			if (detailMeshes[2]!=null)
 | 
						|
			{
 | 
						|
				detailMeshes[2].prototype = detailObjects[2];
 | 
						|
			}
 | 
						|
			return detailMeshes;
 | 
						|
		}*/
 | 
						|
 | 
						|
		
 | 
						|
		bool CheckSplatmap() 
 | 
						|
		{
 | 
						|
			if (splatA==null) return false;
 | 
						|
			FixTextureSettings(splatA);
 | 
						|
 | 
						|
			if (splatA.height != splatA.width) 
 | 
						|
			{
 | 
						|
				EditorUtility.DisplayDialog("Wrong size", "First splatmap must be square (width and height must be the same)", "Cancel"); 
 | 
						|
				return false;
 | 
						|
			}
 | 
						|
 | 
						|
			if (Mathf.ClosestPowerOfTwo(splatA.width) != splatA.width) {
 | 
						|
				EditorUtility.DisplayDialog("Wrong size", "Splatmap width and height must be a power of two", "Cancel"); 
 | 
						|
				return false;	
 | 
						|
			}
 | 
						|
 | 
						|
			if (splatB!=null) 
 | 
						|
			{
 | 
						|
				FixTextureSettings(splatB);
 | 
						|
				if (splatB.height != splatB.width) 
 | 
						|
				{
 | 
						|
					EditorUtility.DisplayDialog("Wrong size", "Second splatmap must be square (width and height must be the same)", "Cancel"); 
 | 
						|
					return false;
 | 
						|
				}
 | 
						|
 | 
						|
				if (Mathf.ClosestPowerOfTwo(splatB.width) != splatB.width) 
 | 
						|
				{
 | 
						|
					EditorUtility.DisplayDialog("Wrong size", "Second splatmap width and height must be a power of two", "Cancel"); 
 | 
						|
					return false;	
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		void ApplySelectedTexturesToTerrain()
 | 
						|
		{
 | 
						|
			if (!myTerrain) myTerrain = Terrain.activeTerrain;
 | 
						|
			if (myTerrain==null) {Debug.LogError("No terrain selected"); return;}
 | 
						|
			myTerrain.terrainData.splatPrototypes = SetupTextures();
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		void ApplySplatmap() 
 | 
						|
		{
 | 
						|
			StartTimer();
 | 
						|
 | 
						|
			if (!myTerrain) myTerrain = Terrain.activeTerrain;
 | 
						|
			if (myTerrain==null) {Debug.LogError("No terrain selected"); return;}
 | 
						|
 | 
						|
			TerrainData terrainData = myTerrain.terrainData;
 | 
						|
 | 
						|
			if (terrainData==null) {Debug.LogError("Failed getting terrain data"); return;}
 | 
						|
 | 
						|
			if (terrainData.alphamapLayers<4) 
 | 
						|
			{
 | 
						|
				EditorUtility.DisplayDialog("Missing Terrain Textures", "Please set up at least 4 textures in the terrain painter dialog", "Cancel");
 | 
						|
				return;	
 | 
						|
			}
 | 
						|
 | 
						|
			if (splatB!=null && terrainData.alphamapLayers<8) 
 | 
						|
			{
 | 
						|
				EditorUtility.DisplayDialog("Missing Terrain Textures", "Please set up at least 8 textures in the terrain painter dialog", "Cancel");
 | 
						|
				return;	
 | 
						|
			}
 | 
						|
 | 
						|
			int width = splatA.width;
 | 
						|
			bool TwoMaps = false;
 | 
						|
 | 
						|
			if (splatB==null) 
 | 
						|
			{
 | 
						|
				//splatB = new Texture2D(w, w, TextureFormat.ARGB32, false);
 | 
						|
			} else {
 | 
						|
				if (splatA.width != splatB.width && splatA.height != splatB.height) {
 | 
						|
					Debug.LogError("Both splatmaps must have same resolution ("+splatA.width+" != "+splatB.width+")");
 | 
						|
					return;
 | 
						|
				}
 | 
						|
				TwoMaps=true;
 | 
						|
			}
 | 
						|
 | 
						|
			
 | 
						|
			Undo.RecordObject(terrainData, "Apply splatmap(s)"); // very slow..
 | 
						|
 | 
						|
			terrainData.alphamapResolution = width;
 | 
						|
 | 
						|
			float[,,] splatmapData = terrainData.GetAlphamaps(0, 0, width, width);
 | 
						|
			Color[] splatmapColors = splatA.GetPixels();
 | 
						|
			Color[] splatmapColors_b=null; //= splatB.GetPixels();
 | 
						|
 | 
						|
			if (TwoMaps) 
 | 
						|
			{
 | 
						|
				splatmapColors_b = splatB.GetPixels();
 | 
						|
			}else{
 | 
						|
				//	DestroyImmediate(splatB);
 | 
						|
				//splatB = null;
 | 
						|
			}
 | 
						|
 | 
						|
			Color col=Color.clear;
 | 
						|
			Color col_b=Color.clear;
 | 
						|
 | 
						|
			for (int y = 0; y < width; y++)
 | 
						|
			{
 | 
						|
 | 
						|
				if (y%10 == 0) // update progress bar every now and then
 | 
						|
				{
 | 
						|
					if (EditorUtility.DisplayCancelableProgressBar("Applying splatmap", "calculating...", Mathf.InverseLerp(0.0f, (float)width, (float)y))) 
 | 
						|
					{
 | 
						|
						EditorUtility.ClearProgressBar();
 | 
						|
						return;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				for (int x = 0; x < width; x++)
 | 
						|
				{
 | 
						|
					float sum;
 | 
						|
 | 
						|
//					Color col = splatmapColors[((w-1)-x)*w + y];
 | 
						|
//					Color col_b = splatmapColors_b[((w-1)-x)*w + y];
 | 
						|
					//col = splatmapColors[ ((w-1)-y)*w + x]; // TODO: get rid of flip
 | 
						|
					col = splatmapColors[x*width+y];
 | 
						|
 | 
						|
 | 
						|
					if (TwoMaps) 
 | 
						|
					{
 | 
						|
//						col_b = splatmapColors_b[((w-1)-y)*w + x];
 | 
						|
						col_b = splatmapColors_b[y*width+x];
 | 
						|
						sum = col.r+col.g+col.b+col_b.r+col_b.g+col_b.b;
 | 
						|
					} else {
 | 
						|
						sum = col.r+col.g+col.b;
 | 
						|
						//sum = col.r+col.g+col.b+(splatHasAlpha?col.a:0);
 | 
						|
					}
 | 
						|
 | 
						|
					if (sum>1.0f) 
 | 
						|
					{
 | 
						|
						// no final channel, and scale down
 | 
						|
						splatmapData[x,y,0] = col.r / sum;
 | 
						|
						splatmapData[x,y,1] = col.g / sum;
 | 
						|
						splatmapData[x,y,2] = col.b / sum;
 | 
						|
						//splatmapData[x,y,3] = col.a / sum;
 | 
						|
						splatmapData[x,y,3] = 1f-sum;
 | 
						|
 | 
						|
	//					splatmapData[y,x,0] = col.r / sum; // TODO: these parts will be later used for invert options
 | 
						|
	//					splatmapData[y,x,1] = col.g / sum;
 | 
						|
	//					splatmapData[y,x,2] = col.b / sum;
 | 
						|
						if (TwoMaps) 
 | 
						|
						{
 | 
						|
							splatmapData[x,y,4] = col_b.r / sum;
 | 
						|
							splatmapData[x,y,5] = col_b.g / sum;
 | 
						|
							splatmapData[x,y,6] = col_b.b / sum;
 | 
						|
 | 
						|
 | 
						|
							splatmapData[x,y,7] = 1f-sum;
 | 
						|
//							splatmapData[x,y,6] = 0.0f;
 | 
						|
						} else { // single map
 | 
						|
							// TODO: need to reset old splats, if previously had 2 splatmaps?
 | 
						|
 | 
						|
//							splatmapData[x,y,4] = 0.0f;
 | 
						|
							// reset old maps
 | 
						|
//							splatmapData[x,y,4] = 0;
 | 
						|
							//splatmapData[x,y,5] = 0;
 | 
						|
							//splatmapData[x,y,6] = 0;
 | 
						|
							//splatmapData[x,y,7] = 0;
 | 
						|
						}
 | 
						|
 | 
						|
					} else { // not over 1.0
 | 
						|
 | 
						|
	//					splatmapData[w-1-y,x,0] = col.r;
 | 
						|
	//					splatmapData[w-1-y,x,1] = col.g;
 | 
						|
	//					splatmapData[w-1-y,x,2] = col.b;
 | 
						|
						// derive final channel from white
 | 
						|
						splatmapData[x,y,0] = col.r;
 | 
						|
						splatmapData[x,y,1] = col.g;
 | 
						|
						splatmapData[x,y,2] = col.b;
 | 
						|
						splatmapData[x,y,3] = 1f-sum;
 | 
						|
 | 
						|
						if (TwoMaps) 
 | 
						|
						{
 | 
						|
							//Debug.Log("asddfasdf");
 | 
						|
							//return;
 | 
						|
							splatmapData[x,y,4] = col_b.r;
 | 
						|
							splatmapData[x,y,5] = col_b.g;
 | 
						|
							splatmapData[x,y,6] = col_b.b;
 | 
						|
							splatmapData[x,y,7] = 1f-sum;
 | 
						|
						} else {
 | 
						|
							//splatmapData[x,y,3] = 1.0f - sum;
 | 
						|
							// reset old maps
 | 
						|
							//splatmapData[x,y,4] = 0;
 | 
						|
							//splatmapData[x,y,5] = 0;
 | 
						|
							//splatmapData[x,y,6] = 0;
 | 
						|
							//splatmapData[x,y,7] = 0;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				} // for splatmap x pixels
 | 
						|
			} // for splatmap y pixels
 | 
						|
 | 
						|
			EditorUtility.ClearProgressBar();
 | 
						|
			terrainData.SetAlphamaps(0, 0, splatmapData);
 | 
						|
			Debug.Log("Splatmaps applied "+GetTimerTime());
 | 
						|
		}
 | 
						|
		
 | 
						|
		
 | 
						|
		bool CheckTreemap() 
 | 
						|
		{
 | 
						|
			if (treemap == null) return false;
 | 
						|
			FixTextureSettings(treemap);
 | 
						|
			
 | 
						|
			if (treemap.height != treemap.width) {
 | 
						|
				EditorUtility.DisplayDialog("Wrong size", "treemap width and height must be the same", "Cancel"); 
 | 
						|
				return false;
 | 
						|
			}
 | 
						|
			if (Mathf.ClosestPowerOfTwo(treemap.width) != treemap.width) {
 | 
						|
				EditorUtility.DisplayDialog("Wrong size", "treemap width and height must be a power of two", "Cancel"); 
 | 
						|
				return false;	
 | 
						|
			}
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		
 | 
						|
		void ApplyTreemap() 
 | 
						|
		{
 | 
						|
			StartTimer();
 | 
						|
			// set up my data
 | 
						|
			if (!myTerrain) myTerrain = Terrain.activeTerrain;
 | 
						|
 | 
						|
			if (myTerrain==null) {Debug.LogError("No terrain selected"); return;}
 | 
						|
 | 
						|
			TerrainData terrainData = myTerrain.terrainData;
 | 
						|
 | 
						|
 | 
						|
			// check if trees are assigned
 | 
						|
			if (terrainData.treePrototypes.Length<3)
 | 
						|
			{
 | 
						|
				if (terrainData.treePrototypes.Length<1)
 | 
						|
				{
 | 
						|
					Debug.LogError("You should assign at least 1 tree to Terrain (at Place Trees tab)");
 | 
						|
					return;
 | 
						|
				}else{
 | 
						|
					Debug.LogWarning("You should assign 3 trees to Terrain to use all 3 splatmap color channels (at Place Trees tab)");
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
			Undo.RecordObject(terrainData, "Apply tree map"); // slow..
 | 
						|
 | 
						|
			int width = treemap.width;
 | 
						|
 | 
						|
			Color[] mapColors = treemap.GetPixels();
 | 
						|
 | 
						|
			int index = -1;
 | 
						|
			int maxIndex=terrainData.treePrototypes.Length;
 | 
						|
			int trees = 0;
 | 
						|
 | 
						|
			float Step = 1.0f/treeDensity;
 | 
						|
			float PositionVariation = (float)(Step*0.5f/(float)width);
 | 
						|
 | 
						|
			if (resetTrees) terrainData.treeInstances = new TreeInstance[0];
 | 
						|
 | 
						|
			int progress = 0;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
			for (float y = 1; y < width-1; y+=Step) 
 | 
						|
			{
 | 
						|
				progress++;
 | 
						|
				if (progress%10 == 0)
 | 
						|
				{
 | 
						|
					progress=0;
 | 
						|
					if (EditorUtility.DisplayCancelableProgressBar("Placing trees", "placed "+trees+" trees so far", Mathf.InverseLerp(0.0f, (float)width, (float)y))) 
 | 
						|
					{
 | 
						|
						EditorUtility.ClearProgressBar();
 | 
						|
						return;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				for (float x = 1; x < width-1; x+=Step)
 | 
						|
				{
 | 
						|
					// place the chosen tree, if the colours are right
 | 
						|
					index = -1;
 | 
						|
					//Color col = mapColors[Mathf.RoundToInt(y)*w + Mathf.RoundToInt(x)];
 | 
						|
					Color col = mapColors[(width-Mathf.RoundToInt(y))*width+Mathf.RoundToInt(x)];
 | 
						|
					//width-x,length-y
 | 
						|
 | 
						|
					if (col.r>treeThreshold+Random.Range(0.0f, 1.0f))
 | 
						|
					{
 | 
						|
						index = 0;
 | 
						|
					}
 | 
						|
					else if (maxIndex>1 && col.g>treeThreshold+Random.Range(0.0f, 1.0f)) 
 | 
						|
					{
 | 
						|
						index = 1;
 | 
						|
					}
 | 
						|
					else if (maxIndex>2 && col.b>treeThreshold+Random.Range(0.0f, 1.0f)) 
 | 
						|
					{
 | 
						|
						index = 2;
 | 
						|
					}
 | 
						|
 | 
						|
 | 
						|
					if (index>=0) 
 | 
						|
					{
 | 
						|
						// place a tree
 | 
						|
						trees++;
 | 
						|
						TreeInstance treeInstance = new TreeInstance();
 | 
						|
 | 
						|
						// random placement modifier for a more natural look
 | 
						|
						float xpos = x/(float)width;
 | 
						|
						float ypos = y/(float)width;
 | 
						|
						xpos = Mathf.Clamp01(xpos+Random.Range(-PositionVariation, PositionVariation));
 | 
						|
						ypos = Mathf.Clamp01(1-ypos+Random.Range(-PositionVariation, PositionVariation));
 | 
						|
 | 
						|
						treeInstance.position = new Vector3(xpos, 0f, ypos);
 | 
						|
 | 
						|
						treeInstance.color = Color.white;
 | 
						|
						treeInstance.lightmapColor = Color.white;
 | 
						|
						treeInstance.prototypeIndex = index;
 | 
						|
 | 
						|
						treeInstance.widthScale = treeSize * (1f + Random.Range(-sizeVariation, sizeVariation));
 | 
						|
						treeInstance.heightScale = treeSize * (1f + Random.Range(-sizeVariation, sizeVariation));
 | 
						|
 | 
						|
						myTerrain.AddTreeInstance(treeInstance);
 | 
						|
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			EditorUtility.ClearProgressBar();
 | 
						|
			Debug.Log("placed "+trees+" trees "+GetTimerTime());
 | 
						|
		}
 | 
						|
		
 | 
						|
		
 | 
						|
		bool CheckGrassmap() 
 | 
						|
		{
 | 
						|
			if (grassmap != null) { 
 | 
						|
				FixTextureSettings(grassmap);
 | 
						|
 | 
						|
				int w = grassmap.width;
 | 
						|
				if (grassmap.height != w) 
 | 
						|
				{
 | 
						|
					EditorUtility.DisplayDialog("Wrong size", "grassmap width and height must be the same", "Cancel"); 
 | 
						|
					return false;
 | 
						|
				}
 | 
						|
				if (Mathf.ClosestPowerOfTwo(w) != w) {
 | 
						|
					EditorUtility.DisplayDialog("Wrong size", "grassmap width and height must be a power of two", "Cancel"); 
 | 
						|
					return false;	
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (bushmap != null) { 
 | 
						|
				FixTextureSettings(bushmap);
 | 
						|
 | 
						|
				int w = bushmap.width;
 | 
						|
				if (bushmap.height != w) {
 | 
						|
					EditorUtility.DisplayDialog("Wrong size", "bushmap width and height must be the same", "Cancel"); 
 | 
						|
					return false;
 | 
						|
				}
 | 
						|
				if (Mathf.ClosestPowerOfTwo(w) != w) {
 | 
						|
					EditorUtility.DisplayDialog("Wrong size", "bushmap width and height must be a power of two", "Cancel"); 
 | 
						|
					return false;	
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		
 | 
						|
		void ApplyGrassmap() 
 | 
						|
		{
 | 
						|
			StartTimer();
 | 
						|
 | 
						|
			if (!myTerrain) myTerrain = Terrain.activeTerrain;
 | 
						|
			if (myTerrain==null) {Debug.LogError("No terrain selected"); return;}
 | 
						|
			TerrainData terrainData = myTerrain.terrainData;
 | 
						|
 | 
						|
			Undo.RecordObject(terrainData, "Apply grass and bush maps");
 | 
						|
			
 | 
						|
			if (grassmap!=null) 
 | 
						|
			{
 | 
						|
				if (SetDetailmap(grassmap, grassDensity, 0, grassclumping, "Grass map")) Debug.Log("Grass map applied "+GetTimerTime());
 | 
						|
			}
 | 
						|
 | 
						|
			if (bushmap!=null) 
 | 
						|
			{
 | 
						|
				//if (SetDetailmap(bushmap, bushmod, 3, 0.0f, "Bush map")) Debug.Log("Bush map applied.");
 | 
						|
				if (SetDetailmap(bushmap, bushDensity, grassmap==null?0:3, 0.0f, "Bush map")) Debug.Log("Bush map applied "+GetTimerTime());
 | 
						|
			}
 | 
						|
			EditorUtility.ClearProgressBar();
 | 
						|
		}
 | 
						|
 | 
						|
		void ApplyBushmap() 
 | 
						|
		{
 | 
						|
			StartTimer();
 | 
						|
			
 | 
						|
			if (!myTerrain) myTerrain = Terrain.activeTerrain;
 | 
						|
			if (myTerrain==null) {Debug.LogError("No terrain selected"); return;}
 | 
						|
			TerrainData terrainData = myTerrain.terrainData;
 | 
						|
			
 | 
						|
			Undo.RecordObject(terrainData, "Apply grass and bush maps");
 | 
						|
			/*
 | 
						|
			if (grassmap!=null) 
 | 
						|
			{
 | 
						|
				if (SetDetailmap(grassmap, grassDensity, 0, grassclumping, "Grass map")) Debug.Log("Grass map applied "+GetTimerTime());
 | 
						|
			}*/
 | 
						|
			
 | 
						|
			if (bushmap!=null) 
 | 
						|
			{
 | 
						|
				//if (SetDetailmap(bushmap, bushmod, 3, 0.0f, "Bush map")) Debug.Log("Bush map applied.");
 | 
						|
				if (SetDetailmap(bushmap, bushDensity, grassmap==null?0:3, 0.0f, "Bush map")) Debug.Log("Bush map applied "+GetTimerTime());
 | 
						|
			}
 | 
						|
			EditorUtility.ClearProgressBar();
 | 
						|
		}
 | 
						|
 | 
						|
		
 | 
						|
		bool SetDetailmap(Texture2D map, float mod, int firstlayer, float clumping, string MapName) 
 | 
						|
		{
 | 
						|
			if (!myTerrain) myTerrain = Terrain.activeTerrain;
 | 
						|
			TerrainData terrainData = myTerrain.terrainData;
 | 
						|
 | 
						|
			if (terrainData.detailPrototypes.Length<3)
 | 
						|
			{
 | 
						|
				if (terrainData.detailPrototypes.Length<1)
 | 
						|
				{
 | 
						|
					Debug.LogError ("You need to add at least 1 detail textures or 1 detail meshes to Terrain (at Paint Details)");
 | 
						|
					return false;
 | 
						|
				}
 | 
						|
				Debug.LogWarning ("You should add 3 detail textures or 3 detail meshes to Terrain to use all splat map color channels (at Paint Details)");
 | 
						|
			}
 | 
						|
 | 
						|
			// validate terrain details count
 | 
						|
			int detailTextureCount=0;
 | 
						|
			int detailMeshCount=0;
 | 
						|
			int maxDetailMeshes = terrainData.detailPrototypes.Length;
 | 
						|
 | 
						|
			for (int nn=0; nn<terrainData.detailPrototypes.Length;nn++)
 | 
						|
			{
 | 
						|
				if (terrainData.detailPrototypes[nn].usePrototypeMesh)
 | 
						|
				{
 | 
						|
					detailMeshCount++;
 | 
						|
				}else{
 | 
						|
					detailTextureCount++;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			// check if there are any details for terrain
 | 
						|
			if (MapName == "Grass map")
 | 
						|
			{
 | 
						|
				if (detailTextureCount<1)
 | 
						|
				{
 | 
						|
					Debug.LogError ("Grass map needs at least 1 detail texture at Terrain - Paint Details tab");
 | 
						|
					return false;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			if (MapName == "Bush map")
 | 
						|
			{
 | 
						|
				if (detailMeshCount<1)
 | 
						|
				{
 | 
						|
					Debug.LogError ("Bush map at least 1 detail meshes at Terrain - Paint Details tab");
 | 
						|
					return false;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			Color[] detailColors = map.GetPixels();
 | 
						|
			int width = map.width;
 | 
						|
			int res = terrainData.detailResolution;
 | 
						|
 | 
						|
			int[,] detail_a = new int[res,res];
 | 
						|
			int[,] detail_b = new int[res,res];
 | 
						|
			int[,] detail_c = new int[res,res];
 | 
						|
 | 
						|
			float scale = (float)width/(float)res;
 | 
						|
 | 
						|
			for (int y = 0; y < res; y++) 
 | 
						|
			{
 | 
						|
 | 
						|
				if (EditorUtility.DisplayCancelableProgressBar("Applying "+MapName, "Calculating...", Mathf.InverseLerp(0.0f, (float)res, (float)y))) 
 | 
						|
				{
 | 
						|
					EditorUtility.ClearProgressBar();
 | 
						|
					return false;
 | 
						|
				}
 | 
						|
 | 
						|
				for (int x = 0; x < res; x++) 
 | 
						|
				{
 | 
						|
					// place detail, depending on colours in map image
 | 
						|
					int sx = Mathf.FloorToInt((float)(x)*scale);
 | 
						|
					int sy = Mathf.FloorToInt((float)(y)*scale);
 | 
						|
					//Color col = detailColors[((width-1)-sx)*width+sy];
 | 
						|
					Color col = detailColors[sx*width+sy];
 | 
						|
 | 
						|
 | 
						|
					detail_a[x,y] = DetailValue(col.r*mod);
 | 
						|
					if (maxDetailMeshes>2) detail_b[x,y] = DetailValue(col.g*mod);
 | 
						|
					if (maxDetailMeshes>3) detail_c[x,y] = DetailValue(col.b*mod);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			
 | 
						|
			if (clumping>0.01f) 
 | 
						|
			{
 | 
						|
				detail_a = MakeClumps(detail_a, clumping);
 | 
						|
				if (maxDetailMeshes>2) detail_b = MakeClumps(detail_b, clumping);
 | 
						|
				if (maxDetailMeshes>3) detail_c = MakeClumps(detail_c, clumping);
 | 
						|
			}
 | 
						|
 | 
						|
			terrainData.SetDetailLayer(0, 0, firstlayer+0, detail_a);
 | 
						|
			if (maxDetailMeshes>2) terrainData.SetDetailLayer(0, 0, firstlayer+1, detail_b);
 | 
						|
			if (maxDetailMeshes>3) terrainData.SetDetailLayer(0, 0, firstlayer+2, detail_c);
 | 
						|
 | 
						|
			return true;
 | 
						|
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		int DetailValue(float col) 
 | 
						|
		{
 | 
						|
			// linearly translates a 0.0-1.0 number to a 0-16 integer
 | 
						|
			int c = Mathf.FloorToInt(col*16);
 | 
						|
			float r = col*16 - Mathf.FloorToInt(col*16);
 | 
						|
			
 | 
						|
			if (r>Random.Range(0.0f, 1.0f)) c++;
 | 
						|
			return Mathf.Clamp(c, 0, 16);
 | 
						|
		}
 | 
						|
		
 | 
						|
		int[,] MakeClumps(int[,] map, float clumping) {
 | 
						|
			int res = map.GetLength(0);
 | 
						|
			int [,] clumpmap = new int[res,res];
 | 
						|
 | 
						|
			// init - there's probably a better way to do this in C# that I just don't know
 | 
						|
			for (int y = 0; y < res; y++) {
 | 
						|
				for (int x = 0; x < res; x++) {
 | 
						|
					clumpmap[x,y]=0;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			for (int y = 0; y < res; y++) {
 | 
						|
				for (int x = 0; x < res; x++) {
 | 
						|
					clumpmap[x,y]+=map[x,y];
 | 
						|
					if (map[x,y]>0) {
 | 
						|
						// there's grass here, we might want to raise the grass value of our neighbours
 | 
						|
						for (int a=-1;a<=1;a++) for (int b=-1;b<=1;b++) {
 | 
						|
							if (x+a<0||x+a>=res||y+b<0||y+b>=res) continue;
 | 
						|
							if (a!=0||b!=0&&Random.Range(0.0f, 1.0f)<clumping) clumpmap[x+a,y+b]++;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			// values above 9 yield strange results
 | 
						|
			for (int y = 0; y < res; y++) {
 | 
						|
				for (int x = 0; x < res; x++) {
 | 
						|
					if (clumpmap[x,y]>9) clumpmap[x,y]=9;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			
 | 
						|
			return clumpmap;
 | 
						|
		}
 | 
						|
		
 | 
						|
		
 | 
						|
		bool CheckOverlaymap() 
 | 
						|
		{
 | 
						|
			if (overlayMap==null) {Debug.LogError("No overlay map assigned"); return false;}
 | 
						|
 | 
						|
			
 | 
						|
			if (!myTerrain) myTerrain = Terrain.activeTerrain;
 | 
						|
 | 
						|
			FixTextureSettings(overlayMap);
 | 
						|
 | 
						|
			if (overlayMap.height != overlayMap.width) {
 | 
						|
				EditorUtility.DisplayDialog("Wrong size", "OverlayMap width and height must be the same", "Cancel"); 
 | 
						|
				return false;
 | 
						|
			}
 | 
						|
			if (Mathf.ClosestPowerOfTwo(overlayMap.width) != overlayMap.width) {
 | 
						|
				EditorUtility.DisplayDialog("Wrong size", "OverlayMap width and height must be a power of two", "Cancel"); 
 | 
						|
				return false;	
 | 
						|
			}
 | 
						|
 | 
						|
			if (overlayMap.width!=myTerrain.terrainData.alphamapResolution) {
 | 
						|
				EditorUtility.DisplayDialog("Wrong size", "OverlayMap must have same size as existing splatmap ("+myTerrain.terrainData.alphamapResolution+")", "Cancel"); 
 | 
						|
				return false;	
 | 
						|
			}
 | 
						|
			
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		
 | 
						|
		void ApplyOverlaymap() 
 | 
						|
		{
 | 
						|
			StartTimer();
 | 
						|
 | 
						|
			if (!myTerrain) myTerrain = Terrain.activeTerrain;
 | 
						|
			TerrainData terrainData = myTerrain.terrainData;
 | 
						|
 | 
						|
			Undo.RecordObject(terrainData, "Apply overlay map");
 | 
						|
 | 
						|
			int w = overlayMap.width;
 | 
						|
			Color[] OverlayMapColors = overlayMap.GetPixels();
 | 
						|
			int layer = myTerrain.terrainData.alphamapLayers;
 | 
						|
 | 
						|
			int detailRes = terrainData.detailWidth;
 | 
						|
			int[] detailLayers = terrainData.GetSupportedLayers(0, 0, detailRes, detailRes);
 | 
						|
			int LayerCount = detailLayers.Length;
 | 
						|
 | 
						|
			AddTexture();
 | 
						|
 | 
						|
			float[,,] splatmapData = terrainData.GetAlphamaps(0, 0, w, w);
 | 
						|
 | 
						|
			float terrainScale = (float)w / ((float)terrainData.heightmapResolution-1);
 | 
						|
			float terrainHeight = terrainData.size.y;
 | 
						|
			int terrainSample = Mathf.CeilToInt(terrainScale);
 | 
						|
 | 
						|
			ArrayList NewTrees = new ArrayList(terrainData.treeInstances);
 | 
						|
			int TreesRemoved = 0;
 | 
						|
 | 
						|
			for (int y = 0; y < w; y++) 
 | 
						|
			{
 | 
						|
				if (y%10 == 0) 
 | 
						|
				{
 | 
						|
					if (clearTrees) 
 | 
						|
					{
 | 
						|
						if (EditorUtility.DisplayCancelableProgressBar("Overlay map", "updating terrain and trees ("+TreesRemoved+" trees removed)", Mathf.InverseLerp(0.0f, (float)w, (float)y))) 
 | 
						|
						{
 | 
						|
							EditorUtility.ClearProgressBar();
 | 
						|
							return;
 | 
						|
						}
 | 
						|
					} else {
 | 
						|
 | 
						|
						if (EditorUtility.DisplayCancelableProgressBar("Overlay map", "updating terrain", Mathf.InverseLerp(0.0f, (float)w, (float)y))) 
 | 
						|
						{
 | 
						|
							EditorUtility.ClearProgressBar();
 | 
						|
							return;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				for (int x = 0; x < w; x++) 
 | 
						|
				{
 | 
						|
//					float value = OverlayMapColors[((w-1)-x)*w + y].grayscale;
 | 
						|
					float value = OverlayMapColors[x*w+y].grayscale;
 | 
						|
					if (value>overlayThreshold) 
 | 
						|
					{
 | 
						|
						splatmapData[x,y,layer] = value;
 | 
						|
						// fix the other layers
 | 
						|
 | 
						|
						for (int l = 0; l<layer; l++) {
 | 
						|
							splatmapData[x,y,l] *= (1.0f-value);
 | 
						|
						}
 | 
						|
 | 
						|
						if (changeTerrain>0.01f || changeTerrain<-0.01f) 
 | 
						|
						{
 | 
						|
							if (value>overlayThreshold) {
 | 
						|
								float change = changeTerrain * value / terrainHeight;
 | 
						|
								int sx = Mathf.FloorToInt((float)y*terrainScale);
 | 
						|
								int sy = Mathf.FloorToInt((float)x*terrainScale);
 | 
						|
								float [,] data = terrainData.GetHeights(sx, sy, terrainSample, terrainSample);
 | 
						|
								for (int a=0;a<terrainSample;a++) for (int b=0;b<terrainSample;b++) {
 | 
						|
									data[a,b]=Mathf.Max(0.0f, data[a,b]+change);
 | 
						|
								}
 | 
						|
								terrainData.SetHeights(sx, sy, data);
 | 
						|
							}
 | 
						|
						}
 | 
						|
						
 | 
						|
						if (clearTrees) 
 | 
						|
						{
 | 
						|
							for (int i = NewTrees.Count -1; i >= 0; i--) {
 | 
						|
								TreeInstance MyTree = (TreeInstance)NewTrees[i];
 | 
						|
								float distance = Vector2.Distance(new Vector2(MyTree.position.z*w, MyTree.position.x*w), new Vector2((float)x, (float)y));
 | 
						|
								if (distance < clearRadius) {
 | 
						|
									NewTrees.RemoveAt(i);
 | 
						|
									TreesRemoved++;
 | 
						|
								}
 | 
						|
							}
 | 
						|
						}
 | 
						|
 | 
						|
					} else {
 | 
						|
						splatmapData[x,y,layer] = 0.0f;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if (clearTrees) 
 | 
						|
			{
 | 
						|
				terrainData.treeInstances = (TreeInstance[])NewTrees.ToArray(typeof(TreeInstance));
 | 
						|
			}
 | 
						|
 | 
						|
			terrainData.SetAlphamaps(0, 0, splatmapData);
 | 
						|
			Debug.Log("Overlay map applied "+GetTimerTime());
 | 
						|
 | 
						|
			if (clearGrass) 
 | 
						|
			{
 | 
						|
				float scale = (float)w / (float)detailRes;
 | 
						|
				for (int l = 0; l<LayerCount; l++) 
 | 
						|
				{
 | 
						|
					if (EditorUtility.DisplayCancelableProgressBar("Overlay map", "clearing away grass", Mathf.InverseLerp(0.0f, (float)l, (float)LayerCount))) 
 | 
						|
					{
 | 
						|
						EditorUtility.ClearProgressBar();
 | 
						|
						return;
 | 
						|
					}
 | 
						|
					int[,] grass = terrainData.GetDetailLayer(0, 0, detailRes, detailRes, l);
 | 
						|
					for (int y = 0; y < detailRes; y++) {
 | 
						|
						for (int x = 0; x < detailRes; x++) {
 | 
						|
							int sx = Mathf.FloorToInt((float)(x)*scale);
 | 
						|
							int sy = Mathf.FloorToInt((float)(y)*scale);
 | 
						|
							//float value = OverlayMapColors[((w-1)-sx)*w + sy].grayscale;
 | 
						|
							float value = OverlayMapColors[sx*w+sy].grayscale;
 | 
						|
							if (value > overlayThreshold && grass[x,y]>0) 
 | 
						|
							{
 | 
						|
								if (value > 0.5f) grass[x,y]=0; else grass[x,y]=1;
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
					terrainData.SetDetailLayer(0, 0, l, grass);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			EditorUtility.ClearProgressBar();
 | 
						|
		}
 | 
						|
 | 
						|
		void AddTexture() 
 | 
						|
		{
 | 
						|
			if (!myTerrain) myTerrain = Terrain.activeTerrain;
 | 
						|
 | 
						|
			SplatPrototype[] oldPrototypes = myTerrain.terrainData.splatPrototypes;
 | 
						|
			SplatPrototype[] newPrototypes = new SplatPrototype[oldPrototypes.Length + 1];
 | 
						|
 | 
						|
			for (int x=0;x<oldPrototypes.Length;x++) 
 | 
						|
			{
 | 
						|
				newPrototypes[x] = oldPrototypes[x];
 | 
						|
			}
 | 
						|
			newPrototypes[oldPrototypes.Length] = new SplatPrototype();
 | 
						|
			newPrototypes[oldPrototypes.Length].texture = overlayTexture;
 | 
						|
			Vector2 vector = new Vector2(tileSize, tileSize);
 | 
						|
			newPrototypes[oldPrototypes.Length].tileSize = vector;
 | 
						|
			myTerrain.terrainData.splatPrototypes = newPrototypes;
 | 
						|
			EditorUtility.SetDirty(myTerrain);
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
		// these are copied from UnityEditor.dll
 | 
						|
		private void CreateTerrain(string name, int size) 
 | 
						|
		{
 | 
						|
			Selection.activeObject = null;
 | 
						|
 | 
						|
			TerrainData newTerrain = new TerrainData();
 | 
						|
 | 
						|
			newTerrain.heightmapResolution = size+1;
 | 
						|
			newTerrain.size = new Vector3(terrainInitWidth, terrainInitHeight, terrainInitLength);
 | 
						|
			newTerrain.heightmapResolution = size;
 | 
						|
			newTerrain.baseMapResolution = 1024;
 | 
						|
			newTerrain.SetDetailResolution(1024, 16); // recommended value from documentation
 | 
						|
 | 
						|
			newTerrain.wavingGrassSpeed = windSettingsSize;
 | 
						|
			newTerrain.wavingGrassAmount = windSettingsBending;
 | 
						|
			newTerrain.wavingGrassStrength = windSettingsSpeed;
 | 
						|
 | 
						|
			string timeStamp = System.DateTime.Now.ToString("ddMMHHmm");
 | 
						|
			AssetDatabase.CreateAsset(newTerrain, name+ "Terrain"+(timeStampFileNames?timeStamp:"") +".asset");
 | 
						|
			AssetDatabase.SaveAssets();
 | 
						|
 | 
						|
			Selection.activeObject = Terrain.CreateTerrainGameObject(newTerrain);
 | 
						|
 | 
						|
 | 
						|
			myTerrain = Terrain.activeTerrains[Terrain.activeTerrains.Length-1]; 
 | 
						|
 | 
						|
		}
 | 
						|
 | 
						|
		
 | 
						|
		public static float[,] ReadRawHeightMap(string path, int widthPlusOne, int heightmapWidth, int heightmapHeight) 
 | 
						|
		{
 | 
						|
			if (!File.Exists(path))
 | 
						|
		    {
 | 
						|
				// try with .r16 extension next
 | 
						|
				path = path.Replace(".raw",".r16");
 | 
						|
				if (!File.Exists(path))
 | 
						|
				{
 | 
						|
					Debug.LogWarning("Heightmap file not found: "+path);
 | 
						|
					return null;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			byte[] buffer;
 | 
						|
			using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read))) 
 | 
						|
			{
 | 
						|
				buffer = reader.ReadBytes(widthPlusOne * widthPlusOne * 2);
 | 
						|
				reader.Close();
 | 
						|
			}
 | 
						|
 | 
						|
//			int heightmapWidth = MyTerrain.terrainData.heightmapWidth;
 | 
						|
//			int heightmapHeight = MyTerrain.terrainData.heightmapHeight;
 | 
						|
 | 
						|
			float[,] heights = new float[heightmapHeight, heightmapWidth];
 | 
						|
 | 
						|
			float deltaMac = -999.0f;
 | 
						|
			float deltaPc = -999.0f;
 | 
						|
 | 
						|
			int morePc=0;
 | 
						|
			int moreMac=0;
 | 
						|
			int jj=0;
 | 
						|
 | 
						|
			// guess endian format by comparing height changes
 | 
						|
			for (int n=0;n<heightmapHeight;n+=4)
 | 
						|
			{
 | 
						|
				float b1 = buffer[jj++];
 | 
						|
				float b2 = buffer[jj++];
 | 
						|
				float b3 = buffer[jj++];
 | 
						|
				float b4 = buffer[jj++];
 | 
						|
				float ht1 = (b1*256.0f + b2);
 | 
						|
				float ht1mac = (b1*256.0f + b2);
 | 
						|
				float ht2 = (b3*256.0f + b4);
 | 
						|
				deltaMac=Mathf.Max (deltaMac,Mathf.Abs(ht1/65535.0f-ht2/65535.0f));
 | 
						|
				ht1 = (b1+b2*256.0f);
 | 
						|
				float ht1pc = (b1+b2*256.0f);
 | 
						|
				ht2 = (b3+b4*256.0f);
 | 
						|
				deltaPc=Mathf.Max (deltaPc,Mathf.Abs(ht1/65535.0f-ht2/65535.0f));
 | 
						|
				if (ht1mac>ht1pc) moreMac++;else morePc+=1;
 | 
						|
			}
 | 
						|
 | 
						|
			int ii=0;
 | 
						|
			bool mac = deltaMac<deltaPc;
 | 
						|
 | 
						|
			for (int i = 0; i < heightmapHeight; i++) 
 | 
						|
			{
 | 
						|
				if (i%10 == 0)
 | 
						|
				{
 | 
						|
 | 
						|
					if (EditorUtility.DisplayCancelableProgressBar("Importing heightmap", "calculating...", Mathf.InverseLerp(0.0f, (float)heightmapHeight, (float)i))) 
 | 
						|
					{
 | 
						|
						EditorUtility.ClearProgressBar();
 | 
						|
						return null;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				for (int j = 0; j < heightmapWidth; j++) 
 | 
						|
				{
 | 
						|
					float bufferVal1 = buffer[ii++];
 | 
						|
					float bufferVal2 = buffer[ii++];
 | 
						|
					float ht = (mac) ? (bufferVal1*256.0f + bufferVal2) : (bufferVal1 + bufferVal2*256.0f);
 | 
						|
 | 
						|
					//heights[j                 , i] = (ht / 65535.0f); // not flipped * worked before ??
 | 
						|
					//heights[j                 , heightmapWidth-i-1] = (ht / 65535.0f); // flip * needs -90 deg
 | 
						|
					//heights[heightmapWidth-j-1, i] = (ht / 65535.0f); // flip original *needs +90 deg
 | 
						|
					//heights[heightmapWidth-j-1  , heightmapWidth-i-1] = (ht / 65535.0f); // * needs flip y?
 | 
						|
 | 
						|
					//heights[i                 , j] = (ht / 65535.0f); // needs flip y?
 | 
						|
					//heights[i                 , heightmapWidth-j-1] = (ht / 65535.0f); // flip * needs -180 deg?
 | 
						|
					heights[heightmapWidth-i-1, j] = (ht / 65535.0f); // new best, with flip fix
 | 
						|
					//heights[heightmapWidth-j-1  , heightmapWidth-i-1] = (ht / 65535.0f); // * needs flip y?
 | 
						|
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return heights;
 | 
						|
		} // ReadRaw()
 | 
						|
 | 
						|
		void StartTimer()
 | 
						|
		{
 | 
						|
			stopwatch.Reset();
 | 
						|
			stopwatch.Start();
 | 
						|
		}
 | 
						|
 | 
						|
		string GetTimerTime()
 | 
						|
		{
 | 
						|
			stopwatch.Stop();
 | 
						|
			return " ("+stopwatch.Elapsed.Milliseconds+"ms)";
 | 
						|
		}
 | 
						|
 | 
						|
	} // class
 | 
						|
} // namespace
 |