Merge branch 'master' into master
This commit is contained in:
@@ -72,11 +72,9 @@ namespace FlaxEditor.Content
|
||||
/// <param name="materialItem">The material item to use as a base material.</param>
|
||||
public static void CreateMaterialInstance(BinaryAssetItem materialItem)
|
||||
{
|
||||
if (materialItem == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
var materialInstanceName = materialItem.ShortName + " Instance";
|
||||
var materialInstanceProxy = Editor.Instance.ContentDatabase.GetProxy<MaterialInstance>();
|
||||
Editor.Instance.Windows.ContentWin.NewItem(materialInstanceProxy, null, item => OnMaterialInstanceCreated(item, materialItem));
|
||||
Editor.Instance.Windows.ContentWin.NewItem(materialInstanceProxy, null, item => OnMaterialInstanceCreated(item, materialItem), materialInstanceName);
|
||||
}
|
||||
|
||||
private static void OnMaterialInstanceCreated(ContentItem item, BinaryAssetItem materialItem)
|
||||
|
||||
@@ -145,7 +145,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
else
|
||||
{
|
||||
// No localization so initialize with empty table
|
||||
var path = Path.Combine(Path.Combine(Path.GetDirectoryName(GameSettings.Load().Localization.Path), "Localization", culture.Name + ".json"));
|
||||
var folder = Path.Combine(Path.GetDirectoryName(GameSettings.Load().Localization.Path), "Localization");
|
||||
if (!Directory.Exists(folder))
|
||||
Directory.CreateDirectory(folder);
|
||||
var path = Path.Combine(Path.Combine(folder, culture.Name + ".json"));
|
||||
var table = FlaxEngine.Content.CreateVirtualAsset<LocalizedStringTable>();
|
||||
table.Locale = culture.Name;
|
||||
if (!table.Save(path))
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
_size.IntValue.MinValue = 0;
|
||||
_size.IntValue.MaxValue = ushort.MaxValue;
|
||||
_size.IntValue.Value = size;
|
||||
_size.IntValue.ValueChanged += OnSizeChanged;
|
||||
_size.IntValue.EditEnd += OnSizeChanged;
|
||||
}
|
||||
|
||||
// Elements
|
||||
|
||||
@@ -190,7 +190,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
_size.IntValue.MinValue = 0;
|
||||
_size.IntValue.MaxValue = _notNullItems ? size : ushort.MaxValue;
|
||||
_size.IntValue.Value = size;
|
||||
_size.IntValue.ValueChanged += OnSizeChanged;
|
||||
_size.IntValue.EditEnd += OnSizeChanged;
|
||||
}
|
||||
|
||||
// Elements
|
||||
|
||||
@@ -6,7 +6,7 @@ using FlaxEngine.GUI;
|
||||
namespace FlaxEditor.CustomEditors.Elements
|
||||
{
|
||||
/// <summary>
|
||||
/// The combobx element.
|
||||
/// The combobox element.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.CustomEditors.LayoutElement" />
|
||||
public class ComboBoxElement : LayoutElement
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (this[i] == referenceSceneObject)
|
||||
if ((SceneObject)this[i] == referenceSceneObject)
|
||||
continue;
|
||||
|
||||
if (this[i] == null || (this[i] is SceneObject valueSceneObject && valueSceneObject && valueSceneObject.PrefabObjectID != referenceSceneObject.PrefabObjectID))
|
||||
|
||||
+73
-48
@@ -9,7 +9,6 @@ using FlaxEditor.Content;
|
||||
using FlaxEditor.Content.Import;
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEditor.Content.Thumbnails;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.Modules;
|
||||
using FlaxEditor.Modules.SourceCodeEditing;
|
||||
using FlaxEditor.Options;
|
||||
@@ -307,6 +306,7 @@ namespace FlaxEditor
|
||||
_areModulesInited = true;
|
||||
|
||||
// Preload initial scene asset
|
||||
try
|
||||
{
|
||||
var startupSceneMode = Options.Options.General.StartupSceneMode;
|
||||
if (startupSceneMode == GeneralOptions.StartupSceneModes.LastOpened && !ProjectCache.HasCustomData(ProjectDataLastScene))
|
||||
@@ -323,12 +323,23 @@ namespace FlaxEditor
|
||||
}
|
||||
case GeneralOptions.StartupSceneModes.LastOpened:
|
||||
{
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastScene, out var lastSceneIdName) && Guid.TryParse(lastSceneIdName, out var lastSceneId))
|
||||
Internal_LoadAsset(ref lastSceneId);
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastScene, out var lastSceneIdName))
|
||||
{
|
||||
var lastScenes = JsonSerializer.Deserialize<Guid[]>(lastSceneIdName);
|
||||
foreach (var scene in lastScenes)
|
||||
{
|
||||
var lastScene = scene;
|
||||
Internal_LoadAsset(ref lastScene);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignore errors
|
||||
}
|
||||
|
||||
InitializationStart?.Invoke();
|
||||
|
||||
@@ -401,58 +412,69 @@ namespace FlaxEditor
|
||||
}
|
||||
|
||||
// Load scene
|
||||
|
||||
// scene cmd line argument
|
||||
var scene = ContentDatabase.Find(_startupSceneCmdLine);
|
||||
if (scene is SceneItem)
|
||||
try
|
||||
{
|
||||
Editor.Log("Loading scene specified in command line");
|
||||
Scene.OpenScene(_startupSceneCmdLine);
|
||||
return;
|
||||
}
|
||||
|
||||
// if no scene cmd line argument is provided
|
||||
var startupSceneMode = Options.Options.General.StartupSceneMode;
|
||||
if (startupSceneMode == GeneralOptions.StartupSceneModes.LastOpened && !ProjectCache.HasCustomData(ProjectDataLastScene))
|
||||
{
|
||||
// Fallback to default project scene if nothing saved in the cache
|
||||
startupSceneMode = GeneralOptions.StartupSceneModes.ProjectDefault;
|
||||
}
|
||||
switch (startupSceneMode)
|
||||
{
|
||||
case GeneralOptions.StartupSceneModes.ProjectDefault:
|
||||
{
|
||||
if (string.IsNullOrEmpty(GameProject.DefaultScene))
|
||||
break;
|
||||
JsonSerializer.ParseID(GameProject.DefaultScene, out var defaultSceneId);
|
||||
var defaultScene = ContentDatabase.Find(defaultSceneId);
|
||||
if (defaultScene is SceneItem)
|
||||
// Scene cmd line argument
|
||||
var scene = ContentDatabase.Find(_startupSceneCmdLine);
|
||||
if (scene is SceneItem)
|
||||
{
|
||||
Editor.Log("Loading default project scene");
|
||||
Scene.OpenScene(defaultSceneId);
|
||||
|
||||
// Use spawn point
|
||||
Windows.EditWin.Viewport.ViewRay = GameProject.DefaultSceneSpawn;
|
||||
Editor.Log("Loading scene specified in command line");
|
||||
Scene.OpenScene(_startupSceneCmdLine);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GeneralOptions.StartupSceneModes.LastOpened:
|
||||
{
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastScene, out var lastSceneIdName) && Guid.TryParse(lastSceneIdName, out var lastSceneId))
|
||||
var startupSceneMode = Options.Options.General.StartupSceneMode;
|
||||
if (startupSceneMode == GeneralOptions.StartupSceneModes.LastOpened && !ProjectCache.HasCustomData(ProjectDataLastScene))
|
||||
{
|
||||
var lastScene = ContentDatabase.Find(lastSceneId);
|
||||
if (lastScene is SceneItem)
|
||||
// Fallback to default project scene if nothing saved in the cache
|
||||
startupSceneMode = GeneralOptions.StartupSceneModes.ProjectDefault;
|
||||
}
|
||||
switch (startupSceneMode)
|
||||
{
|
||||
case GeneralOptions.StartupSceneModes.ProjectDefault:
|
||||
{
|
||||
if (string.IsNullOrEmpty(GameProject.DefaultScene))
|
||||
break;
|
||||
JsonSerializer.ParseID(GameProject.DefaultScene, out var defaultSceneId);
|
||||
var defaultScene = ContentDatabase.Find(defaultSceneId);
|
||||
if (defaultScene is SceneItem)
|
||||
{
|
||||
Editor.Log("Loading last opened scene");
|
||||
Scene.OpenScene(lastSceneId);
|
||||
Editor.Log("Loading default project scene");
|
||||
Scene.OpenScene(defaultSceneId);
|
||||
|
||||
// Use spawn point
|
||||
Windows.EditWin.Viewport.ViewRay = GameProject.DefaultSceneSpawn;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GeneralOptions.StartupSceneModes.LastOpened:
|
||||
{
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastScene, out var lastSceneIdName))
|
||||
{
|
||||
var lastScenes = JsonSerializer.Deserialize<Guid[]>(lastSceneIdName);
|
||||
foreach (var sceneId in lastScenes)
|
||||
{
|
||||
var lastScene = ContentDatabase.Find(sceneId);
|
||||
if (!(lastScene is SceneItem))
|
||||
continue;
|
||||
|
||||
Editor.Log($"Loading last opened scene: {lastScene.ShortName}");
|
||||
if (sceneId == lastScenes[0])
|
||||
Scene.OpenScene(sceneId);
|
||||
else
|
||||
Level.LoadSceneAsync(sceneId);
|
||||
}
|
||||
|
||||
// Restore view
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastSceneSpawn, out var lastSceneSpawnName))
|
||||
Windows.EditWin.Viewport.ViewRay = JsonSerializer.Deserialize<Ray>(lastSceneSpawnName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignore errors
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,8 +603,8 @@ namespace FlaxEditor
|
||||
UI.UpdateStatusBar();
|
||||
}
|
||||
|
||||
if (UI?.StatusBar?.Text != null && !UI.StatusBar.Text.Contains("Auto") &&
|
||||
_saveNowButton != null && _cancelSaveButton != null &&
|
||||
if (UI?.StatusBar?.Text != null && !UI.StatusBar.Text.Contains("Auto") &&
|
||||
_saveNowButton != null && _cancelSaveButton != null &&
|
||||
(_saveNowButton.Visible || _cancelSaveButton.Visible))
|
||||
{
|
||||
_saveNowButton.Visible = false;
|
||||
@@ -662,11 +684,14 @@ namespace FlaxEditor
|
||||
// Start exit
|
||||
StateMachine.GoToState<ClosingState>();
|
||||
|
||||
// Cache last opened scene
|
||||
// Cache last opened scenes
|
||||
{
|
||||
var lastSceneId = Level.ScenesCount > 0 ? Level.Scenes[0].ID : Guid.Empty;
|
||||
var lastScenes = Level.Scenes;
|
||||
var lastSceneIds = new Guid[lastScenes.Length];
|
||||
for (int i = 0; i < lastScenes.Length; i++)
|
||||
lastSceneIds[i] = lastScenes[i].ID;
|
||||
var lastSceneSpawn = Windows.EditWin.Viewport.ViewRay;
|
||||
ProjectCache.SetCustomData(ProjectDataLastScene, lastSceneId.ToString());
|
||||
ProjectCache.SetCustomData(ProjectDataLastScene, JsonSerializer.Serialize(lastSceneIds));
|
||||
ProjectCache.SetCustomData(ProjectDataLastSceneSpawn, JsonSerializer.Serialize(lastSceneSpawn));
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
continue;
|
||||
|
||||
// Prevent from adding the same track twice
|
||||
if (SubTracks.Any(x => x is IObjectTrack y && y.Object == script))
|
||||
if (SubTracks.Any(x => x is IObjectTrack y && y.Object as SceneObject == script))
|
||||
continue;
|
||||
|
||||
var name = Utilities.Utils.GetPropertyNameUI(script.GetType().Name);
|
||||
|
||||
@@ -661,17 +661,20 @@ namespace FlaxEditor.GUI.Tree
|
||||
// Draw drag and drop effect
|
||||
if (IsDragOver && _tree.DraggedOverNode == this)
|
||||
{
|
||||
Color dragOverColor = style.BackgroundSelected * 0.6f;
|
||||
Color dragOverColor = style.BackgroundSelected;
|
||||
Rectangle rect;
|
||||
switch (_dragOverMode)
|
||||
{
|
||||
case DragItemPositioning.At:
|
||||
dragOverColor *= 0.6f;
|
||||
rect = textRect;
|
||||
break;
|
||||
case DragItemPositioning.Above:
|
||||
dragOverColor *= 1.2f;
|
||||
rect = new Rectangle(textRect.X, textRect.Top - DefaultDragInsertPositionMargin - DefaultNodeOffsetY - _margin.Top, textRect.Width, DefaultDragInsertPositionMargin * 2.0f);
|
||||
break;
|
||||
case DragItemPositioning.Below:
|
||||
dragOverColor *= 1.2f;
|
||||
rect = new Rectangle(textRect.X, textRect.Bottom + _margin.Bottom - DefaultDragInsertPositionMargin, textRect.Width, DefaultDragInsertPositionMargin * 2.0f);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -655,7 +655,7 @@ namespace FlaxEditor.Modules
|
||||
var children = folder.Children.ToArray();
|
||||
for (int i = 0; i < children.Length; i++)
|
||||
{
|
||||
Delete(children[0]);
|
||||
Delete(children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -315,6 +315,42 @@ namespace FlaxEditor.Modules
|
||||
Editor.StateMachine.ChangingScenesState.UnloadScene(Level.Scenes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes all of the scenes except for the specified scene (async).
|
||||
/// </summary>
|
||||
/// <param name="scene">The scene to not close.</param>
|
||||
public void CloseAllScenesExcept(Scene scene)
|
||||
{
|
||||
// Check if cannot change scene now
|
||||
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
||||
return;
|
||||
|
||||
var scenes = new List<Scene>();
|
||||
foreach (var s in Level.Scenes)
|
||||
{
|
||||
if (s == scene)
|
||||
continue;
|
||||
scenes.Add(s);
|
||||
}
|
||||
|
||||
// In play-mode Editor mocks the level streaming script
|
||||
if (Editor.IsPlayMode)
|
||||
{
|
||||
foreach (var s in scenes)
|
||||
{
|
||||
Level.UnloadSceneAsync(s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure to save all pending changes
|
||||
if (CheckSaveBeforeClose())
|
||||
return;
|
||||
|
||||
// Unload scenes
|
||||
Editor.StateMachine.ChangingScenesState.UnloadScene(scenes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show save before scene load/unload action.
|
||||
/// </summary>
|
||||
|
||||
@@ -77,6 +77,8 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
}
|
||||
contextMenu.AddButton("Save scene", OnSave).LinkTooltip("Saves this scene.").Enabled = IsEdited && !Editor.IsPlayMode;
|
||||
contextMenu.AddButton("Unload scene", OnUnload).LinkTooltip("Unloads this scene.").Enabled = Editor.Instance.StateMachine.CurrentState.CanChangeScene;
|
||||
if (Level.ScenesCount > 1)
|
||||
contextMenu.AddButton("Unload all but this scene", OnUnloadAllButSelectedScene).LinkTooltip("Unloads all of the active scenes except for the selected scene.").Enabled = Editor.Instance.StateMachine.CurrentState.CanChangeScene;
|
||||
|
||||
base.OnContextMenu(contextMenu);
|
||||
}
|
||||
@@ -95,5 +97,10 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
{
|
||||
Editor.Instance.Scene.CloseScene(Scene);
|
||||
}
|
||||
|
||||
private void OnUnloadAllButSelectedScene()
|
||||
{
|
||||
Editor.Instance.Scene.CloseAllScenesExcept(Scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Description = desc,
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
AlternativeTitles = altTitles,
|
||||
Size = new Float2(140, 40),
|
||||
Size = new Float2(150, 40),
|
||||
DefaultType = new ScriptType(inputType),
|
||||
ConnectionsHints = hints,
|
||||
IndependentBoxes = new[] { 0, 1 },
|
||||
|
||||
@@ -730,12 +730,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 0),
|
||||
|
||||
NodeElementArchetype.Factory.Text(0, 0, "Min", 30.0f, 18.0f),
|
||||
NodeElementArchetype.Factory.Float(30, 0, 0),
|
||||
|
||||
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY, "Max", 30.0f, 18.0f),
|
||||
NodeElementArchetype.Factory.Float(30, Surface.Constants.LayoutOffsetY, 1),
|
||||
NodeElementArchetype.Factory.Input(0, "Min", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Max", true, typeof(float), 2, 1),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
@@ -753,14 +749,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float2), 0),
|
||||
|
||||
NodeElementArchetype.Factory.Text(0, 0, "Min", 30.0f, 18.0f),
|
||||
NodeElementArchetype.Factory.Vector_X(30, 0, 0),
|
||||
NodeElementArchetype.Factory.Vector_Y(83, 0, 0),
|
||||
|
||||
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY, "Max", 30.0f, 18.0f),
|
||||
NodeElementArchetype.Factory.Vector_X(30, Surface.Constants.LayoutOffsetY, 1),
|
||||
NodeElementArchetype.Factory.Vector_Y(83, Surface.Constants.LayoutOffsetY, 1),
|
||||
NodeElementArchetype.Factory.Input(0, "Min", true, typeof(Float2), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Max", true, typeof(Float2), 2, 1),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
@@ -778,16 +768,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float3), 0),
|
||||
|
||||
NodeElementArchetype.Factory.Text(0, 0, "Min", 30.0f, 18.0f),
|
||||
NodeElementArchetype.Factory.Vector_X(30, 0, 0),
|
||||
NodeElementArchetype.Factory.Vector_Y(83, 0, 0),
|
||||
NodeElementArchetype.Factory.Vector_Z(136, 0, 0),
|
||||
|
||||
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY, "Max", 30.0f, 18.0f),
|
||||
NodeElementArchetype.Factory.Vector_X(30, Surface.Constants.LayoutOffsetY, 1),
|
||||
NodeElementArchetype.Factory.Vector_Y(83, Surface.Constants.LayoutOffsetY, 1),
|
||||
NodeElementArchetype.Factory.Vector_Z(136, Surface.Constants.LayoutOffsetY, 1),
|
||||
NodeElementArchetype.Factory.Input(0, "Min", true, typeof(Float3), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Max", true, typeof(Float3), 2, 1),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
@@ -805,18 +787,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float4), 0),
|
||||
|
||||
NodeElementArchetype.Factory.Text(0, 0, "Min", 30.0f, 18.0f),
|
||||
NodeElementArchetype.Factory.Vector_X(30, 0, 0),
|
||||
NodeElementArchetype.Factory.Vector_Y(83, 0, 0),
|
||||
NodeElementArchetype.Factory.Vector_Z(136, 0, 0),
|
||||
NodeElementArchetype.Factory.Vector_W(189, 0, 0),
|
||||
|
||||
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY, "Max", 30.0f, 18.0f),
|
||||
NodeElementArchetype.Factory.Vector_X(30, Surface.Constants.LayoutOffsetY, 1),
|
||||
NodeElementArchetype.Factory.Vector_Y(83, Surface.Constants.LayoutOffsetY, 1),
|
||||
NodeElementArchetype.Factory.Vector_Z(136, Surface.Constants.LayoutOffsetY, 1),
|
||||
NodeElementArchetype.Factory.Vector_W(189, Surface.Constants.LayoutOffsetY, 1),
|
||||
NodeElementArchetype.Factory.Input(0, "Min", true, typeof(Float4), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Max", true, typeof(Float4), 2, 1),
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ AssetReference<MaterialInstance> CustomTextureMaterial;
|
||||
ModelInstanceEntries InstanceBuffers[static_cast<int32>(IconTypes::MAX)];
|
||||
Dictionary<ScriptingTypeHandle, IconTypes> ActorTypeToIconType;
|
||||
Dictionary<ScriptingTypeHandle, AssetReference<Texture>> ActorTypeToTexture;
|
||||
Dictionary<ScriptingObjectReference<Actor>, AssetReference<Texture>> ActorToTexture;
|
||||
Dictionary<AssetReference<Texture>, AssetReference<MaterialBase>> TextureToMaterial;
|
||||
|
||||
class ViewportIconsRendererService : public EngineService
|
||||
{
|
||||
@@ -103,10 +105,18 @@ void ViewportIconsRenderer::AddActor(Actor* actor)
|
||||
actor->GetSceneRendering()->AddViewportIcon(actor);
|
||||
}
|
||||
|
||||
void ViewportIconsRenderer::AddActorWithTexture(Actor* actor, Texture* iconTexture)
|
||||
{
|
||||
CHECK(actor && actor->GetScene() && iconTexture);
|
||||
ActorToTexture[actor] = iconTexture;
|
||||
actor->GetSceneRendering()->AddViewportIcon(actor);
|
||||
}
|
||||
|
||||
void ViewportIconsRenderer::RemoveActor(Actor* actor)
|
||||
{
|
||||
CHECK(actor && actor->GetScene());
|
||||
actor->GetSceneRendering()->RemoveViewportIcon(actor);
|
||||
ActorToTexture.Remove(actor);
|
||||
}
|
||||
|
||||
void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene* scene, Mesh::DrawInfo& draw)
|
||||
@@ -128,7 +138,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene
|
||||
ScriptingTypeHandle typeHandle = icon->GetTypeHandle();
|
||||
draw.Buffer = nullptr;
|
||||
|
||||
if (ActorTypeToTexture.TryGet(typeHandle, texture))
|
||||
if (ActorToTexture.TryGet(icon, texture) || ActorTypeToTexture.TryGet(typeHandle, texture))
|
||||
{
|
||||
// Use custom texture
|
||||
draw.Buffer = &InstanceBuffers[static_cast<int32>(IconTypes::CustomTexture)];
|
||||
@@ -137,9 +147,20 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene
|
||||
// Lazy-init (use in-built icon material with custom texture)
|
||||
draw.Buffer->Setup(1);
|
||||
draw.Buffer->At(0).ReceiveDecals = false;
|
||||
draw.Buffer->At(0).Material = InstanceBuffers[0][0].Material->CreateVirtualInstance();
|
||||
draw.Buffer->At(0).ShadowsMode = ShadowsCastingMode::None;
|
||||
}
|
||||
draw.Buffer->At(0).Material->SetParameterValue(TEXT("Image"), Variant(texture));
|
||||
|
||||
AssetReference<MaterialBase> material;
|
||||
|
||||
if (!TextureToMaterial.TryGet(texture, material))
|
||||
{
|
||||
// Create custom material per custom texture
|
||||
TextureToMaterial[texture] = InstanceBuffers[0][0].Material->CreateVirtualInstance();
|
||||
TextureToMaterial[texture]->SetParameterValue(TEXT("Image"), Variant(texture));
|
||||
material = TextureToMaterial[texture];
|
||||
}
|
||||
|
||||
draw.Buffer->At(0).Material = material;
|
||||
}
|
||||
else if (ActorTypeToIconType.TryGet(typeHandle, iconType))
|
||||
{
|
||||
@@ -170,6 +191,8 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
|
||||
Matrix m1, m2, world;
|
||||
BoundingSphere sphere(actor->GetPosition() - renderContext.View.Origin, ICON_RADIUS);
|
||||
IconTypes iconType;
|
||||
AssetReference<Texture> texture;
|
||||
|
||||
if (frustum.Intersects(sphere) && ActorTypeToIconType.TryGet(actor->GetTypeHandle(), iconType))
|
||||
{
|
||||
// Create world matrix
|
||||
@@ -182,7 +205,39 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
|
||||
// Draw icon
|
||||
GeometryDrawStateData drawState;
|
||||
draw.DrawState = &drawState;
|
||||
draw.Buffer = &InstanceBuffers[static_cast<int32>(iconType)];
|
||||
|
||||
// Support custom icons through types, but not onces that were added through actors,
|
||||
// since they cant register while in prefab view anyway
|
||||
if (ActorTypeToTexture.TryGet(actor->GetTypeHandle(), texture))
|
||||
{
|
||||
// Use custom texture
|
||||
draw.Buffer = &InstanceBuffers[static_cast<int32>(IconTypes::CustomTexture)];
|
||||
if (draw.Buffer->Count() == 0)
|
||||
{
|
||||
// Lazy-init (use in-built icon material with custom texture)
|
||||
draw.Buffer->Setup(1);
|
||||
draw.Buffer->At(0).ReceiveDecals = false;
|
||||
draw.Buffer->At(0).ShadowsMode = ShadowsCastingMode::None;
|
||||
}
|
||||
|
||||
AssetReference<MaterialBase> material;
|
||||
|
||||
if (!TextureToMaterial.TryGet(texture, material))
|
||||
{
|
||||
// Create custom material per custom texture
|
||||
TextureToMaterial[texture] = InstanceBuffers[0][0].Material->CreateVirtualInstance();
|
||||
TextureToMaterial[texture]->SetParameterValue(TEXT("Image"), Variant(texture));
|
||||
material = TextureToMaterial[texture];
|
||||
}
|
||||
|
||||
draw.Buffer->At(0).Material = material;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use predefined material
|
||||
draw.Buffer = &InstanceBuffers[static_cast<int32>(iconType)];
|
||||
}
|
||||
|
||||
draw.World = &world;
|
||||
draw.Bounds = sphere;
|
||||
QuadModel->Draw(renderContext, draw);
|
||||
@@ -196,9 +251,10 @@ bool ViewportIconsRendererService::Init()
|
||||
{
|
||||
QuadModel = Content::LoadAsyncInternal<Model>(TEXT("Engine/Models/Quad"));
|
||||
#define INIT(type, path) \
|
||||
InstanceBuffers[static_cast<int32>(IconTypes::type)].Setup(1); \
|
||||
InstanceBuffers[static_cast<int32>(IconTypes::type)][0].ReceiveDecals = false; \
|
||||
InstanceBuffers[static_cast<int32>(IconTypes::type)][0].Material = Content::LoadAsyncInternal<MaterialInstance>(TEXT(path))
|
||||
InstanceBuffers[static_cast<int32>(IconTypes::type)].Setup(1); \
|
||||
InstanceBuffers[static_cast<int32>(IconTypes::type)][0].ReceiveDecals = false; \
|
||||
InstanceBuffers[static_cast<int32>(IconTypes::type)][0].ShadowsMode = ShadowsCastingMode::None; \
|
||||
InstanceBuffers[static_cast<int32>(IconTypes::type)][0].Material = Content::LoadAsyncInternal<MaterialInstance>(TEXT(path))
|
||||
INIT(PointLight, "Editor/Icons/PointLight");
|
||||
INIT(DirectionalLight, "Editor/Icons/DirectionalLight");
|
||||
INIT(EnvironmentProbe, "Editor/Icons/EnvironmentProbe");
|
||||
@@ -236,4 +292,6 @@ void ViewportIconsRendererService::Dispose()
|
||||
for (int32 i = 0; i < ARRAY_COUNT(InstanceBuffers); i++)
|
||||
InstanceBuffers[i].Release();
|
||||
ActorTypeToIconType.Clear();
|
||||
ActorToTexture.Clear();
|
||||
TextureToMaterial.Clear();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,13 @@ public:
|
||||
/// <param name="actor">The actor to register for icon drawing.</param>
|
||||
API_FUNCTION() static void AddActor(Actor* actor);
|
||||
|
||||
/// <summary>
|
||||
/// Adds actor to the viewport icon rendering.
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor to register for icon drawing.</param>
|
||||
/// <param name="iconTexture">The icon texture to draw.</param>
|
||||
API_FUNCTION() static void AddActorWithTexture(Actor* actor, Texture* iconTexture);
|
||||
|
||||
/// <summary>
|
||||
/// Removes actor from the viewport icon rendering.
|
||||
/// </summary>
|
||||
|
||||
@@ -126,6 +126,10 @@ namespace FlaxEditor.Windows.Assets
|
||||
_presenter.NoSelectionText = "Failed to load asset. See log for more. " + ex.Message.Replace('\n', ' ');
|
||||
}
|
||||
}
|
||||
else if (string.IsNullOrEmpty(dataTypeName))
|
||||
{
|
||||
_presenter.NoSelectionText = "Empty data type.";
|
||||
}
|
||||
else
|
||||
{
|
||||
_presenter.NoSelectionText = string.Format("Missing type '{0}'.", dataTypeName);
|
||||
|
||||
@@ -156,14 +156,14 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
private bool HasEmitter => _track.Asset != null;
|
||||
|
||||
[EditorDisplay("Particle Emitter"), VisibleIf("HasEmitter"), EditorOrder(200), Tooltip("The start frame of the media event.")]
|
||||
[EditorDisplay("Particle Emitter"), VisibleIf(nameof(HasEmitter)), EditorOrder(200), Tooltip("The start frame of the media event.")]
|
||||
public int StartFrame
|
||||
{
|
||||
get => _track.Media.Count > 0 ? _track.TrackMedia.StartFrame : 0;
|
||||
set => _track.TrackMedia.StartFrame = value;
|
||||
}
|
||||
|
||||
[EditorDisplay("Particle Emitter"), Limit(1), VisibleIf("HasEmitter"), EditorOrder(300), Tooltip("The total duration of the media event in the timeline sequence frames amount.")]
|
||||
[EditorDisplay("Particle Emitter"), Limit(1), VisibleIf(nameof(HasEmitter)), EditorOrder(300), Tooltip("The total duration of the media event in the timeline sequence frames amount.")]
|
||||
public int DurationFrames
|
||||
{
|
||||
get => _track.Media.Count > 0 ? _track.TrackMedia.DurationFrames : 0;
|
||||
|
||||
@@ -656,6 +656,11 @@ namespace FlaxEditor.Windows
|
||||
throw new ArgumentNullException(nameof(proxy));
|
||||
|
||||
string name = initialName ?? proxy.NewItemName;
|
||||
|
||||
// If the proxy can not be created in the current folder, then navigate to the content folder
|
||||
if (!proxy.CanCreate(CurrentViewFolder))
|
||||
Navigate(Editor.Instance.ContentDatabase.Game.Content);
|
||||
|
||||
ContentFolder parentFolder = CurrentViewFolder;
|
||||
string parentFolderPath = parentFolder.Path;
|
||||
|
||||
|
||||
@@ -1002,17 +1002,12 @@ Asset* Content::load(const Guid& id, const ScriptingTypeHandle& type, AssetInfo&
|
||||
}
|
||||
|
||||
#if ASSETS_LOADING_EXTRA_VERIFICATION
|
||||
|
||||
// Ensure we have valid asset info
|
||||
ASSERT(assetInfo.TypeName.HasChars() && assetInfo.Path.HasChars());
|
||||
|
||||
// Check if file exists
|
||||
if (!FileSystem::FileExists(assetInfo.Path))
|
||||
{
|
||||
LOG(Error, "Cannot find file '{0}'", assetInfo.Path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Find asset factory based in its type
|
||||
|
||||
@@ -35,6 +35,11 @@ namespace FlaxEngine
|
||||
return null;
|
||||
|
||||
var dataTypeName = DataTypeName;
|
||||
if (string.IsNullOrEmpty(dataTypeName))
|
||||
{
|
||||
Debug.LogError(string.Format("Missing typename of data in Json asset '{0}'.", Path), this);
|
||||
return null;
|
||||
}
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
for (int i = 0; i < assemblies.Length; i++)
|
||||
{
|
||||
|
||||
@@ -379,7 +379,7 @@ public:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actor static fags.
|
||||
/// Gets the actor static flags.
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="NoAnimate, EditorDisplay(\"General\"), EditorOrder(-80), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ActorStaticFlagsEditor\")")
|
||||
FORCE_INLINE StaticFlags GetStaticFlags() const
|
||||
|
||||
@@ -903,12 +903,11 @@ bool LevelImpl::unloadScene(Scene* scene)
|
||||
bool LevelImpl::unloadScenes()
|
||||
{
|
||||
auto scenes = Level::Scenes;
|
||||
for (int32 i = 0; i < scenes.Count(); i++)
|
||||
for (int32 i = scenes.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (unloadScene(scenes[i]))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1210,6 +1209,15 @@ bool LevelImpl::saveScene(Scene* scene, const String& path)
|
||||
|
||||
LOG(Info, "Scene saved! Time {0} ms", Math::CeilToInt((float)(DateTime::NowUTC() - startTime).GetTotalMilliseconds()));
|
||||
|
||||
#if USE_EDITOR
|
||||
// Reload asset at the target location if is loaded
|
||||
Asset* asset = Content::GetAsset(sceneId);
|
||||
if (!asset)
|
||||
asset = Content::GetAsset(path);
|
||||
if (asset)
|
||||
asset->Reload();
|
||||
#endif
|
||||
|
||||
// Fire event
|
||||
CallSceneEvent(SceneEventType::OnSceneSaved, scene, sceneId);
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ Array<Tag> Tags::GetSubTags(Tag parentTag)
|
||||
return subTags;
|
||||
}
|
||||
|
||||
bool Tags::HasTag(const Array<Tag>& list, const Tag& tag)
|
||||
bool Tags::HasTag(const Array<Tag>& list, const Tag tag)
|
||||
{
|
||||
if (tag.Index == 0)
|
||||
return false;
|
||||
@@ -87,7 +87,7 @@ bool Tags::HasTag(const Array<Tag>& list, const Tag& tag)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Tags::HasTagExact(const Array<Tag>& list, const Tag& tag)
|
||||
bool Tags::HasTagExact(const Array<Tag>& list, const Tag tag)
|
||||
{
|
||||
if (tag.Index == 0)
|
||||
return false;
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
/// <param name="list">The tags list to use.</param>
|
||||
/// <param name="tag">The tag to check.</param>
|
||||
/// <returns>True if given tag is contained by the list of tags. Returns false for empty list.</returns>
|
||||
static bool HasTag(const Array<Tag>& list, const Tag& tag);
|
||||
static bool HasTag(const Array<Tag>& list, const Tag tag);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the list of tags contains a given tag (exact match). For example, HasTag({"A.B"}, "A") returns false, for parents check use HasTag.
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
/// <param name="list">The tags list to use.</param>
|
||||
/// <param name="tag">The tag to check.</param>
|
||||
/// <returns>True if given tag is contained by the list of tags. Returns false for empty list.</returns>
|
||||
static bool HasTagExact(const Array<Tag>& list, const Tag& tag);
|
||||
static bool HasTagExact(const Array<Tag>& list, const Tag tag);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the list of tags contains any of the given tags (including parent tags check). For example, HasAny({"A.B", "C"}, {"A"}) returns true, for exact check use HasAnyExact.
|
||||
|
||||
@@ -100,7 +100,7 @@ API_ENUM(Attributes="Flags") enum class StaticFlags
|
||||
Navigation = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// Objects is fully static on the scene.
|
||||
/// Object is fully static in the scene.
|
||||
/// </summary>
|
||||
FullyStatic = Transform | ReflectionProbe | Lightmap | Navigation,
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ REGISTER_JSON_ASSET(LocalizedStringTable, "FlaxEngine.LocalizedStringTable", tru
|
||||
LocalizedStringTable::LocalizedStringTable(const SpawnParams& params, const AssetInfo* info)
|
||||
: JsonAssetBase(params, info)
|
||||
{
|
||||
DataTypeName = TypeName;
|
||||
}
|
||||
|
||||
void LocalizedStringTable::AddString(const StringView& id, const StringView& value)
|
||||
|
||||
@@ -388,33 +388,33 @@ void ParticleEmitterGPUGenerator::ProcessGroupParticles(Box* box, Node* node, Va
|
||||
// Random Float Range
|
||||
case 213:
|
||||
{
|
||||
auto& a = node->Values[0].AsFloat;
|
||||
auto& b = node->Values[1].AsFloat;
|
||||
value = writeLocal(VariantType::Float, String::Format(TEXT("lerp({0}, {1}, RAND)"), a, b), node);
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat();
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat();
|
||||
value = writeLocal(VariantType::Float, String::Format(TEXT("lerp({0}, {1}, RAND)"), a.Value, b.Value), node);
|
||||
break;
|
||||
}
|
||||
// Random Vector2 Range
|
||||
case 214:
|
||||
{
|
||||
auto& a = node->Values[0].AsFloat2();
|
||||
auto& b = node->Values[1].AsFloat2();
|
||||
value = writeLocal(VariantType::Float2, String::Format(TEXT("float2(lerp({0}, {1}, RAND), lerp({2}, {3}, RAND))"), a.X, b.X, a.Y, b.Y), node);
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat2();
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat2();
|
||||
value = writeLocal(VariantType::Float2, String::Format(TEXT("float2(lerp({0}.x, {1}.x, RAND), lerp({0}.y, {1}.y, RAND))"), a.Value, b.Value), node);
|
||||
break;
|
||||
}
|
||||
// Random Vector3 Range
|
||||
case 215:
|
||||
{
|
||||
auto& a = node->Values[0].AsFloat3();
|
||||
auto& b = node->Values[1].AsFloat3();
|
||||
value = writeLocal(VariantType::Float3, String::Format(TEXT("float3(lerp({0}, {1}, RAND), lerp({2}, {3}, RAND), lerp({4}, {5}, RAND))"), a.X, b.X, a.Y, b.Y, a.Z, b.Z), node);
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat3();
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat3();
|
||||
value = writeLocal(VariantType::Float3, String::Format(TEXT("float3(lerp({0}.x, {1}.x, RAND), lerp({0}.y, {1}.y, RAND), lerp({0}.z, {1}.z, RAND))"), a.Value, b.Value), node);
|
||||
break;
|
||||
}
|
||||
// Random Vector4 Range
|
||||
case 216:
|
||||
{
|
||||
auto& a = node->Values[0].AsFloat4();
|
||||
auto& b = node->Values[1].AsFloat4();
|
||||
value = writeLocal(VariantType::Float4, String::Format(TEXT("float4(lerp({0}, {1}, RAND), lerp({2}, {3}, RAND), lerp({4}, {5}, RAND), lerp({6}, {7}, RAND))"), a.X, b.X, a.Y, b.Y, a.Z, b.Z, a.W, b.W), node);
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat4();
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat4();
|
||||
value = writeLocal(VariantType::Float4, String::Format(TEXT("float4(lerp({0}.x, {1}.x, RAND), lerp({0}.y, {1}.y, RAND), lerp({0}.z, {1}.z, RAND), lerp({0}.w, {1}.w, RAND))"), a.Value, b.Value), node);
|
||||
break;
|
||||
}
|
||||
// Particle Emitter Function
|
||||
|
||||
@@ -212,6 +212,12 @@ Asset::LoadResult ParticleSystem::load()
|
||||
|
||||
int32 version;
|
||||
stream.ReadInt32(&version);
|
||||
#if USE_EDITOR
|
||||
// Skip unused parameters
|
||||
#define SKIP_UNUSED_PARAM_OVERRIDE() if (key.First < 0 || key.First >= Emitters.Count() || Emitters[key.First] == nullptr || Emitters[key.First]->Graph.GetParameter(key.Second) == nullptr) continue
|
||||
#else
|
||||
#define SKIP_UNUSED_PARAM_OVERRIDE()
|
||||
#endif
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
@@ -281,13 +287,7 @@ Asset::LoadResult ParticleSystem::load()
|
||||
stream.ReadInt32(&key.First);
|
||||
stream.Read(key.Second);
|
||||
stream.ReadCommonValue(&value);
|
||||
|
||||
#if USE_EDITOR
|
||||
// Skip unused parameters
|
||||
if (key.First < 0 || key.First >= Emitters.Count() || Emitters[key.First]->Graph.GetParameter(key.Second) == nullptr)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
SKIP_UNUSED_PARAM_OVERRIDE();
|
||||
EmittersParametersOverrides.Add(key, Variant(value));
|
||||
}
|
||||
}
|
||||
@@ -361,13 +361,7 @@ Asset::LoadResult ParticleSystem::load()
|
||||
stream.ReadInt32(&key.First);
|
||||
stream.Read(key.Second);
|
||||
stream.ReadCommonValue(&value);
|
||||
|
||||
#if USE_EDITOR
|
||||
// Skip unused parameters
|
||||
if (key.First < 0 || key.First >= Emitters.Count() || Emitters[key.First]->Graph.GetParameter(key.Second) == nullptr)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
SKIP_UNUSED_PARAM_OVERRIDE();
|
||||
EmittersParametersOverrides[key] = Variant(value);
|
||||
}
|
||||
}
|
||||
@@ -440,13 +434,7 @@ Asset::LoadResult ParticleSystem::load()
|
||||
stream.ReadInt32(&key.First);
|
||||
stream.Read(key.Second);
|
||||
stream.ReadVariant(&value);
|
||||
|
||||
#if USE_EDITOR
|
||||
// Skip unused parameters
|
||||
if (key.First < 0 || key.First >= Emitters.Count() || Emitters[key.First]->Graph.GetParameter(key.Second) == nullptr)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
SKIP_UNUSED_PARAM_OVERRIDE();
|
||||
EmittersParametersOverrides[key] = value;
|
||||
}
|
||||
}
|
||||
@@ -457,6 +445,7 @@ Asset::LoadResult ParticleSystem::load()
|
||||
LOG(Warning, "Unknown timeline version {0}.", version);
|
||||
return LoadResult::InvalidData;
|
||||
}
|
||||
#undef SKIP_UNUSED_PARAM_OVERRIDE
|
||||
|
||||
#if !BUILD_RELEASE
|
||||
_debugName = StringUtils::GetFileNameWithoutExtension(GetPath());
|
||||
|
||||
@@ -205,6 +205,42 @@ namespace FlaxEngine
|
||||
return obj != null && obj.__unmanagedPtr != IntPtr.Zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the two objects are equal.
|
||||
/// </summary>
|
||||
/// <param name="left"></param>
|
||||
/// <param name="right"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Object left, Object right)
|
||||
{
|
||||
IntPtr leftPtr = (object)left != null ? left.__unmanagedPtr : IntPtr.Zero;
|
||||
IntPtr rightPtr = (object)right != null ? right.__unmanagedPtr : IntPtr.Zero;
|
||||
return leftPtr == rightPtr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the two objects are not equal.
|
||||
/// </summary>
|
||||
/// <param name="left"></param>
|
||||
/// <param name="right"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Object left, Object right)
|
||||
{
|
||||
IntPtr leftPtr = (object)left != null ? left.__unmanagedPtr : IntPtr.Zero;
|
||||
IntPtr rightPtr = (object)right != null ? right.__unmanagedPtr : IntPtr.Zero;
|
||||
return leftPtr != rightPtr;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is FlaxEngine.Object o)
|
||||
return o.__unmanagedPtr == __unmanagedPtr;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pointer to the native object. Handles null object reference (returns zero).
|
||||
/// </summary>
|
||||
|
||||
@@ -267,3 +267,5 @@ API_CLASS(InBuild) class FLAXENGINE_API PersistentScriptingObject : public Scrip
|
||||
public:
|
||||
PersistentScriptingObject(const SpawnParams& params);
|
||||
};
|
||||
|
||||
extern FLAXENGINE_API class ScriptingObject* FindObject(const Guid& id, class MClass* type);
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace FlaxEngine.Json
|
||||
{
|
||||
// Skip serialization as reference id for the root object serialization (eg. Script)
|
||||
var cache = JsonSerializer.Current.Value;
|
||||
if (cache != null && cache.IsDuringSerialization && cache.SerializerWriter.SerializeStackSize == 0)
|
||||
if (cache != null && cache.IsWriting && cache.SerializerWriter.SerializeStackSize == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace FlaxEngine.Json
|
||||
public JsonSerializerInternalWriter SerializerWriter;
|
||||
public UnmanagedMemoryStream MemoryStream;
|
||||
public StreamReader Reader;
|
||||
public bool IsDuringSerialization;
|
||||
public bool IsWriting;
|
||||
public bool IsReading;
|
||||
|
||||
public unsafe SerializerCache(JsonSerializerSettings settings)
|
||||
{
|
||||
@@ -50,6 +51,49 @@ namespace FlaxEngine.Json
|
||||
DateFormatString = JsonSerializer.DateFormatString,
|
||||
};
|
||||
}
|
||||
|
||||
public void ReadBegin()
|
||||
{
|
||||
if (IsReading)
|
||||
{
|
||||
// TODO: Reset reading state (eg if previous deserialization got exception)
|
||||
}
|
||||
IsWriting = false;
|
||||
IsReading = true;
|
||||
}
|
||||
|
||||
public void ReadEnd()
|
||||
{
|
||||
IsReading = false;
|
||||
}
|
||||
|
||||
public void WriteBegin()
|
||||
{
|
||||
if (IsWriting)
|
||||
{
|
||||
// Reset writing state (eg if previous serialization got exception)
|
||||
JsonWriter = new JsonTextWriter(StringWriter)
|
||||
{
|
||||
IndentChar = '\t',
|
||||
Indentation = 1,
|
||||
Formatting = JsonSerializer.Formatting,
|
||||
DateFormatHandling = JsonSerializer.DateFormatHandling,
|
||||
DateTimeZoneHandling = JsonSerializer.DateTimeZoneHandling,
|
||||
FloatFormatHandling = JsonSerializer.FloatFormatHandling,
|
||||
StringEscapeHandling = JsonSerializer.StringEscapeHandling,
|
||||
Culture = JsonSerializer.Culture,
|
||||
DateFormatString = JsonSerializer.DateFormatString,
|
||||
};
|
||||
}
|
||||
StringBuilder.Clear();
|
||||
IsWriting = true;
|
||||
IsReading = false;
|
||||
}
|
||||
|
||||
public void WriteEnd()
|
||||
{
|
||||
IsWriting = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static JsonSerializerSettings Settings = CreateDefaultSettings(false);
|
||||
@@ -122,9 +166,9 @@ namespace FlaxEngine.Json
|
||||
var cache = isManagedOnly ? CacheManagedOnly.Value : Cache.Value;
|
||||
Current.Value = cache;
|
||||
|
||||
cache.StringBuilder.Clear();
|
||||
cache.IsDuringSerialization = true;
|
||||
cache.WriteBegin();
|
||||
cache.SerializerWriter.Serialize(cache.JsonWriter, obj, type);
|
||||
cache.WriteEnd();
|
||||
|
||||
return cache.StringBuilder.ToString();
|
||||
}
|
||||
@@ -141,9 +185,9 @@ namespace FlaxEngine.Json
|
||||
var cache = isManagedOnly ? CacheManagedOnly.Value : Cache.Value;
|
||||
Current.Value = cache;
|
||||
|
||||
cache.StringBuilder.Clear();
|
||||
cache.IsDuringSerialization = true;
|
||||
cache.WriteBegin();
|
||||
cache.SerializerWriter.Serialize(cache.JsonWriter, obj, type);
|
||||
cache.WriteEnd();
|
||||
|
||||
return cache.StringBuilder.ToString();
|
||||
}
|
||||
@@ -161,9 +205,9 @@ namespace FlaxEngine.Json
|
||||
var cache = isManagedOnly ? CacheManagedOnly.Value : Cache.Value;
|
||||
Current.Value = cache;
|
||||
|
||||
cache.StringBuilder.Clear();
|
||||
cache.IsDuringSerialization = true;
|
||||
cache.WriteBegin();
|
||||
cache.SerializerWriter.SerializeDiff(cache.JsonWriter, obj, type, other);
|
||||
cache.WriteEnd();
|
||||
|
||||
return cache.StringBuilder.ToString();
|
||||
}
|
||||
@@ -176,21 +220,20 @@ namespace FlaxEngine.Json
|
||||
public static void Deserialize(object input, string json)
|
||||
{
|
||||
var cache = Cache.Value;
|
||||
cache.IsDuringSerialization = false;
|
||||
Current.Value = cache;
|
||||
|
||||
cache.ReadBegin();
|
||||
using (JsonReader reader = new JsonTextReader(new StringReader(json)))
|
||||
{
|
||||
cache.JsonSerializer.Populate(reader, input);
|
||||
|
||||
if (!cache.JsonSerializer.CheckAdditionalContent)
|
||||
return;
|
||||
while (reader.Read())
|
||||
if (cache.JsonSerializer.CheckAdditionalContent)
|
||||
{
|
||||
if (reader.TokenType != JsonToken.Comment)
|
||||
throw new Exception("Additional text found in JSON string after finishing deserializing object.");
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType != JsonToken.Comment)
|
||||
throw new Exception("Additional text found in JSON string after finishing deserializing object.");
|
||||
}
|
||||
}
|
||||
}
|
||||
cache.ReadEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -214,22 +257,20 @@ namespace FlaxEngine.Json
|
||||
{
|
||||
object result;
|
||||
var cache = Cache.Value;
|
||||
cache.IsDuringSerialization = false;
|
||||
Current.Value = cache;
|
||||
|
||||
cache.ReadBegin();
|
||||
using (JsonReader reader = new JsonTextReader(new StringReader(json)))
|
||||
{
|
||||
result = cache.JsonSerializer.Deserialize(reader, objectType);
|
||||
|
||||
if (!cache.JsonSerializer.CheckAdditionalContent)
|
||||
return result;
|
||||
while (reader.Read())
|
||||
if (cache.JsonSerializer.CheckAdditionalContent)
|
||||
{
|
||||
if (reader.TokenType != JsonToken.Comment)
|
||||
throw new Exception("Additional text found in JSON string after finishing deserializing object.");
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType != JsonToken.Comment)
|
||||
throw new Exception("Additional text found in JSON string after finishing deserializing object.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cache.ReadEnd();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -242,22 +283,21 @@ namespace FlaxEngine.Json
|
||||
{
|
||||
object result;
|
||||
var cache = Cache.Value;
|
||||
cache.IsDuringSerialization = false;
|
||||
Current.Value = cache;
|
||||
|
||||
cache.ReadBegin();
|
||||
using (JsonReader reader = new JsonTextReader(new StringReader(json)))
|
||||
{
|
||||
result = cache.JsonSerializer.Deserialize(reader);
|
||||
|
||||
if (!cache.JsonSerializer.CheckAdditionalContent)
|
||||
return result;
|
||||
while (reader.Read())
|
||||
if (cache.JsonSerializer.CheckAdditionalContent)
|
||||
{
|
||||
if (reader.TokenType != JsonToken.Comment)
|
||||
throw new Exception("Additional text found in JSON string after finishing deserializing object.");
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType != JsonToken.Comment)
|
||||
throw new Exception("Additional text found in JSON string after finishing deserializing object.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cache.ReadEnd();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -270,8 +310,7 @@ namespace FlaxEngine.Json
|
||||
public static unsafe void Deserialize(object input, byte* jsonBuffer, int jsonLength)
|
||||
{
|
||||
var cache = Cache.Value;
|
||||
cache.IsDuringSerialization = false;
|
||||
Current.Value = cache;
|
||||
cache.ReadBegin();
|
||||
|
||||
/*// Debug json string reading
|
||||
cache.MemoryStream.Initialize(jsonBuffer, jsonLength);
|
||||
@@ -291,14 +330,16 @@ namespace FlaxEngine.Json
|
||||
{
|
||||
cache.JsonSerializer.Populate(jsonReader, input);
|
||||
}
|
||||
|
||||
if (!cache.JsonSerializer.CheckAdditionalContent)
|
||||
return;
|
||||
while (jsonReader.Read())
|
||||
if (cache.JsonSerializer.CheckAdditionalContent)
|
||||
{
|
||||
if (jsonReader.TokenType != JsonToken.Comment)
|
||||
throw new Exception("Additional text found in JSON string after finishing deserializing object.");
|
||||
while (jsonReader.Read())
|
||||
{
|
||||
if (jsonReader.TokenType != JsonToken.Comment)
|
||||
throw new Exception("Additional text found in JSON string after finishing deserializing object.");
|
||||
}
|
||||
}
|
||||
|
||||
cache.ReadEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "Stream.h"
|
||||
#include "Engine/Core/Templates.h"
|
||||
|
||||
extern FLAXENGINE_API class ScriptingObject* FindObject(const Guid& id, class MClass* type);
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all data read streams
|
||||
/// </summary>
|
||||
|
||||
@@ -456,7 +456,7 @@ namespace Serialization
|
||||
Guid id;
|
||||
Deserialize(stream, id, modifier);
|
||||
modifier->IdsMapping.TryGet(id, id);
|
||||
v = (T*)FindObject(id, T::GetStaticClass());
|
||||
v = (T*)::FindObject(id, T::GetStaticClass());
|
||||
}
|
||||
|
||||
// Scripting Object Reference
|
||||
|
||||
@@ -1273,16 +1273,16 @@ void VisjectExecutor::ProcessGroupParticles(Box* box, Node* node, Value& value)
|
||||
// Random Float Range
|
||||
case 213:
|
||||
{
|
||||
auto& a = node->Values[0].AsFloat;
|
||||
auto& b = node->Values[1].AsFloat;
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat;
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat;
|
||||
value = Math::Lerp(a, b, RAND);
|
||||
break;
|
||||
}
|
||||
// Random Vector2 Range
|
||||
case 214:
|
||||
{
|
||||
auto a = (Float2)node->Values[0];
|
||||
auto b = (Float2)node->Values[1];
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat2();
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat2();
|
||||
value = Float2(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND)
|
||||
@@ -1292,8 +1292,8 @@ void VisjectExecutor::ProcessGroupParticles(Box* box, Node* node, Value& value)
|
||||
// Random Vector3 Range
|
||||
case 215:
|
||||
{
|
||||
auto a = (Float3)node->Values[0];
|
||||
auto b = (Float3)node->Values[1];
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat3();
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat3();
|
||||
value = Float3(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND),
|
||||
@@ -1304,8 +1304,8 @@ void VisjectExecutor::ProcessGroupParticles(Box* box, Node* node, Value& value)
|
||||
// Random Vector4 Range
|
||||
case 216:
|
||||
{
|
||||
auto a = (Float4)node->Values[0];
|
||||
auto b = (Float4)node->Values[1];
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat4();
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat4();
|
||||
value = Float4(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND),
|
||||
|
||||
Reference in New Issue
Block a user