You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
12 KiB
C#

3 years ago
using Gaia.Internal;
using PWCommon5;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Gaia
{
public class TerrainStitchInfo
{
public string m_terrainDataGUID;
public bool m_north;
public bool m_south;
public bool m_west;
public bool m_east;
}
public class GaiaTerrainStitcher : EditorWindow, IPWEditor
{
private EditorUtils m_editorUtils;
bool m_targetAllTerrains = true;
static bool m_stitchAllDirections = true;
static bool m_stitchDirectionNorth = true;
static bool m_stitchDirectionSouth = true;
static bool m_stitchDirectionWest = true;
static bool m_stitchDirectionEast = true;
static List<TerrainStitchInfo> m_stitchedTerrains = new List<TerrainStitchInfo>();
static Terrain m_targetTerrain;
public static int m_extraSeamSize = 1;
static float m_maxDifference = 1.0f;
private GaiaSettings m_settings;
public bool PositionChecked { get => true; set => PositionChecked = value; }
void OnEnable()
{
if (m_editorUtils == null)
{
// Get editor utils for this
m_editorUtils = PWApp.GetEditorUtils(this);
}
titleContent = m_editorUtils.GetContent("WindowTitle");
}
void OnGUI()
{
m_editorUtils.Initialize();
m_editorUtils.Panel("TerrainStitcher", DrawTerrainStitcher, true);
}
private void DrawTerrainStitcher(bool helpEnabled)
{
EditorGUILayout.BeginVertical();
m_targetAllTerrains = m_editorUtils.Toggle("AllTerrains", m_targetAllTerrains, helpEnabled);
bool currentGUIState = GUI.enabled;
if (m_targetAllTerrains)
{
GUI.enabled = false;
}
m_targetTerrain = (Terrain)m_editorUtils.ObjectField("TargetTerrain", m_targetTerrain, typeof(Terrain), true, helpEnabled);
GUI.enabled = currentGUIState;
m_stitchAllDirections = m_editorUtils.Toggle("StitchAllDirections", m_stitchAllDirections, helpEnabled);
if (!m_stitchAllDirections)
{
m_stitchDirectionNorth = m_editorUtils.Toggle("StitchDirectionNorth", m_stitchDirectionNorth, helpEnabled);
m_stitchDirectionSouth = m_editorUtils.Toggle("StitchDirectionSouth", m_stitchDirectionSouth, helpEnabled);
m_stitchDirectionWest = m_editorUtils.Toggle("StitchDirectionWest", m_stitchDirectionWest, helpEnabled);
m_stitchDirectionEast = m_editorUtils.Toggle("StitchDirectionEast", m_stitchDirectionEast, helpEnabled);
}
m_maxDifference = m_editorUtils.Slider("MaxDifference", m_maxDifference * 100, 0, 100, helpEnabled) / 100f;
m_extraSeamSize = m_editorUtils.IntSlider("ExtraSeamSize", m_extraSeamSize, 0, 200, helpEnabled);
if (m_settings == null)
{
m_settings = GaiaUtils.GetGaiaSettings();
}
GUI.backgroundColor = m_settings.GetActionButtonColor();
if (m_editorUtils.Button("StartStitching"))
{
if (!m_targetAllTerrains && m_targetTerrain == null)
{
EditorUtility.DisplayDialog("No terrain selected", "There is currently no terrain selected to work with. You need to either check 'Stitch all terrains' or select a single target terrain to use with this tool.", "OK");
EditorGUIUtility.ExitGUI();
return;
}
if (EditorUtility.DisplayDialog("Stitch terrain(s)?", "This tool will align heightmaps between the terrains in your scene. This will permanently change the terrain heights in your scene, so please create a backup of your project if there is any risk of losing work.", "Continue", "Cancel"))
{
m_stitchedTerrains.Clear();
if (m_targetAllTerrains)
{
if (GaiaUtils.HasDynamicLoadedTerrains())
{
GaiaUtils.CallFunctionOnDynamicLoadedTerrains(StitchTerrain, false);
}
else
{
foreach (Terrain t in Terrain.activeTerrains)
{
StitchTerrain(t);
}
}
}
else
{
if (m_targetTerrain != null)
{
StitchTerrain(m_targetTerrain);
}
}
}
}
EditorGUILayout.EndVertical();
}
public static void StitchTerrain(Terrain terrain)
{
TerrainStitchInfo stitchInfo = GetOrCreateStitchInfo(terrain);
Terrain neighborTerrain = null;
TerrainStitchInfo neighborStitchInfo = null;
//Before we begin, we need to load in the potential neighbor scenes for stitching
TerrainScene neighborSceneNorth = null;
TerrainScene neighborSceneSouth = null;
TerrainScene neighborSceneEast = null;
TerrainScene neighborSceneWest = null;
if (GaiaUtils.HasDynamicLoadedTerrains())
{
TerrainScene ts = TerrainLoaderManager.Instance.GetTerrainSceneAtPosition(terrain.transform.position + terrain.terrainData.size * 0.5f);
neighborSceneNorth = TerrainLoaderManager.Instance.TryGetNeighbor(ts, StitchDirection.North);
neighborSceneSouth = TerrainLoaderManager.Instance.TryGetNeighbor(ts, StitchDirection.South);
neighborSceneEast = TerrainLoaderManager.Instance.TryGetNeighbor(ts, StitchDirection.East);
neighborSceneWest = TerrainLoaderManager.Instance.TryGetNeighbor(ts, StitchDirection.West);
}
if ((m_stitchAllDirections || m_stitchDirectionNorth) && stitchInfo.m_north ==false)
{
if (neighborSceneNorth != null)
{
if (neighborSceneNorth.m_regularLoadState != LoadState.Loaded)
{
neighborSceneNorth.AddRegularReference(TerrainLoaderManager.Instance.gameObject);
}
}
neighborTerrain = TerrainHelper.GetTerrainNeighbor(terrain, StitchDirection.North);
if (neighborTerrain != null)
{
neighborStitchInfo = GetOrCreateStitchInfo(neighborTerrain);
if (neighborStitchInfo.m_south == false)
{
TerrainHelper.StitchTerrainHeightmaps(terrain, neighborTerrain, m_extraSeamSize, m_maxDifference);
}
stitchInfo.m_north = true;
neighborStitchInfo.m_south = true;
}
if (neighborSceneNorth != null)
{
neighborSceneNorth.RemoveAllReferences();
}
}
if ((m_stitchAllDirections || m_stitchDirectionSouth) && stitchInfo.m_south == false)
{
if (neighborSceneSouth != null)
{
if (neighborSceneSouth.m_regularLoadState != LoadState.Loaded)
{
neighborSceneSouth.AddRegularReference(TerrainLoaderManager.Instance.gameObject);
}
}
neighborTerrain = TerrainHelper.GetTerrainNeighbor(terrain, StitchDirection.South);
if (neighborTerrain != null)
{
neighborStitchInfo = GetOrCreateStitchInfo(neighborTerrain);
if (neighborStitchInfo.m_north == false)
{
TerrainHelper.StitchTerrainHeightmaps(terrain, neighborTerrain, m_extraSeamSize, m_maxDifference);
}
stitchInfo.m_south = true;
neighborStitchInfo.m_north = true;
}
if (neighborSceneSouth != null)
{
neighborSceneSouth.RemoveAllReferences();
}
}
if ((m_stitchAllDirections || m_stitchDirectionWest) && stitchInfo.m_west == false)
{
if (neighborSceneWest != null)
{
if (neighborSceneWest.m_regularLoadState != LoadState.Loaded)
{
neighborSceneWest.AddRegularReference(TerrainLoaderManager.Instance.gameObject);
}
}
neighborTerrain = TerrainHelper.GetTerrainNeighbor(terrain, StitchDirection.West);
if (neighborTerrain != null)
{
neighborStitchInfo = GetOrCreateStitchInfo(neighborTerrain);
if (neighborStitchInfo.m_east == false)
{
TerrainHelper.StitchTerrainHeightmaps(terrain, neighborTerrain, m_extraSeamSize, m_maxDifference);
}
stitchInfo.m_west = true;
neighborStitchInfo.m_east= true;
}
if (neighborSceneWest != null)
{
neighborSceneWest.RemoveAllReferences();
}
}
if ((m_stitchAllDirections || m_stitchDirectionEast) && stitchInfo.m_east == false)
{
if (neighborSceneEast != null)
{
if (neighborSceneEast.m_regularLoadState != LoadState.Loaded)
{
neighborSceneEast.AddRegularReference(TerrainLoaderManager.Instance.gameObject);
}
}
neighborTerrain = TerrainHelper.GetTerrainNeighbor(terrain, StitchDirection.East);
if (neighborTerrain != null)
{
neighborStitchInfo = GetOrCreateStitchInfo(neighborTerrain);
if (neighborStitchInfo.m_west== false)
{
TerrainHelper.StitchTerrainHeightmaps(terrain, neighborTerrain, m_extraSeamSize, m_maxDifference);
}
stitchInfo.m_east = true;
neighborStitchInfo.m_west = true;
}
if (neighborSceneEast != null)
{
neighborSceneEast.RemoveAllReferences();
}
}
}
private static TerrainStitchInfo GetOrCreateStitchInfo(Terrain terrain)
{
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(terrain.terrainData));
if (!String.IsNullOrEmpty(guid))
{
TerrainStitchInfo stitchInfo = m_stitchedTerrains.Find(x => x.m_terrainDataGUID == guid);
if (stitchInfo == null)
{
stitchInfo = new TerrainStitchInfo() { m_terrainDataGUID = guid };
m_stitchedTerrains.Add(stitchInfo);
}
return stitchInfo;
}
else
{
Debug.LogError($"Error while stitching terrains, could not find terrain data GUID for terrain {terrain.name}");
return null;
}
}
}
}