diff --git a/Output/AForge.Video.DirectShow.dll b/Output/AForge.Video.DirectShow.dll new file mode 100644 index 00000000..2d14556a Binary files /dev/null and b/Output/AForge.Video.DirectShow.dll differ diff --git a/Output/AForge.Video.dll b/Output/AForge.Video.dll new file mode 100644 index 00000000..7ff735b4 Binary files /dev/null and b/Output/AForge.Video.dll differ diff --git a/Output/Languages/Deutsch.xml b/Output/Languages/Deutsch.xml index 610e191e..a0d3db84 100644 --- a/Output/Languages/Deutsch.xml +++ b/Output/Languages/Deutsch.xml @@ -159,6 +159,10 @@ Aktiv Neu Löschen + Snapshot + Snapshot speichern + Snapshot löschen + Webcam Einstellungen Spiel @@ -212,6 +216,8 @@ Video-Vorschau Videos während des Singens Videos der Hintergrundmusik + Webcams + Webcamfähigkeiten Lautstärke diff --git a/Output/Languages/English.xml b/Output/Languages/English.xml index 02105784..c6859e32 100644 --- a/Output/Languages/English.xml +++ b/Output/Languages/English.xml @@ -159,6 +159,10 @@ Active New Delete + Take Snapshot + Save Snapshot + Delete Snapshot + Webcam Menu Options Game @@ -212,6 +216,8 @@ Video Preview Videos while singing Display current backgroundmusic video + Webcams + Webcamcapabilities Volume diff --git a/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml b/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml index a21e9cdc..80d1ac13 100644 --- a/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml +++ b/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml @@ -1,7 +1,7 @@  - 2 + 3 Video @@ -222,6 +222,64 @@ + + + 75 + 345 + + 0,00 + + 32 + + + + StaticColor + + + TextSColor + + Left + + Center + + + + Normal + + TR_SCREENO_VIDEO_WEBCAMDEVICES + + + + + + + 75 + 405 + + 0,00 + + 32 + + + + StaticColor + + + TextSColor + + Left + + Center + + + + Normal + + TR_SCREENO_VIDEO_WEBCAMCAPABILITIES + + + + Button @@ -539,5 +597,151 @@ 3 + + + Invisible + + SelectSlideArrowLeft + + SelectSlideArrowRight + + SelectSlide + + SelectSlideArrowLeft + + SelectSlideArrowRight + + SelectSlide + + 500 + 340 + 0,00 + 700 + 50 + + 505 + 345 + 0,00 + 40 + 40 + + 1170 + 345 + 0,00 + 40 + 40 + + + SelectSlideColor + + + SelectSlideSColor + + + SelectSlideHColor + + + ArrowColor + + + ArrowSColor + + + TextColor + + + TextSColor + + 32,00 + + 205,33 + + Normal + + Bold + + 3 + + + + Invisible + + SelectSlideArrowLeft + + SelectSlideArrowRight + + SelectSlide + + SelectSlideArrowLeft + + SelectSlideArrowRight + + SelectSlide + + 500 + 400 + 0,00 + 700 + 50 + + 505 + 405 + 0,00 + 40 + 40 + + 1170 + 405 + 0,00 + 40 + 40 + + + SelectSlideColor + + + SelectSlideSColor + + + SelectSlideHColor + + + ArrowColor + + + ArrowSColor + + + TextColor + + + TextSColor + + 32,00 + + 205,33 + + Normal + + Bold + + 3 + + + + CoverBackground + + 75 + 460 + 0,00 + 320 + 240 + + + Visible + + + + \ No newline at end of file diff --git a/Output/Themes/Ambient/Screens/ScreenProfiles.xml b/Output/Themes/Ambient/Screens/ScreenProfiles.xml index 7bd59c6b..06cf67ca 100644 --- a/Output/Themes/Ambient/Screens/ScreenProfiles.xml +++ b/Output/Themes/Ambient/Screens/ScreenProfiles.xml @@ -1,7 +1,7 @@  - 1 + 2 Video @@ -576,6 +576,234 @@ 26 + + + Button + + Button + + 985 + 600 + 0,00 + 150 + 50 + + + ButtonColor + + + ButtonSColor + + + 75 + 10 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + Center + + + + Outline + + TR_SCREENPROFILES_BUTTON_TAKESNAPSHOT + + + + + + 10 + 26 + + + + + + 10 + 26 + + + + + Button + + Button + + 985 + 600 + 0,00 + 150 + 50 + + + ButtonColor + + + ButtonSColor + + + 75 + 10 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + Center + + + + Outline + + TR_SCREENPROFILES_BUTTON_WEBCAM + + + + + + 10 + 26 + + + + + + 10 + 26 + + + + + Button + + Button + + 300 + 210 + 0,00 + 150 + 50 + + + ButtonColor + + + ButtonSColor + + + 75 + 10 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + Center + + + + Outline + + TR_SCREENPROFILES_BUTTON_SAVESNAPSHOT + + + + + + 10 + 26 + + + + + + 10 + 26 + + + + + Button + + Button + + 300 + 110 + 0,00 + 150 + 50 + + + ButtonColor + + + ButtonSColor + + + 75 + 10 + + 32 + + 142 + + + ButtonTextColor + + + ButtonTextSColor + + Center + + Center + + + + Outline + + TR_SCREENPROFILES_BUTTON_DISCARDSNAPSHOT + + + + + + 10 + 26 + + + + + + 10 + 26 + + Invisible diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs index 0ea13e8c..14ecf859 100644 --- a/Vocaluxe/Base/CConfig.cs +++ b/Vocaluxe/Base/CConfig.cs @@ -11,6 +11,7 @@ using System.Xml.XPath; using OpenTK.Platform; using Vocaluxe.Lib.Sound; +using Vocaluxe.Lib.Webcam; namespace Vocaluxe.Base { @@ -87,6 +88,12 @@ namespace Vocaluxe.Base OpenAL } + public enum EWebcamLib + { + OpenCV, + AForgeNet + } + public enum ERecordLib { #if WIN @@ -257,6 +264,8 @@ namespace Vocaluxe.Base // Record public static SMicConfig[] MicConfig; public static int MicDelay = 300; //[ms] + public static EWebcamLib WebcamLib = EWebcamLib.OpenCV; + public static SWebcamConfig WebcamConfig; //Lists to save parameters and values private static List _Params = new List(); @@ -443,6 +452,13 @@ namespace Vocaluxe.Base CHelper.TryGetEnumValueFromXML("//root/Video/VideoPreview", navigator, ref VideoPreview); CHelper.TryGetEnumValueFromXML("//root/Video/VideosInSongs", navigator, ref VideosInSongs); CHelper.TryGetEnumValueFromXML("//root/Video/VideosToBackground", navigator, ref VideosToBackground); + + CHelper.TryGetEnumValueFromXML("//root/Video/WebcamLib", navigator, ref WebcamLib); + WebcamConfig = new SWebcamConfig(); + CHelper.GetValueFromXML("//root/Video/WebcamConfig/MonikerString", navigator, ref WebcamConfig.MonikerString, String.Empty); + CHelper.TryGetIntValueFromXML("//root/Video/WebcamConfig/Framerate", navigator, ref WebcamConfig.Framerate); + CHelper.TryGetIntValueFromXML("//root/Video/WebcamConfig/Width", navigator, ref WebcamConfig.Width); + CHelper.TryGetIntValueFromXML("//root/Video/WebcamConfig/Height", navigator, ref WebcamConfig.Height); #endregion Video #region Record @@ -463,7 +479,6 @@ namespace Vocaluxe.Base MicDelay = 0; if (MicDelay > 500) MicDelay = 500; - #endregion Record return true; @@ -690,6 +705,18 @@ namespace Vocaluxe.Base writer.WriteComment("Show backgroundmusic videos as background: " + ListStrings(Enum.GetNames(typeof(EOffOn)))); writer.WriteElementString("VideosToBackground", Enum.GetName(typeof(EOffOn), VideosToBackground)); + writer.WriteComment("WebcamLib: " + ListStrings(Enum.GetNames(typeof(EWebcamLib)))); + writer.WriteElementString("WebcamLib", Enum.GetName(typeof(EWebcamLib), WebcamLib)); + + writer.WriteStartElement("WebcamConfig"); + + writer.WriteElementString("MonikerString", WebcamConfig.MonikerString); + writer.WriteElementString("Framerate", WebcamConfig.Framerate.ToString()); + writer.WriteElementString("Width", WebcamConfig.Width.ToString()); + writer.WriteElementString("Height", WebcamConfig.Height.ToString()); + + writer.WriteEndElement(); + writer.WriteEndElement(); #endregion Video diff --git a/Vocaluxe/Base/CWebcam.cs b/Vocaluxe/Base/CWebcam.cs new file mode 100644 index 00000000..cb735d77 --- /dev/null +++ b/Vocaluxe/Base/CWebcam.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using Vocaluxe.Lib.Webcam; +using Vocaluxe.Lib.Draw; +using System.Drawing; + +namespace Vocaluxe.Base +{ + static class CWebcam + { + private static IWebcam _Webcam; + + public static void Init() + { + switch (CConfig.WebcamLib) + { + case EWebcamLib.AForgeNet: + _Webcam = new CAForgeNet(); + break; + + default: + _Webcam = new CAForgeNet(); + break; + } + _Webcam.Init(); + _Webcam.Select(CConfig.WebcamConfig); + + CConfig.WebcamConfig = _Webcam.GetConfig(); + CConfig.SaveConfig(); + } + + public static bool GetFrame(ref STexture tex) + { + _Webcam.GetFrame(ref tex); + return true; + } + + public static Bitmap GetBitmap() + { + return _Webcam.GetBitmap(); + } + + public static void Close() + { + _Webcam.Close(); + } + + public static void Pause() + { + _Webcam.Pause(); + } + + public static void Start() + { + _Webcam.Start(); + } + + public static void Stop() + { + _Webcam.Stop(); + } + + public static void Select(SWebcamConfig c) + { + _Webcam.Select(c); + } + + public static SWebcamDevice[] GetDevices() + { + return _Webcam.GetDevices(); + } + } +} diff --git a/Vocaluxe/Lib/Webcam/CAForgeNet.cs b/Vocaluxe/Lib/Webcam/CAForgeNet.cs new file mode 100644 index 00000000..0d520e1a --- /dev/null +++ b/Vocaluxe/Lib/Webcam/CAForgeNet.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Vocaluxe.Base; +using AForge.Video; +using System.Drawing; +using AForge.Video.DirectShow; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using Vocaluxe.Lib.Draw; +using System.Threading; + +namespace Vocaluxe.Lib.Webcam +{ + class CAForgeNet : IWebcam + { + private Bitmap _CurrentFrame = new Bitmap(1, 1); + private List _Devices = new List(); + private bool _Paused; + private VideoCaptureDevice _Webcam; + private FilterInfoCollection _WebcamDevices; + private SWebcamConfig _Config; + + public void Close() + { + if (_Webcam != null) + { + _Webcam.SignalToStop(); + _Webcam.NewFrame -= new NewFrameEventHandler(OnFrame); + } + } + + public bool GetFrame(ref STexture Frame) + { + if ((_CurrentFrame != null) && (_Webcam != null)) + { + lock (_CurrentFrame) + { + BitmapData bitmapdata = _CurrentFrame.LockBits(new Rectangle(0, 0, _CurrentFrame.Width, _CurrentFrame.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + byte[] data = new byte[4 * _CurrentFrame.Width * _CurrentFrame.Height]; + Marshal.Copy(bitmapdata.Scan0, data, 0, data.Length); + _CurrentFrame.UnlockBits(bitmapdata); + if (((Frame.index == -1) || (_CurrentFrame.Width != Frame.width)) || (_CurrentFrame.Height != Frame.height)) + { + CDraw.RemoveTexture(ref Frame); + Frame = CDraw.AddTexture(_CurrentFrame.Width, _CurrentFrame.Height, ref data); + } + else + { + CDraw.UpdateTexture(ref Frame, ref data); + } + } + } + return false; + } + + public Bitmap GetBitmap() + { + if ((_CurrentFrame != null) && (_Webcam != null)) + { + lock (_CurrentFrame) + { + return (Bitmap)_CurrentFrame.Clone(); + } + } + else + return null; + } + + public bool Init() + { + _WebcamDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice); + int num = 0; + foreach (FilterInfo info in _WebcamDevices) + { + SWebcamDevice device = new SWebcamDevice { + ID = num, + Name = info.Name, + MonikerString = info.MonikerString, + Capabilities = new List() + }; + num++; + VideoCaptureDevice tmpdev = new VideoCaptureDevice(info.MonikerString); + + for (int i = 0; i < tmpdev.VideoCapabilities.Length; i++ ) + { + SCapabilities item = new SCapabilities + { + Framerate = tmpdev.VideoCapabilities[i].FrameRate, + Height = tmpdev.VideoCapabilities[i].FrameSize.Height, + Width = tmpdev.VideoCapabilities[i].FrameSize.Width + }; + device.Capabilities.Add(item); + } + _Devices.Add(device); + } + return true; + } + + private void OnFrame(object sender, NewFrameEventArgs e) + { + if (!_Paused) + { + lock (_CurrentFrame) + { + _CurrentFrame = (Bitmap) e.Frame.Clone(); + } + } + } + + public void Pause() + { + if (_Webcam != null) + { + _Paused = true; + } + } + + public void Start() + { + if (_Webcam != null) + { + _Webcam.NewFrame -= new NewFrameEventHandler(OnFrame); + //Subscribe to NewFrame event + _Webcam.NewFrame += new NewFrameEventHandler(OnFrame); + _Webcam.Start(); + _Paused = false; + } + } + + public void Stop() + { + if (_Webcam != null) + { + _Webcam.SignalToStop(); + } + } + + public SWebcamDevice[] GetDevices() + { + return _Devices.ToArray(); + } + + public bool Select(SWebcamConfig Config) + { + //Close old camera connection + Close(); + + if (_WebcamDevices == null) + return false; + if (_WebcamDevices.Count < 1) + return false; + + //No MonikerString found, try first webcam + if (Config.MonikerString == String.Empty) + _Webcam = new VideoCaptureDevice(_WebcamDevices[0].MonikerString); + else //Found MonikerString + _Webcam = new VideoCaptureDevice(Config.MonikerString); + + if (_Webcam == null) + return false; + + if (Config.Framerate != 0 && Config.Height != 0 && Config.Width != 0) + { + _Webcam.DesiredFrameRate = Config.Framerate; + _Webcam.DesiredFrameSize = new Size(Config.Width, Config.Height); + } + + _Config.Framerate = _Webcam.DesiredFrameRate; + _Config.Height = _Webcam.DesiredFrameSize.Height; + _Config.Width = _Webcam.DesiredFrameSize.Width; + _Config.MonikerString = _Webcam.Source; + + return true; + } + + public SWebcamConfig GetConfig() + { + return _Config; + } + } +} diff --git a/Vocaluxe/Lib/Webcam/IWebcam.cs b/Vocaluxe/Lib/Webcam/IWebcam.cs new file mode 100644 index 00000000..5b0ed223 --- /dev/null +++ b/Vocaluxe/Lib/Webcam/IWebcam.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Vocaluxe.Lib.Draw; +using System.Drawing; + +namespace Vocaluxe.Lib.Webcam +{ + struct SWebcamDevice + { + public int ID; + public string Name; + public string MonikerString; + public List Capabilities; + } + + struct SCapabilities + { + public int Framerate; + public int Width; + public int Height; + } + + struct SWebcamConfig + { + public string MonikerString; + public int Framerate; + public int Width; + public int Height; + } + + interface IWebcam + { + bool Init(); + + void Start(); + void Pause(); + void Stop(); + void Close(); + + bool GetFrame(ref STexture Frame); + Bitmap GetBitmap(); + SWebcamConfig GetConfig(); + SWebcamDevice[] GetDevices(); + + bool Select(SWebcamConfig sWebcamConfig); + } +} diff --git a/Vocaluxe/Program.cs b/Vocaluxe/Program.cs index a7ca0de1..90927e87 100644 --- a/Vocaluxe/Program.cs +++ b/Vocaluxe/Program.cs @@ -89,6 +89,13 @@ namespace Vocaluxe Application.DoEvents(); + //Init Webcam + CLog.StartBenchmark(0, "Init Webcam"); + CWebcam.Init(); + CLog.StopBenchmark(0, "Init Webcam"); + + Application.DoEvents(); + // Init Background Music CLog.StartBenchmark(0, "Init Background Music"); CBackgroundMusic.Init(); @@ -179,6 +186,7 @@ namespace Vocaluxe CDraw.Unload(); CLog.CloseAll(); CDataBase.CloseConnections(); + CWebcam.Close(); } catch (Exception) { diff --git a/Vocaluxe/Screens/CScreenOptionsVideo.cs b/Vocaluxe/Screens/CScreenOptionsVideo.cs index fd693db6..3e15a258 100644 --- a/Vocaluxe/Screens/CScreenOptionsVideo.cs +++ b/Vocaluxe/Screens/CScreenOptionsVideo.cs @@ -5,6 +5,7 @@ using System.Windows.Forms; using Vocaluxe.Base; using Vocaluxe.Menu; +using Vocaluxe.Lib.Webcam; namespace Vocaluxe.Screens @@ -12,15 +13,24 @@ namespace Vocaluxe.Screens class CScreenOptionsVideo : CMenu { // Version number for theme files. Increment it, if you've changed something on the theme files! - const int ScreenVersion = 2; + const int ScreenVersion = 3; private const string SelectSlideVideoBackgrounds = "SelectSlideVideoBackgrounds"; private const string SelectSlideVideoPreview = "SelectSlideVideoPreview"; private const string SelectSlideVideosInSongs = "SelectSlideVideosInSongs"; private const string SelectSlideVideosToBackground = "SelectSlideVideosToBackground"; + private const string SelectSlideWebcamDevices = "SelectSlideWebcamDevices"; + private const string SelectSlideWebcamCapabilities = "SelectSlideWebcamCapabilities"; + + private const string StaticWebcamOutput = "StaticWebcamOutput"; private const string ButtonExit = "ButtonExit"; + private SWebcamConfig _Config; + Lib.Draw.STexture _WebcamTexture = new Lib.Draw.STexture(-1); + private int _DeviceNr; + private int _CapabilityNr; + public CScreenOptionsVideo() { Init(); @@ -33,8 +43,9 @@ namespace Vocaluxe.Screens _ThemeName = "ScreenOptionsVideo"; _ScreenVersion = ScreenVersion; + _ThemeStatics = new string[] { StaticWebcamOutput }; _ThemeButtons = new string[] { ButtonExit }; - _ThemeSelectSlides = new string[] { SelectSlideVideoBackgrounds, SelectSlideVideoPreview, SelectSlideVideosInSongs, SelectSlideVideosToBackground }; + _ThemeSelectSlides = new string[] { SelectSlideVideoBackgrounds, SelectSlideVideoPreview, SelectSlideVideosInSongs, SelectSlideVideosToBackground, SelectSlideWebcamDevices, SelectSlideWebcamCapabilities }; } public override void LoadTheme() @@ -78,10 +89,18 @@ namespace Vocaluxe.Screens break; case Keys.Left: + if (SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selected) + OnDeviceEvent(); + if (SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selected) + OnCapabilitiesEvent(); SaveConfig(); break; case Keys.Right: + if (SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selected) + OnDeviceEvent(); + if (SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selected) + OnCapabilitiesEvent(); SaveConfig(); break; } @@ -101,6 +120,10 @@ namespace Vocaluxe.Screens if (MouseEvent.LB && IsMouseOver(MouseEvent)) { + if (SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selected) + OnDeviceEvent(); + if (SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selected) + OnCapabilitiesEvent(); SaveConfig(); if (Buttons[htButtons(ButtonExit)].Selected) { @@ -112,6 +135,8 @@ namespace Vocaluxe.Screens public override bool UpdateGame() { + CWebcam.GetFrame(ref _WebcamTexture); + Statics[htStatics(StaticWebcamOutput)].Texture = _WebcamTexture; SelectSlides[htSelectSlides(SelectSlideVideosToBackground)].Selection = (int)CConfig.VideosToBackground; return true; } @@ -119,18 +144,138 @@ namespace Vocaluxe.Screens public override bool Draw() { base.Draw(); + return true; } + public override void OnClose() + { + base.OnClose(); + CWebcam.Close(); + } + + public override void OnShow() + { + base.OnShow(); + SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Clear(); + SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Clear(); + + _DeviceNr = -1; + _CapabilityNr = -1; + + SWebcamDevice[] devices = CWebcam.GetDevices(); + + if (devices != null) + { + if (devices.Length > 0) + { + _DeviceNr = 0; + _CapabilityNr = 0; + GetFirstConfiguredWebcamDevice(ref _DeviceNr, ref _CapabilityNr); + + foreach (SWebcamDevice d in devices) + { + SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].AddValue(d.Name); + } + SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection = _DeviceNr; + + foreach (SCapabilities c in devices[_DeviceNr].Capabilities) + { + SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].AddValue(c.Width.ToString() + " x " + c.Height.ToString() + " @ " + c.Framerate.ToString() + " FPS "); + } + _Config.MonikerString = devices[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].MonikerString; + _Config.Width = devices[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].Capabilities[SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection].Width; + _Config.Height = devices[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].Capabilities[SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection].Height; + _Config.Framerate = devices[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].Capabilities[SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection].Framerate; + CWebcam.Close(); + CWebcam.Select(CConfig.WebcamConfig); + CWebcam.Start(); + } + } + SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Visible = (devices != null && devices.Length > 0); + SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Visible = (devices != null && devices.Length > 0); + Statics[htStatics(StaticWebcamOutput)].Visible = (devices != null && devices.Length > 0); + } + private void SaveConfig() { CConfig.VideoBackgrounds = (EOffOn)SelectSlides[htSelectSlides(SelectSlideVideoBackgrounds)].Selection; CConfig.VideoPreview = (EOffOn)SelectSlides[htSelectSlides(SelectSlideVideoPreview)].Selection; CConfig.VideosInSongs = (EOffOn)SelectSlides[htSelectSlides(SelectSlideVideosInSongs)].Selection; CConfig.VideosToBackground = (EOffOn)SelectSlides[htSelectSlides(SelectSlideVideosToBackground)].Selection; + + CConfig.WebcamConfig = _Config; CBackgroundMusic.VideoEnabled = true; CConfig.SaveConfig(); } + + private void OnDeviceEvent() + { + if (SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection != _DeviceNr) + { + SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Clear(); + _DeviceNr = SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection; + _CapabilityNr = 0; + + SWebcamDevice[] d = CWebcam.GetDevices(); + for (int i = 0; i < d[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].Capabilities.Count; i++) + { + SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].AddValue(d[_DeviceNr].Capabilities[i].Width.ToString() + " x " + d[_DeviceNr].Capabilities[i].Height.ToString() + " @ " + d[_DeviceNr].Capabilities[i].Framerate.ToString() + "FPS"); + } + SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection = 0; + + _Config.MonikerString = d[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].MonikerString; + _Config.Width = d[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].Capabilities[SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection].Width; + _Config.Height = d[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].Capabilities[SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection].Height; + _Config.Framerate = d[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].Capabilities[SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection].Framerate; + + CWebcam.Close(); + CWebcam.Select(_Config); + CWebcam.Start(); + } + } + + private void OnCapabilitiesEvent() + { + if (SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection != _CapabilityNr) + { + _CapabilityNr = SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection; + + SWebcamDevice[] d = CWebcam.GetDevices(); + _Config.MonikerString = d[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].MonikerString; + _Config.Width = d[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].Capabilities[SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection].Width; + _Config.Height = d[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].Capabilities[SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection].Height; + _Config.Framerate = d[SelectSlides[htSelectSlides(SelectSlideWebcamDevices)].Selection].Capabilities[SelectSlides[htSelectSlides(SelectSlideWebcamCapabilities)].Selection].Framerate; + + CWebcam.Close(); + CWebcam.Select(_Config); + CWebcam.Start(); + } + } + + private void GetFirstConfiguredWebcamDevice(ref int Device, ref int Capabilities) + { + SWebcamDevice[] devices = CWebcam.GetDevices(); + + if (devices == null) + return; + + for (int i = 0; i < devices.Length; i++) + { + if (devices[i].MonikerString == CConfig.WebcamConfig.MonikerString) + { + for (int j = 0; j < devices[i].Capabilities.Count; j++) + { + if (devices[i].Capabilities[j].Framerate == CConfig.WebcamConfig.Framerate && devices[i].Capabilities[j].Width == CConfig.WebcamConfig.Width && devices[i].Capabilities[j].Height == CConfig.WebcamConfig.Height) + { + Device = i; + Capabilities = j; + return; + } + } + } + } + } } } diff --git a/Vocaluxe/Screens/CScreenProfiles.cs b/Vocaluxe/Screens/CScreenProfiles.cs index 394e165d..822ebc5f 100644 --- a/Vocaluxe/Screens/CScreenProfiles.cs +++ b/Vocaluxe/Screens/CScreenProfiles.cs @@ -5,6 +5,9 @@ using System.Windows.Forms; using Vocaluxe.Base; using Vocaluxe.Menu; +using System.Drawing; +using System.IO; +using Vocaluxe.Lib.Draw; namespace Vocaluxe.Screens { @@ -17,7 +20,7 @@ namespace Vocaluxe.Screens class CScreenProfiles : CMenu { // Version number for theme files. Increment it, if you've changed something on the theme files! - const int ScreenVersion = 1; + const int ScreenVersion = 2; private const string SelectSlideProfiles = "SelectSlideProfiles"; private const string SelectSlideDifficulty = "SelectSlideDifficulty"; @@ -29,10 +32,17 @@ namespace Vocaluxe.Screens private const string ButtonSave = "ButtonSave"; private const string ButtonNew = "ButtonNew"; private const string ButtonDelete = "ButtonDelete"; + private const string ButtonWebcam = "ButtonWebcam"; + private const string ButtonSaveSnapshot = "ButtonSaveSnapshot"; + private const string ButtonDiscardSnapshot = "ButtonDiscardSnapshot"; + private const string ButtonTakeSnapshot = "ButtonTakeSnapshot"; private const string StaticAvatar = "StaticAvatar"; private EEditMode _EditMode; + + private Lib.Draw.STexture _WebcamTexture = new Lib.Draw.STexture(-1); + private Bitmap _Snapshot = null; public CScreenProfiles() { @@ -45,7 +55,7 @@ namespace Vocaluxe.Screens _ThemeName = "ScreenProfiles"; _ScreenVersion = ScreenVersion; - _ThemeButtons = new string[] { ButtonPlayerName, ButtonExit, ButtonSave, ButtonNew, ButtonDelete }; + _ThemeButtons = new string[] { ButtonPlayerName, ButtonExit, ButtonSave, ButtonNew, ButtonDelete, ButtonWebcam, ButtonSaveSnapshot, ButtonDiscardSnapshot, ButtonTakeSnapshot }; _ThemeSelectSlides = new string[] { SelectSlideProfiles, SelectSlideDifficulty, SelectSlideAvatars, SelectSlideGuestProfile, SelectSlideActive }; _ThemeStatics = new string[] { StaticAvatar }; @@ -56,6 +66,11 @@ namespace Vocaluxe.Screens { base.LoadTheme(); + Buttons[htButtons(ButtonSaveSnapshot)].Visible = false; + Buttons[htButtons(ButtonDiscardSnapshot)].Visible = false; + Buttons[htButtons(ButtonTakeSnapshot)].Visible = false; + if (CWebcam.GetDevices().Length > 0) + Buttons[htButtons(ButtonWebcam)].Visible = true; SelectSlides[htSelectSlides(SelectSlideDifficulty)].SetValues(0); SelectSlides[htSelectSlides(SelectSlideGuestProfile)].SetValues(0); SelectSlides[htSelectSlides(SelectSlideActive)].SetValues(0); @@ -108,6 +123,18 @@ namespace Vocaluxe.Screens } else if (Buttons[htButtons(ButtonDelete)].Selected) { DeleteProfile(); + } else if (Buttons[htButtons(ButtonWebcam)].Selected && CWebcam.GetDevices().Length > 0) + { + OnWebcam(); + } else if (Buttons[htButtons(ButtonSaveSnapshot)].Selected && CWebcam.GetDevices().Length > 0) + { + OnSaveSnapshot(); + } else if (Buttons[htButtons(ButtonDiscardSnapshot)].Selected && CWebcam.GetDevices().Length > 0) + { + OnDiscardSnapshot(); + } else if (Buttons[htButtons(ButtonTakeSnapshot)].Selected && CWebcam.GetDevices().Length > 0) + { + OnTakeSnapshot(); } break; @@ -187,6 +214,18 @@ namespace Vocaluxe.Screens { CProfiles.SetActive(SelectSlides[htSelectSlides(SelectSlideProfiles)].Selection, (EOffOn)SelectSlides[htSelectSlides(SelectSlideActive)].Selection); + } else if (Buttons[htButtons(ButtonWebcam)].Selected && CWebcam.GetDevices().Length > 0) + { + OnWebcam(); + } else if (Buttons[htButtons(ButtonSaveSnapshot)].Selected && CWebcam.GetDevices().Length > 0) + { + OnSaveSnapshot(); + } else if (Buttons[htButtons(ButtonDiscardSnapshot)].Selected && CWebcam.GetDevices().Length > 0) + { + OnDiscardSnapshot(); + } else if (Buttons[htButtons(ButtonTakeSnapshot)].Selected && CWebcam.GetDevices().Length > 0) + { + OnTakeSnapshot(); } } @@ -197,6 +236,68 @@ namespace Vocaluxe.Screens return true; } + private void OnTakeSnapshot() + { + Buttons[htButtons(ButtonSaveSnapshot)].Visible = true; + Buttons[htButtons(ButtonDiscardSnapshot)].Visible = true; + Buttons[htButtons(ButtonWebcam)].Visible = false; + Buttons[htButtons(ButtonTakeSnapshot)].Visible = false; + _Snapshot = CWebcam.GetBitmap(); + } + + private void OnDiscardSnapshot() + { + CWebcam.Stop(); + CDraw.RemoveTexture(ref _WebcamTexture); + _Snapshot = null; + Buttons[htButtons(ButtonSaveSnapshot)].Visible = false; + Buttons[htButtons(ButtonDiscardSnapshot)].Visible = false; + Buttons[htButtons(ButtonTakeSnapshot)].Visible = false; + Buttons[htButtons(ButtonWebcam)].Visible = true; + } + + private void OnSaveSnapshot() + { + string filename = "snapshot"; + int i = 0; + while (File.Exists(Path.Combine(CSettings.sFolderProfiles, filename + i + ".png"))) + { + i++; + } + _Snapshot.Save(Path.Combine(CSettings.sFolderProfiles, filename + i + ".png"), System.Drawing.Imaging.ImageFormat.Png); + CProfiles.LoadAvatars(); + LoadAvatars(); + _Snapshot = null; + CWebcam.Stop(); + CDraw.RemoveTexture(ref _WebcamTexture); + + for (int j = 0; j < CProfiles.Avatars.Length; j++) + { + if (CProfiles.Avatars[j].FileName == (filename + i + ".png")) + { + CProfiles.SetAvatar(SelectSlides[htSelectSlides(SelectSlideProfiles)].Selection, j); + break; + } + + } + + Buttons[htButtons(ButtonSaveSnapshot)].Visible = false; + Buttons[htButtons(ButtonDiscardSnapshot)].Visible = false; + Buttons[htButtons(ButtonTakeSnapshot)].Visible = false; + Buttons[htButtons(ButtonWebcam)].Visible = true; + } + + private void OnWebcam() + { + _Snapshot = null; + CWebcam.Start(); + CWebcam.GetFrame(ref _WebcamTexture); + Buttons[htButtons(ButtonSaveSnapshot)].Visible = false; + Buttons[htButtons(ButtonDiscardSnapshot)].Visible = false; + Buttons[htButtons(ButtonTakeSnapshot)].Visible = true; + Buttons[htButtons(ButtonWebcam)].Visible = false; + } + public override bool UpdateGame() { if (SelectSlides[htSelectSlides(SelectSlideProfiles)].Selection > -1) @@ -211,7 +312,18 @@ namespace Vocaluxe.Screens int avatarNr = CProfiles.GetAvatarNr(SelectSlides[htSelectSlides(SelectSlideProfiles)].Selection); SelectSlides[htSelectSlides(SelectSlideAvatars)].Selection = avatarNr; - Statics[htStatics(StaticAvatar)].Texture = CProfiles.Avatars[avatarNr].Texture; + if (CWebcam.GetDevices().Length > 0 && _WebcamTexture.index > 0) + { + if(_Snapshot == null) + CWebcam.GetFrame(ref _WebcamTexture); + Statics[htStatics(StaticAvatar)].Texture = _WebcamTexture; + + RectangleF bounds = new RectangleF(_WebcamTexture.rect.X, _WebcamTexture.rect.Y, _WebcamTexture.rect.W, _WebcamTexture.rect.H); + RectangleF rect = new RectangleF(0f, 0f, _WebcamTexture.rect.W, _WebcamTexture.rect.H); + CHelper.SetRect(bounds, ref rect, rect.Width / rect.Height, EAspect.Crop); + } + else + Statics[htStatics(StaticAvatar)].Texture = CProfiles.Avatars[avatarNr].Texture; } return true; diff --git a/Vocaluxe/Screens/CScreenSing.cs b/Vocaluxe/Screens/CScreenSing.cs index 5b3b96c7..25cea953 100644 --- a/Vocaluxe/Screens/CScreenSing.cs +++ b/Vocaluxe/Screens/CScreenSing.cs @@ -75,6 +75,7 @@ namespace Vocaluxe.Screens private int _CurrentVideo = -1; private EAspect _VideoAspect = EAspect.Crop; private STexture _CurrentVideoTexture = new STexture(-1); + private STexture _CurrentWebcamFrameTexture = new STexture(-1); private STexture _Background = new STexture(-1); private float _CurrentTime = 0f; @@ -92,6 +93,7 @@ namespace Vocaluxe.Screens private Stopwatch _TimerDuetText2; private bool _Pause; + private bool _Webcam; public CScreenSing() { @@ -184,13 +186,13 @@ namespace Vocaluxe.Screens TogglePause(); if (_Pause) SetInteractionToButton(Buttons[htButtons(ButtonContinue)]); - break; - + break; + case Keys.T: int mode = (int)CConfig.TimerMode; - + mode++; - if (mode > Enum.GetNames(typeof(ETimerMode)).Length-1) + if (mode > Enum.GetNames(typeof(ETimerMode)).Length - 1) { mode = 0; } @@ -215,7 +217,16 @@ namespace Vocaluxe.Screens if(KeyEvent.ModCTRL) LoadNextSong(); break; - + case Keys.W: + if (CWebcam.GetDevices().Length > 0) + { + _Webcam = !_Webcam; + if (_Webcam) + CWebcam.Start(); + else + CWebcam.Stop(); + } + break; case Keys.Enter: if (Buttons[htButtons(ButtonContinue)].Selected && _Pause) TogglePause(); @@ -299,7 +310,7 @@ namespace Vocaluxe.Screens } else Finish = true; - + if (Finish) { LoadNextSong(); @@ -307,7 +318,6 @@ namespace Vocaluxe.Screens UpdateSongText(); UpdateDuetText(); - if (_FadeOut) return true; @@ -346,7 +356,7 @@ namespace Vocaluxe.Screens Texts[htTexts(TextNames[p, CGame.NumPlayer - 1])].Alpha = Alpha[CGame.Player[p].LineNr * 2]; Texts[htTexts(TextScores[p, CGame.NumPlayer - 1])].Alpha = Alpha[CGame.Player[p].LineNr * 2]; } - } + } if (Alpha.Length > 2) { @@ -363,7 +373,7 @@ namespace Vocaluxe.Screens Statics[htStatics(StaticLyricHelper)].Alpha = Alpha[2]; } } - + for (int p = 0; p < CGame.NumPlayer; p++) { @@ -382,18 +392,22 @@ namespace Vocaluxe.Screens float vtime = 0f; CVideo.VdGetFrame(_CurrentVideo, ref _CurrentVideoTexture, _CurrentTime, ref vtime); } - + + if (_Webcam) + CWebcam.GetFrame(ref _CurrentWebcamFrameTexture); + return true; } public override void OnShow() { base.OnShow(); - + _FadeOut = false; - + _CurrentVideo = -1; _CurrentVideoTexture = new STexture(-1); + _CurrentWebcamFrameTexture = new STexture(-1); _CurrentBeat = -100; _CurrentTime = 0f; _FinishTime = 0f; @@ -403,7 +417,7 @@ namespace Vocaluxe.Screens _TimeRects.Clear(); - SingNotes[htSingNotes(SingBars)].Reset(); + SingNotes[htSingNotes(SingBars)].Reset(); for (int i = 0; i < CSettings.MaxNumPlayer; i++) { NoteLines[i] = -1; @@ -435,7 +449,7 @@ namespace Vocaluxe.Screens { if (_Active) { - if (_CurrentVideo != -1 && CConfig.VideosInSongs == EOffOn.TR_CONFIG_ON) + if (_CurrentVideo != -1 && CConfig.VideosInSongs == EOffOn.TR_CONFIG_ON && !_Webcam) { RectangleF bounds = new RectangleF(0, 0, CSettings.iRenderW, CSettings.iRenderH); RectangleF rect = new RectangleF(0f, 0f, _CurrentVideoTexture.width, _CurrentVideoTexture.height); @@ -444,6 +458,15 @@ namespace Vocaluxe.Screens CDraw.DrawTexture(_CurrentVideoTexture, new SRectF(rect.X, rect.Y, rect.Width, rect.Height, 0f), _CurrentVideoTexture.color, new SRectF(bounds.X, bounds.Y, bounds.Width, bounds.Height, 0f), false); } + else if (_Webcam) + { + RectangleF bounds = new RectangleF(0, 0, CSettings.iRenderW, CSettings.iRenderH); + RectangleF rect = new RectangleF(0f, 0f, _CurrentWebcamFrameTexture.width, _CurrentWebcamFrameTexture.height); + CHelper.SetRect(bounds, ref rect, rect.Width / rect.Height, _VideoAspect); + + CDraw.DrawTexture(_CurrentWebcamFrameTexture, new SRectF(rect.X, rect.Y, rect.Width, rect.Height, 0f), + _CurrentVideoTexture.color, new SRectF(bounds.X, bounds.Y, bounds.Width, bounds.Height, 0f), false); + } else { // Draw Background RectangleF bounds = new RectangleF(0, 0, CSettings.iRenderW, CSettings.iRenderH); @@ -484,7 +507,7 @@ namespace Vocaluxe.Screens Lyrics[htLyrics(LyricSubTop)].Draw(-100); Lyrics[htLyrics(LyricMainTop)].Draw(CGame.Beat); - + for (int i = 0; i < CGame.NumPlayer; i++) { @@ -504,7 +527,7 @@ namespace Vocaluxe.Screens foreach (CSelectSlide slide in SelectSlides) slide.Draw(); } - + return true; } @@ -593,7 +616,7 @@ namespace Vocaluxe.Screens CGame.ResetPlayer(); CDraw.RemoveTexture(ref _CurrentVideoTexture); - + if (song.VideoFileName != String.Empty) { _CurrentVideo = CVideo.VdLoad(Path.Combine(song.Folder, song.VideoFileName)); @@ -654,7 +677,7 @@ namespace Vocaluxe.Screens CTheme.GetPlayerColor(p + 1), p); } - + /* case 4: NoteLines[0] = SingNotes[htSingNotes(SingBars)].AddPlayer(new SRectF(35f, 100f, 590f, 200f, -0.5f), CTheme.ThemeColors.Player[0]); @@ -663,7 +686,7 @@ namespace Vocaluxe.Screens NoteLines[3] = SingNotes[htSingNotes(SingBars)].AddPlayer(new SRectF(640f, 350f, 590f, 200f, -0.5f), CTheme.ThemeColors.Player[3]); break; */ - + _TimerSongText.Stop(); _TimerSongText.Reset(); @@ -685,6 +708,8 @@ namespace Vocaluxe.Screens PrepareTimeLine(); CSound.Play(_CurrentStream); CSound.RecordStart(); + if(_Webcam) + CWebcam.Start(); } private void Stop() @@ -695,6 +720,8 @@ namespace Vocaluxe.Screens CGraphics.FadeTo(EScreens.ScreenScore); _FadeOut = true; + if (_Webcam) + CWebcam.Close(); } private void UpdateLyrics() @@ -808,6 +835,7 @@ namespace Vocaluxe.Screens Buttons[htButtons(ButtonContinue)].Visible = false; Buttons[htButtons(ButtonSkip)].Visible = false; CSound.Play(_CurrentStream); + CWebcam.Start(); } } @@ -837,7 +865,7 @@ namespace Vocaluxe.Screens { StaticScores = new string[CSettings.MaxNumPlayer, CSettings.MaxNumPlayer]; StaticAvatars = new string[CSettings.MaxNumPlayer, CSettings.MaxNumPlayer]; - + for (int numplayer = 0; numplayer < CSettings.MaxNumPlayer; numplayer++) { for (int player = 0; player < CSettings.MaxNumPlayer; player++) @@ -863,7 +891,7 @@ namespace Vocaluxe.Screens Statics[htStatics(StaticLyricHelperTop)].Visible = false; Lyrics[htLyrics(LyricMainDuet)].Visible = false; Lyrics[htLyrics(LyricSubDuet)].Visible = false; - + Statics[htStatics(StaticSongText)].Visible = false; Texts[htTexts(TextSongName)].Visible = false; Texts[htTexts(TextDuetName1)].Visible = false; @@ -879,7 +907,7 @@ namespace Vocaluxe.Screens Texts[htTexts(TextNames[player, numplayer])].Visible = ((numplayer + 1 == CGame.NumPlayer) && (CConfig.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH || CConfig.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_NAME)); Statics[htStatics(StaticScores[player, numplayer])].Visible = (numplayer + 1 == CGame.NumPlayer); - Statics[htStatics(StaticAvatars[player, numplayer])].Visible = ((numplayer + 1 == CGame.NumPlayer) + Statics[htStatics(StaticAvatars[player, numplayer])].Visible = ((numplayer + 1 == CGame.NumPlayer) && (CConfig.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH || CConfig.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_AVATAR)); } } @@ -971,7 +999,7 @@ namespace Vocaluxe.Screens time = totaltime; SRectF Rect = Statics[htStatics(StaticLyricHelperDuet)].Rect; - + SColorF Color = new SColorF( Statics[htStatics(StaticLyricHelperDuet)].Color.R, Statics[htStatics(StaticLyricHelperDuet)].Color.G, @@ -1031,7 +1059,7 @@ namespace Vocaluxe.Screens // default values Alpha[i * 2] = 1f; - Alpha[i * 2 + 1] = 1f; + Alpha[i * 2 + 1] = 1f; // main line alpha if (CurrentLine == 0 && CurrentTime < CGame.GetTimeFromBeats(line[CurrentLine].FirstNoteBeat, Song.BPM)) @@ -1063,15 +1091,15 @@ namespace Vocaluxe.Screens float next = CGame.GetTimeFromBeats(line[CurrentLine + 1].FirstNoteBeat, Song.BPM) - CurrentTime; if (last < next) - { + { // fade out Alpha[i * 2] = 1f - last / rt; - } + } else - { + { // fade in if it is time for - if (next > dt) - Alpha[i * 2] = 1f - (next - dt) / rt; + if (next > dt) + Alpha[i * 2] = 1f - (next - dt) / rt; } } } @@ -1086,9 +1114,9 @@ namespace Vocaluxe.Screens // sub if (CurrentLineSub < line.Length - 2) { - float diff = 0f; + float diff = 0f; diff = CGame.GetTimeFromBeats(line[CurrentLineSub + 1].FirstNoteBeat, Song.BPM) - CurrentTime; - + if (diff > dt) { Alpha[i * 2 + 1] = 1f - (diff - dt) / rt; @@ -1229,7 +1257,7 @@ namespace Vocaluxe.Screens float CurrentTime = _CurrentTime - song.Start; if (TotalTime <= 0f) - return; + return; switch (CConfig.TimerMode) { @@ -1312,15 +1340,15 @@ namespace Vocaluxe.Screens CLines[] Lines = new CLines[song.Notes.Lines.Length]; Lines = song.Notes.Lines; for (int i = 0; i < Lines.Length; i++) - { + { CLine[] Line = Lines[i].Line; - for(int j = 0; jtrue Vocaluxe.MainProgram Vocaluxe.ico + x86 @@ -140,6 +141,16 @@ + + False + ..\Output\AForge.Video.dll + False + + + False + ..\Output\AForge.Video.DirectShow.dll + False + ..\Output\Community.CsharpSqlite.dll @@ -176,6 +187,7 @@ + @@ -207,6 +219,8 @@ + +