Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Half overlay #564

Merged
merged 17 commits into from
Dec 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions TLM/TLM/Manager/Impl/LaneArrowManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,15 +319,20 @@ public static void SeparateSegmentLanes(ushort segmentId, ushort nodeId, out Set
if (numdirs < 2) {
return; // no junction
}
bool lht = LaneArrowManager.Instance.Services.SimulationService.TrafficDrivesOnLeft;

if (srcLaneCount == 2 && numdirs == 3) {
LaneArrowManager.Instance.SetLaneArrows(laneList[0].laneId, LaneArrows.LeftForward);
LaneArrowManager.Instance.SetLaneArrows(laneList[1].laneId, LaneArrows.Right);
if (!lht) {
LaneArrowManager.Instance.SetLaneArrows(laneList[0].laneId, LaneArrows.LeftForward);
LaneArrowManager.Instance.SetLaneArrows(laneList[1].laneId, LaneArrows.Right);
}else {
LaneArrowManager.Instance.SetLaneArrows(laneList[1].laneId, LaneArrows.ForwardRight);
LaneArrowManager.Instance.SetLaneArrows(laneList[0].laneId, LaneArrows.Left);
}
return;
}

int l = 0, f = 0, r = 0;
bool lht = LaneArrowManager.Instance.Services.SimulationService.TrafficDrivesOnLeft;
if (numdirs == 2) {
if (!lht) {
//if traffic drives on right, then favour the more difficult left turns.
Expand Down
6 changes: 3 additions & 3 deletions TLM/TLM/UI/SubTool.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace TrafficManager.UI {
namespace TrafficManager.UI {
using ColossalFramework.UI;
using JetBrains.Annotations;
using Textures;
Expand Down Expand Up @@ -78,12 +78,12 @@ private Texture2D BorderlessTexture {

private GUIStyle borderlessStyle_;

protected ushort HoveredNodeId {
protected virtual ushort HoveredNodeId {
get => TrafficManagerTool.HoveredNodeId;
set => TrafficManagerTool.HoveredNodeId = value;
}

protected ushort HoveredSegmentId {
protected virtual ushort HoveredSegmentId {
get => TrafficManagerTool.HoveredSegmentId;
set => TrafficManagerTool.HoveredSegmentId = value;
}
Expand Down
106 changes: 84 additions & 22 deletions TLM/TLM/UI/SubTools/LaneArrowTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace TrafficManager.UI.SubTools {
using GenericGameBridge.Service;
using Manager.Impl;
using State;
using TrafficManager.API.Traffic.Data;
using UnityEngine;

public class LaneArrowTool : SubTool {
Expand Down Expand Up @@ -41,7 +42,7 @@ public override void OnPrimaryClickOverlay() {
LaneArrowManager.SeparateTurningLanes.SeparateSegmentLanes(HoveredSegmentId, HoveredNodeId, out res);
} else if (ctrlDown) {
LaneArrowManager.SeparateTurningLanes.SeparateNode(HoveredNodeId, out res);
} else {
} else if (HasHoverLaneArrows()) {
SelectedSegmentId = HoveredSegmentId;
SelectedNodeId = HoveredNodeId;
}
Expand Down Expand Up @@ -108,20 +109,89 @@ public override void OnToolGUI(Event e) {
cursorInSecondaryPanel_ = windowRect3.Contains(Event.current.mousePosition);
}

/// <summary>
/// Determines whether or not the hovered segment end has lane arrows.
/// </summary>
private bool HasHoverLaneArrows() => HasSegmentEndLaneArrows(HoveredSegmentId, HoveredNodeId);

/// <summary>
/// determines whether or not the given segment end has lane arrows.
/// </summary>
private bool HasSegmentEndLaneArrows(ushort segmentId, ushort nodeId) {
if(nodeId == 0 || segmentId == 0) {
return false;
}
#if DEBUG
if(!Constants.ServiceFactory.NetService.IsNodeValid(nodeId) ||
!Constants.ServiceFactory.NetService.IsSegmentValid(segmentId)) {
Debug.LogError("Invalid node or segment ID");
}
#endif
ExtSegmentEndManager segEndMan = ExtSegmentEndManager.Instance;
ExtSegmentEnd segEnd = segEndMan.ExtSegmentEnds[segEndMan.GetIndex(segmentId, nodeId)];
NetNode[] nodesBuffer = Singleton<NetManager>.instance.m_nodes.m_buffer;
bool bJunction = (nodesBuffer[nodeId].m_flags & NetNode.Flags.Junction) != 0;

// Outgoing lanes toward the node is incomming lanes to the segment end.
return bJunction && segEnd.incoming;
}

protected override ushort HoveredNodeId {
get {
// if the current segment end does not have lane arrows
// and the other end of the segment does have lane arrows, then
// assume the user intends to hover over that one.
// This code makes it easier to hover over small segments.
if (!HasSegmentEndLaneArrows(HoveredSegmentId, base.HoveredNodeId))
{
ref NetSegment segment = ref Singleton<NetManager>.instance.m_segments.m_buffer[HoveredSegmentId];
ushort otherNodeId = segment.GetOtherNode(base.HoveredNodeId);
if (HasSegmentEndLaneArrows(HoveredSegmentId, otherNodeId)) {
return otherNodeId;
}
}
return base.HoveredNodeId;
}
set => base.HoveredNodeId = value;
}

/// <summary>
/// Draws a half sausage to highlight the segment end.
/// </summary>
private void DrawSegmentEnd(
kianzarrin marked this conversation as resolved.
Show resolved Hide resolved
RenderManager.CameraInfo cameraInfo,
ushort segmentId,
bool bStartNode,
Color color,
bool alpha = false) {
ref NetSegment segment = ref Singleton<NetManager>.instance.m_segments.m_buffer[segmentId];

// if only one side of the segment has lane arrows then the length of the
// is 1. but the highlight still looks like a sausage which is cut at one end.
// this is important to give user visual feedback which area is hoverable.
bool con =
HasSegmentEndLaneArrows(segmentId, segment.m_startNode) ^
HasSegmentEndLaneArrows(segmentId, segment.m_endNode);
float cut = con ? 1f : 0.5f;

MainTool.DrawCutSegmentEnd(cameraInfo, segmentId, cut, bStartNode, color, alpha);
}

public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) {
NetManager netManager = Singleton<NetManager>.instance;

bool ctrlDown = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
bool altDown = Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt);

if (ctrlDown) {
bool PrimaryDown = Input.GetMouseButton(0);
if (ctrlDown && !cursorInSecondaryPanel_ && (HoveredNodeId != 0)) {
// draw hovered node
MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
return;
}

// Log._Debug($"LaneArrow Overlay: {HoveredNodeId} {HoveredSegmentId} {SelectedNodeId} {SelectedSegmentId}");
if (!cursorInSecondaryPanel_
&& HasHoverLaneArrows()
&& (HoveredSegmentId != 0)
&& (HoveredNodeId != 0)
&& ((HoveredSegmentId != SelectedSegmentId)
Expand All @@ -131,28 +201,20 @@ public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) {

if (((netManager.m_segments.m_buffer[HoveredSegmentId].m_startNode == HoveredNodeId)
|| (netManager.m_segments.m_buffer[HoveredSegmentId].m_endNode == HoveredNodeId))
&& ((nodeFlags & NetNode.Flags.Junction) != NetNode.Flags.None))
{
NetTool.RenderOverlay(
cameraInfo,
ref Singleton<NetManager>.instance.m_segments.m_buffer[HoveredSegmentId],
MainTool.GetToolColor(altDown, false),
MainTool.GetToolColor(altDown, false));
&& ((nodeFlags & NetNode.Flags.Junction) != NetNode.Flags.None)) {
bool bStartNode = (bool)Constants.ServiceFactory.NetService.IsStartNode(HoveredSegmentId, HoveredNodeId);
Color color = MainTool.GetToolColor(PrimaryDown, false);
bool alpha = !altDown;
DrawSegmentEnd(cameraInfo, HoveredSegmentId, bStartNode, color, alpha);
}
}

if (SelectedSegmentId == 0) return;

Color color;
if (altDown && HoveredSegmentId == SelectedSegmentId)
color = MainTool.GetToolColor(true, true);
else
color = MainTool.GetToolColor(true, false);
NetTool.RenderOverlay(
cameraInfo,
ref Singleton<NetManager>.instance.m_segments.m_buffer[SelectedSegmentId],
color,
color);
if (SelectedSegmentId != 0) {
Color color = MainTool.GetToolColor(true, false);
bool bStartNode = (bool)Constants.ServiceFactory.NetService.IsStartNode(SelectedSegmentId, SelectedNodeId);
bool alpha = !altDown && HoveredSegmentId == SelectedSegmentId;
DrawSegmentEnd(cameraInfo, SelectedSegmentId, bStartNode, color, alpha);
}
}

private void GuiLaneChangeWindow(int num) {
Expand Down
85 changes: 64 additions & 21 deletions TLM/TLM/UI/TrafficManagerTool.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace TrafficManager.UI {
namespace TrafficManager.UI {
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -410,57 +410,100 @@ protected override void OnToolGUI(Event e) {
}
}


public void DrawNodeCircle(RenderManager.CameraInfo cameraInfo,
ushort nodeId,
bool warning = false,
bool alpha = false) {
DrawNodeCircle(cameraInfo, nodeId, GetToolColor(warning, false), alpha);
}

/// <summary>
/// Gets the coordinates of the given node.
/// </summary>
private static Vector3 GetNodePos(ushort nodeId) {
NetNode[] nodeBuffer = Singleton<NetManager>.instance.m_nodes.m_buffer;
Vector3 pos = nodeBuffer[nodeId].m_position;
float terrainY = Singleton<TerrainManager>.instance.SampleDetailHeightSmooth(pos);
if (terrainY > pos.y) {
pos.y = terrainY;
}
return pos;
}

/// <returns>the average half width of all connected segments</returns>
private static float CalculateNodeRadius(ushort nodeId) {

float sum_half_width = 0;
int count = 0;
Constants.ServiceFactory.NetService.IterateNodeSegments(
nodeId,
(ushort segmentId, ref NetSegment segment) => {
sum_half_width += segment.Info.m_halfWidth;
count++;
return true;
});
return sum_half_width / count;
kianzarrin marked this conversation as resolved.
Show resolved Hide resolved
}

public void DrawNodeCircle(RenderManager.CameraInfo cameraInfo,
ushort nodeId,
Color color,
bool alpha = false) {
NetNode[] nodesBuffer = Singleton<NetManager>.instance.m_nodes.m_buffer;
NetSegment segment =
Singleton<NetManager>.instance.m_segments.m_buffer[ nodesBuffer[nodeId].m_segment0];
float r = CalculateNodeRadius(nodeId);
Vector3 pos = Singleton<NetManager>.instance.m_nodes.m_buffer[nodeId].m_position;
DrawOverlayCircle(cameraInfo, color, pos, r * 2, alpha);
}

Vector3 pos = nodesBuffer[nodeId].m_position;
float terrainY = Singleton<TerrainManager>.instance.SampleDetailHeightSmooth(pos);
if (terrainY > pos.y) {
pos.y = terrainY;
/// <summary>
/// Draws a half sausage at segment end.
/// </summary>
/// <param name="segmentId"></param>
/// <param name="cut">The lenght of the highlight [0~1] </param>
/// <param name="bStartNode">Determines the direction of the half sausage.</param>
public void DrawCutSegmentEnd(RenderManager.CameraInfo cameraInfo,
kianzarrin marked this conversation as resolved.
Show resolved Hide resolved
ushort segmentId,
float cut,
bool bStartNode,
Color color,
bool alpha = false) {
if( segmentId == 0) {
return;
}
ref NetSegment segment = ref Singleton<NetManager>.instance.m_segments.m_buffer[segmentId];
float width = segment.Info.m_halfWidth;

NetNode[] nodeBuffer = Singleton<NetManager>.instance.m_nodes.m_buffer;
bool IsMiddle(ushort nodeId) => (nodeBuffer[nodeId].m_flags & NetNode.Flags.Middle) != 0;
kianzarrin marked this conversation as resolved.
Show resolved Hide resolved

Bezier3 bezier;
bezier.a = pos;
bezier.d = pos;
bezier.a = GetNodePos(segment.m_startNode);
bezier.d = GetNodePos(segment.m_endNode);

NetSegment.CalculateMiddlePoints(
bezier.a,
segment.m_startDirection,
bezier.d,
segment.m_endDirection,
false,
false,
IsMiddle(segment.m_startNode),
IsMiddle(segment.m_endNode),
out bezier.b,
out bezier.c);

DrawOverlayBezier(cameraInfo, bezier, color, alpha);
}
if (bStartNode) {
bezier = bezier.Cut(0, cut);
} else {
bezier = bezier.Cut(1 - cut, 1);
}

private void DrawOverlayBezier(RenderManager.CameraInfo cameraInfo,
Bezier3 bezier,
Color color,
bool alpha = false) {
const float width = 8f; // 8 - small roads; 16 - big roads
Singleton<ToolManager>.instance.m_drawCallData.m_overlayCalls++;
Singleton<RenderManager>.instance.OverlayEffect.DrawBezier(
cameraInfo,
color,
bezier,
width * 2f,
width,
width,
bStartNode ? 0 : width,
bStartNode ? width : 0,
-1f,
1280f,
false,
Expand Down