mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
commit
80cd620247
@ -56,6 +56,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
@ -65,6 +66,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ManifestCertificateThumbprint>EAC088BE27A2DE790AE6F37A020409F4A1B5EC0E</ManifestCertificateThumbprint>
|
||||
@ -491,6 +493,13 @@
|
||||
<Compile Include="Profiles\Layers\Types\AmbientLight\ScreenCapturing\DX9ScreenCapture.cs" />
|
||||
<Compile Include="Profiles\Layers\Types\AmbientLight\ScreenCapturing\IScreenCapture.cs" />
|
||||
<Compile Include="Profiles\Layers\Types\AmbientLight\ScreenCapturing\ScreenCaptureManager.cs" />
|
||||
<Compile Include="Profiles\Layers\Types\AngularBrush\AngularBrushPropertiesModel.cs" />
|
||||
<Compile Include="Profiles\Layers\Types\AngularBrush\AngularBrushPropertiesView.xaml.cs">
|
||||
<DependentUpon>AngularBrushPropertiesView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Profiles\Layers\Types\AngularBrush\AngularBrushPropertiesViewModel.cs" />
|
||||
<Compile Include="Profiles\Layers\Types\AngularBrush\AngularBrushType.cs" />
|
||||
<Compile Include="Profiles\Layers\Types\AngularBrush\Drawing\GradientDrawer.cs" />
|
||||
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\AudioCapture.cs" />
|
||||
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\AudioCaptureManager.cs" />
|
||||
<Compile Include="Events\AudioDeviceChangedEventArgs.cs" />
|
||||
@ -862,6 +871,10 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Profiles\Layers\Types\AngularBrush\AngularBrushPropertiesView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Profiles\Layers\Types\Audio\AudioPropertiesView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
||||
@ -3,13 +3,10 @@ using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using System.Windows.Media;
|
||||
using Artemis.DeviceProviders;
|
||||
using Artemis.ViewModels;
|
||||
using Ninject.Extensions.Logging;
|
||||
using Color = System.Drawing.Color;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace Artemis.Managers
|
||||
{
|
||||
@ -21,7 +18,8 @@ namespace Artemis.Managers
|
||||
private readonly DebugViewModel _debugViewModel;
|
||||
private readonly DeviceManager _deviceManager;
|
||||
private readonly ILogger _logger;
|
||||
private readonly Timer _loopTimer;
|
||||
//private readonly Timer _loopTimer;
|
||||
private readonly Task _loopTask;
|
||||
private readonly ModuleManager _moduleManager;
|
||||
|
||||
public LoopManager(ILogger logger, ModuleManager moduleManager, DeviceManager deviceManager,
|
||||
@ -33,10 +31,10 @@ namespace Artemis.Managers
|
||||
_debugViewModel = debugViewModel;
|
||||
|
||||
// Setup timers
|
||||
_loopTimer = new Timer(40);
|
||||
_loopTimer.Elapsed += LoopTimerOnElapsed;
|
||||
_loopTimer.Start();
|
||||
|
||||
//_loopTimer = new Timer(40);
|
||||
//_loopTimer.Elapsed += LoopTimerOnElapsed;
|
||||
//_loopTimer.Start();
|
||||
_loopTask = Task.Factory.StartNew(ProcessLoop);
|
||||
_logger.Info("Intialized LoopManager");
|
||||
}
|
||||
|
||||
@ -49,22 +47,45 @@ namespace Artemis.Managers
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_loopTimer.Stop();
|
||||
_loopTimer.Dispose();
|
||||
_loopTask.Dispose();
|
||||
//_loopTimer.Stop();
|
||||
//_loopTimer.Dispose();
|
||||
}
|
||||
|
||||
private void LoopTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
|
||||
private void ProcessLoop()
|
||||
{
|
||||
try
|
||||
//TODO DarthAffe 14.01.2017: A stop-condition and a real cleanup instead of just aborting might be better
|
||||
while (true)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warn(e, "Exception in render loop");
|
||||
try
|
||||
{
|
||||
long preUpdateTicks = DateTime.Now.Ticks;
|
||||
|
||||
Render();
|
||||
|
||||
int sleep = (int)(40f - ((DateTime.Now.Ticks - preUpdateTicks) / 10000f));
|
||||
if (sleep > 0)
|
||||
Thread.Sleep(sleep);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warn(e, "Exception in render loop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//private void LoopTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// Render();
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// _logger.Warn(e, "Exception in render loop");
|
||||
// }
|
||||
//}
|
||||
|
||||
public Task StartAsync()
|
||||
{
|
||||
return Task.Run(() => Start());
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Profiles.Layers.Models;
|
||||
|
||||
namespace Artemis.Profiles.Layers.Types.AngularBrush
|
||||
{
|
||||
public class AngularBrushPropertiesModel : LayerPropertiesModel
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public IList<Tuple<double, Color>> GradientStops { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public AngularBrushPropertiesModel(LayerPropertiesModel properties = null)
|
||||
: base(properties)
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
<UserControl x:Class="Artemis.Profiles.Layers.Types.AngularBrush.AngularBrushPropertiesView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
|
||||
xmlns:ncore="http://schemas.ncore.com/wpf/xaml/colorbox"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<Grid>
|
||||
<!-- Colors -->
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<!-- Animation -->
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Margin="10" FontSize="13.333" Text="Animation:"
|
||||
VerticalAlignment="Center"
|
||||
Height="18" />
|
||||
<ComboBox Grid.Row="0" Grid.Column="1" Margin="10,10,10,0" x:Name="LayerAnimations" VerticalAlignment="Top"
|
||||
Height="22">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=Name, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<!-- Animation Speed -->
|
||||
<TextBlock Grid.Row="0" Grid.Column="2" Margin="10" FontSize="13.333" Text="Animation speed:"
|
||||
VerticalAlignment="Center" Height="18" />
|
||||
<Slider x:Name="RotationSpeed" Grid.Row="0" Grid.Column="3" VerticalAlignment="Center"
|
||||
TickPlacement="None" TickFrequency="0.05"
|
||||
Value="{Binding Path=LayerModel.Properties.AnimationSpeed, Mode=TwoWay}" Minimum="0.05" Maximum="3"
|
||||
SmallChange="0" IsSnapToTickEnabled="True" Margin="10,12,10,2" Height="24" />
|
||||
|
||||
<!-- ClippingType -->
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Margin="10, 13, 10, 10" FontSize="13.333" Text="Clipping type:"
|
||||
VerticalAlignment="Center" Height="23" />
|
||||
<controls:ToggleSwitch IsChecked="{Binding Path=LayerModel.Properties.Contain, Mode=TwoWay}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1" OnLabel="Contain" OffLabel="Cut-off" Margin="10,1,5,1"
|
||||
VerticalAlignment="Center"
|
||||
Height="36" />
|
||||
|
||||
<!-- Colors -->
|
||||
<StackPanel Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Orientation="Horizontal" x:Name="ShowBrush">
|
||||
<TextBlock Margin="10,13,10,0" FontSize="13.333" Text="Color(s):"
|
||||
VerticalAlignment="Top" Height="18" Width="130" />
|
||||
<Border Margin="10" BorderBrush="{StaticResource ControlBorderBrush}"
|
||||
BorderThickness="1" SnapsToDevicePixels="True" ToolTip="Click to edit">
|
||||
<ncore:ColorBox Brush="{Binding Brush, Mode=TwoWay}" ShowNone="False" Height="24" Width="134"
|
||||
VerticalAlignment="Top" ShowLinear="True" ShowRadial="False" ShowSolid="False" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Dynamic -->
|
||||
<Label Grid.Row="3" Grid.Column="0" FontSize="20" HorizontalAlignment="Left"
|
||||
Content="Dynamic" Width="97" VerticalAlignment="Bottom" />
|
||||
|
||||
<!-- Dynamic property views -->
|
||||
<ContentControl Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="4" x:Name="HeightProperties" />
|
||||
<ContentControl Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="4" x:Name="WidthProperties" />
|
||||
<ContentControl Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="4" x:Name="OpacityProperties" />
|
||||
|
||||
<ContentControl Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="4" x:Name="LayerTweenViewModel" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -0,0 +1,12 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Artemis.Profiles.Layers.Types.AngularBrush
|
||||
{
|
||||
public partial class AngularBrushPropertiesView : UserControl
|
||||
{
|
||||
public AngularBrushPropertiesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Profiles.Layers.Abstract;
|
||||
using Artemis.Profiles.Layers.Interfaces;
|
||||
using Artemis.Utilities;
|
||||
using Artemis.ViewModels;
|
||||
using Artemis.ViewModels.Profiles;
|
||||
using Caliburn.Micro;
|
||||
|
||||
namespace Artemis.Profiles.Layers.Types.AngularBrush
|
||||
{
|
||||
public class AngularBrushPropertiesViewModel : LayerPropertiesViewModel
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private ILayerAnimation _selectedLayerAnimation;
|
||||
|
||||
public BindableCollection<GeneralHelpers.PropertyCollection> DataModelProps { get; set; }
|
||||
public BindableCollection<ILayerAnimation> LayerAnimations { get; set; }
|
||||
public LayerDynamicPropertiesViewModel HeightProperties { get; set; }
|
||||
public LayerDynamicPropertiesViewModel WidthProperties { get; set; }
|
||||
public LayerDynamicPropertiesViewModel OpacityProperties { get; set; }
|
||||
public LayerTweenViewModel LayerTweenViewModel { get; set; }
|
||||
|
||||
public ILayerAnimation SelectedLayerAnimation
|
||||
{
|
||||
get { return _selectedLayerAnimation; }
|
||||
set
|
||||
{
|
||||
if (Equals(value, _selectedLayerAnimation)) return;
|
||||
_selectedLayerAnimation = value;
|
||||
NotifyOfPropertyChange(() => SelectedLayerAnimation);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public AngularBrushPropertiesViewModel(LayerEditorViewModel editorVm)
|
||||
: base(editorVm)
|
||||
{
|
||||
LayerAnimations = new BindableCollection<ILayerAnimation>(editorVm.LayerAnimations);
|
||||
|
||||
HeightProperties = new LayerDynamicPropertiesViewModel("Height", editorVm);
|
||||
WidthProperties = new LayerDynamicPropertiesViewModel("Width", editorVm);
|
||||
OpacityProperties = new LayerDynamicPropertiesViewModel("Opacity", editorVm);
|
||||
LayerTweenViewModel = new LayerTweenViewModel(editorVm);
|
||||
|
||||
SelectedLayerAnimation =
|
||||
LayerAnimations.FirstOrDefault(l => l.Name == editorVm.ProposedLayer.LayerAnimation?.Name) ??
|
||||
LayerAnimations.First(l => l.Name == "None");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void ApplyProperties()
|
||||
{
|
||||
HeightProperties.Apply(LayerModel);
|
||||
WidthProperties.Apply(LayerModel);
|
||||
OpacityProperties.Apply(LayerModel);
|
||||
|
||||
LayerModel.Properties.Brush = Brush;
|
||||
LayerModel.LayerAnimation = SelectedLayerAnimation;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Modules.Abstract;
|
||||
using Artemis.Profiles.Layers.Abstract;
|
||||
using Artemis.Profiles.Layers.Animations;
|
||||
using Artemis.Profiles.Layers.Interfaces;
|
||||
using Artemis.Profiles.Layers.Models;
|
||||
using Artemis.Profiles.Layers.Types.AngularBrush.Drawing;
|
||||
using Artemis.ViewModels;
|
||||
|
||||
namespace Artemis.Profiles.Layers.Types.AngularBrush
|
||||
{
|
||||
public class AngularBrushType : ILayerType
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private GradientDrawer _gradientDrawer;
|
||||
|
||||
public string Name => "Angular Brush";
|
||||
public bool ShowInEdtor => true;
|
||||
public DrawType DrawType => DrawType.Keyboard;
|
||||
|
||||
#endregion
|
||||
|
||||
public AngularBrushType()
|
||||
{
|
||||
_gradientDrawer = new GradientDrawer();
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
public ImageSource DrawThumbnail(LayerModel layer)
|
||||
{
|
||||
//TODO DarthAffe 14.01.2017: This could be replaced with the real brush but it complaints about the thread too
|
||||
Rect thumbnailRect = new Rect(0, 0, 18, 18);
|
||||
DrawingVisual visual = new DrawingVisual();
|
||||
using (DrawingContext c = visual.RenderOpen())
|
||||
if (layer.Properties.Brush != null)
|
||||
c.DrawRectangle(layer.Properties.Brush,
|
||||
new Pen(new SolidColorBrush(Colors.White), 1),
|
||||
thumbnailRect);
|
||||
|
||||
DrawingImage image = new DrawingImage(visual.Drawing);
|
||||
return image;
|
||||
}
|
||||
|
||||
public void Draw(LayerModel layerModel, DrawingContext c)
|
||||
{
|
||||
AngularBrushPropertiesModel properties = layerModel.Properties as AngularBrushPropertiesModel;
|
||||
if (properties == null) return;
|
||||
|
||||
Brush origBrush = layerModel.Brush;
|
||||
|
||||
//TODO DarthAffe 14.01.2017: Check if an update is needed
|
||||
_gradientDrawer.GradientStops = GetGradientStops(layerModel.Brush).Select(x => new Tuple<double, Color>(x.Offset, x.Color)).ToList();
|
||||
_gradientDrawer.Update();
|
||||
layerModel.Brush = _gradientDrawer.Brush.Clone();
|
||||
|
||||
// If an animation is present, let it handle the drawing
|
||||
if (layerModel.LayerAnimation != null && !(layerModel.LayerAnimation is NoneAnimation))
|
||||
{
|
||||
layerModel.LayerAnimation.Draw(layerModel, c);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise draw the rectangle with its layer.AppliedProperties dimensions and brush
|
||||
Rect rect = layerModel.Properties.Contain
|
||||
? layerModel.LayerRect()
|
||||
: new Rect(layerModel.Properties.X * 4, layerModel.Properties.Y * 4,
|
||||
layerModel.Properties.Width * 4, layerModel.Properties.Height * 4);
|
||||
|
||||
Rect clip = layerModel.LayerRect();
|
||||
|
||||
// Can't meddle with the original brush because it's frozen.
|
||||
Brush brush = layerModel.Brush.Clone();
|
||||
brush.Opacity = layerModel.Opacity;
|
||||
|
||||
c.PushClip(new RectangleGeometry(clip));
|
||||
c.DrawRectangle(brush, null, rect);
|
||||
c.Pop();
|
||||
|
||||
layerModel.Brush = origBrush;
|
||||
}
|
||||
|
||||
public void Update(LayerModel layerModel, ModuleDataModel dataModel, bool isPreview = false)
|
||||
{
|
||||
layerModel.ApplyProperties(true);
|
||||
if (isPreview || dataModel == null)
|
||||
return;
|
||||
|
||||
// If not previewing, apply dynamic properties according to datamodel
|
||||
foreach (DynamicPropertiesModel dynamicProperty in layerModel.Properties.DynamicProperties)
|
||||
dynamicProperty.ApplyProperty(dataModel, layerModel);
|
||||
}
|
||||
|
||||
public void SetupProperties(LayerModel layerModel)
|
||||
{
|
||||
if (layerModel.Properties is AngularBrushPropertiesModel)
|
||||
return;
|
||||
|
||||
layerModel.Properties = new AngularBrushPropertiesModel(layerModel.Properties);
|
||||
}
|
||||
|
||||
public LayerPropertiesViewModel SetupViewModel(LayerEditorViewModel layerEditorViewModel, LayerPropertiesViewModel layerPropertiesViewModel)
|
||||
{
|
||||
return (layerPropertiesViewModel as AngularBrushPropertiesViewModel) ?? new AngularBrushPropertiesViewModel(layerEditorViewModel);
|
||||
}
|
||||
|
||||
private GradientStopCollection GetGradientStops(Brush brush)
|
||||
{
|
||||
LinearGradientBrush linearBrush = brush as LinearGradientBrush;
|
||||
if (linearBrush != null)
|
||||
return linearBrush.GradientStops;
|
||||
|
||||
RadialGradientBrush radialBrush = brush as RadialGradientBrush;
|
||||
if (radialBrush != null)
|
||||
return radialBrush.GradientStops;
|
||||
|
||||
SolidColorBrush solidBrush = brush as SolidColorBrush;
|
||||
if (solidBrush != null)
|
||||
return new GradientStopCollection(new[] { new GradientStop(solidBrush.Color, 0), new GradientStop(solidBrush.Color, 1) });
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Artemis.Profiles.Layers.Types.AngularBrush.Drawing
|
||||
{
|
||||
public class GradientDrawer
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private static readonly double ORIGIN = Math.Atan2(-1, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
private WriteableBitmap _bitmap;
|
||||
|
||||
private IList<Tuple<double, Color>> _gradientStops;
|
||||
public IList<Tuple<double, Color>> GradientStops
|
||||
{
|
||||
set { _gradientStops = FixGradientStops(value); }
|
||||
}
|
||||
|
||||
public Brush Brush { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (_bitmap == null)
|
||||
CreateBrush();
|
||||
|
||||
unsafe
|
||||
{
|
||||
_bitmap.Lock();
|
||||
byte* buffer = (byte*)_bitmap.BackBuffer.ToPointer();
|
||||
|
||||
int width = _bitmap.PixelWidth;
|
||||
double widthHalf = width / 2.0;
|
||||
|
||||
int height = _bitmap.PixelHeight;
|
||||
double heightHalf = height / 2.0;
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
int offset = (((y * width) + x) * 4);
|
||||
|
||||
double gradientOffset = CalculateGradientOffset(x, y, widthHalf, heightHalf);
|
||||
GetColor(_gradientStops, gradientOffset,
|
||||
ref buffer[offset + 3], ref buffer[offset + 2],
|
||||
ref buffer[offset + 1], ref buffer[offset]);
|
||||
}
|
||||
|
||||
_bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
|
||||
_bitmap.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateBrush()
|
||||
{
|
||||
_bitmap = new WriteableBitmap(100, 100, 96, 96, PixelFormats.Bgra32, null);
|
||||
Brush = new ImageBrush(_bitmap) { Stretch = Stretch.UniformToFill };
|
||||
}
|
||||
|
||||
private double CalculateGradientOffset(double x, double y, double centerX, double centerY)
|
||||
{
|
||||
double angle = Math.Atan2(y - centerY, x - centerX) - ORIGIN;
|
||||
if (angle < 0) angle += Math.PI * 2;
|
||||
return angle / (Math.PI * 2);
|
||||
}
|
||||
|
||||
private static void GetColor(IList<Tuple<double, Color>> gradientStops, double offset, ref byte colA, ref byte colR, ref byte colG, ref byte colB)
|
||||
{
|
||||
if (gradientStops.Count == 0)
|
||||
{
|
||||
colA = 0;
|
||||
colR = 0;
|
||||
colG = 0;
|
||||
colB = 0;
|
||||
return;
|
||||
}
|
||||
if (gradientStops.Count == 1)
|
||||
{
|
||||
Color color = gradientStops.First().Item2;
|
||||
colA = color.A;
|
||||
colR = color.R;
|
||||
colG = color.G;
|
||||
colB = color.B;
|
||||
return;
|
||||
}
|
||||
|
||||
Tuple<double, Color> beforeStop = null;
|
||||
double afterOffset = -1;
|
||||
Color afterColor = default(Color);
|
||||
|
||||
for (int i = 0; i < gradientStops.Count; i++)
|
||||
{
|
||||
Tuple<double, Color> gradientStop = gradientStops[i];
|
||||
double o = gradientStop.Item1;
|
||||
if (o <= offset)
|
||||
beforeStop = gradientStop;
|
||||
|
||||
if (o >= offset)
|
||||
{
|
||||
afterOffset = gradientStop.Item1;
|
||||
afterColor = gradientStop.Item2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
double beforeOffset = beforeStop.Item1;
|
||||
Color beforeColor = beforeStop.Item2;
|
||||
|
||||
double blendFactor = 0f;
|
||||
if (beforeOffset != afterOffset)
|
||||
blendFactor = ((offset - beforeOffset) / (afterOffset - beforeOffset));
|
||||
|
||||
colA = (byte)((afterColor.A - beforeColor.A) * blendFactor + beforeColor.A);
|
||||
colR = (byte)((afterColor.R - beforeColor.R) * blendFactor + beforeColor.R);
|
||||
colG = (byte)((afterColor.G - beforeColor.G) * blendFactor + beforeColor.G);
|
||||
colB = (byte)((afterColor.B - beforeColor.B) * blendFactor + beforeColor.B);
|
||||
}
|
||||
|
||||
private IList<Tuple<double, Color>> FixGradientStops(IList<Tuple<double, Color>> gradientStops)
|
||||
{
|
||||
if (gradientStops == null) return new List<Tuple<double, Color>>();
|
||||
|
||||
List<Tuple<double, Color>> stops = gradientStops.OrderBy(x => x.Item1).ToList();
|
||||
|
||||
Tuple<double, Color> firstStop = stops.First();
|
||||
if (firstStop.Item1 > 0)
|
||||
stops.Insert(0, new Tuple<double, Color>(0, firstStop.Item2));
|
||||
|
||||
Tuple<double, Color> lastStop = stops.Last();
|
||||
if (lastStop.Item1 < 1)
|
||||
stops.Add(new Tuple<double, Color>(1, lastStop.Item2));
|
||||
|
||||
return stops;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user