void OnEnable() { if (Terrain.activeTerrain != null) { m_selectedMask = GaiaSplatPrototype.GetGaiaSplatPrototypes(Terrain.activeTerrain).Length; } }
void OnGUI() { //Set up the box style if (m_boxStyle == null) { m_boxStyle = new GUIStyle(GUI.skin.box); m_boxStyle.normal.textColor = GUI.skin.label.normal.textColor; m_boxStyle.fontStyle = FontStyle.Bold; m_boxStyle.alignment = TextAnchor.UpperLeft; } //Setup the wrap style if (m_wrapStyle == null) { m_wrapStyle = new GUIStyle(GUI.skin.label); m_wrapStyle.fontStyle = FontStyle.Normal; m_wrapStyle.wordWrap = true; } //Text intro GUILayout.BeginVertical("Gaia Mask Exporter", m_boxStyle); GUILayout.Space(20); EditorGUILayout.LabelField("The Gaia splatmap exporter allows you to export texture splatmaps to use as masks.", m_wrapStyle); GUILayout.EndVertical(); if (string.IsNullOrEmpty(m_maskName)) { m_maskName = string.Format("Terrain-Splatmaps-{0:yyyyMMdd-HHmmss}", DateTime.Now); } m_maskName = EditorGUILayout.TextField(GetLabel("Mask Name"), m_maskName); List <GUIContent> textureNames = new List <GUIContent>(); if (Terrain.activeTerrain != null) { var splatPrototypes = GaiaSplatPrototype.GetGaiaSplatPrototypes(Terrain.activeTerrain); for (int idx = 0; idx < splatPrototypes.Length; idx++) { textureNames.Add(new GUIContent(splatPrototypes[idx].texture.name)); } } textureNames.Add(new GUIContent("All")); m_selectedMask = EditorGUILayout.Popup(GetLabel("Selected Texture"), m_selectedMask, textureNames.ToArray()); GUILayout.Space(5); EditorGUI.indentLevel++; if (DisplayButton(GetLabel("Export Selected Texture"))) { ExportMask(); } EditorGUI.indentLevel--; }
/// <summary> /// Gets all splat prototypes from a terrain. Uses the correct terrain API for pre and post Unity 2018.3. /// </summary> /// <param name="terrain">The terrain containing the splat prototype data.</param> /// <returns>Null if invalid terrain data. An empty GaiaSplatPrototype array if no splat prototypes in terrain data. A filled GaiaSplatPrototype array if splat prototypes present.</returns> public static GaiaSplatPrototype[] GetGaiaSplatPrototypes(Terrain terrain) { if (terrain == null || terrain.terrainData == null) { return(null); } TerrainData terrainData = terrain.terrainData; #if UNITY_2018_3_OR_NEWER if (terrainData.terrainLayers == null || terrainData.terrainLayers.Length == 0) { return(new GaiaSplatPrototype[0]); } GaiaSplatPrototype[] splatPrototypes = new GaiaSplatPrototype[terrainData.terrainLayers.Length]; for (int i = 0; i < terrainData.terrainLayers.Length; i++) { splatPrototypes[i] = new GaiaSplatPrototype(terrainData.terrainLayers[i]); } return(splatPrototypes); #else if (terrainData.splatPrototypes == null || terrainData.splatPrototypes.Length == 0) { return(new GaiaSplatPrototype[0]); } GaiaSplatPrototype[] splatPrototypes = new GaiaSplatPrototype[terrainData.splatPrototypes.Length]; for (int i = 0; i < terrainData.splatPrototypes.Length; i++) { splatPrototypes[i] = new GaiaSplatPrototype(terrainData.splatPrototypes[i]); } return(splatPrototypes); #endif }
/// <summary> /// Takes a spawner preset list and assembles arrays with the new prototypes in them. If a reference Terrain is passed in, the arrays will contain the existing prototypes on the terrain + only the additional stuff from the preset list, no duplicates. /// </summary> /// <param name="spawnerPresetList"></param> /// <param name="terrainLayers"></param> /// <param name="terrainDetails"></param> /// <param name="terrainTrees"></param> /// <param name="referenceTerrain"></param> public static void GetPrototypes(List <BiomeSpawnerListEntry> spawnerPresetList, ref TerrainLayer[] terrainLayers, ref DetailPrototype[] terrainDetails, ref TreePrototype[] terrainTrees, Terrain referenceTerrain = null) { //Early out when no spawner preset list if (spawnerPresetList == null || spawnerPresetList.Count == 0) { return; } //collect the splat prototypes in a GaiaSplatPrototype List first, then build a terrain layer array from that later List <GaiaSplatPrototype> presetSplatPrototypes = new List <GaiaSplatPrototype>(); List <DetailPrototype> presetTerrainDetails = new List <DetailPrototype>(); List <TreePrototype> presetTerrainTrees = new List <TreePrototype>(); //if there is a reference terrain, start by pre-filling those lists with the prototypes from the terrain if (referenceTerrain != null) { foreach (TerrainLayer layer in referenceTerrain.terrainData.terrainLayers) { presetSplatPrototypes.Add(new GaiaSplatPrototype(layer)); } foreach (DetailPrototype detailPrototype in referenceTerrain.terrainData.detailPrototypes) { presetTerrainDetails.Add(detailPrototype); } foreach (TreePrototype treePrototype in referenceTerrain.terrainData.treePrototypes) { presetTerrainTrees.Add(treePrototype); } } foreach (BiomeSpawnerListEntry preset in spawnerPresetList.Where(x => x.m_autoAssignPrototypes == true)) { if (preset == null) { //Skip entries missing information continue; } if (preset.m_spawnerSettings == null) { continue; } if (preset.m_spawnerSettings.m_resources == null) { continue; } GaiaResource resources = preset.m_spawnerSettings.m_resources; foreach (SpawnRule sr in preset.m_spawnerSettings.m_spawnerRules) { //skip if resource is not maintained properly (=null) if (sr.ResourceIsNull(preset.m_spawnerSettings)) { Debug.Log("Spawn Rule " + sr.m_name + " in " + preset.m_spawnerSettings.name + " has missing resources maintained. This rule might not work properly when spawning later."); continue; } switch (sr.m_resourceType) { case GaiaConstants.SpawnerResourceType.TerrainTexture: ResourceProtoTexture protoTexture = resources.m_texturePrototypes[sr.m_resourceIdx]; if (protoTexture != null) { GaiaSplatPrototype newSplat = new GaiaSplatPrototype(); newSplat.normalMap = protoTexture.m_normal; newSplat.normalScale = protoTexture.m_normalScale; newSplat.smoothness = protoTexture.m_smoothness; newSplat.metallic = protoTexture.m_metallic; newSplat.diffuseRemapMin = protoTexture.m_diffuseRemapMin; newSplat.diffuseRemapMax = protoTexture.m_diffuseRemapMax; newSplat.maskMapRemapMin = protoTexture.m_maskMapRemapMin; newSplat.maskMapRemapMax = protoTexture.m_maskMapRemapMax; newSplat.specularColor = protoTexture.m_specularColor; newSplat.tileOffset = new Vector2(protoTexture.m_offsetX, protoTexture.m_offsetY); newSplat.tileSize = new Vector2(protoTexture.m_sizeX, protoTexture.m_sizeY); newSplat.texture = protoTexture.m_texture; newSplat.maskMap = protoTexture.m_maskmap; //Only add as a new prototype if not a fully equal prototype already exists in the list if (!presetSplatPrototypes.Exists(x => x.texture == newSplat.texture && x.normalMap == newSplat.normalMap && x.tileOffset == newSplat.tileOffset && x.tileSize == newSplat.tileSize )) { presetSplatPrototypes.Add(newSplat); } } break; case GaiaConstants.SpawnerResourceType.TerrainDetail: ResourceProtoDetail protoDetail = resources.m_detailPrototypes[sr.m_resourceIdx]; if (protoDetail != null) { DetailPrototype newTerrainDetail = new DetailPrototype(); newTerrainDetail.renderMode = protoDetail.m_renderMode; newTerrainDetail.prototypeTexture = protoDetail.m_detailTexture; newTerrainDetail.prototype = protoDetail.m_detailProtoype; newTerrainDetail.dryColor = protoDetail.m_dryColour; newTerrainDetail.healthyColor = protoDetail.m_healthyColour; newTerrainDetail.maxHeight = protoDetail.m_maxHeight; newTerrainDetail.maxWidth = protoDetail.m_maxWidth; newTerrainDetail.minHeight = protoDetail.m_minHeight; newTerrainDetail.minWidth = protoDetail.m_minWidth; newTerrainDetail.noiseSpread = protoDetail.m_noiseSpread; if ((protoDetail.m_renderMode == DetailRenderMode.Grass && protoDetail.m_detailProtoype == null) || protoDetail.m_renderMode == DetailRenderMode.GrassBillboard) { if (!presetTerrainDetails.Exists(x => x.prototypeTexture == newTerrainDetail.prototypeTexture && x.prototype == newTerrainDetail.prototype && x.dryColor == newTerrainDetail.dryColor && x.healthyColor == newTerrainDetail.healthyColor && x.maxHeight == newTerrainDetail.maxHeight && x.maxWidth == newTerrainDetail.maxWidth && x.minHeight == newTerrainDetail.minHeight && x.minWidth == newTerrainDetail.minWidth && x.noiseSpread == newTerrainDetail.noiseSpread )) { presetTerrainDetails.Add(newTerrainDetail); } } else { if (!presetTerrainDetails.Exists(x => x.prototype == newTerrainDetail.prototype && x.prototype == newTerrainDetail.prototype && x.dryColor == newTerrainDetail.dryColor && x.healthyColor == newTerrainDetail.healthyColor && x.maxHeight == newTerrainDetail.maxHeight && x.maxWidth == newTerrainDetail.maxWidth && x.minHeight == newTerrainDetail.minHeight && x.minWidth == newTerrainDetail.minWidth && x.noiseSpread == newTerrainDetail.noiseSpread )) { presetTerrainDetails.Add(newTerrainDetail); } } } break; case GaiaConstants.SpawnerResourceType.TerrainTree: ResourceProtoTree protoTree = resources.m_treePrototypes[sr.m_resourceIdx]; if (protoTree != null) { TreePrototype newTree = new TreePrototype(); newTree.bendFactor = protoTree.m_bendFactor; newTree.prefab = protoTree.m_desktopPrefab; if (!presetTerrainTrees.Exists(x => x.bendFactor == newTree.bendFactor && x.prefab == newTree.prefab)) { presetTerrainTrees.Add(newTree); } } break; } } } //now look at the existing terrain layers on the terrain again, and add only the additional new Splat Prototypes as new layers - all the other ones must exist on the terrains already List <GaiaSplatPrototype> additionalSplatPrototypes = new List <GaiaSplatPrototype>(); List <DetailPrototype> additionalTerrainDetails = new List <DetailPrototype>(); List <TreePrototype> additionalTerrainTrees = new List <TreePrototype>(); //Do we have a refernece terrain? The only the splat prototypes with a higher index then what is currently present on the terrain already are relevant if (referenceTerrain != null) { for (int i = referenceTerrain.terrainData.terrainLayers.Length; i <= presetSplatPrototypes.Count - 1; i++) { additionalSplatPrototypes.Add(presetSplatPrototypes[i]); } for (int i = referenceTerrain.terrainData.detailPrototypes.Length; i <= presetTerrainDetails.Count - 1; i++) { additionalTerrainDetails.Add(presetTerrainDetails[i]); } for (int i = referenceTerrain.terrainData.treePrototypes.Length; i <= presetTerrainTrees.Count - 1; i++) { additionalTerrainTrees.Add(presetTerrainTrees[i]); } } else { //no reference terrain - we take preset prototypes collected before additionalSplatPrototypes = presetSplatPrototypes; additionalTerrainDetails = presetTerrainDetails; additionalTerrainTrees = presetTerrainTrees; } //convert Gaia Splat Prototypes into actual terrain layer files string layername = string.Format("Gaia_-{0:yyyyMMdd-HHmmss}", DateTime.Now); TerrainLayer[] additionalTerrainLayers = GaiaSplatPrototype.CreateTerrainLayers(layername, additionalSplatPrototypes.ToArray()); if (referenceTerrain != null) { //got a reference terrain? return the existing prototypes so they are not altered and attach the truly new ones terrainLayers = referenceTerrain.terrainData.terrainLayers; terrainLayers = terrainLayers.Concat(additionalTerrainLayers).ToArray(); terrainDetails = referenceTerrain.terrainData.detailPrototypes; terrainDetails = terrainDetails.Concat(additionalTerrainDetails.ToArray()).ToArray(); terrainTrees = referenceTerrain.terrainData.treePrototypes; terrainTrees = terrainTrees.Concat(additionalTerrainTrees.ToArray()).ToArray(); } else { //no reference terrain, just return all the new stuff directly terrainLayers = additionalTerrainLayers; terrainDetails = additionalTerrainDetails.ToArray(); terrainTrees = additionalTerrainTrees.ToArray(); } }