private void FillUniqueSegments(BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, int node)
        {
            var lanePoints = placementAlgorithm.LanePoints;

            uniqueSegments.Clear();
            uniquePoints.Clear();

            if (placementAlgorithm.LaneSegments.TryGetValue(node, out var lanes))
            {
                foreach (var lane in lanes)
                {
                    var currPoint = lanePoints[lane.StartPoint];
                    if (currPoint.Z != 0)
                    {
                        uniquePoints.Add(currPoint);
                    }
                    for (int i = 1; i < lane.NumPoints; i++)
                    {
                        var prevPoint = currPoint;
                        currPoint = lanePoints[lane.StartPoint + i];
                        if (currPoint.Z != 0)
                        {
                            uniquePoints.Add(currPoint);
                        }
                        if (prevPoint.Z != 0 || currPoint.Z != 0)
                        {
                            uniqueSegments.Add(new Pair <Vector3>(prevPoint, currPoint));
                        }
                    }
                }
            }
        }
Пример #2
0
 public BuildingStoryLayoutInstance(IInputService inputService, BuildingStoryLayoutPlacementAlgorithm placementAlgorithm,
                                    ICollisionMesh collisionMesh, IStoryLayoutZoning zoning)
 {
     this.placementAlgorithm = placementAlgorithm;
     this.collisionMesh      = collisionMesh;
     this.zoning             = zoning;
     this.inputService       = inputService;
     sg = placementAlgorithm.StoryGraph;
 }
        private BuildingCorridorDiggingResult BuildElevators(BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, int node)
        {
            const float offset = BuildingConstants.ElevatorOffset;
            var         negativeElevatorCenter = -(placementAlgorithm.HalfSizes[node].Width + offset) * Vector3.UnitX;
            var         negPoint0 = negativeElevatorCenter + new Vector3(offset, 0, offset);
            var         negPoint1 = negativeElevatorCenter + new Vector3(-offset, 0, offset);
            var         negPoint2 = negativeElevatorCenter + new Vector3(-offset, 0, -offset);
            var         negPoint3 = negativeElevatorCenter + new Vector3(offset, 0, -offset);

            var positiveElevatorCenter = (placementAlgorithm.HalfSizes[node].Width + offset) * Vector3.UnitX;
            var posPoint0 = positiveElevatorCenter + new Vector3(-offset, 0, -offset);
            var posPoint1 = positiveElevatorCenter + new Vector3(offset, 0, -offset);
            var posPoint2 = positiveElevatorCenter + new Vector3(offset, 0, offset);
            var posPoint3 = positiveElevatorCenter + new Vector3(-offset, 0, offset);

            var fullHeight = 2 * placementAlgorithm.HalfSizes[node].Height;

            var wallSegments = new List <BuildingWallSegment>
            {
                new BuildingWallSegment(negPoint0, negPoint1, fullHeight),
                new BuildingWallSegment(negPoint1, negPoint2, fullHeight),
                new BuildingWallSegment(negPoint2, negPoint3, fullHeight),
                new BuildingWallSegment(posPoint0, posPoint1, fullHeight),
                new BuildingWallSegment(posPoint1, posPoint2, fullHeight),
                new BuildingWallSegment(posPoint2, posPoint3, fullHeight),
            };

            var children      = placementAlgorithm.StoryGraph.Children[node];
            var currentHeight = BuildingConstants.CeilingHeight;

            foreach (var child in children)
            {
                var verticalOffset  = Vector3.UnitY * currentHeight;
                var floorHeight     = 2 * placementAlgorithm.HalfSizes[child].Height + BuildingConstants.HeightMargin;
                var separatorHeight = floorHeight - BuildingConstants.CeilingHeight;
                wallSegments.Add(new BuildingWallSegment(negPoint3 + verticalOffset, negPoint0 + verticalOffset, separatorHeight));
                wallSegments.Add(new BuildingWallSegment(posPoint3 + verticalOffset, posPoint0 + verticalOffset, separatorHeight));
                currentHeight += floorHeight;
            }

            var floorings = new List <AaRectangle2>
            {
                new AaRectangle2(negativeElevatorCenter.Xz, offset, offset),
                new AaRectangle2(positiveElevatorCenter.Xz, offset, offset),
            };

            return(new BuildingCorridorDiggingResult
            {
                WallSegments = wallSegments,
                RawWallSegments = wallSegments,
                Floorings = floorings
            });
        }
Пример #4
0
        //
        public IStoryLayoutInstance ArrangeAndDecorate(IStoryGraph sg)
        {
            var placementAlgorithm = new BuildingStoryLayoutPlacementAlgorithm(coroutineService, x => ArrangeAndDecorateInternal(sg.Root, x, new List <BuildingWallSegment>()), sg);

            placementAlgorithm.Run();
            var collisionSegments = new List <BuildingWallSegment>();

            ArrangeAndDecorateInternal(sg.Root, placementAlgorithm, collisionSegments);
            var floors = sg.Children[sg.Root]
                         .Select(x => new AaBox(placementAlgorithm.RelativeTransforms[x].Offset, placementAlgorithm.HalfSizes[x]))
                         .ToArray();
            var zonesWithProperties   = floors.Select(x => Tuples.Pair(x, new StoryLayoutZoneProperties(-15f))).ToArray();
            var defaultZoneProperties = new StoryLayoutZoneProperties(0);
            var zoning = new AaBoxStoryLayoutZoning(zonesWithProperties, defaultZoneProperties);
            var buildingCollisionMesh = new CollisionMesh(collisionSegments, floors, zoning);

            return(new BuildingStoryLayoutInstance(inputService, placementAlgorithm, buildingCollisionMesh, zoning));
        }
        private List <BuildingPrimitive> CreatePrimitives(BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, int node)
        {
            var sg = placementAlgorithm.StoryGraph;

            var primitives = new List <BuildingPrimitive>();

            var nodeScale         = placementAlgorithm.HalfSizes[node].ToVector();
            var mainCorridorScale = new Vector3(nodeScale.X, nodeScale.Y, BuildingConstants.CorridorHalfWidth + MathHelper.Eps5);
            var mainCorridor      = new BuildingPrimitive(BuildingPrimitiveType.Rectangle, mainCorridorScale, Transform.Identity, true);

            primitives.Add(mainCorridor);

            foreach (var seg in uniqueSegments)
            {
                var forward   = seg.Second - seg.First;
                var halfWidth = forward.Length() / 2;
                var center    = (seg.First + seg.Second) / 2;
                var scale     = new Vector3(halfWidth, 1, BuildingConstants.CorridorHalfWidth);
                var transform = new Transform(1, Quaternion.RotationToFrame(forward, Vector3.UnitY), center);
                primitives.Add(new BuildingPrimitive(BuildingPrimitiveType.Rectangle, scale, transform));
            }

            foreach (var point in uniquePoints)
            {
                primitives.Add(new BuildingPrimitive(BuildingPrimitiveType.Circle, new Vector3(BuildingConstants.CorridorHalfWidth), Transform.Translation(point)));
            }

            foreach (var child in sg.Children[node])
            {
                var scale = placementAlgorithm.HalfSizes[child].ToVector();
                var pos   = placementAlgorithm.RelativePositions[child];
                if (!sg.Children[child].Any())
                {
                    scale.Z += BuildingConstants.CorridorHalfWidth / 2;
                    pos.Z   -= scale.Z - BuildingConstants.CorridorHalfWidth;
                }
                primitives.Add(new BuildingPrimitive(BuildingPrimitiveType.Rectangle, scale, Transform.Translation(pos)));
            }

            return(primitives);
        }
        public BuildingCorridorDiggingResult Dig(BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, int node)
        {
            var ssg = placementAlgorithm.StoryGraph;

            if (!ssg.Children[node].Any())
            {
                return new BuildingCorridorDiggingResult
                       {
                           WallSegments    = new List <BuildingWallSegment>(),
                           RawWallSegments = new List <BuildingWallSegment>(),
                           Floorings       = new List <AaRectangle2>()
                       }
            }
            ;
            if (node == ssg.Root)
            {
                return(BuildElevators(placementAlgorithm, node));
            }
            FillUniqueSegments(placementAlgorithm, node);
            var primitives      = CreatePrimitives(placementAlgorithm, node);
            var wallSegments    = BuildWallBasementManaged(primitives);
            var rawWallSegments = BuildRawWallSegments(primitives);
            var floorings       = new List <AaRectangle2>();

            if (ssg.Parents[node] == ssg.Root)
            {
                var halfSize = placementAlgorithm.HalfSizes[node];
                floorings.Add(new AaRectangle2(Vector2.Zero, halfSize.Width, halfSize.Depth));
            }
            return(new BuildingCorridorDiggingResult
            {
                WallSegments = wallSegments,
                RawWallSegments = rawWallSegments,
                Floorings = floorings
            });
        }
Пример #7
0
        public BuildingStoryPath(BuildingStoryLayoutPlacementAlgorithm pa, IStoryGraph sg, CameraProps initialCameraProps, int endNodeId, NavigationState navigationState, bool interLevel)
        {
            this.pa = pa;
            this.sg = sg;
            beziers = new List <BezierQuadratic3>();
            var closestNode = sg.Leaves.Minimal(x =>
                                                (BuildingConstants.LeafHalfSize.Depth * Vector3.UnitZ * GetGlobalTransform(x) -
                                                 initialCameraProps.Frame.Eye).LengthSquared());

            //var closestNodeGlobalTransform = GetGlobalTransform(endNodeId);
            //var closestNodeCenter = Vector3.Zero * closestNodeGlobalTransform;
            //var closestNodeConnector = BuildingConstants.LeafHalfSize.Depth * Vector3.UnitZ * closestNodeGlobalTransform;
            if (closestNode != endNodeId || interLevel)
            {
                if (!interLevel && sg.TryFindShortestPath(closestNode, endNodeId, out var nodePath))
                {
                    foreach (var edge in nodePath.SequentialPairs())
                    {
                        IEnumerable <BezierQuadratic3> pathToAdd;
                        if (pa.Lanes.TryGetValue(edge, out var lane))
                        {
                            pathToAdd = lane.GlobalPath;
                        }
                        else if (pa.Lanes.TryGetValue(edge.Reverse(), out lane))
                        {
                            pathToAdd = lane.GlobalPath.Reverse().Select(x => x.Reverse());
                        }
                        else
                        {
                            throw new Exception("Path search returned an unexisting path.");
                        }
                        beziers.AddRange(pathToAdd.Skip(1).ExceptLast());
                    }
                }
                else
                {
                    var endNode       = sg.NodeObjects[endNodeId];
                    var aEndFocus     = endNode.GetComponent <IFocusNodeComponent>();
                    var endCameraInfo = aEndFocus.DefaultViewpointMechanism.FixedCamera.GetProps();
                    directPath = new DirectStoryPath(initialCameraProps, endCameraInfo, 1f);
                }
            }

            switch (navigationState)
            {
            case NavigationState.AtNode:
                break;

            case NavigationState.AtForwardFork:
            {
                var nextEdge   = new Pair <int>(endNodeId, sg.Next[endNodeId].First());
                var nextLane   = pa.Lanes[nextEdge];
                var lastBezier = nextLane.GlobalPath.First();
                var point      = lastBezier.At(1);
                var tangent    = lastBezier.TangentAt(1);
                beziers.Add(BezierQuadratic3.Straight(point - tangent, point));
                break;
            }

            case NavigationState.AtBackwardFork:
            {
                var nextEdge   = new Pair <int>(sg.Previous[endNodeId].First(), endNodeId);
                var nextLane   = pa.Lanes[nextEdge];
                var lastBezier = nextLane.GlobalPath.Last().Reverse();
                var point      = lastBezier.At(1);
                var tangent    = lastBezier.TangentAt(1);
                beziers.Add(BezierQuadratic3.Straight(point - tangent, point));
                break;
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(navigationState), navigationState, null);
            }

            foreach (var indexPair in Enumerable.Range(0, beziers.Count).SequentialPairs())
            {
                if (beziers[indexPair.First].P2 != beziers[indexPair.Second].P0)
                {
                    var avg = (beziers[indexPair.First].P2 + beziers[indexPair.Second].P0) / 2;
                    beziers[indexPair.First]  = beziers[indexPair.First].With((ref BezierQuadratic3 b) => b.P2 = avg);
                    beziers[indexPair.Second] = beziers[indexPair.Second].With((ref BezierQuadratic3 b) => b.P0 = avg);
                }
            }

            if (!beziers.Any())
            {
                beziers.Add(BezierQuadratic3.Straight(initialCameraProps.Frame.Eye,
                                                      initialCameraProps.Frame.Eye + initialCameraProps.Frame.Forward));
            }

            path = beziers
                   .SelectMany(x => x.ToEnumPolyline(BezierTolerance))
                   .SequentialPairs()
                   .Select(x => new PathSegment(x.First, x.Second))
                   .Where(x => x.Length > 0)
                   .ToArray();

            currentCameraProps = initialCameraProps;
        }
Пример #8
0
        private void ArrangeAndDecorateInternal(int subtreeRoot, BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, List <BuildingWallSegment> globalWallSegments)
        {
            var sg       = placementAlgorithm.StoryGraph;
            var node     = sg.NodeObjects[subtreeRoot];
            var aspect   = sg.Aspects[subtreeRoot];
            var index    = node.Id;
            var children = sg.Children[index];

            foreach (var child in children)
            {
                ArrangeAndDecorateInternal(child, placementAlgorithm, globalWallSegments);
            }

            var depth = sg.Depths[subtreeRoot];

            var hasChildren = children.Any();

            var halfSize = placementAlgorithm.HalfSizes[index];

            node.Transform = hasChildren
                ? placementAlgorithm.RelativeTransforms[index]
                : placementAlgorithm.RelativeTransforms[index] * Transform.Translation(0, BuildingConstants.EyeHeight, 0);

            var dynamicParts = new StoryNodeDynamicParts();
            var visualElems  = new List <IVisualElement>();

            var corridorDigger = new BuildingCorridorDigger();
            var digResult      = corridorDigger.Dig(placementAlgorithm, index);

            var globalTransform = placementAlgorithm.GetGlobalTransform(index);

            var rootStoryComponent = sg.Aspects[sg.Root];

            if (digResult.WallSegments.Any())
            {
                var wallModel = BuildWallModel(digResult.WallSegments);
                visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent)
                                .SetModel(wallModel)
                                .SetMaterial(wallMaterial)
                                .SetRenderState(StandardRenderState.New()
                                                .SetCullFace(CullFace.Back)
                                                .FromGlobalCache())
                                .SetHide(x => x.HideMain));
                foreach (var wallSegment in digResult.WallSegments)
                {
                    globalWallSegments.Add(new BuildingWallSegment
                    {
                        Basement = new LineSegment3(
                            wallSegment.Basement.Point1 * globalTransform,
                            wallSegment.Basement.Point2 * globalTransform),
                        Height = wallSegment.Height
                    });
                }

                var wallPrimitivesModel = BuildWallModel4(digResult.RawWallSegments);
                visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent)
                                .SetModel(wallPrimitivesModel)
                                .SetMaterial(rawWallMaterial)
                                .SetHide(x => !x.ShowAux3));

                var filteredWallPrimitivesModel = BuildWallModel4(digResult.WallSegments);
                visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent)
                                .SetModel(filteredWallPrimitivesModel)
                                .SetMaterial(rawWallMaterial)
                                .SetHide(x => !x.ShowAux4));
            }

            foreach (var flooring in digResult.Floorings)
            {
                visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent)
                                .SetModel(BuildFloorOrCeiling(new Size3(flooring.HalfWidth, 0, flooring.HalfHeight), PlaneModelSourceNormalDirection.Positive))
                                .SetMaterial(floorMaterial)
                                .SetRenderState(StandardRenderState.New()
                                                .SetCullFace(CullFace.Back)
                                                .FromGlobalCache())
                                .SetTransform(Transform.Translation(flooring.Center.X, 0, flooring.Center.Y))
                                .SetHide(x => x.HideMain));
            }

            if (index == sg.Root)
            {
                foreach (var lane in placementAlgorithm.Lanes.Values)
                {
                    var laneLoc           = lane;
                    var navigationService = navigationServiceLazy.Value;
                    var model             = BuildLaneModel(lane);
                    visualElems.Add(ModelVisualElement.New()
                                    .SetModel(model)
                                    .SetMaterial(x => new UnorderedPair <int>(navigationService.Previous.Id, navigationService.Current.Id) == new UnorderedPair <int>(laneLoc.Edge.First, laneLoc.Edge.Second) ? currentLineMaterial : lineMaterial)
                                    .SetRenderState(StandardRenderState.New()
                                                    // todo: remove *5
                                                    .SetZOffset(GraphicsHelper.MinZOffset * 5)
                                                    .SetLineWidth(3)
                                                    .FromGlobalCache()));
                }
            }

            dynamicParts.Hittable = hasChildren
                ? new RectangleHittable <ISceneNode>(node, Transform.Rotate(Quaternion.RotationToFrame(Vector3.UnitX, Vector3.UnitZ)), x => new AaRectangle2(Vector2.Zero, halfSize.Width, halfSize.Height), x => - 0.01f * depth)
                : new RectangleHittable <ISceneNode>(node, new Transform(1, Quaternion.RotationToFrame(Vector3.UnitX, Vector3.UnitZ), new Vector3(0, -BuildingConstants.EyeHeight, 0)), x => new AaRectangle2(Vector2.Zero, halfSize.Width, halfSize.Height), x => - 0.01f * depth);

            if (depth == 1)
            {
                visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent)
                                .SetModel(BuildFloorOrCeiling(halfSize, PlaneModelSourceNormalDirection.Negative))
                                .SetMaterial(ceilingMaterial)
                                .SetRenderState(StandardRenderState.New()
                                                .SetCullFace(CullFace.Back)
                                                .FromGlobalCache())
                                .SetTransform(Transform.Translation(0, BuildingConstants.CeilingHeight, 0))
                                .SetHide(x => x.HideMain));
            }

            if (hasChildren)
            {
                var size = halfSize.ToVector().Length();
                dynamicParts.DefaultViewpointMechanism =
                    new WallDefaultViewpointMechanism(node, new TargetedControlledCameraY.Props
                {
                    Target      = Vector3.Zero,
                    Distance    = size,
                    FieldOfView = MathHelper.PiOver4,
                    Pitch       = MathHelper.PiOver4,
                    Yaw         = -MathHelper.PiOver4,
                    ZNear       = 0.01f,
                    ZFar        = 1000f
                });
            }
            else
            {
                dynamicParts.DefaultViewpointMechanism =
                    new WallDefaultViewpointMechanism(node, new TargetedControlledCameraY.Props
                {
                    Distance    = FrustumDistance,
                    FieldOfView = MathHelper.PiOver4,
                    Pitch       = 0,
                    Yaw         = 0,
                    ZNear       = 0.01f,
                    ZFar        = 1000f
                });

                visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent)
                                .SetModel(frustumModel)
                                .SetMaterial(frustumMaterial)
                                .SetRenderState(StandardRenderState.New()
                                                .SetZOffset(GraphicsHelper.MinZOffset * (depth + 1))
                                                .FromGlobalCache())
                                .SetHide(x => !x.ShowAux1));

                dynamicParts.PlacementSurface2D = new PlanarPlacementSurface(node, new Transform(2f, Quaternion.Identity, new Vector3(0, 0, -MathHelper.FrustumDistance)));
                dynamicParts.PlacementSurface3D = new PlanarPlacementSurface(node, Transform.Scaling(0.1f));
            }

            dynamicParts.VisualElements = visualElems;

            aspect.SetDynamicParts(dynamicParts);
        }