using System; using System.Collections; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; using UnityEditor.SceneManagement; #endif using UnityEngine; using UnityEngine.SceneManagement; namespace Gaia { public class WorldMap : MonoBehaviour { public Terrain m_worldMapTerrain; public GaiaConstants.EnvironmentSize m_worldMapTileSize = GaiaConstants.EnvironmentSize.Is2048MetersSq; public GaiaConstants.HeightmapResolution m_heightmapResolution = GaiaConstants.HeightmapResolution._2049; public void DeactivateWorldMap() { foreach (Transform t in transform) { t.gameObject.SetActive(false); } } public void ActivateWorldMap() { foreach (Transform t in transform) { t.gameObject.SetActive(true); } } public void LookAtWorldMap() { #if UNITY_EDITOR //Adjust the scene view so you can see the terrain if (SceneView.lastActiveSceneView != null) { if (m_worldMapTerrain != null) { SceneView.lastActiveSceneView.LookAtDirect(new Vector3(m_worldMapTerrain.transform.position.x + (m_worldMapTerrain.terrainData.size.x / 2f), 300f, -1f * (m_worldMapTerrain.terrainData.size.x / 2f)), Quaternion.Euler(30f, 0f, 0f)); } } #endif } /// /// Syncs the heightmap of the world map to the local terrain tiles, preserving correct height scale, heightmap resolution, etc. /// /// A list of local terrain tile names that are valid to change for the sync operation. If the list is null, all tiles will be assumed valid. public void SyncWorldMapToLocalMap(List validLocalTerrainNames = null) { BoundsDouble bounds = new BoundsDouble(); TerrainHelper.GetTerrainBounds(ref bounds); if (GaiaUtils.HasDynamicLoadedTerrains()) { Action act = (t) => CopyWorldMapToLocalMap(bounds, t); GaiaUtils.CallFunctionOnDynamicLoadedTerrains(act, false, validLocalTerrainNames); } else { foreach (Terrain t in Terrain.activeTerrains) { if (t != m_worldMapTerrain) { if (validLocalTerrainNames == null || validLocalTerrainNames.Contains(t.name)) { CopyWorldMapToLocalMap(bounds, t); } } } } } public void SyncLocalMapToWorldMap() { BoundsDouble bounds = new BoundsDouble(); TerrainHelper.GetTerrainBounds(ref bounds); if (GaiaUtils.HasDynamicLoadedTerrains()) { Action act = (t) => CopyLocalMapToWorldMap(bounds, t); GaiaUtils.CallFunctionOnDynamicLoadedTerrains(act, false); } else { foreach (Terrain t in Terrain.activeTerrains) { if (t != m_worldMapTerrain) { CopyLocalMapToWorldMap(bounds, t); } } } } private void CopyWorldMapToLocalMap(BoundsDouble bounds, Terrain t) { //make sure we have a world map terrain first if (m_worldMapTerrain == null) { m_worldMapTerrain = TerrainHelper.GetWorldMapTerrain(); } if (m_worldMapTerrain == null) { Debug.LogError("Can't export world map to local terrains - world map terrain is missing!"); return; } RenderTexture chunkContent = RenderTexture.GetTemporary(t.terrainData.heightmapTexture.descriptor); //FilterMode oldFilterMode = m_worldMapTerrain.terrainData.heightmapTexture.filterMode; //m_worldMapTerrain.terrainData.heightmapTexture.filterMode = FilterMode.Trilinear; //t.terrainData.heightmapTexture.filterMode = FilterMode.Trilinear; //chunkContent.filterMode = FilterMode.Trilinear; int maxTilesX = Mathf.RoundToInt((float)bounds.size.x / t.terrainData.size.x); int maxTilesZ = Mathf.RoundToInt((float)bounds.size.z / t.terrainData.size.z); int currentTileX = Mathf.RoundToInt((t.transform.position.x - (float)bounds.min.x) / t.terrainData.size.x); int currentTileZ = Mathf.RoundToInt((t.transform.position.z - (float)bounds.min.z) / t.terrainData.size.z); float res = (t.terrainData.heightmapResolution) / ((float)bounds.size.x / t.terrainData.bounds.size.x * (t.terrainData.heightmapResolution-1)); Bounds worldSpaceBounds = t.terrainData.bounds; worldSpaceBounds.center = new Vector3(worldSpaceBounds.center.x + t.transform.position.x, worldSpaceBounds.center.y + t.transform.position.y, worldSpaceBounds.center.z + t.transform.position.z); float xPos = ((float)currentTileX * t.terrainData.heightmapResolution) / (maxTilesX * t.terrainData.heightmapResolution); float zPos = ((float)currentTileZ * t.terrainData.heightmapResolution) / (maxTilesZ * t.terrainData.heightmapResolution); Vector2 pos = new Vector2(xPos, zPos); Graphics.Blit(m_worldMapTerrain.terrainData.heightmapTexture, chunkContent, new Vector2(res, res), pos); //m_worldMapTerrain.terrainData.heightmapTexture.filterMode = oldFilterMode; RenderTexture previousRT = RenderTexture.active; RenderTexture.active = chunkContent; t.terrainData.CopyActiveRenderTextureToHeightmap(new RectInt(0, 0, t.terrainData.heightmapResolution, t.terrainData.heightmapResolution), new Vector2Int(0, 0), t.drawInstanced ? TerrainHeightmapSyncControl.None : TerrainHeightmapSyncControl.HeightOnly); RenderTexture.active = previousRT; t.terrainData.SyncHeightmap(); t.editorRenderFlags = TerrainRenderFlags.All; RenderTexture.ReleaseTemporary(chunkContent); //chunkContent = null; } private void CopyLocalMapToWorldMap(BoundsDouble bounds, Terrain t) { RenderTextureDescriptor rtDesc = t.terrainData.heightmapTexture.descriptor; rtDesc.width = Mathf.CeilToInt(m_worldMapTerrain.terrainData.heightmapResolution / ((float)bounds.size.x / t.terrainData.bounds.size.x)); rtDesc.height = rtDesc.width; RenderTexture chunkContent = RenderTexture.GetTemporary(rtDesc); float res = t.terrainData.heightmapResolution / rtDesc.width; Bounds worldSpaceBounds = t.terrainData.bounds; worldSpaceBounds.center = new Vector3(worldSpaceBounds.center.x + t.transform.position.x, worldSpaceBounds.center.y + t.transform.position.y, worldSpaceBounds.center.z + t.transform.position.z); Vector2 pos = new Vector2(Mathf.InverseLerp(0, (float)bounds.size.x, Mathf.Abs((float)bounds.min.x - worldSpaceBounds.min.x)), Mathf.InverseLerp(0, (float)bounds.size.z, Mathf.Abs((float)bounds.min.z - worldSpaceBounds.min.z))); Graphics.Blit(t.terrainData.heightmapTexture, chunkContent, new Vector2(1, 1), new Vector2(0, 0)); RenderTexture previousRT = RenderTexture.active; RenderTexture.active = chunkContent; m_worldMapTerrain.terrainData.CopyActiveRenderTextureToHeightmap(new RectInt(0, 0, rtDesc.width, rtDesc.height), new Vector2Int(Mathf.FloorToInt(pos.x * m_worldMapTerrain.terrainData.heightmapResolution), Mathf.FloorToInt(pos.y * m_worldMapTerrain.terrainData.heightmapResolution)), t.drawInstanced ? TerrainHeightmapSyncControl.None : TerrainHeightmapSyncControl.HeightOnly); RenderTexture.active = previousRT; m_worldMapTerrain.terrainData.SyncHeightmap(); m_worldMapTerrain.editorRenderFlags = TerrainRenderFlags.All; RenderTexture.ReleaseTemporary(chunkContent); //chunkContent = null; } public static void ShowWorldMapStampSpawner() { GaiaSessionManager gsm = GaiaSessionManager.GetSessionManager(false); //Get the Gaia Settings GaiaSettings settings = GaiaUtils.GetGaiaSettings(); //Create or find the stamper GameObject spawnerObj = GaiaUtils.GetOrCreateWorldDesigner(); Spawner spawner = spawnerObj.GetComponent(); if (spawner == null) { spawner = spawnerObj.AddComponent(); if (settings != null) { spawner.m_worldDesignerBiomePresetSelection = settings.m_biomePresetSelection; spawner.m_BiomeSpawnersToCreate = settings.m_BiomeSpawnersToCreate; if (settings.m_defaultStampSpawnSettings != null) { spawner.LoadSettings(settings.m_defaultStampSpawnSettings); } } spawner.m_showBoundingBox = false; spawner.m_settings.m_isWorldmapSpawner = true; //spawner.m_worldMapTerrain = worldMapTerrain; //set up the export settings with the current Gaia Settings / defaults spawner.m_worldCreationSettings.m_targetSizePreset = settings.m_targeSizePreset; spawner.m_worldCreationSettings.m_xTiles = settings.m_tilesX; spawner.m_worldCreationSettings.m_zTiles = settings.m_tilesZ; spawner.m_worldTileSize = GaiaUtils.IntToEnvironmentSize(settings.m_currentDefaults.m_terrainSize); spawner.m_worldCreationSettings.m_tileSize = settings.m_currentDefaults.m_terrainSize; spawner.m_worldCreationSettings.m_tileHeight = settings.m_currentDefaults.m_terrainHeight; spawner.m_worldCreationSettings.m_createInScene = settings.m_createTerrainScenes; spawner.m_worldCreationSettings.m_autoUnloadScenes = settings.m_unloadTerrainScenes; spawner.m_worldCreationSettings.m_applyFloatingPointFix = settings.m_floatingPointFix; spawner.m_worldCreationSettings.m_qualityPreset = settings.m_currentEnvironment; if (spawner.m_worldCreationSettings.m_gaiaDefaults == null) { spawner.m_worldCreationSettings.m_gaiaDefaults = settings.m_currentDefaults; } spawner.StoreWorldSize(); //spawner.StoreHeightmapResolution(); TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMapPreviewHeightmapResolution = spawner.m_worldCreationSettings.m_gaiaDefaults.m_heightmapResolution; TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMapPreviewRange = Mathf.RoundToInt(spawner.m_worldCreationSettings.m_xTiles * spawner.m_worldCreationSettings.m_tileSize); TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMapPreviewTerrainHeight = spawner.m_worldCreationSettings.m_tileHeight; //Check if we do have an existing terrain already, if yes, we would want to re-use it for the world map -> terrain export if (GaiaUtils.HasTerrains()) { spawner.m_useExistingTerrainForWorldMapExport = true; } else { //No terrains yet - set up the terrain tiles in the session according to the current world creation settings //so that the stamp previews will come out right. TerrainLoaderManager.Instance.TerrainSceneStorage.m_terrainTilesX = settings.m_tilesX; TerrainLoaderManager.Instance.TerrainSceneStorage.m_terrainTilesZ = settings.m_tilesZ; } //spawner.FitToTerrain(); spawner.UpdateMinMaxHeight(); } else { spawner.m_settings.m_isWorldmapSpawner = true; //spawner.m_worldMapTerrain = worldMapTerrain; //spawner.FitToTerrain(); spawner.UpdateMinMaxHeight(); } gsm.m_session.m_worldBiomeMaskSettings = spawner.m_settings; #if UNITY_EDITOR spawner.SetRecommendedStampSizes(false); spawner.FocusSceneViewOnWorldDesignerPreview(); //For the pre-defined sizes we can do a spawn right away so the terrain is populated if (spawner.m_worldCreationSettings.m_targetSizePreset != GaiaConstants.EnvironmentSizePreset.Custom) { spawner.SpawnStamps(); } else { spawner.SetDefaultWorldDesignerPreviewSettings(); } spawner.StoreWorldSize(); #endif } public static GameObject GetOrCreateWorldMapStamper() { //Create or find the stamper GameObject stamperObj = GameObject.Find(GaiaConstants.worldMapStamper); if (stamperObj == null) { stamperObj = new GameObject(GaiaConstants.worldMapStamper); GameObject worldMapObj = GaiaUtils.GetOrCreateWorldDesigner(); stamperObj.transform.parent = worldMapObj.transform; Stamper stamper = stamperObj.AddComponent(); stamper.m_settings = ScriptableObject.CreateInstance(); stamper.m_settings.m_operation = GaiaConstants.FeatureOperation.RaiseHeight; stamper.m_settings.m_isWorldmapStamper = true; stamper.m_recordUndo = false; //stamper.m_seaLevel = m_settings.m_currentDefaults.m_seaLevel; stamper.FitToTerrain(); } else { Stamper stamper = stamperObj.GetComponent(); stamper.m_settings.m_isWorldmapStamper = true; stamper.m_recordUndo = false; //stamper.m_seaLevel = m_settings.m_currentDefaults.m_seaLevel; stamper.FitToTerrain(); } Terrain worldMapTerrain = TerrainHelper.GetWorldMapTerrain(); if (worldMapTerrain != null) { stamperObj.transform.position = worldMapTerrain.transform.position + worldMapTerrain.terrainData.size / 2f; } return stamperObj; } } }