1058 lines
31 KiB
C#
1058 lines
31 KiB
C#
using System;
|
|
using System.Collections;
|
|
using Gaia.FullSerializer;
|
|
using UnityEngine;
|
|
|
|
namespace Gaia
|
|
{
|
|
[ExecuteInEditMode]
|
|
public class Stamper : MonoBehaviour
|
|
{
|
|
public string m_stampID = Guid.NewGuid().ToString();
|
|
|
|
public Texture2D m_stampPreviewImage;
|
|
|
|
public float m_x;
|
|
|
|
public float m_y = 50f;
|
|
|
|
public float m_z;
|
|
|
|
public float m_width = 10f;
|
|
|
|
public float m_height = 10f;
|
|
|
|
public float m_rotation;
|
|
|
|
public bool m_stickBaseToGround = true;
|
|
|
|
[fsIgnore]
|
|
public GaiaResource m_resources;
|
|
|
|
[fsIgnore]
|
|
public float m_seaLevel;
|
|
|
|
public string m_resourcesPath;
|
|
|
|
public bool m_invertStamp;
|
|
|
|
public bool m_normaliseStamp;
|
|
|
|
public float m_baseLevel;
|
|
|
|
public bool m_drawStampBase = true;
|
|
|
|
public GaiaConstants.FeatureOperation m_stampOperation;
|
|
|
|
public int m_smoothIterations;
|
|
|
|
public float m_blendStrength = 0.5f;
|
|
|
|
public float m_stencilHeight = 1f;
|
|
|
|
public AnimationCurve m_heightModifier = AnimationCurve.Linear(0f, 0f, 1f, 1f);
|
|
|
|
public AnimationCurve m_distanceMask = new AnimationCurve(new Keyframe(0f, 1f), new Keyframe(1f, 1f));
|
|
|
|
public GaiaConstants.ImageFitnessFilterMode m_areaMaskMode;
|
|
|
|
public Texture2D m_imageMask;
|
|
|
|
public bool m_imageMaskInvert;
|
|
|
|
public bool m_imageMaskNormalise;
|
|
|
|
public bool m_imageMaskFlip;
|
|
|
|
public int m_imageMaskSmoothIterations = 3;
|
|
|
|
[fsIgnore]
|
|
public HeightMap m_imageMaskHM;
|
|
|
|
public float m_noiseMaskSeed;
|
|
|
|
public int m_noiseMaskOctaves = 8;
|
|
|
|
public float m_noiseMaskPersistence = 0.25f;
|
|
|
|
public float m_noiseMaskFrequency = 1f;
|
|
|
|
public float m_noiseMaskLacunarity = 1.5f;
|
|
|
|
public float m_noiseZoom = 10f;
|
|
|
|
public bool m_alwaysShow;
|
|
|
|
public bool m_showBase = true;
|
|
|
|
public bool m_showSeaLevel = true;
|
|
|
|
public bool m_showRulers;
|
|
|
|
public bool m_showTerrainHelper;
|
|
|
|
[fsIgnore]
|
|
public Color m_gizmoColour = new Color(1f, 0.6f, 0f, 1f);
|
|
|
|
[fsIgnore]
|
|
public IEnumerator m_updateCoroutine;
|
|
|
|
[fsIgnore]
|
|
public float m_updateTimeAllowed = 1f / 30f;
|
|
|
|
[fsIgnore]
|
|
public float m_stampProgress;
|
|
|
|
[fsIgnore]
|
|
public bool m_stampComplete = true;
|
|
|
|
[fsIgnore]
|
|
public bool m_cancelStamp;
|
|
|
|
[fsIgnore]
|
|
public Material m_previewMaterial;
|
|
|
|
private int m_featureID;
|
|
|
|
private int m_scanWidth;
|
|
|
|
private int m_scanDepth;
|
|
|
|
private int m_scanHeight;
|
|
|
|
private float m_scanResolution = 0.1f;
|
|
|
|
private Bounds m_scanBounds;
|
|
|
|
private UnityHeightMap m_stampHM;
|
|
|
|
private GaiaWorldManager m_undoMgr;
|
|
|
|
private GaiaWorldManager m_redoMgr;
|
|
|
|
private MeshFilter m_previewFilter;
|
|
|
|
private MeshRenderer m_previewRenderer;
|
|
|
|
public void LoadStamp()
|
|
{
|
|
m_featureID = -1;
|
|
m_scanBounds = new Bounds(base.transform.position, Vector3.one * 10f);
|
|
if (m_stampPreviewImage == null)
|
|
{
|
|
Debug.LogWarning("Can't load feature - texture not set");
|
|
return;
|
|
}
|
|
m_featureID = m_stampPreviewImage.GetInstanceID();
|
|
if (!GaiaUtils.CheckValidGaiaStampPath(m_stampPreviewImage))
|
|
{
|
|
Debug.LogError("The file provided is not a valid stamp. You need to drag the stamp preview from one of the directories underneath your Gaia Stamps directory.");
|
|
m_featureID = -1;
|
|
m_stampPreviewImage = null;
|
|
return;
|
|
}
|
|
string gaiaStampPath = GaiaUtils.GetGaiaStampPath(m_stampPreviewImage);
|
|
m_stampHM = new UnityHeightMap(gaiaStampPath);
|
|
if (!m_stampHM.HasData())
|
|
{
|
|
m_featureID = -1;
|
|
m_stampPreviewImage = null;
|
|
Debug.LogError("Was unable to load " + gaiaStampPath);
|
|
return;
|
|
}
|
|
float[] array = new float[5];
|
|
Buffer.BlockCopy(m_stampHM.GetMetaData(), 0, array, 0, array.Length * 4);
|
|
m_scanWidth = (int)array[0];
|
|
m_scanDepth = (int)array[1];
|
|
m_scanHeight = (int)array[2];
|
|
m_scanResolution = array[3];
|
|
m_baseLevel = array[4];
|
|
m_scanBounds = new Bounds(base.transform.position, new Vector3((float)m_scanWidth * m_scanResolution * m_width, (float)m_scanHeight * m_scanResolution * m_height, (float)m_scanDepth * m_scanResolution * m_width));
|
|
if (m_invertStamp)
|
|
{
|
|
m_stampHM.Invert();
|
|
}
|
|
if (m_normaliseStamp)
|
|
{
|
|
m_stampHM.Normalise();
|
|
}
|
|
GeneratePreviewMesh();
|
|
}
|
|
|
|
public void LoadStamp(string imagePreviewPath)
|
|
{
|
|
LoadStamp();
|
|
}
|
|
|
|
public bool LoadRuntimeStamp(TextAsset stamp)
|
|
{
|
|
m_stampHM = new UnityHeightMap(stamp);
|
|
if (!m_stampHM.HasData())
|
|
{
|
|
m_featureID = -1;
|
|
m_stampPreviewImage = null;
|
|
Debug.LogError("Was unable to load textasset stamp");
|
|
return false;
|
|
}
|
|
float[] array = new float[5];
|
|
Buffer.BlockCopy(m_stampHM.GetMetaData(), 0, array, 0, array.Length * 4);
|
|
m_scanWidth = (int)array[0];
|
|
m_scanDepth = (int)array[1];
|
|
m_scanHeight = (int)array[2];
|
|
m_scanResolution = array[3];
|
|
m_baseLevel = array[4];
|
|
m_scanBounds = new Bounds(base.transform.position, new Vector3((float)m_scanWidth * m_scanResolution * m_width, (float)m_scanHeight * m_scanResolution * m_height, (float)m_scanDepth * m_scanResolution * m_width));
|
|
if (m_invertStamp)
|
|
{
|
|
m_stampHM.Invert();
|
|
}
|
|
if (m_normaliseStamp)
|
|
{
|
|
m_stampHM.Normalise();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void InvertStamp()
|
|
{
|
|
m_stampHM.Invert();
|
|
GeneratePreviewMesh();
|
|
}
|
|
|
|
public void NormaliseStamp()
|
|
{
|
|
m_stampHM.Normalise();
|
|
GeneratePreviewMesh();
|
|
}
|
|
|
|
public void Stamp()
|
|
{
|
|
m_cancelStamp = false;
|
|
m_stampComplete = false;
|
|
m_stampProgress = 0f;
|
|
AddToSession(GaiaOperation.OperationType.Stamp, "Stamping " + m_stampPreviewImage.name);
|
|
StartCoroutine(ApplyStamp());
|
|
}
|
|
|
|
public void CancelStamp()
|
|
{
|
|
m_cancelStamp = true;
|
|
}
|
|
|
|
public bool IsStamping()
|
|
{
|
|
return !m_stampComplete;
|
|
}
|
|
|
|
public void UpdateStamp()
|
|
{
|
|
if (m_stickBaseToGround)
|
|
{
|
|
AlignToGround();
|
|
}
|
|
base.transform.position = new Vector3(m_x, m_y, m_z);
|
|
base.transform.localScale = new Vector3(m_width, m_height, m_width);
|
|
base.transform.localRotation = Quaternion.AngleAxis(m_rotation, Vector3.up);
|
|
m_scanBounds.center = base.transform.position;
|
|
m_scanBounds.size = new Vector3((float)m_scanWidth * m_scanResolution * m_width, (float)m_scanHeight * m_scanResolution * m_height, (float)m_scanDepth * m_scanResolution * m_width);
|
|
if (m_stampHM != null)
|
|
{
|
|
m_stampHM.SetBoundsWU(m_scanBounds);
|
|
}
|
|
base.transform.hasChanged = false;
|
|
}
|
|
|
|
public void AlignToGround()
|
|
{
|
|
if (m_stampHM != null && m_stampHM.HasData())
|
|
{
|
|
float num = 0f;
|
|
Terrain terrain = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain == null)
|
|
{
|
|
terrain = Terrain.activeTerrain;
|
|
}
|
|
if (terrain != null)
|
|
{
|
|
num = terrain.transform.position.y;
|
|
}
|
|
m_scanBounds.center = base.transform.position;
|
|
m_scanBounds.size = new Vector3((float)m_scanWidth * m_scanResolution * m_width, (float)m_scanHeight * m_scanResolution * m_height, (float)m_scanDepth * m_scanResolution * m_width);
|
|
if (terrain == null)
|
|
{
|
|
m_y = num + m_scanBounds.extents.y;
|
|
return;
|
|
}
|
|
float num2 = m_scanBounds.min.y + m_scanBounds.size.y * m_baseLevel;
|
|
m_y = m_scanBounds.center.y - (num2 - num);
|
|
}
|
|
}
|
|
|
|
public bool GetHeightRange(ref float baseLevel, ref float minHeight, ref float maxHeight)
|
|
{
|
|
if (m_stampHM == null || !m_stampHM.HasData())
|
|
{
|
|
return false;
|
|
}
|
|
baseLevel = m_baseLevel;
|
|
m_stampHM.GetHeightRange(ref minHeight, ref maxHeight);
|
|
return true;
|
|
}
|
|
|
|
public void FitToTerrain()
|
|
{
|
|
Terrain terrain = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain == null)
|
|
{
|
|
terrain = TerrainHelper.GetActiveTerrain();
|
|
}
|
|
if (terrain == null)
|
|
{
|
|
return;
|
|
}
|
|
Bounds bounds = default(Bounds);
|
|
if (TerrainHelper.GetTerrainBounds(terrain, ref bounds))
|
|
{
|
|
m_height = bounds.size.y / 100f * 2f;
|
|
if (m_stampHM != null && m_stampHM.HasData())
|
|
{
|
|
m_width = bounds.size.x / (float)m_stampHM.Width() * 10f;
|
|
}
|
|
else
|
|
{
|
|
m_width = m_height;
|
|
}
|
|
m_height *= 0.25f;
|
|
m_x = bounds.center.x;
|
|
m_y = bounds.center.y;
|
|
m_z = bounds.center.z;
|
|
m_rotation = 0f;
|
|
}
|
|
if (m_stickBaseToGround)
|
|
{
|
|
AlignToGround();
|
|
}
|
|
}
|
|
|
|
public bool IsFitToTerrain()
|
|
{
|
|
Terrain terrain = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain == null)
|
|
{
|
|
terrain = Terrain.activeTerrain;
|
|
}
|
|
if (terrain == null || m_stampHM == null || !m_stampHM.HasData())
|
|
{
|
|
Debug.LogError("Could not check if fit to terrain - no terrain present");
|
|
return false;
|
|
}
|
|
Bounds bounds = default(Bounds);
|
|
if (TerrainHelper.GetTerrainBounds(terrain, ref bounds))
|
|
{
|
|
float num = bounds.size.x / (float)m_stampHM.Width() * 10f;
|
|
float x = bounds.center.x;
|
|
float z = bounds.center.z;
|
|
float num2 = 0f;
|
|
if (num != m_width || x != m_x || z != m_z || num2 != m_rotation)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void AddToSession(GaiaOperation.OperationType opType, string opName)
|
|
{
|
|
GaiaSessionManager sessionManager = GaiaSessionManager.GetSessionManager();
|
|
if (sessionManager != null && !sessionManager.IsLocked())
|
|
{
|
|
GaiaOperation gaiaOperation = new GaiaOperation();
|
|
gaiaOperation.m_description = opName;
|
|
gaiaOperation.m_generatedByID = m_stampID;
|
|
gaiaOperation.m_generatedByName = base.transform.name;
|
|
gaiaOperation.m_generatedByType = GetType().ToString();
|
|
gaiaOperation.m_isActive = true;
|
|
gaiaOperation.m_operationDateTime = DateTime.Now.ToString();
|
|
gaiaOperation.m_operationType = opType;
|
|
if (opType == GaiaOperation.OperationType.Stamp)
|
|
{
|
|
gaiaOperation.m_operationDataJson = new string[1];
|
|
gaiaOperation.m_operationDataJson[0] = SerialiseJson();
|
|
}
|
|
else
|
|
{
|
|
gaiaOperation.m_operationDataJson = new string[0];
|
|
}
|
|
sessionManager.AddOperation(gaiaOperation);
|
|
}
|
|
}
|
|
|
|
public string SerialiseJson()
|
|
{
|
|
new fsSerializer().TrySerialize(this, out var data);
|
|
return fsJsonPrinter.CompressedJson(data);
|
|
}
|
|
|
|
public void DeSerialiseJson(string json)
|
|
{
|
|
fsData data = fsJsonParser.Parse(json);
|
|
fsSerializer obj = new fsSerializer();
|
|
Stamper instance = this;
|
|
obj.TryDeserialize(data, ref instance);
|
|
instance.LoadStamp();
|
|
instance.UpdateStamp();
|
|
}
|
|
|
|
public void FlattenTerrain()
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.FlattenTerrain, "Flattening terrain");
|
|
m_undoMgr = new GaiaWorldManager(Terrain.activeTerrains);
|
|
m_undoMgr.LoadFromWorld();
|
|
m_redoMgr = new GaiaWorldManager(Terrain.activeTerrains);
|
|
m_redoMgr.FlattenWorld();
|
|
m_redoMgr = null;
|
|
}
|
|
|
|
public void SmoothTerrain()
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.SmoothTerrain, "Smoothing terrain");
|
|
m_undoMgr = new GaiaWorldManager(Terrain.activeTerrains);
|
|
m_undoMgr.LoadFromWorld();
|
|
m_redoMgr = new GaiaWorldManager(Terrain.activeTerrains);
|
|
m_redoMgr.SmoothWorld();
|
|
m_redoMgr = null;
|
|
}
|
|
|
|
public void ClearTrees()
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.ClearTrees, "Clearing terrain trees");
|
|
TerrainHelper.ClearTrees();
|
|
}
|
|
|
|
public void ClearDetails()
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.ClearDetails, "Clearing terrain details");
|
|
TerrainHelper.ClearDetails();
|
|
}
|
|
|
|
public bool CanPreview()
|
|
{
|
|
return m_previewRenderer != null;
|
|
}
|
|
|
|
public bool CurrentPreviewState()
|
|
{
|
|
if (m_previewRenderer != null)
|
|
{
|
|
return m_previewRenderer.enabled;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void ShowPreview()
|
|
{
|
|
if (m_previewRenderer != null)
|
|
{
|
|
m_previewRenderer.enabled = true;
|
|
}
|
|
}
|
|
|
|
public void HidePreview()
|
|
{
|
|
if (m_previewRenderer != null)
|
|
{
|
|
m_previewRenderer.enabled = false;
|
|
}
|
|
}
|
|
|
|
public void TogglePreview()
|
|
{
|
|
if (m_previewRenderer != null)
|
|
{
|
|
m_previewRenderer.enabled = !m_previewRenderer.enabled;
|
|
}
|
|
}
|
|
|
|
public bool CanUndo()
|
|
{
|
|
if (m_undoMgr == null)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void CreateUndo()
|
|
{
|
|
m_undoMgr = new GaiaWorldManager(Terrain.activeTerrains);
|
|
m_undoMgr.LoadFromWorld();
|
|
m_redoMgr = null;
|
|
}
|
|
|
|
public void Undo()
|
|
{
|
|
if (m_undoMgr != null)
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.StampUndo, "Undoing stamp");
|
|
m_redoMgr = new GaiaWorldManager(Terrain.activeTerrains);
|
|
m_redoMgr.LoadFromWorld();
|
|
m_undoMgr.SaveToWorld(forceWrite: true);
|
|
}
|
|
}
|
|
|
|
public bool CanRedo()
|
|
{
|
|
if (m_redoMgr == null)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void Redo()
|
|
{
|
|
if (m_redoMgr != null)
|
|
{
|
|
AddToSession(GaiaOperation.OperationType.StampRedo, "Redoing stamp");
|
|
m_redoMgr.SaveToWorld(forceWrite: true);
|
|
m_redoMgr = null;
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (m_stampPreviewImage != null)
|
|
{
|
|
LoadStamp();
|
|
}
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
if (Application.isPlaying)
|
|
{
|
|
HidePreview();
|
|
}
|
|
}
|
|
|
|
public void StartEditorUpdates()
|
|
{
|
|
}
|
|
|
|
public void StopEditorUpdates()
|
|
{
|
|
}
|
|
|
|
private void EditorUpdate()
|
|
{
|
|
}
|
|
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
DrawGizmos(isSelected: true);
|
|
}
|
|
|
|
private void OnDrawGizmos()
|
|
{
|
|
DrawGizmos(isSelected: false);
|
|
}
|
|
|
|
private void DrawGizmos(bool isSelected)
|
|
{
|
|
if (m_stampPreviewImage == null)
|
|
{
|
|
return;
|
|
}
|
|
if (base.transform.hasChanged)
|
|
{
|
|
m_x = base.transform.position.x;
|
|
m_y = base.transform.position.y;
|
|
m_z = base.transform.position.z;
|
|
m_rotation = base.transform.localEulerAngles.y;
|
|
if (base.transform.localScale.x != m_width || base.transform.localScale.z != m_width)
|
|
{
|
|
float num = Mathf.Abs(base.transform.localScale.x - m_width);
|
|
float num2 = Mathf.Abs(base.transform.localScale.z - m_width);
|
|
if (num > num2)
|
|
{
|
|
if (base.transform.localScale.x > 0f)
|
|
{
|
|
m_width = base.transform.localScale.x;
|
|
}
|
|
}
|
|
else if (base.transform.localScale.z > 0f)
|
|
{
|
|
m_width = base.transform.localScale.z;
|
|
}
|
|
}
|
|
if (base.transform.localScale.y != m_height && base.transform.localScale.y > 0f)
|
|
{
|
|
m_height = base.transform.localScale.y;
|
|
}
|
|
UpdateStamp();
|
|
}
|
|
if (!isSelected && !m_alwaysShow)
|
|
{
|
|
return;
|
|
}
|
|
if (m_showBase)
|
|
{
|
|
Bounds bounds = default(Bounds);
|
|
if (TerrainHelper.GetTerrainBounds(base.transform.position, ref bounds))
|
|
{
|
|
bounds.center = new Vector3(bounds.center.x, m_scanBounds.min.y + m_scanBounds.size.y * m_baseLevel, bounds.center.z);
|
|
bounds.size = new Vector3(bounds.size.x, 0.05f, bounds.size.z);
|
|
Gizmos.color = new Color(Color.yellow.r, Color.yellow.g, Color.yellow.b, Color.yellow.a / 2f);
|
|
Gizmos.DrawCube(bounds.center, bounds.size);
|
|
}
|
|
}
|
|
if (m_resources != null)
|
|
{
|
|
m_seaLevel = m_resources.m_seaLevel;
|
|
}
|
|
if (m_showSeaLevel)
|
|
{
|
|
Bounds bounds2 = default(Bounds);
|
|
if (TerrainHelper.GetTerrainBounds(base.transform.position, ref bounds2))
|
|
{
|
|
bounds2.center = new Vector3(bounds2.center.x, m_seaLevel, bounds2.center.z);
|
|
bounds2.size = new Vector3(bounds2.size.x, 0.05f, bounds2.size.z);
|
|
if (isSelected)
|
|
{
|
|
Gizmos.color = new Color(Color.blue.r, Color.blue.g, Color.blue.b, Color.blue.a / 2f);
|
|
Gizmos.DrawCube(bounds2.center, bounds2.size);
|
|
}
|
|
else
|
|
{
|
|
Gizmos.color = new Color(Color.blue.r, Color.blue.g, Color.blue.b, Color.blue.a / 4f);
|
|
Gizmos.DrawCube(bounds2.center, bounds2.size);
|
|
}
|
|
}
|
|
}
|
|
if (m_showRulers)
|
|
{
|
|
DrawRulers();
|
|
}
|
|
Matrix4x4 matrix = Gizmos.matrix;
|
|
Gizmos.matrix = base.transform.localToWorldMatrix;
|
|
Vector3 size = new Vector3((float)m_scanWidth * m_scanResolution, (float)m_scanHeight * m_scanResolution, (float)m_scanDepth * m_scanResolution);
|
|
Gizmos.color = new Color(m_gizmoColour.r, m_gizmoColour.g, m_gizmoColour.b, m_gizmoColour.a / 2f);
|
|
Gizmos.DrawWireCube(Vector3.zero, size);
|
|
Gizmos.matrix = matrix;
|
|
Terrain terrain = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain != null)
|
|
{
|
|
Gizmos.color = Color.white;
|
|
Bounds bounds3 = default(Bounds);
|
|
TerrainHelper.GetTerrainBounds(terrain, ref bounds3);
|
|
Gizmos.DrawWireCube(bounds3.center, bounds3.size);
|
|
}
|
|
}
|
|
|
|
private void DrawRulers()
|
|
{
|
|
}
|
|
|
|
public IEnumerator ApplyStamp()
|
|
{
|
|
UpdateStamp();
|
|
GaiaWorldManager mgr = new GaiaWorldManager(Terrain.activeTerrains);
|
|
mgr.LoadFromWorld();
|
|
if (mgr.TileCount == 0)
|
|
{
|
|
Debug.LogError("Can not stamp without a terrain present!");
|
|
m_stampProgress = 0f;
|
|
m_stampComplete = true;
|
|
m_updateCoroutine = null;
|
|
yield break;
|
|
}
|
|
CreateUndo();
|
|
if (m_areaMaskMode != GaiaConstants.ImageFitnessFilterMode.None && !LoadImageMask())
|
|
{
|
|
m_stampProgress = 0f;
|
|
m_stampComplete = true;
|
|
m_updateCoroutine = null;
|
|
yield break;
|
|
}
|
|
Vector3 angle = new Vector3(0f, base.transform.localRotation.eulerAngles.y, 0f);
|
|
Bounds boundsWU = m_stampHM.GetBoundsWU();
|
|
Bounds bounds = default(Bounds);
|
|
bounds.center = boundsWU.center;
|
|
bounds.Encapsulate(RotatePointAroundPivot(new Vector3(boundsWU.min.x, boundsWU.center.y, boundsWU.min.z), boundsWU.center, angle));
|
|
bounds.Encapsulate(RotatePointAroundPivot(new Vector3(boundsWU.min.x, boundsWU.center.y, boundsWU.max.z), boundsWU.center, angle));
|
|
bounds.Encapsulate(RotatePointAroundPivot(new Vector3(boundsWU.max.x, boundsWU.center.y, boundsWU.min.z), boundsWU.center, angle));
|
|
bounds.Encapsulate(RotatePointAroundPivot(new Vector3(boundsWU.max.x, boundsWU.center.y, boundsWU.max.z), boundsWU.center, angle));
|
|
Vector3 vector = mgr.Ceil(mgr.WUtoTU(bounds.size));
|
|
Vector3 pivot = new Vector3(0.5f, 0f, 0.5f);
|
|
int newSmMaxX = (int)vector.x;
|
|
int newSmMaxZ = (int)vector.z;
|
|
float newSmXtoNU = 1f / vector.x;
|
|
float newSmZtoNU = 1f / vector.z;
|
|
float xNewSMtoOrigSMScale = bounds.size.x / boundsWU.size.x;
|
|
float zNewSMtoOrigSMScale = bounds.size.x / boundsWU.size.z;
|
|
float scaleOffsetX = 0.5f * ((boundsWU.size.x - bounds.size.x) / boundsWU.size.x);
|
|
float scaleOffsetZ = 0.5f * ((boundsWU.size.z - bounds.size.x) / boundsWU.size.z);
|
|
float currentTime = Time.realtimeSinceStartup;
|
|
float accumulatedTime = 0f;
|
|
int currChecks = 0;
|
|
int totalChecks = newSmMaxX * newSmMaxZ;
|
|
Vector3 vector2 = mgr.WUtoTU(base.transform.position);
|
|
Vector3 globalOffsetTU = vector2 - vector * 0.5f;
|
|
Vector3 globalPositionTU = Vector3.one;
|
|
globalPositionTU.y = vector2.y;
|
|
float smToOrigHeightConversion = boundsWU.size.y / mgr.WorldBoundsWU.size.y;
|
|
float smHeightOffset = (boundsWU.min.y - mgr.WorldBoundsWU.min.y) / mgr.WorldBoundsWU.size.y;
|
|
float stencilHeightNU = m_stencilHeight / mgr.WorldBoundsWU.size.y;
|
|
double rotationCosTheta = Math.Cos(Math.PI / 180.0 * (double)angle.y);
|
|
double rotationSinTheta = Math.Sin(Math.PI / 180.0 * (double)angle.y);
|
|
RotationProducts xRotationProducts = new RotationProducts();
|
|
RotationProducts[] zRotationProductCache = new RotationProducts[newSmMaxZ];
|
|
Vector3 vector3 = default(Vector3);
|
|
for (int x = 0; x < newSmMaxX; x++)
|
|
{
|
|
float num = (float)x * newSmXtoNU - pivot.x;
|
|
xRotationProducts.sinTheta = (double)num * rotationSinTheta;
|
|
xRotationProducts.cosTheta = (double)num * rotationCosTheta;
|
|
for (int z = 0; z < newSmMaxZ; z++)
|
|
{
|
|
m_stampProgress = (float)currChecks++ / (float)totalChecks;
|
|
float realtimeSinceStartup = Time.realtimeSinceStartup;
|
|
float num2 = realtimeSinceStartup - currentTime;
|
|
currentTime = realtimeSinceStartup;
|
|
accumulatedTime += num2;
|
|
if (accumulatedTime > m_updateTimeAllowed)
|
|
{
|
|
accumulatedTime = 0f;
|
|
yield return null;
|
|
}
|
|
if (m_cancelStamp)
|
|
{
|
|
break;
|
|
}
|
|
globalPositionTU.x = (float)z + globalOffsetTU.z;
|
|
globalPositionTU.z = (float)x + globalOffsetTU.x;
|
|
if (!mgr.InBoundsTU(globalPositionTU))
|
|
{
|
|
continue;
|
|
}
|
|
if (zRotationProductCache[z] == null)
|
|
{
|
|
float num3 = (float)z * newSmZtoNU - pivot.z;
|
|
zRotationProductCache[z] = new RotationProducts
|
|
{
|
|
sinTheta = (double)num3 * rotationSinTheta,
|
|
cosTheta = (double)num3 * rotationCosTheta
|
|
};
|
|
}
|
|
vector3.x = (float)(xRotationProducts.cosTheta - zRotationProductCache[z].sinTheta + (double)pivot.x);
|
|
vector3.z = (float)(xRotationProducts.sinTheta + zRotationProductCache[z].cosTheta + (double)pivot.z);
|
|
float num4 = vector3.x * xNewSMtoOrigSMScale + scaleOffsetX;
|
|
float num5 = vector3.z * zNewSMtoOrigSMScale + scaleOffsetZ;
|
|
if (!(num4 < 0f) && !(num4 > 1f) && !(num5 < 0f) && !(num5 > 1f))
|
|
{
|
|
float time = GaiaUtils.Math_Distance(num4, num5, pivot.x, pivot.z) * 2f;
|
|
float num6 = m_distanceMask.Evaluate(time);
|
|
if (m_areaMaskMode != GaiaConstants.ImageFitnessFilterMode.None && m_imageMaskHM != null)
|
|
{
|
|
num6 *= m_imageMaskHM[num4, num5];
|
|
}
|
|
float num7 = m_heightModifier.Evaluate(m_stampHM[num4, num5]);
|
|
float smHeightAdj = ((m_stampOperation == GaiaConstants.FeatureOperation.StencilHeight) ? num7 : (smHeightOffset + num7 * smToOrigHeightConversion));
|
|
float heightTU = mgr.GetHeightTU(globalPositionTU);
|
|
float value = CalculateHeight(heightTU, num7, smHeightAdj, stencilHeightNU, num6);
|
|
mgr.SetHeightTU(globalPositionTU, Mathf.Clamp01(value));
|
|
}
|
|
}
|
|
}
|
|
if (!m_cancelStamp)
|
|
{
|
|
mgr.SaveToWorld();
|
|
}
|
|
else
|
|
{
|
|
m_undoMgr = null;
|
|
m_redoMgr = null;
|
|
}
|
|
m_stampProgress = 0f;
|
|
m_stampComplete = true;
|
|
m_updateCoroutine = null;
|
|
}
|
|
|
|
private void GeneratePreviewMesh()
|
|
{
|
|
if (m_previewMaterial == null)
|
|
{
|
|
m_previewMaterial = new Material(Shader.Find("Diffuse"));
|
|
m_previewMaterial.color = Color.white;
|
|
if (Terrain.activeTerrain != null)
|
|
{
|
|
GaiaSplatPrototype[] gaiaSplatPrototypes = GaiaSplatPrototype.GetGaiaSplatPrototypes(Terrain.activeTerrain);
|
|
if (gaiaSplatPrototypes.Length != 0)
|
|
{
|
|
Texture2D texture2D = ((gaiaSplatPrototypes.Length != 4) ? gaiaSplatPrototypes[0].texture : gaiaSplatPrototypes[3].texture);
|
|
GaiaUtils.MakeTextureReadable(texture2D);
|
|
Texture2D texture2D2 = new Texture2D(texture2D.width, texture2D.height, TextureFormat.ARGB32, mipChain: true);
|
|
texture2D2.SetPixels32(texture2D.GetPixels32());
|
|
texture2D2.wrapMode = TextureWrapMode.Repeat;
|
|
texture2D2.Apply();
|
|
m_previewMaterial.mainTexture = texture2D2;
|
|
m_previewMaterial.mainTextureScale = new Vector2(30f, 30f);
|
|
}
|
|
}
|
|
m_previewMaterial.hideFlags = HideFlags.HideInInspector;
|
|
m_previewMaterial.name = "StamperMaterial";
|
|
}
|
|
m_previewFilter = GetComponent<MeshFilter>();
|
|
if (m_previewFilter == null)
|
|
{
|
|
base.gameObject.AddComponent<MeshFilter>();
|
|
m_previewFilter = GetComponent<MeshFilter>();
|
|
m_previewFilter.hideFlags = HideFlags.HideInInspector;
|
|
}
|
|
m_previewRenderer = GetComponent<MeshRenderer>();
|
|
if (m_previewRenderer == null)
|
|
{
|
|
base.gameObject.AddComponent<MeshRenderer>();
|
|
m_previewRenderer = GetComponent<MeshRenderer>();
|
|
m_previewRenderer.hideFlags = HideFlags.HideInInspector;
|
|
}
|
|
m_previewRenderer.sharedMaterial = m_previewMaterial;
|
|
Vector3 targetSize = new Vector3((float)m_scanWidth * m_scanResolution, (float)m_scanHeight * m_scanResolution, (float)m_scanDepth * m_scanResolution);
|
|
m_previewFilter.mesh = GaiaUtils.CreateMesh(m_stampHM.Heights(), targetSize);
|
|
}
|
|
|
|
private bool LoadImageMask()
|
|
{
|
|
m_imageMaskHM = null;
|
|
if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.None)
|
|
{
|
|
return false;
|
|
}
|
|
if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.ImageRedChannel || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.ImageGreenChannel || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.ImageBlueChannel || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.ImageAlphaChannel || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.ImageGreyScale)
|
|
{
|
|
if (m_imageMask == null)
|
|
{
|
|
Debug.LogError("You requested an image mask but did not supply one. Please select mask texture.");
|
|
return false;
|
|
}
|
|
GaiaUtils.MakeTextureReadable(m_imageMask);
|
|
GaiaUtils.MakeTextureUncompressed(m_imageMask);
|
|
m_imageMaskHM = new HeightMap(m_imageMask.width, m_imageMask.height);
|
|
for (int i = 0; i < m_imageMaskHM.Width(); i++)
|
|
{
|
|
for (int j = 0; j < m_imageMaskHM.Depth(); j++)
|
|
{
|
|
switch (m_areaMaskMode)
|
|
{
|
|
case GaiaConstants.ImageFitnessFilterMode.ImageGreyScale:
|
|
m_imageMaskHM[i, j] = m_imageMask.GetPixel(i, j).grayscale;
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.ImageRedChannel:
|
|
m_imageMaskHM[i, j] = m_imageMask.GetPixel(i, j).r;
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.ImageGreenChannel:
|
|
m_imageMaskHM[i, j] = m_imageMask.GetPixel(i, j).g;
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.ImageBlueChannel:
|
|
m_imageMaskHM[i, j] = m_imageMask.GetPixel(i, j).b;
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.ImageAlphaChannel:
|
|
m_imageMaskHM[i, j] = m_imageMask.GetPixel(i, j).a;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.PerlinNoise || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.RidgedNoise || m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.BillowNoise)
|
|
{
|
|
int num = 2048;
|
|
int num2 = 2048;
|
|
Terrain terrain = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain == null)
|
|
{
|
|
terrain = Terrain.activeTerrain;
|
|
}
|
|
if (terrain != null)
|
|
{
|
|
num = terrain.terrainData.heightmapResolution;
|
|
num2 = terrain.terrainData.heightmapResolution;
|
|
}
|
|
m_imageMaskHM = new HeightMap(num, num2);
|
|
FractalGenerator fractalGenerator = new FractalGenerator();
|
|
fractalGenerator.Seed = m_noiseMaskSeed;
|
|
fractalGenerator.Octaves = m_noiseMaskOctaves;
|
|
fractalGenerator.Persistence = m_noiseMaskPersistence;
|
|
fractalGenerator.Frequency = m_noiseMaskFrequency;
|
|
fractalGenerator.Lacunarity = m_noiseMaskLacunarity;
|
|
if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.PerlinNoise)
|
|
{
|
|
fractalGenerator.FractalType = FractalGenerator.Fractals.Perlin;
|
|
}
|
|
else if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.RidgedNoise)
|
|
{
|
|
fractalGenerator.FractalType = FractalGenerator.Fractals.RidgeMulti;
|
|
}
|
|
else if (m_areaMaskMode == GaiaConstants.ImageFitnessFilterMode.BillowNoise)
|
|
{
|
|
fractalGenerator.FractalType = FractalGenerator.Fractals.Billow;
|
|
}
|
|
float num3 = 1f / m_noiseZoom;
|
|
for (int k = 0; k < num; k++)
|
|
{
|
|
for (int l = 0; l < num2; l++)
|
|
{
|
|
m_imageMaskHM[k, l] = fractalGenerator.GetValue((float)k * num3, (float)l * num3);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Terrain terrain2 = TerrainHelper.GetTerrain(base.transform.position);
|
|
if (terrain2 == null)
|
|
{
|
|
terrain2 = Terrain.activeTerrain;
|
|
}
|
|
if (terrain2 == null)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask but there is no terrain.");
|
|
return false;
|
|
}
|
|
GaiaSplatPrototype[] gaiaSplatPrototypes = GaiaSplatPrototype.GetGaiaSplatPrototypes(terrain2);
|
|
switch (m_areaMaskMode)
|
|
{
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture0:
|
|
if (gaiaSplatPrototypes.Length < 1)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 0 but there is no active texture in slot 0.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(terrain2.terrainData.GetAlphamaps(0, 0, terrain2.terrainData.alphamapWidth, terrain2.terrainData.alphamapHeight), 0);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture1:
|
|
if (gaiaSplatPrototypes.Length < 2)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 1 but there is no active texture in slot 1.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(terrain2.terrainData.GetAlphamaps(0, 0, terrain2.terrainData.alphamapWidth, terrain2.terrainData.alphamapHeight), 1);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture2:
|
|
if (gaiaSplatPrototypes.Length < 3)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 2 but there is no active texture in slot 2.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(terrain2.terrainData.GetAlphamaps(0, 0, terrain2.terrainData.alphamapWidth, terrain2.terrainData.alphamapHeight), 2);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture3:
|
|
if (gaiaSplatPrototypes.Length < 4)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 3 but there is no active texture in slot 3.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(terrain2.terrainData.GetAlphamaps(0, 0, terrain2.terrainData.alphamapWidth, terrain2.terrainData.alphamapHeight), 3);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture4:
|
|
if (gaiaSplatPrototypes.Length < 5)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 4 but there is no active texture in slot 4.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(terrain2.terrainData.GetAlphamaps(0, 0, terrain2.terrainData.alphamapWidth, terrain2.terrainData.alphamapHeight), 4);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture5:
|
|
if (gaiaSplatPrototypes.Length < 6)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 5 but there is no active texture in slot 5.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(terrain2.terrainData.GetAlphamaps(0, 0, terrain2.terrainData.alphamapWidth, terrain2.terrainData.alphamapHeight), 5);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture6:
|
|
if (gaiaSplatPrototypes.Length < 7)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 6 but there is no active texture in slot 6.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(terrain2.terrainData.GetAlphamaps(0, 0, terrain2.terrainData.alphamapWidth, terrain2.terrainData.alphamapHeight), 6);
|
|
break;
|
|
case GaiaConstants.ImageFitnessFilterMode.TerrainTexture7:
|
|
if (gaiaSplatPrototypes.Length < 8)
|
|
{
|
|
Debug.LogError("You requested an terrain texture mask 7 but there is no active texture in slot 7.");
|
|
return false;
|
|
}
|
|
m_imageMaskHM = new HeightMap(terrain2.terrainData.GetAlphamaps(0, 0, terrain2.terrainData.alphamapWidth, terrain2.terrainData.alphamapHeight), 7);
|
|
break;
|
|
}
|
|
m_imageMaskHM.Flip();
|
|
}
|
|
if (m_imageMaskSmoothIterations > 0)
|
|
{
|
|
m_imageMaskHM.Smooth(m_imageMaskSmoothIterations);
|
|
}
|
|
if (m_imageMaskFlip)
|
|
{
|
|
m_imageMaskHM.Flip();
|
|
}
|
|
if (m_imageMaskNormalise)
|
|
{
|
|
m_imageMaskHM.Normalise();
|
|
}
|
|
if (m_imageMaskInvert)
|
|
{
|
|
m_imageMaskHM.Invert();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private float CalculateHeight(float terrainHeight, float smHeightRaw, float smHeightAdj, float stencilHeightNU, float strength)
|
|
{
|
|
float num = 0f;
|
|
if (!m_drawStampBase && smHeightRaw < m_baseLevel)
|
|
{
|
|
return terrainHeight;
|
|
}
|
|
switch (m_stampOperation)
|
|
{
|
|
case GaiaConstants.FeatureOperation.RaiseHeight:
|
|
if (smHeightAdj > terrainHeight)
|
|
{
|
|
num = (smHeightAdj - terrainHeight) * strength;
|
|
terrainHeight += num;
|
|
}
|
|
break;
|
|
case GaiaConstants.FeatureOperation.BlendHeight:
|
|
num = (m_blendStrength * smHeightAdj + (1f - m_blendStrength) * terrainHeight - terrainHeight) * strength;
|
|
terrainHeight += num;
|
|
break;
|
|
case GaiaConstants.FeatureOperation.DifferenceHeight:
|
|
num = (Mathf.Abs(smHeightAdj - terrainHeight) - terrainHeight) * strength;
|
|
terrainHeight += num;
|
|
break;
|
|
case GaiaConstants.FeatureOperation.StencilHeight:
|
|
num = (terrainHeight + smHeightAdj * stencilHeightNU - terrainHeight) * strength;
|
|
terrainHeight += num;
|
|
break;
|
|
case GaiaConstants.FeatureOperation.LowerHeight:
|
|
if (smHeightAdj < terrainHeight)
|
|
{
|
|
num = (terrainHeight - smHeightAdj) * strength;
|
|
terrainHeight -= num;
|
|
}
|
|
break;
|
|
}
|
|
return terrainHeight;
|
|
}
|
|
|
|
private Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angle)
|
|
{
|
|
Vector3 vector = point - pivot;
|
|
vector = Quaternion.Euler(angle) * vector;
|
|
point = vector + pivot;
|
|
return point;
|
|
}
|
|
}
|
|
}
|