diff --git a/Source/Editor/Windows/Assets/TextureWindow.cs b/Source/Editor/Windows/Assets/TextureWindow.cs
index 481c48f47..0ae8abe6d 100644
--- a/Source/Editor/Windows/Assets/TextureWindow.cs
+++ b/Source/Editor/Windows/Assets/TextureWindow.cs
@@ -4,7 +4,10 @@ using System.Xml;
using FlaxEditor.Content;
using FlaxEditor.Content.Import;
using FlaxEditor.CustomEditors;
+using FlaxEditor.CustomEditors.Dedicated;
using FlaxEditor.CustomEditors.Editors;
+using FlaxEditor.GUI;
+using FlaxEditor.Scripting;
using FlaxEditor.Viewport.Previews;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -18,47 +21,57 @@ namespace FlaxEditor.Windows.Assets
///
public sealed class TextureWindow : AssetEditorWindowBase
{
+ private sealed class ProxyEditor : GenericEditor
+ {
+ public override void Initialize(LayoutElementsContainer layout)
+ {
+ var window = ((PropertiesProxy)Values[0])._window;
+ var texture = window?.Asset;
+ if (texture == null || !texture.IsLoaded)
+ {
+ layout.Label("Loading...", TextAlignment.Center);
+ return;
+ }
+
+ // Texture info
+ var general = layout.Group("General");
+ general.Label("Format: " + texture.Format);
+ general.Label(string.Format("Size: {0}x{1}", texture.Width, texture.Height));
+ general.Label("Mip levels: " + texture.MipLevels);
+ general.Label("Memory usage: " + Utilities.Utils.FormatBytesCount(texture.TotalMemoryUsage));
+
+ // Texture properties
+ var properties = layout.Group("Properties");
+ var textureGroup = new CustomValueContainer(new ScriptType(typeof(int)), texture.TextureGroup,
+ (instance, index) => texture.TextureGroup,
+ (instance, index, value) =>
+ {
+ texture.TextureGroup = (int)value;
+ window.MarkAsEdited();
+ });
+ properties.Property("Texture Group", textureGroup, new TextureGroupEditor(), "The texture group used by this texture.");
+
+ // Import settings
+ base.Initialize(layout);
+
+ // Reimport
+ layout.Space(10);
+ var reimportButton = layout.Button("Reimport");
+ reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
+ }
+ }
+
///
/// The texture properties proxy object.
///
[CustomEditor(typeof(ProxyEditor))]
private sealed class PropertiesProxy
{
- private TextureWindow _window;
+ internal TextureWindow _window;
[EditorOrder(1000), EditorDisplay("Import Settings", EditorDisplayAttribute.InlineStyle)]
public TextureImportSettings ImportSettings = new TextureImportSettings();
- public sealed class ProxyEditor : GenericEditor
- {
- public override void Initialize(LayoutElementsContainer layout)
- {
- var window = ((PropertiesProxy)Values[0])._window;
- if (window == null)
- {
- layout.Label("Loading...", TextAlignment.Center);
- return;
- }
-
- // Texture properties
- {
- var texture = window.Asset;
-
- var group = layout.Group("General");
- group.Label("Format: " + texture.Format);
- group.Label(string.Format("Size: {0}x{1}", texture.Width, texture.Height));
- group.Label("Mip levels: " + texture.MipLevels);
- group.Label("Memory usage: " + Utilities.Utils.FormatBytesCount(texture.TotalMemoryUsage));
- }
-
- base.Initialize(layout);
-
- layout.Space(10);
- var reimportButton = layout.Button("Reimport");
- reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
- }
- }
-
///
/// Gathers parameters from the specified texture.
///
@@ -110,7 +123,7 @@ namespace FlaxEditor.Windows.Assets
private readonly SplitPanel _split;
private readonly TexturePreview _preview;
private readonly CustomEditorPresenter _propertiesEditor;
-
+ private readonly ToolStripButton _saveButton;
private readonly PropertiesProxy _properties;
private bool _isWaitingForLoad;
@@ -140,6 +153,7 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.Select(_properties);
// Toolstrip
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddButton(Editor.Icons.Import64, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
_toolstrip.AddSeparator();
_toolstrip.AddButton(Editor.Icons.CenterView64, _preview.CenterView).LinkTooltip("Center view");
@@ -173,6 +187,14 @@ namespace FlaxEditor.Windows.Assets
_isWaitingForLoad = true;
}
+ ///
+ protected override void UpdateToolstrip()
+ {
+ _saveButton.Enabled = IsEdited;
+
+ base.UpdateToolstrip();
+ }
+
///
protected override void OnClose()
{
@@ -182,6 +204,21 @@ namespace FlaxEditor.Windows.Assets
base.OnClose();
}
+ ///
+ public override void Save()
+ {
+ if (!IsEdited)
+ return;
+
+ if (Asset.Save())
+ {
+ Editor.LogError("Cannot save asset.");
+ return;
+ }
+
+ ClearEditedFlag();
+ }
+
///
public override void Update(float deltaTime)
{
diff --git a/Source/Engine/Audio/AudioClip.cpp b/Source/Engine/Audio/AudioClip.cpp
index 3213850d3..7c1945803 100644
--- a/Source/Engine/Audio/AudioClip.cpp
+++ b/Source/Engine/Audio/AudioClip.cpp
@@ -401,7 +401,7 @@ Asset::LoadResult AudioClip::load()
if (AudioHeader.Streamable)
{
// Do nothing because data streaming starts when any AudioSource requests the data
- startStreaming(false);
+ StartStreaming(false);
return LoadResult::Ok;
}
@@ -450,7 +450,7 @@ Asset::LoadResult AudioClip::load()
void AudioClip::unload(bool isReloading)
{
- stopStreaming();
+ StopStreaming();
StreamingQueue.Clear();
if (Buffers.HasItems())
{
diff --git a/Source/Engine/Content/Asset.cpp b/Source/Engine/Content/Asset.cpp
index e8536f58d..5436cb6b9 100644
--- a/Source/Engine/Content/Asset.cpp
+++ b/Source/Engine/Content/Asset.cpp
@@ -111,6 +111,11 @@ Asset::Asset(const SpawnParams& params, const AssetInfo* info)
{
}
+int32 Asset::GetReferencesCount() const
+{
+ return (int32)Platform::AtomicRead(const_cast(&_refCount));
+}
+
String Asset::ToString() const
{
return String::Format(TEXT("{0}, {1}, {2}"), GetTypeName(), GetID(), GetPath());
@@ -435,6 +440,15 @@ void Asset::startLoading()
_loadingTask->Start();
}
+void Asset::releaseStorage()
+{
+}
+
+bool Asset::IsInternalType() const
+{
+ return false;
+}
+
bool Asset::onLoad(LoadAssetTask* task)
{
// It may fail when task is cancelled and new one is created later (don't crash but just end with an error)
diff --git a/Source/Engine/Content/Asset.h b/Source/Engine/Content/Asset.h
index a831ee773..3d4ca2789 100644
--- a/Source/Engine/Content/Asset.h
+++ b/Source/Engine/Content/Asset.h
@@ -82,10 +82,7 @@ public:
///
/// Gets asset's reference count. Asset will be automatically unloaded when this reaches zero.
///
- API_PROPERTY() int32 GetReferencesCount() const
- {
- return (int32)Platform::AtomicRead(const_cast(&_refCount));
- }
+ API_PROPERTY() int32 GetReferencesCount() const;
///
/// Adds reference to that asset.
@@ -213,9 +210,7 @@ protected:
///
/// Releases the storage file/container handle to prevent issues when renaming or moving the asset.
///
- virtual void releaseStorage()
- {
- }
+ virtual void releaseStorage();
///
/// Loads asset
@@ -231,10 +226,7 @@ protected:
protected:
- virtual bool IsInternalType() const
- {
- return false;
- }
+ virtual bool IsInternalType() const;
bool onLoad(LoadAssetTask* task);
void onLoaded();
diff --git a/Source/Engine/Content/Assets/Model.cpp b/Source/Engine/Content/Assets/Model.cpp
index dd9c484e1..d337c62a2 100644
--- a/Source/Engine/Content/Assets/Model.cpp
+++ b/Source/Engine/Content/Assets/Model.cpp
@@ -570,7 +570,7 @@ bool Model::Init(const Span& meshesCountPerLod)
}
// Dispose previous data and disable streaming (will start data uploading tasks manually)
- stopStreaming();
+ StopStreaming();
// Setup
MaterialSlots.Resize(1);
@@ -827,7 +827,7 @@ Asset::LoadResult Model::load()
#endif
// Request resource streaming
- startStreaming(true);
+ StartStreaming(true);
return LoadResult::Ok;
}
diff --git a/Source/Engine/Content/Assets/SkinnedModel.cpp b/Source/Engine/Content/Assets/SkinnedModel.cpp
index b98ba2e57..3860aeda8 100644
--- a/Source/Engine/Content/Assets/SkinnedModel.cpp
+++ b/Source/Engine/Content/Assets/SkinnedModel.cpp
@@ -670,7 +670,7 @@ bool SkinnedModel::Init(const Span& meshesCountPerLod)
}
// Dispose previous data and disable streaming (will start data uploading tasks manually)
- stopStreaming();
+ StopStreaming();
// Setup
MaterialSlots.Resize(1);
@@ -973,7 +973,7 @@ Asset::LoadResult SkinnedModel::load()
}
// Request resource streaming
- startStreaming(true);
+ StartStreaming(true);
return LoadResult::Ok;
}
diff --git a/Source/Engine/Content/Assets/Texture.cpp b/Source/Engine/Content/Assets/Texture.cpp
index 23dbff0e2..08100d4b5 100644
--- a/Source/Engine/Content/Assets/Texture.cpp
+++ b/Source/Engine/Content/Assets/Texture.cpp
@@ -17,6 +17,16 @@ Texture::Texture(const SpawnParams& params, const AssetInfo* info)
{
}
+TextureFormatType Texture::GetFormatType() const
+{
+ return _texture.GetFormatType();
+}
+
+bool Texture::IsNormalMap() const
+{
+ return _texture.GetFormatType() == TextureFormatType::NormalMap;
+}
+
#if USE_EDITOR
bool Texture::Save(const StringView& path, const InitData* customData)
diff --git a/Source/Engine/Content/Assets/Texture.h b/Source/Engine/Content/Assets/Texture.h
index afefc59d2..2b0a6c127 100644
--- a/Source/Engine/Content/Assets/Texture.h
+++ b/Source/Engine/Content/Assets/Texture.h
@@ -10,23 +10,16 @@
API_CLASS(NoSpawn) class FLAXENGINE_API Texture : public TextureBase
{
DECLARE_BINARY_ASSET_HEADER(Texture, TexturesSerializedVersion);
-public:
///
/// Gets the texture format type.
///
- FORCE_INLINE TextureFormatType GetFormatType() const
- {
- return _texture.GetFormatType();
- }
+ TextureFormatType GetFormatType() const;
///
/// Returns true if texture is a normal map.
///
- API_PROPERTY() FORCE_INLINE bool IsNormalMap() const
- {
- return GetFormatType() == TextureFormatType::NormalMap;
- }
+ API_PROPERTY() bool IsNormalMap() const;
public:
diff --git a/Source/Engine/Graphics/Textures/StreamingTexture.cpp b/Source/Engine/Graphics/Textures/StreamingTexture.cpp
index f4bd6c082..54063f536 100644
--- a/Source/Engine/Graphics/Textures/StreamingTexture.cpp
+++ b/Source/Engine/Graphics/Textures/StreamingTexture.cpp
@@ -117,7 +117,7 @@ bool StreamingTexture::Create(const TextureHeader& header)
#else
bool isDynamic = false;
#endif
- startStreaming(isDynamic);
+ StartStreaming(isDynamic);
return false;
}
diff --git a/Source/Engine/Graphics/Textures/StreamingTexture.h b/Source/Engine/Graphics/Textures/StreamingTexture.h
index 3aa8fee28..2317c52db 100644
--- a/Source/Engine/Graphics/Textures/StreamingTexture.h
+++ b/Source/Engine/Graphics/Textures/StreamingTexture.h
@@ -11,6 +11,7 @@
///
class FLAXENGINE_API StreamingTexture : public Object, public StreamableResource
{
+ friend class TextureBase;
friend class StreamTextureMipTask;
friend class StreamTextureResizeTask;
protected:
@@ -60,7 +61,6 @@ public:
///
/// Gets total texture width (in texels)
///
- /// Texture width
FORCE_INLINE int32 TotalWidth() const
{
return _header.Width;
diff --git a/Source/Engine/Graphics/Textures/TextureBase.cpp b/Source/Engine/Graphics/Textures/TextureBase.cpp
index 59acc488e..d9aa392cf 100644
--- a/Source/Engine/Graphics/Textures/TextureBase.cpp
+++ b/Source/Engine/Graphics/Textures/TextureBase.cpp
@@ -97,6 +97,20 @@ uint64 TextureBase::GetTotalMemoryUsage() const
return _texture.GetTotalMemoryUsage();
}
+int32 TextureBase::GetTextureGroup() const
+{
+ return _texture._header.TextureGroup;
+}
+
+void TextureBase::SetTextureGroup(int32 textureGroup)
+{
+ if (_texture._header.TextureGroup != textureGroup)
+ {
+ _texture._header.TextureGroup = textureGroup;
+ _texture.RequestStreamingUpdate();
+ }
+}
+
BytesContainer TextureBase::GetMipData(int32 mipIndex, int32& rowPitch, int32& slicePitch)
{
BytesContainer result;
@@ -114,7 +128,6 @@ BytesContainer TextureBase::GetMipData(int32 mipIndex, int32& rowPitch, int32& s
}
else
{
- // Wait for the asset header to be loaded
if (WaitForLoaded())
return result;
@@ -127,7 +140,7 @@ BytesContainer TextureBase::GetMipData(int32 mipIndex, int32& rowPitch, int32& s
slicePitch = slicePitch1;
// Ensure to have chunk loaded
- if (LoadChunk(calculateChunkIndex(mipIndex)))
+ if (LoadChunk(CalculateChunkIndex(mipIndex)))
return result;
}
@@ -261,7 +274,7 @@ bool TextureBase::Init(void* ptr)
return Init(initData);
}
-int32 TextureBase::calculateChunkIndex(int32 mipIndex) const
+int32 TextureBase::CalculateChunkIndex(int32 mipIndex) const
{
// Mips are in 0-13 chunks
return mipIndex;
@@ -287,7 +300,7 @@ Task* TextureBase::RequestMipDataAsync(int32 mipIndex)
if (_customData)
return nullptr;
- auto chunkIndex = calculateChunkIndex(mipIndex);
+ auto chunkIndex = CalculateChunkIndex(mipIndex);
return (Task*)_parent->RequestChunkDataAsync(chunkIndex);
}
@@ -304,7 +317,7 @@ void TextureBase::GetMipData(int32 mipIndex, BytesContainer& data) const
return;
}
- auto chunkIndex = calculateChunkIndex(mipIndex);
+ auto chunkIndex = CalculateChunkIndex(mipIndex);
_parent->GetChunkData(chunkIndex, data);
}
@@ -316,7 +329,7 @@ void TextureBase::GetMipDataWithLoading(int32 mipIndex, BytesContainer& data) co
return;
}
- const auto chunkIndex = calculateChunkIndex(mipIndex);
+ const auto chunkIndex = CalculateChunkIndex(mipIndex);
_parent->LoadChunk(chunkIndex);
_parent->GetChunkData(chunkIndex, data);
}
@@ -399,8 +412,6 @@ bool TextureBase::InitData::GenerateMip(int32 mipIndex, bool linear)
// Allocate data
const int32 dstMipWidth = Math::Max(1, Width >> mipIndex);
const int32 dstMipHeight = Math::Max(1, Height >> mipIndex);
- const int32 srcMipWidth = Math::Max(1, Width >> (mipIndex - 1));
- const int32 srcMipHeight = Math::Max(1, Height >> (mipIndex - 1));
const int32 pixelStride = PixelFormatExtensions::SizeInBytes(Format);
dstMip.RowPitch = dstMipWidth * pixelStride;
dstMip.SlicePitch = dstMip.RowPitch * dstMipHeight;
diff --git a/Source/Engine/Graphics/Textures/TextureBase.h b/Source/Engine/Graphics/Textures/TextureBase.h
index bdc551397..2bb0042df 100644
--- a/Source/Engine/Graphics/Textures/TextureBase.h
+++ b/Source/Engine/Graphics/Textures/TextureBase.h
@@ -50,9 +50,6 @@ protected:
StreamingTexture _texture;
InitData* _customData;
-
-private:
-
BinaryAsset* _parent;
public:
@@ -126,6 +123,16 @@ public:
/// Gets the total memory usage that texture may have in use (if loaded to the maximum quality). Exact value may differ due to memory alignment and resource allocation policy.
///
API_PROPERTY() uint64 GetTotalMemoryUsage() const;
+
+ ///
+ /// Gets the index of the texture group used by this texture.
+ ///
+ API_PROPERTY() int32 GetTextureGroup() const;
+
+ ///
+ /// Sets the index of the texture group used by this texture.
+ ///
+ API_PROPERTY() void SetTextureGroup(int32 textureGroup);
public:
@@ -155,7 +162,7 @@ public:
protected:
- virtual int32 calculateChunkIndex(int32 mipIndex) const;
+ virtual int32 CalculateChunkIndex(int32 mipIndex) const;
private:
diff --git a/Source/Engine/Streaming/StreamableResource.cpp b/Source/Engine/Streaming/StreamableResource.cpp
index af758e786..685faff03 100644
--- a/Source/Engine/Streaming/StreamableResource.cpp
+++ b/Source/Engine/Streaming/StreamableResource.cpp
@@ -14,10 +14,10 @@ StreamableResource::StreamableResource(StreamingGroup* group)
StreamableResource::~StreamableResource()
{
- stopStreaming();
+ StopStreaming();
}
-void StreamableResource::startStreaming(bool isDynamic)
+void StreamableResource::StartStreaming(bool isDynamic)
{
_isDynamic = isDynamic;
@@ -28,7 +28,7 @@ void StreamableResource::startStreaming(bool isDynamic)
}
}
-void StreamableResource::stopStreaming()
+void StreamableResource::StopStreaming()
{
if (_isStreaming == true)
{
diff --git a/Source/Engine/Streaming/StreamableResource.h b/Source/Engine/Streaming/StreamableResource.h
index 8b8854bfe..a27833149 100644
--- a/Source/Engine/Streaming/StreamableResource.h
+++ b/Source/Engine/Streaming/StreamableResource.h
@@ -105,7 +105,6 @@ public:
struct StreamingCache
{
- //float MinDstSinceLastUpdate = MAX_float;
DateTime LastUpdate = 0;
int32 TargetResidency = 0;
DateTime TargetResidencyChange = 0;
@@ -124,6 +123,6 @@ public:
protected:
- void startStreaming(bool isDynamic);
- void stopStreaming();
+ void StartStreaming(bool isDynamic);
+ void StopStreaming();
};
diff --git a/Source/Engine/Streaming/Streaming.cpp b/Source/Engine/Streaming/Streaming.cpp
index 1ce53cf75..a2e010105 100644
--- a/Source/Engine/Streaming/Streaming.cpp
+++ b/Source/Engine/Streaming/Streaming.cpp
@@ -59,7 +59,6 @@ void UpdateResource(StreamableResource* resource, DateTime now)
if (resource->IsDynamic())
{
targetQuality = handler->CalculateTargetQuality(resource, now);
- // TODO: here we should apply resources group master scale (based on game settings quality level and memory level)
targetQuality = Math::Saturate(targetQuality);
}
diff --git a/Source/Engine/Streaming/StreamingGroup.h b/Source/Engine/Streaming/StreamingGroup.h
index 8f7cec045..8e3a78555 100644
--- a/Source/Engine/Streaming/StreamingGroup.h
+++ b/Source/Engine/Streaming/StreamingGroup.h
@@ -14,9 +14,6 @@ class FLAXENGINE_API StreamingGroup
{
public:
- ///
- /// Declares the Group type
- ///
DECLARE_ENUM_4(Type, Custom, Textures, Models, Audio);
protected:
@@ -38,7 +35,6 @@ public:
///
/// Gets the group type.
///
- /// Type
FORCE_INLINE Type GetType() const
{
return _type;
@@ -47,7 +43,6 @@ public:
///
/// Gets the group type name.
///
- /// Typename
FORCE_INLINE const Char* GetTypename() const
{
return ToString(_type);
@@ -56,7 +51,6 @@ public:
///
/// Gets the group streaming handler used by this group.
///
- /// Handler
FORCE_INLINE IStreamingHandler* GetHandler() const
{
return _handler;
@@ -88,7 +82,6 @@ public:
///
/// Gets textures group.
///
- /// Group
FORCE_INLINE StreamingGroup* Textures() const
{
return _textures;
@@ -97,7 +90,6 @@ public:
///
/// Gets models group.
///
- /// Group
FORCE_INLINE StreamingGroup* Models() const
{
return _models;
@@ -106,7 +98,6 @@ public:
///
/// Gets skinned models group.
///
- /// Group
FORCE_INLINE StreamingGroup* SkinnedModels() const
{
return _skinnedModels;
@@ -115,7 +106,6 @@ public:
///
/// Gets audio group.
///
- /// Group
FORCE_INLINE StreamingGroup* Audio() const
{
return _audio;
@@ -126,7 +116,6 @@ public:
///
/// Gets all the groups.
///
- /// Groups.
FORCE_INLINE const Array& Groups() const
{
return _groups;
@@ -135,7 +124,6 @@ public:
///
/// Gets all the handlers.
///
- /// Groups.
FORCE_INLINE const Array& Handlers() const
{
return _handlers;