// Unity C# reference source
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License

using System;
using System.Collections.Generic;
using UnityEditor.EditorTools;
using UnityEditor.IMGUI.Controls;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.Rendering;

namespace UnityEditor
{
    class ShapeModuleUI : ModuleUI
    {
        struct MultiModeParameter
        {
            public SerializedProperty m_Value;
            public SerializedProperty m_Mode;
            public SerializedProperty m_Spread;
            public SerializedMinMaxCurve m_Speed;

            public enum ValueMode { Random, Loop, PingPong, BurstSpread }

            public static MultiModeParameter GetProperty(ModuleUI ui, string name, GUIContent speed, bool skipValue = false)
            {
                MultiModeParameter result = new MultiModeParameter();
                if (!skipValue)
                    result.m_Value = ui.GetProperty(name + ".value");
                result.m_Mode = ui.GetProperty(name + ".mode");
                result.m_Spread = ui.GetProperty(name + ".spread");
                result.m_Speed = new SerializedMinMaxCurve(ui, speed, name + ".speed", kUseSignedRange);
                result.m_Speed.m_AllowRandom = false;
                return result;
            }

            public void OnInspectorGUI(MultiModeTexts text, GUIContent[] modesText, bool showSpread = true, bool showSpeed = true)
            {
                if (m_Value != null)
                    GUIFloat(text.value, m_Value);

                EditorGUI.indentLevel++;

                GUIPopup(text.mode, m_Mode, modesText);
                if (showSpread)
                    GUIFloat(text.spread, m_Spread);

                if (showSpeed && !m_Mode.hasMultipleDifferentValues)
                {
                    ValueMode mode = (ValueMode)m_Mode.intValue;
                    if (mode == ValueMode.Loop || mode == ValueMode.PingPong)
                    {
                        GUIMinMaxCurve(text.speed, m_Speed);
                    }
                }

                EditorGUI.indentLevel--;
            }
        }

        SerializedProperty m_Type;
        SerializedProperty m_RandomDirectionAmount;
        SerializedProperty m_SphericalDirectionAmount;
        SerializedProperty m_RandomPositionAmount;
        SerializedProperty m_AlignToDirection;

        SerializedProperty m_Position;
        SerializedProperty m_Scale;
        SerializedProperty m_Rotation;

        // primitive properties
        MultiModeParameter m_Radius;
        SerializedProperty m_RadiusThickness;
        SerializedProperty m_Angle;
        SerializedProperty m_Length;
        SerializedProperty m_BoxThickness;
        MultiModeParameter m_Arc;
        SerializedProperty m_DonutRadius;

        // mesh properties
        SerializedProperty m_PlacementMode;
        SerializedProperty m_Mesh;
        SerializedProperty m_MeshRenderer;
        SerializedProperty m_SkinnedMeshRenderer;
        SerializedProperty m_Sprite;
        SerializedProperty m_SpriteRenderer;
        SerializedProperty m_MeshMaterialIndex;
        SerializedProperty m_UseMeshMaterialIndex;
        SerializedProperty m_UseMeshColors;
        SerializedProperty m_MeshNormalOffset;
        MultiModeParameter m_MeshSpawn;


        // texture properties
        SerializedProperty m_Texture;
        SerializedProperty m_TextureClipChannel;
        SerializedProperty m_TextureClipThreshold;
        SerializedProperty m_TextureColorAffectsParticles;
        SerializedProperty m_TextureAlphaAffectsParticles;
        SerializedProperty m_TextureBilinearFiltering;
        SerializedProperty m_TextureUVChannel;

        // internal
        private static Material s_Material;
        private static Material s_TextureMaterial;
        private static Material s_SphereTextureMaterial;
        private static Mesh s_CircleMesh;
        private static Mesh s_QuadMesh;
        private static Mesh s_SphereMesh;
        private static Mesh s_HemisphereMesh;
        private static readonly Matrix4x4 s_ArcHandleOffsetMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.AngleAxis(90f, Vector3.right) * Quaternion.AngleAxis(90f, Vector3.up), Vector3.one);
        private static ArcHandle s_ArcHandle = new ArcHandle();
        private static BoxBoundsHandle s_BoxBoundsHandle = new BoxBoundsHandle();
        private static SphereBoundsHandle s_SphereBoundsHandle = new SphereBoundsHandle();
        private static PrefColor s_GizmoColor = new PrefColor("Particle System/Shape Module Gizmos", 148f / 255f, 229f / 255f, 1f, 0.9f);
        private static Color s_ShapeGizmoThicknessTint = new Color(0.7f, 0.7f, 0.7f, 1.0f);

        private static Mesh s_SpriteMesh;

        private readonly ParticleSystemShapeType[] m_GuiTypes = new[] { ParticleSystemShapeType.Sphere, ParticleSystemShapeType.Hemisphere, ParticleSystemShapeType.Cone, ParticleSystemShapeType.Donut, ParticleSystemShapeType.Box, ParticleSystemShapeType.Mesh, ParticleSystemShapeType.MeshRenderer, ParticleSystemShapeType.SkinnedMeshRenderer, ParticleSystemShapeType.Sprite, ParticleSystemShapeType.SpriteRenderer, ParticleSystemShapeType.Circle, ParticleSystemShapeType.SingleSidedEdge, ParticleSystemShapeType.Rectangle };
        private readonly int[] m_TypeToGuiTypeIndex = new[] { 0, 0, 1, 1, 2, 4, 5, 2, 2, 2, 10, 10, 11, 6, 7, 4, 4, 3, 12, 8, 9 };

        private readonly ParticleSystemShapeType[] boxShapes = new ParticleSystemShapeType[] { ParticleSystemShapeType.Box, ParticleSystemShapeType.BoxShell, ParticleSystemShapeType.BoxEdge };
        private readonly ParticleSystemShapeType[] coneShapes = new ParticleSystemShapeType[] { ParticleSystemShapeType.Cone, ParticleSystemShapeType.ConeVolume };

        abstract class ShapeTool : EditorTool
        {
            public override bool IsAvailable()
            {
                foreach (var t in targets)
                {
                    var ps = t as ParticleSystem;
                    if (ps == null)
                        continue;

                    if (ps.shape.enabled)
                        return true;
                }
                return false;

            }
        }

        [EditorTool("Shape", typeof(ParticleSystem))]
        class ShapeGizmoTool : ShapeTool, IDrawSelectedHandles
        {
            public override GUIContent toolbarIcon
            {
                get { return EditorGUIUtility.TrIconContent("ParticleShapeTool", "Shape module gizmo editing mode."); }
            }

            public override void OnToolGUI(EditorWindow window)
            {
                OnShapeToolGUI(true, targets);
            }

            public void OnDrawHandles()
            {
                OnShapeToolGUI(false, targets);
            }
        }

        [EditorTool("Transform Shape", typeof(ParticleSystem))]
        class ShapePositionTool : ShapeTool
        {
            public override GUIContent toolbarIcon
            {
                get { return EditorGUIUtility.TrIconContent("TransformTool", "Shape module transform editing mode."); }
            }

            public override void OnToolGUI(EditorWindow window)
            {
                foreach (var t in targets)
                {
                    var ps = t as ParticleSystem;
                    if (ps == null)
                        continue;

                    var shapeModule = ps.shape;
                    Matrix4x4 transformMatrix = GetSceneViewTransformMatrix(ps);

                    Vector3 position = transformMatrix.MultiplyPoint(shapeModule.position);
                    Quaternion rotation = transformMatrix.rotation * Quaternion.Euler(shapeModule.rotation);
                    Vector3 scale = transformMatrix.MultiplyVector(shapeModule.scale);

                    EditorGUI.BeginChangeCheck();

                    Handles.TransformHandle(ref position, ref rotation, ref scale);

                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoTransform);

                        Matrix4x4 inverseTransformMatrix = transformMatrix.inverse;

                        shapeModule.position = inverseTransformMatrix.MultiplyPoint(position);
                        shapeModule.rotation = (inverseTransformMatrix.rotation * rotation).eulerAngles;
                        shapeModule.scale = inverseTransformMatrix.MultiplyVector(scale);
                    }
                }
            }
        }

        class Texts
        {
            public GUIContent shape = EditorGUIUtility.TrTextContent("Shape", "Defines the shape of the volume from which particles can be emitted, and the direction of the start velocity.");
            public GUIContent radius = EditorGUIUtility.TrTextContent("Radius", "Radius of the shape.");
            public GUIContent radiusThickness = EditorGUIUtility.TrTextContent("Radius Thickness", "Control the thickness of the spawn volume, from 0 to 1.");
            public GUIContent coneAngle = EditorGUIUtility.TrTextContent("Angle", "Angle of the cone.");
            public GUIContent coneLength = EditorGUIUtility.TrTextContent("Length", "Length of the cone.");
            public GUIContent boxThickness = EditorGUIUtility.TrTextContent("Box Thickness", "When using shell/edge modes, control the thickness of the spawn volume, from 0 to 1.");
            public GUIContent meshType = EditorGUIUtility.TrTextContent("Type", "Generate particles from vertices, edges or triangles.");
            public GUIContent mesh = EditorGUIUtility.TrTextContent("Mesh", "Mesh that the particle system will emit from.");
            public GUIContent meshRenderer = EditorGUIUtility.TrTextContent("Mesh", "MeshRenderer that the particle system will emit from.");
            public GUIContent skinnedMeshRenderer = EditorGUIUtility.TrTextContent("Mesh", "SkinnedMeshRenderer that the particle system will emit from.");
            public GUIContent sprite = EditorGUIUtility.TrTextContent("Sprite", "Sprite that the particle system will emit from.");
            public GUIContent spriteRenderer = EditorGUIUtility.TrTextContent("Sprite", "SpriteRenderer that the particle system will emit from.");
            public GUIContent meshMaterialIndex = EditorGUIUtility.TrTextContent("Single Material", "Only emit from a specific material of the mesh.");
            public GUIContent useMeshColors = EditorGUIUtility.TrTextContent("Use Mesh Colors", "Modulate particle color with mesh vertex colors, or if they don't exist, use the shader color property \"_Color\" or \"_TintColor\" from the material. Does not read texture colors.");
            public GUIContent meshNormalOffset = EditorGUIUtility.TrTextContent("Normal Offset", "Offset particle spawn positions along the mesh normal.");
            public GUIContent texture = EditorGUIUtility.TrTextContent("Texture", "Texture that the particles will sample their color from.");
            public GUIContent textureClipChannel = EditorGUIUtility.TrTextContent("Clip Channel", "Select a channel to use for discarding particles.");
            public GUIContent textureClipThreshold = EditorGUIUtility.TrTextContent("Clip Threshold", "Only emit from parts of the texture where the Clip Channel is greater than or equal to this value.");
            public GUIContent textureColorAffectsParticles = EditorGUIUtility.TrTextContent("Color affects Particles", "Multiply the particle color by the texture RGB value.");
            public GUIContent textureAlphaAffectsParticles = EditorGUIUtility.TrTextContent("Alpha affects Particles", "Multiply the particle alpha by the texture alpha value.");
            public GUIContent textureBilinearFiltering = EditorGUIUtility.TrTextContent("Bilinear Filtering", "Blend between pixels on the texture.");
            public GUIContent textureUVChannel = EditorGUIUtility.TrTextContent("UV Channel", "Use the selected UV channel from the source mesh, for reading the texture.");
            public GUIContent alignToDirection = EditorGUIUtility.TrTextContent("Align To Direction", "Automatically align particles based on their initial direction of travel.");
            public GUIContent randomDirectionAmount = EditorGUIUtility.TrTextContent("Randomize Direction", "Override the initial direction of travel with a random direction.");
            public GUIContent sphericalDirectionAmount = EditorGUIUtility.TrTextContent("Spherize Direction", "Override the initial direction of travel with a direction that projects particles outwards from the center of the Shape Transform.");
            public GUIContent randomPositionAmount = EditorGUIUtility.TrTextContent("Randomize Position", "Move the starting positions by a random amount, up to this maximum value.");
            public GUIContent emitFrom = EditorGUIUtility.TrTextContent("Emit from:", "Specifies from where particles are emitted.");
            public GUIContent donutRadius = EditorGUIUtility.TrTextContent("Donut Radius", "The radius of the donut. Used to control the thickness of the ring.");
            public GUIContent position = EditorGUIUtility.TrTextContent("Position", "Translate the emission shape.");
            public GUIContent rotation = EditorGUIUtility.TrTextContent("Rotation", "Rotate the emission shape.");
            public GUIContent scale = EditorGUIUtility.TrTextContent("Scale", "Scale the emission shape.");
            public GUIContent sceneTools = EditorGUIUtility.TrTextContent("Scene Tools");

            public readonly string undoSphereThickness = L10n.Tr("Sphere Thickness Handle Change");
            public readonly string undoSphere = L10n.Tr("Sphere Handle Change");
            public readonly string undoCircleThickness = L10n.Tr("Circle Thickness Handle Change");
            public readonly string undoCircle = L10n.Tr("Circle Handle Change");
            public readonly string undoHemisphereThickness = L10n.Tr("Hemisphere Thickness Handle Change");
            public readonly string undoHemisphere = L10n.Tr("Hemisphere Handle Change");
            public readonly string undoConeThickness = L10n.Tr("Cone Thickness Handle Change");
            public readonly string undoCone = L10n.Tr("Cone Handle Change");
            public readonly string undoConeVolumeThickness = L10n.Tr("Cone Volume Thickness Handle Change");
            public readonly string undoConeVolume = L10n.Tr("Cone Volume Handle Change");
            public readonly string undoBox = L10n.Tr("Box Handle Change");
            public readonly string undoDonut = L10n.Tr("Donut Handle Change");
            public readonly string undoDonutRadiusThickness = L10n.Tr("Donut Radius Thickness Handle Change");
            public readonly string undoDonutRadius = L10n.Tr("Donut Radius Handle Change");
            public readonly string undoEdge = L10n.Tr("Edge Handle Change");
            public readonly string undoRectangle = L10n.Tr("Rectangle Handle Change");
            public readonly string undoTransform = L10n.Tr("Shape Transform Change");

            public GUIContent[] shapeTypes = new GUIContent[]
            {
                EditorGUIUtility.TrTextContent("Sphere"),
                EditorGUIUtility.TrTextContent("Hemisphere"),
                EditorGUIUtility.TrTextContent("Cone"),
                EditorGUIUtility.TrTextContent("Donut"),
                EditorGUIUtility.TrTextContent("Box"),
                EditorGUIUtility.TrTextContent("Mesh"),
                EditorGUIUtility.TrTextContent("Mesh Renderer"),
                EditorGUIUtility.TrTextContent("Skinned Mesh Renderer"),
                EditorGUIUtility.TextContent("Sprite"),
                EditorGUIUtility.TextContent("Sprite Renderer"),
                EditorGUIUtility.TrTextContent("Circle"),
                EditorGUIUtility.TrTextContent("Edge"),
                EditorGUIUtility.TrTextContent("Rectangle")
            };

            public GUIContent[] boxTypes = new GUIContent[]
            {
                EditorGUIUtility.TrTextContent("Volume"),
                EditorGUIUtility.TrTextContent("Shell"),
                EditorGUIUtility.TrTextContent("Edge")
            };

            public GUIContent[] coneTypes = new GUIContent[]
            {
                EditorGUIUtility.TrTextContent("Base"),
                EditorGUIUtility.TrTextContent("Volume")
            };

            public GUIContent[] meshTypes = new GUIContent[]
            {
                EditorGUIUtility.TrTextContent("Vertex"),
                EditorGUIUtility.TrTextContent("Edge"),
                EditorGUIUtility.TrTextContent("Triangle")
            };

            public GUIContent[] emissionModes = new GUIContent[]
            {
                EditorGUIUtility.TrTextContent("Random"),
                EditorGUIUtility.TrTextContent("Loop"),
                EditorGUIUtility.TrTextContent("Ping-Pong"),
                EditorGUIUtility.TrTextContent("Burst Spread")
            };

            public GUIContent[] emissionModesMesh = new GUIContent[]
            {
                EditorGUIUtility.TrTextContent("Random"),
                EditorGUIUtility.TrTextContent("Loop"),
                EditorGUIUtility.TrTextContent("Ping-Pong")
            };

            public GUIContent[] textureClipChannels = new GUIContent[]
            {
                EditorGUIUtility.TrTextContent("Red"),
                EditorGUIUtility.TrTextContent("Green"),
                EditorGUIUtility.TrTextContent("Blue"),
                EditorGUIUtility.TrTextContent("Alpha")
            };
        }

        static Texts s_Texts;

        class MultiModeTexts
        {
            public MultiModeTexts(string _value, string _mode, string _spread, string _speed)
            {
                value = EditorGUIUtility.TextContent(_value);
                mode = EditorGUIUtility.TextContent(_mode);
                spread = EditorGUIUtility.TextContent(_spread);
                speed = EditorGUIUtility.TextContent(_speed);
            }

            public GUIContent value;
            public GUIContent mode;
            public GUIContent spread;
            public GUIContent speed;
        }

        static MultiModeTexts s_RadiusTexts = new MultiModeTexts(
            /*_value:*/ "Radius|New particles are spawned along the radius.",
            /*_mode:*/ "Mode|Control how particles are spawned along the radius.",
            /*_spread:*/ "Spread|Spawn particles only at specific positions along the radius (0 to disable).",
            /*_speed:*/ "Speed|Control the speed that the emission position moves along the radius.");

        static MultiModeTexts s_ArcTexts = new MultiModeTexts(
            /*_value:*/ "Arc|New particles are spawned around the arc.",
            /*_mode:*/ "Mode|Control how particles are spawned around the arc.",
            /*_spread:*/ "Spread|Spawn particles only at specific angles around the arc (0 to disable).",
            /*_speed:*/ "Speed|Control the speed that the emission position moves around the arc.");

        static MultiModeTexts s_MeshTexts = new MultiModeTexts(
            /*_value:*/ null,
            /*_mode:*/ "Mode|Control how particles are spawned across the mesh.",
            /*_spread:*/ "Spread|Spawn particles only at specific positions across the mesh (0 to disable).",
            /*_speed:*/ "Speed|Control the speed that the emission position moves along the edges of the mesh.");

        public ShapeModuleUI(ParticleSystemUI owner, SerializedObject o, string displayName)
            : base(owner, o, "ShapeModule", displayName, VisibilityState.VisibleAndFolded)
        {
            m_ToolTip = "Shape of the emitter volume, which controls where particles are emitted and their initial direction.";
        }

        private bool editToolActive
        {
            get
            {
                return EditorToolManager.activeTool is ShapeTool;
            }
        }

        protected override void Init()
        {
            if (m_Type != null)
                return;
            if (s_Texts == null)
                s_Texts = new Texts();

            m_Type = GetProperty("type");
            m_Radius = MultiModeParameter.GetProperty(this, "radius", s_RadiusTexts.speed);
            m_RadiusThickness = GetProperty("radiusThickness");
            m_Angle = GetProperty("angle");
            m_Length = GetProperty("length");
            m_BoxThickness = GetProperty("boxThickness");
            m_Arc = MultiModeParameter.GetProperty(this, "arc", s_ArcTexts.speed);
            m_DonutRadius = GetProperty("donutRadius");

            m_PlacementMode = GetProperty("placementMode");
            m_Mesh = GetProperty("m_Mesh");
            m_MeshRenderer = GetProperty("m_MeshRenderer");
            m_SkinnedMeshRenderer = GetProperty("m_SkinnedMeshRenderer");
            m_Sprite = GetProperty("m_Sprite");
            m_SpriteRenderer = GetProperty("m_SpriteRenderer");
            m_MeshMaterialIndex = GetProperty("m_MeshMaterialIndex");
            m_UseMeshMaterialIndex = GetProperty("m_UseMeshMaterialIndex");
            m_UseMeshColors = GetProperty("m_UseMeshColors");
            m_MeshNormalOffset = GetProperty("m_MeshNormalOffset");
            m_MeshSpawn = MultiModeParameter.GetProperty(this, "m_MeshSpawn", s_MeshTexts.speed, true);
            m_Texture = GetProperty("m_Texture");
            m_TextureClipChannel = GetProperty("m_TextureClipChannel");
            m_TextureClipThreshold = GetProperty("m_TextureClipThreshold");
            m_TextureColorAffectsParticles = GetProperty("m_TextureColorAffectsParticles");
            m_TextureAlphaAffectsParticles = GetProperty("m_TextureAlphaAffectsParticles");
            m_TextureBilinearFiltering = GetProperty("m_TextureBilinearFiltering");
            m_TextureUVChannel = GetProperty("m_TextureUVChannel");
            m_RandomDirectionAmount = GetProperty("randomDirectionAmount");
            m_SphericalDirectionAmount = GetProperty("sphericalDirectionAmount");
            m_RandomPositionAmount = GetProperty("randomPositionAmount");
            m_AlignToDirection = GetProperty("alignToDirection");

            m_Position = GetProperty("m_Position");
            m_Scale = GetProperty("m_Scale");
            m_Rotation = GetProperty("m_Rotation");
        }

        public override float GetXAxisScalar()
        {
            return m_ParticleSystemUI.GetEmitterDuration();
        }

        private ParticleSystemShapeType ConvertConeEmitFromToConeType(int emitFrom)
        {
            return coneShapes[emitFrom];
        }

        private int ConvertConeTypeToConeEmitFrom(ParticleSystemShapeType shapeType)
        {
            return System.Array.IndexOf(coneShapes, shapeType);
        }

        private ParticleSystemShapeType ConvertBoxEmitFromToBoxType(int emitFrom)
        {
            return boxShapes[emitFrom];
        }

        private int ConvertBoxTypeToBoxEmitFrom(ParticleSystemShapeType shapeType)
        {
            return System.Array.IndexOf(boxShapes, shapeType);
        }

        override public void OnInspectorGUI(InitialModuleUI initial)
        {
            EditorGUI.showMixedValue = m_Type.hasMultipleDifferentValues;
            int type = m_Type.intValue;
            int index = m_TypeToGuiTypeIndex[type];

            EditorGUI.BeginChangeCheck();
            int index2 = GUIPopup(s_Texts.shape, index, s_Texts.shapeTypes, m_Type);
            bool shapeTypeChanged = EditorGUI.EndChangeCheck();

            EditorGUI.showMixedValue = false;

            ParticleSystemShapeType guiType = m_GuiTypes[index2];
            if (index2 != index)
            {
                type = (int)guiType;
            }

            if (!m_Type.hasMultipleDifferentValues)
            {
                switch (guiType)
                {
                    case ParticleSystemShapeType.Box:
                    {
                        int emitFrom = ConvertBoxTypeToBoxEmitFrom((ParticleSystemShapeType)type);
                        emitFrom = GUIPopup(s_Texts.emitFrom, emitFrom, s_Texts.boxTypes, m_Type);
                        type = (int)ConvertBoxEmitFromToBoxType(emitFrom);

                        if (type == (int)ParticleSystemShapeType.BoxShell || type == (int)ParticleSystemShapeType.BoxEdge)
                            GUIVector3Field(s_Texts.boxThickness, m_BoxThickness);
                    }
                    break;

                    case ParticleSystemShapeType.Cone:
                    {
                        GUIFloat(s_Texts.coneAngle, m_Angle);
                        GUIFloat(s_Texts.radius, m_Radius.m_Value);
                        GUIFloat(s_Texts.radiusThickness, m_RadiusThickness);

                        m_Arc.OnInspectorGUI(s_ArcTexts, s_Texts.emissionModes);

                        bool showLength = (type != (int)ParticleSystemShapeType.ConeVolume);
                        using (new EditorGUI.DisabledScope(showLength))
                        {
                            GUIFloat(s_Texts.coneLength, m_Length);
                        }

                        int emitFrom = ConvertConeTypeToConeEmitFrom((ParticleSystemShapeType)type);
                        emitFrom = GUIPopup(s_Texts.emitFrom, emitFrom, s_Texts.coneTypes, m_Type);
                        type = (int)ConvertConeEmitFromToConeType(emitFrom);
                    }
                    break;

                    case ParticleSystemShapeType.Donut:
                    {
                        GUIFloat(s_Texts.radius, m_Radius.m_Value);
                        GUIFloat(s_Texts.donutRadius, m_DonutRadius);
                        GUIFloat(s_Texts.radiusThickness, m_RadiusThickness);

                        m_Arc.OnInspectorGUI(s_ArcTexts, s_Texts.emissionModes);
                    }
                    break;

                    case ParticleSystemShapeType.Mesh:
                    case ParticleSystemShapeType.MeshRenderer:
                    case ParticleSystemShapeType.SkinnedMeshRenderer:
                    {
                        ParticleSystemMeshShapeType placementMode = (ParticleSystemMeshShapeType)GUIPopup(s_Texts.meshType, m_PlacementMode, s_Texts.meshTypes);

                        if (!m_PlacementMode.hasMultipleDifferentValues && placementMode != ParticleSystemMeshShapeType.Triangle)
                        {
                            bool showSpeedAndSpread = (placementMode != ParticleSystemMeshShapeType.Vertex);
                            m_MeshSpawn.OnInspectorGUI(s_MeshTexts, s_Texts.emissionModesMesh, showSpeedAndSpread, showSpeedAndSpread);
                        }

                        Material material = null;
                        Mesh srcMesh = null;
                        if (guiType == ParticleSystemShapeType.Mesh)
                        {
                            GUIObject(s_Texts.mesh, m_Mesh);
                            srcMesh = (Mesh)m_Mesh.objectReferenceValue;
                        }
                        else if (guiType == ParticleSystemShapeType.MeshRenderer)
                        {
                            GUIObject(s_Texts.meshRenderer, m_MeshRenderer);
                            MeshRenderer mesh = (MeshRenderer)m_MeshRenderer.objectReferenceValue;
                            if (mesh)
                            {
                                material = mesh.sharedMaterial;
                                if (mesh.GetComponent<MeshFilter>())
                                    srcMesh = mesh.GetComponent<MeshFilter>().sharedMesh;
                            }
                        }
                        else
                        {
                            GUIObject(s_Texts.skinnedMeshRenderer, m_SkinnedMeshRenderer);
                            SkinnedMeshRenderer mesh = (SkinnedMeshRenderer)m_SkinnedMeshRenderer.objectReferenceValue;
                            if (mesh)
                            {
                                material = mesh.sharedMaterial;
                                srcMesh = mesh.sharedMesh;
                            }
                        }

                        GUIToggleWithIntField(s_Texts.meshMaterialIndex, m_UseMeshMaterialIndex, m_MeshMaterialIndex, false);
                        bool useMeshColors = GUIToggle(s_Texts.useMeshColors, m_UseMeshColors);
                        if (useMeshColors)
                        {
                            if (material != null && srcMesh != null)
                            {
                                int colorName = Shader.PropertyToID("_Color");
                                int tintColorName = Shader.PropertyToID("_TintColor");
                                if (!material.HasProperty(colorName) && !material.HasProperty(tintColorName) && !srcMesh.HasVertexAttribute(VertexAttribute.Color))
                                {
                                    GUIContent warning = EditorGUIUtility.TrTextContent("To use mesh colors, your source mesh must either provide vertex colors, or its shader must contain a color property named \"_Color\" or \"_TintColor\".");
                                    EditorGUILayout.HelpBox(warning.text, MessageType.Warning, true);
                                }
                            }
                        }

                        GUIFloat(s_Texts.meshNormalOffset, m_MeshNormalOffset);
                    }
                    break;

                    case ParticleSystemShapeType.Sprite:
                    case ParticleSystemShapeType.SpriteRenderer:
                    {
                        GUIPopup(s_Texts.meshType, m_PlacementMode, s_Texts.meshTypes);

                        if (guiType == ParticleSystemShapeType.Sprite)
                            GUIObject(s_Texts.sprite, m_Sprite);
                        else if (guiType == ParticleSystemShapeType.SpriteRenderer)
                            GUIObject(s_Texts.spriteRenderer, m_SpriteRenderer);

                        GUIFloat(s_Texts.meshNormalOffset, m_MeshNormalOffset);
                    }
                    break;

                    case ParticleSystemShapeType.Sphere:
                    case ParticleSystemShapeType.Hemisphere:
                    {
                        GUIFloat(s_Texts.radius, m_Radius.m_Value);
                        GUIFloat(s_Texts.radiusThickness, m_RadiusThickness);

                        m_Arc.OnInspectorGUI(s_ArcTexts, s_Texts.emissionModes);
                    }
                    break;

                    case ParticleSystemShapeType.Circle:
                    {
                        GUIFloat(s_Texts.radius, m_Radius.m_Value);
                        GUIFloat(s_Texts.radiusThickness, m_RadiusThickness);

                        m_Arc.OnInspectorGUI(s_ArcTexts, s_Texts.emissionModes);
                    }
                    break;

                    case ParticleSystemShapeType.SingleSidedEdge:
                    {
                        m_Radius.OnInspectorGUI(s_RadiusTexts, s_Texts.emissionModes);
                    }
                    break;

                    case ParticleSystemShapeType.Rectangle:
                        break;
                }
            }

            if (shapeTypeChanged || !m_Type.hasMultipleDifferentValues)
                m_Type.intValue = type;

            OnTextureInspectorGUI();
            OnTransformInspectorGUI();
            OnMiscInspectorGUI();

            if (EditorGUIUtility.comparisonViewMode == EditorGUIUtility.ComparisonViewMode.None)
            {
                EditorGUILayout.BeginVertical("GroupBox");

                var editorTools = new List<EditorTool>(2);
                EditorToolManager.GetComponentTools(x => x.GetEditor<EditorTool>() is ShapeTool, editorTools, true);

                GUILayout.BeginHorizontal();
                EditorGUILayout.PrefixLabel(s_Texts.sceneTools, ParticleSystemStyles.Get().label, ParticleSystemStyles.Get().label);
                EditorGUILayout.EditorToolbar(editorTools);
                GUILayout.EndHorizontal();

                EditorGUILayout.EndVertical();
            }
        }

        private void OnTextureInspectorGUI()
        {
            if (m_Texture.hasMultipleDifferentValues || m_Texture.objectReferenceValue != null)
            {
                EditorGUILayout.Space();
                GUIObject(s_Texts.texture, m_Texture, typeof(Texture2D));
                GUIPopup(s_Texts.textureClipChannel, m_TextureClipChannel, s_Texts.textureClipChannels);
                GUIFloat(s_Texts.textureClipThreshold, m_TextureClipThreshold);
                GUIToggle(s_Texts.textureColorAffectsParticles, m_TextureColorAffectsParticles);
                GUIToggle(s_Texts.textureAlphaAffectsParticles, m_TextureAlphaAffectsParticles);
                GUIToggle(s_Texts.textureBilinearFiltering, m_TextureBilinearFiltering);

                if (!m_Type.hasMultipleDifferentValues)
                {
                    if ((m_Type.intValue == (int)ParticleSystemShapeType.Mesh) || (m_Type.intValue == (int)ParticleSystemShapeType.MeshRenderer) || (m_Type.intValue == (int)ParticleSystemShapeType.SkinnedMeshRenderer))
                        GUIInt(s_Texts.textureUVChannel, m_TextureUVChannel);
                }
            }
            else
            {
                GUIObject(s_Texts.texture, m_Texture, typeof(Texture2D));
            }
        }

        private void OnTransformInspectorGUI()
        {
            EditorGUILayout.Space();
            GUIVector3Field(s_Texts.position, m_Position);
            GUIVector3Field(s_Texts.rotation, m_Rotation);
            GUIVector3Field(s_Texts.scale, m_Scale);
        }

        private void OnMiscInspectorGUI()
        {
            EditorGUILayout.Space();
            GUIToggle(s_Texts.alignToDirection, m_AlignToDirection);
            GUIFloat(s_Texts.randomDirectionAmount, m_RandomDirectionAmount);
            GUIFloat(s_Texts.sphericalDirectionAmount, m_SphericalDirectionAmount);
            GUIFloat(s_Texts.randomPositionAmount, m_RandomPositionAmount);
        }

        private static Matrix4x4 GetSceneViewTransformMatrix(ParticleSystem ps)
        {
            Matrix4x4 transformMatrix = new Matrix4x4();
            var transform = ps.transform;
            if (ps.main.scalingMode == ParticleSystemScalingMode.Local)
                transformMatrix.SetTRS(transform.position, transform.rotation, transform.localScale);
            else
                transformMatrix = transform.localToWorldMatrix;
            return transformMatrix;
        }

        private static void InitResources()
        {
            if (s_Texts == null)
                s_Texts = new Texts();

            if (!s_Material)
                s_Material = Material.GetDefaultMaterial();

            if (!s_TextureMaterial)
            {
                s_TextureMaterial = new Material((Shader)EditorGUIUtility.Load("SceneView/ParticleShapeGizmo.shader"));
                s_TextureMaterial.hideFlags = HideFlags.HideAndDontSave;
            }

            if (!s_SphereTextureMaterial)
            {
                s_SphereTextureMaterial = new Material((Shader)EditorGUIUtility.Load("SceneView/ParticleShapeGizmoSphere.shader"));
                s_SphereTextureMaterial.hideFlags = HideFlags.HideAndDontSave;
            }

            if (!s_CircleMesh)
                s_CircleMesh = ((GameObject)EditorGUIUtility.Load("SceneView/Circle.fbx")).transform.GetComponent<MeshFilter>().sharedMesh;
            if (!s_QuadMesh)
                s_QuadMesh = Resources.GetBuiltinResource(typeof(Mesh), "Quad.fbx") as Mesh;
            if (!s_SphereMesh)
                s_SphereMesh = Resources.GetBuiltinResource(typeof(Mesh), "New-Sphere.fbx") as Mesh;
            if (!s_HemisphereMesh)
                s_HemisphereMesh = ((GameObject)EditorGUIUtility.Load("SceneView/Hemisphere.fbx")).transform.GetComponent<MeshFilter>().sharedMesh;
        }

        internal static void OnShapeToolGUI(bool allowGizmoEditing, IEnumerable<UnityEngine.Object> targets)
        {
            InitResources();

            Color origCol = Handles.color;
            Handles.color = s_GizmoColor;

            Matrix4x4 orgMatrix = Handles.matrix;

            foreach (var target in targets)
            {
                var ps = target as ParticleSystem;
                if (ps == null)
                    continue;

                var shapeModule = ps.shape;
                var mainModule = ps.main;

                ParticleSystemShapeType type = shapeModule.shapeType;

                Matrix4x4 transformMatrix = GetSceneViewTransformMatrix(ps);

                bool isBox = (type == ParticleSystemShapeType.Box || type == ParticleSystemShapeType.BoxShell || type == ParticleSystemShapeType.BoxEdge || type == ParticleSystemShapeType.Rectangle);

                Vector3 emitterScale = isBox ? Vector3.one : shapeModule.scale;
                Matrix4x4 emitterMatrix = Matrix4x4.TRS(shapeModule.position, Quaternion.Euler(shapeModule.rotation), emitterScale);
                Matrix4x4 combinedMatrix = transformMatrix * emitterMatrix;
                Handles.matrix = combinedMatrix;

                Color gizmoEditingColor = new Color(1.0f, 1.0f, 1.0f, allowGizmoEditing && !Event.current.alt ? 1.0f : 0.0f);

                if (type == ParticleSystemShapeType.Sphere)
                {
                    // Thickness
                    Handles.color *= s_ShapeGizmoThicknessTint;
                    EditorGUI.BeginChangeCheck();
                    float radiusThickness = Handles.DoSimpleRadiusHandle(Quaternion.identity, Vector3.zero, shapeModule.radius * (1.0f - shapeModule.radiusThickness), false, shapeModule.arc, allowGizmoEditing);
                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoSphereThickness);
                        shapeModule.radiusThickness = 1.0f - (radiusThickness / shapeModule.radius);
                    }

                    // Sphere
                    Handles.color = s_GizmoColor;
                    EditorGUI.BeginChangeCheck();
                    float radius = Handles.DoSimpleRadiusHandle(Quaternion.identity, Vector3.zero, shapeModule.radius, false, shapeModule.arc, allowGizmoEditing);
                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoSphere);
                        shapeModule.radius = radius;
                    }

                    // Texture
                    Matrix4x4 textureTransform = combinedMatrix * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one * shapeModule.radius * 2.0f);
                    OnSceneViewTextureGUI(shapeModule, s_SphereMesh, false, s_SphereTextureMaterial, textureTransform);
                }
                else if (type == ParticleSystemShapeType.Circle)
                {
                    // Thickness
                    EditorGUI.BeginChangeCheck();

                    s_ArcHandle.angle = shapeModule.arc;
                    s_ArcHandle.radius = shapeModule.radius * (1.0f - shapeModule.radiusThickness);
                    s_ArcHandle.SetColorWithRadiusHandle(s_ShapeGizmoThicknessTint, 0f);
                    s_ArcHandle.radiusHandleColor *= gizmoEditingColor;
                    s_ArcHandle.angleHandleColor = Color.clear;

                    using (new Handles.DrawingScope(Handles.matrix * s_ArcHandleOffsetMatrix))
                        s_ArcHandle.DrawHandle();

                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoCircleThickness);
                        shapeModule.radiusThickness = 1.0f - (s_ArcHandle.radius / shapeModule.radius);
                    }

                    // Circle
                    EditorGUI.BeginChangeCheck();

                    s_ArcHandle.radius = shapeModule.radius;
                    s_ArcHandle.SetColorWithRadiusHandle(Color.white, 0f);
                    s_ArcHandle.radiusHandleColor *= gizmoEditingColor;
                    s_ArcHandle.angleHandleColor *= gizmoEditingColor;

                    using (new Handles.DrawingScope(Handles.matrix * s_ArcHandleOffsetMatrix))
                        s_ArcHandle.DrawHandle();

                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoCircle);
                        shapeModule.radius = s_ArcHandle.radius;
                        shapeModule.arc = s_ArcHandle.angle;
                    }

                    // Texture
                    Matrix4x4 textureTransform = combinedMatrix * Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(90.0f, 0.0f, 180.0f), Vector3.one * shapeModule.radius * 2.0f);
                    OnSceneViewTextureGUI(shapeModule, s_CircleMesh, true, s_TextureMaterial, textureTransform);
                }
                else if (type == ParticleSystemShapeType.Hemisphere)
                {
                    // Thickness
                    Handles.color *= s_ShapeGizmoThicknessTint;
                    EditorGUI.BeginChangeCheck();
                    float radiusThickness = Handles.DoSimpleRadiusHandle(Quaternion.identity, Vector3.zero, shapeModule.radius * (1.0f - shapeModule.radiusThickness), true, shapeModule.arc, allowGizmoEditing);
                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoHemisphereThickness);
                        shapeModule.radiusThickness = 1.0f - (radiusThickness / shapeModule.radius);
                    }

                    // Hemisphere
                    Handles.color = s_GizmoColor;
                    EditorGUI.BeginChangeCheck();
                    float radius = Handles.DoSimpleRadiusHandle(Quaternion.identity, Vector3.zero, shapeModule.radius, true, shapeModule.arc, allowGizmoEditing);
                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoHemisphere);
                        shapeModule.radius = radius;
                    }

                    // Texture
                    Matrix4x4 textureTransform = combinedMatrix * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one * shapeModule.radius * 2.0f);
                    OnSceneViewTextureGUI(shapeModule, s_HemisphereMesh, false, s_SphereTextureMaterial, textureTransform);
                }
                else if (type == ParticleSystemShapeType.Cone)
                {
                    Handles.ConeHandles coneHandlesMask = allowGizmoEditing ? Handles.ConeHandles.All : 0;

                    // Thickness
                    Handles.color *= s_ShapeGizmoThicknessTint;
                    EditorGUI.BeginChangeCheck();
                    float angleThickness = Mathf.Lerp(shapeModule.angle, 0.0f, shapeModule.radiusThickness);
                    Vector3 radiusThicknessAngleRange = new Vector3(shapeModule.radius * (1.0f - shapeModule.radiusThickness), angleThickness, mainModule.startSpeedMultiplier);
                    radiusThicknessAngleRange = Handles.ConeFrustrumHandle(Quaternion.identity, Vector3.zero, radiusThicknessAngleRange, Handles.ConeHandles.Radius & coneHandlesMask);
                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoConeThickness);
                        shapeModule.radiusThickness = 1.0f - (radiusThicknessAngleRange.x / shapeModule.radius);
                    }

                    // Cone
                    Handles.color = s_GizmoColor;
                    EditorGUI.BeginChangeCheck();
                    Vector3 radiusAngleRange = new Vector3(shapeModule.radius, shapeModule.angle, mainModule.startSpeedMultiplier);
                    radiusAngleRange = Handles.ConeFrustrumHandle(Quaternion.identity, Vector3.zero, radiusAngleRange, coneHandlesMask);
                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoCone);
                        shapeModule.radius = radiusAngleRange.x;
                        shapeModule.angle = radiusAngleRange.y;
                        mainModule.startSpeedMultiplier = radiusAngleRange.z;
                    }

                    // Texture
                    Matrix4x4 textureTransform = combinedMatrix * Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(90.0f, 0.0f, 180.0f), Vector3.one * shapeModule.radius * 2.0f);
                    OnSceneViewTextureGUI(shapeModule, s_CircleMesh, true, s_TextureMaterial, textureTransform);
                }
                else if (type == ParticleSystemShapeType.ConeVolume)
                {
                    Handles.ConeHandles coneHandlesMask = allowGizmoEditing ? Handles.ConeHandles.All : 0;

                    // Thickness
                    Handles.color *= s_ShapeGizmoThicknessTint;
                    EditorGUI.BeginChangeCheck();
                    float angleThickness = Mathf.Lerp(shapeModule.angle, 0.0f, shapeModule.radiusThickness);
                    Vector3 radiusThicknessAngleLength = new Vector3(shapeModule.radius * (1.0f - shapeModule.radiusThickness), angleThickness, shapeModule.length);
                    radiusThicknessAngleLength = Handles.ConeFrustrumHandle(Quaternion.identity, Vector3.zero, radiusThicknessAngleLength, Handles.ConeHandles.Radius & coneHandlesMask);
                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoConeVolumeThickness);
                        shapeModule.radiusThickness = 1.0f - (radiusThicknessAngleLength.x / shapeModule.radius);
                    }

                    // Cone
                    Handles.color = s_GizmoColor;
                    EditorGUI.BeginChangeCheck();
                    Vector3 radiusAngleLength = new Vector3(shapeModule.radius, shapeModule.angle, shapeModule.length);
                    radiusAngleLength = Handles.ConeFrustrumHandle(Quaternion.identity, Vector3.zero, radiusAngleLength, coneHandlesMask);
                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoConeVolume);
                        shapeModule.radius = radiusAngleLength.x;
                        shapeModule.angle = radiusAngleLength.y;
                        shapeModule.length = radiusAngleLength.z;
                    }

                    // Texture
                    Matrix4x4 textureTransform = combinedMatrix * Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(90.0f, 0.0f, 180.0f), Vector3.one * shapeModule.radius * 2.0f);
                    OnSceneViewTextureGUI(shapeModule, s_CircleMesh, true, s_TextureMaterial, textureTransform);
                }
                else if (type == ParticleSystemShapeType.Box || type == ParticleSystemShapeType.BoxShell || type == ParticleSystemShapeType.BoxEdge)
                {
                    EditorGUI.BeginChangeCheck();

                    s_BoxBoundsHandle.center = Vector3.zero;
                    s_BoxBoundsHandle.size = shapeModule.scale;
                    s_BoxBoundsHandle.handleColor = gizmoEditingColor;
                    s_BoxBoundsHandle.DrawHandle();

                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoBox);
                        shapeModule.scale = s_BoxBoundsHandle.size;
                    }

                    Matrix4x4 textureTransform = combinedMatrix * Matrix4x4.TRS(new Vector3(0.0f, 0.0f, -s_BoxBoundsHandle.size.z * 0.5f), Quaternion.identity, s_BoxBoundsHandle.size);
                    OnSceneViewTextureGUI(shapeModule, s_QuadMesh, true, s_TextureMaterial, textureTransform);
                }
                else if (type == ParticleSystemShapeType.Donut)
                {
                    // Radius
                    EditorGUI.BeginChangeCheck();

                    s_ArcHandle.radius = shapeModule.radius;
                    s_ArcHandle.angle = shapeModule.arc;
                    s_ArcHandle.SetColorWithRadiusHandle(Color.white * gizmoEditingColor, 0f);
                    s_ArcHandle.wireframeColor = Color.clear;

                    using (new Handles.DrawingScope(Handles.matrix * s_ArcHandleOffsetMatrix))
                        s_ArcHandle.DrawHandle();

                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoDonut);
                        shapeModule.radius = s_ArcHandle.radius;
                        shapeModule.arc = s_ArcHandle.angle;
                    }

                    // Donut extents
                    using (new Handles.DrawingScope(Handles.matrix * s_ArcHandleOffsetMatrix))
                    {
                        float excessAngle = shapeModule.arc % 360f;
                        float angle = Mathf.Abs(shapeModule.arc) >= 360f ? 360f : excessAngle;

                        Handles.DrawWireArc(new Vector3(0.0f, shapeModule.donutRadius, 0.0f), Vector3.up, Vector3.forward, angle, shapeModule.radius);
                        Handles.DrawWireArc(new Vector3(0.0f, -shapeModule.donutRadius, 0.0f), Vector3.up, Vector3.forward, angle, shapeModule.radius);
                        Handles.DrawWireArc(Vector3.zero, Vector3.up, Vector3.forward, angle, shapeModule.radius + shapeModule.donutRadius);
                        Handles.DrawWireArc(Vector3.zero, Vector3.up, Vector3.forward, angle, shapeModule.radius - shapeModule.donutRadius);

                        if (shapeModule.arc != 360.0f)
                        {
                            Quaternion arcRotation = Quaternion.AngleAxis(shapeModule.arc, Vector3.up);
                            Vector3 capCenter = arcRotation * Vector3.forward * shapeModule.radius;
                            Handles.DrawWireDisc(capCenter, arcRotation * Vector3.right, shapeModule.donutRadius);
                        }
                    }

                    // Donut thickness
                    s_SphereBoundsHandle.axes = PrimitiveBoundsHandle.Axes.X | PrimitiveBoundsHandle.Axes.Y;
                    s_SphereBoundsHandle.radius = shapeModule.donutRadius * (1.0f - shapeModule.radiusThickness);
                    s_SphereBoundsHandle.center = Vector3.zero;
                    s_SphereBoundsHandle.SetColor(s_ShapeGizmoThicknessTint);
                    s_SphereBoundsHandle.handleColor *= gizmoEditingColor;

                    const float handleInterval = 90.0f;
                    int numOuterRadii = Mathf.Max(1, (int)Mathf.Ceil(shapeModule.arc / handleInterval));
                    Matrix4x4 donutRadiusStartMatrix = Matrix4x4.TRS(new Vector3(shapeModule.radius, 0.0f, 0.0f), Quaternion.Euler(90.0f, 0.0f, 0.0f), Vector3.one);

                    for (int i = 0; i < numOuterRadii; i++)
                    {
                        EditorGUI.BeginChangeCheck();
                        using (new Handles.DrawingScope(Handles.matrix * (Matrix4x4.Rotate(Quaternion.Euler(0.0f, 0.0f, handleInterval * i)) * donutRadiusStartMatrix)))
                            s_SphereBoundsHandle.DrawHandle();
                        if (EditorGUI.EndChangeCheck())
                        {
                            Undo.RecordObject(ps, s_Texts.undoDonutRadiusThickness);
                            shapeModule.radiusThickness = 1.0f - (s_SphereBoundsHandle.radius / shapeModule.donutRadius);
                        }
                    }

                    // Donut radius
                    s_SphereBoundsHandle.radius = shapeModule.donutRadius;
                    s_SphereBoundsHandle.SetColor(Color.white);
                    s_SphereBoundsHandle.handleColor *= gizmoEditingColor;

                    for (int i = 0; i < numOuterRadii; i++)
                    {
                        EditorGUI.BeginChangeCheck();
                        using (new Handles.DrawingScope(Handles.matrix * (Matrix4x4.Rotate(Quaternion.Euler(0.0f, 0.0f, handleInterval * i)) * donutRadiusStartMatrix)))
                            s_SphereBoundsHandle.DrawHandle();
                        if (EditorGUI.EndChangeCheck())
                        {
                            Undo.RecordObject(ps, s_Texts.undoDonutRadius);
                            shapeModule.donutRadius = s_SphereBoundsHandle.radius;
                        }
                    }

                    // Texture
                    Matrix4x4 textureTransform = combinedMatrix * Matrix4x4.TRS(new Vector3(shapeModule.radius, 0.0f, 0.0f), Quaternion.Euler(180.0f, 0.0f, 180.0f), Vector3.one * shapeModule.donutRadius * 2.0f);
                    OnSceneViewTextureGUI(shapeModule, s_CircleMesh, true, s_TextureMaterial, textureTransform);
                }
                else if (type == ParticleSystemShapeType.SingleSidedEdge)
                {
                    EditorGUI.BeginChangeCheck();
                    float radius = Handles.DoSimpleEdgeHandle(Quaternion.identity, Vector3.zero, shapeModule.radius, allowGizmoEditing);
                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoEdge);
                        shapeModule.radius = radius;
                    }
                }
                else if (type == ParticleSystemShapeType.Mesh)
                {
                    Mesh mesh = shapeModule.mesh;
                    if (mesh)
                    {
                        bool orgWireframeMode = GL.wireframe;
                        GL.wireframe = true;
                        s_Material.SetPass(0);
                        Graphics.DrawMeshNow(mesh, combinedMatrix);
                        GL.wireframe = orgWireframeMode;

                        OnSceneViewTextureGUI(shapeModule, mesh, false, s_TextureMaterial, combinedMatrix);
                    }
                }
                else if (type == ParticleSystemShapeType.Rectangle)
                {
                    EditorGUI.BeginChangeCheck();

                    s_BoxBoundsHandle.center = Vector3.zero;
                    s_BoxBoundsHandle.size = new Vector3(shapeModule.scale.x, shapeModule.scale.y, 0.0f);
                    s_BoxBoundsHandle.handleColor = gizmoEditingColor;
                    s_BoxBoundsHandle.DrawHandle();

                    if (EditorGUI.EndChangeCheck())
                    {
                        Undo.RecordObject(ps, s_Texts.undoRectangle);
                        shapeModule.scale = new Vector3(s_BoxBoundsHandle.size.x, s_BoxBoundsHandle.size.y, 0.0f);
                    }

                    OnSceneViewTextureGUI(shapeModule, s_QuadMesh, true, s_TextureMaterial, combinedMatrix * Matrix4x4.Scale(s_BoxBoundsHandle.size));
                }
                else if (type == ParticleSystemShapeType.Sprite)
                {
                    Sprite sprite = shapeModule.sprite;
                    if (sprite)
                    {
                        if (!s_SpriteMesh)
                        {
                            s_SpriteMesh = new Mesh();
                            s_SpriteMesh.name = "ParticleSpritePreview";
                            s_SpriteMesh.hideFlags |= HideFlags.HideAndDontSave;
                        }

                        s_SpriteMesh.vertices = Array.ConvertAll(sprite.vertices, i => (Vector3)i);
                        s_SpriteMesh.uv = sprite.uv;
                        s_SpriteMesh.triangles = Array.ConvertAll(sprite.triangles, i => (int)i);

                        bool orgWireframeMode = GL.wireframe;
                        GL.wireframe = true;
                        s_Material.SetPass(0);
                        Graphics.DrawMeshNow(s_SpriteMesh, combinedMatrix);
                        GL.wireframe = orgWireframeMode;

                        OnSceneViewTextureGUI(shapeModule, s_SpriteMesh, false, s_TextureMaterial, combinedMatrix);
                    }
                }
            }

            Handles.color = origCol;
            Handles.matrix = orgMatrix;
        }

        private static void OnSceneViewTextureGUI(ParticleSystem.ShapeModule shapeModule, Mesh mesh, bool twoSided, Material mat, Matrix4x4 transform)
        {
            Texture texture = shapeModule.texture;
            if (texture)
            {
                mat.SetPass(0);
                mat.SetTexture("_MainTex", texture);
                mat.SetColor("_Color", new Color(1.0f, 1.0f, 1.0f, 0.4f));
                mat.SetFloat("_ClipChannel", (int)shapeModule.textureClipChannel);
                mat.SetFloat("_ClipThreshold", shapeModule.textureClipThreshold);
                mat.SetFloat("_Cull", twoSided ? (float)CullMode.Off : (float)CullMode.Back);
                mat.SetFloat("_UVChannel", shapeModule.textureUVChannel);
                Graphics.DrawMeshNow(mesh, transform);
            }
        }

        override public void UpdateCullingSupportedString(ref string text)
        {
            bool animatedShape = false;

            foreach (ParticleSystem ps in m_ParticleSystemUI.m_ParticleSystems)
            {
                switch (ps.shape.shapeType)
                {
                    case ParticleSystemShapeType.Cone:
                    case ParticleSystemShapeType.ConeVolume:
                    case ParticleSystemShapeType.Donut:
                    case ParticleSystemShapeType.Circle:
                        animatedShape = (ps.shape.arcMode != ParticleSystemShapeMultiModeValue.Random);
                        break;
                    case ParticleSystemShapeType.SingleSidedEdge:
                        animatedShape = (ps.shape.radiusMode != ParticleSystemShapeMultiModeValue.Random);
                        break;
                    default:
                        break;
                }

                if (animatedShape)
                    break;
            }

            if (animatedShape)
                text += "\n\tAnimated shape emission is enabled.";
        }
    }
} // namespace UnityEditor
