Add support for custom drag&drop into level/prefab viewports from custom asset items

This commit is contained in:
Wojtek Figat
2021-05-24 18:34:19 +02:00
parent c78fb7995e
commit 2c7d62bb8e
13 changed files with 262 additions and 362 deletions

View File

@@ -108,6 +108,26 @@ namespace FlaxEditor.Content
return false; return false;
} }
/// <summary>
/// Called when user dags this item into editor viewport or scene tree node.
/// </summary>
/// <param name="context">The editor context (eg. editor viewport or scene tree node).</param>
/// <returns>True if item can be dropped in, otherwise false.</returns>
public virtual bool OnEditorDrag(object context)
{
return false;
}
/// <summary>
/// Called when user drops the item into editor viewport or scene tree node.
/// </summary>
/// <param name="context">The editor context (eg. editor viewport or scene tree node).</param>
/// <returns>The spawned object.</returns>
public virtual Actor OnEditorDrop(object context)
{
throw new NotSupportedException($"Asset {GetType()} doesn't support dropping into viewport.");
}
/// <inheritdoc /> /// <inheritdoc />
protected override bool DrawShadow => true; protected override bool DrawShadow => true;

View File

@@ -103,14 +103,26 @@ namespace FlaxEditor.Content
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="Model"/> assets. /// Implementation of <see cref="BinaryAssetItem"/> for <see cref="Model"/> assets.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
public class ModelAssetItem : BinaryAssetItem public class ModelItem : BinaryAssetItem
{ {
/// <inheritdoc /> /// <inheritdoc />
public ModelAssetItem(string path, ref Guid id, string typeName, Type type) public ModelItem(string path, ref Guid id, string typeName, Type type)
: base(path, ref id, typeName, type, ContentItemSearchFilter.Model) : base(path, ref id, typeName, type, ContentItemSearchFilter.Model)
{ {
} }
/// <inheritdoc />
public override bool OnEditorDrag(object context)
{
return true;
}
/// <inheritdoc />
public override Actor OnEditorDrop(object context)
{
return new StaticModel { Model = FlaxEngine.Content.LoadAsync<Model>(ID) };
}
/// <inheritdoc /> /// <inheritdoc />
protected override void OnBuildTooltipText(StringBuilder sb) protected override void OnBuildTooltipText(StringBuilder sb)
{ {
@@ -142,14 +154,26 @@ namespace FlaxEditor.Content
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="SkinnedModel"/> assets. /// Implementation of <see cref="BinaryAssetItem"/> for <see cref="SkinnedModel"/> assets.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
public class SkinnedModelAssetItem : BinaryAssetItem public class SkinnedModeItem : BinaryAssetItem
{ {
/// <inheritdoc /> /// <inheritdoc />
public SkinnedModelAssetItem(string path, ref Guid id, string typeName, Type type) public SkinnedModeItem(string path, ref Guid id, string typeName, Type type)
: base(path, ref id, typeName, type, ContentItemSearchFilter.Model) : base(path, ref id, typeName, type, ContentItemSearchFilter.Model)
{ {
} }
/// <inheritdoc />
public override bool OnEditorDrag(object context)
{
return true;
}
/// <inheritdoc />
public override Actor OnEditorDrop(object context)
{
return new AnimatedModel { SkinnedModel = FlaxEngine.Content.LoadAsync<SkinnedModel>(ID) };
}
/// <inheritdoc /> /// <inheritdoc />
protected override void OnBuildTooltipText(StringBuilder sb) protected override void OnBuildTooltipText(StringBuilder sb)
{ {

View File

@@ -21,6 +21,18 @@ namespace FlaxEditor.Content
{ {
} }
/// <inheritdoc />
public override bool OnEditorDrag(object context)
{
return true;
}
/// <inheritdoc />
public override Actor OnEditorDrop(object context)
{
return PrefabManager.SpawnPrefab(FlaxEngine.Content.LoadAsync<Prefab>(ID), null);
}
/// <inheritdoc /> /// <inheritdoc />
public override ContentItemType ItemType => ContentItemType.Asset; public override ContentItemType ItemType => ContentItemType.Asset;

View File

@@ -538,6 +538,18 @@ namespace FlaxEditor.Content
Editor.Instance.CodeEditing.ClearTypes(); Editor.Instance.CodeEditing.ClearTypes();
} }
/// <inheritdoc />
public override bool OnEditorDrag(object context)
{
return new ScriptType(typeof(Actor)).IsAssignableFrom(ScriptType) && ScriptType.CanCreateInstance;
}
/// <inheritdoc />
public override Actor OnEditorDrop(object context)
{
return (Actor)ScriptType.CreateInstance();
}
/// <inheritdoc /> /// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.VisualScript128; public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.VisualScript128;

View File

@@ -2,6 +2,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using FlaxEditor.Content.Thumbnails; using FlaxEditor.Content.Thumbnails;
using FlaxEditor.Viewport.Previews; using FlaxEditor.Viewport.Previews;
using FlaxEditor.Windows; using FlaxEditor.Windows;
@@ -11,11 +12,51 @@ using FlaxEngine.GUI;
namespace FlaxEditor.Content namespace FlaxEditor.Content
{ {
/// <summary>
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="AudioClip"/> assets.
/// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
class AudioClipItem : BinaryAssetItem
{
/// <inheritdoc />
public AudioClipItem(string path, ref Guid id, string typeName, Type type)
: base(path, ref id, typeName, type, ContentItemSearchFilter.Audio)
{
}
/// <inheritdoc />
public override bool OnEditorDrag(object context)
{
return true;
}
/// <inheritdoc />
public override Actor OnEditorDrop(object context)
{
return new AudioSource { Clip = FlaxEngine.Content.LoadAsync<AudioClip>(ID) };
}
/// <inheritdoc />
protected override void OnBuildTooltipText(StringBuilder sb)
{
base.OnBuildTooltipText(sb);
var asset = FlaxEngine.Content.Load<AudioClip>(ID, 100);
if (asset)
{
var info = asset.Info;
sb.Append("Duration: ").Append(asset.Length).AppendLine();
sb.Append("Channels: ").Append(info.NumChannels).AppendLine();
sb.Append("Bit Depth: ").Append(info.BitDepth).AppendLine();
}
}
}
/// <summary> /// <summary>
/// A <see cref="AudioClip"/> asset proxy object. /// A <see cref="AudioClip"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
public class AudioClipProxy : BinaryAssetProxy class AudioClipProxy : BinaryAssetProxy
{ {
private List<AudioClipPreview> _previews; private List<AudioClipPreview> _previews;
@@ -34,6 +75,12 @@ namespace FlaxEditor.Content
return new AudioClipWindow(editor, (AssetItem)item); return new AudioClipWindow(editor, (AssetItem)item);
} }
/// <inheritdoc />
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
{
return new AudioClipItem(path, ref id, typeName, AssetType);
}
/// <inheritdoc /> /// <inheritdoc />
public override Color AccentColor => Color.FromRGB(0xB3452B); public override Color AccentColor => Color.FromRGB(0xB3452B);

View File

@@ -47,9 +47,9 @@ namespace FlaxEditor.Content
if (typeof(TextureBase).IsAssignableFrom(type)) if (typeof(TextureBase).IsAssignableFrom(type))
return new TextureAssetItem(path, ref id, typeName, type); return new TextureAssetItem(path, ref id, typeName, type);
if (typeof(Model).IsAssignableFrom(type)) if (typeof(Model).IsAssignableFrom(type))
return new ModelAssetItem(path, ref id, typeName, type); return new ModelItem(path, ref id, typeName, type);
if (typeof(SkinnedModel).IsAssignableFrom(type)) if (typeof(SkinnedModel).IsAssignableFrom(type))
return new SkinnedModelAssetItem(path, ref id, typeName, type); return new SkinnedModeItem(path, ref id, typeName, type);
ContentItemSearchFilter searchFilter; ContentItemSearchFilter searchFilter;
if (typeof(MaterialBase).IsAssignableFrom(type)) if (typeof(MaterialBase).IsAssignableFrom(type))
@@ -58,11 +58,9 @@ namespace FlaxEditor.Content
searchFilter = ContentItemSearchFilter.Prefab; searchFilter = ContentItemSearchFilter.Prefab;
else if (typeof(SceneAsset).IsAssignableFrom(type)) else if (typeof(SceneAsset).IsAssignableFrom(type))
searchFilter = ContentItemSearchFilter.Scene; searchFilter = ContentItemSearchFilter.Scene;
else if (typeof(AudioClip).IsAssignableFrom(type))
searchFilter = ContentItemSearchFilter.Audio;
else if (typeof(Animation).IsAssignableFrom(type)) else if (typeof(Animation).IsAssignableFrom(type))
searchFilter = ContentItemSearchFilter.Animation; searchFilter = ContentItemSearchFilter.Animation;
else if (typeof(ParticleEmitter).IsAssignableFrom(type) || typeof(ParticleSystem).IsAssignableFrom(type)) else if (typeof(ParticleEmitter).IsAssignableFrom(type))
searchFilter = ContentItemSearchFilter.Particles; searchFilter = ContentItemSearchFilter.Particles;
else else
searchFilter = ContentItemSearchFilter.Other; searchFilter = ContentItemSearchFilter.Other;

View File

@@ -8,11 +8,36 @@ using FlaxEngine;
namespace FlaxEditor.Content namespace FlaxEditor.Content
{ {
/// <summary>
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="CollisionData"/> assets.
/// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
class CollisionDataItem : BinaryAssetItem
{
/// <inheritdoc />
public CollisionDataItem(string path, ref Guid id, string typeName, Type type)
: base(path, ref id, typeName, type, ContentItemSearchFilter.Other)
{
}
/// <inheritdoc />
public override bool OnEditorDrag(object context)
{
return true;
}
/// <inheritdoc />
public override Actor OnEditorDrop(object context)
{
return new MeshCollider { CollisionData = FlaxEngine.Content.LoadAsync<CollisionData>(ID) };
}
}
/// <summary> /// <summary>
/// A <see cref="CollisionData"/> asset proxy object. /// A <see cref="CollisionData"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
public class CollisionDataProxy : BinaryAssetProxy class CollisionDataProxy : BinaryAssetProxy
{ {
/// <inheritdoc /> /// <inheritdoc />
public override string Name => "Collision Data"; public override string Name => "Collision Data";
@@ -23,6 +48,12 @@ namespace FlaxEditor.Content
return new CollisionDataWindow(editor, item as AssetItem); return new CollisionDataWindow(editor, item as AssetItem);
} }
/// <inheritdoc />
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
{
return new CollisionDataItem(path, ref id, typeName, AssetType);
}
/// <inheritdoc /> /// <inheritdoc />
public override Color AccentColor => Color.FromRGB(0x2c3e50); public override Color AccentColor => Color.FromRGB(0x2c3e50);

View File

@@ -47,7 +47,7 @@ namespace FlaxEditor.Content
menu.AddButton("Create collision data", () => menu.AddButton("Create collision data", () =>
{ {
var model = FlaxEngine.Content.LoadAsync<Model>(((ModelAssetItem)item).ID); var model = FlaxEngine.Content.LoadAsync<Model>(((ModelItem)item).ID);
var collisionDataProxy = (CollisionDataProxy)Editor.Instance.ContentDatabase.GetProxy<CollisionData>(); var collisionDataProxy = (CollisionDataProxy)Editor.Instance.ContentDatabase.GetProxy<CollisionData>();
collisionDataProxy.CreateCollisionDataFromModel(model); collisionDataProxy.CreateCollisionDataFromModel(model);
}); });

View File

@@ -10,6 +10,31 @@ using FlaxEngine.GUI;
namespace FlaxEditor.Content namespace FlaxEditor.Content
{ {
/// <summary>
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="ParticleSystem"/> assets.
/// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
class ParticleSystemItem : BinaryAssetItem
{
/// <inheritdoc />
public ParticleSystemItem(string path, ref Guid id, string typeName, Type type)
: base(path, ref id, typeName, type, ContentItemSearchFilter.Particles)
{
}
/// <inheritdoc />
public override bool OnEditorDrag(object context)
{
return true;
}
/// <inheritdoc />
public override Actor OnEditorDrop(object context)
{
return new ParticleEffect { ParticleSystem = FlaxEngine.Content.LoadAsync<ParticleSystem>(ID) };
}
}
/// <summary> /// <summary>
/// A <see cref="ParticleSystem"/> asset proxy object. /// A <see cref="ParticleSystem"/> asset proxy object.
/// </summary> /// </summary>
@@ -28,6 +53,12 @@ namespace FlaxEditor.Content
return new ParticleSystemWindow(editor, item as AssetItem); return new ParticleSystemWindow(editor, item as AssetItem);
} }
/// <inheritdoc />
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
{
return new ParticleSystemItem(path, ref id, typeName, AssetType);
}
/// <inheritdoc /> /// <inheritdoc />
public override Color AccentColor => Color.FromRGB(0xFF790200); public override Color AccentColor => Color.FromRGB(0xFF790200);

View File

@@ -7,6 +7,31 @@ using FlaxEngine;
namespace FlaxEditor.Content namespace FlaxEditor.Content
{ {
/// <summary>
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="SceneAnimation"/> assets.
/// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
class SceneAnimationItem : BinaryAssetItem
{
/// <inheritdoc />
public SceneAnimationItem(string path, ref Guid id, string typeName, Type type)
: base(path, ref id, typeName, type, ContentItemSearchFilter.Other)
{
}
/// <inheritdoc />
public override bool OnEditorDrag(object context)
{
return true;
}
/// <inheritdoc />
public override Actor OnEditorDrop(object context)
{
return new SceneAnimationPlayer { Animation = FlaxEngine.Content.LoadAsync<SceneAnimation>(ID) };
}
}
/// <summary> /// <summary>
/// A <see cref="SceneAnimation"/> asset proxy object. /// A <see cref="SceneAnimation"/> asset proxy object.
/// </summary> /// </summary>
@@ -22,6 +47,12 @@ namespace FlaxEditor.Content
return new SceneAnimationWindow(editor, item as AssetItem); return new SceneAnimationWindow(editor, item as AssetItem);
} }
/// <inheritdoc />
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
{
return new SceneAnimationItem(path, ref id, typeName, AssetType);
}
/// <inheritdoc /> /// <inheritdoc />
public override Color AccentColor => Color.FromRGB(0xff5c4a87); public override Color AccentColor => Color.FromRGB(0xff5c4a87);

View File

@@ -568,121 +568,12 @@ namespace FlaxEditor.SceneGraph.GUI
{ {
for (int i = 0; i < _dragAssets.Objects.Count; i++) for (int i = 0; i < _dragAssets.Objects.Count; i++)
{ {
var assetItem = _dragAssets.Objects[i]; var item = _dragAssets.Objects[i];
var actor = item.OnEditorDrop(this);
if (assetItem.IsOfType<SkinnedModel>()) actor.StaticFlags = Actor.StaticFlags;
{ actor.Name = item.ShortName;
// Create actor actor.Transform = Actor.Transform;
var model = FlaxEngine.Content.LoadAsync<SkinnedModel>(assetItem.ID); ActorNode.Root.Spawn(actor, Actor);
var actor = new AnimatedModel
{
StaticFlags = Actor.StaticFlags,
Name = assetItem.ShortName,
SkinnedModel = model,
Transform = Actor.Transform
};
// Spawn
ActorNode.Root.Spawn(actor, Actor);
}
else if (assetItem.IsOfType<Model>())
{
// Create actor
var model = FlaxEngine.Content.LoadAsync<Model>(assetItem.ID);
var actor = new StaticModel
{
StaticFlags = Actor.StaticFlags,
Name = assetItem.ShortName,
Model = model,
Transform = Actor.Transform
};
// Spawn
ActorNode.Root.Spawn(actor, Actor);
}
else if (assetItem.IsOfType<CollisionData>())
{
// Create actor
var actor = new MeshCollider
{
StaticFlags = Actor.StaticFlags,
Name = assetItem.ShortName,
CollisionData = FlaxEngine.Content.LoadAsync<CollisionData>(assetItem.ID),
Transform = Actor.Transform
};
// Spawn
ActorNode.Root.Spawn(actor, Actor);
}
else if (assetItem.IsOfType<ParticleSystem>())
{
// Create actor
var actor = new ParticleEffect
{
StaticFlags = Actor.StaticFlags,
Name = assetItem.ShortName,
ParticleSystem = FlaxEngine.Content.LoadAsync<ParticleSystem>(assetItem.ID),
Transform = Actor.Transform
};
// Spawn
ActorNode.Root.Spawn(actor, Actor);
}
else if (assetItem.IsOfType<SceneAnimation>())
{
// Create actor
var actor = new SceneAnimationPlayer
{
StaticFlags = Actor.StaticFlags,
Name = assetItem.ShortName,
Animation = FlaxEngine.Content.LoadAsync<SceneAnimation>(assetItem.ID),
Transform = Actor.Transform
};
// Spawn
ActorNode.Root.Spawn(actor, Actor);
}
else if (assetItem.IsOfType<AudioClip>())
{
// Create actor
var actor = new AudioSource
{
StaticFlags = Actor.StaticFlags,
Name = assetItem.ShortName,
Clip = FlaxEngine.Content.LoadAsync<AudioClip>(assetItem.ID),
Transform = Actor.Transform
};
// Spawn
ActorNode.Root.Spawn(actor, Actor);
break;
}
else if (assetItem.IsOfType<Prefab>())
{
// Create prefab instance
var prefab = FlaxEngine.Content.LoadAsync<Prefab>(assetItem.ID);
var actor = PrefabManager.SpawnPrefab(prefab, null);
actor.StaticFlags = Actor.StaticFlags;
actor.Name = assetItem.ShortName;
actor.Transform = Actor.Transform;
// Spawn
ActorNode.Root.Spawn(actor, Actor);
}
else if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
{
// Create actor
var actor = (Actor)visualScriptItem.ScriptType.CreateInstance();
actor.StaticFlags = Actor.StaticFlags;
actor.Name = assetItem.ShortName;
actor.Transform = Actor.Transform;
// Spawn
ActorNode.Root.Spawn(actor, Actor);
}
} }
result = DragDropEffect.Move; result = DragDropEffect.Move;
@@ -737,46 +628,12 @@ namespace FlaxEditor.SceneGraph.GUI
return actorNode.Actor != null && actorNode != ActorNode && actorNode.Find(Actor) == null; return actorNode.Actor != null && actorNode != ActorNode && actorNode.Find(Actor) == null;
} }
/// <summary> private bool ValidateDragAsset(AssetItem assetItem)
/// Validates the asset for drag and drop into one of the scene tree nodes.
/// </summary>
/// <param name="assetItem">The item.</param>
/// <returns>True if can drag and drop it, otherwise false.</returns>
public static bool ValidateDragAsset(AssetItem assetItem)
{ {
if (assetItem.IsOfType<SkinnedModel>()) return assetItem.OnEditorDrag(this);
return true;
if (assetItem.IsOfType<Model>())
return true;
if (assetItem.IsOfType<AudioClip>())
return true;
if (assetItem.IsOfType<Prefab>())
return true;
if (assetItem.IsOfType<CollisionData>())
return true;
if (assetItem.IsOfType<ParticleSystem>())
return true;
if (assetItem.IsOfType<SceneAnimation>())
return true;
if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
return true;
return false;
} }
/// <summary> private static bool ValidateDragActorType(ScriptType actorType)
/// Validates the type of the actor for drag and drop into one of the scene tree nodes.
/// </summary>
/// <param name="actorType">Type of the actor.</param>
/// <returns>True if can drag and drop it, otherwise false.</returns>
public static bool ValidateDragActorType(ScriptType actorType)
{ {
return true; return true;
} }

View File

@@ -36,7 +36,7 @@ namespace FlaxEditor.Viewport
private readonly ViewportWidgetButton _rotateSnapping; private readonly ViewportWidgetButton _rotateSnapping;
private readonly ViewportWidgetButton _scaleSnapping; private readonly ViewportWidgetButton _scaleSnapping;
private readonly DragAssets<DragDropEventArgs> _dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem); private readonly DragAssets<DragDropEventArgs> _dragAssets;
private readonly DragActorType<DragDropEventArgs> _dragActorType = new DragActorType<DragDropEventArgs>(ValidateDragActorType); private readonly DragActorType<DragDropEventArgs> _dragActorType = new DragActorType<DragDropEventArgs>(ValidateDragActorType);
private SelectionOutline _customSelectionOutline; private SelectionOutline _customSelectionOutline;
@@ -187,6 +187,7 @@ namespace FlaxEditor.Viewport
: base(Object.New<SceneRenderTask>(), editor.Undo) : base(Object.New<SceneRenderTask>(), editor.Undo)
{ {
_editor = editor; _editor = editor;
_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem);
// Prepare rendering task // Prepare rendering task
Task.ActorsSource = ActorsSources.Scenes; Task.ActorsSource = ActorsSources.Scenes;
@@ -800,31 +801,19 @@ namespace FlaxEditor.Viewport
return result; return result;
} }
private static bool ValidateDragItem(ContentItem contentItem) private bool ValidateDragItem(ContentItem contentItem)
{ {
if (!Level.IsAnySceneLoaded) if (!Level.IsAnySceneLoaded)
return false; return false;
if (contentItem is AssetItem assetItem) if (contentItem is AssetItem assetItem)
{ {
if (assetItem.IsOfType<ParticleSystem>()) if (assetItem.OnEditorDrag(this))
return true;
if (assetItem.IsOfType<SceneAnimation>())
return true; return true;
if (assetItem.IsOfType<MaterialBase>()) if (assetItem.IsOfType<MaterialBase>())
return true; return true;
if (assetItem.IsOfType<ModelBase>())
return true;
if (assetItem.IsOfType<CollisionData>())
return true;
if (assetItem.IsOfType<AudioClip>())
return true;
if (assetItem.IsOfType<Prefab>())
return true;
if (assetItem.IsOfType<SceneAsset>()) if (assetItem.IsOfType<SceneAsset>())
return true; return true;
if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
return true;
} }
return false; return false;
@@ -891,119 +880,40 @@ namespace FlaxEditor.Viewport
private void Spawn(AssetItem item, SceneGraphNode hit, ref Vector2 location, ref Vector3 hitLocation) private void Spawn(AssetItem item, SceneGraphNode hit, ref Vector2 location, ref Vector3 hitLocation)
{ {
if (item is AssetItem assetItem) if (item.IsOfType<MaterialBase>())
{ {
if (assetItem.IsOfType<ParticleSystem>()) if (hit is StaticModelNode staticModelNode)
{ {
var asset = FlaxEngine.Content.LoadAsync<ParticleSystem>(item.ID); var staticModel = (StaticModel)staticModelNode.Actor;
var actor = new ParticleEffect var ray = ConvertMouseToRay(ref location);
{ if (staticModel.IntersectsEntry(ref ray, out _, out _, out var entryIndex))
Name = item.ShortName,
ParticleSystem = asset
};
Spawn(actor, ref hitLocation);
return;
}
if (assetItem.IsOfType<SceneAnimation>())
{
var asset = FlaxEngine.Content.LoadAsync<SceneAnimation>(item.ID);
var actor = new SceneAnimationPlayer
{
Name = item.ShortName,
Animation = asset
};
Spawn(actor, ref hitLocation);
return;
}
if (assetItem.IsOfType<MaterialBase>())
{
if (hit is StaticModelNode staticModelNode)
{
var staticModel = (StaticModel)staticModelNode.Actor;
var ray = ConvertMouseToRay(ref location);
if (staticModel.IntersectsEntry(ref ray, out _, out _, out var entryIndex))
{
var material = FlaxEngine.Content.LoadAsync<MaterialBase>(item.ID);
using (new UndoBlock(Undo, staticModel, "Change material"))
staticModel.SetMaterial(entryIndex, material);
}
}
else if (hit is BoxBrushNode.SideLinkNode brushSurfaceNode)
{ {
var material = FlaxEngine.Content.LoadAsync<MaterialBase>(item.ID); var material = FlaxEngine.Content.LoadAsync<MaterialBase>(item.ID);
using (new UndoBlock(Undo, brushSurfaceNode.Brush, "Change material")) using (new UndoBlock(Undo, staticModel, "Change material"))
{ staticModel.SetMaterial(entryIndex, material);
var surface = brushSurfaceNode.Surface;
surface.Material = material;
brushSurfaceNode.Surface = surface;
}
} }
return;
} }
if (assetItem.IsOfType<SkinnedModel>()) else if (hit is BoxBrushNode.SideLinkNode brushSurfaceNode)
{ {
var model = FlaxEngine.Content.LoadAsync<SkinnedModel>(item.ID); var material = FlaxEngine.Content.LoadAsync<MaterialBase>(item.ID);
var actor = new AnimatedModel using (new UndoBlock(Undo, brushSurfaceNode.Brush, "Change material"))
{ {
Name = item.ShortName, var surface = brushSurfaceNode.Surface;
SkinnedModel = model surface.Material = material;
}; brushSurfaceNode.Surface = surface;
Spawn(actor, ref hitLocation); }
return;
}
if (assetItem.IsOfType<Model>())
{
var model = FlaxEngine.Content.LoadAsync<Model>(item.ID);
var actor = new StaticModel
{
Name = item.ShortName,
Model = model
};
Spawn(actor, ref hitLocation);
return;
}
if (assetItem.IsOfType<CollisionData>())
{
var collisionData = FlaxEngine.Content.LoadAsync<CollisionData>(item.ID);
var actor = new MeshCollider
{
Name = item.ShortName,
CollisionData = collisionData
};
Spawn(actor, ref hitLocation);
return;
}
if (assetItem.IsOfType<AudioClip>())
{
var clip = FlaxEngine.Content.LoadAsync<AudioClip>(item.ID);
var actor = new AudioSource
{
Name = item.ShortName,
Clip = clip
};
Spawn(actor, ref hitLocation);
return;
}
if (assetItem.IsOfType<Prefab>())
{
var prefab = FlaxEngine.Content.LoadAsync<Prefab>(item.ID);
var actor = PrefabManager.SpawnPrefab(prefab, null);
actor.Name = item.ShortName;
Spawn(actor, ref hitLocation);
return;
}
if (assetItem.IsOfType<SceneAsset>())
{
Editor.Instance.Scene.OpenScene(item.ID, true);
return;
}
if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
{
var actor = (Actor)visualScriptItem.ScriptType.CreateInstance();
actor.Name = item.ShortName;
Spawn(actor, ref hitLocation);
return;
} }
return;
}
if (item.IsOfType<SceneAsset>())
{
Editor.Instance.Scene.OpenScene(item.ID, true);
return;
}
{
var actor = item.OnEditorDrop(this);
actor.Name = item.ShortName;
Spawn(actor, ref hitLocation);
} }
} }

View File

@@ -2,6 +2,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Policy;
using FlaxEditor.Content; using FlaxEditor.Content;
using FlaxEditor.Gizmo; using FlaxEditor.Gizmo;
using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.ContextMenu;
@@ -53,7 +54,7 @@ namespace FlaxEditor.Viewport
private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32); private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32);
private IntPtr _debugDrawContext; private IntPtr _debugDrawContext;
private PrefabSpritesRenderer _spritesRenderer; private PrefabSpritesRenderer _spritesRenderer;
private readonly DragAssets _dragAssets = new DragAssets(ValidateDragItem); private readonly DragAssets _dragAssets;
private readonly DragActorType _dragActorType = new DragActorType(ValidateDragActorType); private readonly DragActorType _dragActorType = new DragActorType(ValidateDragActorType);
private readonly DragHandlers _dragHandlers = new DragHandlers(); private readonly DragHandlers _dragHandlers = new DragHandlers();
@@ -89,6 +90,7 @@ namespace FlaxEditor.Viewport
Undo = window.Undo; Undo = window.Undo;
ViewportCamera = new FPSCamera(); ViewportCamera = new FPSCamera();
_debugDrawContext = DebugDraw.AllocateContext(); _debugDrawContext = DebugDraw.AllocateContext();
_dragAssets = new DragAssets(ValidateDragItem);
// Prepare rendering task // Prepare rendering task
Task.ActorsSource = ActorsSources.CustomActors; Task.ActorsSource = ActorsSources.CustomActors;
@@ -673,24 +675,14 @@ namespace FlaxEditor.Viewport
return _dragHandlers.OnDragEnter(data); return _dragHandlers.OnDragEnter(data);
} }
private static bool ValidateDragItem(ContentItem contentItem) private bool ValidateDragItem(ContentItem contentItem)
{ {
if (contentItem is AssetItem assetItem) if (contentItem is AssetItem assetItem)
{ {
if (assetItem.IsOfType<ParticleSystem>()) if (assetItem.OnEditorDrag(this))
return true; return true;
if (assetItem.IsOfType<MaterialBase>()) if (assetItem.IsOfType<MaterialBase>())
return true; return true;
if (assetItem.IsOfType<ModelBase>())
return true;
if (assetItem.IsOfType<CollisionData>())
return true;
if (assetItem.IsOfType<AudioClip>())
return true;
if (assetItem.IsOfType<Prefab>())
return true;
if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
return true;
} }
return false; return false;
@@ -743,17 +735,6 @@ namespace FlaxEditor.Viewport
{ {
if (item is BinaryAssetItem binaryAssetItem) if (item is BinaryAssetItem binaryAssetItem)
{ {
if (binaryAssetItem.Type == typeof(ParticleSystem))
{
var particleSystem = FlaxEngine.Content.LoadAsync<ParticleSystem>(item.ID);
var actor = new ParticleEffect
{
Name = item.ShortName,
ParticleSystem = particleSystem
};
Spawn(actor, ref hitLocation);
return;
}
if (typeof(MaterialBase).IsAssignableFrom(binaryAssetItem.Type)) if (typeof(MaterialBase).IsAssignableFrom(binaryAssetItem.Type))
{ {
if (hit is StaticModelNode staticModelNode) if (hit is StaticModelNode staticModelNode)
@@ -769,65 +750,11 @@ namespace FlaxEditor.Viewport
} }
return; return;
} }
if (typeof(SkinnedModel).IsAssignableFrom(binaryAssetItem.Type))
{
var model = FlaxEngine.Content.LoadAsync<SkinnedModel>(item.ID);
var actor = new AnimatedModel
{
Name = item.ShortName,
SkinnedModel = model
};
Spawn(actor, ref hitLocation);
return;
}
if (typeof(Model).IsAssignableFrom(binaryAssetItem.Type))
{
var model = FlaxEngine.Content.LoadAsync<Model>(item.ID);
var actor = new StaticModel
{
Name = item.ShortName,
Model = model
};
Spawn(actor, ref hitLocation);
return;
}
if (binaryAssetItem.IsOfType<CollisionData>())
{
var collisionData = FlaxEngine.Content.LoadAsync<CollisionData>(item.ID);
var actor = new MeshCollider
{
Name = item.ShortName,
CollisionData = collisionData
};
Spawn(actor, ref hitLocation);
return;
}
if (typeof(AudioClip).IsAssignableFrom(binaryAssetItem.Type))
{
var clip = FlaxEngine.Content.LoadAsync<AudioClip>(item.ID);
var actor = new AudioSource
{
Name = item.ShortName,
Clip = clip
};
Spawn(actor, ref hitLocation);
return;
}
if (typeof(Prefab).IsAssignableFrom(binaryAssetItem.Type))
{
var prefab = FlaxEngine.Content.LoadAsync<Prefab>(item.ID);
var actor = PrefabManager.SpawnPrefab(prefab, null);
actor.Name = item.ShortName;
Spawn(actor, ref hitLocation);
return;
}
} }
if (item is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
{ {
var actor = (Actor)visualScriptItem.ScriptType.CreateInstance(); var actor = item.OnEditorDrop(this);
actor.Name = item.ShortName; actor.Name = item.ShortName;
Spawn(actor, ref hitLocation); Spawn(actor, ref hitLocation);
return;
} }
} }