#if UNITY_EDITOR using UnityEngine; using UnityEditor; using System; using System.Collections.Generic; namespace GSpawn { public struct ScatterBrushPrefabDiff { public bool used; public bool spawnChance; public bool volumeRadius; public bool alignAxis; public bool alignmentAxis; public bool invertAlignmentAxis; public bool offsetFromSurface; public bool embedInSurface; public bool alignToStroke; public bool strokeAlignmentAxis; public bool invertStrokeAlignmentAxis; public bool randomizeRotation; public bool rotationRandomizationAxis; public bool minRandomRotation; public bool maxRandomRotation; public bool randomizeScale; public bool minRandomScale; public bool maxRandomScale; public bool enableSlopeCheck; public bool minSlope; public bool maxSlope; } public enum ScatterBrushPrefabRotationRandomizationAxis { X = 0, Y, Z, SurfaceNormal, [Obsolete] UIMixed } public class ScatterBrushPrefab : ScriptableObject, IUIItemStateProvider { private SerializedObject _serializedObject; [SerializeField] private PluginGuid _guid = new PluginGuid(Guid.NewGuid()); [SerializeField] private PluginPrefab _pluginPrefab; [SerializeField] private PrefabPreview _preview = new PrefabPreview(); [SerializeField] private bool _uiSelected = false; [NonSerialized] private CopyPasteMode _uiCopyPasteMode = CopyPasteMode.None; [SerializeField] private bool _used = defaultUsed; [SerializeField] private float _spawnChance = defaultSpawnChance; [SerializeField] private float _volumeRadius = defaultVolumeRadius; [SerializeField] private bool _alignAxis = defaultAlignAxis; [SerializeField] private FlexiAxis _alignmentAxis = defaultAlignmentAxis; [SerializeField] private bool _invertAlignmentAxis = defaultInvertAlignmentAxis; [SerializeField] private float _offsetFromSurface = defaultOffsetFromSurface; [SerializeField] private bool _embedInSurface = defaultEmbedInSurface; [SerializeField] private bool _alignToStroke = defaultAlignToStroke; [SerializeField] private FlexiAxis _strokeAlignmentAxis = defaultStrokeAlignmentAxis; [SerializeField] private bool _invertStrokeAlignmentAxis = defaultInvertStrokeAlignmentAxis; [SerializeField] private bool _randomizeRotation = defaultRandomizeRotation; [SerializeField] private ScatterBrushPrefabRotationRandomizationAxis _rotationRandomizationAxis = defaultRotationRandomizationAxis; [SerializeField] private float _minRandomRotation = defaultMinRandomRotation; [SerializeField] private float _maxRandomRotation = defaultMaxRandomRotation; [SerializeField] private bool _randomizeScale = defaultRandomizeScale; [SerializeField] private float _minRandomScale = defaultMinRandomScale; [SerializeField] private float _maxRandomScale = defaultMaxRandomScale; [SerializeField] private bool _enableSlopeCheck = defaultEnableSlopeCheck; [SerializeField] private float _minSlope = defaultMinSlope; [SerializeField] private float _maxSlope = defaultMaxSlope; public Texture2D previewTexture { get { return _preview.texture; } } public PluginPrefab pluginPrefab { get { return _pluginPrefab; } set { _pluginPrefab = value; _preview.setPrefab(_pluginPrefab.prefabAsset); volumeRadius = calcFlatPrefabVolumeRadius(); EditorUtility.SetDirty(this); } } public GameObject prefabAsset { get { return pluginPrefab.prefabAsset; } } public PluginGuid guid { get { return _guid; } } public bool uiSelected { get { return _uiSelected; } set { UndoEx.record(this); _uiSelected = value; } } public CopyPasteMode uiCopyPasteMode { get { return _uiCopyPasteMode; } set { _uiCopyPasteMode = value; } } public SerializedObject serializedObject { get { if (_serializedObject == null) _serializedObject = new SerializedObject(this); return _serializedObject; } } public bool used { get { return _used; } set { UndoEx.record(this); _used = value; EditorUtility.SetDirty(this); } } public float spawnChance { get { return _spawnChance; } set { UndoEx.record(this); _spawnChance = Mathf.Clamp01(value); EditorUtility.SetDirty(this); } } public float volumeRadius { get { return _volumeRadius; } set { UndoEx.record(this); _volumeRadius = Mathf.Max(value, 1e-2f); EditorUtility.SetDirty(this); } } public bool alignAxis { get { return _alignAxis; } set { UndoEx.record(this); _alignAxis = value; EditorUtility.SetDirty(this); } } public FlexiAxis alignmentAxis { get { return _alignmentAxis; } set { UndoEx.record(this); _alignmentAxis = value; EditorUtility.SetDirty(this); } } public bool invertAlignmentAxis { get { return _invertAlignmentAxis; } set { UndoEx.record(this); _invertAlignmentAxis = value; EditorUtility.SetDirty(this); } } public float offsetFromSurface { get { return _offsetFromSurface; } set { UndoEx.record(this); _offsetFromSurface = value; EditorUtility.SetDirty(this); } } public bool embedInSurface { get { return _embedInSurface; } set { UndoEx.record(this); _embedInSurface = value; EditorUtility.SetDirty(this); } } public bool alignToStroke { get { return _alignToStroke; } set { UndoEx.record(this); _alignToStroke = value; EditorUtility.SetDirty(this); } } public FlexiAxis strokeAlignmentAxis { get { return _strokeAlignmentAxis; } set { UndoEx.record(this); _strokeAlignmentAxis = value; EditorUtility.SetDirty(this); } } public bool invertStrokeAlignmentAxis { get { return _invertStrokeAlignmentAxis; } set { UndoEx.record(this); _invertStrokeAlignmentAxis = value; EditorUtility.SetDirty(this); } } public bool randomizeRotation { get { return _randomizeRotation; } set { UndoEx.record(this); _randomizeRotation = value; EditorUtility.SetDirty(this); } } public ScatterBrushPrefabRotationRandomizationAxis rotationRandomizationAxis { get { return _rotationRandomizationAxis; } set { UndoEx.record(this); _rotationRandomizationAxis = value; EditorUtility.SetDirty(this); } } public float minRandomRotation { get { return _minRandomRotation; } set { UndoEx.record(this); _minRandomRotation = Mathf.Clamp(value, 0.0f, 360.0f); if (_maxRandomRotation < _minRandomRotation) _maxRandomRotation = _minRandomRotation; EditorUtility.SetDirty(this); } } public float maxRandomRotation { get { return _maxRandomRotation; } set { UndoEx.record(this); _maxRandomRotation = Mathf.Clamp(value, 0.0f, 360.0f); if (_minRandomRotation > _maxRandomRotation) _minRandomRotation = _maxRandomRotation; EditorUtility.SetDirty(this); } } public bool randomizeScale { get { return _randomizeScale; } set { UndoEx.record(this); _randomizeScale = value; EditorUtility.SetDirty(this); } } public float minRandomScale { get { return _minRandomScale; } set { UndoEx.record(this); _minRandomScale = Mathf.Max(0.1f, value); if (_maxRandomScale < _minRandomScale) _maxRandomScale = _minRandomScale; EditorUtility.SetDirty(this); } } public float maxRandomScale { get { return _maxRandomScale; } set { UndoEx.record(this); _maxRandomScale = Mathf.Max(0.1f, value); if (_minRandomScale > _maxRandomScale) _minRandomScale = _maxRandomScale; EditorUtility.SetDirty(this); } } public bool enableSlopeCheck { get { return _enableSlopeCheck; } set { UndoEx.record(this); _enableSlopeCheck = value; EditorUtility.SetDirty(this); } } public float minSlope { get { return _minSlope; } set { UndoEx.record(this); _minSlope = Mathf.Clamp(value, 0.0f, 90.0f); if (_maxSlope < _minSlope) _maxSlope = _minSlope; EditorUtility.SetDirty(this); } } public float maxSlope { get { return _maxSlope; } set { UndoEx.record(this); _maxSlope = Mathf.Clamp(value, 0.0f, 90.0f); if (_minSlope > _maxSlope) _minSlope = _maxSlope; EditorUtility.SetDirty(this); } } public static bool defaultUsed { get { return true; } } public static float defaultSpawnChance { get { return 1.0f; } } public static float defaultVolumeRadius { get { return 1.0f; } } public static bool defaultAlignAxis { get { return false; } } public static FlexiAxis defaultAlignmentAxis { get { return FlexiAxis.Y; } } public static bool defaultInvertAlignmentAxis { get { return false; } } public static float defaultOffsetFromSurface { get { return 0.0f; } } public static bool defaultEmbedInSurface { get { return true; } } public static bool defaultAlignToStroke { get { return false; } } public static FlexiAxis defaultStrokeAlignmentAxis { get { return FlexiAxis.Longest; } } public static bool defaultInvertStrokeAlignmentAxis { get { return false; } } public static bool defaultRandomizeRotation { get { return true; } } public static ScatterBrushPrefabRotationRandomizationAxis defaultRotationRandomizationAxis { get { return ScatterBrushPrefabRotationRandomizationAxis.SurfaceNormal; } } public static float defaultMinRandomRotation { get { return 0.0f; } } public static float defaultMaxRandomRotation { get { return 360.0f; } } public static bool defaultRandomizeScale { get { return true; } } public static float defaultMinRandomScale { get { return 0.8f; } } public static float defaultMaxRandomScale { get { return 1.0f; } } public static bool defaultEnableSlopeCheck { get { return false; } } public static float defaultMinSlope { get { return 0.0f; } } public static float defaultMaxSlope { get { return 45.0f; } } public static ScatterBrushPrefabDiff checkDiff(List brushPrefabs) { int maxNumDiffs = typeof(ScatterBrushPrefabDiff).GetFields().Length; ScatterBrushPrefabDiff diff = new ScatterBrushPrefabDiff(); int numPrefabs = brushPrefabs.Count; for (int i = 0; i < numPrefabs; ++i) { var prefab = brushPrefabs[i]; for (int j = i + 1; j < numPrefabs; ++j) { var otherPrefab = brushPrefabs[j]; int diffCount = 0; if (prefab.used != otherPrefab.used) { ++diffCount; diff.used = true; } if (prefab.spawnChance != otherPrefab.spawnChance) { ++diffCount; diff.spawnChance = true; } if (prefab.volumeRadius != otherPrefab.volumeRadius) { ++diffCount; diff.volumeRadius = true; } if (prefab.alignAxis != otherPrefab.alignAxis) { ++diffCount; diff.alignAxis = true; } if (prefab.alignmentAxis != otherPrefab.alignmentAxis) { ++diffCount; diff.alignmentAxis = true; } if (prefab.invertAlignmentAxis != otherPrefab.invertAlignmentAxis) { ++diffCount; diff.invertAlignmentAxis = true; } if (prefab.offsetFromSurface != otherPrefab.offsetFromSurface) { ++diffCount; diff.offsetFromSurface = true; } if (prefab.embedInSurface != otherPrefab.embedInSurface) { ++diffCount; diff.embedInSurface = true; } if (prefab.alignToStroke != otherPrefab.alignToStroke) { ++diffCount; diff.alignToStroke = true; } if (prefab.strokeAlignmentAxis != otherPrefab.strokeAlignmentAxis) { ++diffCount; diff.strokeAlignmentAxis = true; } if (prefab.invertStrokeAlignmentAxis != otherPrefab.invertStrokeAlignmentAxis) { ++diffCount; diff.invertStrokeAlignmentAxis = true; } if (prefab.randomizeRotation != otherPrefab.randomizeRotation) { ++diffCount; diff.randomizeRotation = true; } if (prefab.rotationRandomizationAxis != otherPrefab.rotationRandomizationAxis) { ++diffCount; diff.rotationRandomizationAxis = true; } if (prefab.minRandomRotation != otherPrefab.minRandomRotation) { ++diffCount; diff.minRandomRotation = true; } if (prefab.maxRandomRotation != otherPrefab.maxRandomRotation) { ++diffCount; diff.maxRandomRotation = true; } if (prefab.randomizeScale != otherPrefab.randomizeScale) { ++diffCount; diff.randomizeScale = true; } if (prefab.minRandomScale != otherPrefab.minRandomScale) { ++diffCount; diff.minRandomScale = true; } if (prefab.maxRandomScale != otherPrefab.maxRandomScale) { ++diffCount; diff.maxRandomScale = true; } if (prefab.enableSlopeCheck != otherPrefab.enableSlopeCheck) { ++diffCount; diff.enableSlopeCheck = true; } if (prefab.minSlope != otherPrefab.minSlope) { ++diffCount; diff.minSlope = true; } if (prefab.maxSlope != otherPrefab.maxSlope) { ++diffCount; diff.maxSlope = true; } if (diffCount == maxNumDiffs) return diff; } } return diff; } public static void getPluginPrefabs(List scatterBrushPrefabs, List pluginPrefabs) { pluginPrefabs.Clear(); foreach (var brushPrefab in scatterBrushPrefabs) pluginPrefabs.Add(brushPrefab.pluginPrefab); } public void usePrefabVolumeRadius() { volumeRadius = calcPrefabVolumeRadius(); } public void useFlatPrefabVolumeRadius() { volumeRadius = calcFlatPrefabVolumeRadius(); } public void resetPreview() { _preview.reset(); } public void regeneratePreview() { _preview.regenerate(); } public void rotatePreview(Vector2 yawPitch) { _preview.rotate(yawPitch); } public void useDefaults() { used = defaultUsed; spawnChance = defaultSpawnChance; volumeRadius = calcPrefabVolumeRadius(); alignAxis = defaultAlignAxis; alignmentAxis = defaultAlignmentAxis; invertAlignmentAxis = defaultInvertAlignmentAxis; offsetFromSurface = defaultOffsetFromSurface; embedInSurface = defaultEmbedInSurface; alignToStroke = defaultAlignToStroke; strokeAlignmentAxis = defaultStrokeAlignmentAxis; randomizeRotation = defaultRandomizeRotation; rotationRandomizationAxis = defaultRotationRandomizationAxis; minRandomRotation = defaultMinRandomRotation; maxRandomRotation = defaultMaxRandomRotation; randomizeScale = defaultRandomizeScale; minRandomScale = defaultMinRandomScale; maxRandomScale = defaultMaxRandomScale; enableSlopeCheck = defaultEnableSlopeCheck; minSlope = defaultMinSlope; maxSlope = defaultMaxSlope; EditorUtility.SetDirty(this); } private float calcPrefabVolumeRadius() { if (pluginPrefab != null) return pluginPrefab.modelSize.magnitude * 0.5f; return 1.0f; } private float calcFlatPrefabVolumeRadius() { if (pluginPrefab != null) return pluginPrefab.modelSize.replace(1, 0.0f).magnitude * 0.5f; return 1.0f; } } } #endif