diff --git a/GuessWhatLookingAt.zip b/GuessWhatLookingAt.zip
new file mode 100644
index 0000000..0dbc6da
Binary files /dev/null and b/GuessWhatLookingAt.zip differ
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/App.config b/GuessWhatLookingAt/GuessWhatLookingAt/App.config
new file mode 100644
index 0000000..abd76ea
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/App.config
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tcp://127.0.0.1:50020
+
+
+ 6555
+
+
+ 2
+
+
+ 2
+
+
+ 3
+
+
+ 4
+
+
+ False
+
+
+ True
+
+
+ Player
+
+
+
+
+ EYETRIBE
+
+
+ 10
+
+
+ 16
+
+
+
+
\ No newline at end of file
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/App.xaml b/GuessWhatLookingAt/GuessWhatLookingAt/App.xaml
new file mode 100644
index 0000000..60c9ceb
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/App.xaml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/App.xaml.cs b/GuessWhatLookingAt/GuessWhatLookingAt/App.xaml.cs
new file mode 100644
index 0000000..08e0351
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/App.xaml.cs
@@ -0,0 +1,58 @@
+using System;
+using System.IO;
+using System.Windows;
+using System.Xml.Serialization;
+
+namespace GuessWhatLookingAt
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ base.OnStartup(e);
+
+ //WindowViewParameters viewSettings = new WindowViewParameters();
+
+ #region Reading settings
+
+ var gameSettings = new FreezeGameSettings();
+ gameSettings.NameToRanking = GuessWhatLookingAt.Properties.Settings.Default.NameToRanking;
+ gameSettings.PupilAdressString = GuessWhatLookingAt.Properties.Settings.Default.PupilAdressString;
+ gameSettings.EyeTribePort = GuessWhatLookingAt.Properties.Settings.Default.EyeTribePort;
+ gameSettings.AttemptsAmount = GuessWhatLookingAt.Properties.Settings.Default.AttemptsAmount;
+ gameSettings.RoundsAmount = GuessWhatLookingAt.Properties.Settings.Default.RoundsAmount;
+ gameSettings.PhotoTime = GuessWhatLookingAt.Properties.Settings.Default.PhotoTime;
+ gameSettings.EyeTribeTime = GuessWhatLookingAt.Properties.Settings.Default.EyeTribeTime;
+ gameSettings.DisplayPupilGazePoint = GuessWhatLookingAt.Properties.Settings.Default.DisplayPupilGazePoint;
+ gameSettings.DisplayEyeTribeGazePoint = GuessWhatLookingAt.Properties.Settings.Default.DisplayEyeTribeGazePoint;
+
+ #endregion
+
+ #region Reading ranking records
+
+ ListOfRankingRecords rankingRecords = new ListOfRankingRecords();
+
+ try
+ {
+ var xml = new XmlSerializer(typeof(ListOfRankingRecords));
+ FileStream fs = new FileStream("rank.xml", FileMode.OpenOrCreate);
+ TextReader reader = new StreamReader(fs);
+ rankingRecords = (ListOfRankingRecords)xml.Deserialize(reader);
+ }
+ catch (Exception)
+ {
+ rankingRecords = new ListOfRankingRecords();
+ }
+
+ #endregion
+
+ MainWindow app = new MainWindow();
+ MainWindowViewModel context = new MainWindowViewModel(app, gameSettings, rankingRecords);
+ app.DataContext = context;
+ app.Show();
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/EmguCVImage/EmguCVImage.cs b/GuessWhatLookingAt/GuessWhatLookingAt/EmguCVImage/EmguCVImage.cs
new file mode 100644
index 0000000..79d8946
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/EmguCVImage/EmguCVImage.cs
@@ -0,0 +1,152 @@
+using Emgu.CV;
+using Emgu.CV.CvEnum;
+using Emgu.CV.Structure;
+using System;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace GuessWhatLookingAt
+{
+ public class EmguCVImage
+ {
+ public Mat OriginalMat { get; private set; }
+
+ public Mat OutMat { get; private set; }
+
+ public void SetMat(IntPtr dataPointer, int frameWidth, int frameHeight)
+ {
+ try
+ {
+ OriginalMat = new Mat(frameHeight,
+ frameWidth,
+ DepthType.Cv8U,
+ 3,
+ dataPointer,
+ frameWidth * 3);
+ OutMat = OriginalMat.Clone();
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+
+ public void DrawCircleForPupil(GazePoint point, bool cleanImage = false)
+ {
+ try
+ {
+ if (OutMat != null)
+ {
+ if (cleanImage)
+ OutMat = OriginalMat.Clone();
+
+ CvInvoke.Circle(
+ OutMat,
+ new System.Drawing.Point(Convert.ToInt32(point.point.X * OriginalMat.Width), Convert.ToInt32(point.point.Y * OriginalMat.Height)),
+ 1,
+ new Emgu.CV.Structure.MCvScalar(0, 128, 0),
+ 40);
+ }
+ }
+ catch (Exception)
+ {
+
+ }
+
+ }
+
+ public void DrawCircleForEyeTribe(Point point, bool cleanImage = false)
+ {
+ try
+ {
+ if (OutMat != null)
+ {
+ if (cleanImage)
+ OutMat = OriginalMat.Clone();
+
+ CvInvoke.Circle(OutMat,
+ new System.Drawing.Point(
+ Convert.ToInt32(point.X * OriginalMat.Width),
+ Convert.ToInt32(point.Y * OriginalMat.Height)),
+ 1,
+ new MCvScalar(0, 0, 128),
+ 40);
+ }
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+
+ public void DrawCircleForAttemptPoint(Point point)
+ {
+ try
+ {
+ CvInvoke.Circle(OutMat,
+ new System.Drawing.Point(
+ Convert.ToInt32(point.X * OriginalMat.Width),
+ Convert.ToInt32(point.Y * OriginalMat.Height)),
+ 1,
+ new Emgu.CV.Structure.MCvScalar(128, 0, 0),
+ 40);
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+
+ public void CleanImage()
+ {
+ try
+ {
+ if (OriginalMat != null)
+ OutMat = OriginalMat.Clone();
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+
+ public void DrawLineBetweenPoints(Point p1, Point p2)
+ {
+ try
+ {
+ CvInvoke.Line(
+ OutMat,
+ new System.Drawing.Point(
+ Convert.ToInt32(p1.X * OriginalMat.Width),
+ Convert.ToInt32(p1.Y * OriginalMat.Height)),
+ new System.Drawing.Point(
+ Convert.ToInt32(p2.X * OriginalMat.Width),
+ Convert.ToInt32(p2.Y * OriginalMat.Height)),
+ new MCvScalar(128, 128, 0),
+ 2);
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+
+ public BitmapSource GetBitmapSourceFromMat()
+ {
+ try
+ {
+ if (OutMat != null)
+ {
+ var byteArray = OutMat.GetRawData(new int[] { });
+ return BitmapSource.Create(OutMat.Width, OutMat.Height, 96, 96, PixelFormats.Bgr24, null, byteArray, OutMat.Width * 3);
+ }
+ }
+ catch (System.NullReferenceException)
+ {
+
+ }
+ return null;
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/EyeTrackers/EyeTribe.cs b/GuessWhatLookingAt/GuessWhatLookingAt/EyeTrackers/EyeTribe.cs
new file mode 100644
index 0000000..af21f16
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/EyeTrackers/EyeTribe.cs
@@ -0,0 +1,151 @@
+using Newtonsoft.Json.Linq;
+using System;
+using System.IO;
+using System.Net.Sockets;
+using System.Threading;
+
+namespace GuessWhatLookingAt
+{
+ class EyeTribe
+ {
+
+ private TcpClient socket;
+ private Thread incomingThread;
+ private System.Timers.Timer timerHeartbeat;
+
+ public bool isRunning { get; private set; } = false;
+
+ public event EventHandler OnData;
+
+ public delegate void ParameterizedThreadStart(object obj1, object obj2);
+
+ public bool Connect(object port)
+ {
+ var _port = (int)port;
+
+ try
+ {
+ socket = new TcpClient("localhost", _port);
+ }
+ catch (Exception ex)
+ {
+ Console.Out.WriteLine("Error connecting: " + ex.Message);
+ return false;
+ }
+
+ // Send the obligatory connect request message
+ string REQ_CONNECT = "{\"values\":{\"push\":true,\"version\":1},\"category\":\"tracker\",\"request\":\"set\"}";
+ Send(REQ_CONNECT);
+
+ // Lauch a seperate thread to parse incoming data
+ incomingThread = new Thread(ListenerLoop);
+ incomingThread.Start();
+
+ // Start a timer that sends a heartbeat every 250ms.
+ // The minimum interval required by the server can be read out
+ // in the response to the initial connect request.
+
+ string REQ_HEATBEAT = "{\"category\":\"heartbeat\",\"request\":null}";
+ timerHeartbeat = new System.Timers.Timer(250);
+ timerHeartbeat.Elapsed += delegate { Send(REQ_HEATBEAT); };
+ timerHeartbeat.Start();
+
+ return true;
+ }
+
+ private void Send(string message)
+ {
+ if (socket != null && socket.Connected)
+ {
+ StreamWriter writer = new StreamWriter(socket.GetStream());
+ writer.WriteLine(message);
+ writer.Flush();
+ }
+ }
+
+ private void ListenerLoop()
+ {
+ StreamReader reader = new StreamReader(socket.GetStream());
+ isRunning = true;
+
+ while (isRunning)
+ {
+ string response = string.Empty;
+
+ try
+ {
+ response = reader.ReadLine();
+
+ JObject jObject = JObject.Parse(response);
+
+ Packet p = new Packet();
+ p.rawData = jObject.ToString();
+
+ p.category = (string)jObject["category"];
+ p.request = (string)jObject["request"];
+ p.statuscode = (string)jObject["statuscode"];
+
+ JToken values = jObject.GetValue("values");
+
+ if (values != null)
+ {
+ p.values = values.ToString();
+ JObject gaze = JObject.Parse(values.SelectToken("frame").SelectToken("avg").ToString());
+ double gazeX = (double)gaze.Property("x").Value;
+ double gazeY = (double)gaze.Property("y").Value;
+
+ var args = new EyeTribeReceivedDataEventArgs();
+ args.data = p;
+ args.TimeReached = DateTime.Now;
+ OnEyeTribeDataReceived(args);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.Out.WriteLine("Error while reading response: " + ex.Message);
+ }
+ }
+ }
+
+ public void Disconnect()
+ {
+ if(isRunning)
+ {
+ isRunning = false;
+ incomingThread?.Abort();
+ timerHeartbeat.Dispose();
+ socket.Close();
+ socket.Dispose();
+ }
+ }
+
+ public class Packet
+ {
+ public string time = DateTime.UtcNow.Ticks.ToString();
+ public string category = string.Empty;
+ public string request = string.Empty;
+ public string statuscode = string.Empty;
+ public string values = string.Empty;
+ public string rawData { get; set; }
+
+ public Packet() { }
+ }
+
+ public class EyeTribeReceivedDataEventArgs : EventArgs
+ {
+ public Packet data { get; set; }
+ public DateTime TimeReached { get; set; }
+ }
+
+ protected virtual void OnEyeTribeDataReceived(EyeTribeReceivedDataEventArgs e)
+ {
+ EventHandler handler = OnData;
+ if (handler != null)
+ {
+ handler(this, e);
+ }
+ }
+
+
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/EyeTrackers/GazePoint.cs b/GuessWhatLookingAt/GuessWhatLookingAt/EyeTrackers/GazePoint.cs
new file mode 100644
index 0000000..812a5ec
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/EyeTrackers/GazePoint.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace GuessWhatLookingAt
+{
+ public class GazePoint : IComparable
+ {
+ public Point point { get; set; }
+ public double confidence { get; set; } = 0;
+
+ public GazePoint(Point p, double c)
+ {
+ point = p;
+ confidence = c;
+ }
+
+ public GazePoint(double x, double y, double c)
+ {
+ point = new Point(x, y);
+ confidence = c;
+ }
+
+ public int CompareTo(object obj)
+ {
+ if (obj == null)
+ return 1;
+
+ GazePoint otherGazePoint = obj as GazePoint;
+ if (otherGazePoint != null)
+ return confidence.CompareTo(otherGazePoint.confidence);
+ else
+ throw new ArgumentException("Object is not a GazePoint");
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/EyeTrackers/Pupil.cs b/GuessWhatLookingAt/GuessWhatLookingAt/EyeTrackers/Pupil.cs
new file mode 100644
index 0000000..0f18854
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/EyeTrackers/Pupil.cs
@@ -0,0 +1,161 @@
+using NetMQ;
+using NetMQ.Sockets;
+using SimpleMsgPack;
+using System;
+using System.Collections.Generic;
+using System.Windows;
+
+namespace GuessWhatLookingAt
+{
+ public class Pupil
+ {
+ RequestSocket requestClient;
+ SubscriberSocket frameSubscriber;
+ SubscriberSocket gazeSubscriber;
+
+ public bool isConnected { get; private set; } = false;
+
+ string subPort;
+ string pubPort;
+
+ System.Threading.Thread frameThread;
+
+ string frameTopic = "";
+ byte[] framePayload;
+ int frameHeight = 10;
+ int frameWidth = 10;
+ byte[] frameData;
+
+ string gazeMsg;
+ byte[] gazeData;
+
+ public event EventHandler PupilDataReceivedEvent;
+
+ public void Connect(object address)
+ {
+ var _address = (string)address;
+
+ requestClient = new RequestSocket();
+
+ requestClient.Connect(_address);
+
+ //getting subscriber and publisher port
+ requestClient.SendFrame("SUB_PORT");
+ subPort = requestClient.ReceiveFrameString();
+ requestClient.SendFrame("PUB_PORT");
+ pubPort = requestClient.ReceiveFrameString();
+
+ //if (frameSubscriber == null)
+ frameSubscriber = new SubscriberSocket();
+
+ //if (gazeSubscriber == null)
+ gazeSubscriber = new SubscriberSocket();
+
+ //connect to zmq subscriber port and getting frame data
+ frameSubscriber.Connect("tcp://127.0.0.1:" + subPort);
+ gazeSubscriber.Connect("tcp://127.0.0.1:" + subPort);
+
+ //set up subscription on video receive
+ frameSubscriber.Subscribe("frame.world");
+ gazeSubscriber.Subscribe("gaze.");
+
+ //preparing information about desired format video data
+ var msgpackNotify = new MsgPack();
+ msgpackNotify.ForcePathObject("subject").AsString = "frame_publishing.set_format";
+ msgpackNotify.ForcePathObject("format").AsString = "bgr";
+ var byteArrayNotify = msgpackNotify.Encode2Bytes();
+
+ //sending information
+ requestClient.SendMoreFrame("topic.frame_publishing.set_format")
+ .SendFrame(byteArrayNotify);
+
+ requestClient.ReceiveFrameString(); //confirm receive data
+
+ isConnected = true;
+
+ frameThread = new System.Threading.Thread(ReceiveFrame);
+ //gazeThread = new System.Threading.Thread(ReceiveGaze);
+
+ frameThread.Start();
+ //gazeThread.Start();
+ }
+
+ public void ReceiveFrame()
+ {
+ while (isConnected)
+ {
+ frameTopic = frameSubscriber.ReceiveFrameString(); //camera name
+ framePayload = frameSubscriber.ReceiveFrameBytes(); //json with data describe
+
+ MsgPack msgpackFrame = new MsgPack();
+ msgpackFrame.DecodeFromBytes(framePayload);
+
+ frameWidth = Convert.ToInt32(msgpackFrame.ForcePathObject("width").AsInteger);
+ frameHeight = Convert.ToInt32(msgpackFrame.ForcePathObject("height").AsInteger);
+
+ var imageArgs = new PupilReceivedDataEventArgs();
+ imageArgs.GazePoints = new List();
+
+ //receive video frame in bgr
+ frameData = frameSubscriber.ReceiveFrameBytes();
+
+ bool gazeReceived = true;
+
+ while (gazeReceived)
+ {
+ //receive gaze information
+ gazeSubscriber.TryReceiveFrameString(out gazeMsg);
+ gazeReceived = gazeSubscriber.TryReceiveFrameBytes(out gazeData);
+
+ if (gazeData != null)
+ {
+ var msgpackGaze = new MsgPack();
+ msgpackGaze.DecodeFromBytes(gazeData);
+
+ //new event for inform about video data
+ if (msgpackGaze.ForcePathObject("norm_pos").AsArray.Length >= 2 &&
+ msgpackGaze.ForcePathObject("confidence").AsFloat > 0.5)
+ {
+ imageArgs.GazePoints.Add(new GazePoint(
+ new Point(
+ msgpackGaze.ForcePathObject("norm_pos").AsArray[0].AsFloat,
+ (1.0 - msgpackGaze.ForcePathObject("norm_pos").AsArray[1].AsFloat)),
+ msgpackGaze.ForcePathObject("confidence").AsFloat));
+ }
+ }
+ }
+
+ imageArgs.RawImageData = frameData;
+ imageArgs.ImageTimestamp = msgpackFrame.ForcePathObject("timestamp").AsFloat;
+ imageArgs.ImageSize = new Size(frameWidth, frameHeight);
+
+ OnPupilReceivedData(imageArgs);
+ }
+ }
+
+ public void Disconnect()
+ {
+ isConnected = false;
+ frameThread?.Abort();
+
+ //clean after disconnecting
+ requestClient.Dispose();
+ frameSubscriber.Dispose();
+ gazeSubscriber.Dispose();
+ }
+
+ protected virtual void OnPupilReceivedData(PupilReceivedDataEventArgs args)
+ {
+ PupilDataReceivedEvent?.Invoke(this, args);
+ }
+
+ public class PupilReceivedDataEventArgs : EventArgs
+ {
+ public byte[] RawImageData { get; set; }
+ public double ImageTimestamp { get; set; }
+ public Size ImageSize { get; set; }
+ public List GazePoints { get; set; }
+ }
+ }
+}
+
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/FreezeGameModel.cs b/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/FreezeGameModel.cs
new file mode 100644
index 0000000..9a0e48a
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/FreezeGameModel.cs
@@ -0,0 +1,585 @@
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Windows;
+using System.Windows.Media;
+
+namespace GuessWhatLookingAt
+{
+ class FreezeGameModel
+ {
+ #region Variables
+
+ #region Image variables
+
+ readonly EmguCVImage image = new EmguCVImage();
+ public WindowViewParameters _WindowViewParameters { get; private set; }
+
+ public event EventHandler BitmapSourceReached;
+
+ public class BitmapSourceEventArgs : EventArgs
+ {
+ public BitmapSourceEventArgs(ImageSource im) => Image = im;
+
+ public ImageSource Image { get; set; }
+ }
+
+ List _AttemptPoints = new List();
+
+ #endregion//Image variables
+
+ #region Pupil variables
+
+ public Pupil pupil = new Pupil();
+
+ GazePoint _PupilGazePoint;
+ public bool IsPupilConnected { get; private set; } = false;
+
+ System.Threading.Thread pupilConnectThread;
+ #endregion//Pupil variables
+
+ #region Eye Tribe variables
+
+ public EyeTribe eyeTribe = new EyeTribe();
+
+ System.Threading.Thread eyeTribeConnectThread;
+
+ Point? _EyeTribeGazePoint;
+ public bool IsEyeTribeConnected { get; private set; } = false;
+
+ System.Threading.Timer _eyeTribeTimer;
+
+ public int EyeTribeTimerRemainingTime { get; private set; }
+
+ public event EventHandler EyeTribeGazePointReached;
+
+ public class EyeTribeGazePositionEventArgs : EventArgs
+ {
+ public EyeTribeGazePositionEventArgs(double gazeX, double gazeY) => GazePoint = new Point(gazeX, gazeY);
+
+ public Point GazePoint { get; set; }
+ }
+
+ public event EventHandler EyeTribeTimerEvent;
+
+ public class EyeTribeTimerEventArgs : EventArgs
+ {
+ public EyeTribeTimerEventArgs(int time, bool isLastAttempt)
+ {
+ Time = time;
+ IsLastAttempt = isLastAttempt;
+ }
+
+ public int Time { get; set; }
+
+ public bool IsLastAttempt { get; set; }
+ }
+
+ #endregion//Eye Tribe variables
+
+ #region Photo variables
+
+ System.Threading.Timer photoTimer;
+ public int PhotoRemainingTime { get; private set; }
+ public bool HasPhoto { get; private set; } = false;
+
+ public event EventHandler PhotoTimeChangedEvent;
+
+ public class PhotoTimeChangedEventArgs : EventArgs
+ {
+ public PhotoTimeChangedEventArgs(int time, bool isLastRound)
+ {
+ Time = time;
+ IsLastRound = isLastRound;
+ }
+
+ public int Time { get; set; }
+ public bool IsLastRound { get; set; }
+ }
+ #endregion //Photo variables
+
+ #region Logic variables
+
+ FreezeGameSettings GameSettings;
+
+ ListOfRankingRecords RankingRecords;
+
+ RankingRecord _tempRankRecord = new RankingRecord();
+
+ List _distanceHistory = new List();
+
+ int _remainingNumberOfAttempts;
+
+ bool _wasLastAttempt = false;
+
+ public int AttemptNumber { get; set; } = 1;
+
+ double _minAttemptsDistance = Double.MaxValue;
+
+ public int TotalPoints { get; private set; }
+
+ FreezeGamePunctation _punctation = new FreezeGamePunctation();
+
+ int _gameRoundIndex;
+
+ public int NumberOfGameRound { get; private set; } = 1;
+
+ #endregion //Logic variables
+
+ #endregion //Variables
+
+ #region Constructor
+ public FreezeGameModel(WindowViewParameters windowViewParameters, FreezeGameSettings gameSettings, ListOfRankingRecords rankingRecords)
+ {
+ _WindowViewParameters = windowViewParameters;
+ GameSettings = gameSettings;
+ RankingRecords = rankingRecords;
+
+ //logic variables setting up
+ EyeTribeTimerRemainingTime = GameSettings.EyeTribeTime;
+ PhotoRemainingTime = GameSettings.PhotoTime;
+ _remainingNumberOfAttempts = GameSettings.AttemptsAmount;
+
+ //events service setting up
+ eyeTribe.OnData += OnEyeTribeDataReached;
+ pupil.PupilDataReceivedEvent += OnPupilDataReached;
+ }
+ #endregion//Constructors
+
+ #region Methods
+
+ #region Photo methods
+
+ public void TakePhoto()
+ {
+ photoTimer = new System.Threading.Timer(
+ OnTakePhotoTimerEvent,
+ this,
+ 1000,
+ 1000);
+
+ OnPhotoTimeEvent();
+ }
+
+ private void OnTakePhotoTimerEvent(object state)
+ {
+ if (PhotoRemainingTime != 0)
+ {
+ PhotoRemainingTime--;
+ OnPhotoTimeEvent();
+ }
+ else
+ {
+ pupil.Disconnect();
+ HasPhoto = true;
+ IsPupilConnected = false;
+
+ if (GameSettings.DisplayPupilGazePoint)
+ {
+ image.DrawCircleForPupil(_PupilGazePoint, cleanImage: true);
+ OnImageSourceReached(new BitmapSourceEventArgs(image.GetBitmapSourceFromMat()));
+ }
+
+ OnPhotoTimeEvent();
+ PhotoRemainingTime = GameSettings.PhotoTime;
+
+ photoTimer.Change(
+ Timeout.Infinite,
+ Timeout.Infinite); //turn off photoTimer
+ }
+ }
+
+ private void OnPhotoTimeEvent()
+ {
+ PhotoTimeChangedEventArgs args = new PhotoTimeChangedEventArgs(
+ time: PhotoRemainingTime,
+ isLastRound: _gameRoundIndex == 0);
+
+ PhotoTimeChangedEvent?.Invoke(this, args);
+ }
+
+ #endregion//Photo meethods
+
+ #region Image methods
+
+ private void OnImageSourceReached(BitmapSourceEventArgs args)
+ {
+ BitmapSourceReached?.Invoke(this, args);
+ }
+
+ private void DrawImageWithAllAttempts()
+ {
+ _wasLastAttempt = true;
+
+ image.DrawCircleForPupil(point: _PupilGazePoint, cleanImage: true);
+
+ foreach (Point point in _AttemptPoints)
+ {
+ image.DrawCircleForAttemptPoint(point);
+ image.DrawLineBetweenPoints(_PupilGazePoint.point, point);
+ }
+
+ OnImageSourceReached(new BitmapSourceEventArgs(image.GetBitmapSourceFromMat()));
+ }
+
+ #endregion//Image methods
+
+ #region Pupil methods
+ public void ConnectWithPupil()
+ {
+ if (!pupil.isConnected)
+ {
+ HasPhoto = false;
+ pupilConnectThread = new Thread(() => pupil.Connect(GameSettings.PupilAdressString));
+ pupilConnectThread.Start();
+ }
+ }
+ public void DisconnectPupil()
+ {
+ if (pupil.isConnected)
+ {
+ pupil.Disconnect();
+ IsPupilConnected = false;
+ }
+ else
+ pupilConnectThread?.Abort();
+ }
+
+ void OnPupilDataReached(object sender, Pupil.PupilReceivedDataEventArgs pupilArgs)
+ {
+ IsPupilConnected = true;
+
+ if (pupilArgs.RawImageData != null)
+ {
+ GCHandle pinnedarray = GCHandle.Alloc(pupilArgs.RawImageData, GCHandleType.Pinned);
+ IntPtr pointer = pinnedarray.AddrOfPinnedObject();
+
+ image.SetMat(pointer, Convert.ToInt32(pupilArgs.ImageSize.Width), Convert.ToInt32(pupilArgs.ImageSize.Height));
+ pinnedarray.Free();
+ }
+ if (pupilArgs.GazePoints.Count != 0)
+ {
+ _PupilGazePoint = pupilArgs.GazePoints.Max();
+
+ if (GameSettings.DisplayPupilGazePoint)
+ foreach (GazePoint gazePoint in pupilArgs.GazePoints)
+ image.DrawCircleForPupil(gazePoint);
+ }
+ if (GameSettings.DisplayEyeTribeGazePoint && _EyeTribeGazePoint != null)
+ image.DrawCircleForEyeTribe(_EyeTribeGazePoint.GetValueOrDefault());
+
+ if (image.OutMat != null)
+ OnImageSourceReached(new BitmapSourceEventArgs(image.GetBitmapSourceFromMat()));
+ }
+
+ #endregion//Pupil methods
+
+ #region Eye Tribe methods
+ public void ConnectWithEyeTribe()
+ {
+ if (!eyeTribe.isRunning)
+ {
+ eyeTribeConnectThread = new Thread(() => eyeTribe.Connect(GameSettings.EyeTribePort));
+ eyeTribeConnectThread.Start();
+ }
+ }
+
+ public void DisconnectEyeTribe()
+ {
+ if (eyeTribe.isRunning)
+ {
+ eyeTribe.Disconnect();
+ IsEyeTribeConnected = false;
+ }
+ else
+ eyeTribeConnectThread?.Abort();
+ }
+
+ void OnEyeTribeDataReached(object sender, EyeTribe.EyeTribeReceivedDataEventArgs e)
+ {
+ IsEyeTribeConnected = true;
+
+ JObject values = JObject.Parse(e.data.values);
+ JObject gaze = JObject.Parse(values.SelectToken("frame").SelectToken("avg").ToString());
+ double gazeX = (double)gaze.Property("x").Value;
+ double gazeY = (double)gaze.Property("y").Value;
+
+ var eyeTribePoint = new Point(gazeX, gazeY);
+
+ if ((_WindowViewParameters.WindowState == WindowState.Maximized && _WindowViewParameters.WindowMaximizedRect.Contains(eyeTribePoint)) ||
+ (_WindowViewParameters.WindowState == WindowState.Normal && _WindowViewParameters.WindowRect.Contains(eyeTribePoint)))
+ _EyeTribeGazePoint = NormalizePointCoordinatesToImage(
+ point: eyeTribePoint,
+ saveToAttemptPoints: false,
+ relativeToWindow: false);
+ else
+ _EyeTribeGazePoint = null;
+
+ var args = new EyeTribeGazePositionEventArgs(gazeX, gazeY);
+ OnEyeTribeGazePositionReached(args);
+
+ if (HasPhoto && !IsPupilConnected) //during "has photo" time
+ DisplayImageDuringHasPhotoETGazePointReached();
+ else if(!IsPupilConnected)
+ DisplayImageWhenPupilDisconnectETGazePointReached();
+ }
+
+ void DisplayImageDuringHasPhotoETGazePointReached()
+ {
+ if (GameSettings.DisplayPupilGazePoint)
+ image.DrawCircleForPupil(point: _PupilGazePoint, cleanImage: true);
+ else
+ image.CleanImage();
+
+ if (GameSettings.DisplayEyeTribeGazePoint)
+ image.DrawCircleForEyeTribe(_EyeTribeGazePoint.Value);
+
+ DrawAllAttemptPoints();
+
+ if (_wasLastAttempt)
+ {
+ image.DrawCircleForPupil(_PupilGazePoint);
+ DrawLinesBetweenPoints();
+ }
+
+ OnImageSourceReached(new BitmapSourceEventArgs(image.GetBitmapSourceFromMat()));
+ }
+
+ void DisplayImageWhenPupilDisconnectETGazePointReached()
+ {
+ image.CleanImage();
+
+ if (GameSettings.DisplayPupilGazePoint)
+ image.DrawCircleForPupil(_PupilGazePoint, cleanImage: false);
+
+ if (GameSettings.DisplayEyeTribeGazePoint)
+ image.DrawCircleForEyeTribe(_EyeTribeGazePoint.Value, cleanImage: false);
+
+ OnImageSourceReached(new BitmapSourceEventArgs(image.GetBitmapSourceFromMat()));
+ }
+
+ void DrawLinesBetweenPoints()
+ {
+ foreach (Point point in _AttemptPoints)
+ image.DrawLineBetweenPoints(point, _PupilGazePoint.point);
+ }
+
+ void DrawAllAttemptPoints()
+ {
+ foreach (Point point in _AttemptPoints)
+ image.DrawCircleForAttemptPoint(point);
+ }
+
+
+ public void OnEyeTribeGazePositionReached(EyeTribeGazePositionEventArgs args)
+ {
+ EyeTribeGazePointReached?.Invoke(this, args);
+ }
+
+ public void StartEyeTribeTimer()
+ {
+ if (eyeTribe.isRunning)
+ {
+ _eyeTribeTimer = new System.Threading.Timer(
+ callback: OnEyeTribeTimerEvent,
+ state: this,
+ dueTime: 1000,
+ period: 1000);
+
+ OnEyeTribeTimerEvent();
+ }
+ }
+
+ private void OnEyeTribeTimerEvent(object state)
+ {
+ if (EyeTribeTimerRemainingTime != 0)
+ {
+ EyeTribeTimerRemainingTime--;
+ OnEyeTribeTimerEvent();
+ }
+ else
+ {
+ OnEyeTribeTimerEvent();
+ EyeTribeTimerRemainingTime = GameSettings.EyeTribeTime;
+ _eyeTribeTimer.Change(Timeout.Infinite, Timeout.Infinite);
+ }
+ }
+
+ private void OnEyeTribeTimerEvent()
+ {
+ EyeTribeTimerEventArgs args = new EyeTribeTimerEventArgs(
+ time: EyeTribeTimerRemainingTime,
+ isLastAttempt: _remainingNumberOfAttempts == 0);
+
+ EyeTribeTimerEvent?.Invoke(this, args);
+ }
+
+ #endregion//Eye Tribe methods
+
+ #region Logic methods
+
+ public void StartRound()
+ {
+ _gameRoundIndex--;
+ TakePhoto();
+
+ if (_gameRoundIndex == -1) //first round
+ {
+ _gameRoundIndex = GameSettings.RoundsAmount - 1;
+ NumberOfGameRound = 1;
+ TotalPoints = 0;
+
+ _tempRankRecord.AttemptsAmountInRound = GameSettings.AttemptsAmount;
+ _tempRankRecord.RoundsAmount = GameSettings.RoundsAmount;
+ }
+ else
+ ActualiseRoundNumber();
+
+ _wasLastAttempt = false;
+ _AttemptPoints.Clear();
+ }
+
+ //When points variable is null, it isn't last attempt
+ public bool MouseAttemptStarted(Point mousePosition, out double? distance, out int? points)
+ {
+ distance = CountPointsDifferenceMouse(mousePosition);
+ _remainingNumberOfAttempts--;
+
+ _distanceHistory.Add(distance.Value);
+
+ var normalizedMousePointCoordinates = NormalizePointCoordinatesToImage(
+ mousePosition,
+ false);
+
+ image.DrawCircleForAttemptPoint(normalizedMousePointCoordinates);
+ OnImageSourceReached(new BitmapSourceEventArgs(image.GetBitmapSourceFromMat()));
+
+ return RealiseAttemptLogic(ref distance, out points);
+ }
+
+ public bool EyeTribeAttemptStarted(out double? distance, out int? points)
+ {
+ var eyeTribePoint = _EyeTribeGazePoint != null ? _EyeTribeGazePoint.Value : new Point(0, 0);
+
+ distance = CountPointsDifferenceEyeTribe(eyeTribePoint);
+ _remainingNumberOfAttempts--;
+
+ _distanceHistory.Add(distance.Value);
+
+ _AttemptPoints.Add(eyeTribePoint);
+
+ return RealiseAttemptLogic(ref distance, out points);
+ }
+
+ private double CountPointsDifferenceMouse(Point point, bool coordinatesRelativeToWindow = true)
+ {
+ var normalizedMousePositionOnImage = NormalizePointCoordinatesToImage(
+ point: point,
+ saveToAttemptPoints: true,
+ relativeToWindow: coordinatesRelativeToWindow);
+
+ return Point.Subtract(_PupilGazePoint.point, normalizedMousePositionOnImage).Length;
+ }
+
+ private double CountPointsDifferenceEyeTribe(Point point)
+ {
+ return Point.Subtract(_PupilGazePoint.point, point).Length;
+ }
+
+ private Point NormalizePointCoordinatesToImage(Point point, bool saveToAttemptPoints, bool relativeToWindow = true)
+ {
+ Rect rect;
+ if (_WindowViewParameters.WindowState == WindowState.Maximized)
+ rect = _WindowViewParameters.WindowMaximizedRect;
+ else
+ rect = _WindowViewParameters.WindowRect;
+
+ if (!relativeToWindow)
+ point.Offset(-rect.X, -rect.Y);
+
+ var normalizedPoint = new Point(
+ point.X / (rect.Width * 0.9),
+ point.Y / (rect.Height * 0.9));
+
+ if (saveToAttemptPoints)
+ _AttemptPoints.Add(normalizedPoint);
+
+ return normalizedPoint;
+ }
+
+ private void CountPointsAfterAttempts()
+ {
+ for (int i = _punctation.PunctationList.Count; i > 0; i--)
+ {
+ if (_minAttemptsDistance <= _punctation.PunctationList[i - 1])
+ {
+ TotalPoints += i;
+ return;
+ }
+ }
+ }
+
+ private bool RealiseAttemptLogic(ref double? distance, out int? points)
+ {
+ if (distance != null && distance.Value < _minAttemptsDistance)
+ _minAttemptsDistance = distance.Value;
+
+ if (_remainingNumberOfAttempts == 0) //last attempt
+ {
+ DrawImageWithAllAttempts();
+ distance = _minAttemptsDistance;
+ _remainingNumberOfAttempts = GameSettings.AttemptsAmount;
+ CountPointsAfterAttempts();
+ points = TotalPoints;
+ ResetMinAttemptDistance();
+ AttemptNumber = 1;
+
+ if (_gameRoundIndex == 0)
+ ActualiseRanking(points);
+
+ if (!IsEyeTribeConnected)
+ _AttemptPoints.Clear();
+
+ return true;
+ }
+ else
+ {
+ ActualiseAttemptNumber();
+ points = null;
+ return false;
+ }
+ }
+
+ void ActualiseRanking(int? points)
+ {
+ _tempRankRecord.Name = GameSettings.NameToRanking;
+ _tempRankRecord.Date = DateTime.Now;
+ _tempRankRecord.PointsGenerally = ((11.0m - Convert.ToDecimal(_tempRankRecord.AttemptsAmountInRound)) * Convert.ToDecimal(points.Value)) / (Convert.ToDecimal(_tempRankRecord.RoundsAmount * 100.0m));
+ _tempRankRecord.PointsInGame = points.Value;
+ _tempRankRecord.AverageDistance = Math.Round(_distanceHistory.Sum() / (_tempRankRecord.AttemptsAmountInRound * _tempRankRecord.RoundsAmount), 4);
+ RankingRecords.list.Add(_tempRankRecord);
+ _tempRankRecord = new RankingRecord();
+
+ RankingRecords.NewElement();
+ }
+
+ private void ResetMinAttemptDistance()
+ {
+ if (_WindowViewParameters.WindowState == WindowState.Maximized)
+ _minAttemptsDistance = Point.Subtract(_WindowViewParameters.WindowMaximizedRect.TopLeft, _WindowViewParameters.WindowMaximizedRect.BottomRight).Length;
+ else
+ _minAttemptsDistance = Point.Subtract(_WindowViewParameters.WindowRect.TopLeft, _WindowViewParameters.WindowRect.BottomRight).Length;
+ }
+
+ private void ActualiseAttemptNumber() => AttemptNumber = GameSettings.AttemptsAmount - _remainingNumberOfAttempts;
+
+ private void ActualiseRoundNumber() => NumberOfGameRound = GameSettings.RoundsAmount - _gameRoundIndex;
+
+ #endregion//logic methods
+
+ #endregion//Methods
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/FreezeGamePunctation.cs b/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/FreezeGamePunctation.cs
new file mode 100644
index 0000000..d98c9cd
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/FreezeGamePunctation.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+
+namespace GuessWhatLookingAt
+{
+ public class FreezeGamePunctation
+ {
+ public List PunctationList = new List();
+ private int maxPoints = 10;
+
+ public FreezeGamePunctation()
+ {
+ for(int i = maxPoints; i > 0; i--)
+ {
+ PunctationList.Add(i * 0.05);
+ }
+ }
+
+ public FreezeGamePunctation(List punctation) => PunctationList = punctation;
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/FreezeGameSettings.cs b/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/FreezeGameSettings.cs
new file mode 100644
index 0000000..20bf923
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/FreezeGameSettings.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GuessWhatLookingAt
+{
+ public class FreezeGameSettings
+ {
+ public string NameToRanking { get; set; } = "";
+
+ public string PupilAdressString { get; set; } = "";
+
+ public int EyeTribePort { get; set; } = 0;
+
+ public int AttemptsAmount { get; set; } = 0;
+
+ public int RoundsAmount { get; set; } = 0;
+
+ public int PhotoTime { get; set; } = 0;
+
+ public int EyeTribeTime { get; set; } = 0;
+
+ public bool DisplayPupilGazePoint { get; set; } = false;
+
+ public bool DisplayEyeTribeGazePoint { get; set; } = false;
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/RankingRecord.cs b/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/RankingRecord.cs
new file mode 100644
index 0000000..7202a59
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/GameModel/RankingRecord.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GuessWhatLookingAt
+{
+ public class ListOfRankingRecords
+ {
+ public List list { get; set; }
+
+ public ListOfRankingRecords() => list = new List();
+
+ public void NewElement()
+ {
+ var args = new RankingRecordSavedEventArgs();
+ OnRankingRecordSaved?.Invoke(this, args);
+ }
+
+ public event EventHandler OnRankingRecordSaved;
+
+ public class RankingRecordSavedEventArgs : EventArgs
+ {
+
+ }
+ }
+
+ public class RankingRecord
+ {
+ public string Name { get; set; }
+
+ public DateTime Date { get; set; }
+
+ public decimal PointsGenerally { get; set; }
+
+ public int PointsInGame { get; set; }
+
+ public int AttemptsAmountInRound { get; set; }
+
+ public int RoundsAmount { get; set; }
+
+ public double AverageDistance { get; set; }
+
+
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/GuessWhatLookingAt.csproj b/GuessWhatLookingAt/GuessWhatLookingAt/GuessWhatLookingAt.csproj
new file mode 100644
index 0000000..072f5af
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/GuessWhatLookingAt.csproj
@@ -0,0 +1,264 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {E30F7550-189A-4B99-B6B4-B2801B6F9AE7}
+ WinExe
+ GuessWhatLookingAt
+ GuessWhatLookingAt
+ v4.8
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+ true
+ true
+
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ 7.3
+ prompt
+ true
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ 7.3
+ prompt
+ true
+
+
+
+ ..\packages\AsyncIO.0.1.69\lib\net40\AsyncIO.dll
+
+
+ ..\packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll
+
+
+ ..\packages\Emgu.CV.4.4.0.4061\lib\netstandard2.0\Emgu.CV.Platform.NetStandard.dll
+
+
+ packages\MaterialDesignColors.1.2.7\lib\net45\MaterialDesignColors.dll
+
+
+ packages\MaterialDesignThemes.3.2.0\lib\net45\MaterialDesignThemes.Wpf.dll
+
+
+ ..\packages\NaCl.Net.0.1.13\lib\net472\NaCl.dll
+
+
+ ..\packages\NetMQ.4.0.1.6\lib\net47\NetMQ.dll
+
+
+ packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
+
+
+ ..\packages\SimpleMsgPack.1.0.0.0\lib\net40\SimpleMsgPack.dll
+
+
+
+ ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+
+
+
+
+ ..\packages\System.Drawing.Primitives.4.3.0\lib\net45\System.Drawing.Primitives.dll
+ True
+ True
+
+
+ ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+
+
+ ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ ..\packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll
+ True
+ True
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
+ True
+ True
+
+
+
+ ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
+
+
+ ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
+
+
+
+
+
+
+
+
+ 4.0
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Settings.settings
+ Always
+
+
+
+
+
+ RankingUserControl.xaml
+
+
+
+
+ FreezeGameUserControl.xaml
+
+
+
+ SettingsUserControl.xaml
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+ App.xaml
+ Code
+
+
+ MainWindow.xaml
+ Code
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+
+ Code
+
+
+ True
+ True
+ Resources.resx
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+ PublicSettingsSingleFileGenerator
+ Settings.Designer.cs
+ Always
+
+
+
+
+
+
+
+ False
+ Microsoft .NET Framework 4.8 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/GuessWhatLookingAt.sln b/GuessWhatLookingAt/GuessWhatLookingAt/GuessWhatLookingAt.sln
new file mode 100644
index 0000000..e465c20
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/GuessWhatLookingAt.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30804.86
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GuessWhatLookingAt", "GuessWhatLookingAt.csproj", "{E30F7550-189A-4B99-B6B4-B2801B6F9AE7}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E30F7550-189A-4B99-B6B4-B2801B6F9AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E30F7550-189A-4B99-B6B4-B2801B6F9AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E30F7550-189A-4B99-B6B4-B2801B6F9AE7}.Debug|x64.ActiveCfg = Debug|x64
+ {E30F7550-189A-4B99-B6B4-B2801B6F9AE7}.Debug|x64.Build.0 = Debug|x64
+ {E30F7550-189A-4B99-B6B4-B2801B6F9AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E30F7550-189A-4B99-B6B4-B2801B6F9AE7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E30F7550-189A-4B99-B6B4-B2801B6F9AE7}.Release|x64.ActiveCfg = Release|x64
+ {E30F7550-189A-4B99-B6B4-B2801B6F9AE7}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B1027487-C295-4010-8666-A6762E6B4362}
+ EndGlobalSection
+EndGlobal
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/EventArgs.cs b/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/EventArgs.cs
new file mode 100644
index 0000000..b190646
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/EventArgs.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GuessWhatLookingAt
+{
+ public class EventArgs : EventArgs
+ {
+ public EventArgs(T value)
+ {
+ Value = value;
+ }
+
+ public T Value { get; private set; }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/EventRaiser.cs b/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/EventRaiser.cs
new file mode 100644
index 0000000..02dab4b
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/EventRaiser.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GuessWhatLookingAt
+{
+ public static class EventRaiser
+ {
+ public static void Raise(this EventHandler handler, object sender)
+ {
+ handler?.Invoke(sender, EventArgs.Empty);
+ }
+
+ public static void Raise(this EventHandler> handler, object sender, T value)
+ {
+ handler?.Invoke(sender, new EventArgs(value));
+ }
+
+ public static void Raise(this EventHandler handler, object sender, T value) where T : EventArgs
+ {
+ handler?.Invoke(sender, value);
+ }
+
+ public static void Raise(this EventHandler> handler, object sender, EventArgs value)
+ {
+ handler?.Invoke(sender, value);
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/Mediator.cs b/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/Mediator.cs
new file mode 100644
index 0000000..b9a3057
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/Mediator.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+
+namespace GuessWhatLookingAt
+{
+ public static class Mediator
+ {
+ private static IDictionary>> pl_dict =
+ new Dictionary>>();
+
+ public static void Subscribe(string token, Action callback)
+ {
+ if (!pl_dict.ContainsKey(token))
+ {
+ var list = new List>();
+ list.Add(callback);
+ pl_dict.Add(token, list);
+ }
+ else
+ {
+ bool found = false;
+ foreach (var item in pl_dict[token])
+ if (item.Method.ToString() == callback.Method.ToString())
+ found = true;
+ if (!found)
+ pl_dict[token].Add(callback);
+ }
+ }
+
+ public static void Unsubscribe(string token, Action callback)
+ {
+ if (pl_dict.ContainsKey(token))
+ pl_dict[token].Remove(callback);
+ }
+
+ public static void Notify(string token, object args = null)
+ {
+ if (pl_dict.ContainsKey(token))
+ foreach (var callback in pl_dict[token])
+ callback(args);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/RelayCommand.cs b/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/RelayCommand.cs
new file mode 100644
index 0000000..38dec2c
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/NavigateBetweenViews/RelayCommand.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace GuessWhatLookingAt
+{
+ public class RelayCommand : ICommand
+ {
+ private readonly Predicate _canExecute;
+ private readonly Action _execute;
+
+ public RelayCommand(Action execute)
+ : this(execute, null)
+ {
+ _execute = execute;
+ }
+
+ public RelayCommand(Action execute, Predicate canExecute)
+ {
+ if (execute == null)
+ {
+ throw new ArgumentNullException("execute");
+ }
+ _execute = execute;
+ _canExecute = canExecute;
+ }
+
+ public bool CanExecute(object parameter)
+ {
+ return _canExecute == null || _canExecute((T)parameter);
+ }
+
+ public void Execute(object parameter)
+ {
+ _execute((T)parameter);
+ }
+
+ public event EventHandler CanExecuteChanged
+ {
+ add { CommandManager.RequerySuggested += value; }
+ remove { CommandManager.RequerySuggested -= value; }
+ }
+ }
+
+ public class RelayCommand : ICommand
+ {
+ private readonly Predicate _canExecute;
+ private readonly Action _execute;
+
+ public RelayCommand(Action execute)
+ : this(execute, null)
+ {
+ _execute = execute;
+ }
+
+ public RelayCommand(Action execute, Predicate canExecute)
+ {
+ if (execute == null)
+ {
+ throw new ArgumentNullException("execute");
+ }
+ _execute = execute;
+ _canExecute = canExecute;
+ }
+
+ public bool CanExecute(object parameter)
+ {
+ return _canExecute == null || _canExecute(parameter);
+ }
+
+ public void Execute(object parameter)
+ {
+ _execute(parameter);
+ }
+
+ // Ensures WPF commanding infrastructure asks all RelayCommand objects whether their
+ // associated views should be enabled whenever a command is invoked
+ public event EventHandler CanExecuteChanged
+ {
+ add
+ {
+ CommandManager.RequerySuggested += value;
+ CanExecuteChangedInternal += value;
+ }
+ remove
+ {
+ CommandManager.RequerySuggested -= value;
+ CanExecuteChangedInternal -= value;
+ }
+ }
+
+ private event EventHandler CanExecuteChangedInternal;
+
+ public void RaiseCanExecuteChanged()
+ {
+ CanExecuteChangedInternal.Raise(this);
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Properties/AssemblyInfo.cs b/GuessWhatLookingAt/GuessWhatLookingAt/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d7e3dcc
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("GuessWhatLookingAt")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("GuessWhatLookingAt")]
+[assembly: AssemblyCopyright("Copyright © 2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+//In order to begin building localizable applications, set
+//CultureYouAreCodingWith in your .csproj file
+//inside a . For example, if you are using US english
+//in your source files, set the to en-US. Then uncomment
+//the NeutralResourceLanguage attribute below. Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
+
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Resources.Designer.cs b/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..1002065
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace GuessWhatLookingAt.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GuessWhatLookingAt.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Resources.resx b/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Resources.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Resources.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Settings.Designer.cs b/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..a80e959
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Settings.Designer.cs
@@ -0,0 +1,134 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace GuessWhatLookingAt.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
+ public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("tcp://127.0.0.1:50020")]
+ public string PupilAdressString {
+ get {
+ return ((string)(this["PupilAdressString"]));
+ }
+ set {
+ this["PupilAdressString"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("6555")]
+ public int EyeTribePort {
+ get {
+ return ((int)(this["EyeTribePort"]));
+ }
+ set {
+ this["EyeTribePort"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("2")]
+ public int AttemptsAmount {
+ get {
+ return ((int)(this["AttemptsAmount"]));
+ }
+ set {
+ this["AttemptsAmount"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("2")]
+ public int RoundsAmount {
+ get {
+ return ((int)(this["RoundsAmount"]));
+ }
+ set {
+ this["RoundsAmount"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("3")]
+ public int PhotoTime {
+ get {
+ return ((int)(this["PhotoTime"]));
+ }
+ set {
+ this["PhotoTime"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("4")]
+ public int EyeTribeTime {
+ get {
+ return ((int)(this["EyeTribeTime"]));
+ }
+ set {
+ this["EyeTribeTime"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ public bool DisplayPupilGazePoint {
+ get {
+ return ((bool)(this["DisplayPupilGazePoint"]));
+ }
+ set {
+ this["DisplayPupilGazePoint"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("True")]
+ public bool DisplayEyeTribeGazePoint {
+ get {
+ return ((bool)(this["DisplayEyeTribeGazePoint"]));
+ }
+ set {
+ this["DisplayEyeTribeGazePoint"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("Player")]
+ public string NameToRanking {
+ get {
+ return ((string)(this["NameToRanking"]));
+ }
+ set {
+ this["NameToRanking"] = value;
+ }
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Settings.settings b/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Settings.settings
new file mode 100644
index 0000000..39ef77d
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Properties/Settings.settings
@@ -0,0 +1,33 @@
+
+
+
+
+
+ tcp://127.0.0.1:50020
+
+
+ 6555
+
+
+ 2
+
+
+ 2
+
+
+ 3
+
+
+ 4
+
+
+ False
+
+
+ True
+
+
+ Player
+
+
+
\ No newline at end of file
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Settings.cs b/GuessWhatLookingAt/GuessWhatLookingAt/Settings.cs
new file mode 100644
index 0000000..60b312b
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Settings.cs
@@ -0,0 +1,28 @@
+namespace MvvmNavigation.Properties {
+
+
+ // This class allows you to handle specific events on the settings class:
+ // The SettingChanging event is raised before a setting's value is changed.
+ // The PropertyChanged event is raised after a setting's value is changed.
+ // The SettingsLoaded event is raised after the setting values are loaded.
+ // The SettingsSaving event is raised before the setting values are saved.
+ public sealed partial class Settings {
+
+ public Settings() {
+ // // To add event handlers for saving and changing settings, uncomment the lines below:
+ //
+ // this.SettingChanging += this.SettingChangingEventHandler;
+ //
+ // this.SettingsSaving += this.SettingsSavingEventHandler;
+ //
+ }
+
+ private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
+ // Add code to handle the SettingChangingEvent event here.
+ }
+
+ private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
+ // Add code to handle the SettingsSaving event here.
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/BaseViewModel.cs b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/BaseViewModel.cs
new file mode 100644
index 0000000..d556f36
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/BaseViewModel.cs
@@ -0,0 +1,24 @@
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+
+namespace GuessWhatLookingAt
+{
+ public abstract class BaseViewModel : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ protected void OnPropertyChanged(string propertyName)
+ {
+ VerifyPropertyName(propertyName);
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+ [Conditional("DEBUG")]
+ private void VerifyPropertyName(string propertyName)
+ {
+ if (TypeDescriptor.GetProperties(this)[propertyName] == null)
+ throw new ArgumentNullException(GetType().Name + " does not contain property: " + propertyName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/FreezeGameViewModel.cs b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/FreezeGameViewModel.cs
new file mode 100644
index 0000000..1202ba6
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/FreezeGameViewModel.cs
@@ -0,0 +1,531 @@
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Xml.Serialization;
+
+namespace GuessWhatLookingAt
+{
+ public class FreezeGameViewModel : BaseViewModel, IPageViewModel, INotifyPropertyChanged
+ {
+ FreezeGameModel model;
+
+ #region XAML Properties
+ public ImageSource imageFromPupil { get; set; }
+
+ private string connectPupilButtonContentString = "Connect with Pupil";
+ public string ConnectPupilButtonContentString
+ {
+ get => connectPupilButtonContentString;
+ set
+ {
+ connectPupilButtonContentString = value;
+ OnPropertyChanged("ConnectPupilButtonContentString");
+ }
+ }
+
+ private string connectEyeTribeButtonContentString = "Connect with Eye Tribe";
+ public string ConnectEyeTribeButtonContentString
+ {
+ get => connectEyeTribeButtonContentString;
+ set
+ {
+ connectEyeTribeButtonContentString = value;
+ OnPropertyChanged("ConnectEyeTribeButtonContentString");
+ }
+ }
+
+ private string mouseDistanceToPupilGazePoint = "";
+ public string MouseDistanceToPupilGazePoint
+ {
+ get => mouseDistanceToPupilGazePoint;
+ set
+ {
+ mouseDistanceToPupilGazePoint = value;
+ OnPropertyChanged("MouseDistanceToPupilGazePoint");
+ }
+ }
+
+ private string gameInfoLabelContentString = "";
+ public string GameInfoLabelContentString
+ {
+ get => gameInfoLabelContentString;
+ set
+ {
+ gameInfoLabelContentString = value;
+ OnPropertyChanged("GameInfoLabelContentString");
+ }
+ }
+
+ private string eyeTribeCoordinatesString = "X: Y: ";
+ public string EyeTribeCoordinatesString
+ {
+ get => eyeTribeCoordinatesString;
+ set
+ {
+ eyeTribeCoordinatesString = value;
+ OnPropertyChanged("EyeTribeCoordinatesString");
+ }
+ }
+
+ private string startRoundButtonContentString = "Start game";
+ public string StartRoundButtonContentString
+ {
+ get => startRoundButtonContentString;
+ set
+ {
+ startRoundButtonContentString = value;
+ OnPropertyChanged("StartRoundButtonContentString");
+ }
+ }
+
+
+ private string roundValueLabelContentString = "";
+ public string RoundValueLabelContentString
+ {
+ get => roundValueLabelContentString;
+ set
+ {
+ roundValueLabelContentString = value;
+ OnPropertyChanged("RoundValueLabelContentString");
+ }
+ }
+
+ private string attemptValueLabelContentString = "";
+ public string AttemptValueLabelContentString
+ {
+ get => attemptValueLabelContentString;
+ set
+ {
+ attemptValueLabelContentString = value;
+ OnPropertyChanged("AttemptValueLabelContentString");
+ }
+ }
+
+ private string pointsValueLabelContentString = "";
+ public string PointsValueLabelContentString
+ {
+ get => pointsValueLabelContentString;
+ set
+ {
+ pointsValueLabelContentString = value;
+ OnPropertyChanged("PointsValueLabelContentString");
+ }
+ }
+
+ public static WindowViewParameters _WindowViewParameters { get; set; }
+ #endregion
+
+ MainWindow MainWindow { get; set; }
+ FreezeGameSettings GameSettings;
+ ListOfRankingRecords RankingRecords;
+
+ int _lastMouseClickTimestamp = 0;
+ bool _lockMouseLeftButton = false;
+ bool _lockEyeTribeTimer = false;
+ bool _isLastAttempt = false;
+ bool _isLastRound = false;
+ int _lastPointsAmount = 0;
+
+ #region Constructor
+ public FreezeGameViewModel(MainWindow mainWindow, FreezeGameSettings gameSettings, ListOfRankingRecords rankingRecords)
+ {
+ MainWindow = mainWindow;
+ mainWindow.WindowViewParametersChangedEvent += OnWindowViewParametersChanged;
+ mainWindow.GameClosedEvent += OnGameClosed;
+
+ _WindowViewParameters = new WindowViewParameters();
+ GameSettings = gameSettings;
+ RankingRecords = rankingRecords;
+ model = new FreezeGameModel(_WindowViewParameters, GameSettings, rankingRecords);
+
+ model.BitmapSourceReached += OnBitmapSourceReached;
+ model.EyeTribeGazePointReached += OnEyeTribeGazePointReached;
+ model.PhotoTimeChangedEvent += OnPhotoTimeChanged;
+ }
+ #endregion
+
+ #region Commands
+
+ #region Go to settings
+ private ICommand _goToSettings;
+
+ public ICommand GoToSettings
+ {
+ get
+ {
+ return _goToSettings ?? (_goToSettings = new RelayCommand(x =>
+ {
+ Mediator.Notify("GoToSettings", "");
+ }));
+ }
+ }
+ #endregion
+
+ #region Go to ranking
+ private ICommand _goToRanking;
+
+ public ICommand GoToRanking
+ {
+ get
+ {
+ return _goToRanking ?? (_goToRanking = new RelayCommand(x =>
+ {
+ Mediator.Notify("GoToRanking", "");
+ }));
+ }
+ }
+ #endregion
+
+ #region Connect with Pupil
+ private ICommand _ConnectDisconnectWithPupil;
+ public ICommand ConnectDisconnectWithPupil
+ {
+ get
+ {
+ return _ConnectDisconnectWithPupil ?? (_ConnectDisconnectWithPupil = new RelayCommand(
+ x =>
+ {
+ if (!model.IsPupilConnected)
+ ConnectWithPupil();
+ else
+ DisconnectPupil();
+ }));
+ }
+ }
+
+ void ConnectWithPupil()
+ {
+ model.ConnectWithPupil();
+ ConnectPupilButtonContentString = "Disconnect Pupil";
+ MouseDistanceToPupilGazePoint = "";
+ }
+
+ void DisconnectPupil()
+ {
+ model.DisconnectPupil();
+ ConnectPupilButtonContentString = "Connect with Pupil";
+ }
+ #endregion
+
+ #region Connect with Eye Tribe
+ private ICommand _ConnectDisconnectWithEyeTribe;
+ public ICommand ConnectDisconnectWithEyeTribe
+ {
+ get
+ {
+ return _ConnectDisconnectWithEyeTribe ?? (_ConnectDisconnectWithEyeTribe = new RelayCommand(
+ x =>
+ {
+ if (!model.IsEyeTribeConnected)
+ ConnectWithEyeTribe();
+ else
+ DisconnectEyeTribe();
+ }));
+ }
+ }
+
+ void ConnectWithEyeTribe()
+ {
+ model.ConnectWithEyeTribe();
+ ConnectEyeTribeButtonContentString = "Disconnect Eye Tribe";
+ }
+
+ void DisconnectEyeTribe()
+ {
+ model.DisconnectEyeTribe();
+ ConnectEyeTribeButtonContentString = "Connect with Eye Tribe";
+ EyeTribeCoordinatesString = "X: Y: "; ;
+ }
+ #endregion
+
+ #region Start round
+ private ICommand _StartRound;
+
+ public ICommand StartRound
+ {
+ get
+ {
+ return _StartRound ?? (_StartRound = new RelayCommand(
+ x =>
+ {
+ if (!model.HasPhoto) //new game
+ ClickedNewGameButton();
+ else if (model.HasPhoto && !_isLastAttempt)
+ ClickedNextAttemptButton();
+ else if (model.HasPhoto && _isLastAttempt) //after last attempt
+ ClickedNextRoundButton();
+ }));
+ }
+ }
+
+ void ClickedNewGameButton()
+ {
+ model.ConnectWithPupil();
+ model.StartRound();
+ RoundValueLabelContentString = model.NumberOfGameRound.ToString();
+ AttemptValueLabelContentString = model.AttemptNumber.ToString();
+ }
+
+ void ClickedNextAttemptButton()
+ {
+ model.EyeTribeTimerEvent += OnEyeTribeTimerChanged;
+ model.StartEyeTribeTimer();
+ AttemptValueLabelContentString = (model.AttemptNumber + 1).ToString();
+ _lockEyeTribeTimer = false;
+ }
+
+ void ClickedNextRoundButton()
+ {
+ if (!model.IsPupilConnected)
+ model.ConnectWithPupil();
+
+ model.StartRound();
+ RoundValueLabelContentString = model.NumberOfGameRound.ToString();
+ AttemptValueLabelContentString = model.AttemptNumber.ToString();
+ }
+ #endregion//Start round
+
+ #region Display Pupil gaze points
+
+ private ICommand _DisplayPupilGazePoint;
+ public ICommand DisplayPupilGazePoint
+ {
+ get
+ {
+ return _DisplayPupilGazePoint ?? (_DisplayPupilGazePoint = new RelayCommand(
+ x =>
+ {
+ GameSettings.DisplayPupilGazePoint = !GameSettings.DisplayPupilGazePoint;
+ }));
+ }
+ }
+
+ #endregion
+
+ #region Display Eye Tribe gaze points
+
+ private ICommand _DisplayEyeTribeGazePoint;
+
+ public ICommand DisplayEyeTribeGazePoint
+ {
+ get
+ {
+ return _DisplayEyeTribeGazePoint ?? (_DisplayEyeTribeGazePoint = new RelayCommand(
+ x =>
+ {
+ GameSettings.DisplayEyeTribeGazePoint = !GameSettings.DisplayEyeTribeGazePoint;
+ }));
+ }
+ }
+
+ #endregion
+
+ #endregion
+
+ #region Events services
+
+ void OnWindowViewParametersChanged(object sender, MainWindow.WindowViewParametersEventArgs args)
+ {
+ _WindowViewParameters.WindowState = args.WndState;
+
+ if (args.WasLoaded && args.WndState == WindowState.Maximized)
+ _WindowViewParameters.WindowMaximizedRect = args.WindowRect;
+ else
+ _WindowViewParameters.WindowRect = args.WindowRect;
+ }
+
+ void OnBitmapSourceReached(object sender, FreezeGameModel.BitmapSourceEventArgs args) => LoadImageFromPupil(args.Image);
+
+ Point GetAbsoluteMousePos() => MainWindow.PointToScreen(Mouse.GetPosition(MainWindow));
+
+ private void OnLeftMouseButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ if (model.HasPhoto && e.LeftButton == MouseButtonState.Pressed &&
+ !_lockMouseLeftButton && _lastMouseClickTimestamp != e.Timestamp)
+ {
+ Point relativeMousePosition = Mouse.GetPosition(MainWindow);
+ Point absoluteMousePosition = GetAbsoluteMousePos();
+
+ //when mouse position is located on game window
+ if ((_WindowViewParameters.WindowState == WindowState.Maximized && _WindowViewParameters.WindowMaximizedRect.Contains(relativeMousePosition)) ||
+ (_WindowViewParameters.WindowState == WindowState.Normal && _WindowViewParameters.WindowRect.Contains(absoluteMousePosition)))
+ {
+ double? distance;
+ int? points;
+ model.MouseAttemptStarted(relativeMousePosition, out distance, out points);
+
+ _isLastAttempt = points != null;
+
+ if (_isLastAttempt)
+ {
+ App.Current.Dispatcher.Invoke(delegate
+ {
+ App.Current.MainWindow.MouseDown -= OnLeftMouseButtonDown;
+ });
+
+ _lockMouseLeftButton = true;
+ }
+ else
+ AttemptValueLabelContentString = (model.AttemptNumber + 1).ToString();
+
+ //Actualise mouse click timstamp
+ _lastMouseClickTimestamp = e.Timestamp;
+ MouseDistanceToPupilGazePoint = Math.Round(distance.Value, 4).ToString();
+
+ if (_isLastRound && _isLastAttempt)
+ DisplayAfterLastAttemptInRound();
+ else if (points != null)
+ DisplayAfterLastAttempt(points);
+ }
+ }
+ }
+
+ private void OnPhotoTimeChanged(object sender, FreezeGameModel.PhotoTimeChangedEventArgs args)
+ {
+ if (args.Time != 0)
+ {
+ if (args.Time != 1)
+ GameInfoLabelContentString = "Take photo in " + args.Time + " seconds";
+ else
+ GameInfoLabelContentString = "Take photo in 1 second";
+ }
+ else //Time == 0
+ {
+ if (!_isLastRound)
+ StartRoundButtonContentString = "Start next round";
+
+ GameInfoLabelContentString = "";
+ ConnectPupilButtonContentString = "Connect with Pupil";
+
+ if (!model.IsEyeTribeConnected)
+ {
+ App.Current.Dispatcher.Invoke(delegate //Guessing gaze position player with mouse using
+ {
+ App.Current.MainWindow.MouseDown += OnLeftMouseButtonDown;
+ });
+ _lockMouseLeftButton = false;
+ }
+ else // Eye Tribe is connected
+ {
+ model.EyeTribeTimerEvent += OnEyeTribeTimerChanged;
+ model.StartEyeTribeTimer();
+ _lockEyeTribeTimer = false;
+ }
+
+ _isLastRound = args.IsLastRound;
+ }
+ }
+
+ private void OnEyeTribeGazePointReached(object sender, FreezeGameModel.EyeTribeGazePositionEventArgs args)
+ {
+ EyeTribeCoordinatesString = "X: " + Math.Round(args.GazePoint.X, 0).ToString() + " Y: " + Math.Round(args.GazePoint.Y, 0).ToString();
+ }
+
+ private void OnEyeTribeTimerChanged(object sender, FreezeGameModel.EyeTribeTimerEventArgs args)
+ {
+ if (!_lockEyeTribeTimer)
+ {
+ if (args.Time != 0)
+ {
+ if (args.Time != 1)
+ GameInfoLabelContentString = "Save Eye Tribe gaze point to indicate second player gaze point in " + args.Time + " seconds";
+ else
+ GameInfoLabelContentString = "Save Eye Tribe gaze point to indicate second player gaze point in 1 second";
+ }
+ else //Time == 0
+ {
+ GameInfoLabelContentString = "";
+
+ double? distance;
+ int? points;
+ model.EyeTribeAttemptStarted(out distance, out points);
+
+ _isLastAttempt = points != null;
+
+ model.EyeTribeTimerEvent -= OnEyeTribeTimerChanged;
+ _lockEyeTribeTimer = true;
+
+ MouseDistanceToPupilGazePoint = Math.Round(distance.Value, 4).ToString();
+
+ if (_isLastRound && _isLastAttempt)
+ DisplayAfterLastAttemptInRound();
+ else if (!_isLastAttempt)
+ StartRoundButtonContentString = "Start next attempt";
+ else
+ {
+ StartRoundButtonContentString = "Start next round";
+ if (points != null)
+ DisplayAfterLastAttempt(points);
+ }
+ }
+ }
+ }
+
+ void DisplayAfterLastAttemptInRound()
+ {
+ GameInfoLabelContentString = String.Concat("Your score for this game is ",
+ model.TotalPoints.ToString(),
+ "/",
+ (model.NumberOfGameRound * 10).ToString());
+ PointsValueLabelContentString = "";
+ RoundValueLabelContentString = "";
+ AttemptValueLabelContentString = "";
+ StartRoundButtonContentString = "Start game";
+ _lastPointsAmount = 0;
+ }
+
+ void DisplayAfterLastAttempt(int? points)
+ {
+ PointsValueLabelContentString = String.Concat(
+ points.Value.ToString(),
+ "/",
+ (model.NumberOfGameRound * 10).ToString(),
+ " (+",
+ (points.Value - _lastPointsAmount).ToString(), ")");
+ _lastPointsAmount = points.Value;
+ }
+
+ private void OnGameClosed(object sender, MainWindow.GameClosedEventArgs args)
+ {
+ try
+ {
+ Properties.Settings.Default.NameToRanking = GameSettings.NameToRanking;
+ Properties.Settings.Default.PupilAdressString = GameSettings.PupilAdressString;
+ Properties.Settings.Default.EyeTribePort = GameSettings.EyeTribePort;
+ Properties.Settings.Default.AttemptsAmount = GameSettings.AttemptsAmount;
+ Properties.Settings.Default.RoundsAmount = GameSettings.RoundsAmount;
+ Properties.Settings.Default.PhotoTime = GameSettings.PhotoTime;
+ Properties.Settings.Default.EyeTribeTime = GameSettings.EyeTribeTime;
+ Properties.Settings.Default.DisplayPupilGazePoint = GameSettings.DisplayPupilGazePoint;
+ Properties.Settings.Default.DisplayEyeTribeGazePoint = GameSettings.DisplayEyeTribeGazePoint;
+
+ Properties.Settings.Default.Save();
+
+ XmlSerializer xml = new XmlSerializer(typeof(ListOfRankingRecords));
+ TextWriter xmlWriter = new StreamWriter("rank.xml");
+ xml.Serialize(xmlWriter, RankingRecords);
+ xmlWriter.Close();
+ }
+ catch (Exception)
+ { }
+ }
+
+ #endregion
+
+ #region Actualise XAML
+ public void LoadImageFromPupil(ImageSource image)
+ {
+ if (image != null)
+ {
+ image.Freeze();
+ imageFromPupil = image;
+
+ OnPropertyChanged("imageFromPupil");
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/IPageViewModel.cs b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/IPageViewModel.cs
new file mode 100644
index 0000000..61eb48f
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/IPageViewModel.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+
+namespace GuessWhatLookingAt
+{
+ public interface IPageViewModel
+ {
+ }
+}
+
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/MainWindowViewModel.cs b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/MainWindowViewModel.cs
new file mode 100644
index 0000000..5997f30
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/MainWindowViewModel.cs
@@ -0,0 +1,74 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+
+namespace GuessWhatLookingAt
+{
+ public class MainWindowViewModel : BaseViewModel
+ {
+ private IPageViewModel _currentPageViewModel;
+ private List _pageViewModels;
+
+ public List PageViewModels
+ {
+ get
+ {
+ if (_pageViewModels == null)
+ _pageViewModels = new List();
+
+ return _pageViewModels;
+ }
+ }
+
+ public IPageViewModel CurrentPageViewModel
+ {
+ get
+ {
+ return _currentPageViewModel;
+ }
+ set
+ {
+ _currentPageViewModel = value;
+ OnPropertyChanged("CurrentPageViewModel");
+ }
+ }
+
+ private void ChangeViewModel(IPageViewModel viewModel)
+ {
+ if (!PageViewModels.Contains(viewModel))
+ PageViewModels.Add(viewModel);
+
+ CurrentPageViewModel = PageViewModels
+ .FirstOrDefault(vm => vm == viewModel);
+ }
+
+ private void OnGoToSettings(object obj)
+ {
+ ChangeViewModel(PageViewModels[0]);
+ }
+
+ private void OnGoToFreezeGame(object obj)
+ {
+ ChangeViewModel(PageViewModels[1]);
+ }
+
+ private void OnGoToRanking(object obj)
+ {
+ ChangeViewModel(PageViewModels[2]);
+ }
+
+ public MainWindowViewModel(MainWindow mainWindow, FreezeGameSettings gameSettings, ListOfRankingRecords rankingRecords)
+ {
+ // Add available pages and set page
+ PageViewModels.Add(new SettingsViewModel(gameSettings));
+ PageViewModels.Add(new FreezeGameViewModel(mainWindow, gameSettings, rankingRecords));
+ PageViewModels.Add(new RankingViewModel(rankingRecords));
+
+ CurrentPageViewModel = PageViewModels[1];
+
+ Mediator.Subscribe("GoToSettings", OnGoToSettings);
+ Mediator.Subscribe("GoToFreezeGame", OnGoToFreezeGame);
+ Mediator.Subscribe("GoToRanking", OnGoToRanking);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/RankingViewModel.cs b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/RankingViewModel.cs
new file mode 100644
index 0000000..8e81cbc
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/RankingViewModel.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace GuessWhatLookingAt
+{
+ public class RankingViewModel : BaseViewModel, IPageViewModel, INotifyPropertyChanged
+ {
+ ListOfRankingRecords listOfRankingRecords;
+
+ List _rankingRecords;
+ public List RankingRecords
+ {
+ get
+ {
+ return _rankingRecords;
+ }
+ set
+ {
+ _rankingRecords = value;
+ _rankingRecords.Sort((RankingRecord r1, RankingRecord r2) =>
+ {
+ if (r1.PointsGenerally < r2.PointsGenerally)
+ return 1;
+ else if (r1.PointsGenerally > r2.PointsGenerally)
+ return -1;
+ else
+ return 0;
+ });
+ OnPropertyChanged("RankingRecords");
+ }
+ }
+
+ public RankingViewModel(ListOfRankingRecords rankingRecords)
+ {
+ listOfRankingRecords = rankingRecords;
+ listOfRankingRecords.OnRankingRecordSaved += OnNewRankingRecord;
+ RankingRecords = rankingRecords.list;
+ }
+
+ public void OnNewRankingRecord(object sender, ListOfRankingRecords.RankingRecordSavedEventArgs args)
+ {
+ RankingRecords = listOfRankingRecords.list;
+ OnPropertyChanged("RankingRecords");
+ }
+
+ private ICommand _goToFreezeGame;
+
+ public ICommand GoToFreezeGame
+ {
+ get
+ {
+ return _goToFreezeGame ?? (_goToFreezeGame = new RelayCommand(x =>
+ {
+ Mediator.Notify("GoToFreezeGame", "");
+ }));
+ }
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/SettingsViewModel.cs b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/SettingsViewModel.cs
new file mode 100644
index 0000000..e63c4cc
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/SettingsViewModel.cs
@@ -0,0 +1,202 @@
+using System;
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Input;
+
+namespace GuessWhatLookingAt
+{
+ public class SettingsViewModel : BaseViewModel, IPageViewModel, INotifyPropertyChanged
+ {
+ #region Settings variables
+
+ FreezeGameSettings GameSettings;
+
+ string _nameToRanking = "";
+ public string NameToRanking
+ {
+ get
+ {
+ return _nameToRanking;
+ }
+ set
+ {
+ _nameToRanking = value;
+ OnPropertyChanged("NameToRanking");
+ }
+ }
+
+ string _pupilAdressString = "";
+ public string PupilAdressString
+ {
+ get
+ {
+ return _pupilAdressString;
+ }
+ set
+ {
+ _pupilAdressString = value;
+ OnPropertyChanged("PupilAdressString");
+ }
+ }
+
+ string _eyeTribePortString = "6255";
+ public string EyeTribePortString
+ {
+ get
+ {
+ return _eyeTribePortString;
+ }
+
+ set
+ {
+ _eyeTribePortString = value;
+ OnPropertyChanged("EyeTribePortString");
+ }
+
+ }
+
+
+ int _attemptsAmount = 3;
+ public int AttemptsAmount
+ {
+ get
+ {
+ return _attemptsAmount;
+ }
+ set
+ {
+ _attemptsAmount = value;
+ OnPropertyChanged("AttemptsAmount");
+ }
+ }
+
+ int _roundsAmount = 7;
+ public int RoundsAmount
+ {
+ get
+ {
+ return _roundsAmount;
+ }
+ set
+ {
+ _roundsAmount = value;
+ OnPropertyChanged("RoundsAmount");
+ }
+ }
+
+ int _photoTime = 3;
+ public int PhotoTime
+ {
+ get
+ {
+ return _photoTime;
+ }
+ set
+ {
+ _photoTime = value;
+ OnPropertyChanged("PhotoTime");
+ }
+ }
+
+ int _eyeTribeTime = 5;
+ public int EyeTribeTime
+ {
+ get
+ {
+ return _eyeTribeTime;
+ }
+ set
+ {
+ _eyeTribeTime = value;
+ OnPropertyChanged("EyeTribeTime");
+ }
+ }
+
+ bool _displayPupilGazePoint = false;
+ public bool DisplayPupilGazePoint
+ {
+ get
+ {
+ return _displayPupilGazePoint;
+ }
+ set
+ {
+ _displayPupilGazePoint = value;
+ OnPropertyChanged("DisplayPupilGazePoint");
+ }
+ }
+
+ bool _displayEyeTribeGazePoint = false;
+ public bool DisplayEyeTribeGazePoint
+ {
+ get
+ {
+ return _displayEyeTribeGazePoint;
+ }
+ set
+ {
+ _displayEyeTribeGazePoint = value;
+ OnPropertyChanged("DisplayEyeTribeGazePoint");
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public SettingsViewModel(FreezeGameSettings gameSettings)
+ {
+ GameSettings = gameSettings;
+ _nameToRanking = GameSettings.NameToRanking;
+ _pupilAdressString = GameSettings.PupilAdressString;
+ _eyeTribePortString = GameSettings.EyeTribePort.ToString();
+ _attemptsAmount = GameSettings.AttemptsAmount;
+ _roundsAmount = GameSettings.RoundsAmount;
+ _photoTime = GameSettings.PhotoTime;
+ _eyeTribeTime = GameSettings.EyeTribeTime;
+ _displayPupilGazePoint = GameSettings.DisplayPupilGazePoint;
+ _displayEyeTribeGazePoint = GameSettings.DisplayEyeTribeGazePoint;
+ }
+
+ #endregion
+
+ #region GoToFreezeGame
+
+ private ICommand _goToFreezeGame;
+
+ public ICommand GoToFreezeGame
+ {
+ get
+ {
+ return _goToFreezeGame ?? (_goToFreezeGame = new RelayCommand(x =>
+ {
+ Mediator.Notify("GoToFreezeGame", "");
+ }));
+ }
+ }
+
+ #endregion
+
+
+ private ICommand _saveSettings;
+
+ public ICommand SaveSettings
+ {
+ get
+ {
+ return _saveSettings ?? (_saveSettings = new RelayCommand(x =>
+ {
+ GameSettings.NameToRanking = _nameToRanking;
+ GameSettings.PupilAdressString = _pupilAdressString;
+ GameSettings.EyeTribePort = Int32.Parse(_eyeTribePortString);
+ GameSettings.AttemptsAmount = _attemptsAmount;
+ GameSettings.RoundsAmount = _roundsAmount;
+ GameSettings.PhotoTime = _photoTime;
+ GameSettings.EyeTribeTime = _eyeTribeTime;
+ GameSettings.DisplayPupilGazePoint = _displayPupilGazePoint;
+ GameSettings.DisplayEyeTribeGazePoint = _displayEyeTribeGazePoint;
+ }));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/WindowViewParameters.cs b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/WindowViewParameters.cs
new file mode 100644
index 0000000..4d498d1
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/ViewModels/WindowViewParameters.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace GuessWhatLookingAt
+{
+ public class WindowViewParameters
+ {
+ public Rect WindowRect { get; set; }
+
+ public Rect WindowMaximizedRect { get; set; }
+
+ public WindowState WindowState { get; set; }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Views/FreezeGameUserControl.xaml b/GuessWhatLookingAt/GuessWhatLookingAt/Views/FreezeGameUserControl.xaml
new file mode 100644
index 0000000..a173805
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Views/FreezeGameUserControl.xaml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Views/FreezeGameUserControl.xaml.cs b/GuessWhatLookingAt/GuessWhatLookingAt/Views/FreezeGameUserControl.xaml.cs
new file mode 100644
index 0000000..6fe7320
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Views/FreezeGameUserControl.xaml.cs
@@ -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 GuessWhatLookingAt
+{
+ ///
+ /// Interaction logic for UserControl1.xaml
+ ///
+ public partial class FreezeGameUserControl : UserControl
+ {
+ public FreezeGameUserControl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Views/MainWindow.xaml b/GuessWhatLookingAt/GuessWhatLookingAt/Views/MainWindow.xaml
new file mode 100644
index 0000000..dfbd30b
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Views/MainWindow.xaml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Views/MainWindow.xaml.cs b/GuessWhatLookingAt/GuessWhatLookingAt/Views/MainWindow.xaml.cs
new file mode 100644
index 0000000..f620a86
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Views/MainWindow.xaml.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Windows;
+
+
+namespace GuessWhatLookingAt
+{
+ public partial class MainWindow : Window
+ {
+ public event EventHandler WindowViewParametersChangedEvent;
+ public event EventHandler GameClosedEvent;
+ public MainWindow() => InitializeComponent();
+
+ private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ var args = new WindowViewParametersEventArgs(
+ new Rect(
+ x: Left,
+ y: Top,
+ width: Width,
+ height: Height));
+ args.WndState = WindowState;
+ WindowViewParametersChangedEvent?.Invoke(this, args);
+ }
+
+ private void Window_LocationChanged(object sender, EventArgs e)
+ {
+ var args = new WindowViewParametersEventArgs(
+ new Rect(
+ x: Left,
+ y: Top,
+ width: Width,
+ height: Height));
+ args.WndState = WindowState;
+ WindowViewParametersChangedEvent?.Invoke(this, args);
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ var args = new WindowViewParametersEventArgs(
+ new Rect(
+ x: Left,
+ y: Top,
+ width: Width,
+ height: Height));
+ args.WndState = WindowState;
+ args.WasLoaded = true;
+ WindowViewParametersChangedEvent?.Invoke(this, args);
+ }
+
+ private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ var args = new GameClosedEventArgs();
+ GameClosedEvent?.Invoke(this, args);
+
+ Environment.Exit(Environment.ExitCode);
+ }
+
+ public class WindowViewParametersEventArgs : EventArgs
+ {
+ public WindowViewParametersEventArgs(Rect r) => WindowRect = r;
+ public Rect WindowRect { get; set; }
+ public WindowState WndState { get; set; }
+
+ public bool WasLoaded { get; set; } = false;
+ }
+
+ public class GameClosedEventArgs : EventArgs
+ {}
+
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Views/RankingUserControl.xaml b/GuessWhatLookingAt/GuessWhatLookingAt/Views/RankingUserControl.xaml
new file mode 100644
index 0000000..1a394c5
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Views/RankingUserControl.xaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Views/RankingUserControl.xaml.cs b/GuessWhatLookingAt/GuessWhatLookingAt/Views/RankingUserControl.xaml.cs
new file mode 100644
index 0000000..9041332
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Views/RankingUserControl.xaml.cs
@@ -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 GuessWhatLookingAt
+{
+ ///
+ /// Interaction logic for RankingUserControl.xaml
+ ///
+ public partial class RankingUserControl : UserControl
+ {
+ public RankingUserControl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Views/SettingsUserControl.xaml b/GuessWhatLookingAt/GuessWhatLookingAt/Views/SettingsUserControl.xaml
new file mode 100644
index 0000000..ee994d3
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Views/SettingsUserControl.xaml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/Views/SettingsUserControl.xaml.cs b/GuessWhatLookingAt/GuessWhatLookingAt/Views/SettingsUserControl.xaml.cs
new file mode 100644
index 0000000..c7701e3
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/Views/SettingsUserControl.xaml.cs
@@ -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 GuessWhatLookingAt
+{
+ ///
+ /// Interaction logic for UserControl2.xaml
+ ///
+ public partial class SettingsUserControl : UserControl
+ {
+ public SettingsUserControl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/GuessWhatLookingAt/GuessWhatLookingAt/packages.config b/GuessWhatLookingAt/GuessWhatLookingAt/packages.config
new file mode 100644
index 0000000..125e3f8
--- /dev/null
+++ b/GuessWhatLookingAt/GuessWhatLookingAt/packages.config
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0734f14
--- /dev/null
+++ b/README.md
@@ -0,0 +1,78 @@
+# GuessWhatLookingAt
+
+Simple game used [Pupil Labs Core](https://pupil-labs.com/products/core/) and [The Eye Tribe](https://theeyetribe.com/theeyetribe.com/about/index.html) eye trackers. Game made for Engineering Thesis with .NET Framework 4.8 and WPF.
+
+## Table of contents
+* [Screenshots from game](#screenshots-from-game)
+* [Rules](#rules)
+* [Used libraries](#used-libraries)
+* [Launch and preapring for game](#launch-and-preapring-for-game)
+* [License](#license)
+
+## Screenshots from game
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+You can also see an video of example game [here](https://1drv.ms/u/s!AoCDBbbUtWLph419cpl7viQwTJBT6A?e=sGeVAu)
+
+## Rules
+
+The first player shares video from Pupil Labs Core main camera and indicates one thing on which he is looking at. The second one tries to guess what is it and indicates this thing by The Eye Tribe or mouse. Second player gets points to ranking depending on a distance between Pupil gaze point and second player's indicated point.
+
+## Used libraries
+
+- [NetMQ](https://netmq.readthedocs.io/en/latest/) - [ZeroMQ](https://zeromq.org/) for C# (communicating with Pupil Labs [IPC Backbone API](https://docs.pupil-labs.com/developer/core/network-api/#ipc-backbone))
+- [SimpleMessagePack](https://github.com/ymofen/SimpleMsgPack.Net) - [MessagePack](https://msgpack.org/) for C# (packing and unpacking text message data send/received to/from IPC Backbone)
+- [EmguCV](https://www.emgu.com/wiki/index.php/Main_Page) - [OpenCV](https://opencv.org/) for C# (display video from Pupil Labs main camera and drawing gaze points on it in real time)
+- [JSON.NET Newtonsoft](https://www.newtonsoft.com/json) - reading JSON messages
+- [MaterialDesignThemes](https://www.nuget.org/packages/MaterialDesignThemes/) - GUI library
+
+## Launch and preapring for game
+
+For launch game you have to install:
+- [.NET Framework 4.8](https://dotnet.microsoft.com/download/dotnet-framework/net48)
+- [Pupil Capture](https://github.com/pupil-labs/pupil/releases) (author used 2.6 version)
+- [The Eye Tribe SDK](https://github.com/EyeTribe/sdk-installers/releases/tag/0.9.77.1).
+
+Next you should run Pupil Capture, wear Pupil Labs Core eye tracker, set cameras up[[1]](https://docs.pupil-labs.com/core/hardware/#rotate-world-camera)[[2]](https://docs.pupil-labs.com/core/software/pupil-capture/#pupil-detection) and [calibrate](https://docs.pupil-labs.com/core/software/pupil-capture/#calibration) eye tracker. If second player wants to inidicate points by The Eye Tribe, he/she should run EyeTribeServer and EyeTribe UI, next calibrate eye tracker in Eyetribe UI. At the end build GuessWhatLookingAt WPF application.
+
+## License
+
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
diff --git a/ReadmeFiles/image1.png b/ReadmeFiles/image1.png
new file mode 100644
index 0000000..e44f650
Binary files /dev/null and b/ReadmeFiles/image1.png differ
diff --git a/ReadmeFiles/image2.png b/ReadmeFiles/image2.png
new file mode 100644
index 0000000..ad16498
Binary files /dev/null and b/ReadmeFiles/image2.png differ
diff --git a/ReadmeFiles/image3.png b/ReadmeFiles/image3.png
new file mode 100644
index 0000000..6aa4c28
Binary files /dev/null and b/ReadmeFiles/image3.png differ
diff --git a/ReadmeFiles/image4.png b/ReadmeFiles/image4.png
new file mode 100644
index 0000000..c082f64
Binary files /dev/null and b/ReadmeFiles/image4.png differ