예제 #1
0
			public void ChangeTextureArray (Texture2DArray texArr, ref LandTypeList types, bool isBump)
			{
				/*//array was removed - removing sources
				if (texArr == null)
					for (int i=0; i<types.array.Length; i++)
					{
						if (isBump) types.array[i].bumpSource = null;
						else { types.array[i].mainSource = null; types.array[i].alphaSource = null; }
					}

				else
				{
				
					//changing the blocks count on diffuse array assign
					if (!isBump  &&  types.array.Length != texArr.depth) 
						ArrayTools.Resize(ref types.array, texArr.depth, createElement:num => new BlockType() {name="Block " + num});

					//reload sources
					for (int i=0; i<types.array.Length; i++)
					{
						if (isBump) types.array[i].bumpSource = texArr.GetSource(i);
						else { types.array[i].mainSource = texArr.GetSource(i); types.array[i].alphaSource = texArr.GetSource(i, isAlpha:true); }
					}
				}*/

				//to mat
				types.ApplyToMaterial(voxeland.material);
				types.ApplyToMaterial(voxeland.farMaterial, horizon:true);
			}
예제 #2
0
			public Texture2DArray CreateTextureArrayAsset (string filename, LandTypeList types, bool isBump)   
			{
				string savePath = UnityEditor.EditorUtility.SaveFilePanel("Create New Texture Array", "Assets", filename, "asset");
				if (savePath == null  ||  savePath.Length==0) return null;  //savefilepanel returns "" on cancel
				savePath = savePath.Replace(Application.dataPath, "Assets");

				Texture2DArray texArr = new Texture2DArray(1024, 1024, types.array.Length, TextureFormat.RGBA32, true, linear:isBump);
				AssetDatabase.CreateAsset(texArr, savePath);
				EditorUtility.SetDirty(texArr);
				AssetDatabase.SaveAssets();

				TextureArrayDecorator texArrDec = new TextureArrayDecorator(texArr);
				for (int i=0; i<types.array.Length; i++)
				{
					if (isBump) texArrDec.SetSource(types.array[i].bumpMap, i, isAlpha:false, saveSources:false);
					else
					{
						texArrDec.SetSource(types.array[i].mainTex, i, isAlpha:false, saveSources:false);
						//texArrDec.SetSource(types.array[i].alphaSource, i, isAlpha:true, saveSources:false);
					}
				}
				texArrDec.SaveSources();

				AssetDatabase.Refresh();
				return texArr;
			}
예제 #3
0
		public override void OnInspectorGUI ()
		{
			voxeland = (Voxeland)target;
			Voxeland.current = voxeland;

			//assigning voxeland to mapmagic window
			#if MAPMAGIC
			if (MapMagic.MapMagicWindow.instance != null && MapMagic.MapMagicWindow.instance.mapMagic != (MapMagic.IMapMagic)voxeland && voxeland.data != null && voxeland.data.generator != null && voxeland.data.generator.mapMagicGens != null)
				MapMagic.MapMagicWindow.Show(voxeland.data.generator.mapMagicGens, voxeland, forceOpen:false);
			#endif

			if (layout == null) layout = new Layout();
			layout.margin = 0; layout.rightMargin = 5;
			layout.field = Layout.GetInspectorRect();
			layout.cursor = new Rect();
			layout.undoObject = voxeland;
			layout.undoName =  "Voxeland settings change";
			layout.dragChange = true;
			layout.change = false;
			layout.delayed = true;

			if (voxeland.data == null) { layout.Par(30); layout.Label("Voxeland data is not assigned in Settings menu. No edit or rebuild allowed.", rect:layout.Inset(), helpbox:true); }

			#region Progress

				layout.Par();

				if (ThreadWorker.IsWorking("Voxeland"))
				{
					float calculatedSum; float completeSum; float totalSum;
					ThreadWorker.GetProgresByTag("VoxelandChunk", out totalSum, out calculatedSum, out completeSum);

					if (totalSum>10) 
					{
						Rect gaugeRect = layout.Inset(0.7f);
						layout.Gauge(0, "", gaugeRect);
						layout.Gauge(1, "", new Rect(gaugeRect.x, gaugeRect.y, gaugeRect.width * calculatedSum/totalSum, gaugeRect.height), disabled:true);
						layout.Gauge(1, "", new Rect(gaugeRect.x, gaugeRect.y, gaugeRect.width * completeSum/totalSum, gaugeRect.height));

					//	Rect cursor = layout.cursor;
				//		layout.Gauge(calculatedSum/totalSum, "", layout.Inset(0.7f), disabled:true);
					//	layout.cursor = cursor;
				//		layout.Gauge(calculatedSum/totalSum, "", layout.Inset(0.7f));
						//layout.Gauge(progress, "Progress: " + (int)completeSum + "(" + calculatedSum + ")" + "/" + (int)totalSum, layout.Inset(0.7f));
					//	layout.cursor = cursor;
						layout.Label("Progress: " + (int)completeSum + "(" + calculatedSum + ")" + "/" + (int)totalSum, gaugeRect);
					}
					else layout.Label("Progress: building", layout.Inset(0.7f));
					gaugeDisplayed = true;

					Repaint();
				}
				else 
				{
					layout.Label("Progress: complete", layout.Inset(0.7f));
					gaugeDisplayed = false;
				}

				if (layout.Button("Rebuild", layout.Inset(0.3f))) voxeland.Rebuild();

			#endregion

			layout.margin = 0; layout.rightMargin = 5;

			#region Brush
				layout.Par(8); 
				layout.Foldout(ref voxeland.guiBrush, "Brush");
				if (voxeland.guiBrush) 
				{
					Rect anchor = layout.lastRect;

					layout.Field(ref voxeland.brush.form, "Form");
					 voxeland.brush.extent = layout.Field(voxeland.brush.extent, "Extent", min:0, max: voxeland.brush.maxExtent, slider:true);
					layout.Toggle(ref voxeland.brush.round, "Round");
			
					layout.Par(5);
					if (voxeland.brush.form==Brush.Form.stamp)
					{
						 layout.Field(ref voxeland.brush.getStamp, "Get Stamp");
						if (voxeland.brush.getStamp)
						{
							layout.Par();
							layout.Label("Min:",rect:layout.Inset(0.25f));
							layout.Field(ref voxeland.brush.getStampMin.x, "X", rect:layout.Inset(0.25f));
							layout.Field(ref voxeland.brush.getStampMin.y, "Y", rect:layout.Inset(0.25f));
							layout.Field(ref voxeland.brush.getStampMin.z, "Z", rect:layout.Inset(0.25f));

							layout.Par();
							layout.Label("Max:",rect:layout.Inset(0.25f));
							layout.Field(ref voxeland.brush.getStampMax.x, "X", rect:layout.Inset(0.25f));
							layout.Field(ref voxeland.brush.getStampMax.y, "Y", rect:layout.Inset(0.25f));
							layout.Field(ref voxeland.brush.getStampMax.z, "Z", rect:layout.Inset(0.25f));
						}
					}

					layout.Par(5);
					layout.Field(ref voxeland.standardEditMode, "Standard Edit");
					layout.Field(ref voxeland.controlEditMode, "Control Mode");
					layout.Field(ref voxeland.shiftEditMode, "Shift Mode");
					layout.Field(ref voxeland.controlShiftEditMode, "Control+Shift Mode");

					layout.Par(5);
					layout.Toggle(ref voxeland.continuousPainting, "Continuous Painting");

					layout.Foreground(anchor);
					//if (voxeland.guiBrush) layout.Par(3);
				}

			#endregion

				
			#region Land Types
			layout.Par(8); 
			layout.Foldout(ref voxeland.guiBlocks, "Land Blocks");
			if (voxeland.guiBlocks) 
			{ 
				Rect anchor = layout.lastRect;
				layout.margin += 5; layout.rightMargin += 5;
				

				LandTypeList types = voxeland.landTypes;

				//blocks
				if (types.textureArrays  &&  types.mainTexArray != null  &&  types.bumpMapArray != null)
				{
					if (types.mainTexArrDec == null  ||  types.mainTexArrDec.texArr != types.mainTexArray) types.mainTexArrDec = new TextureArrayDecorator(types.mainTexArray);
					if (types.bumpTexArrDec == null  ||  types.bumpTexArrDec.texArr != types.bumpMapArray) types.bumpTexArrDec = new TextureArrayDecorator(types.bumpMapArray);

					int minCount = Mathf.Min(types.mainTexArray.depth, types.bumpMapArray.depth);
					if (types.array.Length != minCount) ArrayTools.Resize(ref types.array, minCount, createElement:num => new BlockType() { name="Land Block" });
				}

				layout.Par(4);
				for (int i=0; i<types.array.Length; i++)
				{
					/*#if RTP
					if (rtpMat) layout.DrawWithBackground(null, active:i==types.selected))
					else layout.DrawWithBackground(types.array[i].OnGUI, active:i==types.selected))

					if (layout.lastChange && !rtpMat) 
					{
						voxeland.landTypes.ApplyToMaterial(voxeland.material);
						voxeland.landTypes.ApplyToMaterial(voxeland.farMaterial);
					}
					#else*/
					
					layout.Layer(types, i);

					if (layout.lastChange) 
					{
						types.ApplyToMaterial(voxeland.material);
						types.ApplyToMaterial(voxeland.farMaterial, horizon:true);
					}

					//#endif
				}

				//drawing buttons
				layout.Par(3); layout.Par();
				layout.LayerButtons(types, types.array.Length, rect:layout.Inset(0.6f));
				layout.Inset(0.05f);
				layout.Field(ref types.changeBlockData, "Sync Data", rect:layout.Inset(0.35f), fieldSize:0.15f);
				layout.Par(5);

				//layout.AssetNewSaveField(ref voxeland.material, "Material", saveFilename:"LandMaterial", saveType:"mat", create:Voxeland.GetDefaultLandMaterial);

				//common (material)
				layout.Par(6); 
				layout.Par();
				layout.Foldout(ref voxeland.guiLandCommon, "General Material", rect:layout.Inset(), bold:false);
				if (voxeland.guiLandCommon) 
				{
					Rect internalAnchor = layout.lastRect;
					layout.change = false;

					layout.AssetNewSaveField(ref voxeland.material, "Material", saveFilename:"LandMaterial", saveType:"mat", create:Voxeland.GetDefaultLandMaterial);
					layout.Par(5);

					if (types.textureArrays)
						layout.Field(ref types.anisotropicFiltration, "Anisotropic Filtration", tooltip:"For TextureArray shader - enables/disables the anisotropic filtration in texture arrays created from blocks textures. Highly affects shader performance.");
					layout.Field(ref types.tile, "Tile");
					layout.Field(ref types.mips, "MipMap Factor");
					layout.Field(ref types.ambientOcclusion, "Ambient Occlusion");
					layout.Field(ref types.blendMapFactor, "Blend Map Factor");
					layout.Field(ref types.blendCrisp, "Blend Crispness");
					layout.Field(ref types.previewType, "Preview");

					if (layout.change)
					{
						types.ApplyToMaterial(voxeland.material);
						types.ApplyToMaterial(voxeland.farMaterial, horizon:true);
					}

					layout.Foreground(internalAnchor, layout.lastRect);
				}
				

				//texture arrays
				layout.Par(6); 
				layout.Foldout(ref voxeland.guiLandTexarr, "Texture Arrays", bold:false);
				if (voxeland.guiLandTexarr) 
				{
					Rect internalAnchor = layout.lastRect;

					layout.Toggle(ref types.textureArrays, "Use Texture Arrays");
					if (layout.lastChange)
					{
						//for (int i=0; i<types.array.Length; i++)
						//	types.array[i].icon = null;
					}

					if (types.textureArrays)
					{
						//if (voxeland.material==null || !voxeland.material.HasProperty("_MainTexArr"))
						//	{ layout.Par(30); layout.Label("Switch material to TextureArray shader in order to use texture arrays.", rect:layout.Inset(), helpbox:true); }

						layout.Par();
						layout.Field(ref types.mainTexArray, "Albedo", rect:layout.Inset(layout.field.width-25-layout.margin-layout.rightMargin));
						if (layout.lastChange) ChangeTextureArray(types.mainTexArray, ref types, isBump:false);
						layout.Inset(5);
						if (layout.Button("", rect:layout.Inset(20), icon:"DPLayout_New"))
						{
							Texture2DArray texArr = CreateTextureArrayAsset("MainTexArr", types, isBump:false);
							if (texArr != null) { types.mainTexArray = texArr; ChangeTextureArray(types.mainTexArray, ref types, isBump:false); }
						}

						layout.Par();
						layout.Field(ref types.bumpMapArray, "Normal", rect:layout.Inset(layout.field.width-25-layout.margin-layout.rightMargin));
						if (layout.lastChange) ChangeTextureArray(types.bumpMapArray, ref types, isBump:true);
						layout.Inset(5);
						if (layout.Button("", rect:layout.Inset(20), icon:"DPLayout_New"))
						{
							Texture2DArray texArr = CreateTextureArrayAsset("BumpMapArr", types, isBump:true);
							if (texArr != null) { types.bumpMapArray = texArr; ChangeTextureArray(types.bumpMapArray, ref types, isBump:true); }
						}

						if (types.bumpMapArray == null)
							{ layout.Par(30); layout.Label("A normal map is required for proper terrain lighing.", rect:layout.Inset(), helpbox:true); }

						layout.Par(0); layout.Inset();
					}
					//if (!types.textureArrays && voxeland.material!=null && voxeland.material.HasProperty("_MainTexArr"))
					//		{ layout.Par(30); layout.Label("Switch material to non-TextureArray (Voxeland/Land) shader in order to use the standard textures.", rect:layout.Inset(), helpbox:true); }
				
					layout.Foreground(internalAnchor, layout.lastRect);
				}

				//megasplat clusters (not yet implemented)
				/*#if __MEGASPLAT__
				layout.Par(6); 
				layout.Foldout(ref voxeland.guiLandMegaSplatClusters, "MegaSplat Clusters", bold:false);
				if (voxeland.guiLandMegaSplatClusters) 
				{
					Rect internalAnchor = layout.lastRect;

					layout.Toggle(ref types.megaClusters, "Use MegaSplat");
					if (layout.lastChange)
					{
						if (types.megaClusters) voxeland.channelEncoding = Voxeland.ChannelEncoding.MegaSplat;
						else voxeland.channelEncoding = Voxeland.ChannelEncoding.RTP;
					}

					if (types.megaClusters)
					{
						if (voxeland.material==null || !voxeland.material.HasProperty("_Diffuse") || !voxeland.material.HasProperty("_Normal"))
							{ layout.Par(30); layout.Label("Assign a proper MegaSplat mesh material.", rect:layout.Inset(), helpbox:true); }

						layout.Field(ref types.megaTexList);
						if (layout.lastChange) 
						{ 
							//if (types.megaTexList != null && types.array.Length != types.megaTexList.clusters.Length) 
							//	ArrayTools.Resize(ref types.array, types.megaTexList.clusters.Length, createElement:num => new BlockType() {name=types.megaTexList.clusters[num].name});
							types.array = new BlockType[0];
							if (types.megaTexList != null)
								ArrayTools.Resize(ref types.array, types.megaTexList.clusters.Length, createElement:num => new BlockType() {name=types.megaTexList.clusters[num].name});
						}
					}

					layout.Foreground(internalAnchor, layout.lastRect);
				}
				#endif*/
				

				//distant display
				layout.Par(6); 
				layout.Foldout(ref voxeland.guiLandFar, "Distant Tile", bold:false);
				if (voxeland.guiLandFar) 
				{
					Rect internalAnchor = layout.lastRect;
					layout.change = false;

					layout.Toggle(ref types.farEnabled, "Enabled");
					layout.Field(ref types.farTile, "Tile");
					layout.Field(ref types.farStart, "Start");
					layout.Field(ref types.farEnd, "End");

					if (layout.change)
					{
						types.ApplyToMaterial(voxeland.material);
						types.ApplyToMaterial(voxeland.farMaterial, horizon:true);
					}

					layout.Foreground(internalAnchor, layout.lastRect);
				}
				

				//horizon
				layout.Par(6); 
				layout.Foldout(ref voxeland.guiLandHorizon, "Horizon", bold:false);
				if (voxeland.guiLandHorizon) 
				{
					Rect internalAnchor = layout.lastRect;
					layout.change = false;

					layout.Field(ref types.horizonTile, "Tile");
					layout.Field(ref types.horizonBorderLower, "Border Lower");

					if (layout.change)
					{
						types.ApplyToMaterial(voxeland.material);
						types.ApplyToMaterial(voxeland.farMaterial, horizon:true);
					}

					layout.Foreground(internalAnchor, layout.lastRect);
				}
				
				layout.Par(5);

				
				layout.margin -= 5; layout.rightMargin -= 5;
				layout.Par(0,0,0); layout.Inset(1);
				layout.Foreground(anchor, layout.lastRect);
			}
			#endregion


			#region Object Types
			layout.Par(8); 
			layout.Foldout(ref voxeland.guiObjects, "Object Blocks");
			if (voxeland.guiObjects) 
			{ 
				Rect anchor = layout.lastRect;
				layout.margin += 5; layout.rightMargin += 5;

				ObjectTypeList types = voxeland.objectsTypes;

				layout.Par(0);
				for (int i=0; i<types.array.Length; i++)
					layout.Layer(types, i);

				layout.Par(3); layout.Par();
				layout.LayerButtons(types, types.array.Length, rect:layout.Inset(0.6f));
				layout.Inset(0.05f);
				layout.Field(ref types.changeBlockData, "Sync Data", rect:layout.Inset(0.35f), fieldSize:0.15f);

				layout.Par(10);
				layout.Toggle(ref voxeland.objectsPool.regardPrefabRotation, "Regard Prefab Rotation");
				layout.Toggle(ref voxeland.objectsPool.regardPrefabScale, "Regard Prefab Scale");
				layout.Toggle(ref voxeland.objectsPool.instantiateClones, "Instantiate Clones");

				layout.margin -= 5; layout.rightMargin -= 5;
				layout.Foreground(anchor);
			}
			#endregion


			#region Grass Types
			layout.Par(8); 
			layout.Foldout(ref voxeland.guiGrass, "Grass");
			if (voxeland.guiGrass) 
			{
				Rect anchor = layout.lastRect;
				layout.margin += 5; layout.rightMargin += 5;

				GrassTypeList types = voxeland.grassTypes;


				//layers
				layout.Par(4);
				for (int i=0; i<types.array.Length; i++)
				{
					layout.Layer(types, i);
					if (layout.lastChange) types.ApplyToMaterial(voxeland.grassMaterial);
				}

				//drawing buttons
				layout.Par(3); layout.Par();
				layout.LayerButtons(types, types.array.Length, rect:layout.Inset(0.6f));
				layout.Inset(0.05f);
				layout.Field(ref types.changeBlockData, "Sync Data", rect:layout.Inset(0.35f), fieldSize:0.15f);
				layout.Par(5);

				//common (material)
				layout.Par(6); 
				layout.Par();
				layout.Foldout(ref voxeland.guiGrassCommon, "Grass Material", rect:layout.Inset(), bold:false);
				if (voxeland.guiGrassCommon) 
				{
					Rect internalAnchor = layout.lastRect;
					layout.change = false;

					layout.AssetNewSaveField(ref voxeland.grassMaterial, "Material", saveFilename:"GrassMaterial", saveType:"mat", create:Voxeland.GetDefaultGrassMaterial);
					layout.Par(5);

					layout.Field(ref types.culling, "Culling");
					layout.Field(ref types.cutoff, "Alpha Ref");
					layout.Field(ref types.ambientPower, "Ambient");
					layout.Field(ref types.mipFactor, "Mip Factor");
					layout.Field(ref types.vanishAngle, "Vanish Angle");
					layout.Field(ref types.appearAngle, "Appear Angle");
					layout.Par(5); layout.Inset();

					if (layout.change)
						types.ApplyToMaterial(voxeland.grassMaterial);

					layout.Foreground(internalAnchor, layout.lastRect);
				}

				//atlas
				layout.Par(6); 
				layout.Par();
				layout.Foldout(ref voxeland.guiGrassAtlas, "Atlas", rect:layout.Inset(), bold:false);
				if (voxeland.guiGrassAtlas) 
				{
					Rect internalAnchor = layout.lastRect;
					layout.change = false;

					layout.Field(ref types.atlas, "Atlas Enabled");
					if (layout.lastChange && types.atlas)  //removing layer textures
						for (int i=0; i<types.array.Length; i++)
						{
//							types.array[i].mainTex = null;
//							types.array[i].bumpMap = null;
//							types.array[i].specSmoothMap = null;
//							types.array[i].sssVanishMap = null;
						}
					if (layout.lastChange && types.atlas)  //removing assigned atlas
					{
//						types.mainTex = null;
//						types.bumpMap = null;
//						types.specSmoothMap = null;
//						types.sssVanishMap = null;
					}

					if (types.atlas)
					{
						layout.Field(ref types.mainTex, "Albedo/Alpha");
						layout.Field(ref types.bumpMap, "Normal");
						layout.Field(ref types.specSmoothMap, "Spec/Gloss");
						layout.Field(ref types.sssVanishMap, "SSS");
						
					}

					if (layout.change)
						types.ApplyToMaterial(voxeland.grassMaterial);

					layout.Foreground(internalAnchor, layout.lastRect);
				}

				//SSS
				layout.Par(6); 
				layout.Par();
				layout.Foldout(ref voxeland.guiGrassSSS, "Translucency", rect:layout.Inset(), bold:false);
				if (voxeland.guiGrassSSS) 
				{
					Rect internalAnchor = layout.lastRect;
					layout.change = false;

					layout.Field(ref types.sss, "Value");
					layout.Field(ref types.saturation, "Saturation");
					layout.Field(ref types.sssDistance, "Distance");
					layout.Par(5); layout.Inset();

					if (layout.change)
						types.ApplyToMaterial(voxeland.grassMaterial);

					layout.Foreground(internalAnchor, layout.lastRect);
				}

				//Shake
				layout.Par(6); 
				layout.Par();
				layout.Foldout(ref voxeland.guiGrassShake, "Shake/Wind", rect:layout.Inset(), bold:false);
				if (voxeland.guiGrassShake) 
				{
					Rect internalAnchor = layout.lastRect;
					layout.change = false;

					layout.Field(ref types.shakingAmplitude, "Shake Amplitude");
					layout.Field(ref types.shakingFrequency, "Shake Frequency");

					layout.Field(ref types.windTex, "Wind Texture");
					layout.Field(ref types.windSize, "Wind Size");
					layout.Field(ref types.windSpeed, "Wind Speed");
					layout.Field(ref types.windStrength, "Wind Strength");

					if (layout.change)
						types.ApplyToMaterial(voxeland.grassMaterial);

					layout.Foreground(internalAnchor, layout.lastRect);
				}

				layout.Par(5); layout.Inset();
				layout.margin -= 5; layout.rightMargin -= 5;
				layout.Foreground(anchor);
			}
			#endregion


			#region Distances

			layout.Par(8); 
			layout.Foldout(ref voxeland.guiDistances, "Mode and Ranges");
			if (voxeland.guiDistances)
			{
				Rect anchor = layout.lastRect;

				layout.fieldSize = 0.4f;
				layout.Field(ref voxeland.editorSizeMode, "Editor Mode");
				layout.Field(ref voxeland.playmodeSizeMode, "Playmode Mode");
				
				layout.Par(5);
				if (voxeland.editorSizeMode!=Voxeland.SizeMode.DynamicInfinite || voxeland.playmodeSizeMode!=Voxeland.SizeMode.DynamicInfinite)
				{
					layout.Field(ref voxeland.terrainSize, "Terrain Size");
					voxeland.terrainSize = ((int)(voxeland.terrainSize/voxeland.chunkSize)) * voxeland.chunkSize;
				}

				bool prevChange = layout.change;
				layout.change = false;

				if (voxeland.editorSizeMode!=Voxeland.SizeMode.Static || voxeland.playmodeSizeMode!=Voxeland.SizeMode.Static)
				{
					layout.Par(5);
					layout.Label("Terrain Ranges:");
					if (voxeland.guiDistancesFullControl)
					{
						layout.fieldSize = 0.2f;
						voxeland.guiDistancesMax = layout.Field(voxeland.guiDistancesMax, "Max Distance", delayed:true);
						layout.fieldSize = 0.8f;
					
						layout.Par(5);
						layout.Label("Chunks");
						DrawRange("Create", ref voxeland.createRange, 0.01f, voxeland.guiDistancesMax, voxeland.guiDistancesMax);
						DrawRange("Remove", ref voxeland.removeRange, voxeland.createRange, voxeland.guiDistancesMax, voxeland.guiDistancesMax);

						layout.Par(5);
						layout.Label("Voxel Meshes");
						DrawRange("Low Detail", ref voxeland.voxelLoRange,	voxeland.voxelHiRange,	voxeland.createRange,	voxeland.guiDistancesMax);
						DrawRange("High Detail", ref voxeland.voxelHiRange,	0.01f,						voxeland.voxelLoRange,	voxeland.guiDistancesMax);
						DrawRange("Collision", ref voxeland.collisionRange,	0.01f,						voxeland.voxelLoRange,	voxeland.guiDistancesMax);
						DrawRange("Objects", ref voxeland.objectsRange,		0.01f,						voxeland.createRange,	voxeland.guiDistancesMax);
						DrawRange("Grass", ref voxeland.grassRange,			0.01f,						voxeland.voxelLoRange,	voxeland.guiDistancesMax);
						DrawRange("Remove", ref voxeland.voxelRemoveRange,	voxeland.voxelLoRange,	voxeland.createRange,	voxeland.guiDistancesMax);

						layout.Par(5);
						layout.Label("Sculpt Areas");
						DrawRange("Generate", ref voxeland.areaGenerateRange, 0.01f, voxeland.areaRemoveRange, voxeland.areaRemoveRange);
						DrawRange("Remove", ref voxeland.areaRemoveRange, voxeland.areaGenerateRange, voxeland.areaRemoveRange, voxeland.areaRemoveRange);
					}

					else 
					{
						layout.fieldSize = 0.8f;
					
						DrawRange("Voxel Mesh", ref voxeland.voxelLoRange,	0.01f,	300, 300);
						DrawRange("Objects", ref voxeland.objectsRange,		0.01f,	300, 300);

						layout.Par(5);
						DrawRange("Collision", ref voxeland.collisionRange,	0.01f,	voxeland.voxelLoRange,	voxeland.guiDistancesMax);
						DrawRange("Grass", ref voxeland.grassRange,			0.01f,	voxeland.voxelLoRange,	voxeland.guiDistancesMax);
						DrawRange("High Detail", ref voxeland.voxelHiRange,	0.01f,	voxeland.voxelLoRange,	voxeland.guiDistancesMax);

						voxeland.createRange = Mathf.Max(voxeland.voxelLoRange, voxeland.objectsRange);
						voxeland.removeRange = voxeland.createRange + voxeland.chunkSize*2+1;
						voxeland.voxelRemoveRange = voxeland.voxelLoRange + voxeland.chunkSize*2+1;

						voxeland.areaGenerateRange = voxeland.createRange + voxeland.data.areaSize;
						voxeland.areaRemoveRange = voxeland.areaGenerateRange + voxeland.data.areaSize*2;
					}

					layout.Toggle(ref voxeland.guiDistancesFullControl, "Advanced");
					layout.fieldSize = 0.5f;
				}

				if (layout.change) voxeland.ForceUpdate();
				layout.change = prevChange;

				layout.Foreground(anchor);
			}
			#endregion

			#region Settings

			layout.Par(8); 
			layout.Foldout(ref voxeland.guiSettings, "Settings");
			if (voxeland.guiSettings)
			{
				Rect anchor = layout.lastRect;

				layout.margin += 5; layout.rightMargin += 5;
				layout.fieldSize = 0.4f;

				//data label
				layout.Par(5);
				voxeland.data = layout.ScriptableAssetField(voxeland.data, construct:null, savePath:null, fieldSize:0.8f);

				//margins
				layout.Par(5);
				layout.Field(ref voxeland.meshMargin, "Mesh Margin");
				layout.Field(ref voxeland.ambientMargin, "Ambient Margin");
				layout.Field(ref voxeland.ambientFade, "Ambient Fade", min:0, max:1);
				layout.Field(ref voxeland.normalsSmooth, "Smooth Normals", min:0, max:5);
				layout.Field(ref voxeland.relaxStrength, "Relax Strength", min:0, max:3);
				layout.Field(ref voxeland.relaxIterations, "Relax Iterations", min:0, max:10);
				if (voxeland.relaxIterations > voxeland.meshMargin)
				{
					layout.Par(30);
					layout.Label("Consider using Mesh Margin value higher than Relax Iterations to avoid visible seams between chunks.", rect:layout.Inset(), helpbox:true);
				}
				layout.Field(ref voxeland.channelEncoding, "Mesh Channel Encoding");
				layout.Field(ref voxeland.useAmbient, "Use Ambient");
				layout.Field(ref voxeland.playmodeEdit, "Edit in Playmode");
				

				//threads
				layout.Par(5);
				layout.Field(ref ThreadWorker.multithreading, "Multithreading");

				if (ThreadWorker.multithreading)
				{
					layout.Par();
					layout.Field(ref ThreadWorker.maxThreads, "Max Threads", rect:layout.Inset(0.75f), fieldSize:0.2f, disabled:ThreadWorker.autoMaxThreads);
					layout.Toggle(ref ThreadWorker.autoMaxThreads, "Auto",rect:layout.Inset(0.25f));
				}
				else layout.Field(ref ThreadWorker.maxThreads, "Max Coroutines");
				 
				layout.Field(ref ThreadWorker.maxApplyTime, "Max Apply Time");

				//other
				layout.Par(5);
				layout.Field(ref voxeland.guiLockSelection, "Lock Selection");
				layout.Field(ref voxeland.guiHideWireframe, "Hide Frame");
				if (layout.lastChange) voxeland.transform.ToggleDisplayWireframe(!voxeland.guiHideWireframe);
				layout.Field(ref voxeland.hideColliderWire, "Hide Collider Wire");
				layout.Field(ref voxeland.brush.maxExtent, "Max Brush Size");
				if (voxeland.brush.maxExtent>8) { layout.Par(30); layout.Label("Large brush extent can slow down Blob Brush display", layout.Inset(), helpbox:true); }

				layout.Par(5);
				layout.Field(ref voxeland.saveMeshes, "Save Meshes with Scene");
				layout.Field(ref voxeland.saveNonpinnedAreas, "Save Non-pinned Areas");

				layout.Par(5);
				layout.Field(ref voxeland.chunkName, "Default Chunk Name");
				layout.Field(ref voxeland.copyLayersTags, "Copy Layers and Tags to Chunk");
				layout.Field(ref voxeland.copyComponents, "Copy Components to Chunk");

				//horizon
				layout.Par(10);
				layout.Par(0,padding:0); layout.Inset();
				Rect internalAnchor = layout.lastRect;
				bool useHorizon = layout.Toggle(voxeland.horizon!=null, "Horizon Mesh");
				if (useHorizon && voxeland.horizon==null) 
				{
					voxeland.horizon = Horizon.Create(voxeland); 
					voxeland.horizon.meshRenderer.sharedMaterial = voxeland.farMaterial;  
					
					voxeland.landTypes.ApplyToMaterial(voxeland.farMaterial, horizon:true);
				}

				if (!useHorizon && voxeland.horizon!=null) GameObject.DestroyImmediate(voxeland.horizon.gameObject);

				if (voxeland.horizon!=null)
				{
					voxeland.horizon.meshFilter.sharedMesh = layout.Field(voxeland.horizon.meshFilter.sharedMesh, "Mesh");
					layout.Field(ref voxeland.horizon.meshSize, "Mesh Bounding Box Size");
					layout.Field(ref voxeland.horizon.scale, "Scale");
					layout.Field(ref voxeland.horizon.textureResolutions, "Texture Resolution");
				}
				else
				{
					layout.Field<Mesh>(null, "Mesh", disabled:true);
					layout.Field(60, "Mesh Bounding Box Size", disabled:true);
					layout.Field(1, "Scale", disabled:true);
					layout.Field(512, "Texture Resolution", disabled:true);
				}
				layout.Foreground(internalAnchor);

				//floaty origin solution
				layout.Par(10);
				layout.Par(0,padding:0); layout.Inset();
				internalAnchor = layout.lastRect;
				layout.Toggle(ref voxeland.shift, "Shift World (Floating Point Solution)");
				layout.Field(ref voxeland.shiftThreshold, "Shift Threshold", disabled:!voxeland.shift);
				layout.Foreground(internalAnchor);

				//debug
				BuildTargetGroup buildGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
				string defineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildGroup);
				
				bool debug = false;
				if (defineSymbols.Contains("WDEBUG;") || defineSymbols.EndsWith("WDEBUG")) debug = true;
				
				layout.Par(10);
				layout.Toggle(ref debug, "Debug (Requires re-compile)");
				if (layout.lastChange) 
				{
					if (debug)
					{
						defineSymbols += (defineSymbols.Length!=0? ";" : "") + "WDEBUG";
					}
					else
					{
						defineSymbols = defineSymbols.Replace("WDEBUG","");  
						defineSymbols = defineSymbols.Replace(";;", ";"); 
					}
					PlayerSettings.SetScriptingDefineSymbolsForGroup(buildGroup, defineSymbols);
				}

				layout.margin -= 5; layout.rightMargin -= 5;

				layout.Foreground(anchor);
			}

			#endregion

			#region Material
			layout.Par(8); 
			layout.Foldout(ref voxeland.guiMaterial, "Materials");
			if (voxeland.guiMaterial)
			{
				Rect anchor = layout.lastRect;
				layout.margin += 10;
				layout.fieldSize = 0.5f;

				layout.AssetNewSaveField(ref voxeland.material, "Land", saveFilename:"Land", saveType:"mat", create:Voxeland.GetDefaultLandMaterial);
				layout.AssetNewSaveField(ref voxeland.farMaterial, "Horizon", saveFilename:"Horizon", saveType:"mat", create:Voxeland.GetDefaultFarMaterial);
				layout.AssetNewSaveField(ref voxeland.grassMaterial, "Grass", saveFilename:"Grass.mat", saveType:"mat", create:Voxeland.GetDefaultGrassMaterial);
				if (voxeland.highlight!=null) layout.AssetNewSaveField(ref voxeland.highlight.material, "Highlight", saveFilename:"Highlight.mat", saveType:"mat", create:Voxeland.GetDefaultHighlightMaterial);
				else layout.Field<Material>(null, "Highlight", disabled:true);

				layout.margin -= 10;
				layout.Foreground(anchor);
				//if (voxeland.guiMaterial) layout.Par(3);
			}

			#endregion

			#region Generate
			layout.Par(8); 
			layout.Foldout(ref voxeland.guiGenerate, "Generate");
			if (voxeland.guiGenerate)
			{
				Rect anchor = layout.lastRect;
				layout.margin += 10;

				if (voxeland.data == null) layout.Label("No proper Voxeland data to generate");
				else
				{	
					Generator generator = voxeland.data.generator;
					bool change = layout.change;
					layout.change = false;
				
					layout.Field(ref generator.generatorType, "Generator Type");

					//gathering block names
					if (blockNames == null || blockNames.Length != voxeland.landTypes.array.Length+2) blockNames = new string[voxeland.landTypes.array.Length+2];
					for (int i=0; i<voxeland.landTypes.array.Length; i++)
						blockNames[i] = voxeland.landTypes.array[i].name;
					blockNames[blockNames.Length-1] = "Empty";

					if (objectNames == null || objectNames.Length != voxeland.objectsTypes.array.Length+2) objectNames = new string[voxeland.objectsTypes.array.Length+2];
					for (int i=0; i<voxeland.objectsTypes.array.Length; i++)
						objectNames[i] = voxeland.objectsTypes.array[i].name;
					objectNames[objectNames.Length-1] = "Empty";

					if (grassNames == null || grassNames.Length != voxeland.grassTypes.array.Length+2) grassNames = new string[voxeland.grassTypes.array.Length+2];
					for (int i=0; i<voxeland.grassTypes.array.Length; i++)
						grassNames[i] = voxeland.grassTypes.array[i].name;
					grassNames[grassNames.Length-1] = "Empty";


					layout.Par(10);
			
					if (generator.generatorType == Generator.GeneratorType.Planar)
					{
						generator.planarGen.OnGUI(layout, blockNames);
					}

					if (generator.generatorType == Generator.GeneratorType.Noise)
					{
						generator.noiseGen.OnGUI(layout, blockNames, "Noise");
						generator.curveGen.OnGUI(layout, blockNames);
						generator.slopeGen.OnGUI(layout, blockNames);
						generator.cavityGen.OnGUI(layout, blockNames);
						generator.blurGen.OnGUI(layout, blockNames);
						generator.stainsGen.OnGUI(layout, blockNames);
						generator.noiseGenB.OnGUI(layout, blockNames, "Bedrock (Noise)");
						generator.scatterGen.OnGUI(layout, objectNames, blockNames);

						//grass
						generator.grassGens.grassNames = grassNames;
						generator.grassGens.landNames = blockNames;

						layout.LayerButtons(generator.grassGens, generator.grassGens.gens.Length, "Grass Generators:", addBeforeSelected:true);

						layout.margin += 3; layout.rightMargin += 1; //right margin is 3 by default
						layout.Par(3);
						for (int num=0; num<generator.grassGens.gens.Length; num++)
							layout.Layer(generator.grassGens, num);
						layout.Par(3);
						layout.margin -= 3; layout.rightMargin -= 1;
					}

					else if (generator.generatorType == Generator.GeneratorType.MapMagic)
					{
						#if MAPMAGIC
						MapMagic.VoxelandOutput.voxeland = voxeland;
						MapMagic.VoxelandGrassOutput.voxeland = voxeland;
						MapMagic.VoxelandObjectsOutput.voxeland = voxeland;

						//data field
						layout.Par(5);
						layout.fieldSize = 0.7f;
						//generator.mapMagicGens = layout.ScriptableAssetField(generator.mapMagicGens, construct:MapMagic.GeneratorsAsset.DefaultVoxeland, savePath: null);
						generator.mapMagicGens = layout.ScriptableAssetField(generator.mapMagicGens, construct:MapMagic.Graph.DefaultVoxeland, savePath: null);
						if (layout.lastChange) 
							MapMagic.MapMagicWindow.Show(generator.mapMagicGens, voxeland, forceOpen:false, asBiome:false);
				
						//show editor button
						layout.Par(5);
						layout.Par(22);
						if (layout.Button("Show Editor", rect:layout.Inset(1f), disabled:generator.mapMagicGens==null))
							MapMagic.MapMagicWindow.Show(generator.mapMagicGens, voxeland, forceOpen:true);
					
						#else
						layout.Par(40);
						layout.Label("MapMagic World Generator does not seems to be installed. If you sure that you have it try restarting Unity to add it's define symbol.", rect:layout.Inset(), helpbox:true);
						#endif
					}

					else if (generator.generatorType == Generator.GeneratorType.Heightmap)
					{
						generator.standaloneHeightGen.OnGUI(layout, blockNames);
					}

					if (generator.generatorType != Generator.GeneratorType.Planar)
					{
						layout.Par(10);
				
						layout.Field(ref generator.seed, "Seed"); if (layout.lastChange) generator.change = true;
						#if MAPMAGIC
						if (layout.lastChange) voxeland.ClearResults();
						#endif
						layout.Field(ref generator.heightFactor, "Height"); if (layout.lastChange) generator.change = true;
						layout.Toggle(ref generator.saveResults, "Save Interim Results");
						layout.Toggle(ref generator.instantGenerate,"Instant Generate");
						//layout.Toggle(ref generator.forceGenerateChangedAreas, "Force Generate Changed Areas");
						layout.Toggle(ref generator.polish, "Polish");
						//layout.Toggle(ref generator.leaveDemoUntouched, "Leave Demo Untouched");
				
						layout.Par();
						layout.Toggle(ref generator.removeThinLayers, "Remove Thin Layers", rect:layout.Inset(0.8f));
						layout.Field(ref generator.minLayerThickness, rect:layout.Inset(0.2f));

						if (layout.change) voxeland.Refresh();
						layout.change = change;
					}

					layout.Par(5);

					string readyIcon = "Voxeland_Success"; int readyAnimFrames = 0;
					if (ThreadWorker.IsWorking("VoxelandGenerate")) { readyIcon = "Voxeland_Loading"; readyAnimFrames=12; Repaint(); }

					layout.Par(24);
					if (layout.Button("Generate", rect:layout.Inset(), icon:readyIcon, iconAnimFrames:readyAnimFrames)) 
						voxeland.Refresh();
					if (layout.Button("Force Re-Generate") && EditorUtility.DisplayDialog("Re-Generate", "This will remove all of the custom changes made in your DATA file. Are you sure you wish to continue?", "Re-Generate", "Cancel")) 
						voxeland.Refresh(force:true);
					
				}

				layout.margin -= 10;
				layout.Foreground(anchor);
			}
			#endregion

			#region About
			layout.Par(8); 
			layout.Foldout(ref voxeland.guiAbout, "About");
			if (voxeland.guiAbout)
			{
				Rect anchor = layout.lastRect;
				Rect savedCursor = layout.cursor;
				
				layout.margin = 20;
				layout.Par(100, padding:0);
				layout.Icon("VoxelandIcon", layout.Inset(50,padding:0));

				layout.cursor = savedCursor;
				layout.margin = 80;

				string versionName = Voxeland.version.ToString();
				versionName = versionName[0]+"."+versionName[1]+"."+versionName[2];
				layout.Label("Voxeland " + versionName);
				layout.Label("by Denis Pahunov");
				
				layout.Par(10);
				layout.Label(" - Wiki", url:"https://gitlab.com/denispahunov/voxeland/wikis/home");
				layout.Label(" - Forums", url:"https://forum.unity3d.com/threads/voxeland-voxel-terrain-tool.187741/");
				layout.Label(" - Issues / Ideas", url:"https://gitlab.com/denispahunov/voxeland/issues"); 

				/*layout.Par(10);
				layout.Label("Other Products:");

				layout.Par(5);
				layout.Label("MapMagic", url:"https://gitlab.com/denispahunov/voxeland/wikis/home");
				layout.Label("Node based infinite terrain generator");*/

				layout.Foreground(anchor);
			}
			#endregion

			Layout.SetInspectorRect(layout.field);
		}