// TODO: remove all stairs specific parameters static void GenerateTopRamp(CSGBrushSubMesh[] subMeshes, int startIndex, int stepCount, Vector3 min, Vector3 max, Vector3 extrusion, float sideHeight, float extraDepth, float maxDepth, StairsRiserType riserType, CSGLinearStairsDefinition definition, CSGSurfaceAsset[] surfaceAssets, SurfaceDescription[] surfaceDescriptions) { //var diffY = (max.y - min.y); //var diffZ = (max.z - min.z); //var aspect = diffY / diffZ; var diagonalHeight = sideHeight + definition.treadHeight; //Mathf.Max(sideHeight + definition.treadHeight, (aspect * (riserDepth)));// + definition.nosingDepth)) + definition.treadHeight; for (int i = 0, j = startIndex; i < stepCount; i++, j++) { var topY = max.y + diagonalHeight; var bottomY = min.y; var middleY = (bottomY + diagonalHeight); // - (lastStep ? (riserDepth * aspect) : 0); var rightZ = Mathf.Max(maxDepth, max.z); // + (lastStep ? riserDepth : 0); var leftZ = Mathf.Max(maxDepth, min.z); // topY leftZ // 0 4 // *--* // | \ // | \ // lefterZ | \ 3 // | * // | | rightZ // *------* // 1 2 // bottomY var lefterZ = (i == 0 || (riserType == StairsRiserType.FillDown)) ? maxDepth : Mathf.Max(maxDepth, leftZ - extraDepth); var vertices = new[] { new Vector3(min.x, topY, lefterZ), // 0 new Vector3(min.x, bottomY, lefterZ), // 1 new Vector3(min.x, bottomY, rightZ), // 2 new Vector3(min.x, middleY, rightZ), // 3 new Vector3(min.x, topY, leftZ), // 4 }; CreateExtrudedSubMesh(subMeshes[j + 0], vertices, extrusion, new int[] { 0, 1, 2, 3, 3, 3, 3 }, // TODO: fix this new int[] { 0, 1, 2, 2, 2, 2, 2 }, // TODO: fix this surfaceAssets, surfaceDescriptions); min.z += definition.stepDepth; max.z += definition.stepDepth; min.y -= definition.stepHeight; max.y -= definition.stepHeight; } }
public static bool GenerateLinearStairsAsset(CSGBrushMeshAsset brushMeshAsset, CSGLinearStairsDefinition definition) { definition.Validate(); int subMeshCount = GetLinearStairsSubMeshCount(definition, definition.leftSide, definition.rightSide); if (subMeshCount == 0) { brushMeshAsset.Clear(); return(false); } CSGBrushSubMesh[] subMeshes; if (brushMeshAsset.SubMeshCount != subMeshCount) { subMeshes = new CSGBrushSubMesh[subMeshCount]; for (int i = 0; i < subMeshCount; i++) { subMeshes[i] = new CSGBrushSubMesh(); } } else { subMeshes = brushMeshAsset.SubMeshes; } if (!GenerateLinearStairsSubMeshes(subMeshes, definition, definition.leftSide, definition.rightSide, 0)) { brushMeshAsset.Clear(); return(false); } brushMeshAsset.SubMeshes = subMeshes; brushMeshAsset.CalculatePlanes(); brushMeshAsset.SetDirty(); return(true); }
public static bool GenerateLinearStairsSubMeshes(CSGBrushSubMesh[] subMeshes, CSGLinearStairsDefinition definition, StairsSideType leftSideDefinition, StairsSideType rightSideDefinition, int subMeshOffset = 0) { // TODO: properly assign all materials //const int Top = (int)CSGLinearStairsDefinition.SurfaceSides.Top; //const int Bottom = (int)CSGLinearStairsDefinition.SurfaceSides.Bottom; const int Left = (int)CSGLinearStairsDefinition.SurfaceSides.Left; const int Right = (int)CSGLinearStairsDefinition.SurfaceSides.Right; //const int Forward = (int)CSGLinearStairsDefinition.SurfaceSides.Forward; //const int Back = (int)CSGLinearStairsDefinition.SurfaceSides.Back; const int Tread = (int)CSGLinearStairsDefinition.SurfaceSides.Tread; const int Step = (int)CSGLinearStairsDefinition.SurfaceSides.Step; CSGSurfaceAsset[] surfaceAssets = definition.surfaceAssets; SurfaceDescription[] surfaceDescriptions = definition.surfaceDescriptions; if (surfaceAssets.Length != (int)CSGLinearStairsDefinition.SurfaceSides.TotalSides || surfaceDescriptions.Length != 6) { 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 }; } CreateExtrudedSubMesh(subMeshes[subMeshOffset + i], vertices, extrusion, new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this new int[] { Left, Right, Step, Tread, Step, Tread }, // TODO: fix this surfaceAssets, surfaceDescriptions); 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); CreateExtrudedSubMesh(subMeshes[subMeshOffset + startTread + i], vertices, extrusion, new int[] { 0, 1, 2, 2, 2, 2 }, // TODO: fix this new int[] { Left, Right, Tread, Tread, Tread, Tread }, // TODO: fix this surfaceAssets, surfaceDescriptions); 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(subMeshes, subMeshOffset + startLeftSideDown, stepCount, min, max, extrusion, riserType, definition.stepDepth - riserDepth, extraDepth, maxDepth, definition, surfaceAssets, surfaceDescriptions); } 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(subMeshes, subMeshOffset + startRightSideDown, stepCount, min, max, extrusion, riserType, definition.stepDepth - riserDepth, extraDepth, maxDepth, definition, surfaceAssets, surfaceDescriptions); } 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(subMeshes, subMeshOffset + startLeftSideUp, stepCount - 1, min, max, extrusion, sideHeight, extraDepth, maxDepth, riserType, definition, surfaceAssets, surfaceDescriptions); 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 }; CreateExtrudedSubMesh(subMeshes[subMeshOffset + startLeftSideUp + (stepCount - 1)], vertices, extrusion, new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this new int[] { 0, 1, 2, 2, 2, 2 }, // TODO: fix this surfaceAssets, surfaceDescriptions); } //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 }; } CreateExtrudedSubMesh(subMeshes[subMeshOffset + startLeftSideUp + stepCount], vertices, extrusion, new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this new int[] { 0, 1, 2, 2, 2, 2 }, // TODO: fix this surfaceAssets, surfaceDescriptions); } } 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(subMeshes, subMeshOffset + startRightSideUp, stepCount - 1, min, max, extrusion, sideHeight, extraDepth, maxDepth, riserType, definition, surfaceAssets, surfaceDescriptions); 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 }; CreateExtrudedSubMesh(subMeshes[subMeshOffset + startRightSideUp + (stepCount - 1)], vertices, extrusion, new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this new int[] { 0, 1, 2, 2, 2, 2 }, // TODO: fix this surfaceAssets, surfaceDescriptions); } //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 }; } CreateExtrudedSubMesh(subMeshes[subMeshOffset + startRightSideUp + stepCount], vertices, extrusion, new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this new int[] { 0, 1, 2, 2, 2, 2 }, // TODO: fix this surfaceAssets, surfaceDescriptions); } } } return(true); }
// TODO: remove all stairs specific parameters static void GenerateBottomRamp(CSGBrushSubMesh[] subMeshes, int startIndex, int stepCount, Vector3 min, Vector3 max, Vector3 extrusion, StairsRiserType riserType, float riserDepth, float extraDepth, float maxDepth, CSGLinearStairsDefinition definition, CSGSurfaceAsset[] surfaceAssets, SurfaceDescription[] surfaceDescriptions) { for (int i = 0, j = startIndex; i < stepCount; i++, j++) { Vector3[] vertices; var z0 = Mathf.Max(maxDepth, min.z - extraDepth); var z1 = Mathf.Max(maxDepth, max.z - extraDepth); var z2 = Mathf.Max(maxDepth, min.z + riserDepth);/* * if (z2 < z1) * { * var t = z1; z1 = z2; z2 = t; * z1 = Mathf.Max(maxDepth, min.z - extraDepth + definition.stepDepth); * z2 = Mathf.Max(maxDepth, max.z); * }*/ if (i != stepCount - 1) { vertices = new[] { new Vector3(min.x, max.y, z2), // 0 new Vector3(min.x, max.y, z0), // 1 new Vector3(min.x, min.y, z1), // 2 new Vector3(min.x, min.y, z2), // 3 }; } else { vertices = new[] { new Vector3(min.x, max.y, z2), // 0 new Vector3(min.x, max.y, z0), // 1 new Vector3(min.x, min.y + definition.treadHeight, z1), // 2 new Vector3(min.x, min.y + definition.treadHeight, z2), // 3 }; } CreateExtrudedSubMesh(subMeshes[j], vertices, extrusion, new int[] { 0, 1, 2, 3, 3, 3 }, // TODO: fix this new int[] { 0, 1, 2, 2, 2, 2 }, // TODO: fix this surfaceAssets, surfaceDescriptions); min.z += definition.stepDepth; max.z += definition.stepDepth; min.y -= definition.stepHeight; max.y -= definition.stepHeight; } }
public static int GetLinearStairsSubMeshCount(CSGLinearStairsDefinition definition, StairsSideType leftSideDefinition, StairsSideType rightSideDefinition) { CSGSurfaceAsset[] surfaceAssets = definition.surfaceAssets; SurfaceDescription[] surfaceDescriptions = definition.surfaceDescriptions; if (surfaceAssets.Length != (int)CSGLinearStairsDefinition.SurfaceSides.TotalSides || surfaceDescriptions.Length != 6) { return(0); } // 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 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 sideHeight = definition.sideHeight; var stepCount = definition.StepCount; var haveTread = (treadHeight >= kEpsilon); var haveTopSide = (sideHeight > kEpsilon); var subMeshCount = 0; if (haveRiser) { subMeshCount = stepCount; } if (haveTread) { subMeshCount += stepCount; } if (haveLeftSideDown) { subMeshCount += stepCount; } if (haveRightSideDown) { subMeshCount += stepCount; } if (haveLeftSideUp) { subMeshCount += (stepCount - 1) + (haveTopSide ? 1 : 0) + 1; //(haveLeftSideDown ? 0 : 1); } if (haveRightSideUp) { subMeshCount += (stepCount - 1) + (haveTopSide ? 1 : 0) + 1; //(haveRightSideDown ? 0 : 1); } return(subMeshCount); }