diff --git a/Content/Shaders/GlobalSignDistanceField.flax b/Content/Shaders/GlobalSignDistanceField.flax
index 18f653f86..0e94c5c06 100644
--- a/Content/Shaders/GlobalSignDistanceField.flax
+++ b/Content/Shaders/GlobalSignDistanceField.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2c8aa181a814d69b15ffec6493a71a6f42ae816ce04f7803cff2d5073b4b3c4f
-size 11790
+oid sha256:e075583620e62407503c73f52487c204ddcad421e80fa621aebd55af1cfb08d5
+size 11798
diff --git a/GenerateProjectFiles.bat b/GenerateProjectFiles.bat
index 622939c34..28970a203 100644
--- a/GenerateProjectFiles.bat
+++ b/GenerateProjectFiles.bat
@@ -15,7 +15,7 @@ if errorlevel 1 goto BuildToolFailed
:: Build bindings for all editor configurations
echo Building C# bindings...
-Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor,FlaxGame
+Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor
popd
echo Done!
diff --git a/GenerateProjectFiles.command b/GenerateProjectFiles.command
index 5ee5c0783..a42121252 100755
--- a/GenerateProjectFiles.command
+++ b/GenerateProjectFiles.command
@@ -14,4 +14,4 @@ bash ./Development/Scripts/Mac/CallBuildTool.sh --genproject "$@"
# Build bindings for all editor configurations
echo Building C# bindings...
# TODO: Detect the correct architecture here
-Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor,FlaxGame
+Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor
diff --git a/GenerateProjectFiles.sh b/GenerateProjectFiles.sh
index dceb8abe8..76d96c7ef 100755
--- a/GenerateProjectFiles.sh
+++ b/GenerateProjectFiles.sh
@@ -14,4 +14,4 @@ bash ./Development/Scripts/Linux/CallBuildTool.sh --genproject "$@"
# Build bindings for all editor configurations
echo Building C# bindings...
# TODO: Detect the correct architecture here
-Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor,FlaxGame
+Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor
diff --git a/Source/Editor/Content/Proxy/SceneProxy.cs b/Source/Editor/Content/Proxy/SceneProxy.cs
index 78d88b440..004c2aed7 100644
--- a/Source/Editor/Content/Proxy/SceneProxy.cs
+++ b/Source/Editor/Content/Proxy/SceneProxy.cs
@@ -30,6 +30,12 @@ namespace FlaxEditor.Content
return item is SceneItem;
}
+ ///
+ public override bool AcceptsAsset(string typeName, string path)
+ {
+ return (typeName == Scene.AssetTypename || typeName == Scene.EditorPickerTypename) && path.EndsWith(FileExtension, StringComparison.OrdinalIgnoreCase);
+ }
+
///
public override bool CanCreate(ContentFolder targetLocation)
{
diff --git a/Source/Editor/Content/Thumbnails/ThumbnailsModule.cs b/Source/Editor/Content/Thumbnails/ThumbnailsModule.cs
index 160c783ed..1282e4daa 100644
--- a/Source/Editor/Content/Thumbnails/ThumbnailsModule.cs
+++ b/Source/Editor/Content/Thumbnails/ThumbnailsModule.cs
@@ -406,18 +406,16 @@ namespace FlaxEditor.Content.Thumbnails
for (int i = 0; i < maxChecks; i++)
{
var request = _requests[i];
-
try
{
if (request.IsReady)
- {
return request;
- }
}
catch (Exception ex)
{
- Editor.LogWarning(ex);
Editor.LogWarning($"Failed to prepare thumbnail rendering for {request.Item.ShortName}.");
+ Editor.LogWarning(ex);
+ _requests.RemoveAt(i--);
}
}
@@ -515,7 +513,6 @@ namespace FlaxEditor.Content.Thumbnails
for (int i = 0; i < checks; i++)
{
var request = _requests[i];
-
try
{
if (request.IsReady)
@@ -529,8 +526,9 @@ namespace FlaxEditor.Content.Thumbnails
}
catch (Exception ex)
{
- Editor.LogWarning(ex);
Editor.LogWarning($"Failed to prepare thumbnail rendering for {request.Item.ShortName}.");
+ Editor.LogWarning(ex);
+ _requests.RemoveAt(i--);
}
}
diff --git a/Source/Editor/Modules/ContentDatabaseModule.cs b/Source/Editor/Modules/ContentDatabaseModule.cs
index b1de78456..80f419a6f 100644
--- a/Source/Editor/Modules/ContentDatabaseModule.cs
+++ b/Source/Editor/Modules/ContentDatabaseModule.cs
@@ -811,10 +811,9 @@ namespace FlaxEditor.Modules
{
if (node == null)
return;
-
- // Temporary data
var folder = node.Folder;
var path = folder.Path;
+ var canHaveAssets = node.CanHaveAssets;
if (_isDuringFastSetup)
{
@@ -833,20 +832,38 @@ namespace FlaxEditor.Modules
var child = folder.Children[i];
if (!child.Exists)
{
- // Send info
+ // Item doesn't exist anymore
Editor.Log(string.Format($"Content item \'{child.Path}\' has been removed"));
-
- // Destroy it
Delete(child, false);
-
i--;
}
+ else if (canHaveAssets && child is AssetItem childAsset)
+ {
+ // Check if asset type doesn't match the item proxy (eg. item reimported as Material Instance instead of Material)
+ if (FlaxEngine.Content.GetAssetInfo(child.Path, out var assetInfo))
+ {
+ bool changed = assetInfo.ID != childAsset.ID;
+ if (!changed && assetInfo.TypeName != childAsset.TypeName)
+ {
+ // Use proxy check (eg. scene asset might accept different typename than AssetInfo reports)
+ var proxy = GetAssetProxy(childAsset.TypeName, child.Path);
+ if (proxy == null)
+ proxy = GetAssetProxy(assetInfo.TypeName, child.Path);
+ changed = !proxy.AcceptsAsset(assetInfo.TypeName, child.Path);
+ }
+ if (changed)
+ {
+ OnAssetTypeInfoChanged(childAsset, ref assetInfo);
+ i--;
+ }
+ }
+ }
}
}
// Find files
var files = Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly);
- if (node.CanHaveAssets)
+ if (canHaveAssets)
{
LoadAssets(node, files);
}
@@ -1157,19 +1174,8 @@ namespace FlaxEditor.Modules
// For eg. change texture to sprite atlas on reimport
if (binaryAssetItem.TypeName != assetInfo.TypeName)
{
- // Asset type has been changed!
- Editor.LogWarning(string.Format("Asset \'{0}\' changed type from {1} to {2}", item.Path, binaryAssetItem.TypeName, assetInfo.TypeName));
- Editor.Windows.CloseAllEditors(item);
-
- // Remove this item from the database and some related data
var toRefresh = binaryAssetItem.ParentFolder;
- binaryAssetItem.Dispose();
- toRefresh.Children.Remove(binaryAssetItem);
- if (!binaryAssetItem.HasDefaultThumbnail)
- {
- // Delete old thumbnail and remove it from the cache
- Editor.Instance.Thumbnails.DeletePreview(binaryAssetItem);
- }
+ OnAssetTypeInfoChanged(binaryAssetItem, ref assetInfo);
// Refresh the parent folder to find the new asset (it should have different type or some other format)
RefreshFolder(toRefresh, false);
@@ -1186,6 +1192,23 @@ namespace FlaxEditor.Modules
}
}
+ private void OnAssetTypeInfoChanged(AssetItem assetItem, ref AssetInfo assetInfo)
+ {
+ // Asset type has been changed!
+ Editor.LogWarning(string.Format("Asset \'{0}\' changed type from {1} to {2}", assetItem.Path, assetItem.TypeName, assetInfo.TypeName));
+ Editor.Windows.CloseAllEditors(assetItem);
+
+ // Remove this item from the database and some related data
+ assetItem.Dispose();
+ assetItem.ParentFolder.Children.Remove(assetItem);
+
+ // Delete old thumbnail and remove it from the cache
+ if (!assetItem.HasDefaultThumbnail)
+ {
+ Editor.Instance.Thumbnails.DeletePreview(assetItem);
+ }
+ }
+
internal void OnDirectoryEvent(MainContentTreeNode node, FileSystemEventArgs e)
{
// Ensure to be ready for external events
diff --git a/Source/Editor/Modules/UIModule.cs b/Source/Editor/Modules/UIModule.cs
index 492d78918..1369ecd1e 100644
--- a/Source/Editor/Modules/UIModule.cs
+++ b/Source/Editor/Modules/UIModule.cs
@@ -2,7 +2,6 @@
using System;
using System.IO;
-using System.Linq;
using System.Collections.Generic;
using FlaxEditor.Gizmo;
using FlaxEditor.GUI;
@@ -11,7 +10,6 @@ using FlaxEditor.GUI.Dialogs;
using FlaxEditor.GUI.Input;
using FlaxEditor.Progress.Handlers;
using FlaxEditor.SceneGraph;
-using FlaxEditor.SceneGraph.Actors;
using FlaxEditor.Utilities;
using FlaxEditor.Viewport.Cameras;
using FlaxEditor.Windows;
@@ -208,6 +206,7 @@ namespace FlaxEditor.Modules
_toolStripScale.Checked = gizmoMode == TransformGizmoBase.Mode.Scale;
//
_toolStripBuildScenes.Enabled = (canEditScene && !isPlayMode) || Editor.StateMachine.BuildingScenesState.IsActive;
+ _toolStripBuildScenes.Visible = Editor.Options.Options.General.BuildActions?.Length != 0;
_toolStripCook.Enabled = Editor.Windows.GameCookerWin.CanBuild(Platform.PlatformType) && !GameCooker.IsRunning;
//
var play = _toolStripPlay;
@@ -653,7 +652,7 @@ namespace FlaxEditor.Modules
cm.AddButton("Information about Flax", () => new AboutDialog().Show());
}
- private void OnOptionsChanged(FlaxEditor.Options.EditorOptions options)
+ private void OnOptionsChanged(EditorOptions options)
{
var inputOptions = options.Input;
@@ -688,6 +687,8 @@ namespace FlaxEditor.Modules
_menuToolsTakeScreenshot.ShortKeys = inputOptions.TakeScreenshot.ToString();
MainMenuShortcutKeysUpdated?.Invoke();
+
+ UpdateToolstrip();
}
private void InitToolstrip(RootControl mainWindow)
@@ -709,11 +710,11 @@ namespace FlaxEditor.Modules
_toolStripScale = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Scale32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip($"Change Gizmo tool mode to Scale ({inputOptions.ScaleMode})");
ToolStrip.AddSeparator();
- // Cook scenes
+ // Build 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 ({inputOptions.BuildScenesData})");
// 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 ({inputOptions.Play})");
+ _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.CookAndRun})");
_toolStripCook.ContextMenu = new ContextMenu();
_toolStripCook.ContextMenu.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked);
_toolStripCook.ContextMenu.AddSeparator();
diff --git a/Source/Editor/Options/GeneralOptions.cs b/Source/Editor/Options/GeneralOptions.cs
index 33124bab0..9f29f4bdb 100644
--- a/Source/Editor/Options/GeneralOptions.cs
+++ b/Source/Editor/Options/GeneralOptions.cs
@@ -117,7 +117,7 @@ namespace FlaxEditor.Options
///
/// Gets or sets the sequence of actions to perform when using Build Scenes button. Can be used to configure this as button (eg. compile code or just update navmesh).
///
- [EditorDisplay("General"), EditorOrder(200), Tooltip("The sequence of actions to perform when using Build Scenes button. Can be used to configure this as button (eg. compile code or just update navmesh).")]
+ [EditorDisplay("General"), EditorOrder(200), ExpandGroups, Tooltip("The sequence of actions to perform when using Build Scenes button. Can be used to configure this as button (eg. compile code or just update navmesh).")]
public BuildAction[] BuildActions { get; set; } =
{
BuildAction.CSG,
diff --git a/Source/Editor/Windows/Assets/AssetEditorWindow.cs b/Source/Editor/Windows/Assets/AssetEditorWindow.cs
index 0d244479c..2e048b924 100644
--- a/Source/Editor/Windows/Assets/AssetEditorWindow.cs
+++ b/Source/Editor/Windows/Assets/AssetEditorWindow.cs
@@ -388,14 +388,16 @@ namespace FlaxEditor.Windows.Assets
protected override void OnShow()
{
// Check if has no asset (but has item linked)
- if (_asset == null && _item != null)
+ var item = _item;
+ if (_asset == null && item != null)
{
// Load asset
_asset = LoadAsset();
if (_asset == null)
{
- Editor.LogError(string.Format("Cannot load asset \'{0}\' ({1})", _item.Path, typeof(T)));
+ Editor.LogError(string.Format("Cannot load asset \'{0}\' ({1})", item.Path, typeof(T)));
Close();
+ Editor.ContentDatabase.RefreshFolder(item, false);
return;
}
diff --git a/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs b/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs
index 5f1273999..3e0525fb7 100644
--- a/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs
+++ b/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs
@@ -521,8 +521,11 @@ namespace FlaxEditor.Windows.Assets
///
protected override void OnClose()
{
- // Discard unsaved changes
- _properties.DiscardChanges();
+ if (Asset)
+ {
+ // Discard unsaved changes
+ _properties.DiscardChanges();
+ }
// Cleanup
_undo.Clear();
diff --git a/Source/Engine/Content/Assets/Material.cpp b/Source/Engine/Content/Assets/Material.cpp
index 76ed34b80..276b6b1f7 100644
--- a/Source/Engine/Content/Assets/Material.cpp
+++ b/Source/Engine/Content/Assets/Material.cpp
@@ -20,6 +20,7 @@
#include "Engine/ShadersCompilation/Config.h"
#if BUILD_DEBUG
#include "Engine/Engine/Globals.h"
+#include "Engine/Scripting/BinaryModule.h"
#endif
#endif
@@ -256,7 +257,9 @@ Asset::LoadResult Material::load()
#if BUILD_DEBUG && USE_EDITOR
// Dump generated material source to the temporary file
+ BinaryModule::Locker.Lock();
source.SaveToFile(Globals::ProjectCacheFolder / TEXT("material.txt"));
+ BinaryModule::Locker.Unlock();
#endif
// Encrypt source code
diff --git a/Source/Engine/ContentImporters/ImportModelFile.cpp b/Source/Engine/ContentImporters/ImportModelFile.cpp
index b9a4f5675..b34bbfaaf 100644
--- a/Source/Engine/ContentImporters/ImportModelFile.cpp
+++ b/Source/Engine/ContentImporters/ImportModelFile.cpp
@@ -124,7 +124,8 @@ CreateAssetResult ImportModelFile::Import(CreateAssetContext& context)
// Import model file
ModelData modelData;
String errorMsg;
- String autoImportOutput = String(StringUtils::GetDirectoryName(context.TargetAssetPath)) / StringUtils::GetFileNameWithoutExtension(context.InputPath);
+ String autoImportOutput(StringUtils::GetDirectoryName(context.TargetAssetPath));
+ autoImportOutput /= options.SubAssetFolder.HasChars() ? options.SubAssetFolder.TrimTrailing() : String(StringUtils::GetFileNameWithoutExtension(context.InputPath));
if (ModelTool::ImportModel(context.InputPath, modelData, options, errorMsg, autoImportOutput))
{
LOG(Error, "Cannot import model file. {0}", errorMsg);
diff --git a/Source/Engine/Core/Collections/ChunkedArray.h b/Source/Engine/Core/Collections/ChunkedArray.h
index 38bf92fb8..b3765a9fe 100644
--- a/Source/Engine/Core/Collections/ChunkedArray.h
+++ b/Source/Engine/Core/Collections/ChunkedArray.h
@@ -100,7 +100,7 @@ public:
int32 _chunkIndex;
int32 _index;
- Iterator(ChunkedArray const* collection, const int32 index)
+ Iterator(const ChunkedArray* collection, const int32 index)
: _collection(const_cast(collection))
, _chunkIndex(index / ChunkSize)
, _index(index % ChunkSize)
@@ -122,29 +122,29 @@ public:
{
}
- public:
- FORCE_INLINE ChunkedArray* GetChunkedArray() const
+ Iterator(Iterator&& i)
+ : _collection(i._collection)
+ , _chunkIndex(i._chunkIndex)
+ , _index(i._index)
{
- return _collection;
}
+ public:
FORCE_INLINE int32 Index() const
{
return _chunkIndex * ChunkSize + _index;
}
- public:
- bool IsEnd() const
+ FORCE_INLINE bool IsEnd() const
{
- return Index() == _collection->Count();
+ return (_chunkIndex * ChunkSize + _index) == _collection->_count;
}
- bool IsNotEnd() const
+ FORCE_INLINE bool IsNotEnd() const
{
- return Index() != _collection->Count();
+ return (_chunkIndex * ChunkSize + _index) != _collection->_count;
}
- public:
FORCE_INLINE T& operator*() const
{
return _collection->_chunks[_chunkIndex]->At(_index);
@@ -155,7 +155,6 @@ public:
return &_collection->_chunks[_chunkIndex]->At(_index);
}
- public:
FORCE_INLINE bool operator==(const Iterator& v) const
{
return _collection == v._collection && _chunkIndex == v._chunkIndex && _index == v._index;
@@ -166,17 +165,22 @@ public:
return _collection != v._collection || _chunkIndex != v._chunkIndex || _index != v._index;
}
- public:
+ Iterator& operator=(const Iterator& v)
+ {
+ _collection = v._collection;
+ _chunkIndex = v._chunkIndex;
+ _index = v._index;
+ return *this;
+ }
+
Iterator& operator++()
{
// Check if it is not at end
- const int32 end = _collection->Count();
- if (Index() != end)
+ if ((_chunkIndex * ChunkSize + _index) != _collection->_count)
{
// Move forward within chunk
_index++;
- // Check if need to change chunk
if (_index == ChunkSize && _chunkIndex < _collection->_chunks.Count() - 1)
{
// Move to next chunk
@@ -189,9 +193,9 @@ public:
Iterator operator++(int)
{
- Iterator temp = *this;
- ++temp;
- return temp;
+ Iterator i = *this;
+ ++i;
+ return i;
}
Iterator& operator--()
@@ -199,7 +203,6 @@ public:
// Check if it's not at beginning
if (_index != 0 || _chunkIndex != 0)
{
- // Check if need to change chunk
if (_index == 0)
{
// Move to previous chunk
@@ -217,9 +220,9 @@ public:
Iterator operator--(int)
{
- Iterator temp = *this;
- --temp;
- return temp;
+ Iterator i = *this;
+ --i;
+ return i;
}
};
@@ -294,7 +297,7 @@ public:
{
if (IsEmpty())
return;
- ASSERT(i.GetChunkedArray() == this);
+ ASSERT(i._collection == this);
ASSERT(i._chunkIndex < _chunks.Count() && i._index < ChunkSize);
ASSERT(i.Index() < Count());
@@ -432,11 +435,31 @@ public:
Iterator End() const
{
- return Iterator(this, Count());
+ return Iterator(this, _count);
}
Iterator IteratorAt(int32 index) const
{
return Iterator(this, index);
}
+
+ FORCE_INLINE Iterator begin()
+ {
+ return Iterator(this, 0);
+ }
+
+ FORCE_INLINE Iterator end()
+ {
+ return Iterator(this, _count);
+ }
+
+ FORCE_INLINE const Iterator begin() const
+ {
+ return Iterator(this, 0);
+ }
+
+ FORCE_INLINE const Iterator end() const
+ {
+ return Iterator(this, _count);
+ }
};
diff --git a/Source/Engine/Core/Types/Span.h b/Source/Engine/Core/Types/Span.h
index e0518ec77..b51c858ec 100644
--- a/Source/Engine/Core/Types/Span.h
+++ b/Source/Engine/Core/Types/Span.h
@@ -107,6 +107,26 @@ public:
ASSERT(index >= 0 && index < _length);
return _data[index];
}
+
+ FORCE_INLINE T* begin()
+ {
+ return _data;
+ }
+
+ FORCE_INLINE T* end()
+ {
+ return _data + _length;
+ }
+
+ FORCE_INLINE const T* begin() const
+ {
+ return _data;
+ }
+
+ FORCE_INLINE const T* end() const
+ {
+ return _data + _length;
+ }
};
template
diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp
index 82765f151..898139ce7 100644
--- a/Source/Engine/Foliage/Foliage.cpp
+++ b/Source/Engine/Foliage/Foliage.cpp
@@ -634,15 +634,12 @@ void Foliage::RemoveFoliageType(int32 index)
int32 Foliage::GetFoliageTypeInstancesCount(int32 index) const
{
PROFILE_CPU();
-
int32 result = 0;
-
- for (auto i = Instances.Begin(); i.IsNotEnd(); i++)
+ for (auto i = Instances.Begin(); i.IsNotEnd(); ++i)
{
if (i->Type == index)
result++;
}
-
return result;
}
diff --git a/Source/Engine/Particles/ParticleEmitter.cpp b/Source/Engine/Particles/ParticleEmitter.cpp
index 20e4c0490..ea1161c6b 100644
--- a/Source/Engine/Particles/ParticleEmitter.cpp
+++ b/Source/Engine/Particles/ParticleEmitter.cpp
@@ -19,6 +19,7 @@
#include "Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.h"
#if BUILD_DEBUG
#include "Engine/Engine/Globals.h"
+#include "Engine/Scripting/BinaryModule.h"
#endif
#endif
#if COMPILE_WITH_GPU_PARTICLES
@@ -185,7 +186,9 @@ Asset::LoadResult ParticleEmitter::load()
#if BUILD_DEBUG && USE_EDITOR
// Dump generated shader source to the temporary file
+ BinaryModule::Locker.Lock();
source.SaveToFile(Globals::ProjectCacheFolder / TEXT("particle_emitter.txt"));
+ BinaryModule::Locker.Unlock();
#endif
// Encrypt source code
diff --git a/Source/Engine/Render2D/SpriteAtlas.cpp b/Source/Engine/Render2D/SpriteAtlas.cpp
index 0e0aa071f..ac711b8b8 100644
--- a/Source/Engine/Render2D/SpriteAtlas.cpp
+++ b/Source/Engine/Render2D/SpriteAtlas.cpp
@@ -47,10 +47,16 @@ int32 SpriteAtlas::GetSpritesCount() const
Sprite SpriteAtlas::GetSprite(int32 index) const
{
- CHECK_RETURN(index >= 0 && index < Sprites.Count(), Sprite())
+ CHECK_RETURN(index >= 0 && index < Sprites.Count(), Sprite());
return Sprites.Get()[index];
}
+void SpriteAtlas::GetSpriteArea(int32 index, Rectangle& result) const
+{
+ CHECK(index >= 0 && index < Sprites.Count());
+ result = Sprites.Get()[index].Area;
+}
+
void SpriteAtlas::SetSprite(int32 index, const Sprite& value)
{
CHECK(index >= 0 && index < Sprites.Count());
diff --git a/Source/Engine/Render2D/SpriteAtlas.cs b/Source/Engine/Render2D/SpriteAtlas.cs
index b3796ffd3..93cdf68b2 100644
--- a/Source/Engine/Render2D/SpriteAtlas.cs
+++ b/Source/Engine/Render2D/SpriteAtlas.cs
@@ -70,7 +70,13 @@ namespace FlaxEngine
[NoSerialize]
public Float2 Size
{
- get => Area.Size * Atlas.Size;
+ get
+ {
+ if (Atlas == null)
+ throw new InvalidOperationException("Cannot use invalid sprite.");
+ Atlas.GetSpriteArea(Index, out var area);
+ return area.Size * Atlas.Size;
+ }
set
{
var area = Area;
@@ -89,7 +95,8 @@ namespace FlaxEngine
{
if (Atlas == null)
throw new InvalidOperationException("Cannot use invalid sprite.");
- return Atlas.GetSprite(Index).Area;
+ Atlas.GetSpriteArea(Index, out var area);
+ return area;
}
set
{
diff --git a/Source/Engine/Render2D/SpriteAtlas.h b/Source/Engine/Render2D/SpriteAtlas.h
index 6fcda5162..533440c68 100644
--- a/Source/Engine/Render2D/SpriteAtlas.h
+++ b/Source/Engine/Render2D/SpriteAtlas.h
@@ -120,6 +120,14 @@ public:
/// The sprite data.
API_FUNCTION() Sprite GetSprite(int32 index) const;
+ ///
+ /// Gets the sprite area.
+ ///
+ /// The index.
+ /// The output sprite area.
+ /// The sprite data.
+ API_FUNCTION() void GetSpriteArea(int32 index, API_PARAM(Out) Rectangle& result) const;
+
///
/// Sets the sprite data.
///
diff --git a/Source/Engine/Tools/ModelTool/ModelTool.cpp b/Source/Engine/Tools/ModelTool/ModelTool.cpp
index b703b47d1..116f63407 100644
--- a/Source/Engine/Tools/ModelTool/ModelTool.cpp
+++ b/Source/Engine/Tools/ModelTool/ModelTool.cpp
@@ -22,6 +22,7 @@
#include "Engine/Core/Types/DateTime.h"
#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Core/Types/Pair.h"
+#include "Engine/Core/Types/Variant.h"
#include "Engine/Graphics/Models/SkeletonUpdater.h"
#include "Engine/Graphics/Models/SkeletonMapping.h"
#include "Engine/Core/Utilities.h"
@@ -396,6 +397,7 @@ void ModelTool::Options::Serialize(SerializeStream& stream, const void* otherObj
SERIALIZE(SDFResolution);
SERIALIZE(SplitObjects);
SERIALIZE(ObjectIndex);
+ SERIALIZE(SubAssetFolder);
}
void ModelTool::Options::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
@@ -441,6 +443,7 @@ void ModelTool::Options::Deserialize(DeserializeStream& stream, ISerializeModifi
DESERIALIZE(SDFResolution);
DESERIALIZE(SplitObjects);
DESERIALIZE(ObjectIndex);
+ DESERIALIZE(SubAssetFolder);
// [Deprecated on 23.11.2021, expires on 21.11.2023]
int32 AnimationIndex = -1;
@@ -744,6 +747,32 @@ void MeshOptDeallocate(void* ptr)
Allocator::Free(ptr);
}
+void TrySetupMaterialParameter(MaterialInstance* instance, Span paramNames, const Variant& value, MaterialParameterType type)
+{
+ for (const Char* name : paramNames)
+ {
+ for (MaterialParameter& param : instance->Params)
+ {
+ const MaterialParameterType paramType = param.GetParameterType();
+ if (type != paramType)
+ {
+ if (type == MaterialParameterType::Color)
+ {
+ if (paramType != MaterialParameterType::Vector3 ||
+ paramType != MaterialParameterType::Vector4)
+ continue;
+ }
+ else
+ continue;
+ }
+ if (StringUtils::CompareIgnoreCase(name, param.GetName().Get()) != 0)
+ continue;
+ param.SetValue(value);
+ return;
+ }
+ }
+}
+
bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& options, String& errorMsg, const String& autoImportOutput)
{
LOG(Info, "Importing model from \'{0}\'", path);
@@ -1014,9 +1043,18 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op
{
// Create material instance
AssetsImportingManager::Create(AssetsImportingManager::CreateMaterialInstanceTag, assetPath, material.AssetID);
- if (MaterialInstance* materialInstance = Content::Load(assetPath))
+ if (auto* materialInstance = Content::Load(assetPath))
{
materialInstance->SetBaseMaterial(options.InstanceToImportAs);
+
+ // Customize base material based on imported material (blind guess based on the common names used in materials)
+ const Char* diffuseColorNames[] = { TEXT("color"), TEXT("col"), TEXT("diffuse"), TEXT("basecolor"), TEXT("base color") };
+ TrySetupMaterialParameter(materialInstance, ToSpan(diffuseColorNames, ARRAY_COUNT(diffuseColorNames)), material.Diffuse.Color, MaterialParameterType::Color);
+ const Char* emissiveColorNames[] = { TEXT("emissive"), TEXT("emission"), TEXT("light") };
+ TrySetupMaterialParameter(materialInstance, ToSpan(emissiveColorNames, ARRAY_COUNT(emissiveColorNames)), material.Emissive.Color, MaterialParameterType::Color);
+ const Char* opacityValueNames[] = { TEXT("opacity"), TEXT("alpha") };
+ TrySetupMaterialParameter(materialInstance, ToSpan(opacityValueNames, ARRAY_COUNT(opacityValueNames)), material.Opacity.Value, MaterialParameterType::Float);
+
materialInstance->Save();
}
else
diff --git a/Source/Engine/Tools/ModelTool/ModelTool.h b/Source/Engine/Tools/ModelTool/ModelTool.h
index 36bb9b12c..bad10b86e 100644
--- a/Source/Engine/Tools/ModelTool/ModelTool.h
+++ b/Source/Engine/Tools/ModelTool/ModelTool.h
@@ -370,6 +370,12 @@ public:
API_FIELD(Attributes="EditorOrder(2010), EditorDisplay(\"Splitting\")")
int32 ObjectIndex = -1;
+ public: // Other
+
+ // If specified, will be used as sub-directory name for automatically imported sub assets such as textures and materials. Set to whitespace (single space) to import to the same directory.
+ API_FIELD(Attributes="EditorOrder(3030), EditorDisplay(\"Other\")")
+ String SubAssetFolder = TEXT("");
+
// Runtime data for objects splitting during import (used internally)
void* SplitContext = nullptr;
Function OnSplitImport;
diff --git a/Source/Shaders/GlobalSignDistanceField.shader b/Source/Shaders/GlobalSignDistanceField.shader
index 3d4f7dd46..bc4f272fc 100644
--- a/Source/Shaders/GlobalSignDistanceField.shader
+++ b/Source/Shaders/GlobalSignDistanceField.shader
@@ -211,7 +211,7 @@ float SampleSDF(uint3 voxelCoordMip, int3 offset)
float result = GlobalSDFTex[voxelCoordMip].r;
// Extend by distance to the sampled texel location
- float distanceInWorldUnits = length(offset) * (MaxDistance / (float)GenerateMipTexResolution);
+ float distanceInWorldUnits = length((float3)offset) * (MaxDistance / (float)GenerateMipTexResolution);
float distanceToVoxel = distanceInWorldUnits / MaxDistance;
result = CombineDistanceToSDF(result, distanceToVoxel);