using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Storage.Entities.Profile;
using SkiaSharp;
namespace Artemis.Core.LayerBrushes;
///
/// For internal use only, please use or or instead
///
public abstract class BaseLayerBrush : BreakableModel, IDisposable, IPluginFeatureDependent
{
private LayerBrushType _brushType;
private ILayerBrushConfigurationDialog? _configurationDialog;
private LayerBrushDescriptor _descriptor;
private Layer _layer;
private bool _supportsTransformation = true;
///
/// Creates a new instance of the class
///
protected BaseLayerBrush()
{
// Both are set right after construction to keep the constructor of inherited classes clean
_layer = null!;
_descriptor = null!;
LayerBrushEntity = null!;
}
///
/// Gets the layer this brush is applied to
///
public Layer Layer
{
get => _layer;
internal set => SetAndNotify(ref _layer, value);
}
///
/// Gets the brush entity this brush uses for persistent storage
///
public LayerBrushEntity LayerBrushEntity { get; internal set; }
///
/// Gets the descriptor of this brush
///
public LayerBrushDescriptor Descriptor
{
get => _descriptor;
internal set => SetAndNotify(ref _descriptor, value);
}
///
/// Gets or sets a configuration dialog complementing the regular properties
///
public ILayerBrushConfigurationDialog? ConfigurationDialog
{
get => _configurationDialog;
protected set => SetAndNotify(ref _configurationDialog, value);
}
///
/// Gets the type of layer brush
///
public LayerBrushType BrushType
{
get => _brushType;
internal set => SetAndNotify(ref _brushType, value);
}
///
/// Gets the ID of the that provided this effect
///
public string? ProviderId => Descriptor?.Provider.Id;
///
/// Gets a reference to the layer property group without knowing it's type
///
public virtual LayerPropertyGroup? BaseProperties => null;
///
/// Gets a list of presets available to this layer brush
///
public virtual List? Presets => null;
///
/// Gets the default preset used for new instances of this layer brush
///
public virtual ILayerBrushPreset? DefaultPreset => Presets?.FirstOrDefault();
///
/// Gets a boolean indicating whether the layer brush is enabled or not
///
public bool Enabled { get; private set; }
///
/// Gets or sets whether the brush supports transformations
/// Note: RGB.NET brushes can never be transformed and setting this to true will throw an exception
///
public bool SupportsTransformation
{
get => _supportsTransformation;
protected set
{
if (value && BrushType == LayerBrushType.RgbNet)
throw new ArtemisPluginFeatureException(Descriptor?.Provider!, "An RGB.NET brush cannot support transformation");
_supportsTransformation = value;
}
}
#region Overrides of BreakableModel
///
public override string BrokenDisplayName => Descriptor.DisplayName;
#endregion
///
/// Called when the layer brush is activated
///
public abstract void EnableLayerBrush();
///
/// Called when the layer brush is deactivated
///
public abstract void DisableLayerBrush();
///
/// Called before rendering every frame, write your update logic here
///
/// Seconds passed since last update
public abstract void Update(double deltaTime);
///
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
///
///
/// to release both managed and unmanaged resources;
/// to release only unmanaged resources.
///
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
DisableLayerBrush();
BaseProperties?.Dispose();
}
}
internal void InternalUpdate(Timeline timeline)
{
BaseProperties?.Update(timeline);
TryOrBreak(() => Update(timeline.Delta.TotalSeconds), "Failed to update");
}
///
/// Enables the layer brush if it isn't already enabled
///
internal void InternalEnable()
{
if (Enabled)
return;
if (!TryOrBreak(EnableLayerBrush, "Failed to enable"))
return;
Enabled = true;
}
///
/// Disables the layer brush if it isn't already disabled
///
internal void InternalDisable()
{
if (!Enabled)
return;
DisableLayerBrush();
Enabled = false;
}
// Not only is this needed to initialize properties on the layer brushes, it also prevents implementing anything
// but LayerBrush and RgbNetLayerBrush outside the core
internal abstract void Initialize();
internal abstract void InternalRender(SKCanvas canvas, SKRect path, SKPaint paint);
internal void Save()
{
// No need to update the type or provider ID, they're set once by the LayerBrushDescriptors CreateInstance and can't change
BaseProperties?.ApplyToEntity();
LayerBrushEntity.PropertyGroup = BaseProperties?.PropertyGroupEntity;
}
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#region Implementation of IPluginFeatureDependent
///
public IEnumerable GetFeatureDependencies()
{
IEnumerable result = [Descriptor.Provider];
if (BaseProperties != null)
result = result.Concat(BaseProperties.GetFeatureDependencies());
return result;
}
#endregion
}
///
/// Describes the type of a layer brush
///
public enum LayerBrushType
{
///
/// A regular brush that users Artemis' SkiaSharp-based rendering engine
///
Regular,
///
/// An RGB.NET brush that uses RGB.NET's per-LED rendering engine.
///
RgbNet
}