public bool GenerateNodes(ChiselBlobAssetReference <NativeChiselSurfaceDefinition> surfaceDefinitionBlob, NativeList <GeneratedNode> nodes, Allocator allocator)
        {
            var generatedBrushMeshes = new NativeList <ChiselBlobAssetReference <BrushMeshBlob> >(nodes.Length, Allocator.Temp);

            try
            {
                generatedBrushMeshes.Resize(nodes.Length, NativeArrayOptions.ClearMemory);
                if (!BrushMeshFactory.GenerateSpiralStairs(generatedBrushMeshes,
                                                           ref this,
                                                           in surfaceDefinitionBlob,
                                                           allocator))
                {
                    for (int i = 0; i < generatedBrushMeshes.Length; i++)
                    {
                        if (generatedBrushMeshes[i].IsCreated)
                        {
                            generatedBrushMeshes[i].Dispose();
                        }
                        generatedBrushMeshes[i] = default;
                    }
                    return(false);
                }
                for (int i = 0; i < generatedBrushMeshes.Length; i++)
                {
                    nodes[i] = GeneratedNode.GenerateBrush(generatedBrushMeshes[i]);
                }

                // TODO: clean this up
                {
                    var subMeshIndex = TreadStart - CylinderSubMeshCount;
                    var node         = nodes[subMeshIndex];
                    node.operation      = CSGOperationType.Intersecting;
                    nodes[subMeshIndex] = node;

                    subMeshIndex        = RequiredSubMeshCount - CylinderSubMeshCount;
                    node                = nodes[subMeshIndex];
                    node.operation      = CSGOperationType.Intersecting;
                    nodes[subMeshIndex] = node;
                }

                if (HaveInnerCylinder)
                {
                    var subMeshIndex = TreadStart - 1;
                    var node         = nodes[subMeshIndex];
                    node.operation      = CSGOperationType.Subtractive;
                    nodes[subMeshIndex] = node;

                    subMeshIndex        = RequiredSubMeshCount - 1;
                    node                = nodes[subMeshIndex];
                    node.operation      = CSGOperationType.Subtractive;
                    nodes[subMeshIndex] = node;
                }

                return(true);
            }
            finally
            {
                generatedBrushMeshes.Dispose();
            }
        }
示例#2
0
        public static bool GenerateCapsule(ref ChiselBrushContainer brushContainer, ref ChiselCapsuleDefinition definition)
        {
            definition.Validate();
            Vector3[] vertices = null;
            if (!BrushMeshFactory.GenerateCapsuleVertices(ref definition, ref vertices))
            {
                return(false);
            }

            // TODO: share this with GenerateCapsuleVertices
            var bottomCap    = !definition.haveRoundedBottom;
            var topCap       = !definition.haveRoundedTop;
            var sides        = definition.sides;
            var segments     = definition.segments;
            var bottomVertex = definition.bottomVertex;
            var topVertex    = definition.topVertex;

            brushContainer.EnsureSize(1);

            return(BrushMeshFactory.GenerateSegmentedSubMesh(ref brushContainer.brushMeshes[0],
                                                             sides, segments,
                                                             vertices,
                                                             topCap, bottomCap,
                                                             topVertex, bottomVertex,
                                                             definition.surfaceDefinition));
        }
示例#3
0
        public static bool GenerateCapsule(ref BrushMesh brushMesh, ref ChiselCapsuleDefinition definition)
        {
            Vector3[] vertices = null;
            if (!BrushMeshFactory.GenerateCapsuleVertices(ref definition, ref vertices))
            {
                brushMesh.Clear();
                return(false);
            }

            // TODO: share this with GenerateCapsuleVertices
            var bottomCap    = !definition.haveRoundedBottom;
            var topCap       = !definition.haveRoundedTop;
            var sides        = definition.sides;
            var segments     = definition.segments;
            var bottomVertex = definition.bottomVertex;
            var topVertex    = definition.topVertex;

            if (!BrushMeshFactory.GenerateSegmentedSubMesh(ref brushMesh,
                                                           sides, segments,
                                                           vertices,
                                                           topCap, bottomCap,
                                                           topVertex, bottomVertex,
                                                           definition.surfaceDefinition))
            {
                brushMesh.Clear();
                return(false);
            }
            return(true);
        }
示例#4
0
        public static bool GenerateSphere(ref BrushMesh brushMesh, ref ChiselSphereDefinition definition)
        {
            definition.Validate();
            var transform = float4x4.TRS(Vector3.zero, quaternion.AxisAngle(new Vector3(0, 1, 0), definition.rotation), Vector3.one);

            return(BrushMeshFactory.GenerateSphere(ref brushMesh, definition.diameterXYZ, definition.offsetY, definition.generateFromCenter, transform, definition.horizontalSegments, definition.verticalSegments, definition.surfaceDefinition));
        }
示例#5
0
        public override void OnEdit(IChiselHandles handles)
        {
            var normal = Vector3.up;

            float3[] vertices = null;
            if (BrushMeshFactory.GenerateTorusVertices(this, ref vertices))
            {
                var baseColor = handles.color;
                handles.color = handles.GetStateColor(baseColor, false, false);
                DrawOutline(handles, this, vertices, lineMode: LineMode.ZTest);
                handles.color = handles.GetStateColor(baseColor, false, true);
                DrawOutline(handles, this, vertices, lineMode: LineMode.NoZTest);
                handles.color = baseColor;
            }

            var outerRadius = settings.outerDiameter * 0.5f;
            var innerRadius = settings.InnerDiameter * 0.5f;
            var topPoint    = normal * (settings.tubeHeight * 0.5f);
            var bottomPoint = normal * (-settings.tubeHeight * 0.5f);

            handles.DoRadiusHandle(ref outerRadius, normal, float3.zero);
            handles.DoRadiusHandle(ref innerRadius, normal, float3.zero);
            handles.DoDirectionHandle(ref bottomPoint, -normal);
            handles.DoDirectionHandle(ref topPoint, normal);
            if (handles.modified)
            {
                settings.outerDiameter = outerRadius * 2.0f;
                settings.InnerDiameter = innerRadius * 2.0f;
                settings.tubeHeight    = (topPoint.y - bottomPoint.y);
                // TODO: handle sizing down
            }
        }
示例#6
0
 public ChiselBlobAssetReference <BrushMeshBlob> GenerateMesh(ChiselBlobAssetReference <NativeChiselSurfaceDefinition> surfaceDefinitionBlob, Allocator allocator)
 {
     if (!BrushMeshFactory.CreateBox(bounds.Min, bounds.Max,
                                     in surfaceDefinitionBlob,
                                     out var newBrushMesh,
                                     allocator))
     {
         return(default);
示例#7
0
        public static bool GenerateSphere(ref ChiselBrushContainer brushContainer, ref ChiselSphereDefinition definition)
        {
            definition.Validate();

            brushContainer.EnsureSize(1);

            var transform = Matrix4x4.TRS(Vector3.zero, Quaternion.AngleAxis(definition.rotation, Vector3.up), Vector3.one);

            return(BrushMeshFactory.GenerateSphere(ref brushContainer.brushMeshes[0], definition.diameterXYZ, definition.offsetY, definition.generateFromCenter, transform, definition.horizontalSegments, definition.verticalSegments, definition.surfaceDefinition));
        }
        public static bool GenerateStadium(ref ChiselBrushContainer brushContainer, ref ChiselStadiumDefinition definition)
        {
            definition.Validate();
            Vector3[] vertices = null;
            if (!GenerateStadiumVertices(definition, ref vertices))
            {
                return(false);
            }

            brushContainer.EnsureSize(1);

            var surfaceIndices = new int[vertices.Length + 2];

            return(BrushMeshFactory.CreateExtrudedSubMesh(ref brushContainer.brushMeshes[0], definition.sides, surfaceIndices, 0, 1, vertices, definition.surfaceDefinition));
        }
        static                         Vector3[] vertices = null; // TODO: store this per instance? or just allocate every frame?

        public void OnEdit(IChiselHandles handles)
        {
            var baseColor = handles.color;
            var normal    = Vector3.up;

            if (BrushMeshFactory.GenerateHemisphereVertices(ref this, ref vertices))
            {
                handles.color = handles.GetStateColor(baseColor, false, false);
                DrawOutline(handles, this, vertices, lineMode: LineMode.ZTest);

                handles.color = handles.GetStateColor(baseColor, false, true);
                DrawOutline(handles, this, vertices, lineMode: LineMode.NoZTest);
                handles.color = baseColor;
            }


            var topPoint = normal * this.diameterXYZ.y;
            var radius2D = new Vector2(this.diameterXYZ.x, this.diameterXYZ.z) * 0.5f;

            if (this.diameterXYZ.y < 0)
            {
                normal = -normal;
            }
            bool previousModified;

            previousModified = handles.modified;
            {
                handles.color = baseColor;
                // TODO: make it possible to (optionally) size differently in x & z
                handles.DoRadiusHandle(ref radius2D.x, normal, Vector3.zero);

                {
                    var isTopBackfaced = false;          // TODO: how to do this?

                    handles.backfaced = isTopBackfaced;
                    handles.DoDirectionHandle(ref topPoint, normal);
                    handles.backfaced = false;
                }
            }
            if (previousModified != handles.modified)
            {
                var diameter = this.diameterXYZ;
                diameter.y       = topPoint.y;
                diameter.x       = radius2D.x * 2.0f;
                diameter.z       = radius2D.x * 2.0f;
                this.diameterXYZ = diameter;
            }
        }
示例#10
0
        public bool GenerateNodes(ChiselBlobAssetReference <NativeChiselSurfaceDefinition> surfaceDefinitionBlob, NativeList <GeneratedNode> nodes, Allocator allocator)
        {
            var generatedBrushMeshes = new NativeList <ChiselBlobAssetReference <BrushMeshBlob> >(nodes.Length, Allocator.Temp);

            try
            {
                generatedBrushMeshes.Resize(nodes.Length, NativeArrayOptions.ClearMemory);
                using var vertices = BrushMeshFactory.GenerateTorusVertices(outerDiameter,
                                                                            tubeWidth,
                                                                            tubeHeight,
                                                                            tubeRotation,
                                                                            startAngle,
                                                                            totalAngle,
                                                                            verticalSegments,
                                                                            horizontalSegments,
                                                                            fitCircle,
                                                                            Allocator.Temp);

                if (!BrushMeshFactory.GenerateTorus(generatedBrushMeshes,
                                                    in vertices,
                                                    verticalSegments,
                                                    horizontalSegments,
                                                    in surfaceDefinitionBlob,
                                                    allocator))
                {
                    for (int i = 0; i < generatedBrushMeshes.Length; i++)
                    {
                        if (generatedBrushMeshes[i].IsCreated)
                        {
                            generatedBrushMeshes[i].Dispose();
                        }
                        generatedBrushMeshes[i] = default;
                    }
                    return(false);
                }

                for (int i = 0; i < generatedBrushMeshes.Length; i++)
                {
                    nodes[i] = GeneratedNode.GenerateBrush(generatedBrushMeshes[i]);
                }
                return(true);
            }
            finally
            {
                generatedBrushMeshes.Dispose();
            }
        }
示例#11
0
        public static bool GenerateLinearStairs(ref ChiselBrushContainer brushContainer, ref ChiselLinearStairsDefinition definition)
        {
            definition.Validate();

            int requiredSubMeshCount = BrushMeshFactory.GetLinearStairsSubMeshCount(definition, definition.leftSide, definition.rightSide);

            if (requiredSubMeshCount == 0)
            {
                return(false);
            }

            int subMeshOffset = 0;

            brushContainer.EnsureSize(requiredSubMeshCount);

            return(GenerateLinearStairsSubMeshes(ref brushContainer, definition, definition.leftSide, definition.rightSide, subMeshOffset));
        }
        public static bool GenerateStadium(ref BrushMesh brushMesh, ref ChiselStadiumDefinition definition)
        {
            definition.Validate();
            Vector3[] vertices = null;
            if (!GenerateStadiumVertices(definition, ref vertices))
            {
                brushMesh.Clear();
                return(false);
            }

            var surfaceIndices = new int[vertices.Length + 2];

            if (!BrushMeshFactory.CreateExtrudedSubMesh(ref brushMesh, definition.sides, surfaceIndices, 0, 1, vertices, definition.surfaceDefinition))
            {
                brushMesh.Clear();
                return(false);
            }

            return(true);
        }
 public bool Generate(ref ChiselBrushContainer brushContainer)
 {
     return(BrushMeshFactory.GenerateCapsule(ref brushContainer, ref this));
 }
示例#14
0
 public bool Generate(ref ChiselBrushContainer brushContainer)
 {
     return(BrushMeshFactory.GenerateSpiralStairs(ref brushContainer, ref this));
 }
示例#15
0
        public void OnEdit(IChiselHandles handles)
        {
            var baseColor     = handles.color;
            var upVector      = Vector3.up;
            var rightVector   = Vector3.right;
            var forwardVector = Vector3.forward;

            Vector3[] vertices = null;
            if (BrushMeshFactory.GenerateStadiumVertices(this, ref vertices))
            {
                handles.color = handles.GetStateColor(baseColor, false, false);
                DrawOutline(handles, this, vertices, lineMode: LineMode.ZTest);

                handles.color = handles.GetStateColor(baseColor, false, true);
                DrawOutline(handles, this, vertices, lineMode: LineMode.NoZTest);
                handles.color = baseColor;
            }

            var height   = this.height;
            var length   = this.length;
            var diameter = this.diameter;
            var sides    = this.sides;

            var firstTopSide    = this.firstTopSide;
            var lastTopSide     = this.lastTopSide;
            var firstBottomSide = this.firstBottomSide;
            var lastBottomSide  = this.lastBottomSide;

            var haveRoundedTop    = this.haveRoundedTop;
            var haveRoundedBottom = this.haveRoundedBottom;
            var haveCenter        = this.haveCenter;
            var topLength         = this.topLength;
            var bottomLength      = this.bottomLength;


            var midY       = height * 0.5f;
            var halfLength = length * 0.5f;
            var midZ       = ((halfLength - (haveRoundedTop ? topLength : 0)) - (halfLength - (haveRoundedBottom ? bottomLength : 0))) * -0.5f;
            //	haveCenter ? ((vertices[firstTopSide].z + vertices[firstBottomSide].z) * 0.5f) : 0;

            var topPoint    = new Vector3(0, height, midZ);
            var bottomPoint = new Vector3(0, 0, midZ);
            var frontPoint  = new Vector3(0, midY, halfLength);
            var backPoint   = new Vector3(0, midY, -halfLength);
            var leftPoint   = new Vector3(diameter * 0.5f, midY, midZ);
            var rightPoint  = new Vector3(diameter * -0.5f, midY, midZ);

            {
                {
                    var isTopBackfaced = handles.IsSufaceBackFaced(topPoint, upVector);

                    handles.backfaced = isTopBackfaced;
                    handles.DoDirectionHandle(ref topPoint, upVector);
                    var topHasFocus = handles.lastHandleHadFocus;
                    handles.backfaced = false;
                    //if (this.haveRoundedTop)
                    {
                        var thickness = topHasFocus ? kCapLineThicknessSelected : kCapLineThickness;

                        handles.color = handles.GetStateColor(handles.color, topHasFocus, true);
                        handles.DrawLineLoop(vertices, sides, sides, lineMode: LineMode.NoZTest, thickness: thickness);
                        if (haveRoundedTop)
                        {
                            handles.DrawLine(vertices[sides + firstTopSide], vertices[sides + lastTopSide], lineMode: LineMode.NoZTest, thickness: kVertLineThickness);
                        }
                        if (haveRoundedBottom && haveCenter)
                        {
                            handles.DrawLine(vertices[sides + firstBottomSide], vertices[sides + lastBottomSide], lineMode: LineMode.NoZTest, thickness: kVertLineThickness);
                        }

                        handles.color = handles.GetStateColor(handles.color, topHasFocus, false);
                        handles.DrawLineLoop(vertices, sides, sides, lineMode: LineMode.ZTest, thickness: thickness);
                        if (haveRoundedTop)
                        {
                            handles.DrawLine(vertices[sides + firstTopSide], vertices[sides + lastTopSide], lineMode: LineMode.ZTest, thickness: kVertLineThickness);
                        }
                        if (haveRoundedBottom && haveCenter)
                        {
                            handles.DrawLine(vertices[sides + firstBottomSide], vertices[sides + lastBottomSide], lineMode: LineMode.ZTest, thickness: kVertLineThickness);
                        }
                    }
                }

                {
                    var isBottomBackfaced = handles.IsSufaceBackFaced(bottomPoint, -upVector);

                    handles.backfaced = isBottomBackfaced;
                    handles.DoDirectionHandle(ref bottomPoint, -upVector);
                    var bottomHasFocus = handles.lastHandleHadFocus;
                    handles.backfaced = false;
                    //if (this.haveRoundedBottom)
                    {
                        var thickness = bottomHasFocus ? kCapLineThicknessSelected : kCapLineThickness;

                        handles.color = handles.GetStateColor(baseColor, bottomHasFocus, true);
                        handles.DrawLineLoop(vertices, 0, sides, lineMode: LineMode.NoZTest, thickness: thickness);
                        if (haveRoundedTop)
                        {
                            handles.DrawLine(vertices[firstTopSide], vertices[lastTopSide], lineMode: LineMode.NoZTest, thickness: kVertLineThickness);
                        }
                        if (haveRoundedBottom && haveCenter)
                        {
                            handles.DrawLine(vertices[firstBottomSide], vertices[lastBottomSide], lineMode: LineMode.NoZTest, thickness: kVertLineThickness);
                        }

                        handles.color = handles.GetStateColor(baseColor, bottomHasFocus, false);
                        handles.DrawLineLoop(vertices, 0, sides, lineMode: LineMode.ZTest, thickness: thickness);
                        if (haveRoundedTop)
                        {
                            handles.DrawLine(vertices[firstTopSide], vertices[lastTopSide], lineMode: LineMode.ZTest, thickness: kVertLineThickness);
                        }
                        if (haveRoundedBottom && haveCenter)
                        {
                            handles.DrawLine(vertices[firstBottomSide], vertices[lastBottomSide], lineMode: LineMode.ZTest, thickness: kVertLineThickness);
                        }
                    }
                }

                {
                    var isTopBackfaced = handles.IsSufaceBackFaced(frontPoint, forwardVector);

                    handles.backfaced = isTopBackfaced;
                    handles.DoDirectionHandle(ref frontPoint, forwardVector);
                    handles.backfaced = false;
                }

                {
                    var isBottomBackfaced = handles.IsSufaceBackFaced(backPoint, -forwardVector);

                    handles.backfaced = isBottomBackfaced;
                    handles.DoDirectionHandle(ref backPoint, -forwardVector);
                    handles.backfaced = false;
                }

                {
                    var isTopBackfaced = handles.IsSufaceBackFaced(leftPoint, rightVector);

                    handles.backfaced = isTopBackfaced;
                    handles.DoDirectionHandle(ref leftPoint, rightVector);
                    handles.backfaced = false;
                }

                {
                    var isBottomBackfaced = handles.IsSufaceBackFaced(rightPoint, -rightVector);

                    handles.backfaced = isBottomBackfaced;
                    handles.DoDirectionHandle(ref rightPoint, -rightVector);
                    handles.backfaced = false;
                }
            }
            if (handles.modified)
            {
                this.height   = topPoint.y - bottomPoint.y;
                this.length   = Mathf.Max(0, frontPoint.z - backPoint.z);
                this.diameter = leftPoint.x - rightPoint.x;
                // TODO: handle sizing in some directions (needs to modify transformation?)
            }
        }
        static                         Vector3[] vertices = null; // TODO: store this per instance? or just allocate every frame?

        public void OnEdit(IChiselHandles handles)
        {
            var baseColor = handles.color;
            var normal    = Vector3.up;

            if (BrushMeshFactory.GenerateSphereVertices(this, ref vertices))
            {
                handles.color = handles.GetStateColor(baseColor, false, false);
                DrawOutline(handles, this, vertices, lineMode: LineMode.ZTest);

                handles.color = handles.GetStateColor(baseColor, false, true);
                DrawOutline(handles, this, vertices, lineMode: LineMode.NoZTest);
                handles.color = baseColor;
            }

            Vector3 center, topPoint, bottomPoint;

            if (!this.generateFromCenter)
            {
                center      = normal * (this.offsetY + (this.diameterXYZ.y * 0.5f));
                topPoint    = normal * (this.offsetY + this.diameterXYZ.y);
                bottomPoint = normal * (this.offsetY);
            }
            else
            {
                center      = normal * (this.offsetY);
                topPoint    = normal * (this.offsetY + (this.diameterXYZ.y * 0.5f));
                bottomPoint = normal * (this.offsetY + (this.diameterXYZ.y * -0.5f));
            }

            if (this.diameterXYZ.y < 0)
            {
                normal = -normal;
            }

            var radius2D = new Vector2(this.diameterXYZ.x, this.diameterXYZ.z) * 0.5f;

            {
                // TODO: make it possible to (optionally) size differently in x & z
                var radiusX = radius2D.x;
                handles.DoRadiusHandle(ref radiusX, normal, center);
                radius2D.x = radiusX;

                {
                    var isBottomBackfaced = false;       // TODO: how to do this?

                    handles.backfaced = isBottomBackfaced;
                    handles.DoDirectionHandle(ref bottomPoint, -normal);
                    handles.backfaced = false;
                }

                {
                    var isTopBackfaced = false;          // TODO: how to do this?

                    handles.backfaced = isTopBackfaced;
                    handles.DoDirectionHandle(ref topPoint, normal);
                    handles.backfaced = false;
                }
            }
            if (handles.modified)
            {
                var diameter = this.diameterXYZ;
                diameter.y       = topPoint.y - bottomPoint.y;
                diameter.x       = radius2D.x * 2.0f;
                diameter.z       = radius2D.x * 2.0f;
                this.offsetY     = bottomPoint.y;
                this.diameterXYZ = diameter;
                // TODO: handle sizing down (needs to modify transformation?)
            }
        }
示例#17
0
        static                         Vector3[] vertices = null; // TODO: store this per instance? or just allocate every frame?

        public void OnEdit(IChiselHandles handles)
        {
            var baseColor = handles.color;
            var normal    = Vector3.up;

            if (BrushMeshFactory.GenerateCapsuleVertices(ref this, ref vertices))
            {
                handles.color = handles.GetStateColor(baseColor, false, false);
                DrawOutline(handles, this, vertices, lineMode: LineMode.ZTest);

                handles.color = handles.GetStateColor(baseColor, false, true);
                DrawOutline(handles, this, vertices, lineMode: LineMode.NoZTest);

                handles.color = baseColor;
            }

            var topPoint    = normal * (this.offsetY + this.height);
            var bottomPoint = normal * (this.offsetY);
            var middlePoint = normal * (this.offsetY + (this.height * 0.5f));
            var radius2D    = new Vector2(this.diameterX, this.diameterZ) * 0.5f;

            var topHeight    = this.topHeight;
            var bottomHeight = this.bottomHeight;

            var maxTopHeight    = this.height - bottomHeight;
            var maxBottomHeight = this.height - topHeight;

            if (this.height < 0)
            {
                normal = -normal;
            }

            var prevModified = handles.modified;

            {
                handles.color = baseColor;
                // TODO: make it possible to (optionally) size differently in x & z
                var radius2Dx = radius2D.x;
                handles.DoRadiusHandle(ref radius2Dx, normal, middlePoint);
                radius2D.x = radius2Dx;

                {
                    var isTopBackfaced  = handles.IsSufaceBackFaced(topPoint, normal);
                    var topLoopHasFocus = false;
                    handles.backfaced = isTopBackfaced;
                    for (int j = this.sides - 1, i = 0; i < this.sides; j = i, i++)
                    {
                        var from = vertices[j + this.topVertexOffset];
                        var to   = vertices[i + this.topVertexOffset];

                        if (handles.DoEdgeHandle1DOffset(out var edgeOffset, UnitySceneExtensions.Axis.Y, from, to, renderLine: false))
                        {
                            topHeight = Mathf.Clamp(topHeight - edgeOffset, 0, maxTopHeight);
                        }
                        topLoopHasFocus = topLoopHasFocus || handles.lastHandleHadFocus;
                    }


                    handles.color = baseColor;
                    handles.DoDirectionHandle(ref topPoint, normal);
                    var topHasFocus = handles.lastHandleHadFocus;
                    handles.backfaced = false;

                    topLoopHasFocus = topLoopHasFocus || (topHasFocus && !this.haveRoundedTop);

                    var thickness = topLoopHasFocus ? kCapLineThicknessSelected : kCapLineThickness;

                    handles.color = handles.GetStateColor(baseColor, topLoopHasFocus, true);
                    handles.DrawLineLoop(vertices, this.topVertexOffset, this.sides, lineMode: LineMode.NoZTest, thickness: thickness);

                    handles.color = handles.GetStateColor(baseColor, topLoopHasFocus, false);
                    handles.DrawLineLoop(vertices, this.topVertexOffset, this.sides, lineMode: LineMode.ZTest, thickness: thickness);
                }

                {
                    var isBottomBackfaced  = handles.IsSufaceBackFaced(bottomPoint, -normal);
                    var bottomLoopHasFocus = false;
                    handles.backfaced = isBottomBackfaced;
                    for (int j = this.sides - 1, i = 0; i < this.sides; j = i, i++)
                    {
                        var from = vertices[j + this.bottomVertexOffset];
                        var to   = vertices[i + this.bottomVertexOffset];

                        if (handles.DoEdgeHandle1DOffset(out var edgeOffset, UnitySceneExtensions.Axis.Y, from, to, renderLine: false))
                        {
                            bottomHeight = Mathf.Clamp(bottomHeight + edgeOffset, 0, maxBottomHeight);
                        }
                        bottomLoopHasFocus = bottomLoopHasFocus || handles.lastHandleHadFocus;
                    }

                    handles.color = baseColor;
                    handles.DoDirectionHandle(ref bottomPoint, -normal);
                    var bottomHasFocus = handles.lastHandleHadFocus;
                    handles.backfaced = false;

                    bottomLoopHasFocus = bottomLoopHasFocus || (bottomHasFocus && !this.haveRoundedBottom);

                    var thickness = bottomLoopHasFocus ? kCapLineThicknessSelected : kCapLineThickness;

                    handles.color = handles.GetStateColor(baseColor, bottomLoopHasFocus, true);
                    handles.DrawLineLoop(vertices, this.bottomVertexOffset, this.sides, lineMode: LineMode.NoZTest, thickness: thickness);

                    handles.color = handles.GetStateColor(baseColor, bottomLoopHasFocus, false);
                    handles.DrawLineLoop(vertices, this.bottomVertexOffset, this.sides, lineMode: LineMode.ZTest, thickness: thickness);
                }
            }
            if (prevModified != handles.modified)
            {
                this.diameterX    = radius2D.x * 2.0f;
                this.height       = topPoint.y - bottomPoint.y;
                this.diameterZ    = radius2D.x * 2.0f;
                this.offsetY      = bottomPoint.y;
                this.topHeight    = topHeight;
                this.bottomHeight = bottomHeight;
                // TODO: handle sizing down (needs to modify transformation?)
            }
        }
        public override void OnEdit(IChiselHandles handles)
        {
            var normal       = Vector3.up;
            var topDirection = Vector3.forward;
            var lowDirection = Vector3.forward;

            var originalOuterDiameter = settings.outerDiameter;
            var originalInnerDiameter = settings.innerDiameter;
            var originalStartAngle    = settings.startAngle;
            var originalStepHeight    = settings.stepHeight;
            var originalRotation      = settings.rotation;
            var originalHeight        = settings.height;
            var originalOrigin        = settings.origin;
            var cylinderTop           = new BrushMeshFactory.ChiselCircleDefinition {
                diameterX = 1, diameterZ = 1, height = originalOrigin.y + originalHeight
            };
            var cylinderLow = new BrushMeshFactory.ChiselCircleDefinition {
                diameterX = 1, diameterZ = 1, height = originalOrigin.y
            };
            var originalTopPoint = normal * cylinderTop.height;
            var originalLowPoint = normal * cylinderLow.height;
            var originalMidPoint = (originalTopPoint + originalLowPoint) * 0.5f;

            var outerDiameter = originalOuterDiameter;
            var innerDiameter = originalInnerDiameter;
            var topPoint      = originalTopPoint;
            var lowPoint      = originalLowPoint;
            var midPoint      = originalMidPoint;
            var startAngle    = originalStartAngle;
            var rotation      = originalRotation;

            {
                var currRotation = startAngle + rotation;
                handles.DoRotatableLineHandle(ref startAngle, lowPoint, outerDiameter * 0.5f, normal, lowDirection, Vector3.Cross(normal, lowDirection));
                handles.DoRotatableLineHandle(ref currRotation, topPoint, outerDiameter * 0.5f, normal, topDirection, Vector3.Cross(normal, topDirection));
                if (handles.modified)
                {
                    rotation = currRotation - startAngle;
                }


                // TODO: properly show things as backfaced
                // TODO: temporarily show inner or outer diameter as disabled when resizing one or the other
                // TODO: FIXME: why aren't there any arrows?
                handles.DoDirectionHandle(ref topPoint, normal, snappingStep: originalStepHeight);
                topPoint.y = math.max(lowPoint.y + originalStepHeight, topPoint.y);
                handles.DoDirectionHandle(ref lowPoint, -normal, snappingStep: originalStepHeight);
                lowPoint.y = math.min(topPoint.y - originalStepHeight, lowPoint.y);

                float minOuterDiameter = innerDiameter + ChiselSpiralStairs.kMinStairsDepth;
                {
                    var outerRadius = outerDiameter * 0.5f;
                    handles.DoRadiusHandle(ref outerRadius, Vector3.up, topPoint, renderDisc: false);
                    handles.DoRadiusHandle(ref outerRadius, Vector3.up, lowPoint, renderDisc: false);
                    outerDiameter = math.max(minOuterDiameter, outerRadius * 2.0f);
                }

                float maxInnerDiameter = outerDiameter - ChiselSpiralStairs.kMinStairsDepth;
                {
                    var innerRadius = innerDiameter * 0.5f;
                    handles.DoRadiusHandle(ref innerRadius, Vector3.up, midPoint, renderDisc: false);
                    innerDiameter = math.min(maxInnerDiameter, innerRadius * 2.0f);
                }



                // TODO: somehow put this into a separate renderer
                cylinderTop.diameterZ = cylinderTop.diameterX = cylinderLow.diameterZ = cylinderLow.diameterX = originalInnerDiameter;
                BrushMeshFactory.GetConicalFrustumVertices(cylinderLow, cylinderTop, 0, settings.innerSegments, ref s_InnerVertices);

                cylinderTop.diameterZ = cylinderTop.diameterX = cylinderLow.diameterZ = cylinderLow.diameterX = originalOuterDiameter;
                BrushMeshFactory.GetConicalFrustumVertices(cylinderLow, cylinderTop, 0, settings.outerSegments, ref s_OuterVertices);

                var originalColor = handles.color;
                var color         = handles.color;
                var outlineColor  = Color.black;
                outlineColor.a = color.a;

                handles.color = outlineColor;
                {
                    var sides = settings.outerSegments;
                    for (int i = 0, j = sides - 1; i < sides; j = i, i++)
                    {
                        var t0 = s_OuterVertices[i];
                        var t1 = s_OuterVertices[j];
                        var b0 = s_OuterVertices[i + sides];
                        var b1 = s_OuterVertices[j + sides];

                        handles.DrawLine(t0, b0, thickness: 1.0f);
                        handles.DrawLine(t0, t1, thickness: 1.0f);
                        handles.DrawLine(b0, b1, thickness: 1.0f);
                    }
                }
                {
                    var sides = settings.innerSegments;
                    for (int i = 0, j = sides - 1; i < sides; j = i, i++)
                    {
                        var t0 = s_InnerVertices[i];
                        var t1 = s_InnerVertices[j];
                        var b0 = s_InnerVertices[i + sides];
                        var b1 = s_InnerVertices[j + sides];

                        handles.DrawLine(t0, b0, thickness: 1.0f);
                        handles.DrawLine(t0, t1, thickness: 1.0f);
                        handles.DrawLine(b0, b1, thickness: 1.0f);
                    }
                }

                handles.color = originalColor;
                {
                    var sides = settings.outerSegments;
                    for (int i = 0, j = sides - 1; i < sides; j = i, i++)
                    {
                        var t0 = s_OuterVertices[i];
                        var t1 = s_OuterVertices[j];
                        var b0 = s_OuterVertices[i + sides];
                        var b1 = s_OuterVertices[j + sides];

                        handles.DrawLine(t0, b0, thickness: 1.0f);
                        handles.DrawLine(t0, t1, thickness: 1.0f);
                        handles.DrawLine(b0, b1, thickness: 1.0f);
                    }
                }
                {
                    var sides = settings.innerSegments;
                    for (int i = 0, j = sides - 1; i < sides; j = i, i++)
                    {
                        var t0 = s_InnerVertices[i];
                        var t1 = s_InnerVertices[j];
                        var b0 = s_InnerVertices[i + sides];
                        var b1 = s_InnerVertices[j + sides];


                        handles.DrawLine(t0, b0, thickness: 1.0f);
                        handles.DrawLine(t0, t1, thickness: 1.0f);
                        handles.DrawLine(b0, b1, thickness: 1.0f);

                        var m0 = (t0 + b0) * 0.5f;
                        var m1 = (t1 + b1) * 0.5f;
                        handles.DrawLine(m0, m1, thickness: 2.0f);
                    }
                }
            }
            if (handles.modified)
            {
                settings.outerDiameter = outerDiameter;
                settings.innerDiameter = innerDiameter;
                settings.startAngle    = startAngle;
                settings.rotation      = rotation;

                if (topPoint != originalTopPoint)
                {
                    settings.height = topPoint.y - lowPoint.y;
                }

                if (lowPoint != originalLowPoint)
                {
                    settings.height = topPoint.y - lowPoint.y;
                    var newOrigin = originalOrigin;
                    newOrigin.y    += lowPoint.y - originalLowPoint.y;
                    settings.origin = newOrigin;
                }
            }
        }
        public static bool GenerateRevolvedShape(ref ChiselBrushContainer brushContainer, ref ChiselRevolvedShapeDefinition definition)
        {
            definition.Validate();


            var shapeVertices       = new List <Vector2>();
            var shapeSegmentIndices = new List <int>();

            BrushMeshFactory.GetPathVertices(definition.shape, definition.curveSegments, shapeVertices, shapeSegmentIndices);

            Vector2[][] polygonVerticesArray;
            int[][]     polygonIndicesArray;

            if (!Decomposition.ConvexPartition(shapeVertices, shapeSegmentIndices,
                                               out polygonVerticesArray,
                                               out polygonIndicesArray))
            {
                return(false);
            }

            // TODO: splitting it before we do the composition would be better
            var polygonVerticesList = polygonVerticesArray.ToList();

            for (int i = polygonVerticesList.Count - 1; i >= 0; i--)
            {
                SplitPolygon(polygonVerticesList, i);
            }

            var brushMeshesList      = new List <BrushMesh>();
            var horzSegments         = definition.revolveSegments;           //horizontalSegments;
            var horzDegreePerSegment = definition.totalAngle / horzSegments;


            // TODO: make this work when intersecting rotation axis
            //			1. split polygons along rotation axis
            //			2. if edge lies on rotation axis, make sure we don't create infinitely thin quad
            //					collapse this quad, or prevent this from happening
            // TODO: share this code with torus generator
            for (int p = 0; p < polygonVerticesList.Count; p++)
            {
                var polygonVertices = polygonVerticesList[p];
//				var segmentIndices		= polygonIndicesArray[p];
                var shapeSegments = polygonVertices.Length;

                var vertSegments     = polygonVertices.Length;
                var descriptionIndex = new int[2 + vertSegments];

                descriptionIndex[0] = 0;
                descriptionIndex[1] = 1;

                for (int v = 0; v < vertSegments; v++)
                {
                    descriptionIndex[v + 2] = 2;
                }

                var horzOffset = definition.startAngle;
                for (int h = 1, pr = 0; h < horzSegments + 1; pr = h, h++)
                {
                    var hDegree0        = (pr * horzDegreePerSegment) + horzOffset;
                    var hDegree1        = (h * horzDegreePerSegment) + horzOffset;
                    var rotation0       = quaternion.AxisAngle(Vector3.forward, hDegree0);
                    var rotation1       = quaternion.AxisAngle(Vector3.forward, hDegree1);
                    var subMeshVertices = new Vector3[vertSegments * 2];
                    for (int v = 0; v < vertSegments; v++)
                    {
                        subMeshVertices[v + vertSegments] = math.mul(rotation0, new Vector3(polygonVertices[v].x, 0, polygonVertices[v].y));
                        subMeshVertices[v] = math.mul(rotation1, new Vector3(polygonVertices[v].x, 0, polygonVertices[v].y));
                    }

                    var brushMesh = new BrushMesh();
                    if (!BrushMeshFactory.CreateExtrudedSubMesh(ref brushMesh, vertSegments, descriptionIndex, 0, 1, subMeshVertices, in definition.surfaceDefinition))
                    {
                        continue;
                    }

                    if (!brushMesh.Validate())
                    {
                        return(false);
                    }
                    brushMeshesList.Add(brushMesh);
                }
            }

            brushContainer.CopyFrom(brushMeshesList);
            return(true);
        }
        public static bool GeneratePathedStairs(ref ChiselBrushContainer brushContainer, ref ChiselPathedStairsDefinition definition)
        {
            definition.Validate();

            var shapeVertices       = new List <Vector2>();
            var shapeSegmentIndices = new List <int>();

            GetPathVertices(definition.shape, definition.curveSegments, shapeVertices, shapeSegmentIndices);

            var totalSubMeshCount = 0;

            for (int i = 0; i < shapeVertices.Count; i++)
            {
                if (i == 0 && !definition.shape.closed)
                {
                    continue;
                }

                var leftSide  = (!definition.shape.closed && i == 1) ? definition.stairs.leftSide  : StairsSideType.None;
                var rightSide = (!definition.shape.closed && i == shapeVertices.Count - 1) ? definition.stairs.rightSide : StairsSideType.None;

                totalSubMeshCount += BrushMeshFactory.GetLinearStairsSubMeshCount(definition.stairs, leftSide, rightSide);
            }
            if (totalSubMeshCount == 0)
            {
                return(false);
            }

            //			var stairDirections = definition.shape.closed ? shapeVertices.Count : (shapeVertices.Count - 1);

            brushContainer.EnsureSize(totalSubMeshCount);

            var depth  = definition.stairs.depth;
            var height = definition.stairs.height;

            var halfDepth  = depth * 0.5f;
            var halfHeight = height * 0.5f;

            int subMeshIndex = 0;

            for (int vi0 = shapeVertices.Count - 3, vi1 = shapeVertices.Count - 2, vi2 = shapeVertices.Count - 1, vi3 = 0; vi3 < shapeVertices.Count; vi0 = vi1, vi1 = vi2, vi2 = vi3, vi3++)
            {
                if (vi2 == 0 && !definition.shape.closed)
                {
                    continue;
                }

                // TODO: optimize this, we're probably redoing a lot of stuff for every iteration
                var v0 = shapeVertices[vi0];
                var v1 = shapeVertices[vi1];
                var v2 = shapeVertices[vi2];
                var v3 = shapeVertices[vi3];

                var m0 = (v0 + v1) * 0.5f;
                var m1 = (v1 + v2) * 0.5f;
                var m2 = (v2 + v3) * 0.5f;

                var d0 = (v1 - v0);
                var d1 = (v2 - v1);
                var d2 = (v3 - v2);

                var maxWidth0  = d0.magnitude;
                var maxWidth1  = d1.magnitude;
                var maxWidth2  = d2.magnitude;
                var halfWidth1 = d1 * 0.5f;

                d0 /= maxWidth0;
                d1 /= maxWidth1;
                d2 /= maxWidth2;

                var depthVector = new Vector3(d1.y, 0, -d1.x);
                var lineCenter  = new Vector3(m1.x, halfHeight, m1.y) - (depthVector * halfDepth);

                var depthVector0 = new Vector2(d0.y, -d0.x) * depth;
                var depthVector1 = new Vector2(d1.y, -d1.x) * depth;
                var depthVector2 = new Vector2(d2.y, -d2.x) * depth;

                m0 -= depthVector0;
                m1 -= depthVector1;
                m2 -= depthVector2;

                Vector2 output;
                var     leftShear  = Intersect(m1, d1, m0, d0, out output) ?  Vector2.Dot(d1, (output - (m1 - halfWidth1))) : 0;
                var     rightShear = Intersect(m1, d1, m2, d2, out output) ? -Vector2.Dot(d1, (output - (m1 + halfWidth1))) : 0;

                var transform = Matrix4x4.TRS(lineCenter,                                       // move to center of line
                                              Quaternion.LookRotation(depthVector, Vector3.up), // rotate to align with line
                                              Vector3.one);

                // set the width to the width of the line
                definition.stairs.width       = maxWidth1;
                definition.stairs.nosingWidth = 0;

                var leftSide     = (!definition.shape.closed && vi2 == 1) ? definition.stairs.leftSide  : StairsSideType.None;
                var rightSide    = (!definition.shape.closed && vi2 == shapeVertices.Count - 1) ? definition.stairs.rightSide : StairsSideType.None;
                var subMeshCount = BrushMeshFactory.GetLinearStairsSubMeshCount(definition.stairs, leftSide, rightSide);
                if (subMeshCount == 0)
                {
                    continue;
                }

                if (!BrushMeshFactory.GenerateLinearStairsSubMeshes(ref brushContainer, definition.stairs, leftSide, rightSide, subMeshIndex))
                {
                    return(false);
                }

                var halfWidth = maxWidth1 * 0.5f;
                for (int m = 0; m < subMeshCount; m++)
                {
                    var vertices = brushContainer.brushMeshes[subMeshIndex + m].vertices;
                    for (int v = 0; v < vertices.Length; v++)
                    {
                        // TODO: is it possible to put all of this in a single matrix?
                        // lerp the stairs to go from less wide to wider depending on the depth of the vertex
                        var depthFactor = 1.0f - ((vertices[v].z / definition.stairs.depth) + 0.5f);
                        var wideFactor  = (vertices[v].x / halfWidth) + 0.5f;
                        var scale       = (vertices[v].x / halfWidth);

                        // lerp the stairs width depending on if it's on the left or right side of the stairs
                        vertices[v].x = Mathf.Lerp(scale * (halfWidth - (rightShear * depthFactor)),
                                                   scale * (halfWidth - (leftShear * depthFactor)),
                                                   wideFactor);
                        vertices[v] = transform.MultiplyPoint(vertices[v]);
                    }
                }

                subMeshIndex += subMeshCount;
            }
            return(false);
        }
示例#21
0
 public bool Generate(ref ChiselBrushContainer brushContainer)
 {
     return(BrushMeshFactory.GenerateRevolvedShape(ref brushContainer, ref this));
 }
示例#22
0
        public static bool GenerateLinearStairsSubMeshes(ref ChiselBrushContainer brushContainer, ChiselLinearStairsDefinition definition, StairsSideType leftSideDefinition, StairsSideType rightSideDefinition, int subMeshOffset = 0)
        {
            // TODO: properly assign all materials

            if (definition.surfaceDefinition.surfaces.Length != (int)ChiselLinearStairsDefinition.SurfaceSides.TotalSides)
            {
                return(false);
            }

            // TODO: implement smooth riser-type

            const float kEpsilon = 0.001f;

            // TODO: put these values in a shared location since they need to match in multiple locations

            var treadHeight   = (definition.treadHeight < kEpsilon) ? 0 : definition.treadHeight;
            var riserType     = (treadHeight == 0 && definition.riserType == StairsRiserType.ThinRiser) ? StairsRiserType.ThickRiser : definition.riserType;
            var leftSideType  = (riserType == StairsRiserType.None && definition.leftSide == StairsSideType.Up) ? StairsSideType.DownAndUp : leftSideDefinition;
            var rightSideType = (riserType == StairsRiserType.None && definition.rightSide == StairsSideType.Up) ? StairsSideType.DownAndUp : rightSideDefinition;

            if (riserType == StairsRiserType.Smooth)
            {
                switch (leftSideType)
                {
                case StairsSideType.Up: leftSideType = StairsSideType.DownAndUp; break;

                case StairsSideType.None: leftSideType = StairsSideType.Down; break;
                }
                switch (rightSideType)
                {
                case StairsSideType.Up: rightSideType = StairsSideType.DownAndUp; break;

                case StairsSideType.None: rightSideType = StairsSideType.Down; break;
                }
            }
            var boundsMin = definition.bounds.min;
            var boundsMax = definition.bounds.max;

            if (boundsMin.y > boundsMax.y)
            {
                var t = boundsMin.y; boundsMin.y = boundsMax.y; boundsMax.y = t;
            }
            if (boundsMin.x > boundsMax.x)
            {
                var t = boundsMin.x; boundsMin.x = boundsMax.x; boundsMax.x = t;
            }
            if (boundsMin.z > boundsMax.z)
            {
                var t = boundsMin.z; boundsMin.z = boundsMax.z; boundsMax.z = t;
            }

            var haveRiser        = riserType != StairsRiserType.None;
            var haveLeftSideDown = riserType != StairsRiserType.FillDown &&
                                   (leftSideType == StairsSideType.Down || leftSideType == StairsSideType.DownAndUp);
            var haveLeftSideUp    = (leftSideType == StairsSideType.Up || leftSideType == StairsSideType.DownAndUp);
            var haveRightSideDown = riserType != StairsRiserType.FillDown &&
                                    (rightSideType == StairsSideType.Down || rightSideType == StairsSideType.DownAndUp);
            var haveRightSideUp = (rightSideType == StairsSideType.Up || rightSideType == StairsSideType.DownAndUp);
            var sideWidth       = definition.sideWidth;
            var sideHeight      = definition.sideHeight;
            var leftSideDepth   = (haveLeftSideDown) ? definition.sideDepth : 0;
            var rightSideDepth  = (haveRightSideDown) ? definition.sideDepth : 0;
            var thickRiser      = riserType == StairsRiserType.ThickRiser || riserType == StairsRiserType.Smooth;
            var riserDepth      = (haveRiser && !thickRiser) ? definition.riserDepth : 0;

            var stepCount   = definition.StepCount;
            var offsetZ     = (definition.StepDepthOffset < kEpsilon) ? 0 : definition.StepDepthOffset;
            var offsetY     = definition.plateauHeight;
            var nosingDepth = definition.nosingDepth;

            var haveTread   = (treadHeight >= kEpsilon);
            var haveTopSide = (sideHeight > kEpsilon);

            var leftNosingWidth     = haveLeftSideUp ? -sideWidth : definition.nosingWidth;
            var rightNosingWidth    = haveRightSideUp ? -sideWidth : definition.nosingWidth;
            var leftTopNosingWidth  = (haveLeftSideUp && (!haveTopSide)) ? definition.nosingWidth : leftNosingWidth;
            var rightTopNosingWidth = (haveRightSideUp && (!haveTopSide)) ? definition.nosingWidth : rightNosingWidth;

            var subMeshCount = 0; if (haveRiser)
            {
                subMeshCount = stepCount;
            }
            var startTread = subMeshCount; if (haveTread)
            {
                subMeshCount += stepCount;
            }
            var startLeftSideDown = subMeshCount; if (haveLeftSideDown)
            {
                subMeshCount += stepCount;
            }
            var startRightSideDown = subMeshCount; if (haveRightSideDown)
            {
                subMeshCount += stepCount;
            }
            var startLeftSideUp = subMeshCount; if (haveLeftSideUp)
            {
                subMeshCount += (stepCount - 1) + (haveTopSide ? 1 : 0) + 1;                                                        //(haveLeftSideDown  ? 0 : 1);
            }
            var startRightSideUp = subMeshCount; if (haveRightSideUp)
            {
                subMeshCount += (stepCount - 1) + (haveTopSide ? 1 : 0) + 1;                                                         //(haveRightSideDown ? 0 : 1);
            }
            var stepOffset = new Vector3(0, -definition.stepHeight, definition.stepDepth);

            if (stepCount > 0)
            {
                if (haveRiser)
                {
                    var min = boundsMin;
                    var max = boundsMax;
                    max.z = min.z + definition.StepDepthOffset + definition.stepDepth;
                    if (riserType != StairsRiserType.FillDown)
                    {
                        if (riserType == StairsRiserType.ThinRiser)
                        {
                            min.z = max.z - riserDepth;
                        }
                        else
                        {
                            min.z = min.z + definition.StepDepthOffset;
                        }
                        if (thickRiser)
                        {
                            min.z -= offsetZ;
                        }
                    }
                    min.y  = max.y - definition.stepHeight;
                    min.y -= treadHeight;
                    max.y -= treadHeight;
                    min.x += haveRightSideUp ? sideWidth : 0;
                    max.x -= haveLeftSideUp ? sideWidth : 0;
                    var extrusion = new Vector3(max.x - min.x, 0, 0);
                    for (int i = 0; i < stepCount; i++)
                    {
                        if (i == 1 &&
                            thickRiser)
                        {
                            min.z += offsetZ;
                        }
                        if (i == stepCount - 1)
                        {
                            min.y += treadHeight - offsetY;
                        }

                        Vector3[] vertices;
                        if (i == 0 || riserType != StairsRiserType.Smooth)
                        {
                            vertices = new[] {
                                new Vector3(min.x, min.y, min.z),                   // 0
                                new Vector3(min.x, min.y, max.z),                   // 1
                                new Vector3(min.x, max.y, max.z),                   // 2
                                new Vector3(min.x, max.y, min.z),                   // 3
                            };
                        }
                        else
                        {
                            vertices = new[] {
                                new Vector3(min.x, min.y, min.z),                        // 0
                                new Vector3(min.x, min.y, max.z),                        // 1
                                new Vector3(min.x, max.y, max.z),                        // 2
                                new Vector3(min.x, max.y, min.z - definition.stepDepth), // 3
                            };
                        }

                        BrushMeshFactory.CreateExtrudedSubMesh(ref brushContainer.brushMeshes[subMeshOffset + i], vertices, extrusion,
                                                               new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this
                                                               definition.surfaceDefinition);

                        if (riserType != StairsRiserType.FillDown)
                        {
                            min.z += definition.stepDepth;
                        }
                        max.z += definition.stepDepth;
                        min.y -= definition.stepHeight;
                        max.y -= definition.stepHeight;
                    }
                }
                if (haveTread)
                {
                    var min = new Vector3(boundsMin.x + sideWidth, boundsMax.y - definition.treadHeight, boundsMin.z);
                    var max = new Vector3(boundsMax.x - sideWidth, boundsMax.y, boundsMin.z + definition.StepDepthOffset + definition.stepDepth + nosingDepth);
                    for (int i = 0; i < stepCount; i++)
                    {
                        min.x = boundsMin.x - ((i == 0) ? rightTopNosingWidth : rightNosingWidth);
                        max.x = boundsMax.x + ((i == 0) ? leftTopNosingWidth : leftNosingWidth);
                        if (i == 1)
                        {
                            min.z = max.z - (definition.stepDepth + nosingDepth);
                        }
                        var vertices = new[] {
                            new Vector3(min.x, min.y, min.z),                       // 0
                            new Vector3(min.x, min.y, max.z),                       // 1
                            new Vector3(min.x, max.y, max.z),                       // 2
                            new Vector3(min.x, max.y, min.z),                       // 3
                        };
                        var extrusion = new Vector3(max.x - min.x, 0, 0);
                        BrushMeshFactory.CreateExtrudedSubMesh(ref brushContainer.brushMeshes[subMeshOffset + startTread + i], vertices, extrusion,
                                                               new int[] { 0, 1, 2, 2, 2, 2 }, // TODO: fix this
                                                               definition.surfaceDefinition);
                        min += stepOffset;
                        max += stepOffset;
                    }
                }
                if (haveLeftSideDown)
                {
                    var min = new Vector3(boundsMax.x - sideWidth, boundsMax.y - definition.stepHeight - definition.treadHeight, boundsMin.z + definition.StepDepthOffset);
                    var max = new Vector3(boundsMax.x, boundsMax.y - definition.treadHeight, boundsMin.z + definition.StepDepthOffset + definition.stepDepth);

                    var extrusion  = new Vector3(sideWidth, 0, 0);
                    var extraDepth = (thickRiser ? definition.stepDepth : riserDepth) + leftSideDepth;
                    var maxDepth   = boundsMin.z;

                    GenerateBottomRamp(ref brushContainer, subMeshOffset + startLeftSideDown, stepCount, min, max, extrusion, riserType, definition.stepDepth - riserDepth, extraDepth, maxDepth, definition, definition.surfaceDefinition);
                }
                if (haveRightSideDown)
                {
                    var min = new Vector3(boundsMin.x, boundsMax.y - definition.stepHeight - definition.treadHeight, boundsMin.z + definition.StepDepthOffset);
                    var max = new Vector3(boundsMin.x + sideWidth, boundsMax.y - definition.treadHeight, boundsMin.z + definition.StepDepthOffset + definition.stepDepth);

                    var extrusion  = new Vector3(sideWidth, 0, 0);
                    var extraDepth = (thickRiser ? definition.stepDepth : riserDepth) + rightSideDepth;
                    var maxDepth   = boundsMin.z;

                    GenerateBottomRamp(ref brushContainer, subMeshOffset + startRightSideDown, stepCount, min, max, extrusion, riserType, definition.stepDepth - riserDepth, extraDepth, maxDepth, definition, definition.surfaceDefinition);
                }
                if (haveLeftSideUp)
                {
                    var min        = new Vector3(boundsMax.x - sideWidth, boundsMax.y - definition.treadHeight - definition.stepHeight, boundsMin.z + definition.StepDepthOffset + definition.stepDepth);
                    var max        = new Vector3(boundsMax.x, boundsMax.y - definition.treadHeight, boundsMin.z + definition.StepDepthOffset + definition.stepDepth + definition.stepDepth);
                    var extrusion  = new Vector3(sideWidth, 0, 0);
                    var extraDepth = (thickRiser ? definition.stepDepth : riserDepth) + leftSideDepth;
                    var maxDepth   = boundsMin.z;

                    GenerateTopRamp(ref brushContainer, subMeshOffset + startLeftSideUp, stepCount - 1, min, max, extrusion, sideHeight, extraDepth, maxDepth, riserType, definition, definition.surfaceDefinition);

                    if (haveTopSide)
                    {
                        var vertices = new[] {
                            new Vector3(min.x, max.y + sideHeight + definition.treadHeight, min.z),                         // 0
                            new Vector3(min.x, max.y + sideHeight + definition.treadHeight, boundsMin.z),                   // 1
                            new Vector3(min.x, max.y, boundsMin.z),                                                         // 2
                            new Vector3(min.x, max.y, min.z),                                                               // 3
                        };

                        BrushMeshFactory.CreateExtrudedSubMesh(ref brushContainer.brushMeshes[subMeshOffset + startLeftSideUp + (stepCount - 1)], vertices, extrusion,
                                                               new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this
                                                               definition.surfaceDefinition);
                    }
                    //if (!haveLeftSideDown)
                    {
                        var       stepHeight = definition.stepHeight;
                        Vector3[] vertices;
                        if (riserType == StairsRiserType.FillDown)
                        {
                            vertices = new[] {
                                new Vector3(min.x, boundsMin.y + stepHeight, boundsMax.z),              // 0
                                new Vector3(min.x, boundsMin.y + stepHeight, boundsMin.z),              // 1
                                new Vector3(min.x, boundsMin.y, boundsMin.z),                           // 2
                                new Vector3(min.x, boundsMin.y, boundsMax.z),                           // 3
                            };
                        }
                        else
                        {
                            vertices = new[] {
                                new Vector3(min.x, boundsMin.y + stepHeight, boundsMax.z),                      // 0
                                new Vector3(min.x, boundsMin.y + stepHeight, boundsMax.z - extraDepth),         // 1
                                new Vector3(min.x, boundsMin.y, boundsMax.z - extraDepth),                      // 2
                                new Vector3(min.x, boundsMin.y, boundsMax.z),                                   // 3
                            };
                        }

                        BrushMeshFactory.CreateExtrudedSubMesh(ref brushContainer.brushMeshes[subMeshOffset + startLeftSideUp + stepCount], vertices, extrusion,
                                                               new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this
                                                               definition.surfaceDefinition);
                    }
                }
                if (haveRightSideUp)
                {
                    var min        = new Vector3(boundsMin.x, boundsMax.y - definition.treadHeight - definition.stepHeight, boundsMin.z + definition.StepDepthOffset + definition.stepDepth);
                    var max        = new Vector3(boundsMin.x + sideWidth, boundsMax.y - definition.treadHeight, boundsMin.z + definition.StepDepthOffset + definition.stepDepth + definition.stepDepth);
                    var extrusion  = new Vector3(sideWidth, 0, 0);
                    var extraDepth = (thickRiser ? definition.stepDepth : riserDepth) + rightSideDepth;
                    var maxDepth   = boundsMin.z;

                    GenerateTopRamp(ref brushContainer, subMeshOffset + startRightSideUp, stepCount - 1, min, max, extrusion, sideHeight, extraDepth, maxDepth, riserType, definition, definition.surfaceDefinition);

                    if (haveTopSide)
                    {
                        var vertices = new[] {
                            new Vector3(min.x, max.y + sideHeight + definition.treadHeight, min.z),                         // 0
                            new Vector3(min.x, max.y + sideHeight + definition.treadHeight, boundsMin.z),                   // 1
                            new Vector3(min.x, max.y, boundsMin.z),                                                         // 2
                            new Vector3(min.x, max.y, min.z),                                                               // 3
                        };

                        BrushMeshFactory.CreateExtrudedSubMesh(ref brushContainer.brushMeshes[subMeshOffset + startRightSideUp + (stepCount - 1)], vertices, extrusion,
                                                               new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this
                                                               definition.surfaceDefinition);
                    }
                    //if (!haveRightSideDown)
                    {
                        var       stepHeight = definition.stepHeight;
                        Vector3[] vertices;
                        if (riserType == StairsRiserType.FillDown)
                        {
                            vertices = new[] {
                                new Vector3(min.x, boundsMin.y + stepHeight, boundsMax.z),               // 0
                                new Vector3(min.x, boundsMin.y + stepHeight, boundsMin.z),               // 1
                                new Vector3(min.x, boundsMin.y, boundsMin.z),                            // 2
                                new Vector3(min.x, boundsMin.y, boundsMax.z),                            // 3
                            };
                        }
                        else
                        {
                            vertices = new[] {
                                new Vector3(min.x, boundsMin.y + stepHeight, boundsMax.z),                      // 0
                                new Vector3(min.x, boundsMin.y + stepHeight, boundsMax.z - extraDepth),         // 1
                                new Vector3(min.x, boundsMin.y, boundsMax.z - extraDepth),                      // 2
                                new Vector3(min.x, boundsMin.y, boundsMax.z),                                   // 3
                            };
                        }

                        BrushMeshFactory.CreateExtrudedSubMesh(ref brushContainer.brushMeshes[subMeshOffset + startRightSideUp + stepCount], vertices, extrusion,
                                                               new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this
                                                               definition.surfaceDefinition);
                    }
                }
            }
            return(true);
        }
        public void OnEdit(IChiselHandles handles)
        {
            var baseColor = handles.color;
            var normal    = Vector3.forward;

            var controlPoints = shape.controlPoints;

            var shapeVertices       = new List <Vector2>();
            var shapeSegmentIndices = new List <int>();

            BrushMeshFactory.GetPathVertices(this.shape, this.curveSegments, shapeVertices, shapeSegmentIndices);


            var horzSegments         = this.revolveSegments;
            var horzDegreePerSegment = this.totalAngle / horzSegments;
            var horzOffset           = this.startAngle;

            var noZTestcolor = handles.GetStateColor(baseColor, false, true);
            var zTestcolor   = handles.GetStateColor(baseColor, false, false);

            for (int h = 1, pr = 0; h < horzSegments + 1; pr = h, h++)
            {
                var hDegree0  = (pr * horzDegreePerSegment) + horzOffset;
                var hDegree1  = (h * horzDegreePerSegment) + horzOffset;
                var rotation0 = Quaternion.AngleAxis(hDegree0, normal);
                var rotation1 = Quaternion.AngleAxis(hDegree1, normal);
                for (int p0 = controlPoints.Length - 1, p1 = 0; p1 < controlPoints.Length; p0 = p1, p1++)
                {
                    var point0 = controlPoints[p0].position;
                    //var point1	= controlPoints[p1].position;
                    var vertexA = rotation0 * new Vector3(point0.x, 0, point0.y);
                    var vertexB = rotation1 * new Vector3(point0.x, 0, point0.y);
                    //var vertexC	= rotation0 * new Vector3(point1.x, 0, point1.y);

                    handles.color = noZTestcolor;
                    handles.DrawLine(vertexA, vertexB, lineMode: LineMode.NoZTest, thickness: kHorzLineThickness);//, dashSize: kLineDash);

                    handles.color = zTestcolor;
                    handles.DrawLine(vertexA, vertexB, lineMode: LineMode.ZTest, thickness: kHorzLineThickness);  //, dashSize: kLineDash);
                }

                for (int v0 = shapeVertices.Count - 1, v1 = 0; v1 < shapeVertices.Count; v0 = v1, v1++)
                {
                    var point0  = shapeVertices[v0];
                    var point1  = shapeVertices[v1];
                    var vertexA = rotation0 * new Vector3(point0.x, 0, point0.y);
                    var vertexB = rotation0 * new Vector3(point1.x, 0, point1.y);

                    handles.color = noZTestcolor;
                    handles.DrawLine(vertexA, vertexB, lineMode: LineMode.NoZTest, thickness: kHorzLineThickness, dashSize: kLineDash);

                    handles.color = zTestcolor;
                    handles.DrawLine(vertexA, vertexB, lineMode: LineMode.ZTest, thickness: kHorzLineThickness, dashSize: kLineDash);
                }
            }
            handles.color = baseColor;

            {
                // TODO: make this work non grid aligned so we can place it upwards
                handles.DoShapeHandle(ref shape);
                handles.DrawLine(normal * 10, normal * -10, dashSize: 4.0f);
            }
        }