Merge branch 'master' into Visject-ContextSensitiveNodes
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices.Marshalling;
|
using System.Runtime.InteropServices.Marshalling;
|
||||||
@@ -13,6 +14,7 @@ using FlaxEditor.Content.Thumbnails;
|
|||||||
using FlaxEditor.Modules;
|
using FlaxEditor.Modules;
|
||||||
using FlaxEditor.Modules.SourceCodeEditing;
|
using FlaxEditor.Modules.SourceCodeEditing;
|
||||||
using FlaxEditor.Options;
|
using FlaxEditor.Options;
|
||||||
|
using FlaxEditor.SceneGraph.Actors;
|
||||||
using FlaxEditor.States;
|
using FlaxEditor.States;
|
||||||
using FlaxEditor.Windows;
|
using FlaxEditor.Windows;
|
||||||
using FlaxEditor.Windows.Assets;
|
using FlaxEditor.Windows.Assets;
|
||||||
@@ -1274,6 +1276,69 @@ namespace FlaxEditor
|
|||||||
Scene.MarkSceneEdited(scenes);
|
Scene.MarkSceneEdited(scenes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bakes all environmental probes in the scene.
|
||||||
|
/// </summary>
|
||||||
|
public void BakeAllEnvProbes()
|
||||||
|
{
|
||||||
|
Scene.ExecuteOnGraph(node =>
|
||||||
|
{
|
||||||
|
if (node is EnvironmentProbeNode envProbeNode && envProbeNode.IsActive)
|
||||||
|
{
|
||||||
|
((EnvironmentProbe)envProbeNode.Actor).Bake();
|
||||||
|
node.ParentScene.IsEdited = true;
|
||||||
|
}
|
||||||
|
else if (node is SkyLightNode skyLightNode && skyLightNode.IsActive && skyLightNode.Actor is SkyLight skyLight && skyLight.Mode == SkyLight.Modes.CaptureScene)
|
||||||
|
{
|
||||||
|
skyLight.Bake();
|
||||||
|
node.ParentScene.IsEdited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.IsActive;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds CSG for all open scenes.
|
||||||
|
/// </summary>
|
||||||
|
public void BuildCSG()
|
||||||
|
{
|
||||||
|
var scenes = Level.Scenes;
|
||||||
|
scenes.ToList().ForEach(x => x.BuildCSG(0));
|
||||||
|
Scene.MarkSceneEdited(scenes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds Nav mesh for all open scenes.
|
||||||
|
/// </summary>
|
||||||
|
public void BuildNavMesh()
|
||||||
|
{
|
||||||
|
var scenes = Level.Scenes;
|
||||||
|
scenes.ToList().ForEach(x => Navigation.BuildNavMesh(x, 0));
|
||||||
|
Scene.MarkSceneEdited(scenes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds SDF for all static models in the scene.
|
||||||
|
/// </summary>
|
||||||
|
public void BuildAllMeshesSDF()
|
||||||
|
{
|
||||||
|
// TODO: async maybe with progress reporting?
|
||||||
|
Scene.ExecuteOnGraph(node =>
|
||||||
|
{
|
||||||
|
if (node is StaticModelNode staticModelNode && staticModelNode.Actor is StaticModel staticModel)
|
||||||
|
{
|
||||||
|
if (staticModel.DrawModes.HasFlag(DrawPass.GlobalSDF) && staticModel.Model != null && !staticModel.Model.IsVirtual && staticModel.Model.SDF.Texture == null)
|
||||||
|
{
|
||||||
|
Log("Generating SDF for " + staticModel.Model);
|
||||||
|
if (!staticModel.Model.GenerateSDF())
|
||||||
|
staticModel.Model.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Internal Calls
|
#region Internal Calls
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using FlaxEditor.Options;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
@@ -269,6 +270,24 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the button.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The text.</param>
|
||||||
|
/// <param name="binding">The input binding.</param>
|
||||||
|
/// <param name="clicked">On button clicked event.</param>
|
||||||
|
/// <returns>Created context menu item control.</returns>
|
||||||
|
public ContextMenuButton AddButton(string text, InputBinding binding, Action clicked)
|
||||||
|
{
|
||||||
|
var item = new ContextMenuButton(this, text, binding.ToString())
|
||||||
|
{
|
||||||
|
Parent = _panel
|
||||||
|
};
|
||||||
|
item.Clicked += clicked;
|
||||||
|
SortButtons();
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the child menu (with that name).
|
/// Gets the child menu (with that name).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -42,8 +42,10 @@ namespace FlaxEditor.Modules
|
|||||||
|
|
||||||
private ContextMenuButton _menuFileSaveScenes;
|
private ContextMenuButton _menuFileSaveScenes;
|
||||||
private ContextMenuButton _menuFileCloseScenes;
|
private ContextMenuButton _menuFileCloseScenes;
|
||||||
|
private ContextMenuButton _menuFileOpenScriptsProject;
|
||||||
private ContextMenuButton _menuFileGenerateScriptsProjectFiles;
|
private ContextMenuButton _menuFileGenerateScriptsProjectFiles;
|
||||||
private ContextMenuButton _menuSaveAll;
|
private ContextMenuButton _menuFileRecompileScripts;
|
||||||
|
private ContextMenuButton _menuFileSaveAll;
|
||||||
private ContextMenuButton _menuEditUndo;
|
private ContextMenuButton _menuEditUndo;
|
||||||
private ContextMenuButton _menuEditRedo;
|
private ContextMenuButton _menuEditRedo;
|
||||||
private ContextMenuButton _menuEditCut;
|
private ContextMenuButton _menuEditCut;
|
||||||
@@ -62,15 +64,19 @@ namespace FlaxEditor.Modules
|
|||||||
private ContextMenuButton _menuGamePlayCurrentScenes;
|
private ContextMenuButton _menuGamePlayCurrentScenes;
|
||||||
private ContextMenuButton _menuGameStop;
|
private ContextMenuButton _menuGameStop;
|
||||||
private ContextMenuButton _menuGamePause;
|
private ContextMenuButton _menuGamePause;
|
||||||
|
private ContextMenuButton _menuGameCookAndRun;
|
||||||
|
private ContextMenuButton _menuGameRunCookedGame;
|
||||||
private ContextMenuButton _menuToolsBuildScenes;
|
private ContextMenuButton _menuToolsBuildScenes;
|
||||||
private ContextMenuButton _menuToolsBakeLightmaps;
|
private ContextMenuButton _menuToolsBakeLightmaps;
|
||||||
private ContextMenuButton _menuToolsClearLightmaps;
|
private ContextMenuButton _menuToolsClearLightmaps;
|
||||||
private ContextMenuButton _menuToolsBakeAllEnvProbes;
|
private ContextMenuButton _menuToolsBakeAllEnvProbes;
|
||||||
private ContextMenuButton _menuToolsBuildCSGMesh;
|
private ContextMenuButton _menuToolsBuildCSGMesh;
|
||||||
private ContextMenuButton _menuToolsBuildNavMesh;
|
private ContextMenuButton _menuToolsBuildNavMesh;
|
||||||
private ContextMenuButton _menuToolsBuildAllMesgesSDF;
|
private ContextMenuButton _menuToolsBuildAllMeshesSDF;
|
||||||
private ContextMenuButton _menuToolsCancelBuilding;
|
private ContextMenuButton _menuToolsCancelBuilding;
|
||||||
|
private ContextMenuButton _menuToolsProfilerWindow;
|
||||||
private ContextMenuButton _menuToolsSetTheCurrentSceneViewAsDefault;
|
private ContextMenuButton _menuToolsSetTheCurrentSceneViewAsDefault;
|
||||||
|
private ContextMenuButton _menuToolsTakeScreenshot;
|
||||||
private ContextMenuChildMenu _menuWindowApplyWindowLayout;
|
private ContextMenuChildMenu _menuWindowApplyWindowLayout;
|
||||||
|
|
||||||
private ToolStripButton _toolStripSaveAll;
|
private ToolStripButton _toolStripSaveAll;
|
||||||
@@ -510,13 +516,13 @@ namespace FlaxEditor.Modules
|
|||||||
MenuFile = MainMenu.AddButton("File");
|
MenuFile = MainMenu.AddButton("File");
|
||||||
var cm = MenuFile.ContextMenu;
|
var cm = MenuFile.ContextMenu;
|
||||||
cm.VisibleChanged += OnMenuFileShowHide;
|
cm.VisibleChanged += OnMenuFileShowHide;
|
||||||
_menuSaveAll = cm.AddButton("Save All", inputOptions.Save.ToString(), Editor.SaveAll);
|
_menuFileSaveAll = cm.AddButton("Save All", inputOptions.Save, Editor.SaveAll);
|
||||||
_menuFileSaveScenes = cm.AddButton("Save scenes", Editor.Scene.SaveScenes);
|
_menuFileSaveScenes = cm.AddButton("Save scenes", inputOptions.SaveScenes, Editor.Scene.SaveScenes);
|
||||||
_menuFileCloseScenes = cm.AddButton("Close scenes", Editor.Scene.CloseAllScenes);
|
_menuFileCloseScenes = cm.AddButton("Close scenes", inputOptions.CloseScenes, Editor.Scene.CloseAllScenes);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
cm.AddButton("Open scripts project", Editor.CodeEditing.OpenSolution);
|
_menuFileOpenScriptsProject = cm.AddButton("Open scripts project", inputOptions.OpenScriptsProject, Editor.CodeEditing.OpenSolution);
|
||||||
_menuFileGenerateScriptsProjectFiles = cm.AddButton("Generate scripts project files", Editor.ProgressReporting.GenerateScriptsProjectFiles.RunAsync);
|
_menuFileGenerateScriptsProjectFiles = cm.AddButton("Generate scripts project files", inputOptions.GenerateScriptsProject, Editor.ProgressReporting.GenerateScriptsProjectFiles.RunAsync);
|
||||||
cm.AddButton("Recompile scripts", ScriptsBuilder.Compile);
|
_menuFileRecompileScripts = cm.AddButton("Recompile scripts", inputOptions.RecompileScripts, ScriptsBuilder.Compile);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
cm.AddButton("Open project...", OpenProject);
|
cm.AddButton("Open project...", OpenProject);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
@@ -526,27 +532,27 @@ namespace FlaxEditor.Modules
|
|||||||
MenuEdit = MainMenu.AddButton("Edit");
|
MenuEdit = MainMenu.AddButton("Edit");
|
||||||
cm = MenuEdit.ContextMenu;
|
cm = MenuEdit.ContextMenu;
|
||||||
cm.VisibleChanged += OnMenuEditShowHide;
|
cm.VisibleChanged += OnMenuEditShowHide;
|
||||||
_menuEditUndo = cm.AddButton(string.Empty, inputOptions.Undo.ToString(), Editor.PerformUndo);
|
_menuEditUndo = cm.AddButton(string.Empty, inputOptions.Undo, Editor.PerformUndo);
|
||||||
_menuEditRedo = cm.AddButton(string.Empty, inputOptions.Redo.ToString(), Editor.PerformRedo);
|
_menuEditRedo = cm.AddButton(string.Empty, inputOptions.Redo, Editor.PerformRedo);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
_menuEditCut = cm.AddButton("Cut", inputOptions.Cut.ToString(), Editor.SceneEditing.Cut);
|
_menuEditCut = cm.AddButton("Cut", inputOptions.Cut, Editor.SceneEditing.Cut);
|
||||||
_menuEditCopy = cm.AddButton("Copy", inputOptions.Copy.ToString(), Editor.SceneEditing.Copy);
|
_menuEditCopy = cm.AddButton("Copy", inputOptions.Copy, Editor.SceneEditing.Copy);
|
||||||
_menuEditPaste = cm.AddButton("Paste", inputOptions.Paste.ToString(), Editor.SceneEditing.Paste);
|
_menuEditPaste = cm.AddButton("Paste", inputOptions.Paste, Editor.SceneEditing.Paste);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
_menuEditDelete = cm.AddButton("Delete", inputOptions.Delete.ToString(), Editor.SceneEditing.Delete);
|
_menuEditDelete = cm.AddButton("Delete", inputOptions.Delete, Editor.SceneEditing.Delete);
|
||||||
_menuEditDuplicate = cm.AddButton("Duplicate", inputOptions.Duplicate.ToString(), Editor.SceneEditing.Duplicate);
|
_menuEditDuplicate = cm.AddButton("Duplicate", inputOptions.Duplicate, Editor.SceneEditing.Duplicate);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
_menuEditSelectAll = cm.AddButton("Select all", inputOptions.SelectAll.ToString(), Editor.SceneEditing.SelectAllScenes);
|
_menuEditSelectAll = cm.AddButton("Select all", inputOptions.SelectAll, Editor.SceneEditing.SelectAllScenes);
|
||||||
_menuEditFind = cm.AddButton("Find", inputOptions.Search.ToString(), Editor.Windows.SceneWin.Search);
|
_menuEditFind = cm.AddButton("Find", inputOptions.Search, Editor.Windows.SceneWin.Search);
|
||||||
|
|
||||||
// Scene
|
// Scene
|
||||||
MenuScene = MainMenu.AddButton("Scene");
|
MenuScene = MainMenu.AddButton("Scene");
|
||||||
cm = MenuScene.ContextMenu;
|
cm = MenuScene.ContextMenu;
|
||||||
cm.VisibleChanged += OnMenuSceneShowHide;
|
cm.VisibleChanged += OnMenuSceneShowHide;
|
||||||
_menuSceneMoveActorToViewport = cm.AddButton("Move actor to viewport", MoveActorToViewport);
|
_menuSceneMoveActorToViewport = cm.AddButton("Move actor to viewport", inputOptions.MoveActorToViewport, MoveActorToViewport);
|
||||||
_menuSceneAlignActorWithViewport = cm.AddButton("Align actor with viewport", AlignActorWithViewport);
|
_menuSceneAlignActorWithViewport = cm.AddButton("Align actor with viewport", inputOptions.AlignActorWithViewport, AlignActorWithViewport);
|
||||||
_menuSceneAlignViewportWithActor = cm.AddButton("Align viewport with actor", AlignViewportWithActor);
|
_menuSceneAlignViewportWithActor = cm.AddButton("Align viewport with actor", inputOptions.AlignViewportWithActor, AlignViewportWithActor);
|
||||||
_menuScenePilotActor = cm.AddButton("Pilot actor", PilotActor);
|
_menuScenePilotActor = cm.AddButton("Pilot actor", inputOptions.PilotActor, PilotActor);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
_menuSceneCreateTerrain = cm.AddButton("Create terrain", CreateTerrain);
|
_menuSceneCreateTerrain = cm.AddButton("Create terrain", CreateTerrain);
|
||||||
|
|
||||||
@@ -555,39 +561,41 @@ namespace FlaxEditor.Modules
|
|||||||
cm = MenuGame.ContextMenu;
|
cm = MenuGame.ContextMenu;
|
||||||
cm.VisibleChanged += OnMenuGameShowHide;
|
cm.VisibleChanged += OnMenuGameShowHide;
|
||||||
|
|
||||||
_menuGamePlayGame = cm.AddButton("Play Game", Editor.Simulation.RequestPlayGameOrStopPlay);
|
_menuGamePlayGame = cm.AddButton("Play Game", inputOptions.Play, Editor.Simulation.RequestPlayGameOrStopPlay);
|
||||||
_menuGamePlayCurrentScenes = cm.AddButton("Play Current Scenes", Editor.Simulation.RequestPlayScenesOrStopPlay);
|
_menuGamePlayCurrentScenes = cm.AddButton("Play Current Scenes", inputOptions.PlayCurrentScenes, Editor.Simulation.RequestPlayScenesOrStopPlay);
|
||||||
_menuGameStop = cm.AddButton("Stop Game", Editor.Simulation.RequestStopPlay);
|
_menuGameStop = cm.AddButton("Stop Game", inputOptions.Play, Editor.Simulation.RequestStopPlay);
|
||||||
_menuGamePause = cm.AddButton("Pause", inputOptions.Pause.ToString(), Editor.Simulation.RequestPausePlay);
|
_menuGamePause = cm.AddButton("Pause", inputOptions.Pause, Editor.Simulation.RequestPausePlay);
|
||||||
|
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
var numberOfClientsMenu = cm.AddChildMenu("Number of game clients");
|
var numberOfClientsMenu = cm.AddChildMenu("Number of game clients");
|
||||||
_numberOfClientsGroup.AddItemsToContextMenu(numberOfClientsMenu.ContextMenu);
|
_numberOfClientsGroup.AddItemsToContextMenu(numberOfClientsMenu.ContextMenu);
|
||||||
|
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
cm.AddButton("Cook & Run", Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip("Runs Game Cooker to build the game for this platform and runs the game after.");
|
_menuGameCookAndRun = cm.AddButton("Cook & Run", inputOptions.CookAndRun, Editor.Windows.GameCookerWin.BuildAndRun);
|
||||||
cm.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked).LinkTooltip("Runs the game build from the last cooking output. Use Cook&Play or Game Cooker first.");
|
_menuGameCookAndRun.LinkTooltip("Runs Game Cooker to build the game for this platform and runs the game after.");
|
||||||
|
_menuGameRunCookedGame = cm.AddButton("Run cooked game", inputOptions.RunCookedGame, Editor.Windows.GameCookerWin.RunCooked);
|
||||||
|
_menuGameRunCookedGame.LinkTooltip("Runs the game build from the last cooking output. Use 'Cook & Run' or Game Cooker first.");
|
||||||
|
|
||||||
// Tools
|
// Tools
|
||||||
MenuTools = MainMenu.AddButton("Tools");
|
MenuTools = MainMenu.AddButton("Tools");
|
||||||
cm = MenuTools.ContextMenu;
|
cm = MenuTools.ContextMenu;
|
||||||
cm.VisibleChanged += OnMenuToolsShowHide;
|
cm.VisibleChanged += OnMenuToolsShowHide;
|
||||||
_menuToolsBuildScenes = cm.AddButton("Build scenes data", "Ctrl+F10", Editor.BuildScenesOrCancel);
|
_menuToolsBuildScenes = cm.AddButton("Build scenes data", inputOptions.BuildScenesData, Editor.BuildScenesOrCancel);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
_menuToolsBakeLightmaps = cm.AddButton("Bake lightmaps", Editor.BakeLightmapsOrCancel);
|
_menuToolsBakeLightmaps = cm.AddButton("Bake lightmaps", inputOptions.BakeLightmaps, Editor.BakeLightmapsOrCancel);
|
||||||
_menuToolsClearLightmaps = cm.AddButton("Clear lightmaps data", Editor.ClearLightmaps);
|
_menuToolsClearLightmaps = cm.AddButton("Clear lightmaps data", inputOptions.ClearLightmaps, Editor.ClearLightmaps);
|
||||||
_menuToolsBakeAllEnvProbes = cm.AddButton("Bake all env probes", BakeAllEnvProbes);
|
_menuToolsBakeAllEnvProbes = cm.AddButton("Bake all env probes", inputOptions.BakeEnvProbes, Editor.BakeAllEnvProbes);
|
||||||
_menuToolsBuildCSGMesh = cm.AddButton("Build CSG mesh", BuildCSG);
|
_menuToolsBuildCSGMesh = cm.AddButton("Build CSG mesh", inputOptions.BuildCSG, Editor.BuildCSG);
|
||||||
_menuToolsBuildNavMesh = cm.AddButton("Build Nav Mesh", BuildNavMesh);
|
_menuToolsBuildNavMesh = cm.AddButton("Build Nav Mesh", inputOptions.BuildNav, Editor.BuildNavMesh);
|
||||||
_menuToolsBuildAllMesgesSDF = cm.AddButton("Build all meshes SDF", BuildAllMeshesSDF);
|
_menuToolsBuildAllMeshesSDF = cm.AddButton("Build all meshes SDF", inputOptions.BuildSDF, Editor.BuildAllMeshesSDF);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
cm.AddButton("Game Cooker", Editor.Windows.GameCookerWin.FocusOrShow);
|
cm.AddButton("Game Cooker", Editor.Windows.GameCookerWin.FocusOrShow);
|
||||||
_menuToolsCancelBuilding = cm.AddButton("Cancel building game", () => GameCooker.Cancel());
|
_menuToolsCancelBuilding = cm.AddButton("Cancel building game", () => GameCooker.Cancel());
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
cm.AddButton("Profiler", Editor.Windows.ProfilerWin.FocusOrShow);
|
_menuToolsProfilerWindow = cm.AddButton("Profiler", inputOptions.ProfilerWindow, () => Editor.Windows.ProfilerWin.FocusOrShow());
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
_menuToolsSetTheCurrentSceneViewAsDefault = cm.AddButton("Set current scene view as project default", SetTheCurrentSceneViewAsDefault);
|
_menuToolsSetTheCurrentSceneViewAsDefault = cm.AddButton("Set current scene view as project default", SetTheCurrentSceneViewAsDefault);
|
||||||
cm.AddButton("Take screenshot", "F12", Editor.Windows.TakeScreenshot);
|
_menuToolsTakeScreenshot = cm.AddButton("Take screenshot", inputOptions.TakeScreenshot, Editor.Windows.TakeScreenshot);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
cm.AddButton("Plugins", () => Editor.Windows.PluginsWin.Show());
|
cm.AddButton("Plugins", () => Editor.Windows.PluginsWin.Show());
|
||||||
cm.AddButton("Options", () => Editor.Windows.EditorOptionsWin.Show());
|
cm.AddButton("Options", () => Editor.Windows.EditorOptionsWin.Show());
|
||||||
@@ -606,7 +614,7 @@ namespace FlaxEditor.Modules
|
|||||||
cm.AddButton("Output Log", Editor.Windows.OutputLogWin.FocusOrShow);
|
cm.AddButton("Output Log", Editor.Windows.OutputLogWin.FocusOrShow);
|
||||||
cm.AddButton("Graphics Quality", Editor.Windows.GraphicsQualityWin.FocusOrShow);
|
cm.AddButton("Graphics Quality", Editor.Windows.GraphicsQualityWin.FocusOrShow);
|
||||||
cm.AddButton("Game Cooker", Editor.Windows.GameCookerWin.FocusOrShow);
|
cm.AddButton("Game Cooker", Editor.Windows.GameCookerWin.FocusOrShow);
|
||||||
cm.AddButton("Profiler", Editor.Windows.ProfilerWin.FocusOrShow);
|
cm.AddButton("Profiler", inputOptions.ProfilerWindow, Editor.Windows.ProfilerWin.FocusOrShow);
|
||||||
cm.AddButton("Content Search", Editor.ContentFinding.ShowSearch);
|
cm.AddButton("Content Search", Editor.ContentFinding.ShowSearch);
|
||||||
cm.AddButton("Visual Script Debugger", Editor.Windows.VisualScriptDebuggerWin.FocusOrShow);
|
cm.AddButton("Visual Script Debugger", Editor.Windows.VisualScriptDebuggerWin.FocusOrShow);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
@@ -633,7 +641,12 @@ namespace FlaxEditor.Modules
|
|||||||
{
|
{
|
||||||
var inputOptions = options.Input;
|
var inputOptions = options.Input;
|
||||||
|
|
||||||
_menuSaveAll.ShortKeys = inputOptions.Save.ToString();
|
_menuFileSaveAll.ShortKeys = inputOptions.Save.ToString();
|
||||||
|
_menuFileSaveScenes.ShortKeys = inputOptions.SaveScenes.ToString();
|
||||||
|
_menuFileCloseScenes.ShortKeys = inputOptions.CloseScenes.ToString();
|
||||||
|
_menuFileOpenScriptsProject.ShortKeys = inputOptions.OpenScriptsProject.ToString();
|
||||||
|
_menuFileGenerateScriptsProjectFiles.ShortKeys = inputOptions.GenerateScriptsProject.ToString();
|
||||||
|
_menuFileRecompileScripts.ShortKeys = inputOptions.RecompileScripts.ToString();
|
||||||
_menuEditUndo.ShortKeys = inputOptions.Undo.ToString();
|
_menuEditUndo.ShortKeys = inputOptions.Undo.ToString();
|
||||||
_menuEditRedo.ShortKeys = inputOptions.Redo.ToString();
|
_menuEditRedo.ShortKeys = inputOptions.Redo.ToString();
|
||||||
_menuEditCut.ShortKeys = inputOptions.Cut.ToString();
|
_menuEditCut.ShortKeys = inputOptions.Cut.ToString();
|
||||||
@@ -642,8 +655,21 @@ namespace FlaxEditor.Modules
|
|||||||
_menuEditDuplicate.ShortKeys = inputOptions.Duplicate.ToString();
|
_menuEditDuplicate.ShortKeys = inputOptions.Duplicate.ToString();
|
||||||
_menuEditSelectAll.ShortKeys = inputOptions.SelectAll.ToString();
|
_menuEditSelectAll.ShortKeys = inputOptions.SelectAll.ToString();
|
||||||
_menuEditFind.ShortKeys = inputOptions.Search.ToString();
|
_menuEditFind.ShortKeys = inputOptions.Search.ToString();
|
||||||
_menuGamePlayCurrentScenes.ShortKeys = inputOptions.Play.ToString();
|
_menuGamePlayGame.ShortKeys = inputOptions.Play.ToString();
|
||||||
|
_menuGamePlayCurrentScenes.ShortKeys = inputOptions.PlayCurrentScenes.ToString();
|
||||||
_menuGamePause.ShortKeys = inputOptions.Pause.ToString();
|
_menuGamePause.ShortKeys = inputOptions.Pause.ToString();
|
||||||
|
_menuGameStop.ShortKeys = inputOptions.Play.ToString();
|
||||||
|
_menuGameCookAndRun.ShortKeys = inputOptions.CookAndRun.ToString();
|
||||||
|
_menuGameRunCookedGame.ShortKeys = inputOptions.RunCookedGame.ToString();
|
||||||
|
_menuToolsBuildScenes.ShortKeys = inputOptions.BuildScenesData.ToString();
|
||||||
|
_menuToolsBakeLightmaps.ShortKeys = inputOptions.BakeLightmaps.ToString();
|
||||||
|
_menuToolsClearLightmaps.ShortKeys = inputOptions.ClearLightmaps.ToString();
|
||||||
|
_menuToolsBakeAllEnvProbes.ShortKeys = inputOptions.BakeEnvProbes.ToString();
|
||||||
|
_menuToolsBuildCSGMesh.ShortKeys = inputOptions.BuildCSG.ToString();
|
||||||
|
_menuToolsBuildNavMesh.ShortKeys = inputOptions.BuildNav.ToString();
|
||||||
|
_menuToolsBuildAllMeshesSDF.ShortKeys = inputOptions.BuildSDF.ToString();
|
||||||
|
_menuToolsProfilerWindow.ShortKeys = inputOptions.ProfilerWindow.ToString();
|
||||||
|
_menuToolsTakeScreenshot.ShortKeys = inputOptions.TakeScreenshot.ToString();
|
||||||
|
|
||||||
MainMenuShortcutKeysUpdated?.Invoke();
|
MainMenuShortcutKeysUpdated?.Invoke();
|
||||||
}
|
}
|
||||||
@@ -668,10 +694,10 @@ namespace FlaxEditor.Modules
|
|||||||
ToolStrip.AddSeparator();
|
ToolStrip.AddSeparator();
|
||||||
|
|
||||||
// Cook scenes
|
// Cook scenes
|
||||||
_toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build64, Editor.BuildScenesOrCancel).LinkTooltip("Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options (Ctrl+F10)");
|
_toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build64, Editor.BuildScenesOrCancel).LinkTooltip($"Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options ({inputOptions.BuildScenesData})");
|
||||||
|
|
||||||
// Cook and run
|
// Cook and run
|
||||||
_toolStripCook = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.ShipIt64, Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip("Cook & Run - build game for the current platform and run it locally");
|
_toolStripCook = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.ShipIt64, Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip($"Cook & Run - build game for the current platform and run it locally ({inputOptions.Play})");
|
||||||
_toolStripCook.ContextMenu = new ContextMenu();
|
_toolStripCook.ContextMenu = new ContextMenu();
|
||||||
_toolStripCook.ContextMenu.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked);
|
_toolStripCook.ContextMenu.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked);
|
||||||
_toolStripCook.ContextMenu.AddSeparator();
|
_toolStripCook.ContextMenu.AddSeparator();
|
||||||
@@ -692,7 +718,7 @@ namespace FlaxEditor.Modules
|
|||||||
playActionGroup.SelectedChanged = SetPlayAction;
|
playActionGroup.SelectedChanged = SetPlayAction;
|
||||||
Editor.Options.OptionsChanged += options => { playActionGroup.Selected = options.Interface.PlayButtonAction; };
|
Editor.Options.OptionsChanged += options => { playActionGroup.Selected = options.Interface.PlayButtonAction; };
|
||||||
|
|
||||||
_toolStripPause = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Pause64, Editor.Simulation.RequestResumeOrPause).LinkTooltip($"Pause/Resume game({inputOptions.Pause})");
|
_toolStripPause = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Pause64, Editor.Simulation.RequestResumeOrPause).LinkTooltip($"Pause/Resume game ({inputOptions.Pause})");
|
||||||
_toolStripStep = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Skip64, Editor.Simulation.RequestPlayOneFrame).LinkTooltip("Step one frame in game");
|
_toolStripStep = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Skip64, Editor.Simulation.RequestPlayOneFrame).LinkTooltip("Step one frame in game");
|
||||||
|
|
||||||
UpdateToolstrip();
|
UpdateToolstrip();
|
||||||
@@ -872,7 +898,7 @@ namespace FlaxEditor.Modules
|
|||||||
_menuToolsBakeLightmaps.Text = isBakingLightmaps ? "Cancel baking lightmaps" : "Bake lightmaps";
|
_menuToolsBakeLightmaps.Text = isBakingLightmaps ? "Cancel baking lightmaps" : "Bake lightmaps";
|
||||||
_menuToolsClearLightmaps.Enabled = canEdit;
|
_menuToolsClearLightmaps.Enabled = canEdit;
|
||||||
_menuToolsBakeAllEnvProbes.Enabled = canEdit;
|
_menuToolsBakeAllEnvProbes.Enabled = canEdit;
|
||||||
_menuToolsBuildAllMesgesSDF.Enabled = canEdit && !isBakingLightmaps;
|
_menuToolsBuildAllMeshesSDF.Enabled = canEdit && !isBakingLightmaps;
|
||||||
_menuToolsBuildCSGMesh.Enabled = canEdit;
|
_menuToolsBuildCSGMesh.Enabled = canEdit;
|
||||||
_menuToolsBuildNavMesh.Enabled = canEdit;
|
_menuToolsBuildNavMesh.Enabled = canEdit;
|
||||||
_menuToolsCancelBuilding.Enabled = GameCooker.IsRunning;
|
_menuToolsCancelBuilding.Enabled = GameCooker.IsRunning;
|
||||||
@@ -911,7 +937,7 @@ namespace FlaxEditor.Modules
|
|||||||
Editor.Windows.LoadLayout((string)button.Tag);
|
Editor.Windows.LoadLayout((string)button.Tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AlignViewportWithActor()
|
internal void AlignViewportWithActor()
|
||||||
{
|
{
|
||||||
var selection = Editor.SceneEditing;
|
var selection = Editor.SceneEditing;
|
||||||
if (selection.HasSthSelected && selection.Selection[0] is ActorNode node)
|
if (selection.HasSthSelected && selection.Selection[0] is ActorNode node)
|
||||||
@@ -922,7 +948,7 @@ namespace FlaxEditor.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MoveActorToViewport()
|
internal void MoveActorToViewport()
|
||||||
{
|
{
|
||||||
var selection = Editor.SceneEditing;
|
var selection = Editor.SceneEditing;
|
||||||
if (selection.HasSthSelected && selection.Selection[0] is ActorNode node)
|
if (selection.HasSthSelected && selection.Selection[0] is ActorNode node)
|
||||||
@@ -936,7 +962,7 @@ namespace FlaxEditor.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AlignActorWithViewport()
|
internal void AlignActorWithViewport()
|
||||||
{
|
{
|
||||||
var selection = Editor.SceneEditing;
|
var selection = Editor.SceneEditing;
|
||||||
if (selection.HasSthSelected && selection.Selection[0] is ActorNode node)
|
if (selection.HasSthSelected && selection.Selection[0] is ActorNode node)
|
||||||
@@ -972,57 +998,6 @@ namespace FlaxEditor.Modules
|
|||||||
new Tools.Terrain.CreateTerrainDialog().Show(Editor.Windows.MainWindow);
|
new Tools.Terrain.CreateTerrainDialog().Show(Editor.Windows.MainWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BakeAllEnvProbes()
|
|
||||||
{
|
|
||||||
Editor.Scene.ExecuteOnGraph(node =>
|
|
||||||
{
|
|
||||||
if (node is EnvironmentProbeNode envProbeNode && envProbeNode.IsActive)
|
|
||||||
{
|
|
||||||
((EnvironmentProbe)envProbeNode.Actor).Bake();
|
|
||||||
node.ParentScene.IsEdited = true;
|
|
||||||
}
|
|
||||||
else if (node is SkyLightNode skyLightNode && skyLightNode.IsActive && skyLightNode.Actor is SkyLight skyLight && skyLight.Mode == SkyLight.Modes.CaptureScene)
|
|
||||||
{
|
|
||||||
skyLight.Bake();
|
|
||||||
node.ParentScene.IsEdited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node.IsActive;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BuildCSG()
|
|
||||||
{
|
|
||||||
var scenes = Level.Scenes;
|
|
||||||
scenes.ToList().ForEach(x => x.BuildCSG(0));
|
|
||||||
Editor.Scene.MarkSceneEdited(scenes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BuildNavMesh()
|
|
||||||
{
|
|
||||||
var scenes = Level.Scenes;
|
|
||||||
scenes.ToList().ForEach(x => Navigation.BuildNavMesh(x, 0));
|
|
||||||
Editor.Scene.MarkSceneEdited(scenes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BuildAllMeshesSDF()
|
|
||||||
{
|
|
||||||
// TODO: async maybe with progress reporting?
|
|
||||||
Editor.Scene.ExecuteOnGraph(node =>
|
|
||||||
{
|
|
||||||
if (node is StaticModelNode staticModelNode && staticModelNode.Actor is StaticModel staticModel)
|
|
||||||
{
|
|
||||||
if (staticModel.DrawModes.HasFlag(DrawPass.GlobalSDF) && staticModel.Model != null && !staticModel.Model.IsVirtual && staticModel.Model.SDF.Texture == null)
|
|
||||||
{
|
|
||||||
Editor.Log("Generating SDF for " + staticModel.Model);
|
|
||||||
if (!staticModel.Model.GenerateSDF())
|
|
||||||
staticModel.Model.Save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetTheCurrentSceneViewAsDefault()
|
private void SetTheCurrentSceneViewAsDefault()
|
||||||
{
|
{
|
||||||
var projectInfo = Editor.GameProject;
|
var projectInfo = Editor.GameProject;
|
||||||
|
|||||||
@@ -721,7 +721,7 @@ namespace FlaxEditor.Modules
|
|||||||
// Create main window
|
// Create main window
|
||||||
var settings = CreateWindowSettings.Default;
|
var settings = CreateWindowSettings.Default;
|
||||||
settings.Title = "Flax Editor";
|
settings.Title = "Flax Editor";
|
||||||
settings.Size = Platform.DesktopSize;
|
//settings.Size = Platform.DesktopSize;
|
||||||
settings.StartPosition = WindowStartPosition.CenterScreen;
|
settings.StartPosition = WindowStartPosition.CenterScreen;
|
||||||
settings.ShowAfterFirstPaint = true;
|
settings.ShowAfterFirstPaint = true;
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,66 @@ namespace FlaxEditor.Options
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ProcessModifiers(Control control)
|
||||||
|
{
|
||||||
|
return ProcessModifiers(control.Root.GetKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ProcessModifiers(Window window)
|
||||||
|
{
|
||||||
|
return ProcessModifiers(window.GetKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ProcessModifiers(Func<KeyboardKeys, bool> getKeyFunc)
|
||||||
|
{
|
||||||
|
bool ctrlPressed = getKeyFunc(KeyboardKeys.Control);
|
||||||
|
bool shiftPressed = getKeyFunc(KeyboardKeys.Shift);
|
||||||
|
bool altPressed = getKeyFunc(KeyboardKeys.Alt);
|
||||||
|
|
||||||
|
bool mod1 = false;
|
||||||
|
if (Modifier1 == KeyboardKeys.None)
|
||||||
|
mod1 = true;
|
||||||
|
else if (Modifier1 == KeyboardKeys.Control)
|
||||||
|
{
|
||||||
|
mod1 = ctrlPressed;
|
||||||
|
ctrlPressed = false;
|
||||||
|
}
|
||||||
|
else if (Modifier1 == KeyboardKeys.Shift)
|
||||||
|
{
|
||||||
|
mod1 = shiftPressed;
|
||||||
|
shiftPressed = false;
|
||||||
|
}
|
||||||
|
else if (Modifier1 == KeyboardKeys.Alt)
|
||||||
|
{
|
||||||
|
mod1 = altPressed;
|
||||||
|
altPressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mod2 = false;
|
||||||
|
if (Modifier2 == KeyboardKeys.None)
|
||||||
|
mod2 = true;
|
||||||
|
else if (Modifier2 == KeyboardKeys.Control)
|
||||||
|
{
|
||||||
|
mod2 = ctrlPressed;
|
||||||
|
ctrlPressed = false;
|
||||||
|
}
|
||||||
|
else if (Modifier2 == KeyboardKeys.Shift)
|
||||||
|
{
|
||||||
|
mod2 = shiftPressed;
|
||||||
|
shiftPressed = false;
|
||||||
|
}
|
||||||
|
else if (Modifier2 == KeyboardKeys.Alt)
|
||||||
|
{
|
||||||
|
mod2 = altPressed;
|
||||||
|
altPressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any unhandled modifiers are not pressed
|
||||||
|
if (mod1 && mod2)
|
||||||
|
return !ctrlPressed && !shiftPressed && !altPressed;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes this input binding to check if state matches.
|
/// Processes this input binding to check if state matches.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -142,19 +202,7 @@ namespace FlaxEditor.Options
|
|||||||
public bool Process(Control control)
|
public bool Process(Control control)
|
||||||
{
|
{
|
||||||
var root = control.Root;
|
var root = control.Root;
|
||||||
|
return root.GetKey(Key) && ProcessModifiers(control);
|
||||||
if (root.GetKey(Key))
|
|
||||||
{
|
|
||||||
if (Modifier1 == KeyboardKeys.None || root.GetKey(Modifier1))
|
|
||||||
{
|
|
||||||
if (Modifier2 == KeyboardKeys.None || root.GetKey(Modifier2))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -165,20 +213,20 @@ namespace FlaxEditor.Options
|
|||||||
/// <returns>True if input has been processed, otherwise false.</returns>
|
/// <returns>True if input has been processed, otherwise false.</returns>
|
||||||
public bool Process(Control control, KeyboardKeys key)
|
public bool Process(Control control, KeyboardKeys key)
|
||||||
{
|
{
|
||||||
var root = control.Root;
|
if (key != Key)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (key == Key)
|
return ProcessModifiers(control);
|
||||||
{
|
}
|
||||||
if (Modifier1 == KeyboardKeys.None || root.GetKey(Modifier1))
|
|
||||||
{
|
|
||||||
if (Modifier2 == KeyboardKeys.None || root.GetKey(Modifier2))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
/// <summary>
|
||||||
|
/// Processes this input binding to check if state matches.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window">The input providing window.</param>
|
||||||
|
/// <returns>True if input has been processed, otherwise false.</returns>
|
||||||
|
public bool Process(Window window)
|
||||||
|
{
|
||||||
|
return window.GetKey(Key) && ProcessModifiers(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -78,6 +78,30 @@ namespace FlaxEditor.Options
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region File
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("File"), EditorOrder(300)]
|
||||||
|
public InputBinding SaveScenes = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("File"), EditorOrder(310)]
|
||||||
|
public InputBinding CloseScenes = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("File"), EditorOrder(320)]
|
||||||
|
public InputBinding OpenScriptsProject = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("File"), EditorOrder(330)]
|
||||||
|
public InputBinding GenerateScriptsProject = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("File"), EditorOrder(340)]
|
||||||
|
public InputBinding RecompileScripts = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Scene
|
#region Scene
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "End")]
|
[DefaultValue(typeof(InputBinding), "End")]
|
||||||
@@ -85,35 +109,115 @@ namespace FlaxEditor.Options
|
|||||||
public InputBinding SnapToGround = new InputBinding(KeyboardKeys.End);
|
public InputBinding SnapToGround = new InputBinding(KeyboardKeys.End);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "F5")]
|
[DefaultValue(typeof(InputBinding), "F5")]
|
||||||
[EditorDisplay("Scene"), EditorOrder(510)]
|
[EditorDisplay("Scene", "Play/Stop"), EditorOrder(510)]
|
||||||
public InputBinding Play = new InputBinding(KeyboardKeys.F5);
|
public InputBinding Play = new InputBinding(KeyboardKeys.F5);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Scene", "Play Current Scenes/Stop"), EditorOrder(520)]
|
||||||
|
public InputBinding PlayCurrentScenes = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "F6")]
|
[DefaultValue(typeof(InputBinding), "F6")]
|
||||||
[EditorDisplay("Scene"), EditorOrder(520)]
|
[EditorDisplay("Scene"), EditorOrder(530)]
|
||||||
public InputBinding Pause = new InputBinding(KeyboardKeys.F6);
|
public InputBinding Pause = new InputBinding(KeyboardKeys.F6);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "F11")]
|
[DefaultValue(typeof(InputBinding), "F11")]
|
||||||
[EditorDisplay("Scene"), EditorOrder(530)]
|
[EditorDisplay("Scene"), EditorOrder(540)]
|
||||||
public InputBinding StepFrame = new InputBinding(KeyboardKeys.F11);
|
public InputBinding StepFrame = new InputBinding(KeyboardKeys.F11);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Scene", "Cook & Run"), EditorOrder(550)]
|
||||||
|
public InputBinding CookAndRun = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Scene", "Run cooked game"), EditorOrder(560)]
|
||||||
|
public InputBinding RunCookedGame = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Scene", "Move actor to viewport"), EditorOrder(570)]
|
||||||
|
public InputBinding MoveActorToViewport = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Scene", "Align actor with viewport"), EditorOrder(571)]
|
||||||
|
public InputBinding AlignActorWithViewport = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Scene", "Align viewport with actor"), EditorOrder(572)]
|
||||||
|
public InputBinding AlignViewportWithActor = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Scene"), EditorOrder(573)]
|
||||||
|
public InputBinding PilotActor = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Tools
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Ctrl+F10")]
|
||||||
|
[EditorDisplay("Tools", "Build scenes data"), EditorOrder(600)]
|
||||||
|
public InputBinding BuildScenesData = new InputBinding(KeyboardKeys.F10, KeyboardKeys.Control);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Tools", "Bake lightmaps"), EditorOrder(601)]
|
||||||
|
public InputBinding BakeLightmaps = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Tools", "Clear lightmaps data"), EditorOrder(602)]
|
||||||
|
public InputBinding ClearLightmaps = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Tools", "Bake all env probes"), EditorOrder(603)]
|
||||||
|
public InputBinding BakeEnvProbes = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Tools", "Build CSG mesh"), EditorOrder(604)]
|
||||||
|
public InputBinding BuildCSG = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Tools", "Build Nav Mesh"), EditorOrder(605)]
|
||||||
|
public InputBinding BuildNav = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Tools", "Build all meshes SDF"), EditorOrder(606)]
|
||||||
|
public InputBinding BuildSDF = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "F12")]
|
||||||
|
[EditorDisplay("Tools", "Take screenshot"), EditorOrder(607)]
|
||||||
|
public InputBinding TakeScreenshot = new InputBinding(KeyboardKeys.F12);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Profiler
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Profiler", "Open Profiler Window"), EditorOrder(630)]
|
||||||
|
public InputBinding ProfilerWindow = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Profiler", "Start/Stop Profiler"), EditorOrder(631)]
|
||||||
|
public InputBinding ProfilerStartStop = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Profiler", "Clear Profiler data"), EditorOrder(632)]
|
||||||
|
public InputBinding ProfilerClear = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Debugger
|
#region Debugger
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "F5")]
|
[DefaultValue(typeof(InputBinding), "F5")]
|
||||||
[EditorDisplay("Debugger", "Continue"), EditorOrder(610)]
|
[EditorDisplay("Debugger", "Continue"), EditorOrder(810)]
|
||||||
public InputBinding DebuggerContinue = new InputBinding(KeyboardKeys.F5);
|
public InputBinding DebuggerContinue = new InputBinding(KeyboardKeys.F5);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "F10")]
|
[DefaultValue(typeof(InputBinding), "F10")]
|
||||||
[EditorDisplay("Debugger", "Step Over"), EditorOrder(620)]
|
[EditorDisplay("Debugger", "Step Over"), EditorOrder(820)]
|
||||||
public InputBinding DebuggerStepOver = new InputBinding(KeyboardKeys.F10);
|
public InputBinding DebuggerStepOver = new InputBinding(KeyboardKeys.F10);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "F11")]
|
[DefaultValue(typeof(InputBinding), "F11")]
|
||||||
[EditorDisplay("Debugger", "Step Into"), EditorOrder(630)]
|
[EditorDisplay("Debugger", "Step Into"), EditorOrder(830)]
|
||||||
public InputBinding DebuggerStepInto = new InputBinding(KeyboardKeys.F11);
|
public InputBinding DebuggerStepInto = new InputBinding(KeyboardKeys.F11);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "Shift+F11")]
|
[DefaultValue(typeof(InputBinding), "Shift+F11")]
|
||||||
[EditorDisplay("Debugger", "Step Out"), EditorOrder(640)]
|
[EditorDisplay("Debugger", "Step Out"), EditorOrder(840)]
|
||||||
public InputBinding DebuggerStepOut = new InputBinding(KeyboardKeys.F11, KeyboardKeys.Shift);
|
public InputBinding DebuggerStepOut = new InputBinding(KeyboardKeys.F11, KeyboardKeys.Shift);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -132,6 +236,10 @@ namespace FlaxEditor.Options
|
|||||||
[EditorDisplay("Gizmo"), EditorOrder(1020)]
|
[EditorDisplay("Gizmo"), EditorOrder(1020)]
|
||||||
public InputBinding ScaleMode = new InputBinding(KeyboardKeys.Alpha3);
|
public InputBinding ScaleMode = new InputBinding(KeyboardKeys.Alpha3);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Alpha4")]
|
||||||
|
[EditorDisplay("Gizmo"), EditorOrder(1030)]
|
||||||
|
public InputBinding ToggleTransformSpace = new InputBinding(KeyboardKeys.Alpha4);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Viewport
|
#region Viewport
|
||||||
@@ -160,28 +268,40 @@ namespace FlaxEditor.Options
|
|||||||
[EditorDisplay("Viewport"), EditorOrder(1550)]
|
[EditorDisplay("Viewport"), EditorOrder(1550)]
|
||||||
public InputBinding Down = new InputBinding(KeyboardKeys.Q);
|
public InputBinding Down = new InputBinding(KeyboardKeys.Q);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Viewport", "Toggle Camera Rotation"), EditorOrder(1560)]
|
||||||
|
public InputBinding CameraToggleRotation = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Viewport", "Increase Camera Move Speed"), EditorOrder(1570)]
|
||||||
|
public InputBinding CameraIncreaseMoveSpeed = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("Viewport", "Decrease Camera Move Speed"), EditorOrder(1571)]
|
||||||
|
public InputBinding CameraDecreaseMoveSpeed = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "Numpad0")]
|
[DefaultValue(typeof(InputBinding), "Numpad0")]
|
||||||
[EditorDisplay("Viewport"), EditorOrder(1600)]
|
[EditorDisplay("Viewport"), EditorOrder(1700)]
|
||||||
public InputBinding ViewpointFront = new InputBinding(KeyboardKeys.Numpad0);
|
public InputBinding ViewpointFront = new InputBinding(KeyboardKeys.Numpad0);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "Numpad5")]
|
[DefaultValue(typeof(InputBinding), "Numpad5")]
|
||||||
[EditorDisplay("Viewport"), EditorOrder(1610)]
|
[EditorDisplay("Viewport"), EditorOrder(1710)]
|
||||||
public InputBinding ViewpointBack = new InputBinding(KeyboardKeys.Numpad5);
|
public InputBinding ViewpointBack = new InputBinding(KeyboardKeys.Numpad5);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "Numpad4")]
|
[DefaultValue(typeof(InputBinding), "Numpad4")]
|
||||||
[EditorDisplay("Viewport"), EditorOrder(1620)]
|
[EditorDisplay("Viewport"), EditorOrder(1720)]
|
||||||
public InputBinding ViewpointLeft = new InputBinding(KeyboardKeys.Numpad4);
|
public InputBinding ViewpointLeft = new InputBinding(KeyboardKeys.Numpad4);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "Numpad6")]
|
[DefaultValue(typeof(InputBinding), "Numpad6")]
|
||||||
[EditorDisplay("Viewport"), EditorOrder(1630)]
|
[EditorDisplay("Viewport"), EditorOrder(1730)]
|
||||||
public InputBinding ViewpointRight = new InputBinding(KeyboardKeys.Numpad6);
|
public InputBinding ViewpointRight = new InputBinding(KeyboardKeys.Numpad6);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "Numpad8")]
|
[DefaultValue(typeof(InputBinding), "Numpad8")]
|
||||||
[EditorDisplay("Viewport"), EditorOrder(1640)]
|
[EditorDisplay("Viewport"), EditorOrder(1740)]
|
||||||
public InputBinding ViewpointTop = new InputBinding(KeyboardKeys.Numpad8);
|
public InputBinding ViewpointTop = new InputBinding(KeyboardKeys.Numpad8);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "Numpad2")]
|
[DefaultValue(typeof(InputBinding), "Numpad2")]
|
||||||
[EditorDisplay("Viewport"), EditorOrder(1650)]
|
[EditorDisplay("Viewport"), EditorOrder(1750)]
|
||||||
public InputBinding ViewpointBottom = new InputBinding(KeyboardKeys.Numpad2);
|
public InputBinding ViewpointBottom = new InputBinding(KeyboardKeys.Numpad2);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ using FlaxEditor.GUI.ContextMenu;
|
|||||||
using FlaxEditor.GUI.Input;
|
using FlaxEditor.GUI.Input;
|
||||||
using FlaxEditor.GUI.Tree;
|
using FlaxEditor.GUI.Tree;
|
||||||
using FlaxEditor.SceneGraph;
|
using FlaxEditor.SceneGraph;
|
||||||
using FlaxEditor.Scripting;
|
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using FlaxEngine.Utilities;
|
using FlaxEngine.Utilities;
|
||||||
|
using FlaxEditor.Windows;
|
||||||
|
|
||||||
namespace FlaxEngine
|
namespace FlaxEngine
|
||||||
{
|
{
|
||||||
@@ -1235,5 +1235,60 @@ namespace FlaxEditor.Utilities
|
|||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binds global input actions for the window.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window">The editor window.</param>
|
||||||
|
public static void SetupCommonInputActions(EditorWindow window)
|
||||||
|
{
|
||||||
|
var inputActions = window.InputActions;
|
||||||
|
|
||||||
|
// Setup input actions
|
||||||
|
inputActions.Add(options => options.Save, Editor.Instance.SaveAll);
|
||||||
|
inputActions.Add(options => options.Undo, () =>
|
||||||
|
{
|
||||||
|
Editor.Instance.PerformUndo();
|
||||||
|
window.Focus();
|
||||||
|
});
|
||||||
|
inputActions.Add(options => options.Redo, () =>
|
||||||
|
{
|
||||||
|
Editor.Instance.PerformRedo();
|
||||||
|
window.Focus();
|
||||||
|
});
|
||||||
|
inputActions.Add(options => options.Cut, Editor.Instance.SceneEditing.Cut);
|
||||||
|
inputActions.Add(options => options.Copy, Editor.Instance.SceneEditing.Copy);
|
||||||
|
inputActions.Add(options => options.Paste, Editor.Instance.SceneEditing.Paste);
|
||||||
|
inputActions.Add(options => options.Duplicate, Editor.Instance.SceneEditing.Duplicate);
|
||||||
|
inputActions.Add(options => options.SelectAll, Editor.Instance.SceneEditing.SelectAllScenes);
|
||||||
|
inputActions.Add(options => options.Delete, Editor.Instance.SceneEditing.Delete);
|
||||||
|
inputActions.Add(options => options.Search, () => Editor.Instance.Windows.SceneWin.Search());
|
||||||
|
inputActions.Add(options => options.MoveActorToViewport, Editor.Instance.UI.MoveActorToViewport);
|
||||||
|
inputActions.Add(options => options.AlignActorWithViewport, Editor.Instance.UI.AlignActorWithViewport);
|
||||||
|
inputActions.Add(options => options.AlignViewportWithActor, Editor.Instance.UI.AlignViewportWithActor);
|
||||||
|
inputActions.Add(options => options.PilotActor, Editor.Instance.UI.PilotActor);
|
||||||
|
inputActions.Add(options => options.Play, Editor.Instance.Simulation.DelegatePlayOrStopPlayInEditor);
|
||||||
|
inputActions.Add(options => options.PlayCurrentScenes, Editor.Instance.Simulation.RequestPlayScenesOrStopPlay);
|
||||||
|
inputActions.Add(options => options.Pause, Editor.Instance.Simulation.RequestResumeOrPause);
|
||||||
|
inputActions.Add(options => options.StepFrame, Editor.Instance.Simulation.RequestPlayOneFrame);
|
||||||
|
inputActions.Add(options => options.CookAndRun, () => Editor.Instance.Windows.GameCookerWin.BuildAndRun());
|
||||||
|
inputActions.Add(options => options.RunCookedGame, () => Editor.Instance.Windows.GameCookerWin.RunCooked());
|
||||||
|
inputActions.Add(options => options.BuildScenesData, Editor.Instance.BuildScenesOrCancel);
|
||||||
|
inputActions.Add(options => options.BakeLightmaps, Editor.Instance.BakeLightmapsOrCancel);
|
||||||
|
inputActions.Add(options => options.ClearLightmaps, Editor.Instance.ClearLightmaps);
|
||||||
|
inputActions.Add(options => options.BakeEnvProbes, Editor.Instance.BakeAllEnvProbes);
|
||||||
|
inputActions.Add(options => options.BuildCSG, Editor.Instance.BuildCSG);
|
||||||
|
inputActions.Add(options => options.BuildNav, Editor.Instance.BuildNavMesh);
|
||||||
|
inputActions.Add(options => options.BuildSDF, Editor.Instance.BuildAllMeshesSDF);
|
||||||
|
inputActions.Add(options => options.TakeScreenshot, Editor.Instance.Windows.TakeScreenshot);
|
||||||
|
inputActions.Add(options => options.ProfilerWindow, () => Editor.Instance.Windows.ProfilerWin.FocusOrShow());
|
||||||
|
inputActions.Add(options => options.ProfilerStartStop, () => { Editor.Instance.Windows.ProfilerWin.LiveRecording = !Editor.Instance.Windows.ProfilerWin.LiveRecording; Editor.Instance.UI.AddStatusMessage($"Profiling {(Editor.Instance.Windows.ProfilerWin.LiveRecording ? "started" : "stopped")}."); });
|
||||||
|
inputActions.Add(options => options.ProfilerClear, () => { Editor.Instance.Windows.ProfilerWin.Clear(); Editor.Instance.UI.AddStatusMessage($"Profiling results cleared."); });
|
||||||
|
inputActions.Add(options => options.SaveScenes, () => Editor.Instance.Scene.SaveScenes());
|
||||||
|
inputActions.Add(options => options.CloseScenes, () => Editor.Instance.Scene.CloseAllScenes());
|
||||||
|
inputActions.Add(options => options.OpenScriptsProject, () => Editor.Instance.CodeEditing.OpenSolution());
|
||||||
|
inputActions.Add(options => options.GenerateScriptsProject, () => Editor.Instance.ProgressReporting.GenerateScriptsProjectFiles.RunAsync());
|
||||||
|
inputActions.Add(options => options.RecompileScripts, ScriptsBuilder.Compile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ namespace FlaxEditor.Viewport
|
|||||||
|
|
||||||
// Input
|
// Input
|
||||||
|
|
||||||
private bool _isControllingMouse, _isViewportControllingMouse;
|
private bool _isControllingMouse, _isViewportControllingMouse, _wasVirtualMouseRightDown, _isVirtualMouseRightDown;
|
||||||
private int _deltaFilteringStep;
|
private int _deltaFilteringStep;
|
||||||
private Float2 _startPos;
|
private Float2 _startPos;
|
||||||
private Float2 _mouseDeltaLast;
|
private Float2 _mouseDeltaLast;
|
||||||
@@ -685,6 +685,9 @@ namespace FlaxEditor.Viewport
|
|||||||
InputActions.Add(options => options.ViewpointBack, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Back").Orientation)));
|
InputActions.Add(options => options.ViewpointBack, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Back").Orientation)));
|
||||||
InputActions.Add(options => options.ViewpointRight, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Right").Orientation)));
|
InputActions.Add(options => options.ViewpointRight, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Right").Orientation)));
|
||||||
InputActions.Add(options => options.ViewpointLeft, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Left").Orientation)));
|
InputActions.Add(options => options.ViewpointLeft, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Left").Orientation)));
|
||||||
|
InputActions.Add(options => options.CameraToggleRotation, () => _isVirtualMouseRightDown = !_isVirtualMouseRightDown);
|
||||||
|
InputActions.Add(options => options.CameraIncreaseMoveSpeed, () => AdjustCameraMoveSpeed(1));
|
||||||
|
InputActions.Add(options => options.CameraDecreaseMoveSpeed, () => AdjustCameraMoveSpeed(-1));
|
||||||
|
|
||||||
// Link for task event
|
// Link for task event
|
||||||
task.Begin += OnRenderBegin;
|
task.Begin += OnRenderBegin;
|
||||||
@@ -722,6 +725,30 @@ namespace FlaxEditor.Viewport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Increases or decreases the camera movement speed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="step">The stepping direction for speed adjustment.</param>
|
||||||
|
protected void AdjustCameraMoveSpeed(int step)
|
||||||
|
{
|
||||||
|
int camValueIndex = -1;
|
||||||
|
for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
|
||||||
|
{
|
||||||
|
if (Mathf.NearEqual(EditorViewportCameraSpeedValues[i], _movementSpeed))
|
||||||
|
{
|
||||||
|
camValueIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (camValueIndex == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (step > 0)
|
||||||
|
MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Min(camValueIndex + 1, EditorViewportCameraSpeedValues.Length - 1)];
|
||||||
|
else if (step < 0)
|
||||||
|
MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Max(camValueIndex - 1, 0)];
|
||||||
|
}
|
||||||
|
|
||||||
private void OnEditorOptionsChanged(EditorOptions options)
|
private void OnEditorOptionsChanged(EditorOptions options)
|
||||||
{
|
{
|
||||||
_mouseSensitivity = options.Viewport.MouseSensitivity;
|
_mouseSensitivity = options.Viewport.MouseSensitivity;
|
||||||
@@ -1048,6 +1075,15 @@ namespace FlaxEditor.Viewport
|
|||||||
// Track controlling mouse state change
|
// Track controlling mouse state change
|
||||||
bool wasControllingMouse = _prevInput.IsControllingMouse;
|
bool wasControllingMouse = _prevInput.IsControllingMouse;
|
||||||
_isControllingMouse = _input.IsControllingMouse;
|
_isControllingMouse = _input.IsControllingMouse;
|
||||||
|
|
||||||
|
// Simulate holding mouse right down for trackpad users
|
||||||
|
if ((_prevInput.IsMouseRightDown && !_input.IsMouseRightDown) || win.GetKeyDown(KeyboardKeys.Escape))
|
||||||
|
_isVirtualMouseRightDown = false; // Cancel when mouse right or escape is pressed
|
||||||
|
if (_wasVirtualMouseRightDown)
|
||||||
|
wasControllingMouse = true;
|
||||||
|
if (_isVirtualMouseRightDown)
|
||||||
|
_isControllingMouse = _isVirtualMouseRightDown;
|
||||||
|
|
||||||
if (wasControllingMouse != _isControllingMouse)
|
if (wasControllingMouse != _isControllingMouse)
|
||||||
{
|
{
|
||||||
if (_isControllingMouse)
|
if (_isControllingMouse)
|
||||||
@@ -1061,16 +1097,18 @@ namespace FlaxEditor.Viewport
|
|||||||
OnLeftMouseButtonDown();
|
OnLeftMouseButtonDown();
|
||||||
else if (_prevInput.IsMouseLeftDown && !_input.IsMouseLeftDown)
|
else if (_prevInput.IsMouseLeftDown && !_input.IsMouseLeftDown)
|
||||||
OnLeftMouseButtonUp();
|
OnLeftMouseButtonUp();
|
||||||
//
|
|
||||||
if (!_prevInput.IsMouseRightDown && _input.IsMouseRightDown)
|
if ((!_prevInput.IsMouseRightDown && _input.IsMouseRightDown) || (!_wasVirtualMouseRightDown && _isVirtualMouseRightDown))
|
||||||
OnRightMouseButtonDown();
|
OnRightMouseButtonDown();
|
||||||
else if (_prevInput.IsMouseRightDown && !_input.IsMouseRightDown)
|
else if ((_prevInput.IsMouseRightDown && !_input.IsMouseRightDown) || (_wasVirtualMouseRightDown && !_isVirtualMouseRightDown))
|
||||||
OnRightMouseButtonUp();
|
OnRightMouseButtonUp();
|
||||||
//
|
|
||||||
if (!_prevInput.IsMouseMiddleDown && _input.IsMouseMiddleDown)
|
if (!_prevInput.IsMouseMiddleDown && _input.IsMouseMiddleDown)
|
||||||
OnMiddleMouseButtonDown();
|
OnMiddleMouseButtonDown();
|
||||||
else if (_prevInput.IsMouseMiddleDown && !_input.IsMouseMiddleDown)
|
else if (_prevInput.IsMouseMiddleDown && !_input.IsMouseMiddleDown)
|
||||||
OnMiddleMouseButtonUp();
|
OnMiddleMouseButtonUp();
|
||||||
|
|
||||||
|
_wasVirtualMouseRightDown = _isVirtualMouseRightDown;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get clamped delta time (more stable during lags)
|
// Get clamped delta time (more stable during lags)
|
||||||
@@ -1088,7 +1126,7 @@ namespace FlaxEditor.Viewport
|
|||||||
bool isAltDown = _input.IsAltDown;
|
bool isAltDown = _input.IsAltDown;
|
||||||
bool lbDown = _input.IsMouseLeftDown;
|
bool lbDown = _input.IsMouseLeftDown;
|
||||||
bool mbDown = _input.IsMouseMiddleDown;
|
bool mbDown = _input.IsMouseMiddleDown;
|
||||||
bool rbDown = _input.IsMouseRightDown;
|
bool rbDown = _input.IsMouseRightDown || _isVirtualMouseRightDown;
|
||||||
bool wheelInUse = Math.Abs(_input.MouseWheelDelta) > Mathf.Epsilon;
|
bool wheelInUse = Math.Abs(_input.MouseWheelDelta) > Mathf.Epsilon;
|
||||||
|
|
||||||
_input.IsPanning = !isAltDown && mbDown && !rbDown;
|
_input.IsPanning = !isAltDown && mbDown && !rbDown;
|
||||||
@@ -1098,32 +1136,20 @@ namespace FlaxEditor.Viewport
|
|||||||
_input.IsOrbiting = isAltDown && lbDown && !mbDown && !rbDown;
|
_input.IsOrbiting = isAltDown && lbDown && !mbDown && !rbDown;
|
||||||
|
|
||||||
// Control move speed with RMB+Wheel
|
// Control move speed with RMB+Wheel
|
||||||
rmbWheel = useMovementSpeed && _input.IsMouseRightDown && wheelInUse;
|
rmbWheel = useMovementSpeed && (_input.IsMouseRightDown || _isVirtualMouseRightDown) && wheelInUse;
|
||||||
if (rmbWheel)
|
if (rmbWheel)
|
||||||
{
|
{
|
||||||
float step = 4.0f;
|
const float step = 4.0f;
|
||||||
_wheelMovementChangeDeltaSum += _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity;
|
_wheelMovementChangeDeltaSum += _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity;
|
||||||
int camValueIndex = -1;
|
if (_wheelMovementChangeDeltaSum >= step)
|
||||||
for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
|
|
||||||
{
|
{
|
||||||
if (Mathf.NearEqual(EditorViewportCameraSpeedValues[i], _movementSpeed))
|
_wheelMovementChangeDeltaSum -= step;
|
||||||
{
|
AdjustCameraMoveSpeed(1);
|
||||||
camValueIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (camValueIndex != -1)
|
else if (_wheelMovementChangeDeltaSum <= -step)
|
||||||
{
|
{
|
||||||
if (_wheelMovementChangeDeltaSum >= step)
|
_wheelMovementChangeDeltaSum += step;
|
||||||
{
|
AdjustCameraMoveSpeed(-1);
|
||||||
_wheelMovementChangeDeltaSum -= step;
|
|
||||||
MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Min(camValueIndex + 1, EditorViewportCameraSpeedValues.Length - 1)];
|
|
||||||
}
|
|
||||||
else if (_wheelMovementChangeDeltaSum <= -step)
|
|
||||||
{
|
|
||||||
_wheelMovementChangeDeltaSum += step;
|
|
||||||
MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Max(camValueIndex - 1, 0)];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1165,7 +1191,7 @@ namespace FlaxEditor.Viewport
|
|||||||
|
|
||||||
// Calculate smooth mouse delta not dependant on viewport size
|
// Calculate smooth mouse delta not dependant on viewport size
|
||||||
var offset = _viewMousePos - _startPos;
|
var offset = _viewMousePos - _startPos;
|
||||||
if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown && !_isOrtho && !rmbWheel)
|
if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown && !_isOrtho && !rmbWheel && !_isVirtualMouseRightDown)
|
||||||
{
|
{
|
||||||
offset = Float2.Zero;
|
offset = Float2.Zero;
|
||||||
}
|
}
|
||||||
@@ -1213,7 +1239,7 @@ namespace FlaxEditor.Viewport
|
|||||||
UpdateView(dt, ref moveDelta, ref mouseDelta, out var centerMouse);
|
UpdateView(dt, ref moveDelta, ref mouseDelta, out var centerMouse);
|
||||||
|
|
||||||
// Move mouse back to the root position
|
// Move mouse back to the root position
|
||||||
if (centerMouse && (_input.IsMouseRightDown || _input.IsMouseLeftDown || _input.IsMouseMiddleDown))
|
if (centerMouse && (_input.IsMouseRightDown || _input.IsMouseLeftDown || _input.IsMouseMiddleDown || _isVirtualMouseRightDown))
|
||||||
{
|
{
|
||||||
var center = PointToWindow(_startPos);
|
var center = PointToWindow(_startPos);
|
||||||
win.MousePosition = center;
|
win.MousePosition = center;
|
||||||
@@ -1229,7 +1255,7 @@ namespace FlaxEditor.Viewport
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_input.IsMouseLeftDown || _input.IsMouseRightDown)
|
if (_input.IsMouseLeftDown || _input.IsMouseRightDown || _isVirtualMouseRightDown)
|
||||||
{
|
{
|
||||||
// Calculate smooth mouse delta not dependant on viewport size
|
// Calculate smooth mouse delta not dependant on viewport size
|
||||||
var offset = _viewMousePos - _startPos;
|
var offset = _viewMousePos - _startPos;
|
||||||
@@ -1359,6 +1385,7 @@ namespace FlaxEditor.Viewport
|
|||||||
{
|
{
|
||||||
OnControlMouseEnd(RootWindow.Window);
|
OnControlMouseEnd(RootWindow.Window);
|
||||||
_isControllingMouse = false;
|
_isControllingMouse = false;
|
||||||
|
_isVirtualMouseRightDown = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ namespace FlaxEditor.Viewport
|
|||||||
{
|
{
|
||||||
_editor = editor;
|
_editor = editor;
|
||||||
_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem);
|
_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem);
|
||||||
|
var inputOptions = editor.Options.Options.Input;
|
||||||
|
|
||||||
// Prepare rendering task
|
// Prepare rendering task
|
||||||
Task.ActorsSource = ActorsSources.Scenes;
|
Task.ActorsSource = ActorsSources.Scenes;
|
||||||
@@ -250,7 +251,7 @@ namespace FlaxEditor.Viewport
|
|||||||
var transformSpaceToggle = new ViewportWidgetButton(string.Empty, editor.Icons.Globe32, null, true)
|
var transformSpaceToggle = new ViewportWidgetButton(string.Empty, editor.Icons.Globe32, null, true)
|
||||||
{
|
{
|
||||||
Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World,
|
Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World,
|
||||||
TooltipText = "Gizmo transform space (world or local)",
|
TooltipText = $"Gizmo transform space (world or local) ({inputOptions.ToggleTransformSpace})",
|
||||||
Parent = transformSpaceWidget
|
Parent = transformSpaceWidget
|
||||||
};
|
};
|
||||||
transformSpaceToggle.Toggled += OnTransformSpaceToggle;
|
transformSpaceToggle.Toggled += OnTransformSpaceToggle;
|
||||||
@@ -347,7 +348,7 @@ namespace FlaxEditor.Viewport
|
|||||||
_gizmoModeTranslate = new ViewportWidgetButton(string.Empty, editor.Icons.Translate32, null, true)
|
_gizmoModeTranslate = new ViewportWidgetButton(string.Empty, editor.Icons.Translate32, null, true)
|
||||||
{
|
{
|
||||||
Tag = TransformGizmoBase.Mode.Translate,
|
Tag = TransformGizmoBase.Mode.Translate,
|
||||||
TooltipText = "Translate gizmo mode",
|
TooltipText = $"Translate gizmo mode ({inputOptions.TranslateMode})",
|
||||||
Checked = true,
|
Checked = true,
|
||||||
Parent = gizmoMode
|
Parent = gizmoMode
|
||||||
};
|
};
|
||||||
@@ -355,14 +356,14 @@ namespace FlaxEditor.Viewport
|
|||||||
_gizmoModeRotate = new ViewportWidgetButton(string.Empty, editor.Icons.Rotate32, null, true)
|
_gizmoModeRotate = new ViewportWidgetButton(string.Empty, editor.Icons.Rotate32, null, true)
|
||||||
{
|
{
|
||||||
Tag = TransformGizmoBase.Mode.Rotate,
|
Tag = TransformGizmoBase.Mode.Rotate,
|
||||||
TooltipText = "Rotate gizmo mode",
|
TooltipText = $"Rotate gizmo mode ({inputOptions.RotateMode})",
|
||||||
Parent = gizmoMode
|
Parent = gizmoMode
|
||||||
};
|
};
|
||||||
_gizmoModeRotate.Toggled += OnGizmoModeToggle;
|
_gizmoModeRotate.Toggled += OnGizmoModeToggle;
|
||||||
_gizmoModeScale = new ViewportWidgetButton(string.Empty, editor.Icons.Scale32, null, true)
|
_gizmoModeScale = new ViewportWidgetButton(string.Empty, editor.Icons.Scale32, null, true)
|
||||||
{
|
{
|
||||||
Tag = TransformGizmoBase.Mode.Scale,
|
Tag = TransformGizmoBase.Mode.Scale,
|
||||||
TooltipText = "Scale gizmo mode",
|
TooltipText = $"Scale gizmo mode ({inputOptions.ScaleMode})",
|
||||||
Parent = gizmoMode
|
Parent = gizmoMode
|
||||||
};
|
};
|
||||||
_gizmoModeScale.Toggled += OnGizmoModeToggle;
|
_gizmoModeScale.Toggled += OnGizmoModeToggle;
|
||||||
@@ -390,6 +391,7 @@ namespace FlaxEditor.Viewport
|
|||||||
InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate);
|
InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate);
|
||||||
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
|
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
|
||||||
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
|
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
|
||||||
|
InputActions.Add(options => options.ToggleTransformSpace, () => { OnTransformSpaceToggle(transformSpaceToggle); transformSpaceToggle.Checked = !transformSpaceToggle.Checked; });
|
||||||
InputActions.Add(options => options.LockFocusSelection, LockFocusSelection);
|
InputActions.Add(options => options.LockFocusSelection, LockFocusSelection);
|
||||||
InputActions.Add(options => options.FocusSelection, FocusSelection);
|
InputActions.Add(options => options.FocusSelection, FocusSelection);
|
||||||
InputActions.Add(options => options.RotateSelection, RotateSelection);
|
InputActions.Add(options => options.RotateSelection, RotateSelection);
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ namespace FlaxEditor.Viewport
|
|||||||
_dragAssets = new DragAssets(ValidateDragItem);
|
_dragAssets = new DragAssets(ValidateDragItem);
|
||||||
ShowDebugDraw = true;
|
ShowDebugDraw = true;
|
||||||
ShowEditorPrimitives = true;
|
ShowEditorPrimitives = true;
|
||||||
|
var inputOptions = window.Editor.Options.Options.Input;
|
||||||
|
|
||||||
// Prepare rendering task
|
// Prepare rendering task
|
||||||
Task.ActorsSource = ActorsSources.CustomActors;
|
Task.ActorsSource = ActorsSources.CustomActors;
|
||||||
@@ -113,7 +114,7 @@ namespace FlaxEditor.Viewport
|
|||||||
var transformSpaceToggle = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Globe32, null, true)
|
var transformSpaceToggle = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Globe32, null, true)
|
||||||
{
|
{
|
||||||
Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World,
|
Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World,
|
||||||
TooltipText = "Gizmo transform space (world or local)",
|
TooltipText = $"Gizmo transform space (world or local) ({inputOptions.ToggleTransformSpace})",
|
||||||
Parent = transformSpaceWidget
|
Parent = transformSpaceWidget
|
||||||
};
|
};
|
||||||
transformSpaceToggle.Toggled += OnTransformSpaceToggle;
|
transformSpaceToggle.Toggled += OnTransformSpaceToggle;
|
||||||
@@ -205,7 +206,7 @@ namespace FlaxEditor.Viewport
|
|||||||
_gizmoModeTranslate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Translate32, null, true)
|
_gizmoModeTranslate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Translate32, null, true)
|
||||||
{
|
{
|
||||||
Tag = TransformGizmoBase.Mode.Translate,
|
Tag = TransformGizmoBase.Mode.Translate,
|
||||||
TooltipText = "Translate gizmo mode",
|
TooltipText = $"Translate gizmo mode ({inputOptions.TranslateMode})",
|
||||||
Checked = true,
|
Checked = true,
|
||||||
Parent = gizmoMode
|
Parent = gizmoMode
|
||||||
};
|
};
|
||||||
@@ -213,14 +214,14 @@ namespace FlaxEditor.Viewport
|
|||||||
_gizmoModeRotate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Rotate32, null, true)
|
_gizmoModeRotate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Rotate32, null, true)
|
||||||
{
|
{
|
||||||
Tag = TransformGizmoBase.Mode.Rotate,
|
Tag = TransformGizmoBase.Mode.Rotate,
|
||||||
TooltipText = "Rotate gizmo mode",
|
TooltipText = $"Rotate gizmo mode ({inputOptions.RotateMode})",
|
||||||
Parent = gizmoMode
|
Parent = gizmoMode
|
||||||
};
|
};
|
||||||
_gizmoModeRotate.Toggled += OnGizmoModeToggle;
|
_gizmoModeRotate.Toggled += OnGizmoModeToggle;
|
||||||
_gizmoModeScale = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Scale32, null, true)
|
_gizmoModeScale = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Scale32, null, true)
|
||||||
{
|
{
|
||||||
Tag = TransformGizmoBase.Mode.Scale,
|
Tag = TransformGizmoBase.Mode.Scale,
|
||||||
TooltipText = "Scale gizmo mode",
|
TooltipText = $"Scale gizmo mode ({inputOptions.ScaleMode})",
|
||||||
Parent = gizmoMode
|
Parent = gizmoMode
|
||||||
};
|
};
|
||||||
_gizmoModeScale.Toggled += OnGizmoModeToggle;
|
_gizmoModeScale.Toggled += OnGizmoModeToggle;
|
||||||
@@ -233,6 +234,7 @@ namespace FlaxEditor.Viewport
|
|||||||
InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate);
|
InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate);
|
||||||
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
|
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
|
||||||
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
|
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
|
||||||
|
InputActions.Add(options => options.ToggleTransformSpace, () => { OnTransformSpaceToggle(transformSpaceToggle); transformSpaceToggle.Checked = !transformSpaceToggle.Checked; });
|
||||||
InputActions.Add(options => options.FocusSelection, ShowSelectedActors);
|
InputActions.Add(options => options.FocusSelection, ShowSelectedActors);
|
||||||
|
|
||||||
SetUpdate(ref _update, OnUpdate);
|
SetUpdate(ref _update, OnUpdate);
|
||||||
|
|||||||
@@ -142,6 +142,8 @@ namespace FlaxEditor.Windows
|
|||||||
Title = "Content";
|
Title = "Content";
|
||||||
Icon = editor.Icons.Folder32;
|
Icon = editor.Icons.Folder32;
|
||||||
|
|
||||||
|
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||||
|
|
||||||
// Content database events
|
// Content database events
|
||||||
editor.ContentDatabase.WorkspaceModified += () => _isWorkspaceDirty = true;
|
editor.ContentDatabase.WorkspaceModified += () => _isWorkspaceDirty = true;
|
||||||
editor.ContentDatabase.ItemRemoved += OnContentDatabaseItemRemoved;
|
editor.ContentDatabase.ItemRemoved += OnContentDatabaseItemRemoved;
|
||||||
|
|||||||
@@ -317,6 +317,7 @@ namespace FlaxEditor.Windows
|
|||||||
Title = "Debug Log";
|
Title = "Debug Log";
|
||||||
Icon = IconInfo;
|
Icon = IconInfo;
|
||||||
OnEditorOptionsChanged(Editor.Options.Options);
|
OnEditorOptionsChanged(Editor.Options.Options);
|
||||||
|
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||||
|
|
||||||
// Toolstrip
|
// Toolstrip
|
||||||
var toolstrip = new ToolStrip(22.0f)
|
var toolstrip = new ToolStrip(22.0f)
|
||||||
|
|||||||
@@ -216,5 +216,36 @@ namespace FlaxEditor.Windows
|
|||||||
|
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool OnClosing(ClosingReason reason)
|
||||||
|
{
|
||||||
|
// Block closing only on user events
|
||||||
|
if (reason == ClosingReason.User)
|
||||||
|
{
|
||||||
|
// Check if asset has been edited and not saved (and still has linked item)
|
||||||
|
if (_isDataDirty && _options != null)
|
||||||
|
{
|
||||||
|
// Ask user for further action
|
||||||
|
var result = MessageBox.Show(
|
||||||
|
"Editor options have been edited. Save before closing?",
|
||||||
|
"Save before closing?",
|
||||||
|
MessageBoxButtons.YesNoCancel
|
||||||
|
);
|
||||||
|
if (result == DialogResult.OK || result == DialogResult.Yes)
|
||||||
|
{
|
||||||
|
// Save and close
|
||||||
|
SaveData();
|
||||||
|
}
|
||||||
|
else if (result == DialogResult.Cancel || result == DialogResult.Abort)
|
||||||
|
{
|
||||||
|
// Cancel closing
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnClosing(reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,6 +271,8 @@ namespace FlaxEditor.Windows
|
|||||||
Title = "Game";
|
Title = "Game";
|
||||||
AutoFocus = true;
|
AutoFocus = true;
|
||||||
|
|
||||||
|
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||||
|
|
||||||
var task = MainRenderTask.Instance;
|
var task = MainRenderTask.Instance;
|
||||||
|
|
||||||
// Setup viewport
|
// Setup viewport
|
||||||
@@ -302,10 +304,6 @@ namespace FlaxEditor.Windows
|
|||||||
// Link editor options
|
// Link editor options
|
||||||
Editor.Options.OptionsChanged += OnOptionsChanged;
|
Editor.Options.OptionsChanged += OnOptionsChanged;
|
||||||
OnOptionsChanged(Editor.Options.Options);
|
OnOptionsChanged(Editor.Options.Options);
|
||||||
|
|
||||||
InputActions.Add(options => options.Play, Editor.Simulation.DelegatePlayOrStopPlayInEditor);
|
|
||||||
InputActions.Add(options => options.Pause, Editor.Simulation.RequestResumeOrPause);
|
|
||||||
InputActions.Add(options => options.StepFrame, Editor.Simulation.RequestPlayOneFrame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChangeViewportRatio(ViewportScaleOptions v)
|
private void ChangeViewportRatio(ViewportScaleOptions v)
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
Title = "Output Log";
|
Title = "Output Log";
|
||||||
ClipChildren = false;
|
ClipChildren = false;
|
||||||
|
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||||
|
|
||||||
// Setup UI
|
// Setup UI
|
||||||
_viewDropdown = new Button(2, 2, 40.0f, TextBoxBase.DefaultHeight)
|
_viewDropdown = new Button(2, 2, 40.0f, TextBoxBase.DefaultHeight)
|
||||||
|
|||||||
@@ -116,6 +116,10 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
_tabs.SelectedTabChanged += OnSelectedTabChanged;
|
_tabs.SelectedTabChanged += OnSelectedTabChanged;
|
||||||
|
|
||||||
|
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||||
|
InputActions.Bindings.RemoveAll(x => x.Callback == this.FocusOrShow);
|
||||||
|
InputActions.Add(options => options.ProfilerWindow, Hide);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnLiveRecordingChanged()
|
private void OnLiveRecordingChanged()
|
||||||
|
|||||||
@@ -19,28 +19,7 @@ namespace FlaxEditor.Windows
|
|||||||
protected SceneEditorWindow(Editor editor, bool hideOnClose, ScrollBars scrollBars)
|
protected SceneEditorWindow(Editor editor, bool hideOnClose, ScrollBars scrollBars)
|
||||||
: base(editor, hideOnClose, scrollBars)
|
: base(editor, hideOnClose, scrollBars)
|
||||||
{
|
{
|
||||||
// Setup input actions
|
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||||
InputActions.Add(options => options.Save, Editor.SaveAll);
|
|
||||||
InputActions.Add(options => options.Undo, () =>
|
|
||||||
{
|
|
||||||
Editor.PerformUndo();
|
|
||||||
Focus();
|
|
||||||
});
|
|
||||||
InputActions.Add(options => options.Redo, () =>
|
|
||||||
{
|
|
||||||
Editor.PerformRedo();
|
|
||||||
Focus();
|
|
||||||
});
|
|
||||||
InputActions.Add(options => options.Cut, Editor.SceneEditing.Cut);
|
|
||||||
InputActions.Add(options => options.Copy, Editor.SceneEditing.Copy);
|
|
||||||
InputActions.Add(options => options.Paste, Editor.SceneEditing.Paste);
|
|
||||||
InputActions.Add(options => options.Duplicate, Editor.SceneEditing.Duplicate);
|
|
||||||
InputActions.Add(options => options.SelectAll, Editor.SceneEditing.SelectAllScenes);
|
|
||||||
InputActions.Add(options => options.Delete, Editor.SceneEditing.Delete);
|
|
||||||
InputActions.Add(options => options.Search, () => Editor.Windows.SceneWin.Search());
|
|
||||||
InputActions.Add(options => options.Play, Editor.Simulation.DelegatePlayOrStopPlayInEditor);
|
|
||||||
InputActions.Add(options => options.Pause, Editor.Simulation.RequestResumeOrPause);
|
|
||||||
InputActions.Add(options => options.StepFrame, Editor.Simulation.RequestPlayOneFrame);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ namespace FlaxEditor.Windows
|
|||||||
bool hasSthSelected = Editor.SceneEditing.HasSthSelected;
|
bool hasSthSelected = Editor.SceneEditing.HasSthSelected;
|
||||||
bool isSingleActorSelected = Editor.SceneEditing.SelectionCount == 1 && Editor.SceneEditing.Selection[0] is ActorNode;
|
bool isSingleActorSelected = Editor.SceneEditing.SelectionCount == 1 && Editor.SceneEditing.Selection[0] is ActorNode;
|
||||||
bool canEditScene = Editor.StateMachine.CurrentState.CanEditScene && Level.IsAnySceneLoaded;
|
bool canEditScene = Editor.StateMachine.CurrentState.CanEditScene && Level.IsAnySceneLoaded;
|
||||||
|
var inputOptions = Editor.Options.Options.Input;
|
||||||
|
|
||||||
// Create popup
|
// Create popup
|
||||||
|
|
||||||
@@ -44,17 +45,17 @@ namespace FlaxEditor.Windows
|
|||||||
|
|
||||||
if (hasSthSelected)
|
if (hasSthSelected)
|
||||||
{
|
{
|
||||||
contextMenu.AddButton(Editor.Windows.EditWin.IsPilotActorActive ? "Stop piloting actor" : "Pilot actor", Editor.UI.PilotActor);
|
contextMenu.AddButton(Editor.Windows.EditWin.IsPilotActorActive ? "Stop piloting actor" : "Pilot actor", inputOptions.PilotActor, Editor.UI.PilotActor);
|
||||||
}
|
}
|
||||||
|
|
||||||
contextMenu.AddSeparator();
|
contextMenu.AddSeparator();
|
||||||
|
|
||||||
// Basic editing options
|
// Basic editing options
|
||||||
|
|
||||||
b = contextMenu.AddButton("Rename", Rename);
|
b = contextMenu.AddButton("Rename", inputOptions.Rename, Rename);
|
||||||
b.Enabled = isSingleActorSelected;
|
b.Enabled = isSingleActorSelected;
|
||||||
|
|
||||||
b = contextMenu.AddButton("Duplicate", Editor.SceneEditing.Duplicate);
|
b = contextMenu.AddButton("Duplicate", inputOptions.Duplicate, Editor.SceneEditing.Duplicate);
|
||||||
b.Enabled = hasSthSelected;
|
b.Enabled = hasSthSelected;
|
||||||
|
|
||||||
if (isSingleActorSelected)
|
if (isSingleActorSelected)
|
||||||
@@ -116,17 +117,17 @@ namespace FlaxEditor.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b = contextMenu.AddButton("Delete", Editor.SceneEditing.Delete);
|
b = contextMenu.AddButton("Delete", inputOptions.Delete, Editor.SceneEditing.Delete);
|
||||||
b.Enabled = hasSthSelected;
|
b.Enabled = hasSthSelected;
|
||||||
|
|
||||||
contextMenu.AddSeparator();
|
contextMenu.AddSeparator();
|
||||||
|
|
||||||
b = contextMenu.AddButton("Copy", Editor.SceneEditing.Copy);
|
b = contextMenu.AddButton("Copy", inputOptions.Copy, Editor.SceneEditing.Copy);
|
||||||
|
|
||||||
b.Enabled = hasSthSelected;
|
b.Enabled = hasSthSelected;
|
||||||
contextMenu.AddButton("Paste", Editor.SceneEditing.Paste);
|
contextMenu.AddButton("Paste", inputOptions.Paste, Editor.SceneEditing.Paste);
|
||||||
|
|
||||||
b = contextMenu.AddButton("Cut", Editor.SceneEditing.Cut);
|
b = contextMenu.AddButton("Cut", inputOptions.Cut, Editor.SceneEditing.Cut);
|
||||||
b.Enabled = canEditScene;
|
b.Enabled = canEditScene;
|
||||||
|
|
||||||
// Prefab options
|
// Prefab options
|
||||||
|
|||||||
@@ -353,6 +353,8 @@ namespace FlaxEditor.Windows
|
|||||||
: base(editor, true, ScrollBars.None)
|
: base(editor, true, ScrollBars.None)
|
||||||
{
|
{
|
||||||
Title = "Toolbox";
|
Title = "Toolbox";
|
||||||
|
|
||||||
|
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
internal static IntPtr MarshalReturnValueType(ref Type returnValue)
|
internal static IntPtr MarshalReturnValueType(ref Type returnValue)
|
||||||
{
|
{
|
||||||
return returnValue != null ? ManagedHandle.ToIntPtr(GetTypeGCHandle(returnValue)) : IntPtr.Zero;
|
return returnValue != null ? ManagedHandle.ToIntPtr(GetTypeManagedHandle(returnValue)) : IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IntPtr MarshalReturnValueArray<TRet>(ref TRet returnValue)
|
internal static IntPtr MarshalReturnValueArray<TRet>(ref TRet returnValue)
|
||||||
@@ -162,8 +162,8 @@ namespace FlaxEngine.Interop
|
|||||||
return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject);
|
return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject);
|
||||||
if (returnType == typeof(bool))
|
if (returnType == typeof(bool))
|
||||||
return (bool)returnObject ? boolTruePtr : boolFalsePtr;
|
return (bool)returnObject ? boolTruePtr : boolFalsePtr;
|
||||||
if (returnType == typeof(Type))
|
if (returnType == typeof(Type) || returnType == typeof(TypeHolder))
|
||||||
return ManagedHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As<Type>(returnObject)));
|
return ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As<Type>(returnObject)));
|
||||||
if (returnType.IsArray && ArrayFactory.GetMarshalledType(returnType.GetElementType()) == returnType.GetElementType())
|
if (returnType.IsArray && ArrayFactory.GetMarshalledType(returnType.GetElementType()) == returnType.GetElementType())
|
||||||
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(Unsafe.As<Array>(returnObject)), GCHandleType.Weak);
|
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(Unsafe.As<Array>(returnObject)), GCHandleType.Weak);
|
||||||
if (returnType.IsArray)
|
if (returnType.IsArray)
|
||||||
@@ -186,8 +186,8 @@ namespace FlaxEngine.Interop
|
|||||||
return (IntPtr)(object)returnObject;
|
return (IntPtr)(object)returnObject;
|
||||||
if (returnType == typeof(ManagedHandle))
|
if (returnType == typeof(ManagedHandle))
|
||||||
return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject);
|
return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject);
|
||||||
if (returnType == typeof(Type))
|
if (returnType == typeof(Type) || returnType == typeof(TypeHolder))
|
||||||
return returnObject != null ? ManagedHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As<Type>(returnObject))) : IntPtr.Zero;
|
return returnObject != null ? ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As<Type>(returnObject))) : IntPtr.Zero;
|
||||||
if (returnType.IsArray)
|
if (returnType.IsArray)
|
||||||
{
|
{
|
||||||
var elementType = returnType.GetElementType();
|
var elementType = returnType.GetElementType();
|
||||||
|
|||||||
@@ -119,13 +119,13 @@ namespace FlaxEngine.Interop
|
|||||||
[CustomMarshaller(typeof(Type), MarshalMode.Default, typeof(SystemTypeMarshaller))]
|
[CustomMarshaller(typeof(Type), MarshalMode.Default, typeof(SystemTypeMarshaller))]
|
||||||
public static class SystemTypeMarshaller
|
public static class SystemTypeMarshaller
|
||||||
{
|
{
|
||||||
public static Type ConvertToManaged(IntPtr unmanaged) => Unsafe.As<Type>(ManagedHandleMarshaller.ConvertToManaged(unmanaged));
|
public static Type ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<FlaxEngine.Interop.NativeInterop.TypeHolder>(ManagedHandleMarshaller.ConvertToManaged(unmanaged)).type : null;
|
||||||
|
|
||||||
public static IntPtr ConvertToUnmanaged(Type managed)
|
public static IntPtr ConvertToUnmanaged(Type managed)
|
||||||
{
|
{
|
||||||
if (managed == null)
|
if (managed == null)
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
ManagedHandle handle = NativeInterop.GetTypeGCHandle(managed);
|
ManagedHandle handle = NativeInterop.GetTypeManagedHandle(managed);
|
||||||
return ManagedHandle.ToIntPtr(handle);
|
return ManagedHandle.ToIntPtr(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace FlaxEngine.Interop
|
|||||||
internal struct NativeClassDefinitions
|
internal struct NativeClassDefinitions
|
||||||
{
|
{
|
||||||
internal ManagedHandle typeHandle;
|
internal ManagedHandle typeHandle;
|
||||||
|
internal IntPtr nativePointer;
|
||||||
internal IntPtr name;
|
internal IntPtr name;
|
||||||
internal IntPtr fullname;
|
internal IntPtr fullname;
|
||||||
internal IntPtr @namespace;
|
internal IntPtr @namespace;
|
||||||
@@ -40,6 +41,7 @@ namespace FlaxEngine.Interop
|
|||||||
internal IntPtr name;
|
internal IntPtr name;
|
||||||
internal ManagedHandle fieldHandle;
|
internal ManagedHandle fieldHandle;
|
||||||
internal ManagedHandle fieldTypeHandle;
|
internal ManagedHandle fieldTypeHandle;
|
||||||
|
internal int fieldOffset;
|
||||||
internal uint fieldAttributes;
|
internal uint fieldAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,6 +141,9 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
unsafe partial class NativeInterop
|
unsafe partial class NativeInterop
|
||||||
{
|
{
|
||||||
|
[LibraryImport("FlaxEngine", EntryPoint = "NativeInterop_CreateClass", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
|
||||||
|
internal static partial void NativeInterop_CreateClass(ref NativeClassDefinitions managedClass, ManagedHandle assemblyHandle);
|
||||||
|
|
||||||
internal enum MTypes : uint
|
internal enum MTypes : uint
|
||||||
{
|
{
|
||||||
End = 0x00,
|
End = 0x00,
|
||||||
@@ -205,46 +210,8 @@ namespace FlaxEngine.Interop
|
|||||||
NativeMemory.AlignedFree(ptr);
|
NativeMemory.AlignedFree(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
private static Assembly GetOwningAssembly(Type type)
|
||||||
internal static void GetManagedClasses(ManagedHandle assemblyHandle, NativeClassDefinitions** managedClasses, int* managedClassCount)
|
|
||||||
{
|
{
|
||||||
Assembly assembly = Unsafe.As<Assembly>(assemblyHandle.Target);
|
|
||||||
var assemblyTypes = GetAssemblyTypes(assembly);
|
|
||||||
|
|
||||||
NativeClassDefinitions* arr = (NativeClassDefinitions*)NativeAlloc(assemblyTypes.Length, Unsafe.SizeOf<NativeClassDefinitions>());
|
|
||||||
|
|
||||||
for (int i = 0; i < assemblyTypes.Length; i++)
|
|
||||||
{
|
|
||||||
var type = assemblyTypes[i];
|
|
||||||
IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf<NativeClassDefinitions>() * i);
|
|
||||||
var managedClass = new NativeClassDefinitions
|
|
||||||
{
|
|
||||||
typeHandle = GetTypeGCHandle(type),
|
|
||||||
name = NativeAllocStringAnsi(type.Name),
|
|
||||||
fullname = NativeAllocStringAnsi(type.GetTypeName()),
|
|
||||||
@namespace = NativeAllocStringAnsi(type.Namespace ?? ""),
|
|
||||||
typeAttributes = (uint)type.Attributes,
|
|
||||||
};
|
|
||||||
Unsafe.Write(ptr.ToPointer(), managedClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
*managedClasses = arr;
|
|
||||||
*managedClassCount = assemblyTypes.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
|
||||||
internal static void GetManagedClassFromType(ManagedHandle typeHandle, NativeClassDefinitions* managedClass, ManagedHandle* assemblyHandle)
|
|
||||||
{
|
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
|
||||||
*managedClass = new NativeClassDefinitions
|
|
||||||
{
|
|
||||||
typeHandle = GetTypeGCHandle(type),
|
|
||||||
name = NativeAllocStringAnsi(type.Name),
|
|
||||||
fullname = NativeAllocStringAnsi(type.GetTypeName()),
|
|
||||||
@namespace = NativeAllocStringAnsi(type.Namespace ?? ""),
|
|
||||||
typeAttributes = (uint)type.Attributes,
|
|
||||||
};
|
|
||||||
|
|
||||||
Assembly assembly = null;
|
Assembly assembly = null;
|
||||||
if (type.IsGenericType && !type.Assembly.IsCollectible)
|
if (type.IsGenericType && !type.Assembly.IsCollectible)
|
||||||
{
|
{
|
||||||
@@ -261,14 +228,87 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
if (assembly == null)
|
if (assembly == null)
|
||||||
assembly = type.Assembly;
|
assembly = type.Assembly;
|
||||||
|
return assembly;
|
||||||
|
}
|
||||||
|
|
||||||
*assemblyHandle = GetAssemblyHandle(assembly);
|
private static NativeClassDefinitions CreateNativeClassDefinitions(Type type, out ManagedHandle assemblyHandle)
|
||||||
|
{
|
||||||
|
assemblyHandle = GetAssemblyHandle(GetOwningAssembly(type));
|
||||||
|
return CreateNativeClassDefinitions(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NativeClassDefinitions CreateNativeClassDefinitions(Type type)
|
||||||
|
{
|
||||||
|
return new NativeClassDefinitions()
|
||||||
|
{
|
||||||
|
typeHandle = RegisterType(type).handle,
|
||||||
|
name = NativeAllocStringAnsi(type.Name),
|
||||||
|
fullname = NativeAllocStringAnsi(type.GetTypeName()),
|
||||||
|
@namespace = NativeAllocStringAnsi(type.Namespace ?? ""),
|
||||||
|
typeAttributes = (uint)type.Attributes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NativeClassDefinitions CreateNativeClassDefinitions(Type type, ManagedHandle typeHandle, out ManagedHandle assemblyHandle)
|
||||||
|
{
|
||||||
|
assemblyHandle = GetAssemblyHandle(GetOwningAssembly(type));
|
||||||
|
return new NativeClassDefinitions()
|
||||||
|
{
|
||||||
|
typeHandle = typeHandle,
|
||||||
|
name = NativeAllocStringAnsi(type.Name),
|
||||||
|
fullname = NativeAllocStringAnsi(type.GetTypeName()),
|
||||||
|
@namespace = NativeAllocStringAnsi(type.Namespace ?? ""),
|
||||||
|
typeAttributes = (uint)type.Attributes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static void GetManagedClasses(ManagedHandle assemblyHandle, NativeClassDefinitions** managedClasses, int* managedClassCount)
|
||||||
|
{
|
||||||
|
Assembly assembly = Unsafe.As<Assembly>(assemblyHandle.Target);
|
||||||
|
Type[] assemblyTypes = GetAssemblyTypes(assembly);
|
||||||
|
|
||||||
|
*managedClasses = (NativeClassDefinitions*)NativeAlloc(assemblyTypes.Length, Unsafe.SizeOf<NativeClassDefinitions>());
|
||||||
|
*managedClassCount = assemblyTypes.Length;
|
||||||
|
Span<NativeClassDefinitions> span = new Span<NativeClassDefinitions>(*managedClasses, assemblyTypes.Length);
|
||||||
|
for (int i = 0; i < assemblyTypes.Length; i++)
|
||||||
|
{
|
||||||
|
Type type = assemblyTypes[i];
|
||||||
|
ref var managedClass = ref span[i];
|
||||||
|
managedClass = CreateNativeClassDefinitions(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static void RegisterManagedClassNativePointers(NativeClassDefinitions** managedClasses, int managedClassCount)
|
||||||
|
{
|
||||||
|
Span<NativeClassDefinitions> span = new Span<NativeClassDefinitions>(Unsafe.Read<IntPtr>(managedClasses).ToPointer(), managedClassCount);
|
||||||
|
foreach (ref NativeClassDefinitions managedClass in span)
|
||||||
|
{
|
||||||
|
TypeHolder typeHolder = Unsafe.As<TypeHolder>(managedClass.typeHandle.Target);
|
||||||
|
typeHolder.managedClassPointer = managedClass.nativePointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static void GetManagedClassFromType(ManagedHandle typeHandle, NativeClassDefinitions* managedClass, ManagedHandle* assemblyHandle)
|
||||||
|
{
|
||||||
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
|
*managedClass = CreateNativeClassDefinitions(type, out ManagedHandle handle);
|
||||||
|
*assemblyHandle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RegisterNativeClassFromType(TypeHolder typeHolder, ManagedHandle typeHandle)
|
||||||
|
{
|
||||||
|
NativeClassDefinitions managedClass = CreateNativeClassDefinitions(typeHolder.type, typeHandle, out ManagedHandle assemblyHandle);
|
||||||
|
NativeInterop_CreateClass(ref managedClass, assemblyHandle);
|
||||||
|
typeHolder.managedClassPointer = managedClass.nativePointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static void GetClassMethods(ManagedHandle typeHandle, NativeMethodDefinitions** classMethods, int* classMethodsCount)
|
internal static void GetClassMethods(ManagedHandle typeHandle, NativeMethodDefinitions** classMethods, int* classMethodsCount)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
|
|
||||||
var methods = new List<MethodInfo>();
|
var methods = new List<MethodInfo>();
|
||||||
var staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
|
var staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
|
||||||
@@ -296,7 +336,7 @@ namespace FlaxEngine.Interop
|
|||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static void GetClassFields(ManagedHandle typeHandle, NativeFieldDefinitions** classFields, int* classFieldsCount)
|
internal static void GetClassFields(ManagedHandle typeHandle, NativeFieldDefinitions** classFields, int* classFieldsCount)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
var fields = type.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
var fields = type.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
|
||||||
NativeFieldDefinitions* arr = (NativeFieldDefinitions*)NativeAlloc(fields.Length, Unsafe.SizeOf<NativeFieldDefinitions>());
|
NativeFieldDefinitions* arr = (NativeFieldDefinitions*)NativeAlloc(fields.Length, Unsafe.SizeOf<NativeFieldDefinitions>());
|
||||||
@@ -318,7 +358,8 @@ namespace FlaxEngine.Interop
|
|||||||
{
|
{
|
||||||
name = NativeAllocStringAnsi(fieldHolder.field.Name),
|
name = NativeAllocStringAnsi(fieldHolder.field.Name),
|
||||||
fieldHandle = fieldHandle,
|
fieldHandle = fieldHandle,
|
||||||
fieldTypeHandle = GetTypeGCHandle(fieldHolder.field.FieldType),
|
fieldTypeHandle = GetTypeManagedHandle(fieldHolder.field.FieldType),
|
||||||
|
fieldOffset = fieldHolder.fieldOffset,
|
||||||
fieldAttributes = (uint)fieldHolder.field.Attributes,
|
fieldAttributes = (uint)fieldHolder.field.Attributes,
|
||||||
};
|
};
|
||||||
Unsafe.Write(IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf<NativeFieldDefinitions>() * i).ToPointer(), classField);
|
Unsafe.Write(IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf<NativeFieldDefinitions>() * i).ToPointer(), classField);
|
||||||
@@ -330,7 +371,7 @@ namespace FlaxEngine.Interop
|
|||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static void GetClassProperties(ManagedHandle typeHandle, NativePropertyDefinitions** classProperties, int* classPropertiesCount)
|
internal static void GetClassProperties(ManagedHandle typeHandle, NativePropertyDefinitions** classProperties, int* classPropertiesCount)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
var properties = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
var properties = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
|
||||||
var arr = (NativePropertyDefinitions*)NativeAlloc(properties.Length, Unsafe.SizeOf<NativePropertyDefinitions>());
|
var arr = (NativePropertyDefinitions*)NativeAlloc(properties.Length, Unsafe.SizeOf<NativePropertyDefinitions>());
|
||||||
@@ -364,7 +405,7 @@ namespace FlaxEngine.Interop
|
|||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static void GetClassAttributes(ManagedHandle typeHandle, ManagedHandle** classAttributes, int* classAttributesCount)
|
internal static void GetClassAttributes(ManagedHandle typeHandle, ManagedHandle** classAttributes, int* classAttributesCount)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
object[] attributeValues = type.GetCustomAttributes(false);
|
object[] attributeValues = type.GetCustomAttributes(false);
|
||||||
|
|
||||||
ManagedHandle* arr = (ManagedHandle*)NativeAlloc(attributeValues.Length, Unsafe.SizeOf<ManagedHandle>());
|
ManagedHandle* arr = (ManagedHandle*)NativeAlloc(attributeValues.Length, Unsafe.SizeOf<ManagedHandle>());
|
||||||
@@ -384,13 +425,13 @@ namespace FlaxEngine.Interop
|
|||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle GetCustomAttribute(ManagedHandle typeHandle, ManagedHandle attributeHandle)
|
internal static ManagedHandle GetCustomAttribute(ManagedHandle typeHandle, ManagedHandle attributeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
var attributes = type.GetCustomAttributes(false);
|
var attributes = type.GetCustomAttributes(false);
|
||||||
object attrib;
|
object attrib;
|
||||||
if (attributeHandle.IsAllocated)
|
if (attributeHandle.IsAllocated)
|
||||||
{
|
{
|
||||||
// Check for certain attribute type
|
// Check for certain attribute type
|
||||||
Type attributeType = Unsafe.As<Type>(attributeHandle.Target);
|
Type attributeType = Unsafe.As<TypeHolder>(attributeHandle.Target);
|
||||||
attrib = attributes.FirstOrDefault(x => x.GetType() == attributeType);
|
attrib = attributes.FirstOrDefault(x => x.GetType() == attributeType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -413,7 +454,7 @@ namespace FlaxEngine.Interop
|
|||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static void GetClassInterfaces(ManagedHandle typeHandle, IntPtr* classInterfaces, int* classInterfacesCount)
|
internal static void GetClassInterfaces(ManagedHandle typeHandle, IntPtr* classInterfaces, int* classInterfacesCount)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
Type[] interfaces = type.GetInterfaces();
|
Type[] interfaces = type.GetInterfaces();
|
||||||
|
|
||||||
// Match mono_class_get_interfaces which doesn't return interfaces from base class
|
// Match mono_class_get_interfaces which doesn't return interfaces from base class
|
||||||
@@ -465,7 +506,7 @@ namespace FlaxEngine.Interop
|
|||||||
IntPtr arr = (IntPtr)NativeAlloc(interfaces.Length, IntPtr.Size);
|
IntPtr arr = (IntPtr)NativeAlloc(interfaces.Length, IntPtr.Size);
|
||||||
for (int i = 0; i < interfaces.Length; i++)
|
for (int i = 0; i < interfaces.Length; i++)
|
||||||
{
|
{
|
||||||
ManagedHandle handle = GetTypeGCHandle(interfaces[i]);
|
ManagedHandle handle = GetTypeManagedHandle(interfaces[i]);
|
||||||
Unsafe.Write<ManagedHandle>(IntPtr.Add(arr, IntPtr.Size * i).ToPointer(), handle);
|
Unsafe.Write<ManagedHandle>(IntPtr.Add(arr, IntPtr.Size * i).ToPointer(), handle);
|
||||||
}
|
}
|
||||||
*classInterfaces = arr;
|
*classInterfaces = arr;
|
||||||
@@ -477,7 +518,7 @@ namespace FlaxEngine.Interop
|
|||||||
{
|
{
|
||||||
MethodHolder methodHolder = Unsafe.As<MethodHolder>(methodHandle.Target);
|
MethodHolder methodHolder = Unsafe.As<MethodHolder>(methodHandle.Target);
|
||||||
Type returnType = methodHolder.returnType;
|
Type returnType = methodHolder.returnType;
|
||||||
return GetTypeGCHandle(returnType);
|
return GetTypeManagedHandle(returnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
@@ -488,7 +529,7 @@ namespace FlaxEngine.Interop
|
|||||||
IntPtr arr = (IntPtr)NativeAlloc(methodHolder.parameterTypes.Length, IntPtr.Size);
|
IntPtr arr = (IntPtr)NativeAlloc(methodHolder.parameterTypes.Length, IntPtr.Size);
|
||||||
for (int i = 0; i < methodHolder.parameterTypes.Length; i++)
|
for (int i = 0; i < methodHolder.parameterTypes.Length; i++)
|
||||||
{
|
{
|
||||||
ManagedHandle typeHandle = GetTypeGCHandle(methodHolder.parameterTypes[i]);
|
ManagedHandle typeHandle = GetTypeManagedHandle(methodHolder.parameterTypes[i]);
|
||||||
Unsafe.Write<ManagedHandle>(IntPtr.Add(new IntPtr(arr), IntPtr.Size * i).ToPointer(), typeHandle);
|
Unsafe.Write<ManagedHandle>(IntPtr.Add(new IntPtr(arr), IntPtr.Size * i).ToPointer(), typeHandle);
|
||||||
}
|
}
|
||||||
*typeHandles = arr;
|
*typeHandles = arr;
|
||||||
@@ -509,22 +550,15 @@ namespace FlaxEngine.Interop
|
|||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle NewObject(ManagedHandle typeHandle)
|
internal static ManagedHandle NewObject(ManagedHandle typeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
TypeHolder typeHolder = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
if (type.IsAbstract)
|
object value = typeHolder.CreateObject();
|
||||||
{
|
|
||||||
// Dotnet doesn't allow to instantiate abstract type thus allow to use generated mock class usage (eg. for Script or GPUResource) for generated abstract types
|
|
||||||
var abstractWrapper = type.GetNestedType("AbstractWrapper", BindingFlags.NonPublic);
|
|
||||||
if (abstractWrapper != null)
|
|
||||||
type = abstractWrapper;
|
|
||||||
}
|
|
||||||
object value = RuntimeHelpers.GetUninitializedObject(type);
|
|
||||||
return ManagedHandle.Alloc(value);
|
return ManagedHandle.Alloc(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle NewArray(ManagedHandle typeHandle, long size)
|
internal static ManagedHandle NewArray(ManagedHandle typeHandle, long size)
|
||||||
{
|
{
|
||||||
Type elementType = Unsafe.As<Type>(typeHandle.Target);
|
Type elementType = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
Type marshalledType = ArrayFactory.GetMarshalledType(elementType);
|
Type marshalledType = ArrayFactory.GetMarshalledType(elementType);
|
||||||
Type arrayType = ArrayFactory.GetArrayType(elementType);
|
Type arrayType = ArrayFactory.GetArrayType(elementType);
|
||||||
if (marshalledType.IsValueType)
|
if (marshalledType.IsValueType)
|
||||||
@@ -543,9 +577,9 @@ namespace FlaxEngine.Interop
|
|||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle GetArrayTypeFromElementType(ManagedHandle elementTypeHandle)
|
internal static ManagedHandle GetArrayTypeFromElementType(ManagedHandle elementTypeHandle)
|
||||||
{
|
{
|
||||||
Type elementType = Unsafe.As<Type>(elementTypeHandle.Target);
|
Type elementType = Unsafe.As<TypeHolder>(elementTypeHandle.Target);
|
||||||
Type classType = ArrayFactory.GetArrayType(elementType);
|
Type classType = ArrayFactory.GetArrayType(elementType);
|
||||||
return GetTypeGCHandle(classType);
|
return GetTypeManagedHandle(classType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
@@ -606,7 +640,7 @@ namespace FlaxEngine.Interop
|
|||||||
Type classType = obj.GetType();
|
Type classType = obj.GetType();
|
||||||
if (classType == typeof(ManagedArray))
|
if (classType == typeof(ManagedArray))
|
||||||
classType = ((ManagedArray)obj).ArrayType;
|
classType = ((ManagedArray)obj).ArrayType;
|
||||||
return GetTypeGCHandle(classType);
|
return GetTypeManagedHandle(classType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
@@ -647,7 +681,7 @@ namespace FlaxEngine.Interop
|
|||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle BoxValue(ManagedHandle typeHandle, IntPtr valuePtr)
|
internal static ManagedHandle BoxValue(ManagedHandle typeHandle, IntPtr valuePtr)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
object value = MarshalToManaged(valuePtr, type);
|
object value = MarshalToManaged(valuePtr, type);
|
||||||
return ManagedHandle.Alloc(value, GCHandleType.Weak);
|
return ManagedHandle.Alloc(value, GCHandleType.Weak);
|
||||||
}
|
}
|
||||||
@@ -690,6 +724,14 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static IntPtr GetObjectClass(ManagedHandle objectHandle)
|
||||||
|
{
|
||||||
|
object obj = objectHandle.Target;
|
||||||
|
TypeHolder typeHolder = GetTypeHolder(obj.GetType());
|
||||||
|
return typeHolder.managedClassPointer;
|
||||||
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static IntPtr InvokeMethod(ManagedHandle instanceHandle, ManagedHandle methodHandle, IntPtr paramPtr, IntPtr exceptionPtr)
|
internal static IntPtr InvokeMethod(ManagedHandle instanceHandle, ManagedHandle methodHandle, IntPtr paramPtr, IntPtr exceptionPtr)
|
||||||
{
|
{
|
||||||
@@ -706,7 +748,7 @@ namespace FlaxEngine.Interop
|
|||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
if (exceptionPtr != IntPtr.Zero)
|
if (exceptionPtr != IntPtr.Zero)
|
||||||
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(exception, GCHandleType.Weak));
|
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(exception, GCHandleType.Weak));
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
}
|
}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
@@ -721,7 +763,7 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
for (int i = 0; i < numParams; i++)
|
for (int i = 0; i < numParams; i++)
|
||||||
{
|
{
|
||||||
IntPtr nativePtr = Marshal.ReadIntPtr(IntPtr.Add(paramPtr, sizeof(IntPtr) * i));
|
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||||
methodParameters[i] = MarshalToManaged(nativePtr, methodHolder.parameterTypes[i]);
|
methodParameters[i] = MarshalToManaged(nativePtr, methodHolder.parameterTypes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -737,7 +779,7 @@ namespace FlaxEngine.Interop
|
|||||||
realException = exception.InnerException;
|
realException = exception.InnerException;
|
||||||
|
|
||||||
if (exceptionPtr != IntPtr.Zero)
|
if (exceptionPtr != IntPtr.Zero)
|
||||||
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||||
else
|
else
|
||||||
throw realException;
|
throw realException;
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
@@ -749,7 +791,7 @@ namespace FlaxEngine.Interop
|
|||||||
Type parameterType = methodHolder.parameterTypes[i];
|
Type parameterType = methodHolder.parameterTypes[i];
|
||||||
if (parameterType.IsByRef)
|
if (parameterType.IsByRef)
|
||||||
{
|
{
|
||||||
IntPtr nativePtr = Marshal.ReadIntPtr(IntPtr.Add(paramPtr, sizeof(IntPtr) * i));
|
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||||
MarshalToNative(methodParameters[i], nativePtr, parameterType.GetElementType());
|
MarshalToNative(methodParameters[i], nativePtr, parameterType.GetElementType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -803,7 +845,7 @@ namespace FlaxEngine.Interop
|
|||||||
internal static int FieldGetOffset(ManagedHandle fieldHandle)
|
internal static int FieldGetOffset(ManagedHandle fieldHandle)
|
||||||
{
|
{
|
||||||
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
||||||
return (int)Marshal.OffsetOf(field.field.DeclaringType, field.field.Name);
|
return field.fieldOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
@@ -811,7 +853,40 @@ namespace FlaxEngine.Interop
|
|||||||
{
|
{
|
||||||
object fieldOwner = fieldOwnerHandle.Target;
|
object fieldOwner = fieldOwnerHandle.Target;
|
||||||
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
||||||
field.toNativeMarshaller(field.field, fieldOwner, valuePtr, out int fieldOffset);
|
field.toNativeMarshaller(field.fieldOffset, fieldOwner, valuePtr, out int fieldSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static void FieldGetValueReference(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle, IntPtr valuePtr)
|
||||||
|
{
|
||||||
|
object fieldOwner = fieldOwnerHandle.Target;
|
||||||
|
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
||||||
|
if (fieldOwner.GetType().IsValueType)
|
||||||
|
{
|
||||||
|
ref IntPtr fieldRef = ref FieldHelper.GetValueTypeFieldReference<object, IntPtr>(field.fieldOffset, ref fieldOwner);
|
||||||
|
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference<object, IntPtr>(field.fieldOffset, ref fieldOwner);
|
||||||
|
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static void FieldGetValueReferenceWithOffset(ManagedHandle fieldOwnerHandle, int fieldOffset, IntPtr valuePtr)
|
||||||
|
{
|
||||||
|
object fieldOwner = fieldOwnerHandle.Target;
|
||||||
|
if (fieldOwner.GetType().IsValueType)
|
||||||
|
{
|
||||||
|
ref IntPtr fieldRef = ref FieldHelper.GetValueTypeFieldReference<object, IntPtr>(fieldOffset, ref fieldOwner);
|
||||||
|
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference<object, IntPtr>(fieldOffset, ref fieldOwner);
|
||||||
|
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
@@ -839,7 +914,15 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle LoadAssemblyImage(IntPtr assemblyPathPtr, IntPtr* assemblyName, IntPtr* assemblyFullName)
|
internal static void GetAssemblyName(ManagedHandle assemblyHandle, IntPtr* assemblyName, IntPtr* assemblyFullName)
|
||||||
|
{
|
||||||
|
Assembly assembly = Unsafe.As<Assembly>(assemblyHandle.Target);
|
||||||
|
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
|
||||||
|
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static ManagedHandle LoadAssemblyImage(IntPtr assemblyPathPtr)
|
||||||
{
|
{
|
||||||
if (!firstAssemblyLoaded)
|
if (!firstAssemblyLoaded)
|
||||||
{
|
{
|
||||||
@@ -847,8 +930,6 @@ namespace FlaxEngine.Interop
|
|||||||
firstAssemblyLoaded = true;
|
firstAssemblyLoaded = true;
|
||||||
|
|
||||||
Assembly flaxEngineAssembly = AssemblyLoadContext.Default.Assemblies.First(x => x.GetName().Name == "FlaxEngine.CSharp");
|
Assembly flaxEngineAssembly = AssemblyLoadContext.Default.Assemblies.First(x => x.GetName().Name == "FlaxEngine.CSharp");
|
||||||
*assemblyName = NativeAllocStringAnsi(flaxEngineAssembly.GetName().Name);
|
|
||||||
*assemblyFullName = NativeAllocStringAnsi(flaxEngineAssembly.FullName);
|
|
||||||
return GetAssemblyHandle(flaxEngineAssembly);
|
return GetAssemblyHandle(flaxEngineAssembly);
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
@@ -882,8 +963,6 @@ namespace FlaxEngine.Interop
|
|||||||
// Assemblies loaded via streams have no Location: https://github.com/dotnet/runtime/issues/12822
|
// Assemblies loaded via streams have no Location: https://github.com/dotnet/runtime/issues/12822
|
||||||
AssemblyLocations.Add(assembly.FullName, assemblyPath);
|
AssemblyLocations.Add(assembly.FullName, assemblyPath);
|
||||||
|
|
||||||
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
|
|
||||||
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
|
|
||||||
return GetAssemblyHandle(assembly);
|
return GetAssemblyHandle(assembly);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -894,15 +973,12 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle GetAssemblyByName(IntPtr namePtr, IntPtr* assemblyName, IntPtr* assemblyFullName)
|
internal static ManagedHandle GetAssemblyByName(IntPtr namePtr)
|
||||||
{
|
{
|
||||||
string name = Marshal.PtrToStringAnsi(namePtr);
|
string name = Marshal.PtrToStringAnsi(namePtr);
|
||||||
Assembly assembly = Utils.GetAssemblies().FirstOrDefault(x => x.GetName().Name == name);
|
Assembly assembly = Utils.GetAssemblies().FirstOrDefault(x => x.GetName().Name == name);
|
||||||
if (assembly == null)
|
if (assembly == null)
|
||||||
return new ManagedHandle();
|
return new ManagedHandle();
|
||||||
|
|
||||||
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
|
|
||||||
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
|
|
||||||
return GetAssemblyHandle(assembly);
|
return GetAssemblyHandle(assembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -941,9 +1017,9 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
// Release all references in collectible ALC
|
// Release all references in collectible ALC
|
||||||
cachedDelegatesCollectible.Clear();
|
cachedDelegatesCollectible.Clear();
|
||||||
foreach (var pair in typeHandleCacheCollectible)
|
foreach (var pair in managedTypesCollectible)
|
||||||
pair.Value.Free();
|
pair.Value.handle.Free();
|
||||||
typeHandleCacheCollectible.Clear();
|
managedTypesCollectible.Clear();
|
||||||
foreach (var handle in methodHandlesCollectible)
|
foreach (var handle in methodHandlesCollectible)
|
||||||
handle.Free();
|
handle.Free();
|
||||||
methodHandlesCollectible.Clear();
|
methodHandlesCollectible.Clear();
|
||||||
@@ -973,7 +1049,7 @@ namespace FlaxEngine.Interop
|
|||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static int NativeSizeOf(ManagedHandle typeHandle)
|
internal static int NativeSizeOf(ManagedHandle typeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
Type nativeType = GetInternalType(type) ?? type;
|
Type nativeType = GetInternalType(type) ?? type;
|
||||||
if (nativeType == typeof(Version))
|
if (nativeType == typeof(Version))
|
||||||
nativeType = typeof(NativeVersion);
|
nativeType = typeof(NativeVersion);
|
||||||
@@ -991,8 +1067,8 @@ namespace FlaxEngine.Interop
|
|||||||
if (typeHandle == otherTypeHandle)
|
if (typeHandle == otherTypeHandle)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
Type otherType = Unsafe.As<Type>(otherTypeHandle.Target);
|
Type otherType = Unsafe.As<TypeHolder>(otherTypeHandle.Target);
|
||||||
|
|
||||||
if (type == otherType)
|
if (type == otherType)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1009,37 +1085,39 @@ namespace FlaxEngine.Interop
|
|||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static byte TypeIsAssignableFrom(ManagedHandle typeHandle, ManagedHandle otherTypeHandle)
|
internal static byte TypeIsAssignableFrom(ManagedHandle typeHandle, ManagedHandle otherTypeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
Type otherType = Unsafe.As<Type>(otherTypeHandle.Target);
|
Type otherType = Unsafe.As<TypeHolder>(otherTypeHandle.Target);
|
||||||
return (byte)(type.IsAssignableFrom(otherType) ? 1 : 0);
|
return (byte)(type.IsAssignableFrom(otherType) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static byte TypeIsValueType(ManagedHandle typeHandle)
|
internal static byte TypeIsValueType(ManagedHandle typeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
return (byte)(type.IsValueType ? 1 : 0);
|
return (byte)(type.IsValueType ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static byte TypeIsEnum(ManagedHandle typeHandle)
|
internal static byte TypeIsEnum(ManagedHandle typeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
return (byte)(type.IsEnum ? 1 : 0);
|
return (byte)(type.IsEnum ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle GetClassParent(ManagedHandle typeHandle)
|
internal static IntPtr GetClassParent(ManagedHandle typeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
TypeHolder typeHolder = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
return GetTypeGCHandle(type.BaseType);
|
TypeHolder baseTypeHolder = GetTypeHolder(typeHolder.type.BaseType);
|
||||||
|
return baseTypeHolder.managedClassPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle GetElementClass(ManagedHandle typeHandle)
|
internal static IntPtr GetElementClass(ManagedHandle typeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
TypeHolder typeHolder = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
return GetTypeGCHandle(type.GetElementType());
|
TypeHolder elementTypeHolder = GetTypeHolder(typeHolder.type.GetElementType());
|
||||||
|
return elementTypeHolder.managedClassPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
@@ -1130,32 +1208,35 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle GetTypeClass(ManagedHandle typeHandle)
|
internal static IntPtr GetTypeClass(ManagedHandle typeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
TypeHolder typeHolder = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
if (type.IsByRef)
|
if (typeHolder.type.IsByRef)
|
||||||
type = type.GetElementType(); // Drop reference type (&) to get actual value type
|
{
|
||||||
return GetTypeGCHandle(type);
|
// Drop reference type (&) to get actual value type
|
||||||
|
return GetTypeHolder(typeHolder.type.GetElementType()).managedClassPointer;
|
||||||
|
}
|
||||||
|
return typeHolder.managedClassPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static bool GetTypeIsPointer(ManagedHandle typeHandle)
|
internal static bool GetTypeIsPointer(ManagedHandle typeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
return type.IsPointer;
|
return type.IsPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static bool GetTypeIsReference(ManagedHandle typeHandle)
|
internal static bool GetTypeIsReference(ManagedHandle typeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
return type.IsByRef;
|
return type.IsByRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static uint GetTypeMTypesEnum(ManagedHandle typeHandle)
|
internal static uint GetTypeMTypesEnum(ManagedHandle typeHandle)
|
||||||
{
|
{
|
||||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
if (type.IsByRef)
|
if (type.IsByRef)
|
||||||
type = type.GetElementType(); // Drop reference type (&) to get actual value type
|
type = type.GetElementType(); // Drop reference type (&) to get actual value type
|
||||||
MTypes monoType;
|
MTypes monoType;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,9 +15,11 @@ namespace
|
|||||||
{
|
{
|
||||||
if (collection.IsEmpty())
|
if (collection.IsEmpty())
|
||||||
return;
|
return;
|
||||||
|
const auto c = collection.Get();
|
||||||
for (int32 i = 0; i < collection.Count(); i++)
|
for (int32 i = 0; i < collection.Count(); i++)
|
||||||
{
|
{
|
||||||
if (collection[i].First == collider || collection[i].Second == collider)
|
const SimulationEventCallback::CollidersPair cc = c[i];
|
||||||
|
if (cc.First == collider || cc.Second == collider)
|
||||||
{
|
{
|
||||||
collection.RemoveAt(i--);
|
collection.RemoveAt(i--);
|
||||||
if (collection.IsEmpty())
|
if (collection.IsEmpty())
|
||||||
@@ -32,7 +34,8 @@ namespace
|
|||||||
return;
|
return;
|
||||||
for (auto i = collection.Begin(); i.IsNotEnd(); ++i)
|
for (auto i = collection.Begin(); i.IsNotEnd(); ++i)
|
||||||
{
|
{
|
||||||
if (i->Key.First == collider || i->Key.Second == collider)
|
const SimulationEventCallback::CollidersPair cc = i->Key;
|
||||||
|
if (cc.First == collider || cc.Second == collider)
|
||||||
{
|
{
|
||||||
collection.Remove(i);
|
collection.Remove(i);
|
||||||
if (collection.IsEmpty())
|
if (collection.IsEmpty())
|
||||||
|
|||||||
@@ -51,6 +51,15 @@ public:
|
|||||||
/// <param name="name">The assembly name.</param>
|
/// <param name="name">The assembly name.</param>
|
||||||
MAssembly(MDomain* domain, const StringAnsiView& name);
|
MAssembly(MDomain* domain, const StringAnsiView& name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MAssembly"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="domain">The assembly domain.</param>
|
||||||
|
/// <param name="name">The assembly name.</param>
|
||||||
|
/// <param name="fullname">The assembly full name.</param>
|
||||||
|
/// <param name="handle">The managed handle of the assembly.</param>
|
||||||
|
MAssembly(MDomain* domain, const StringAnsiView& name, const StringAnsiView& fullname, void* handle);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finalizes an instance of the <see cref="MAssembly"/> class.
|
/// Finalizes an instance of the <see cref="MAssembly"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -48,6 +48,18 @@ MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name, const StringAnsiView& fullname, void* handle)
|
||||||
|
: _domain(domain)
|
||||||
|
, _isLoaded(false)
|
||||||
|
, _isLoading(false)
|
||||||
|
, _hasCachedClasses(false)
|
||||||
|
, _reloadCount(0)
|
||||||
|
, _name(name)
|
||||||
|
, _fullname(fullname)
|
||||||
|
, _handle(handle)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
MAssembly::~MAssembly()
|
MAssembly::~MAssembly()
|
||||||
{
|
{
|
||||||
Unload();
|
Unload();
|
||||||
|
|||||||
@@ -190,4 +190,13 @@ public:
|
|||||||
static MClass* Double;
|
static MClass* Double;
|
||||||
static MClass* String;
|
static MClass* String;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Utilities for ScriptingObject management.
|
||||||
|
/// </summary>
|
||||||
|
struct FLAXENGINE_API ScriptingObject
|
||||||
|
{
|
||||||
|
static void SetInternalValues(MClass* klass, MObject* object, void* unmanagedPtr, const Guid* id);
|
||||||
|
static MObject* CreateScriptingObject(MClass* klass, void* unmanagedPtr, const Guid* id);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ protected:
|
|||||||
#elif USE_NETCORE
|
#elif USE_NETCORE
|
||||||
void* _handle;
|
void* _handle;
|
||||||
void* _type;
|
void* _type;
|
||||||
|
int32 _fieldOffset;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MClass* _parentClass;
|
MClass* _parentClass;
|
||||||
@@ -35,7 +36,7 @@ public:
|
|||||||
#if USE_MONO
|
#if USE_MONO
|
||||||
explicit MField(MonoClassField* monoField, const char* name, MClass* parentClass);
|
explicit MField(MonoClassField* monoField, const char* name, MClass* parentClass);
|
||||||
#elif USE_NETCORE
|
#elif USE_NETCORE
|
||||||
MField(MClass* parentClass, void* handle, const char* name, void* type, MFieldAttributes attributes);
|
MField(MClass* parentClass, void* handle, const char* name, void* type, int fieldOffset, MFieldAttributes attributes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -102,6 +103,16 @@ public:
|
|||||||
/// <param name="result">The return value of undefined type.</param>
|
/// <param name="result">The return value of undefined type.</param>
|
||||||
void GetValue(MObject* instance, void* result) const;
|
void GetValue(MObject* instance, void* result) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Value will be a pointer.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="instance">The object of given type to get value from.</param>
|
||||||
|
/// <param name="result">The return value of undefined type.</param>
|
||||||
|
void GetValueReference(MObject* instance, void* result) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null. If returned value is a value type it will be boxed.
|
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null. If returned value is a value type it will be boxed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace FlaxEngine
|
|||||||
// Construct missing native object if managed objects gets created in managed world
|
// Construct missing native object if managed objects gets created in managed world
|
||||||
if (__unmanagedPtr == IntPtr.Zero)
|
if (__unmanagedPtr == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Internal_ManagedInstanceCreated(this);
|
Internal_ManagedInstanceCreated(this, FlaxEngine.Interop.NativeInterop.GetTypeHolder(GetType()).managedClassPointer);
|
||||||
if (__unmanagedPtr == IntPtr.Zero)
|
if (__unmanagedPtr == IntPtr.Zero)
|
||||||
throw new Exception($"Failed to create native instance for object of type {GetType().FullName} (assembly: {GetType().Assembly.FullName}).");
|
throw new Exception($"Failed to create native instance for object of type {GetType().FullName} (assembly: {GetType().Assembly.FullName}).");
|
||||||
}
|
}
|
||||||
@@ -320,7 +320,7 @@ namespace FlaxEngine
|
|||||||
internal static partial Object Internal_Create2(string typeName);
|
internal static partial Object Internal_Create2(string typeName);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceCreated", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceCreated", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
|
||||||
internal static partial void Internal_ManagedInstanceCreated(Object managedInstance);
|
internal static partial void Internal_ManagedInstanceCreated(Object managedInstance, IntPtr theKlass);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceDeleted", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceDeleted", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
|
||||||
internal static partial void Internal_ManagedInstanceDeleted(IntPtr nativeInstance);
|
internal static partial void Internal_ManagedInstanceDeleted(IntPtr nativeInstance);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "Engine/Platform/Platform.h"
|
#include "Engine/Platform/Platform.h"
|
||||||
#include "Engine/Platform/File.h"
|
#include "Engine/Platform/File.h"
|
||||||
#include "Engine/Platform/FileSystem.h"
|
#include "Engine/Platform/FileSystem.h"
|
||||||
|
#include "Engine/Scripting/Internal/InternalCalls.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||||
@@ -214,6 +215,7 @@ void* GetCustomAttribute(const MClass* klass, const MClass* attributeClass);
|
|||||||
struct NativeClassDefinitions
|
struct NativeClassDefinitions
|
||||||
{
|
{
|
||||||
void* typeHandle;
|
void* typeHandle;
|
||||||
|
MClass* nativePointer;
|
||||||
const char* name;
|
const char* name;
|
||||||
const char* fullname;
|
const char* fullname;
|
||||||
const char* namespace_;
|
const char* namespace_;
|
||||||
@@ -233,6 +235,7 @@ struct NativeFieldDefinitions
|
|||||||
const char* name;
|
const char* name;
|
||||||
void* fieldHandle;
|
void* fieldHandle;
|
||||||
void* fieldType;
|
void* fieldType;
|
||||||
|
int fieldOffset;
|
||||||
MFieldAttributes fieldAttributes;
|
MFieldAttributes fieldAttributes;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -341,8 +344,8 @@ void MCore::Object::Init(MObject* obj)
|
|||||||
MClass* MCore::Object::GetClass(MObject* obj)
|
MClass* MCore::Object::GetClass(MObject* obj)
|
||||||
{
|
{
|
||||||
ASSERT(obj);
|
ASSERT(obj);
|
||||||
MType* typeHandle = GetObjectType(obj);
|
static void* GetObjectClassPtr = GetStaticMethodPointer(TEXT("GetObjectClass"));
|
||||||
return GetOrCreateClass(typeHandle);
|
return (MClass*)CallStaticMethod<MClass*, void*>(GetObjectClassPtr, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
MString* MCore::Object::ToString(MObject* obj)
|
MString* MCore::Object::ToString(MObject* obj)
|
||||||
@@ -574,8 +577,7 @@ MObject* MCore::Exception::GetNotSupported(const char* msg)
|
|||||||
MClass* MCore::Type::GetClass(MType* type)
|
MClass* MCore::Type::GetClass(MType* type)
|
||||||
{
|
{
|
||||||
static void* GetTypeClassPtr = GetStaticMethodPointer(TEXT("GetTypeClass"));
|
static void* GetTypeClassPtr = GetStaticMethodPointer(TEXT("GetTypeClass"));
|
||||||
type = (MType*)CallStaticMethod<void*, void*>(GetTypeClassPtr, type);
|
return CallStaticMethod<MClass*, void*>(GetTypeClassPtr, type);
|
||||||
return GetOrCreateClass(type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MType* MCore::Type::GetElementType(MType* type)
|
MType* MCore::Type::GetElementType(MType* type)
|
||||||
@@ -640,10 +642,16 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
|
|||||||
MClass* klass = New<MClass>(this, managedClass.typeHandle, managedClass.name, managedClass.fullname, managedClass.namespace_, managedClass.typeAttributes);
|
MClass* klass = New<MClass>(this, managedClass.typeHandle, managedClass.name, managedClass.fullname, managedClass.namespace_, managedClass.typeAttributes);
|
||||||
_classes.Add(klass->GetFullName(), klass);
|
_classes.Add(klass->GetFullName(), klass);
|
||||||
|
|
||||||
|
managedClass.nativePointer = klass;
|
||||||
|
|
||||||
MCore::GC::FreeMemory((void*)managedClasses[i].name);
|
MCore::GC::FreeMemory((void*)managedClasses[i].name);
|
||||||
MCore::GC::FreeMemory((void*)managedClasses[i].fullname);
|
MCore::GC::FreeMemory((void*)managedClasses[i].fullname);
|
||||||
MCore::GC::FreeMemory((void*)managedClasses[i].namespace_);
|
MCore::GC::FreeMemory((void*)managedClasses[i].namespace_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void* RegisterManagedClassNativePointersPtr = GetStaticMethodPointer(TEXT("RegisterManagedClassNativePointers"));
|
||||||
|
CallStaticMethod<void, NativeClassDefinitions**, int>(RegisterManagedClassNativePointersPtr, &managedClasses, classCount);
|
||||||
|
|
||||||
MCore::GC::FreeMemory(managedClasses);
|
MCore::GC::FreeMemory(managedClasses);
|
||||||
|
|
||||||
const auto endTime = DateTime::NowUTC();
|
const auto endTime = DateTime::NowUTC();
|
||||||
@@ -658,6 +666,39 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
|
|||||||
return _classes;
|
return _classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetAssemblyName(void* assemblyHandle, StringAnsi& name, StringAnsi& fullname)
|
||||||
|
{
|
||||||
|
static void* GetAssemblyNamePtr = GetStaticMethodPointer(TEXT("GetAssemblyName"));
|
||||||
|
const char* name_;
|
||||||
|
const char* fullname_;
|
||||||
|
CallStaticMethod<void, void*, const char**, const char**>(GetAssemblyNamePtr, assemblyHandle, &name_, &fullname_);
|
||||||
|
name = name_;
|
||||||
|
fullname = fullname_;
|
||||||
|
MCore::GC::FreeMemory((void*)name_);
|
||||||
|
MCore::GC::FreeMemory((void*)fullname_);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_INTERNAL_CALL(void) NativeInterop_CreateClass(NativeClassDefinitions* managedClass, void* assemblyHandle)
|
||||||
|
{
|
||||||
|
MAssembly* assembly = GetAssembly(assemblyHandle);
|
||||||
|
if (assembly == nullptr)
|
||||||
|
{
|
||||||
|
StringAnsi assemblyName;
|
||||||
|
StringAnsi assemblyFullName;
|
||||||
|
GetAssemblyName(assemblyHandle, assemblyName, assemblyFullName);
|
||||||
|
|
||||||
|
assembly = New<MAssembly>(nullptr, assemblyName, assemblyFullName, assemblyHandle);
|
||||||
|
CachedAssemblyHandles.Add(assemblyHandle, assembly);
|
||||||
|
}
|
||||||
|
|
||||||
|
MClass* klass = New<MClass>(assembly, managedClass->typeHandle, managedClass->name, managedClass->fullname, managedClass->namespace_, managedClass->typeAttributes);
|
||||||
|
if (assembly != nullptr)
|
||||||
|
{
|
||||||
|
const_cast<MAssembly::ClassesDictionary&>(assembly->GetClasses()).Add(klass->GetFullName(), klass);
|
||||||
|
}
|
||||||
|
managedClass->nativePointer = klass;
|
||||||
|
}
|
||||||
|
|
||||||
bool MAssembly::LoadCorlib()
|
bool MAssembly::LoadCorlib()
|
||||||
{
|
{
|
||||||
if (IsLoaded())
|
if (IsLoaded())
|
||||||
@@ -677,14 +718,9 @@ bool MAssembly::LoadCorlib()
|
|||||||
|
|
||||||
// Load
|
// Load
|
||||||
{
|
{
|
||||||
const char* name;
|
|
||||||
const char* fullname;
|
|
||||||
static void* GetAssemblyByNamePtr = GetStaticMethodPointer(TEXT("GetAssemblyByName"));
|
static void* GetAssemblyByNamePtr = GetStaticMethodPointer(TEXT("GetAssemblyByName"));
|
||||||
_handle = CallStaticMethod<void*, const char*, const char**, const char**>(GetAssemblyByNamePtr, "System.Private.CoreLib", &name, &fullname);
|
_handle = CallStaticMethod<void*, const char*>(GetAssemblyByNamePtr, "System.Private.CoreLib");
|
||||||
_name = name;
|
GetAssemblyName(_handle, _name, _fullname);
|
||||||
_fullname = fullname;
|
|
||||||
MCore::GC::FreeMemory((void*)name);
|
|
||||||
MCore::GC::FreeMemory((void*)fullname);
|
|
||||||
}
|
}
|
||||||
if (_handle == nullptr)
|
if (_handle == nullptr)
|
||||||
{
|
{
|
||||||
@@ -703,19 +739,14 @@ bool MAssembly::LoadImage(const String& assemblyPath, const StringView& nativePa
|
|||||||
{
|
{
|
||||||
// TODO: Use new hostfxr delegate load_assembly_bytes? (.NET 8+)
|
// TODO: Use new hostfxr delegate load_assembly_bytes? (.NET 8+)
|
||||||
// Open .Net assembly
|
// Open .Net assembly
|
||||||
const char* name = nullptr;
|
|
||||||
const char* fullname = nullptr;
|
|
||||||
static void* LoadAssemblyImagePtr = GetStaticMethodPointer(TEXT("LoadAssemblyImage"));
|
static void* LoadAssemblyImagePtr = GetStaticMethodPointer(TEXT("LoadAssemblyImage"));
|
||||||
_handle = CallStaticMethod<void*, const Char*, const char**, const char**>(LoadAssemblyImagePtr, assemblyPath.Get(), &name, &fullname);
|
_handle = CallStaticMethod<void*, const Char*>(LoadAssemblyImagePtr, assemblyPath.Get());
|
||||||
_name = StringAnsi(name);
|
|
||||||
_fullname = StringAnsi(fullname);
|
|
||||||
MCore::GC::FreeMemory((void*)name);
|
|
||||||
MCore::GC::FreeMemory((void*)fullname);
|
|
||||||
if (_handle == nullptr)
|
if (_handle == nullptr)
|
||||||
{
|
{
|
||||||
Log::CLRInnerException(TEXT(".NET assembly image is invalid at ") + assemblyPath);
|
Log::CLRInnerException(TEXT(".NET assembly image is invalid at ") + assemblyPath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
GetAssemblyName(_handle, _name, _fullname);
|
||||||
CachedAssemblyHandles.Add(_handle, this);
|
CachedAssemblyHandles.Add(_handle, this);
|
||||||
|
|
||||||
// Provide new path of hot-reloaded native library path for managed DllImport
|
// Provide new path of hot-reloaded native library path for managed DllImport
|
||||||
@@ -845,8 +876,7 @@ MType* MClass::GetType() const
|
|||||||
MClass* MClass::GetBaseClass() const
|
MClass* MClass::GetBaseClass() const
|
||||||
{
|
{
|
||||||
static void* GetClassParentPtr = GetStaticMethodPointer(TEXT("GetClassParent"));
|
static void* GetClassParentPtr = GetStaticMethodPointer(TEXT("GetClassParent"));
|
||||||
MType* parentTypeHandle = CallStaticMethod<MType*, void*>(GetClassParentPtr, _handle);
|
return CallStaticMethod<MClass*, void*>(GetClassParentPtr, _handle);
|
||||||
return GetOrCreateClass(parentTypeHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MClass::IsSubClassOf(const MClass* klass, bool checkInterfaces) const
|
bool MClass::IsSubClassOf(const MClass* klass, bool checkInterfaces) const
|
||||||
@@ -881,8 +911,7 @@ uint32 MClass::GetInstanceSize() const
|
|||||||
MClass* MClass::GetElementClass() const
|
MClass* MClass::GetElementClass() const
|
||||||
{
|
{
|
||||||
static void* GetElementClassPtr = GetStaticMethodPointer(TEXT("GetElementClass"));
|
static void* GetElementClassPtr = GetStaticMethodPointer(TEXT("GetElementClass"));
|
||||||
MType* elementTypeHandle = CallStaticMethod<MType*, void*>(GetElementClassPtr, _handle);
|
return CallStaticMethod<MClass*, void*>(GetElementClassPtr, _handle);
|
||||||
return GetOrCreateClass(elementTypeHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MMethod* MClass::GetMethod(const char* name, int32 numParams) const
|
MMethod* MClass::GetMethod(const char* name, int32 numParams) const
|
||||||
@@ -941,7 +970,7 @@ const Array<MField*>& MClass::GetFields() const
|
|||||||
for (int32 i = 0; i < numFields; i++)
|
for (int32 i = 0; i < numFields; i++)
|
||||||
{
|
{
|
||||||
NativeFieldDefinitions& definition = fields[i];
|
NativeFieldDefinitions& definition = fields[i];
|
||||||
MField* field = New<MField>(const_cast<MClass*>(this), definition.fieldHandle, definition.name, definition.fieldType, definition.fieldAttributes);
|
MField* field = New<MField>(const_cast<MClass*>(this), definition.fieldHandle, definition.name, definition.fieldType, definition.fieldOffset, definition.fieldAttributes);
|
||||||
_fields.Add(field);
|
_fields.Add(field);
|
||||||
MCore::GC::FreeMemory((void*)definition.name);
|
MCore::GC::FreeMemory((void*)definition.name);
|
||||||
}
|
}
|
||||||
@@ -1022,7 +1051,7 @@ bool MClass::HasAttribute(const MClass* monoClass) const
|
|||||||
|
|
||||||
bool MClass::HasAttribute() const
|
bool MClass::HasAttribute() const
|
||||||
{
|
{
|
||||||
return GetCustomAttribute(this, nullptr) != nullptr;
|
return !GetAttributes().IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
MObject* MClass::GetAttribute(const MClass* monoClass) const
|
MObject* MClass::GetAttribute(const MClass* monoClass) const
|
||||||
@@ -1132,11 +1161,12 @@ MException::~MException()
|
|||||||
Delete(InnerException);
|
Delete(InnerException);
|
||||||
}
|
}
|
||||||
|
|
||||||
MField::MField(MClass* parentClass, void* handle, const char* name, void* type, MFieldAttributes attributes)
|
MField::MField(MClass* parentClass, void* handle, const char* name, void* type, int fieldOffset, MFieldAttributes attributes)
|
||||||
: _handle(handle)
|
: _handle(handle)
|
||||||
, _type(type)
|
, _type(type)
|
||||||
, _parentClass(parentClass)
|
, _parentClass(parentClass)
|
||||||
, _name(name)
|
, _name(name)
|
||||||
|
, _fieldOffset(fieldOffset)
|
||||||
, _hasCachedAttributes(false)
|
, _hasCachedAttributes(false)
|
||||||
{
|
{
|
||||||
switch (attributes & MFieldAttributes::FieldAccessMask)
|
switch (attributes & MFieldAttributes::FieldAccessMask)
|
||||||
@@ -1172,8 +1202,7 @@ MType* MField::GetType() const
|
|||||||
|
|
||||||
int32 MField::GetOffset() const
|
int32 MField::GetOffset() const
|
||||||
{
|
{
|
||||||
static void* FieldGetOffsetPtr = GetStaticMethodPointer(TEXT("FieldGetOffset"));
|
return _fieldOffset;
|
||||||
return CallStaticMethod<int32, void*>(FieldGetOffsetPtr, _handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MField::GetValue(MObject* instance, void* result) const
|
void MField::GetValue(MObject* instance, void* result) const
|
||||||
@@ -1182,6 +1211,12 @@ void MField::GetValue(MObject* instance, void* result) const
|
|||||||
CallStaticMethod<void, void*, void*, void*>(FieldGetValuePtr, instance, _handle, result);
|
CallStaticMethod<void, void*, void*, void*>(FieldGetValuePtr, instance, _handle, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MField::GetValueReference(MObject* instance, void* result) const
|
||||||
|
{
|
||||||
|
static void* FieldGetValueReferencePtr = GetStaticMethodPointer(TEXT("FieldGetValueReferenceWithOffset"));
|
||||||
|
CallStaticMethod<void, void*, int, void*>(FieldGetValueReferencePtr, instance, _fieldOffset, result);
|
||||||
|
}
|
||||||
|
|
||||||
MObject* MField::GetValueBoxed(MObject* instance) const
|
MObject* MField::GetValueBoxed(MObject* instance) const
|
||||||
{
|
{
|
||||||
static void* FieldGetValueBoxedPtr = GetStaticMethodPointer(TEXT("FieldGetValueBoxed"));
|
static void* FieldGetValueBoxedPtr = GetStaticMethodPointer(TEXT("FieldGetValueBoxed"));
|
||||||
@@ -1514,8 +1549,7 @@ void* GetCustomAttribute(const MClass* klass, const MClass* attributeClass)
|
|||||||
const Array<MObject*>& attributes = klass->GetAttributes();
|
const Array<MObject*>& attributes = klass->GetAttributes();
|
||||||
for (MObject* attr : attributes)
|
for (MObject* attr : attributes)
|
||||||
{
|
{
|
||||||
MType* typeHandle = GetObjectType(attr);
|
MClass* attrClass = MCore::Object::GetClass(attr);
|
||||||
MClass* attrClass = GetOrCreateClass(typeHandle);
|
|
||||||
if (attrClass == attributeClass)
|
if (attrClass == attributeClass)
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
@@ -1703,6 +1737,18 @@ void* GetStaticMethodPointer(const String& methodName)
|
|||||||
return fun;
|
return fun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCore::ScriptingObject::SetInternalValues(MClass* klass, MObject* object, void* unmanagedPtr, const Guid* id)
|
||||||
|
{
|
||||||
|
static void* ScriptingObjectSetInternalValuesPtr = GetStaticMethodPointer(TEXT("ScriptingObjectSetInternalValues"));
|
||||||
|
CallStaticMethod<void, MObject*, void*, const Guid*>(ScriptingObjectSetInternalValuesPtr, object, unmanagedPtr, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MObject* MCore::ScriptingObject::CreateScriptingObject(MClass* klass, void* unmanagedPtr, const Guid* id)
|
||||||
|
{
|
||||||
|
static void* ScriptingObjectSetInternalValuesPtr = GetStaticMethodPointer(TEXT("ScriptingObjectCreate"));
|
||||||
|
return CallStaticMethod<MObject*, void*, void*, const Guid*>(ScriptingObjectSetInternalValuesPtr, klass->_handle, unmanagedPtr, id);
|
||||||
|
}
|
||||||
|
|
||||||
#elif DOTNET_HOST_MONO
|
#elif DOTNET_HOST_MONO
|
||||||
|
|
||||||
#ifdef USE_MONO_AOT_MODULE
|
#ifdef USE_MONO_AOT_MODULE
|
||||||
|
|||||||
@@ -2127,6 +2127,44 @@ const Array<MObject*>& MProperty::GetAttributes() const
|
|||||||
return _attributes;
|
return _attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCore::ScriptingObject::SetInternalValues(MClass* klass, MObject* object, void* unmanagedPtr, const Guid* id)
|
||||||
|
{
|
||||||
|
// Set handle to unmanaged object
|
||||||
|
const MField* monoUnmanagedPtrField = klass->GetField("__unmanagedPtr");
|
||||||
|
if (monoUnmanagedPtrField)
|
||||||
|
{
|
||||||
|
const void* param = unmanagedPtr;
|
||||||
|
monoUnmanagedPtrField->SetValue(managedInstance, ¶m);
|
||||||
|
}
|
||||||
|
if (id != nullptr)
|
||||||
|
{
|
||||||
|
// Set object id
|
||||||
|
const MField* monoIdField = klass->GetField("__internalId");
|
||||||
|
if (monoIdField)
|
||||||
|
{
|
||||||
|
monoIdField->SetValue(managedInstance, (void*)id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MObject* MCore::ScriptingObject::CreateScriptingObject(MClass* klass, void* unmanagedPtr, const Guid* id)
|
||||||
|
{
|
||||||
|
// Ensure to have managed domain attached (this can be called from custom native thread, eg. content loader)
|
||||||
|
MCore::Thread::Attach();
|
||||||
|
|
||||||
|
// Allocate managed instance
|
||||||
|
MObject* managedInstance = MCore::Object::New(klass);
|
||||||
|
if (managedInstance)
|
||||||
|
{
|
||||||
|
// Set unmanaged object handle and id
|
||||||
|
MCore::ScriptingObject::SetInternalValues(klass, managedInstance, unmanagedPtr, _id);
|
||||||
|
|
||||||
|
// Initialize managed instance (calls constructor)
|
||||||
|
MCore::Object::Init(managedInstance);
|
||||||
|
}
|
||||||
|
return managedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if USE_MONO && PLATFORM_WIN32 && !USE_MONO_DYNAMIC_LIB
|
#if USE_MONO && PLATFORM_WIN32 && !USE_MONO_DYNAMIC_LIB
|
||||||
|
|||||||
@@ -565,4 +565,13 @@ const Array<MObject*>& MProperty::GetAttributes() const
|
|||||||
return _attributes;
|
return _attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCore::ScriptingObject::SetInternalValues(MClass* klass, MObject* object, void* unmanagedPtr, const Guid* id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MObject* MCore::ScriptingObject::CreateScriptingObject(MClass* klass, void* unmanagedPtr, const Guid* id)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -180,10 +180,14 @@ ScriptingObject* ScriptingObject::ToNative(MObject* obj)
|
|||||||
#if USE_CSHARP
|
#if USE_CSHARP
|
||||||
if (obj)
|
if (obj)
|
||||||
{
|
{
|
||||||
// TODO: cache the field offset from object and read directly from object pointer
|
#if USE_MONO
|
||||||
const auto ptrField = MCore::Object::GetClass(obj)->GetField(ScriptingObject_unmanagedPtr);
|
const auto ptrField = MCore::Object::GetClass(obj)->GetField(ScriptingObject_unmanagedPtr);
|
||||||
CHECK_RETURN(ptrField, nullptr);
|
CHECK_RETURN(ptrField, nullptr);
|
||||||
ptrField->GetValue(obj, &ptr);
|
ptrField->GetValue(obj, &ptr);
|
||||||
|
#else
|
||||||
|
static const MField* ptrField = MCore::Object::GetClass(obj)->GetField(ScriptingObject_unmanagedPtr);
|
||||||
|
ptrField->GetValueReference(obj, &ptr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return ptr;
|
return ptr;
|
||||||
@@ -274,12 +278,7 @@ bool ScriptingObject::CreateManaged()
|
|||||||
if (const auto monoClass = GetClass())
|
if (const auto monoClass = GetClass())
|
||||||
{
|
{
|
||||||
// Reset managed to unmanaged pointer
|
// Reset managed to unmanaged pointer
|
||||||
const MField* monoUnmanagedPtrField = monoClass->GetField(ScriptingObject_unmanagedPtr);
|
MCore::ScriptingObject::SetInternalValues(monoClass, managedInstance, nullptr, nullptr);
|
||||||
if (monoUnmanagedPtrField)
|
|
||||||
{
|
|
||||||
void* param = nullptr;
|
|
||||||
monoUnmanagedPtrField->SetValue(managedInstance, ¶m);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
MCore::GCHandle::Free(handle);
|
MCore::GCHandle::Free(handle);
|
||||||
return true;
|
return true;
|
||||||
@@ -305,34 +304,12 @@ MObject* ScriptingObject::CreateManagedInternal()
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure to have managed domain attached (this can be called from custom native thread, eg. content loader)
|
MObject* managedInstance = MCore::ScriptingObject::CreateScriptingObject(monoClass, this, &_id);
|
||||||
MCore::Thread::Attach();
|
|
||||||
|
|
||||||
// Allocate managed instance
|
|
||||||
MObject* managedInstance = MCore::Object::New(monoClass);
|
|
||||||
if (managedInstance == nullptr)
|
if (managedInstance == nullptr)
|
||||||
{
|
{
|
||||||
LOG(Warning, "Failed to create new instance of the object of type {0}", String(monoClass->GetFullName()));
|
LOG(Warning, "Failed to create new instance of the object of type {0}", String(monoClass->GetFullName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set handle to unmanaged object
|
|
||||||
const MField* monoUnmanagedPtrField = monoClass->GetField(ScriptingObject_unmanagedPtr);
|
|
||||||
if (monoUnmanagedPtrField)
|
|
||||||
{
|
|
||||||
const void* value = this;
|
|
||||||
monoUnmanagedPtrField->SetValue(managedInstance, &value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set object id
|
|
||||||
const MField* monoIdField = monoClass->GetField(ScriptingObject_id);
|
|
||||||
if (monoIdField)
|
|
||||||
{
|
|
||||||
monoIdField->SetValue(managedInstance, (void*)&_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize managed instance (calls constructor)
|
|
||||||
MCore::Object::Init(managedInstance);
|
|
||||||
|
|
||||||
return managedInstance;
|
return managedInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,12 +326,7 @@ void ScriptingObject::DestroyManaged()
|
|||||||
{
|
{
|
||||||
if (const auto monoClass = GetClass())
|
if (const auto monoClass = GetClass())
|
||||||
{
|
{
|
||||||
const MField* monoUnmanagedPtrField = monoClass->GetField(ScriptingObject_unmanagedPtr);
|
MCore::ScriptingObject::SetInternalValues(monoClass, managedInstance, nullptr, nullptr);
|
||||||
if (monoUnmanagedPtrField)
|
|
||||||
{
|
|
||||||
void* param = nullptr;
|
|
||||||
monoUnmanagedPtrField->SetValue(managedInstance, ¶m);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,12 +450,7 @@ bool ManagedScriptingObject::CreateManaged()
|
|||||||
if (const auto monoClass = GetClass())
|
if (const auto monoClass = GetClass())
|
||||||
{
|
{
|
||||||
// Reset managed to unmanaged pointer
|
// Reset managed to unmanaged pointer
|
||||||
const MField* monoUnmanagedPtrField = monoClass->GetField(ScriptingObject_unmanagedPtr);
|
MCore::ScriptingObject::SetInternalValues(monoClass, managedInstance, nullptr, nullptr);
|
||||||
if (monoUnmanagedPtrField)
|
|
||||||
{
|
|
||||||
void* param = nullptr;
|
|
||||||
monoUnmanagedPtrField->SetValue(managedInstance, ¶m);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
MCore::GCHandle::Free(handle);
|
MCore::GCHandle::Free(handle);
|
||||||
return true;
|
return true;
|
||||||
@@ -605,10 +572,8 @@ DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_Create2(MString* typeNameObj)
|
|||||||
return managedInstance;
|
return managedInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MObject* managedInstance)
|
DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MObject* managedInstance, MClass* typeClass)
|
||||||
{
|
{
|
||||||
MClass* typeClass = MCore::Object::GetClass(managedInstance);
|
|
||||||
|
|
||||||
// Get the assembly with that class
|
// Get the assembly with that class
|
||||||
auto module = ManagedBinaryModule::FindModule(typeClass);
|
auto module = ManagedBinaryModule::FindModule(typeClass);
|
||||||
if (module == nullptr)
|
if (module == nullptr)
|
||||||
@@ -645,22 +610,8 @@ DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MObject* manage
|
|||||||
}
|
}
|
||||||
|
|
||||||
MClass* monoClass = obj->GetClass();
|
MClass* monoClass = obj->GetClass();
|
||||||
|
const Guid id = obj->GetID();
|
||||||
// Set handle to unmanaged object
|
MCore::ScriptingObject::SetInternalValues(monoClass, managedInstance, obj, &id);
|
||||||
const MField* monoUnmanagedPtrField = monoClass->GetField(ScriptingObject_unmanagedPtr);
|
|
||||||
if (monoUnmanagedPtrField)
|
|
||||||
{
|
|
||||||
const void* value = obj;
|
|
||||||
monoUnmanagedPtrField->SetValue(managedInstance, &value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set object id
|
|
||||||
const MField* monoIdField = monoClass->GetField(ScriptingObject_id);
|
|
||||||
if (monoIdField)
|
|
||||||
{
|
|
||||||
const Guid id = obj->GetID();
|
|
||||||
monoIdField->SetValue(managedInstance, (void*)&id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register object
|
// Register object
|
||||||
if (!obj->IsRegistered())
|
if (!obj->IsRegistered())
|
||||||
|
|||||||
@@ -68,26 +68,12 @@ namespace FlaxEngine.GUI
|
|||||||
var parentWin = target.Root;
|
var parentWin = target.Root;
|
||||||
if (parentWin == null)
|
if (parentWin == null)
|
||||||
return;
|
return;
|
||||||
float dpiScale = target.RootWindow.DpiScale;
|
var dpiScale = target.RootWindow.DpiScale;
|
||||||
var dpiSize = Size * dpiScale;
|
var dpiSize = Size * dpiScale;
|
||||||
var locationWS = target.PointToWindow(location);
|
var locationWS = target.PointToWindow(location);
|
||||||
var locationSS = parentWin.PointToScreen(locationWS);
|
var locationSS = parentWin.PointToScreen(locationWS);
|
||||||
var monitorBounds = Platform.GetMonitorBounds(locationSS);
|
|
||||||
var rightBottomMonitorBounds = monitorBounds.BottomRight;
|
|
||||||
var rightBottomLocationSS = locationSS + dpiSize;
|
|
||||||
|
|
||||||
// Prioritize tooltip placement within parent window, fall back to virtual desktop
|
|
||||||
if (rightBottomMonitorBounds.Y < rightBottomLocationSS.Y)
|
|
||||||
{
|
|
||||||
// Direction: up
|
|
||||||
locationSS.Y -= dpiSize.Y;
|
|
||||||
}
|
|
||||||
if (rightBottomMonitorBounds.X < rightBottomLocationSS.X)
|
|
||||||
{
|
|
||||||
// Direction: left
|
|
||||||
locationSS.X -= dpiSize.X;
|
|
||||||
}
|
|
||||||
_showTarget = target;
|
_showTarget = target;
|
||||||
|
WrapPosition(ref locationSS);
|
||||||
|
|
||||||
// Create window
|
// Create window
|
||||||
var desc = CreateWindowSettings.Default;
|
var desc = CreateWindowSettings.Default;
|
||||||
@@ -106,6 +92,7 @@ namespace FlaxEngine.GUI
|
|||||||
desc.IsTopmost = true;
|
desc.IsTopmost = true;
|
||||||
desc.IsRegularWindow = false;
|
desc.IsRegularWindow = false;
|
||||||
desc.HasSizingFrame = false;
|
desc.HasSizingFrame = false;
|
||||||
|
desc.ShowAfterFirstPaint = true;
|
||||||
_window = Platform.CreateWindow(ref desc);
|
_window = Platform.CreateWindow(ref desc);
|
||||||
if (_window == null)
|
if (_window == null)
|
||||||
throw new InvalidOperationException("Failed to create tooltip window.");
|
throw new InvalidOperationException("Failed to create tooltip window.");
|
||||||
@@ -192,11 +179,37 @@ namespace FlaxEngine.GUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void WrapPosition(ref Float2 locationSS, float flipOffset = 0.0f)
|
||||||
|
{
|
||||||
|
// Calculate popup direction
|
||||||
|
var dpiScale = _showTarget.RootWindow.DpiScale;
|
||||||
|
var dpiSize = Size * dpiScale;
|
||||||
|
var monitorBounds = Platform.GetMonitorBounds(locationSS);
|
||||||
|
var rightBottomMonitorBounds = monitorBounds.BottomRight;
|
||||||
|
var rightBottomLocationSS = locationSS + dpiSize;
|
||||||
|
|
||||||
|
// Prioritize tooltip placement within parent window, fall back to virtual desktop
|
||||||
|
if (rightBottomMonitorBounds.Y < rightBottomLocationSS.Y)
|
||||||
|
{
|
||||||
|
// Direction: up
|
||||||
|
locationSS.Y -= dpiSize.Y + flipOffset;
|
||||||
|
}
|
||||||
|
if (rightBottomMonitorBounds.X < rightBottomLocationSS.X)
|
||||||
|
{
|
||||||
|
// Direction: left
|
||||||
|
locationSS.X -= dpiSize.X + flipOffset * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Update(float deltaTime)
|
public override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
// Auto hide if mouse leaves control area
|
// Move window with mouse location
|
||||||
var mousePos = Input.MouseScreenPosition;
|
var mousePos = Input.MouseScreenPosition;
|
||||||
|
WrapPosition(ref mousePos, 10);
|
||||||
|
_window.Position = mousePos + new Float2(15, 10);
|
||||||
|
|
||||||
|
// Auto hide if mouse leaves control area
|
||||||
var location = _showTarget.PointFromScreen(mousePos);
|
var location = _showTarget.PointFromScreen(mousePos);
|
||||||
if (!_showTarget.OnTestTooltipOverControl(ref location))
|
if (!_showTarget.OnTestTooltipOverControl(ref location))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user