1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-12 21:38:38 +00:00

Ambient Lightning WIP

This commit is contained in:
SpoinkyNL 2016-03-05 00:09:19 +01:00
parent edeffeda21
commit ae66e7a63a
14 changed files with 450 additions and 30 deletions

View File

@ -147,6 +147,10 @@
<HintPath>..\packages\Hardcodet.NotifyIcon.Wpf.1.0.5\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Kaliko.ImageLibrary, Version=2.0.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageLibrary.2.0.5\lib\net45\Kaliko.ImageLibrary.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.2.0.5\lib\net45-full\log4net.dll</HintPath>
<Private>True</Private>
@ -166,6 +170,18 @@
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpDX, Version=3.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.3.0.1\lib\net45\SharpDX.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpDX.Direct3D11, Version=3.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Direct3D11.3.0.1\lib\net45\SharpDX.Direct3D11.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpDX.DXGI, Version=3.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.DXGI.3.0.1\lib\net45\SharpDX.DXGI.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
@ -248,6 +264,12 @@
<Compile Include="Models\EffectModel.cs" />
<Compile Include="Models\EffectSettings.cs" />
<Compile Include="Models\GameSettings.cs" />
<Compile Include="Modules\Effects\AmbientLightning\AmbientLightningEffectModel.cs" />
<Compile Include="Modules\Effects\AmbientLightning\AmbientLightningEffectSettings.cs" />
<Compile Include="Modules\Effects\AmbientLightning\AmbientLightningEffectView.xaml.cs">
<DependentUpon>AmbientLightningEffectView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Effects\AmbientLightning\AmbientLightningEffectViewModel.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualization.Designer.cs">
<DependentUpon>AudioVisualization.settings</DependentUpon>
<AutoGen>True</AutoGen>
@ -328,6 +350,7 @@
<Compile Include="Utilities\Memory\Win32.cs" />
<Compile Include="Utilities\Keyboard\Key.cs" />
<Compile Include="Utilities\Keyboard\KeyboardRectangle.cs" />
<Compile Include="Utilities\ScreenCapture.cs" />
<Compile Include="Utilities\ShellLink.cs" />
<Compile Include="Utilities\Updater.cs" />
<Compile Include="ViewModels\Abstract\EffectViewModel.cs" />
@ -456,6 +479,10 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Page Include="Modules\Effects\AmbientLightning\AmbientLightningEffectView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Resources\Icons.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -529,9 +556,6 @@
<Content Include="LogitechLedEnginesWrapper.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="RzChromaSDK64.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\CounterStrike\gamestateConfiguration.txt" />
</ItemGroup>
<ItemGroup>

View File

@ -1,6 +1,7 @@
using System.Collections.Generic;
using Artemis.KeyboardProviders.Corsair;
using Artemis.KeyboardProviders.Logitech;
using Artemis.KeyboardProviders.Razer;
namespace Artemis.KeyboardProviders
{
@ -11,8 +12,8 @@ namespace Artemis.KeyboardProviders
return new List<KeyboardProvider>
{
new Orion(),
new CorsairRGB()
//new BlackWidow()
new CorsairRGB(),
new BlackWidow()
};
}
}

View File

@ -3,6 +3,8 @@ using System.Drawing;
using Artemis.KeyboardProviders.Razer.Utilities;
using Corale.Colore.Core;
using Corale.Colore.Razer.Keyboard;
using ColoreColor = Corale.Colore.Core.Color;
using KeyboardCustom = Corale.Colore.Razer.Keyboard.Effects.Custom;
namespace Artemis.KeyboardProviders.Razer
{
@ -22,19 +24,9 @@ namespace Artemis.KeyboardProviders.Razer
return false;
// Some people have Synapse installed, but not a Chroma keyboard, deal with this
try
{
// Create a bitmap to send as a test
var b = new Bitmap(22, 6);
var razerArray = RazerUtilities.BitmapColorArray(b, 6, 22);
Chroma.Instance.Keyboard.SetGrid(razerArray);
Chroma.Instance.Keyboard.Clear();
}
catch (NullReferenceException)
{
return false;
}
return true;
var blackWidowFound = Chroma.Instance.Query(Corale.Colore.Razer.Devices.Blackwidow).Connected;
var blackWidowTeFound = Chroma.Instance.Query(Corale.Colore.Razer.Devices.BlackwidowTe).Connected;
return (blackWidowFound || blackWidowTeFound);
}
public override void Enable()
@ -52,7 +44,8 @@ namespace Artemis.KeyboardProviders.Razer
public override void DrawBitmap(Bitmap bitmap)
{
var razerArray = RazerUtilities.BitmapColorArray(bitmap, Height, Width);
Chroma.Instance.Keyboard.SetGrid(razerArray);
Chroma.Instance.Keyboard.SetCustom(razerArray);
}
}
}

View File

@ -1,25 +1,23 @@
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using Color = Corale.Colore.Core.Color;
using Corale.Colore.Razer.Keyboard.Effects;
namespace Artemis.KeyboardProviders.Razer.Utilities
{
public static class RazerUtilities
{
public static Color[][] BitmapColorArray(Bitmap b, int height, int width)
public static Custom BitmapColorArray(Bitmap b, int height, int width)
{
var res = new Color[height][];
var keyboardGrid = Custom.Create();
if (b.Width > width || b.Height > height)
b = ResizeImage(b, width, height);
for (var y = 0; y < b.Height - 1; y++)
{
res[y] = new Color[width];
for (var x = 0; x < b.Width - 1; x++)
res[y][x] = b.GetPixel(x, y);
}
return res;
for (var y = 0; y < b.Height; y++)
for (var x = 0; x < b.Width; x++)
keyboardGrid[y, x] = b.GetPixel(x, y);
return keyboardGrid;
}
/// <summary>

View File

@ -0,0 +1,135 @@
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Utilities;
using Artemis.Utilities.Keyboard;
using Kaliko.ImageLibrary;
using Kaliko.ImageLibrary.Filters;
namespace Artemis.Modules.Effects.AmbientLightning
{
internal class AmbientLightningEffectModel : EffectModel
{
private KeyboardRectangle _botRect;
private List<Color> _colors;
private List<Rectangle> _rectangles;
private ScreenCapture _screenCapturer;
private KeyboardRectangle _topRect;
public AmbientLightningEffectModel(MainManager mainManager, AmbientLightningEffectSettings settings)
: base(mainManager)
{
Name = "Ambient Lightning";
Settings = settings;
Scale = 4;
Initialized = false;
}
public int Scale { get; set; }
public AmbientLightningEffectSettings Settings { get; set; }
public KeyboardRectangle KeyboardRectangle { get; set; }
public override void Dispose()
{
Initialized = false;
_screenCapturer = null;
}
public override void Enable()
{
Initialized = false;
_colors = new List<Color>();
_screenCapturer = new ScreenCapture();
_topRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, 0, new List<Color>(),
LinearGradientMode.Horizontal) {Height = MainManager.KeyboardManager.ActiveKeyboard.Height*Scale/2};
_botRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, 0, new List<Color>(),
LinearGradientMode.Horizontal);
Initialized = true;
}
public override void Update()
{
var capture = _screenCapturer.Capture();
_rectangles = new List<Rectangle>();
// Analise the result
// Chop the screen into 2 rows and 3 columns
var resolution = Screen.PrimaryScreen.Bounds;
var blockWidth = resolution.Width/3;
var blockHeight = resolution.Height/2;
var colorIndex = 0;
for (var row = 0; row < 2; row++)
{
for (var column = 0; column < 3; column++)
{
var blockBase = new Point(blockWidth*column, blockHeight*row);
var samples = new List<Color>();
// For each block, take samples
for (var blockRow = 0; blockRow < 6; blockRow++)
{
for (var blockColumn = 0; blockColumn < 6; blockColumn++)
{
var x = blockWidth/6*blockColumn + blockWidth/6/4 + blockBase.X;
var y = blockHeight/6*blockRow + blockHeight/6/4 + blockBase.Y;
samples.Add(ScreenCapture.GetColor(capture, new Point(x, y)));
}
}
// Take the average of the samples
var averageR = samples.Sum(s => s.R)/samples.Count;
var averageG = samples.Sum(s => s.G)/samples.Count;
var averageB = samples.Sum(s => s.B)/samples.Count;
if (_colors.Count <= colorIndex)
_colors.Add(Color.FromArgb(255, averageR, averageG, averageB));
else
_colors[colorIndex] = Color.FromArgb(255, (averageR + _colors[colorIndex].R * 5) / 6, (averageG + _colors[colorIndex].G * 5) / 6, (averageB + _colors[colorIndex].B * 5) / 6);
colorIndex++;
}
}
// Put the resulting colors in 6 rectangles, their size differs per keyboard
var rectWidth = MainManager.KeyboardManager.ActiveKeyboard.Width/3*Scale;
var rectHeight = MainManager.KeyboardManager.ActiveKeyboard.Height/2*Scale;
for (var row = 0; row < 2; row++)
{
for (var column = 0; column < 3; column++)
{
var rectBase = new Point(rectWidth * column, rectHeight * row);
_rectangles.Add(new Rectangle(rectBase.X, rectBase.Y, rectWidth, rectHeight));
}
}
}
public override Bitmap GenerateBitmap()
{
var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale);
using (var g = Graphics.FromImage(bitmap))
{
var i = 0;
foreach (var rectangle in _rectangles)
{
g.FillRectangle(new SolidBrush(_colors[i]), rectangle);
i++;
}
}
var test = new KalikoImage(bitmap);
test.ApplyFilter(new GaussianBlurFilter(8f));
var ms = new MemoryStream();
test.SaveBmp(ms);
ms.Position = 0;
return new Bitmap(ms);
}
}
}

View File

@ -0,0 +1,37 @@
using System.Drawing.Drawing2D;
using Artemis.Models;
namespace Artemis.Modules.Effects.AmbientLightning
{
internal class AmbientLightningEffectSettings : EffectSettings
{
public AmbientLightningEffectSettings()
{
Load();
}
public int Width { get; set; }
public int Height { get; set; }
public bool Rotate { get; set; }
public int Scale { get; set; }
public LinearGradientMode Type { get; set; }
public sealed override void Load()
{
ToDefault();
}
public sealed override void Save()
{
}
public sealed override void ToDefault()
{
Width = 84;
Height = 24;
Scale = 4;
Type = LinearGradientMode.Horizontal;
Rotate = true;
}
}
}

View File

@ -0,0 +1,55 @@
<UserControl x:Class="Artemis.Modules.Effects.AmbientLightning.AmbientLightningEffectView"
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:local="clr-namespace:Artemis.Modules.Effects.AmbientLightning"
xmlns:cal="http://www.caliburnproject.org"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d"
d:DesignHeight="475.392" d:DesignWidth="583.577">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15, 5, 15, 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="20" MaxWidth="500" HorizontalAlignment="Left">
<Label.Content>
<AccessText TextWrapping="Wrap"
Text="Colors the keyboard according to what is on screen" />
</Label.Content>
</Label>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Label Content="Enable effect" Margin="0 3 0 0" HorizontalAlignment="Right" />
<ToggleButton x:Name="EffectEnabled" Margin="0 3 0 0" Width="25" Height="25"
Style="{DynamicResource MetroCircleToggleButtonStyle}"
cal:Message.Attach="[Event Click] = [Action ToggleEffect]"
ToolTip="Note: You can't enable an effect when Artemis is disabled"
ToolTipService.ShowOnDisabled="True" />
</StackPanel>
</StackPanel>
<!-- Buttons -->
<StackPanel Grid.Column="0" Grid.Row="8" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button x:Name="ResetSettings" Content="Reset effect" VerticalAlignment="Top" Width="100"
Style="{DynamicResource SquareButtonStyle}" />
<Button x:Name="SaveSettings" Content="Save changes" VerticalAlignment="Top" Width="100"
Margin="10,0,0,0"
Style="{DynamicResource SquareButtonStyle}" />
</StackPanel>
</Grid>
</ScrollViewer>
</UserControl>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Artemis.Modules.Effects.AmbientLightning
{
/// <summary>
/// Interaction logic for AmbientLightningEffectView.xaml
/// </summary>
public partial class AmbientLightningEffectView : UserControl
{
public AmbientLightningEffectView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,32 @@
using Artemis.Events;
using Artemis.Managers;
using Artemis.ViewModels.Abstract;
using Caliburn.Micro;
namespace Artemis.Modules.Effects.AmbientLightning
{
internal class AmbientLightningEffectViewModel : EffectViewModel, IHandle<ActiveEffectChanged>
{
public AmbientLightningEffectViewModel(MainManager mainManager)
{
// Subscribe to main model
MainManager = mainManager;
MainManager.Events.Subscribe(this);
// Settings are loaded from file by class
EffectSettings = new AmbientLightningEffectSettings();
// Create effect model and add it to MainManager
EffectModel = new AmbientLightningEffectModel(mainManager, (AmbientLightningEffectSettings) EffectSettings);
MainManager.EffectManager.EffectModels.Add(EffectModel);
}
public static string Name => "Ambient Lightning";
public void Handle(ActiveEffectChanged message)
{
NotifyOfPropertyChange(() => EffectEnabled);
}
}
}

Binary file not shown.

View File

@ -177,7 +177,6 @@ namespace Artemis.Utilities.Keyboard
// Apply the devided positions
colorBlend.Positions = positions.ToArray();
return colorBlend;
}

View File

@ -0,0 +1,110 @@
using System.Drawing;
using System.IO;
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using Device = SharpDX.Direct3D11.Device;
using MapFlags = SharpDX.DXGI.MapFlags;
using Resource = SharpDX.DXGI.Resource;
using ResultCode = SharpDX.DXGI.ResultCode;
namespace Artemis.Utilities
{
internal class ScreenCapture
{
private readonly Device _device;
private readonly OutputDuplication _duplicatedOutput;
private readonly Texture2D _screenTexture;
private readonly uint numAdapter = 0; // # of graphics card adapter
private readonly uint numOutput = 0; // # of output device (i.e. monitor)
private DataStream _dataStream;
private Resource _screenResource;
private Surface _screenSurface;
public ScreenCapture()
{
// Create device and factory
_device = new Device(DriverType.Hardware);
var factory = new Factory1();
// Creating CPU-accessible texture resource
var texdes = new Texture2DDescription
{
CpuAccessFlags = CpuAccessFlags.Read,
BindFlags = BindFlags.None,
Format = Format.B8G8R8A8_UNorm,
Height = factory.Adapters1[numAdapter].Outputs[numOutput].Description.DesktopBounds.Bottom,
Width = factory.Adapters1[numAdapter].Outputs[numOutput].Description.DesktopBounds.Right,
OptionFlags = ResourceOptionFlags.None,
MipLevels = 1,
ArraySize = 1,
SampleDescription =
{
Count = 1,
Quality = 0
},
Usage = ResourceUsage.Staging
};
_screenTexture = new Texture2D(_device, texdes);
// duplicate output stuff
var output = new Output1(factory.Adapters1[numAdapter].Outputs[numOutput].NativePointer);
_duplicatedOutput = output.DuplicateOutput(_device);
_screenResource = null;
_dataStream = null;
}
public DataStream Capture()
{
try
{
OutputDuplicateFrameInformation duplicateFrameInformation;
_duplicatedOutput.AcquireNextFrame(1000, out duplicateFrameInformation, out _screenResource);
}
catch (SharpDXException e)
{
if (e.ResultCode.Code == ResultCode.WaitTimeout.Result.Code)
return Capture();
throw;
}
// copy resource into memory that can be accessed by the CPU
_device.ImmediateContext.CopyResource(_screenResource.QueryInterface<SharpDX.Direct3D11.Resource>(),
_screenTexture);
// cast from texture to surface, so we can access its bytes
_screenSurface = _screenTexture.QueryInterface<Surface>();
// map the resource to access it
_screenSurface.Map(MapFlags.Read, out _dataStream);
// seek within the stream and read one byte
_dataStream.Position = 4;
_dataStream.ReadByte();
// free resources
_dataStream.Close();
_screenSurface.Unmap();
_screenSurface.Dispose();
_screenResource.Dispose();
_duplicatedOutput.ReleaseFrame();
return _dataStream;
}
/// <summary>
/// Gets a specific pixel out of the data stream.
/// </summary>
/// <param name="surfaceDataStream"></param>
/// <param name="position">Given point on the screen.</param>
/// <returns></returns>
public static Color GetColor(DataStream surfaceDataStream, Point position)
{
var data = new byte[4];
surfaceDataStream.Seek(position.Y*1920*4 + position.X*4, SeekOrigin.Begin);
surfaceDataStream.Read(data, 0, 4);
return Color.FromArgb(255, data[2], data[1], data[0]);
}
}
}

View File

@ -1,4 +1,5 @@
using Artemis.Managers;
using Artemis.Modules.Effects.AmbientLightning;
using Artemis.Modules.Effects.AudioVisualizer;
using Artemis.Modules.Effects.Debug;
using Artemis.Modules.Effects.TypeHole;
@ -13,12 +14,14 @@ namespace Artemis.ViewModels
private readonly DebugEffectViewModel _debugVm;
private readonly TypeHoleViewModel _typeHoleVm;
private readonly TypeWaveViewModel _typeWaveVm;
private readonly AmbientLightningEffectViewModel _ambientLightningVm;
public EffectsViewModel(MainManager mainManager)
{
_typeWaveVm = new TypeWaveViewModel(mainManager) {DisplayName = "Type Waves"};
//_typeHoleVm = new TypeHoleViewModel(MainManager) {DisplayName = "Type Holes (NYI)"};
_audioVisualizerVm = new AudioVisualizerViewModel(mainManager) {DisplayName = "Audio Visualization"};
_ambientLightningVm = new AmbientLightningEffectViewModel(mainManager) {DisplayName = "Ambient Lightning"};
_debugVm = new DebugEffectViewModel(mainManager) {DisplayName = "Debug Effect"};
}
@ -29,6 +32,7 @@ namespace Artemis.ViewModels
ActivateItem(_typeWaveVm);
//ActivateItem(_typeHoleVm);
ActivateItem(_audioVisualizerVm);
ActivateItem(_ambientLightningVm);
ActivateItem(_debugVm);
}
}

View File

@ -8,11 +8,15 @@
<package id="CUE.NET" version="1.0.2.1" targetFramework="net452" />
<package id="Extended.Wpf.Toolkit" version="2.6" targetFramework="net452" />
<package id="Hardcodet.NotifyIcon.Wpf" version="1.0.5" targetFramework="net452" />
<package id="ImageLibrary" version="2.0.5" targetFramework="net452" />
<package id="log4net" version="2.0.5" targetFramework="net452" />
<package id="MahApps.Metro" version="1.2.4.0" targetFramework="net452" />
<package id="MahApps.Metro.Resources" version="0.4.0.0" targetFramework="net452" />
<package id="NAudio" version="1.7.3" targetFramework="net452" />
<package id="Newtonsoft.Json" version="8.0.2" targetFramework="net452" />
<package id="SharpDX" version="3.0.1" targetFramework="net452" />
<package id="SharpDX.Direct3D11" version="3.0.1" targetFramework="net452" />
<package id="SharpDX.DXGI" version="3.0.1" targetFramework="net452" />
<package id="VirtualInput" version="1.0.1" targetFramework="net452" />
<package id="WpfExceptionViewer" version="1.0.0.0" targetFramework="net452" />
</packages>