public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            if (HoveredNodeId == SelectedNodeId)
            {
                return;
            }

            // no highlight for existing priority node in sign mode
            if (TrafficPriorityManager.Instance.HasNodePrioritySign(HoveredNodeId))
            {
                //Log._Debug($"PrioritySignsTool.RenderOverlay: HasNodePrioritySign({HoveredNodeId})=true");
                return;
            }

            if (!TrafficPriorityManager.Instance.MayNodeHavePrioritySigns(HoveredNodeId))
            {
                //Log._Debug($"PrioritySignsTool.RenderOverlay: MayNodeHavePrioritySigns({HoveredNodeId})=false");
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
        }
Esempio n. 2
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            // For current camera store its position and cast a ray via mouse position
            Vector3 camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;
            // Ray mouseRay = currentCamera.ScreenPointToRay(Input.mousePosition);

            // Check if camera pos/angle has changed then re-filter the visible nodes
            // Assumption: The states checked in this loop don't change while the tool is active
            var currentCameraState = new CameraTransformValue(InGameUtil.Instance.CachedMainCamera);

            if (!LastCachedCamera.Equals(currentCameraState))
            {
                CachedVisibleNodeIds.Clear();
                LastCachedCamera = currentCameraState;

                FilterVisibleNodes(camPos);
            }

            // Render the current hovered node as blue
            if ((HoveredNodeId != 0) && Flags.MayHaveTrafficLight(HoveredNodeId))
            {
                MainTool.DrawNodeCircle(
                    cameraInfo,
                    HoveredNodeId,
                    Input.GetMouseButton(0),
                    false);
            }
        }
Esempio n. 3
0
        private void RenderManualNodeOverlays(RenderManager.CameraInfo cameraInfo)
        {
            var nodeSimulation = TrafficLightSimulationManager.Instance.GetNodeSimulation(SelectedNodeId);

            if (nodeSimulation == null || !nodeSimulation.IsManualLight())
            {
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, SelectedNodeId, true, false);

            /*CustomSegmentLightsManager customTrafficLightsManager = CustomSegmentLightsManager.Instance;
             *
             * NodeGeometry nodeGeometry = NodeGeometry.Get(SelectedNodeId);
             * foreach (SegmentEndGeometry end in nodeGeometry.SegmentEndGeometries) {
             *      if (end == null)
             *              continue;
             *
             *      var colorGray = new Color(0.25f, 0.25f, 0.25f, 0.25f);
             *
             *      var position = CalculateNodePositionForSegment(Singleton<NetManager>.instance.m_nodes.m_buffer[SelectedNodeId], end.SegmentId);
             *
             *      var width = _hoveredButton[0] == end.SegmentId ? 11.25f : 10f;
             *      MainTool.DrawOverlayCircle(cameraInfo, colorGray, position, width, end.SegmentId != _hoveredButton[0]);
             * }*/
        }
Esempio n. 4
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            // no highlight for existing priority node in sign mode
            if (TrafficPriorityManager.Instance.IsPriorityNode(HoveredNodeId, false))
            {
                return;
            }

            if (HoveredNodeId == 0)
            {
                return;
            }

            if (!Flags.mayHaveTrafficLight(HoveredNodeId))
            {
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
        }
Esempio n. 5
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            if (HoveredNodeId == 0)
            {
                return;
            }

            if (!Flags.mayHaveTrafficLight(HoveredNodeId))
            {
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0), false);

            /*
             * var segment = Singleton<NetManager>.instance.m_segments.m_buffer[Singleton<NetManager>.instance.m_nodes.m_buffer[HoveredNodeId].m_segment0];
             *
             * Bezier3 bezier;
             * bezier.a = Singleton<NetManager>.instance.m_nodes.m_buffer[HoveredNodeId].m_position;
             * bezier.d = Singleton<NetManager>.instance.m_nodes.m_buffer[HoveredNodeId].m_position;
             *
             * var color = MainTool.GetToolColor(Input.GetMouseButton(0), false);
             *
             * NetSegment.CalculateMiddlePoints(bezier.a, segment.m_startDirection, bezier.d,
             *      segment.m_endDirection,
             *      false, false, out bezier.b, out bezier.c);
             *
             * MainTool.DrawOverlayBezier(cameraInfo, bezier, color);*/
        }
Esempio n. 6
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
            {
                // draw hovered segments
                if (HoveredSegmentId != 0)
                {
                    Color color = MainTool.GetToolColor(Input.GetMouseButton(0), false);
                    SegmentTraverser.Traverse(
                        HoveredSegmentId,
                        TraverseDirection.AnyDirection,
                        TraverseSide.Straight,
                        SegmentStopCriterion.None,
                        data => {
                        NetTool.RenderOverlay(
                            cameraInfo,
                            ref Singleton <NetManager> .instance.m_segments.m_buffer[
                                data.CurSeg.segmentId],
                            color,
                            color);
                        return(true);
                    });
                }
                else
                {
                    massEditMode = PrioritySignsMassEditMode.MainYield;
                }

                return;
            }

            massEditMode = PrioritySignsMassEditMode.MainYield;

            if (HoveredNodeId == SelectedNodeId)
            {
                return;
            }

            // no highlight for existing priority node in sign mode
            if (TrafficPriorityManager.Instance.HasNodePrioritySign(HoveredNodeId))
            {
                // Log._Debug($"PrioritySignsTool.RenderOverlay: HasNodePrioritySign({HoveredNodeId})=true");
                return;
            }

            if (!TrafficPriorityManager.Instance.MayNodeHavePrioritySigns(HoveredNodeId))
            {
                // Log._Debug($"PrioritySignsTool.RenderOverlay: MayNodeHavePrioritySigns({HoveredNodeId})=false");
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
        }
        private void RenderManualSelectionOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (HoveredNodeId == 0)
            {
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, false, false);
        }
        private void RenderManualNodeOverlays(RenderManager.CameraInfo cameraInfo)
        {
            if (!TrafficLightSimulationManager.Instance.HasManualSimulation(SelectedNodeId))
            {
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, SelectedNodeId, true, false);
        }
Esempio n. 9
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (SelectedNodeId != 0)
            {
                // draw selected node
                MainTool.DrawNodeCircle(cameraInfo, SelectedNodeId, true);
            }

            if (HoveredNodeId != 0 && HoveredNodeId != SelectedNodeId && (Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_flags & (NetNode.Flags.Junction | NetNode.Flags.Bend)) != NetNode.Flags.None)
            {
                // draw hovered node
                MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
            }
        }
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            //Log._Debug($"TppLaneConnectorTool: RenderOverlay. SelectedNodeId={SelectedNodeId} SelectedSegmentId={SelectedSegmentId} HoveredNodeId={HoveredNodeId} HoveredSegmentId={HoveredSegmentId} IsInsideUI={MainTool.GetToolController().IsInsideUI}");
            // draw lane markers and connections

            hoveredMarker = null;

            ShowOverlay(false, cameraInfo);

            // draw bezier from source marker to mouse position in target marker selection
            if (SelectedNodeId != 0)
            {
                if (GetMarkerSelectionMode() == MarkerSelectionMode.SelectTarget)
                {
                    Vector3 selNodePos = NetManager.instance.m_nodes.m_buffer[SelectedNodeId].m_position;

                    ToolBase.RaycastOutput output;
                    if (RayCastSegmentAndNode(out output))
                    {
                        RenderLane(cameraInfo, selectedMarker.position, output.m_hitPos, selNodePos, selectedMarker.color);
                    }
                }

                if (Input.GetKey(KeyCode.Delete))
                {
                    // remove all connections at selected node

                    List <NodeLaneMarker> nodeMarkers = GetNodeMarkers(SelectedNodeId);
                    if (nodeMarkers != null)
                    {
                        selectedMarker = null;
                        foreach (NodeLaneMarker sourceLaneMarker in nodeMarkers)
                        {
                            foreach (NodeLaneMarker targetLaneMarker in sourceLaneMarker.connectedMarkers)
                            {
                                LaneConnectionManager.Instance().RemoveLaneConnection(sourceLaneMarker.laneId, targetLaneMarker.laneId, sourceLaneMarker.startNode);
                            }
                        }
                    }
                    RefreshCurrentNodeMarkers();
                }
            }

            if (GetMarkerSelectionMode() == MarkerSelectionMode.None && HoveredNodeId != 0)
            {
                // draw hovered node
                MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
            }
        }
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            if (HoveredNodeId == 0)
            {
                return;
            }

            if (!Flags.mayHaveTrafficLight(HoveredNodeId))
            {
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0), false);
        }
Esempio n. 12
0
        private void RenderManualSelectionOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (HoveredNodeId == 0)
            {
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, false, false);

            /*var segment = Singleton<NetManager>.instance.m_segments.m_buffer[Singleton<NetManager>.instance.m_nodes.m_buffer[HoveredNodeId].m_segment0];
             *
             * //if ((node.m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None) return;
             * Bezier3 bezier;
             * bezier.a = Singleton<NetManager>.instance.m_nodes.m_buffer[HoveredNodeId].m_position;
             * bezier.d = Singleton<NetManager>.instance.m_nodes.m_buffer[HoveredNodeId].m_position;
             *
             * var color = MainTool.GetToolColor(false, false);
             *
             * NetSegment.CalculateMiddlePoints(bezier.a, segment.m_startDirection, bezier.d,
             *      segment.m_endDirection, false, false, out bezier.b, out bezier.c);
             * MainTool.DrawOverlayBezier(cameraInfo, bezier, color);*/
        }
Esempio n. 13
0
        private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo)
        {
            if (viewOnly && !Options.connectedLanesOverlay)
            {
                return;
            }

            NetManager netManager = Singleton <NetManager> .instance;

            var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;
            //Bounds bounds = new Bounds(Vector3.zero, Vector3.one);
            Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);

            foreach (KeyValuePair <ushort, List <NodeLaneMarker> > e in currentNodeMarkers)
            {
                ushort nodeId = e.Key;
                List <NodeLaneMarker> nodeMarkers = e.Value;
                Vector3 nodePos = NetManager.instance.m_nodes.m_buffer[nodeId].m_position;

                var diff = nodePos - camPos;
                if (diff.magnitude > TrafficManagerTool.PriorityCloseLod)
                {
                    continue;                     // do not draw if too distant
                }
                if (!viewOnly && GetMarkerSelectionMode() == MarkerSelectionMode.None)
                {
                    MainTool.DrawNodeCircle(cameraInfo, nodeId, DefaultNodeMarkerColor, true);
                }

                foreach (NodeLaneMarker laneMarker in nodeMarkers)
                {
                    foreach (NodeLaneMarker targetLaneMarker in laneMarker.connectedMarkers)
                    {
                        // render lane connection from laneMarker to targetLaneMarker
                        RenderLane(cameraInfo, laneMarker.position, targetLaneMarker.position, nodePos, laneMarker.color);
                    }

                    if (!viewOnly && nodeId == SelectedNodeId)
                    {
                        //bounds.center = laneMarker.position;
                        bool markerIsHovered = IsLaneMarkerHovered(laneMarker, ref mouseRay);                        // bounds.IntersectRay(mouseRay);

                        // draw source marker in source selection mode,
                        // draw target marker (if segment turning angles are within bounds) and selected source marker in target selection mode
                        bool drawMarker = (GetMarkerSelectionMode() == MarkerSelectionMode.SelectSource && laneMarker.isSource) ||
                                          (GetMarkerSelectionMode() == MarkerSelectionMode.SelectTarget && (
                                               (!laneMarker.isSource &&
                                                (laneMarker.vehicleType & selectedMarker.vehicleType) != VehicleInfo.VehicleType.None &&
                                                CheckSegmentsTurningAngle(selectedMarker.segmentId, ref netManager.m_segments.m_buffer[selectedMarker.segmentId], selectedMarker.startNode, laneMarker.segmentId, ref netManager.m_segments.m_buffer[laneMarker.segmentId], laneMarker.startNode)
                                               ) || laneMarker == selectedMarker));
                        // highlight hovered marker and selected marker
                        bool highlightMarker = drawMarker && (laneMarker == selectedMarker || markerIsHovered);

                        if (drawMarker)
                        {
                            if (highlightMarker)
                            {
                                laneMarker.radius = 2f;
                            }
                            else
                            {
                                laneMarker.radius = 1f;
                            }
                        }
                        else
                        {
                            markerIsHovered = false;
                        }

                        if (markerIsHovered)
                        {
                            /*if (hoveredMarker != sourceLaneMarker)
                             *      Log._Debug($"Marker @ lane {sourceLaneMarker.laneId} hovered");*/
                            hoveredMarker = laneMarker;
                        }

                        if (drawMarker)
                        {
                            //DrawLaneMarker(laneMarker, cameraInfo);
                            RenderManager.instance.OverlayEffect.DrawCircle(cameraInfo, laneMarker.color, laneMarker.position, laneMarker.radius, laneMarker.position.y - 100f, laneMarker.position.y + 100f, false, true);
                        }
                    }
                }
            }
        }
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            // Log._Debug($"LaneConnectorTool: RenderOverlay. SelectedNodeId={SelectedNodeId}
            //     SelectedSegmentId={SelectedSegmentId} HoveredNodeId={HoveredNodeId}
            //     HoveredSegmentId={HoveredSegmentId} IsInsideUI={MainTool.GetToolController().IsInsideUI}");

            // draw lane markers and connections
            hoveredMarker = null;

            ShowOverlay(false, cameraInfo);

            // draw bezier from source marker to mouse position in target marker selection
            if (SelectedNodeId != 0)
            {
                if (GetMarkerSelectionMode() == MarkerSelectionMode.SelectTarget)
                {
                    Vector3 selNodePos =
                        NetManager.instance.m_nodes.m_buffer[SelectedNodeId].m_position;

                    // Draw a currently dragged curve
                    var pos = HitPos;
                    if (hoveredMarker == null)
                    {
                        float hitH = TrafficManagerTool.GetAccurateHitHeight();
                        pos.y = hitH; // fix height.
                        float mouseH = MousePosition.y;
                        if (hitH < mouseH - MAX_HIT_ERROR)
                        {
                            // for metros lane curve is projected on the ground.
                            pos = MousePosition;
                        }
                    }
                    else
                    {
                        // snap to hovered:
                        pos = hoveredMarker.SecondaryPosition;
                    }
                    DrawLaneCurve(
                        cameraInfo,
                        selectedMarker.Position,
                        pos,
                        selNodePos,
                        Color.Lerp(selectedMarker.Color, Color.white, 0.33f),
                        Color.white,
                        size: 0.11f);
                }

                bool deleteAll =
                    (frameClearPressed > 0) && ((Time.frameCount - frameClearPressed) < 20); // 0.33 sec

                NetNode[] nodesBuffer = Singleton <NetManager> .instance.m_nodes.m_buffer;

                // Must press Shift+S (or another shortcut) within last 20 frames for this to work
                bool stayInLane = (frameStayInLanePressed > 0) &&
                                  ((Time.frameCount - frameStayInLanePressed) < 20) && // 0.33 sec
                                  (nodesBuffer[SelectedNodeId].CountSegments() == 2);

                if (stayInLane)
                {
                    frameStayInLanePressed = 0; // not pressed anymore (consumed)
                    deleteAll = true;
                }

                if (deleteAll)
                {
                    frameClearPressed = 0; // consumed
                    // remove all connections at selected node
                    LaneConnectionManager.Instance.RemoveLaneConnectionsFromNode(SelectedNodeId);
                    RefreshCurrentNodeMarkers(SelectedNodeId);
                }

                if (stayInLane)
                {
                    // "stay in lane"
                    switch (stayInLaneMode)
                    {
                    case StayInLaneMode.None: {
                        stayInLaneMode = StayInLaneMode.Both;
                        break;
                    }

                    case StayInLaneMode.Both: {
                        stayInLaneMode = StayInLaneMode.Forward;
                        break;
                    }

                    case StayInLaneMode.Forward: {
                        stayInLaneMode = StayInLaneMode.Backward;
                        break;
                    }

                    case StayInLaneMode.Backward: {
                        stayInLaneMode = StayInLaneMode.None;
                        break;
                    }
                    }

                    if (stayInLaneMode != StayInLaneMode.None)
                    {
                        selectedMarker = null;
                        StayInLane(SelectedNodeId, stayInLaneMode);
                        RefreshCurrentNodeMarkers(SelectedNodeId);
                    }
                } // if stay in lane
            }     // if selected node

            if ((GetMarkerSelectionMode() == MarkerSelectionMode.None) && (HoveredNodeId != 0))
            {
                // draw hovered node
                MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
            }
        }
        private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo)
        {
            if (viewOnly && !Options.connectedLanesOverlay)
            {
                return;
            }

            NetManager netManager = Singleton <NetManager> .instance;

            var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;
            //Bounds bounds = new Bounds(Vector3.zero, Vector3.one);
            Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);

            for (uint nodeId = 1; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId)
            {
                if (!Constants.ServiceFactory.NetService.IsNodeValid((ushort)nodeId))
                {
                    continue;
                }

                // TODO refactor connection class check
                ItemClass connectionClass = NetManager.instance.m_nodes.m_buffer[nodeId].Info.GetConnectionClass();
                if (connectionClass == null ||
                    !(connectionClass.m_service == ItemClass.Service.Road || (connectionClass.m_service == ItemClass.Service.PublicTransport &&
                                                                              (connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain ||
                                                                               connectionClass.m_subService == ItemClass.SubService.PublicTransportMetro ||
                                                                               connectionClass.m_subService == ItemClass.SubService.PublicTransportMonorail))))
                {
                    continue;
                }

                var diff = NetManager.instance.m_nodes.m_buffer[nodeId].m_position - camPos;
                if (diff.magnitude > TrafficManagerTool.MaxOverlayDistance)
                {
                    continue; // do not draw if too distant
                }
                List <NodeLaneMarker> nodeMarkers;
                var hasMarkers = currentNodeMarkers.TryGetValue((ushort)nodeId, out nodeMarkers);

                if (!viewOnly && GetMarkerSelectionMode() == MarkerSelectionMode.None)
                {
                    MainTool.DrawNodeCircle(cameraInfo, (ushort)nodeId, DefaultNodeMarkerColor, true);
                }

                if (hasMarkers)
                {
                    foreach (NodeLaneMarker laneMarker in nodeMarkers)
                    {
                        if (!Constants.ServiceFactory.NetService.IsLaneValid(laneMarker.laneId))
                        {
                            continue;
                        }

                        foreach (NodeLaneMarker targetLaneMarker in laneMarker.connectedMarkers)
                        {
                            // render lane connection from laneMarker to targetLaneMarker
                            if (!Constants.ServiceFactory.NetService.IsLaneValid(targetLaneMarker.laneId))
                            {
                                continue;
                            }
                            RenderLane(cameraInfo, laneMarker.position, targetLaneMarker.position, NetManager.instance.m_nodes.m_buffer[nodeId].m_position, laneMarker.color);
                        }

                        if (!viewOnly && nodeId == SelectedNodeId)
                        {
                            //bounds.center = laneMarker.position;
                            bool markerIsHovered = IsLaneMarkerHovered(laneMarker, ref mouseRay);// bounds.IntersectRay(mouseRay);

                            // draw source marker in source selection mode,
                            // draw target marker (if segment turning angles are within bounds) and selected source marker in target selection mode
                            bool drawMarker = (GetMarkerSelectionMode() == MarkerSelectionMode.SelectSource && laneMarker.isSource) ||
                                              (GetMarkerSelectionMode() == MarkerSelectionMode.SelectTarget && (
                                                   (laneMarker.isTarget &&
                                                    (laneMarker.vehicleType & selectedMarker.vehicleType) != VehicleInfo.VehicleType.None &&
                                                    CheckSegmentsTurningAngle(selectedMarker.segmentId, ref netManager.m_segments.m_buffer[selectedMarker.segmentId], selectedMarker.startNode, laneMarker.segmentId, ref netManager.m_segments.m_buffer[laneMarker.segmentId], laneMarker.startNode)
                                                   ) || laneMarker == selectedMarker));
                            // highlight hovered marker and selected marker
                            bool highlightMarker = drawMarker && (laneMarker == selectedMarker || markerIsHovered);

                            if (drawMarker)
                            {
                                if (highlightMarker)
                                {
                                    laneMarker.radius = 2f;
                                }
                                else
                                {
                                    laneMarker.radius = 1f;
                                }
                            }
                            else
                            {
                                markerIsHovered = false;
                            }

                            if (markerIsHovered)
                            {
                                /*if (hoveredMarker != sourceLaneMarker)
                                 *      Log._Debug($"Marker @ lane {sourceLaneMarker.laneId} hovered");*/
                                hoveredMarker = laneMarker;
                            }

                            if (drawMarker)
                            {
                                //DrawLaneMarker(laneMarker, cameraInfo);
                                RenderManager.instance.OverlayEffect.DrawCircle(cameraInfo, laneMarker.color, laneMarker.position, laneMarker.radius, laneMarker.position.y - 100f, laneMarker.position.y + 100f, false, true);
                            }
                        }
                    }
                }
            }
        }
        private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo)
        {
            if (viewOnly && !(Options.connectedLanesOverlay ||
                              PrioritySignsTool.MassEditOVerlay.IsActive))
            {
                return;
            }

            NetManager netManager = Singleton <NetManager> .instance;

            Vector3 camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;

            // Bounds bounds = new Bounds(Vector3.zero, Vector3.one);
            Camera currentCamera = Camera.main;
            Ray    mouseRay      = currentCamera.ScreenPointToRay(Input.mousePosition);

            // Check if camera pos/angle has changed then re-filter the visible nodes
            // Assumption: The states checked in this loop don't change while the tool is active
            var currentCameraState = new CameraTransformValue(currentCamera);

            if (!LastCachedCamera.Equals(currentCameraState))
            {
                CachedVisibleNodeIds.Clear();
                LastCachedCamera = currentCameraState;

                for (uint nodeId = 1; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId)
                {
                    if (!Constants.ServiceFactory.NetService.IsNodeValid((ushort)nodeId))
                    {
                        continue;
                    }

                    //---------------------------
                    // Check the connection class
                    //---------------------------
                    // TODO refactor connection class check
                    ItemClass connectionClass =
                        NetManager.instance.m_nodes.m_buffer[nodeId].Info.GetConnectionClass();

                    if ((connectionClass == null) ||
                        !((connectionClass.m_service == ItemClass.Service.Road) ||
                          ((connectionClass.m_service == ItemClass.Service.PublicTransport) &&
                           ((connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain) ||
                            (connectionClass.m_subService == ItemClass.SubService.PublicTransportMetro) ||
                            (connectionClass.m_subService == ItemClass.SubService.PublicTransportMonorail)))))
                    {
                        continue;
                    }

                    //--------------------------
                    // Check the camera distance
                    //--------------------------
                    Vector3 diff = NetManager.instance.m_nodes.m_buffer[nodeId].m_position - camPos;

                    if (diff.sqrMagnitude > TrafficManagerTool.MAX_OVERLAY_DISTANCE_SQR)
                    {
                        continue; // do not draw if too distant
                    }

                    // Add
                    CachedVisibleNodeIds.Add(nodeId);
                }
            }

            for (int cacheIndex = CachedVisibleNodeIds.Size - 1; cacheIndex >= 0; cacheIndex--)
            {
                var nodeId = CachedVisibleNodeIds.Values[cacheIndex];

                List <NodeLaneMarker> nodeMarkers;
                bool hasMarkers = currentNodeMarkers.TryGetValue((ushort)nodeId, out nodeMarkers);

                if (!viewOnly && (GetMarkerSelectionMode() == MarkerSelectionMode.None))
                {
                    MainTool.DrawNodeCircle(
                        cameraInfo,
                        (ushort)nodeId,
                        DefaultNodeMarkerColor,
                        true);
                }

                if (!hasMarkers)
                {
                    continue;
                }

                foreach (NodeLaneMarker laneMarker in nodeMarkers)
                {
                    if (!Constants.ServiceFactory.NetService.IsLaneValid(laneMarker.LaneId))
                    {
                        continue;
                    }

                    if (laneMarker != selectedMarker)
                    {
                        foreach (NodeLaneMarker targetLaneMarker in laneMarker.ConnectedMarkers)
                        {
                            // render lane connection from laneMarker to targetLaneMarker
                            if (!Constants.ServiceFactory.NetService.IsLaneValid(targetLaneMarker.LaneId))
                            {
                                continue;
                            }

                            DrawLaneCurve(
                                cameraInfo,
                                laneMarker.Position,
                                targetLaneMarker.Position,
                                NetManager.instance.m_nodes.m_buffer[nodeId].m_position,
                                laneMarker.Color,
                                Color.black);
                        }
                    }

                    if (viewOnly || (nodeId != SelectedNodeId))
                    {
                        continue;
                    }

                    // draw source marker in source selection mode,
                    // draw target marker (if segment turning angles are within bounds) and
                    // selected source marker in target selection mode
                    bool drawMarker
                        = ((GetMarkerSelectionMode() == MarkerSelectionMode.SelectSource) &&
                           laneMarker.IsSource) ||
                          ((GetMarkerSelectionMode() == MarkerSelectionMode.SelectTarget) &&
                           ((laneMarker.IsTarget &&
                             ((laneMarker.VehicleType & selectedMarker.VehicleType)
                              != VehicleInfo.VehicleType.None) &&
                             CheckSegmentsTurningAngle(
                                 selectedMarker.SegmentId,
                                 ref netManager.m_segments.m_buffer[selectedMarker.SegmentId],
                                 selectedMarker.StartNode,
                                 laneMarker.SegmentId,
                                 ref netManager.m_segments.m_buffer[laneMarker.SegmentId],
                                 laneMarker.StartNode)) ||
                            (laneMarker == selectedMarker)));

                    // highlight hovered marker and selected marker
                    if (drawMarker)
                    {
                        bool markerIsHovered = false;
                        if (hoveredMarker == null)
                        {
                            float hitH = TrafficManagerTool.GetAccurateHitHeight();
                            markerIsHovered =
                                laneMarker.segmentLaneMarker.IntersectRay(ref mouseRay, hitH);

                            if (markerIsHovered)
                            {
                                hoveredMarker = laneMarker;
                            }
                        }

                        bool isTarget        = selectedMarker != null && laneMarker != selectedMarker;
                        var  color           = isTarget ? Color.white : laneMarker.Color;
                        bool highlightMarker = laneMarker == selectedMarker || markerIsHovered;
                        if (highlightMarker)
                        {
                            laneMarker.segmentLaneMarker.RenderOverlay(cameraInfo, color, enlarge: true);
                        }
                        laneMarker.RenderOverlay(cameraInfo, color, enlarge: highlightMarker);
                    } // if drawMarker

                    if (selectedMarker != null)
                    {
                        // lane curves for selectedMarker will be drawn last to
                        // be on the top of other lane markers.
                        foreach (NodeLaneMarker targetLaneMarker in selectedMarker.ConnectedMarkers)
                        {
                            if (!Constants.ServiceFactory.NetService.IsLaneValid(targetLaneMarker.LaneId))
                            {
                                continue;
                            }

                            DrawLaneCurve(
                                cameraInfo,
                                selectedMarker.Position,
                                targetLaneMarker.Position,
                                NetManager.instance.m_nodes.m_buffer[nodeId].m_position,
                                selectedMarker.Color,
                                Color.grey,
                                size: 0.18f // Embolden
                                );
                        } // end foreach selectedMarker.ConnectedMarkers
                    } // end if selectedMarker != null
                }     // end foreach lanemarker in node markers
            }         // end for node in all nodes
        }
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            //Log._Debug($"LaneConnectorTool: RenderOverlay. SelectedNodeId={SelectedNodeId} SelectedSegmentId={SelectedSegmentId} HoveredNodeId={HoveredNodeId} HoveredSegmentId={HoveredSegmentId} IsInsideUI={MainTool.GetToolController().IsInsideUI}");
            // draw lane markers and connections

            hoveredMarker = null;

            ShowOverlay(false, cameraInfo);

            // draw bezier from source marker to mouse position in target marker selection
            if (SelectedNodeId != 0)
            {
                if (GetMarkerSelectionMode() == MarkerSelectionMode.SelectTarget)
                {
                    Vector3 selNodePos = NetManager.instance.m_nodes.m_buffer[SelectedNodeId].m_position;

                    ToolBase.RaycastOutput output;
                    if (RayCastSegmentAndNode(out output))
                    {
                        RenderLane(cameraInfo, selectedMarker.position, output.m_hitPos, selNodePos, selectedMarker.color);
                    }
                }

                var deleteAll = frameClearPressed > 0 && (Time.frameCount - frameClearPressed) < 20; // 0.33 sec

                // Must press Shift+S (or another shortcut) within last 20 frames for this to work
                var stayInLane = frameStayInLanePressed > 0 &&
                                 (Time.frameCount - frameStayInLanePressed) < 20 && // 0.33 sec
                                 Singleton <NetManager> .instance.m_nodes.m_buffer[SelectedNodeId].CountSegments() == 2;

                if (stayInLane)
                {
                    frameStayInLanePressed = 0; // not pressed anymore (consumed)
                    deleteAll = true;
                }

                if (deleteAll)
                {
                    frameClearPressed = 0; // consumed
                    // remove all connections at selected node
                    LaneConnectionManager.Instance.RemoveLaneConnectionsFromNode(SelectedNodeId);
                    RefreshCurrentNodeMarkers(SelectedNodeId);
                }

                if (stayInLane)
                {
                    // "stay in lane"
                    switch (stayInLaneMode)
                    {
                    case StayInLaneMode.None:
                        stayInLaneMode = StayInLaneMode.Both;
                        break;

                    case StayInLaneMode.Both:
                        stayInLaneMode = StayInLaneMode.Forward;
                        break;

                    case StayInLaneMode.Forward:
                        stayInLaneMode = StayInLaneMode.Backward;
                        break;

                    case StayInLaneMode.Backward:
                        stayInLaneMode = StayInLaneMode.None;
                        break;
                    }

                    if (stayInLaneMode != StayInLaneMode.None)
                    {
                        List <NodeLaneMarker> nodeMarkers = GetNodeMarkers(SelectedNodeId, ref Singleton <NetManager> .instance.m_nodes.m_buffer[SelectedNodeId]);
                        if (nodeMarkers != null)
                        {
                            selectedMarker = null;
                            foreach (NodeLaneMarker sourceLaneMarker in nodeMarkers)
                            {
                                if (!sourceLaneMarker.isSource)
                                {
                                    continue;
                                }

                                if (stayInLaneMode == StayInLaneMode.Forward || stayInLaneMode == StayInLaneMode.Backward)
                                {
                                    if (sourceLaneMarker.segmentIndex == 0 ^ stayInLaneMode == StayInLaneMode.Backward)
                                    {
                                        continue;
                                    }
                                }

                                foreach (NodeLaneMarker targetLaneMarker in nodeMarkers)
                                {
                                    if (!targetLaneMarker.isTarget || targetLaneMarker.segmentId == sourceLaneMarker.segmentId)
                                    {
                                        continue;
                                    }

                                    if (targetLaneMarker.innerSimilarLaneIndex == sourceLaneMarker.innerSimilarLaneIndex)
                                    {
                                        Log._Debug($"Adding lane connection {sourceLaneMarker.laneId} -> {targetLaneMarker.laneId}");
                                        LaneConnectionManager.Instance.AddLaneConnection(sourceLaneMarker.laneId, targetLaneMarker.laneId, sourceLaneMarker.startNode);
                                    }
                                }
                            }
                        }
                        RefreshCurrentNodeMarkers(SelectedNodeId);
                    }
                }
            }

            if (GetMarkerSelectionMode() == MarkerSelectionMode.None && HoveredNodeId != 0)
            {
                // draw hovered node
                MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
            }
        }
Esempio n. 18
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            // Log._Debug($"LaneConnectorTool: RenderOverlay. SelectedNodeId={SelectedNodeId}
            //     SelectedSegmentId={SelectedSegmentId} HoveredNodeId={HoveredNodeId}
            //     HoveredSegmentId={HoveredSegmentId} IsInsideUI={MainTool.GetToolController().IsInsideUI}");

            // draw lane markers and connections
            hoveredMarker = null;

            ShowOverlay(false, cameraInfo);

            // draw bezier from source marker to mouse position in target marker selection
            if (SelectedNodeId != 0)
            {
                if (GetMarkerSelectionMode() == MarkerSelectionMode.SelectTarget)
                {
                    Vector3 selNodePos =
                        NetManager.instance.m_nodes.m_buffer[SelectedNodeId].m_position;

                    ToolBase.RaycastOutput output;
                    // Draw a currently dragged curve
                    if (RayCastSegmentAndNode(out output))
                    {
                        DrawLaneCurve(
                            cameraInfo,
                            selectedMarker.Position,
                            output.m_hitPos,
                            selNodePos,
                            Color.Lerp(selectedMarker.Color, Color.white, 0.33f),
                            Color.white);
                    }
                }

                bool deleteAll =
                    (frameClearPressed > 0) && ((Time.frameCount - frameClearPressed) < 20); // 0.33 sec

                NetNode[] nodesBuffer = Singleton <NetManager> .instance.m_nodes.m_buffer;

                // Must press Shift+S (or another shortcut) within last 20 frames for this to work
                bool stayInLane = (frameStayInLanePressed > 0) &&
                                  ((Time.frameCount - frameStayInLanePressed) < 20) && // 0.33 sec
                                  (nodesBuffer[SelectedNodeId].CountSegments() == 2);

                if (stayInLane)
                {
                    frameStayInLanePressed = 0; // not pressed anymore (consumed)
                    deleteAll = true;
                }

                if (deleteAll)
                {
                    frameClearPressed = 0; // consumed
                    // remove all connections at selected node
                    LaneConnectionManager.Instance.RemoveLaneConnectionsFromNode(SelectedNodeId);
                    RefreshCurrentNodeMarkers(SelectedNodeId);
                }

                if (stayInLane)
                {
                    // "stay in lane"
                    switch (stayInLaneMode)
                    {
                    case StayInLaneMode.None: {
                        stayInLaneMode = StayInLaneMode.Both;
                        break;
                    }

                    case StayInLaneMode.Both: {
                        stayInLaneMode = StayInLaneMode.Forward;
                        break;
                    }

                    case StayInLaneMode.Forward: {
                        stayInLaneMode = StayInLaneMode.Backward;
                        break;
                    }

                    case StayInLaneMode.Backward: {
                        stayInLaneMode = StayInLaneMode.None;
                        break;
                    }
                    }

                    if (stayInLaneMode != StayInLaneMode.None)
                    {
                        selectedMarker = null;
                        StayInLane(SelectedNodeId, stayInLaneMode);
                        RefreshCurrentNodeMarkers(SelectedNodeId);
                    }
                } // if stay in lane
            }     // if selected node

            if ((GetMarkerSelectionMode() == MarkerSelectionMode.None) && (HoveredNodeId != 0))
            {
                // draw hovered node
                MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
            }
        }
Esempio n. 19
0
        private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo)
        {
            if (viewOnly && !Options.connectedLanesOverlay)
            {
                return;
            }

            NetManager netManager = Singleton <NetManager> .instance;

            Vector3 camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;

            // Bounds bounds = new Bounds(Vector3.zero, Vector3.one);
            Camera currentCamera = Camera.main;
            Ray    mouseRay      = currentCamera.ScreenPointToRay(Input.mousePosition);

            // Check if camera pos/angle has changed then re-filter the visible nodes
            // Assumption: The states checked in this loop don't change while the tool is active
            var currentCameraState = new CameraTransformValue(currentCamera);

            if (!LastCachedCamera.Equals(currentCameraState))
            {
                CachedVisibleNodeIds.Clear();
                LastCachedCamera = currentCameraState;

                for (uint nodeId = 1; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId)
                {
                    if (!Constants.ServiceFactory.NetService.IsNodeValid((ushort)nodeId))
                    {
                        continue;
                    }

                    //---------------------------
                    // Check the connection class
                    //---------------------------
                    // TODO refactor connection class check
                    ItemClass connectionClass =
                        NetManager.instance.m_nodes.m_buffer[nodeId].Info.GetConnectionClass();

                    if ((connectionClass == null) ||
                        !((connectionClass.m_service == ItemClass.Service.Road) ||
                          ((connectionClass.m_service == ItemClass.Service.PublicTransport) &&
                           ((connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain) ||
                            (connectionClass.m_subService == ItemClass.SubService.PublicTransportMetro) ||
                            (connectionClass.m_subService == ItemClass.SubService.PublicTransportMonorail)))))
                    {
                        continue;
                    }

                    //--------------------------
                    // Check the camera distance
                    //--------------------------
                    Vector3 diff = NetManager.instance.m_nodes.m_buffer[nodeId].m_position - camPos;

                    if (diff.sqrMagnitude > TrafficManagerTool.MAX_OVERLAY_DISTANCE_SQR)
                    {
                        continue; // do not draw if too distant
                    }

                    // Add
                    CachedVisibleNodeIds.Add(nodeId);
                }
            }

            for (int cacheIndex = CachedVisibleNodeIds.Size - 1; cacheIndex >= 0; cacheIndex--)
            {
                var nodeId = CachedVisibleNodeIds.Values[cacheIndex];

                List <NodeLaneMarker> nodeMarkers;
                bool hasMarkers = currentNodeMarkers.TryGetValue((ushort)nodeId, out nodeMarkers);

                if (!viewOnly && (GetMarkerSelectionMode() == MarkerSelectionMode.None))
                {
                    MainTool.DrawNodeCircle(
                        cameraInfo,
                        (ushort)nodeId,
                        DefaultNodeMarkerColor,
                        true);
                }

                if (!hasMarkers)
                {
                    continue;
                }

                foreach (NodeLaneMarker laneMarker in nodeMarkers)
                {
                    if (!Constants.ServiceFactory.NetService.IsLaneValid(laneMarker.LaneId))
                    {
                        continue;
                    }

                    foreach (NodeLaneMarker targetLaneMarker in laneMarker.ConnectedMarkers)
                    {
                        // render lane connection from laneMarker to targetLaneMarker
                        if (!Constants.ServiceFactory.NetService.IsLaneValid(targetLaneMarker.LaneId))
                        {
                            continue;
                        }

                        DrawLaneCurve(
                            cameraInfo,
                            laneMarker.Position,
                            targetLaneMarker.Position,
                            NetManager.instance.m_nodes.m_buffer[nodeId].m_position,
                            laneMarker.Color,
                            Color.black);
                    }

                    if (viewOnly || (nodeId != SelectedNodeId))
                    {
                        continue;
                    }

                    // bounds.center = laneMarker.position;
                    // bounds.IntersectRay(mouseRay);
                    bool markerIsHovered = IsLaneMarkerHovered(laneMarker, ref mouseRay);

                    // draw source marker in source selection mode,
                    // draw target marker (if segment turning angles are within bounds) and
                    // selected source marker in target selection mode
                    bool drawMarker
                        = ((GetMarkerSelectionMode() == MarkerSelectionMode.SelectSource) &&
                           laneMarker.IsSource) ||
                          ((GetMarkerSelectionMode() == MarkerSelectionMode.SelectTarget) &&
                           ((laneMarker.IsTarget &&
                             ((laneMarker.VehicleType & selectedMarker.VehicleType)
                              != VehicleInfo.VehicleType.None) &&
                             CheckSegmentsTurningAngle(
                                 selectedMarker.SegmentId,
                                 ref netManager.m_segments.m_buffer[selectedMarker.SegmentId],
                                 selectedMarker.StartNode,
                                 laneMarker.SegmentId,
                                 ref netManager.m_segments.m_buffer[laneMarker.SegmentId],
                                 laneMarker.StartNode)) ||
                            (laneMarker == selectedMarker)));

                    // highlight hovered marker and selected marker
                    bool highlightMarker =
                        drawMarker && ((laneMarker == selectedMarker) || markerIsHovered);

                    if (drawMarker)
                    {
                        laneMarker.Radius = highlightMarker ? 2f : 1f;
                    }
                    else
                    {
                        markerIsHovered = false;
                    }

                    if (markerIsHovered)
                    {
                        hoveredMarker = laneMarker;
                    }

                    var circleColor = laneMarker.IsTarget ? Color.white : laneMarker.Color;

                    if (drawMarker)
                    {
                        RenderManager.instance.OverlayEffect.DrawCircle(
                            cameraInfo,
                            circleColor,
                            laneMarker.Position,
                            laneMarker.Radius,
                            laneMarker.Position.y - 100f, // through all the geometry -100..100
                            laneMarker.Position.y + 100f,
                            false,
                            true);
                        RenderManager.instance.OverlayEffect.DrawCircle(
                            cameraInfo,
                            Color.black,
                            laneMarker.Position,
                            laneMarker.Radius * 0.75f,    // inner black
                            laneMarker.Position.y - 100f, // through all the geometry -100..100
                            laneMarker.Position.y + 100f,
                            false,
                            false);
                    }
                } // end foreach lanemarker in node markers
            }     // end for node in all nodes
        }
Esempio n. 20
0
        private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo)
        {
            if (viewOnly && !(Options.connectedLanesOverlay ||
                              PrioritySignsTool.MassEditOVerlay.IsActive))
            {
                return;
            }

            NetManager netManager = Singleton <NetManager> .instance;

            Vector3 camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;

            // Bounds bounds = new Bounds(Vector3.zero, Vector3.one);
            Camera currentCamera = Camera.main;

            // Check if camera pos/angle has changed then re-filter the visible nodes
            // Assumption: The states checked in this loop don't change while the tool is active
            var currentCameraState = new CameraTransformValue(currentCamera);

            if (!LastCachedCamera.Equals(currentCameraState))
            {
                CachedVisibleNodeIds.Clear();
                LastCachedCamera = currentCameraState;

                for (uint nodeId = 1; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId)
                {
                    if (!Constants.ServiceFactory.NetService.IsNodeValid((ushort)nodeId))
                    {
                        continue;
                    }

                    //---------------------------
                    // Check the connection class
                    //---------------------------
                    // TODO refactor connection class check
                    ItemClass connectionClass =
                        NetManager.instance.m_nodes.m_buffer[nodeId].Info.GetConnectionClass();

                    if ((connectionClass == null) ||
                        !((connectionClass.m_service == ItemClass.Service.Road) ||
                          ((connectionClass.m_service == ItemClass.Service.PublicTransport) &&
                           ((connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain) ||
                            (connectionClass.m_subService == ItemClass.SubService.PublicTransportMetro) ||
                            (connectionClass.m_subService == ItemClass.SubService.PublicTransportMonorail)))))
                    {
                        continue;
                    }

                    //--------------------------
                    // Check the camera distance
                    //--------------------------
                    Vector3 diff = NetManager.instance.m_nodes.m_buffer[nodeId].m_position - camPos;

                    if (diff.sqrMagnitude > TrafficManagerTool.MAX_OVERLAY_DISTANCE_SQR)
                    {
                        continue; // do not draw if too distant
                    }

                    // Add
                    CachedVisibleNodeIds.Add(nodeId);
                }
            }

            for (int cacheIndex = CachedVisibleNodeIds.Size - 1; cacheIndex >= 0; cacheIndex--)
            {
                var nodeId = CachedVisibleNodeIds.Values[cacheIndex];

                bool hasMarkers = currentLaneEnds.TryGetValue((ushort)nodeId, out List <LaneEnd> laneEnds);
                if (!viewOnly && (GetSelectionMode() == SelectionMode.None))
                {
                    MainTool.DrawNodeCircle(
                        cameraInfo,
                        (ushort)nodeId,
                        DefaultLaneEndColor,
                        true);
                }

                if (!hasMarkers)
                {
                    continue;
                }

                foreach (LaneEnd laneEnd in laneEnds)
                {
                    if (!Constants.ServiceFactory.NetService.IsLaneValid(laneEnd.LaneId))
                    {
                        continue;
                    }

                    if (laneEnd != selectedLaneEnd)
                    {
                        foreach (LaneEnd targetLaneEnd in laneEnd.ConnectedLaneEnds)
                        {
                            // render lane connection from laneEnd to targetLaneEnd
                            if (!Constants.ServiceFactory.NetService.IsLaneValid(targetLaneEnd.LaneId))
                            {
                                continue;
                            }

                            DrawLaneCurve(
                                cameraInfo,
                                laneEnd.NodeMarker.TerrainPosition,
                                targetLaneEnd.NodeMarker.TerrainPosition,
                                NetManager.instance.m_nodes.m_buffer[nodeId].m_position,
                                laneEnd.Color,
                                Color.black);
                        }
                    }

                    if (viewOnly || (nodeId != SelectedNodeId))
                    {
                        continue;
                    }

                    bool drawMarker = false;
                    bool SourceMode = GetSelectionMode() == SelectionMode.SelectSource;
                    bool TargetMode = GetSelectionMode() == SelectionMode.SelectTarget;
                    if (SourceMode & laneEnd.IsSource)
                    {
                        // draw source marker in source selection mode,
                        // make exception for markers that have no target:
                        foreach (var targetLaneEnd in laneEnds)
                        {
                            if (CanConnect(laneEnd, targetLaneEnd))
                            {
                                drawMarker = true;
                                break;
                            }
                        }
                    }
                    else if (TargetMode)
                    {
                        // selected source marker in target selection mode
                        drawMarker =
                            selectedLaneEnd == laneEnd ||
                            CanConnect(selectedLaneEnd, laneEnd);
                    }

                    // highlight hovered marker and selected marker
                    if (drawMarker)
                    {
                        bool markerIsHovered = false;
                        if (hoveredLaneEnd == null)
                        {
                            float hitH = TrafficManagerTool.GetAccurateHitHeight();
                            markerIsHovered =
                                laneEnd.IntersectRay();

                            if (markerIsHovered)
                            {
                                hoveredLaneEnd = laneEnd;
                            }
                        }

                        bool isTarget        = selectedLaneEnd != null && laneEnd != selectedLaneEnd;
                        var  color           = isTarget ? Color.white : laneEnd.Color;
                        bool highlightMarker = laneEnd == selectedLaneEnd || markerIsHovered;
                        laneEnd.RenderOverlay(cameraInfo, color, highlightMarker);
                    } // if drawMarker

                    if (selectedLaneEnd != null)
                    {
                        // lane curves for selectedMarker will be drawn last to
                        // be on the top of other lane markers.
                        foreach (LaneEnd targetLaneEnd in selectedLaneEnd.ConnectedLaneEnds)
                        {
                            if (!Constants.ServiceFactory.NetService.IsLaneValid(targetLaneEnd.LaneId))
                            {
                                continue;
                            }

                            DrawLaneCurve(
                                cameraInfo,
                                selectedLaneEnd.NodeMarker.TerrainPosition,
                                targetLaneEnd.NodeMarker.TerrainPosition,
                                NetManager.instance.m_nodes.m_buffer[nodeId].m_position,
                                selectedLaneEnd.Color,
                                Color.grey,
                                size: 0.18f // Embolden
                                );
                        } // end foreach selectedMarker.ConnectedMarkers
                    } // end if selectedMarker != null
                }     // end foreach lanemarker in node markers
            }         // end for node in all nodes
        }
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            //Log._Debug($"TppLaneConnectorTool: RenderOverlay. SelectedNodeId={SelectedNodeId} SelectedSegmentId={SelectedSegmentId} HoveredNodeId={HoveredNodeId} HoveredSegmentId={HoveredSegmentId} IsInsideUI={MainTool.GetToolController().IsInsideUI}");
            // draw lane markers and connections

            hoveredMarker = null;

            ShowOverlay(false, cameraInfo);

            // draw bezier from source marker to mouse position in target marker selection
            if (SelectedNodeId != 0)
            {
                if (GetMarkerSelectionMode() == MarkerSelectionMode.SelectTarget)
                {
                    Vector3 selNodePos = NetManager.instance.m_nodes.m_buffer[SelectedNodeId].m_position;

                    ToolBase.RaycastOutput output;
                    if (RayCastSegmentAndNode(out output))
                    {
                        RenderLane(cameraInfo, selectedMarker.position, output.m_hitPos, selNodePos, selectedMarker.color);
                    }
                }

                bool deleteAll  = Input.GetKeyDown(KeyCode.Delete) || Input.GetKeyDown(KeyCode.Backspace);
                bool stayInLane = Input.GetKeyDown(KeyCode.S) && (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) && Singleton <NetManager> .instance.m_nodes.m_buffer[SelectedNodeId].CountSegments() == 2;
                if (stayInLane)
                {
                    deleteAll = true;
                }

                if (deleteAll)
                {
                    // remove all connections at selected node
                    LaneConnectionManager.Instance.RemoveLaneConnectionsFromNode(SelectedNodeId);
                    RefreshCurrentNodeMarkers(SelectedNodeId);
                }

                if (stayInLane)
                {
                    // "stay in lane"
                    switch (stayInLaneMode)
                    {
                    case StayInLaneMode.None:
                        stayInLaneMode = StayInLaneMode.Both;
                        break;

                    case StayInLaneMode.Both:
                        stayInLaneMode = StayInLaneMode.Forward;
                        break;

                    case StayInLaneMode.Forward:
                        stayInLaneMode = StayInLaneMode.Backward;
                        break;

                    case StayInLaneMode.Backward:
                        stayInLaneMode = StayInLaneMode.None;
                        break;
                    }

                    if (stayInLaneMode != StayInLaneMode.None)
                    {
                        List <NodeLaneMarker> nodeMarkers = GetNodeMarkers(SelectedNodeId, ref Singleton <NetManager> .instance.m_nodes.m_buffer[SelectedNodeId]);
                        if (nodeMarkers != null)
                        {
                            selectedMarker = null;
                            foreach (NodeLaneMarker sourceLaneMarker in nodeMarkers)
                            {
                                if (!sourceLaneMarker.isSource)
                                {
                                    continue;
                                }

                                if (stayInLaneMode == StayInLaneMode.Forward || stayInLaneMode == StayInLaneMode.Backward)
                                {
                                    if (sourceLaneMarker.finalDirection == NetInfo.Direction.Backward ^ stayInLaneMode == StayInLaneMode.Backward)
                                    {
                                        continue;
                                    }
                                }

                                foreach (NodeLaneMarker targetLaneMarker in nodeMarkers)
                                {
                                    if (!targetLaneMarker.isTarget || targetLaneMarker.segmentId == sourceLaneMarker.segmentId)
                                    {
                                        continue;
                                    }

                                    if (targetLaneMarker.innerSimilarLaneIndex == sourceLaneMarker.innerSimilarLaneIndex)
                                    {
                                        Log._Debug($"Adding lane connection {sourceLaneMarker.laneId} -> {targetLaneMarker.laneId}");
                                        LaneConnectionManager.Instance.AddLaneConnection(sourceLaneMarker.laneId, targetLaneMarker.laneId, sourceLaneMarker.startNode);
                                    }
                                }
                            }
                        }
                        RefreshCurrentNodeMarkers(SelectedNodeId);
                    }
                }
            }

            if (GetMarkerSelectionMode() == MarkerSelectionMode.None && HoveredNodeId != 0)
            {
                // draw hovered node
                MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
            }
        }