initial commit

This commit is contained in:
dmusial98 2025-06-22 20:49:22 +02:00
parent 613b80b2fd
commit 20e00e4c47
45 changed files with 3685 additions and 0 deletions

BIN
GuessWhatLookingAt.zip Normal file

Binary file not shown.

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="GuessWhatLookingAt.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
<section name="MvvmNavigation.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<userSettings>
<GuessWhatLookingAt.Properties.Settings>
<setting name="PupilAdressString" serializeAs="String">
<value>tcp://127.0.0.1:50020</value>
</setting>
<setting name="EyeTribePort" serializeAs="String">
<value>6555</value>
</setting>
<setting name="AttemptsAmount" serializeAs="String">
<value>2</value>
</setting>
<setting name="RoundsAmount" serializeAs="String">
<value>2</value>
</setting>
<setting name="PhotoTime" serializeAs="String">
<value>3</value>
</setting>
<setting name="EyeTribeTime" serializeAs="String">
<value>4</value>
</setting>
<setting name="DisplayPupilGazePoint" serializeAs="String">
<value>False</value>
</setting>
<setting name="DisplayEyeTribeGazePoint" serializeAs="String">
<value>True</value>
</setting>
<setting name="NameToRanking" serializeAs="String">
<value>Player</value>
</setting>
</GuessWhatLookingAt.Properties.Settings>
<MvvmNavigation.Properties.Settings>
<setting name="EyeTribe" serializeAs="String">
<value>EYETRIBE</value>
</setting>
<setting name="Number" serializeAs="String">
<value>10</value>
</setting>
<setting name="Number2" serializeAs="String">
<value>16</value>
</setting>
</MvvmNavigation.Properties.Settings>
</userSettings>
</configuration>

View file

@ -0,0 +1,24 @@
<Application x:Class="GuessWhatLookingAt.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:local="clr-namespace:GuessWhatLookingAt">
<!--StartupUri="MainWindow.xaml">-->
<Application.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type local:FreezeGameViewModel}">
<local:FreezeGameUserControl />
</DataTemplate>
<DataTemplate DataType="{x:Type local:SettingsViewModel}">
<local:SettingsUserControl />
</DataTemplate>
<DataTemplate DataType="{x:Type local:RankingViewModel}">
<local:RankingUserControl />
</DataTemplate>
<ResourceDictionary.MergedDictionaries>
<materialDesign:CustomColorTheme BaseTheme="Dark" PrimaryColor="DarkGreen" SecondaryColor="DarkBlue" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

View file

@ -0,0 +1,58 @@
using System;
using System.IO;
using System.Windows;
using System.Xml.Serialization;
namespace GuessWhatLookingAt
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
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();
}
}
}

View file

@ -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;
}
}
}

View file

@ -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<EyeTribeReceivedDataEventArgs> 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<EyeTribeReceivedDataEventArgs> handler = OnData;
if (handler != null)
{
handler(this, e);
}
}
}
}

View file

@ -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");
}
}
}

View file

@ -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<PupilReceivedDataEventArgs> 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<GazePoint>();
//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<GazePoint> GazePoints { get; set; }
}
}
}

View file

@ -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<BitmapSourceEventArgs> BitmapSourceReached;
public class BitmapSourceEventArgs : EventArgs
{
public BitmapSourceEventArgs(ImageSource im) => Image = im;
public ImageSource Image { get; set; }
}
List<Point> _AttemptPoints = new List<Point>();
#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<EyeTribeGazePositionEventArgs> EyeTribeGazePointReached;
public class EyeTribeGazePositionEventArgs : EventArgs
{
public EyeTribeGazePositionEventArgs(double gazeX, double gazeY) => GazePoint = new Point(gazeX, gazeY);
public Point GazePoint { get; set; }
}
public event EventHandler<EyeTribeTimerEventArgs> 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<PhotoTimeChangedEventArgs> 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<double> _distanceHistory = new List<double>();
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
}
}

View file

@ -0,0 +1,20 @@
using System.Collections.Generic;
namespace GuessWhatLookingAt
{
public class FreezeGamePunctation
{
public List<double> PunctationList = new List<double>();
private int maxPoints = 10;
public FreezeGamePunctation()
{
for(int i = maxPoints; i > 0; i--)
{
PunctationList.Add(i * 0.05);
}
}
public FreezeGamePunctation(List<double> punctation) => PunctationList = punctation;
}
}

View file

@ -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;
}
}

View file

@ -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<RankingRecord> list { get; set; }
public ListOfRankingRecords() => list = new List<RankingRecord>();
public void NewElement()
{
var args = new RankingRecordSavedEventArgs();
OnRankingRecordSaved?.Invoke(this, args);
}
public event EventHandler<RankingRecordSavedEventArgs> 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; }
}
}

View file

@ -0,0 +1,264 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E30F7550-189A-4B99-B6B4-B2801B6F9AE7}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>GuessWhatLookingAt</RootNamespace>
<AssemblyName>GuessWhatLookingAt</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="AsyncIO, Version=0.1.69.0, Culture=neutral, PublicKeyToken=44a94435bd6f33f8, processorArchitecture=MSIL">
<HintPath>..\packages\AsyncIO.0.1.69\lib\net40\AsyncIO.dll</HintPath>
</Reference>
<Reference Include="Castle.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="Emgu.CV.Platform.NetStandard, Version=4.4.0.4061, Culture=neutral, PublicKeyToken=7281126722ab4438, processorArchitecture=MSIL">
<HintPath>..\packages\Emgu.CV.4.4.0.4061\lib\netstandard2.0\Emgu.CV.Platform.NetStandard.dll</HintPath>
</Reference>
<Reference Include="MaterialDesignColors, Version=1.2.7.1979, Culture=neutral, PublicKeyToken=df2a72020bd7962a, processorArchitecture=MSIL">
<HintPath>packages\MaterialDesignColors.1.2.7\lib\net45\MaterialDesignColors.dll</HintPath>
</Reference>
<Reference Include="MaterialDesignThemes.Wpf, Version=3.2.0.1979, Culture=neutral, PublicKeyToken=df2a72020bd7962a, processorArchitecture=MSIL">
<HintPath>packages\MaterialDesignThemes.3.2.0\lib\net45\MaterialDesignThemes.Wpf.dll</HintPath>
</Reference>
<Reference Include="NaCl, Version=0.1.13.0, Culture=neutral, PublicKeyToken=827c20e50a9775fa, processorArchitecture=MSIL">
<HintPath>..\packages\NaCl.Net.0.1.13\lib\net472\NaCl.dll</HintPath>
</Reference>
<Reference Include="NetMQ, Version=4.0.1.6, Culture=neutral, PublicKeyToken=a6decef4ddc58b3a, processorArchitecture=MSIL">
<HintPath>..\packages\NetMQ.4.0.1.6\lib\net47\NetMQ.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SimpleMsgPack, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleMsgPack.1.0.0.0\lib\net40\SimpleMsgPack.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Drawing.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Drawing.Primitives.4.3.0\lib\net45\System.Drawing.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime, Version=4.1.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.ServiceModel" />
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="ViewModels\BaseViewModel.cs" />
<Compile Include="EyeTrackers\EyeTribe.cs" />
<Compile Include="GameModel\FreezeGameModel.cs" />
<Compile Include="GameModel\FreezeGamePunctation.cs" />
<Compile Include="GameModel\FreezeGameSettings.cs" />
<Compile Include="EyeTrackers\GazePoint.cs" />
<Compile Include="ViewModels\MainWindowViewModel.cs" />
<Compile Include="NavigateBetweenViews\EventArgs.cs" />
<Compile Include="NavigateBetweenViews\EventRaiser.cs" />
<Compile Include="ViewModels\IPageViewModel.cs" />
<Compile Include="NavigateBetweenViews\Mediator.cs" />
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Settings.settings</DependentUpon>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Compile>
<Compile Include="EyeTrackers\Pupil.cs" />
<Compile Include="EmguCVImage\EmguCVImage.cs" />
<Compile Include="GameModel\RankingRecord.cs" />
<Compile Include="Views\RankingUserControl.xaml.cs">
<DependentUpon>RankingUserControl.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\RankingViewModel.cs" />
<Compile Include="NavigateBetweenViews\RelayCommand.cs" />
<Compile Include="Views\FreezeGameUserControl.xaml.cs">
<DependentUpon>FreezeGameUserControl.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\FreezeGameViewModel.cs" />
<Compile Include="Views\SettingsUserControl.xaml.cs">
<DependentUpon>SettingsUserControl.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\SettingsViewModel.cs" />
<Compile Include="ViewModels\WindowViewParameters.cs" />
<Page Include="Views\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Views\MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="Views\FreezeGameUserControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\RankingUserControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SettingsUserControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>PublicSettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.8">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.8 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Emgu.CV.runtime.windows.4.4.0.4099\build\Emgu.CV.runtime.windows.targets" Condition="Exists('..\packages\Emgu.CV.runtime.windows.4.4.0.4099\build\Emgu.CV.runtime.windows.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Emgu.CV.runtime.windows.4.4.0.4099\build\Emgu.CV.runtime.windows.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Emgu.CV.runtime.windows.4.4.0.4099\build\Emgu.CV.runtime.windows.targets'))" />
<Error Condition="!Exists('packages\MaterialDesignThemes.3.2.0\build\MaterialDesignThemes.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\MaterialDesignThemes.3.2.0\build\MaterialDesignThemes.targets'))" />
</Target>
<Import Project="packages\MaterialDesignThemes.3.2.0\build\MaterialDesignThemes.targets" Condition="Exists('packages\MaterialDesignThemes.3.2.0\build\MaterialDesignThemes.targets')" />
</Project>

View file

@ -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

View file

@ -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<T> : EventArgs
{
public EventArgs(T value)
{
Value = value;
}
public T Value { get; private set; }
}
}

View file

@ -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<T>(this EventHandler<EventArgs<T>> handler, object sender, T value)
{
handler?.Invoke(sender, new EventArgs<T>(value));
}
public static void Raise<T>(this EventHandler<T> handler, object sender, T value) where T : EventArgs
{
handler?.Invoke(sender, value);
}
public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, EventArgs<T> value)
{
handler?.Invoke(sender, value);
}
}
}

View file

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
namespace GuessWhatLookingAt
{
public static class Mediator
{
private static IDictionary<string, List<Action<object>>> pl_dict =
new Dictionary<string, List<Action<object>>>();
public static void Subscribe(string token, Action<object> callback)
{
if (!pl_dict.ContainsKey(token))
{
var list = new List<Action<object>>();
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<object> 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);
}
}
}

View file

@ -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<T> : ICommand
{
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public RelayCommand(Action<T> execute)
: this(execute, null)
{
_execute = execute;
}
public RelayCommand(Action<T> execute, Predicate<T> 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<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
_execute = execute;
}
public RelayCommand(Action<object> execute, Predicate<object> 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);
}
}
}

View file

@ -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
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> 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")]

View file

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
namespace GuessWhatLookingAt.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// 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() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[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;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -0,0 +1,134 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
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;
}
}
}
}

View file

@ -0,0 +1,33 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="GuessWhatLookingAt.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="PupilAdressString" Type="System.String" Scope="User">
<Value Profile="(Default)">tcp://127.0.0.1:50020</Value>
</Setting>
<Setting Name="EyeTribePort" Type="System.Int32" Scope="User">
<Value Profile="(Default)">6555</Value>
</Setting>
<Setting Name="AttemptsAmount" Type="System.Int32" Scope="User">
<Value Profile="(Default)">2</Value>
</Setting>
<Setting Name="RoundsAmount" Type="System.Int32" Scope="User">
<Value Profile="(Default)">2</Value>
</Setting>
<Setting Name="PhotoTime" Type="System.Int32" Scope="User">
<Value Profile="(Default)">3</Value>
</Setting>
<Setting Name="EyeTribeTime" Type="System.Int32" Scope="User">
<Value Profile="(Default)">4</Value>
</Setting>
<Setting Name="DisplayPupilGazePoint" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="DisplayEyeTribeGazePoint" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="NameToRanking" Type="System.String" Scope="User">
<Value Profile="(Default)">Player</Value>
</Setting>
</Settings>
</SettingsFile>

View file

@ -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.
}
}
}

View file

@ -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);
}
}
}

View file

@ -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
}
}

View file

@ -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
{
}
}

View file

@ -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<IPageViewModel> _pageViewModels;
public List<IPageViewModel> PageViewModels
{
get
{
if (_pageViewModels == null)
_pageViewModels = new List<IPageViewModel>();
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);
}
}
}

View file

@ -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<RankingRecord> _rankingRecords;
public List<RankingRecord> 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", "");
}));
}
}
}
}

View file

@ -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;
}));
}
}
}
}

View file

@ -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; }
}
}

View file

@ -0,0 +1,97 @@
<UserControl x:Class="GuessWhatLookingAt.FreezeGameUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:GuessWhatLookingAt"
mc:Ignorable="d" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90*" />
<ColumnDefinition Width="10*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="90*" />
<RowDefinition Height="10*" />
</Grid.RowDefinitions>
<Image Name="PupilImageXAML" Grid.Row="0" Stretch="Fill" Source="{Binding Path=imageFromPupil, UpdateSourceTrigger=PropertyChanged}" />
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="12*" />
<ColumnDefinition Width="12*" />
<ColumnDefinition Width="12*" />
<ColumnDefinition Width="66*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Margin="5" Content="{Binding Path=ConnectPupilButtonContentString, UpdateSourceTrigger=PropertyChanged}" Command="{Binding ConnectDisconnectWithPupil}" />
<Button Grid.Column="1" Margin="5" Content="{Binding Path=ConnectEyeTribeButtonContentString, UpdateSourceTrigger=PropertyChanged}" Command="{Binding ConnectDisconnectWithEyeTribe}" />
<Button Grid.Column="2" Margin="5" Command="{Binding StartRound}">
<TextBlock TextWrapping="Wrap" Text="{Binding Path=StartRoundButtonContentString, UpdateSourceTrigger=PropertyChanged}" />
</Button>
<Label Grid.Column="3" FontSize="30" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock TextWrapping="Wrap" Text="{Binding Path=GameInfoLabelContentString, UpdateSourceTrigger=PropertyChanged}" />
</Label>
</Grid>
</Grid>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Margin="8" Content="Settings" Command="{Binding GoToSettings}" />
<Button Grid.Row="1" Margin="8" Content="Ranking" Command="{Binding GoToRanking}"/>
<Label Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center" >
<TextBlock TextWrapping="Wrap" Text="Eye Tribe:" />
</Label>
<Label Grid.Row="3" VerticalAlignment="Center" HorizontalAlignment="Center" >
<TextBlock TextWrapping="Wrap" Text="{Binding Path=EyeTribeCoordinatesString, UpdateSourceTrigger=PropertyChanged}" />
</Label>
<Label Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock TextWrapping="Wrap" Text="Distance:" />
</Label>
<Label Grid.Row="5" VerticalAlignment="Center" HorizontalAlignment="Center" >
<TextBlock TextWrapping="Wrap" Text="{Binding Path=MouseDistanceToPupilGazePoint, UpdateSourceTrigger=PropertyChanged}" />
</Label>
<Label Grid.Row="6" VerticalAlignment="Center" HorizontalAlignment="Center" >
<TextBlock TextWrapping="Wrap" Text="Round:" />
</Label>
<Label Grid.Row="7" VerticalAlignment="Center" HorizontalAlignment="Center" >
<TextBlock TextWrapping="Wrap" Text="{Binding Path=RoundValueLabelContentString, UpdateSourceTrigger=PropertyChanged}" />
</Label>
<Label Grid.Row="8" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock TextWrapping="Wrap" Text="Attempt:" />
</Label>
<Label Grid.Row="9" VerticalAlignment="Center" HorizontalAlignment="Center" >
<TextBlock TextWrapping="Wrap" Text="{Binding Path=AttemptValueLabelContentString, UpdateSourceTrigger=PropertyChanged}" />
</Label>
<Label Grid.Row="10" VerticalAlignment="Center" HorizontalAlignment="Center" >
<TextBlock TextWrapping="Wrap" Text="Points:" />
</Label>
<Label Grid.Row="11" VerticalAlignment="Center" HorizontalAlignment="Center" >
<TextBlock TextWrapping="Wrap" Text="{Binding Path=PointsValueLabelContentString, UpdateSourceTrigger=PropertyChanged}" />
</Label>
<Button Grid.Row="12" Margin="8" Content="Display Pupil point" Command="{Binding DisplayPupilGazePoint}"/>
<Button Grid.Row="13" Margin="8" Content="Display ET point" Command="{Binding DisplayEyeTribeGazePoint}"/>
</Grid>
</Grid>
</UserControl>

View file

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

View file

@ -0,0 +1,23 @@
<Window x:Class="GuessWhatLookingAt.MainWindow"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextElement.FontWeight="Regular"
TextElement.FontSize="12"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{DynamicResource MaterialDesignFont}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GuessWhatLookingAt"
mc:Ignorable="d"
Title="Guess what looking at" WindowState="Maximized" SizeChanged="Window_SizeChanged" LocationChanged="Window_LocationChanged"
Loaded="Window_Loaded" StateChanged="Window_LocationChanged" Closing="Window_Closing">
<Grid>
<ContentControl Content="{Binding CurrentPageViewModel}" />
</Grid>
</Window>

View file

@ -0,0 +1,71 @@
using System;
using System.Windows;
namespace GuessWhatLookingAt
{
public partial class MainWindow : Window
{
public event EventHandler<WindowViewParametersEventArgs> WindowViewParametersChangedEvent;
public event EventHandler<GameClosedEventArgs> 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
{}
}
}

View file

@ -0,0 +1,36 @@
<UserControl x:Class="GuessWhatLookingAt.RankingUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:GuessWhatLookingAt"
mc:Ignorable="d"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="12*" />
<RowDefinition Height="18*" />
<RowDefinition Height="80*" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Go to game" Margin="10" HorizontalAlignment="Right" VerticalAlignment="Top" Command="{Binding GoToFreezeGame}"/>
<Label Grid.Row="1" FontSize="30" Content="Ranking" VerticalAlignment="Center" HorizontalAlignment="Center" />
<ListView Grid.Row="2" HorizontalAlignment="Center" ItemsSource="{Binding RankingRecords, UpdateSourceTrigger=PropertyChanged}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Date" DisplayMemberBinding="{Binding Date}" />
<GridViewColumn Header="Points Generally" DisplayMemberBinding="{Binding PointsGenerally}" />
<GridViewColumn Header="Points in game" DisplayMemberBinding="{Binding PointsInGame}" />
<GridViewColumn Header="Attempts in round" DisplayMemberBinding="{Binding AttemptsAmountInRound}" />
<GridViewColumn Header="Rounds amount" DisplayMemberBinding="{Binding RoundsAmount}" />
<GridViewColumn Header="Average distance" DisplayMemberBinding="{Binding AverageDistance}" />
</GridView>
</ListView.View>
</ListView>
<!--<Button Grid.Row="3" HorizontalAlignment="Center" VerticalAlignment="Center" Content="Remove result" Margin="10" />-->
</Grid>
</UserControl>

View file

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

View file

@ -0,0 +1,106 @@
<UserControl x:Class="GuessWhatLookingAt.SettingsUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:GuessWhatLookingAt"
mc:Ignorable="d" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="8*" />
<RowDefinition Height="20*" />
<RowDefinition Height="64*" />
<RowDefinition Height="8*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions >
<ColumnDefinition Width="92*" />
<ColumnDefinition Width="8*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="1" Margin="10" Content="Go to game" Command="{Binding GoToFreezeGame}" />
</Grid>
<Label Grid.Row="1" FontSize="40" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock TextWrapping="Wrap" Text="Settings" />
</Label>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Margin="15" HorizontalAlignment="Center" VerticalAlignment="Center" Content="Name for saving result in ranking:" />
<TextBox Grid.Row="0" Grid.Column="1" Margin="20" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Path=NameToRanking, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Label Grid.Row="1" Grid.Column="0" Margin="15" Content="Pupil Capture IP address:" VerticalAlignment="Center" HorizontalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" Margin="20" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Path=PupilAdressString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Eye tribe port number:" />
<TextBox Grid.Row="2" Grid.Column="1" Margin="20" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Path=EyeTribePortString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Label Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Number of rounds in one game:" />
<Grid Grid.Row="3" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90*" />
<ColumnDefinition Width="10*" />
</Grid.ColumnDefinitions>
<Slider Grid.Column="0" Maximum="25" Minimum="1" Margin="20" Value="{Binding Path=RoundsAmount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Label Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Content="{Binding Path=RoundsAmount, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
<Label Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Number of attempts in one round:" />
<Grid Grid.Row="4" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90*" />
<ColumnDefinition Width="10*" />
</Grid.ColumnDefinitions>
<Slider Grid.Column="0" Margin="20" Maximum="10" Minimum="1" Value="{Binding Path=AttemptsAmount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Label Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Content="{Binding Path=AttemptsAmount, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
<Label Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Time for taking photo in seconds:" />
<Grid Grid.Row="5" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90*" />
<ColumnDefinition Width="10*" />
</Grid.ColumnDefinitions>
<Slider Grid.Column="0" Margin="20" Maximum="30" Minimum="1" Value="{Binding Path=PhotoTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Label Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Content="{Binding Path=PhotoTime, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
<Label Grid.Row="6" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Time for taking position of Eye Tribe gaze point is seconds:" />
<Grid Grid.Row="6" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90*" />
<ColumnDefinition Width="10*" />
</Grid.ColumnDefinitions>
<Slider Grid.Column="0" Margin="20" Maximum="30" Minimum="1" Value="{Binding Path=EyeTribeTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Label Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Content="{Binding Path=EyeTribeTime, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
<Label Grid.Row="7" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Show Pupil gaze points:" />
<CheckBox Grid.Row="7" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding Path=DisplayPupilGazePoint, UpdateSourceTrigger=PropertyChanged}" />
<Label Grid.Row="8" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Show Eye Tribe gaze point" />
<CheckBox Grid.Row="8" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding Path=DisplayEyeTribeGazePoint, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="46*"/>
<ColumnDefinition Width="8*" />
<ColumnDefinition Width="46*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="1" Margin="5" Command="{Binding SaveSettings}">
<TextBlock TextWrapping="Wrap" Text="Save" />
</Button>
</Grid>
</Grid>
</UserControl>

View file

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

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AsyncIO" version="0.1.69" targetFramework="net48" />
<package id="Castle.Core" version="3.3.3" targetFramework="net48" />
<package id="Emgu.CV" version="4.4.0.4061" targetFramework="net48" />
<package id="Emgu.CV.runtime.windows" version="4.4.0.4099" targetFramework="net48" />
<package id="MaterialDesignColors" version="1.2.7" targetFramework="net48" />
<package id="MaterialDesignThemes" version="3.2.0" targetFramework="net48" />
<package id="NaCl.Net" version="0.1.13" targetFramework="net48" />
<package id="NetMQ" version="4.0.1.6" targetFramework="net48" />
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net48" />
<package id="SimpleMsgPack" version="1.0.0.0" targetFramework="net48" />
<package id="System.Buffers" version="4.4.0" targetFramework="net48" />
<package id="System.Drawing.Primitives" version="4.3.0" targetFramework="net48" />
<package id="System.Memory" version="4.5.3" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net48" />
<package id="System.Runtime" version="4.3.1" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net48" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net48" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
</packages>

78
README.md Normal file
View file

@ -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
<p align="center">
<table cellspacing="0" cellpadding="0">
<tr>
<img src="https://github.com/dmusial98/GuessWhatLookingAt/blob/master/ReadmeFiles/image1.png">
</tr>
<tr>
<img src="https://github.com/dmusial98/GuessWhatLookingAt/blob/master/ReadmeFiles/image2.png">
</tr>
<tr>
<img src="https://github.com/dmusial98/GuessWhatLookingAt/blob/master/ReadmeFiles/image3.png">
</tr>
<tr>
<img src="https://github.com/dmusial98/GuessWhatLookingAt/blob/master/ReadmeFiles/image4.png">
</tr>
</table>
</p>
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 <http://unlicense.org/>

BIN
ReadmeFiles/image1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
ReadmeFiles/image2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 MiB

BIN
ReadmeFiles/image3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
ReadmeFiles/image4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB