1 using Godot;
2 
3 // This is identical to the GDScript version, yet it doesn't work.
4 [Tool]
5 public class Viewport25D : Control
6 {
7     private int zoomLevel = 0;
8     private bool isPanning = false;
9     private Vector2 panCenter;
10     private Vector2 viewportCenter;
11     private int viewModeIndex = 0;
12 
13     // The type or namespace name 'EditorInterface' could not be found (are you missing a using directive or an assembly reference?)
14     // No idea why this error shows up in VS Code. It builds fine...
15     public EditorInterface editorInterface; // Set in node25d_plugin.gd
16     private bool moving = false;
17 
18     private Viewport viewport2d;
19     private Viewport viewportOverlay;
20     private ButtonGroup viewModeButtonGroup;
21     private Label zoomLabel;
22     private PackedScene gizmo25dScene;
23 
_Ready()24     public async override void _Ready()
25     {
26         // Give Godot a chance to fully load the scene. Should take two frames.
27         //yield(get_tree(), "idle_frame");
28         //yield(get_tree(), "idle_frame");
29         await ToSignal(GetTree(), "idle_frame");
30         await ToSignal(GetTree(), "idle_frame");
31         var editedSceneRoot = GetTree().EditedSceneRoot;
32         if (editedSceneRoot == null)
33         {
34             // Godot hasn't finished loading yet, so try loading the plugin again.
35             //editorInterface.SetPluginEnabled("node25d", false);
36             //editorInterface.SetPluginEnabled("node25d", true);
37             return;
38         }
39         // Alright, we're loaded up. Now check if we have a valid world and assign it.
40         var world2d = editedSceneRoot.GetViewport().World2d;
41         if (world2d == GetViewport().World2d)
42         {
43             return; // This is the MainScreen25D scene opened in the editor!
44         }
45         viewport2d.World2d = world2d;
46 
47         // Onready vars.
48         viewport2d = GetNode<Viewport>("Viewport2D");
49         viewportOverlay = GetNode<Viewport>("ViewportOverlay");
50         viewModeButtonGroup = GetParent().GetNode("TopBar").GetNode("ViewModeButtons").GetNode<Button>("45Degree").Group;
51         zoomLabel = GetParent().GetNode("TopBar").GetNode("Zoom").GetNode<Label>("ZoomPercent");
52         gizmo25dScene = ResourceLoader.Load<PackedScene>("res://addons/node25d/main_screen/gizmo_25d.tscn");
53     }
54 
55 
_Process(float delta)56     public override void _Process(float delta)
57     {
58         if (editorInterface == null) // Something's not right... bail!
59         {
60             return;
61         }
62 
63         // View mode polling.
64         var viewModeChangedThisFrame = false;
65         var newViewMode = viewModeButtonGroup.GetPressedButton().GetIndex();
66         if (viewModeIndex != newViewMode)
67         {
68             viewModeIndex = newViewMode;
69             viewModeChangedThisFrame = true;
70             RecursiveChangeViewMode(GetTree().EditedSceneRoot);
71         }
72 
73         // Zooming.
74         if (Input.IsMouseButtonPressed((int)ButtonList.WheelUp))
75         {
76             zoomLevel += 1;
77         }
78         else if (Input.IsMouseButtonPressed((int)ButtonList.WheelDown))
79         {
80             zoomLevel -= 1;
81         }
82         float zoom = GetZoomAmount();
83 
84         // Viewport size.
85         Vector2 size = GetGlobalRect().Size;
86         viewport2d.Size = size;
87 
88         // Viewport transform.
89         Transform2D viewportTrans = Transform2D.Identity;
90         viewportTrans.x *= zoom;
91         viewportTrans.y *= zoom;
92         viewportTrans.origin = viewportTrans.BasisXform(viewportCenter) + size / 2;
93         viewport2d.CanvasTransform = viewportTrans;
94         viewportOverlay.CanvasTransform = viewportTrans;
95 
96         // Delete unused gizmos.
97         var selection = editorInterface.GetSelection().GetSelectedNodes();
98         var overlayChildren = viewportOverlay.GetChildren();
99         foreach (Gizmo25D overlayChild in overlayChildren)
100         {
101             bool contains = false;
102             foreach (Node selected in selection)
103             {
104                 if (selected == overlayChild.node25d && !viewModeChangedThisFrame)
105                 {
106                     contains = true;
107                 }
108             }
109             if (!contains)
110             {
111                 overlayChild.QueueFree();
112             }
113         }
114         // Add new gizmos.
115         foreach (Node sel in selection)
116         {
117             if (sel is Node25D selected)
118             {
119                 var newNode = true;
120                 foreach (Gizmo25D overlayChild2 in overlayChildren)
121                 {
122                     if (selected == overlayChild2.node25d)
123                     {
124                         newNode = false;
125                     }
126                 }
127                 if (newNode)
128                 {
129                     Gizmo25D gizmo = (Gizmo25D)gizmo25dScene.Instance();
130                     viewportOverlay.AddChild(gizmo);
131                     gizmo.node25d = selected;
132                     gizmo.Initialize();
133                 }
134             }
135         }
136     }
137 
138     // This only accepts input when the mouse is inside of the 2.5D viewport.
_GuiInput(InputEvent inputEvent)139     public override void _GuiInput(InputEvent inputEvent)
140     {
141         if (inputEvent is InputEventMouseButton mouseButtonEvent)
142         {
143             if (mouseButtonEvent.IsPressed())
144             {
145                 if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.WheelUp)
146                 {
147                     zoomLevel += 1;
148                     AcceptEvent();
149                 }
150                 else if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.WheelDown)
151                 {
152                     zoomLevel -= 1;
153                     AcceptEvent();
154                 }
155                 else if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.Middle)
156                 {
157                     isPanning = true;
158                     panCenter = viewportCenter - mouseButtonEvent.Position;
159                     AcceptEvent();
160                 }
161                 else if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.Left)
162                 {
163                     var overlayChildren2 = viewportOverlay.GetChildren();
164                     foreach (Gizmo25D overlayChild in overlayChildren2)
165                     {
166                         overlayChild.wantsToMove = true;
167                     }
168                     AcceptEvent();
169                 }
170             }
171             else if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.Middle)
172             {
173                 isPanning = false;
174                 AcceptEvent();
175             }
176             else if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.Left)
177             {
178                 var overlayChildren3 = viewportOverlay.GetChildren();
179                 foreach (Gizmo25D overlayChild in overlayChildren3)
180                 {
181                     overlayChild.wantsToMove = false;
182                 }
183                 AcceptEvent();
184             }
185         }
186         else if (inputEvent is InputEventMouseMotion mouseEvent)
187         {
188             if (isPanning)
189             {
190                 viewportCenter = panCenter + mouseEvent.Position;
191                 AcceptEvent();
192             }
193         }
194     }
195 
RecursiveChangeViewMode(Node currentNode)196     public void RecursiveChangeViewMode(Node currentNode)
197     {
198         // TODO
199         if (currentNode.HasMethod("SetViewMode"))
200         {
201             //currentNode.SetViewMode(viewModeIndex);
202         }
203         foreach (Node child in currentNode.GetChildren())
204         {
205             RecursiveChangeViewMode(child);
206         }
207     }
208 
GetZoomAmount()209     private float GetZoomAmount()
210     {
211         float zoomAmount = Mathf.Pow(1.05476607648f, zoomLevel); // 13th root of 2
212         zoomLabel.Text = Mathf.Round(zoomAmount * 1000) / 10 + "%";
213         return zoomAmount;
214     }
215 
OnZoomOutPressed()216     public void OnZoomOutPressed()
217     {
218         zoomLevel -= 1;
219     }
220 
OnZoomInPressed()221     public void OnZoomInPressed()
222     {
223         zoomLevel += 1;
224     }
225 
OnZoomResetPressed()226     public void OnZoomResetPressed()
227     {
228         zoomLevel = 0;
229     }
230 }
231