diff --git a/TheGameExtreme.Android/Resources/Resource.designer.cs b/TheGameExtreme.Android/Resources/Resource.designer.cs
index 455e66d..884c56f 100644
--- a/TheGameExtreme.Android/Resources/Resource.designer.cs
+++ b/TheGameExtreme.Android/Resources/Resource.designer.cs
@@ -1,11 +1,11 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
//
-// Ce code a été généré par un outil.
-// Version du runtime :4.0.30319.42000
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
//
-// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
-// le code est régénéré.
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
//
//------------------------------------------------------------------------------
diff --git a/TheGameExtreme.iOS/TheGameExtreme.iOS.csproj b/TheGameExtreme.iOS/TheGameExtreme.iOS.csproj
index 5fdc1c6..e641617 100644
--- a/TheGameExtreme.iOS/TheGameExtreme.iOS.csproj
+++ b/TheGameExtreme.iOS/TheGameExtreme.iOS.csproj
@@ -71,10 +71,12 @@
-
+
+ TheGameExtreme.iOS.Resources.Apple.png
+
diff --git a/TheGameExtreme/TheGameExtreme.csproj b/TheGameExtreme/TheGameExtreme.csproj
index 5ffaf23..5ab6b8d 100644
--- a/TheGameExtreme/TheGameExtreme.csproj
+++ b/TheGameExtreme/TheGameExtreme.csproj
@@ -21,7 +21,6 @@
-
diff --git a/TheGameExtreme/view/MainPage.xaml b/TheGameExtreme/view/MainPage.xaml
index 8185052..baacf32 100644
--- a/TheGameExtreme/view/MainPage.xaml
+++ b/TheGameExtreme/view/MainPage.xaml
@@ -7,15 +7,20 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
xmlns:tt="clr-namespace:TouchTracking.Forms;assembly=TouchTracking.Forms"
+ xmlns:local="clr-namespace:TheGameExtreme.view"
mc:Ignorable="d"
x:Class="TheGameExtreme.view.MainPage">
-
-
-
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
-
-
+ Grid.Column="2">
+
+
+
+
+
+ Grid.RowSpan="2"
+ Grid.Column="0"
+ Grid.ColumnSpan="3"/>
diff --git a/TheGameExtreme/view/MainPage.xaml.cs b/TheGameExtreme/view/MainPage.xaml.cs
index 6bf67a1..6b2b140 100644
--- a/TheGameExtreme/view/MainPage.xaml.cs
+++ b/TheGameExtreme/view/MainPage.xaml.cs
@@ -19,17 +19,14 @@ namespace TheGameExtreme.view
{
private bool isFirst = true;
private Main viewmodel;
- private List stacks = new List();
+ private List stacks = new List();
Button button = new Button();
List playersNames;
- SKBitmap bitmap;
- SKBitmap bitmap2;
- SKMatrix matrix = SKMatrix.MakeIdentity();
- // Touch information
- long touchId = -1;
- SKPoint previousPoint;
+ TouchManipulationBitmap bitmap;
+ List bitmapCollection = new List();
+ Dictionary bitmapDictionary = new Dictionary();
public MainPage(List playersNames)
@@ -39,17 +36,29 @@ namespace TheGameExtreme.view
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
-
- string resourceID = "TheGameExtreme.Media.thegame.jpg";
- string resourceID2 = "TheGameExtreme.Media.moon.jpg";
Assembly assembly = GetType().GetTypeInfo().Assembly;
- Stream stream = assembly.GetManifestResourceStream(resourceID);
- bitmap = SKBitmap.Decode(stream);
+ string[] resourceIDs = assembly.GetManifestResourceNames();
- Stream stream2 = assembly.GetManifestResourceStream(resourceID2);
- bitmap2 = SKBitmap.Decode(stream2);
+ SKPoint position = new SKPoint();
+ foreach (string resourceID in resourceIDs)
+ {
+ if (resourceID.EndsWith(".png") ||
+ resourceID.EndsWith(".jpg"))
+ {
+ using (Stream stream = assembly.GetManifestResourceStream(resourceID))
+ {
+ SKBitmap bitmap = SKBitmap.Decode(stream);
+ bitmapCollection.Add(new TouchManipulationBitmap(bitmap)
+ {
+ Matrix = SKMatrix.MakeTranslation(position.X, position.Y),
+ });
+ position.X += 100;
+ position.Y += 100;
+ }
+ }
+ }
//stacks.Add(checkbox0);
@@ -75,60 +84,76 @@ namespace TheGameExtreme.view
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) // Faire plusieurs canvas
{
- SKImageInfo info = args.Info;
- SKSurface surface = args.Surface;
- SKCanvas canvas = surface.Canvas;
+ SKCanvas canvas = args.Surface.Canvas;
canvas.Clear();
- // Display the bitmap
- canvas.SetMatrix(matrix);
- canvas.DrawBitmap(bitmap, new SKPoint());
- //canvas.DrawBitmap(bitmap2, new SKPoint(500, 500));
+ foreach (TouchManipulationBitmap bitmap in bitmapCollection)
+ {
+ bitmap.Paint(canvas);
+ }
}
-
-
void OnTouchEffectAction(object sender, TouchActionEventArgs args)
- {
- // Convert Xamarin.Forms point to pixels
- TouchTrackingPoint pt = args.Location;
- SKPoint point =
- new SKPoint((float)(canvasView.CanvasSize.Width * pt.X / canvasView.Width),
- (float)(canvasView.CanvasSize.Height * pt.Y / canvasView.Height));
+ {
+ // Convert Xamarin.Forms point to pixels
+ TouchTrackingPoint pt = args.Location;
+ SKPoint point =
+ new SKPoint((float)(canvasView.CanvasSize.Width * pt.X / canvasView.Width),
+ (float)(canvasView.CanvasSize.Height * pt.Y / canvasView.Height));
- switch (args.Type)
- {
- case TouchActionType.Pressed:
- // Find transformed bitmap rectangle
- SKRect rect = new SKRect(0, 0, bitmap.Width, bitmap.Height);
- rect = matrix.MapRect(rect);
+ switch (args.Type)
+ {
+ case TouchActionType.Pressed:
+ for (int i = bitmapCollection.Count - 1; i >= 0; i--)
+ {
+ TouchManipulationBitmap bitmap = bitmapCollection[i];
- // Determine if the touch was within that rectangle
- if (rect.Contains(point))
+ if (bitmap.HitTest(point))
{
- touchId = args.Id;
- previousPoint = point;
- }
- break;
+ // Move bitmap to end of collection
+ bitmapCollection.Remove(bitmap);
+ bitmapCollection.Add(bitmap);
- case TouchActionType.Moved:
- if (touchId == args.Id)
- {
- // Adjust the matrix for the new position
- matrix.TransX += point.X - previousPoint.X;
- matrix.TransY += point.Y - previousPoint.Y;
- previousPoint = point;
+ // Do the touch processing
+ bitmapDictionary.Add(args.Id, bitmap);
+ bitmap.ProcessTouchEvent(args.Id, args.Type, point);
canvasView.InvalidateSurface();
+ break;
}
- break;
+ }
+ break;
- case TouchActionType.Released:
- case TouchActionType.Cancelled:
- touchId = -1;
- break;
- }
+ case TouchActionType.Moved:
+ if (bitmapDictionary.ContainsKey(args.Id))
+ {
+ TouchManipulationBitmap bitmap = bitmapDictionary[args.Id];
+ bitmap.ProcessTouchEvent(args.Id, args.Type, point);
+ canvasView.InvalidateSurface();
+ }
+ break;
+
+ case TouchActionType.Released:
+ case TouchActionType.Cancelled:
+ if (bitmapDictionary.ContainsKey(args.Id))
+ {
+ TouchManipulationBitmap bitmap = bitmapDictionary[args.Id];
+ bitmap.ProcessTouchEvent(args.Id, args.Type, point);
+ bitmapDictionary.Remove(args.Id);
+ canvasView.InvalidateSurface();
+ }
+ break;
+ }
+ }
+
+ void OnTouchModePickerSelectedIndexChanged(object sender, EventArgs args)
+ {
+ if (bitmap != null)
+ {
+ Picker picker = (Picker)sender;
+ bitmap.TouchManager.Mode = (TouchManipulationMode)picker.SelectedItem;
}
+ }
diff --git a/TheGameExtreme/view/MatrixDisplay.cs b/TheGameExtreme/view/MatrixDisplay.cs
new file mode 100644
index 0000000..eea59dd
--- /dev/null
+++ b/TheGameExtreme/view/MatrixDisplay.cs
@@ -0,0 +1,103 @@
+using System;
+using SkiaSharp;
+
+namespace TheGameExtreme.view
+{
+ public class MatrixDisplay
+ {
+ public SKPaint MatrixPaint { set; get; } = new SKPaint
+ {
+ Color = SKColors.Black,
+ TextSize = 48,
+ StrokeWidth = 2
+ };
+
+ public string PerspectiveFormat { set; get; } = "F0";
+
+ public SKSize Measure(SKMatrix matrix)
+ {
+ return MeasureAndPaint(null, matrix, new SKPoint(), false);
+ }
+
+ public void Paint(SKCanvas canvas, SKMatrix matrix, SKPoint location)
+ {
+ MeasureAndPaint(canvas, matrix, location, true);
+ }
+
+ SKSize MeasureAndPaint(SKCanvas canvas, SKMatrix matrix, SKPoint location, bool doPaint)
+ {
+ float[] values = matrix.Values;
+ string[] texts = new string[9];
+ SKRect[] bounds = new SKRect[9];
+ float[] widths = new float[3];
+
+ for (int i = 0; i < 9; i++)
+ {
+ int row = i % 3;
+ int col = i / 3;
+
+ // Format string differently based on row
+ texts[i] = values[i].ToString(row == 2 ? "F0" : (col == 2 ? PerspectiveFormat : "F2"));
+
+ // Measure string with a '-' even if one is not present
+ bool isNegative = texts[i][0] == '-';
+ string text = (isNegative ? "" : "-") + texts[i];
+ MatrixPaint.MeasureText(text, ref bounds[i]);
+
+ // Get maximum width for each column
+ widths[col] = Math.Max(widths[col], bounds[i].Width);
+
+ // Measure the text again without the '-' in front
+ MatrixPaint.MeasureText(texts[i], ref bounds[i]);
+ }
+
+ // Some formatting constants
+ float horzGap = MatrixPaint.TextSize;
+ float horzMarg = MatrixPaint.TextSize;
+ float vertMarg = MatrixPaint.FontSpacing / 4;
+
+ // Calculate the total width and height of the matrix display
+ float totalWidth = widths[0] + widths[1] + widths[2] + 2 * horzGap + 2 * horzMarg;
+ float totalHeight = 3 * MatrixPaint.FontSpacing + 2 * vertMarg;
+
+ if (doPaint)
+ {
+ SKPaintStyle saveStyle = MatrixPaint.Style;
+
+ for (int i = 0; i < 9; i++)
+ {
+ int row = i % 3;
+ int col = i / 3;
+
+ // Find x, y of upper-left corner of text
+ float x = location.X + horzMarg;
+
+ for (int c = 0; c < col; c++)
+ {
+ x += widths[c] + horzGap;
+ }
+
+ float y = location.Y + vertMarg + row * MatrixPaint.FontSpacing;
+
+ // Adjust for right-justified text
+ x += widths[col] - bounds[i].Width;
+ y += (MatrixPaint.FontSpacing - bounds[i].Height) / 2 - bounds[i].Top;
+
+ // Draw the text
+ MatrixPaint.Style = SKPaintStyle.Fill;
+ canvas.DrawText(texts[i], x, y, MatrixPaint);
+ }
+
+ // Display vertical lines at the sides of the matrix
+ MatrixPaint.Style = SKPaintStyle.Stroke;
+ canvas.DrawLine(location.X + horzMarg / 2, location.Y + vertMarg,
+ location.X + horzMarg / 2, location.Y + totalHeight - vertMarg, MatrixPaint);
+ canvas.DrawLine(location.X + totalWidth - horzMarg / 2, location.Y + vertMarg,
+ location.X + totalWidth - horzMarg / 2, location.Y + totalHeight - vertMarg, MatrixPaint);
+
+ MatrixPaint.Style = saveStyle;
+ }
+ return new SKSize(totalWidth, totalHeight);
+ }
+ }
+}
diff --git a/TheGameExtreme/view/Settings.xaml b/TheGameExtreme/view/Settings.xaml
index c8e4c8c..dfd29e8 100644
--- a/TheGameExtreme/view/Settings.xaml
+++ b/TheGameExtreme/view/Settings.xaml
@@ -6,84 +6,111 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TheGameExtreme.view.Settings">
-
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
+
-
-
-
-
+ BackgroundColor="{DynamicResource BlackColor}"
+ Margin="10,10,0,0"/>
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
-
+
+
+
+
+
-
+
-
-
+
+
+
+
+
-
+
+
+
diff --git a/TheGameExtreme/view/TouchManipulationBitmap.cs b/TheGameExtreme/view/TouchManipulationBitmap.cs
new file mode 100644
index 0000000..72295a4
--- /dev/null
+++ b/TheGameExtreme/view/TouchManipulationBitmap.cs
@@ -0,0 +1,113 @@
+using System.Collections.Generic;
+using SkiaSharp;
+using TouchTracking;
+
+namespace TheGameExtreme.view
+{
+ public class TouchManipulationBitmap
+ {
+ SKBitmap bitmap;
+ Dictionary touchDictionary = new Dictionary();
+
+ public TouchManipulationBitmap(SKBitmap bitmap)
+ {
+ this.bitmap = bitmap;
+ Matrix = SKMatrix.MakeIdentity();
+
+ TouchManager = new TouchManipulationManager
+ {
+ Mode = TouchManipulationMode.ScaleRotate
+ };
+ }
+
+ public TouchManipulationManager TouchManager { set; get; }
+
+ public SKMatrix Matrix { set; get; }
+
+ public void Paint(SKCanvas canvas)
+ {
+ canvas.Save();
+ SKMatrix matrix = Matrix;
+ canvas.Concat(ref matrix);
+ canvas.DrawBitmap(bitmap, 0, 0);
+ canvas.Restore();
+ }
+
+ public bool HitTest(SKPoint location)
+ {
+ // Invert the matrix
+ SKMatrix inverseMatrix;
+
+ if (Matrix.TryInvert(out inverseMatrix))
+ {
+ // Transform the point using the inverted matrix
+ SKPoint transformedPoint = inverseMatrix.MapPoint(location);
+
+ // Check if it's in the untransformed bitmap rectangle
+ SKRect rect = new SKRect(0, 0, bitmap.Width, bitmap.Height);
+ return rect.Contains(transformedPoint);
+ }
+ return false;
+ }
+
+ public void ProcessTouchEvent(long id, TouchActionType type, SKPoint location)
+ {
+ switch (type)
+ {
+ case TouchActionType.Pressed:
+ touchDictionary.Add(id, new TouchManipulationInfo
+ {
+ PreviousPoint = location,
+ NewPoint = location
+ });
+ break;
+
+ case TouchActionType.Moved:
+ TouchManipulationInfo info = touchDictionary[id];
+ info.NewPoint = location;
+ Manipulate();
+ info.PreviousPoint = info.NewPoint;
+ break;
+
+ case TouchActionType.Released:
+ touchDictionary[id].NewPoint = location;
+ Manipulate();
+ touchDictionary.Remove(id);
+ break;
+
+ case TouchActionType.Cancelled:
+ touchDictionary.Remove(id);
+ break;
+ }
+ }
+
+ void Manipulate()
+ {
+ TouchManipulationInfo[] infos = new TouchManipulationInfo[touchDictionary.Count];
+ touchDictionary.Values.CopyTo(infos, 0);
+ SKMatrix touchMatrix = SKMatrix.MakeIdentity();
+
+ if (infos.Length == 1)
+ {
+ SKPoint prevPoint = infos[0].PreviousPoint;
+ SKPoint newPoint = infos[0].NewPoint;
+ SKPoint pivotPoint = Matrix.MapPoint(bitmap.Width / 2, bitmap.Height / 2);
+
+ touchMatrix = TouchManager.OneFingerManipulate(prevPoint, newPoint, pivotPoint);
+ }
+ else if (infos.Length >= 2)
+ {
+ int pivotIndex = infos[0].NewPoint == infos[0].PreviousPoint ? 0 : 1;
+ SKPoint pivotPoint = infos[pivotIndex].NewPoint;
+ SKPoint newPoint = infos[1 - pivotIndex].NewPoint;
+ SKPoint prevPoint = infos[1 - pivotIndex].PreviousPoint;
+
+ touchMatrix = TouchManager.TwoFingerManipulate(prevPoint, newPoint, pivotPoint);
+ }
+
+ SKMatrix matrix = Matrix;
+ SKMatrix.PostConcat(ref matrix, touchMatrix);
+ Matrix = matrix;
+ }
+ }
+}
\ No newline at end of file
diff --git a/TheGameExtreme/view/TouchManipulationInfo.cs b/TheGameExtreme/view/TouchManipulationInfo.cs
new file mode 100644
index 0000000..a1f5a08
--- /dev/null
+++ b/TheGameExtreme/view/TouchManipulationInfo.cs
@@ -0,0 +1,12 @@
+using System;
+using SkiaSharp;
+
+namespace TheGameExtreme.view
+{
+ public class TouchManipulationInfo
+ {
+ public SKPoint PreviousPoint { set; get; }
+
+ public SKPoint NewPoint { set; get; }
+ }
+}
diff --git a/TheGameExtreme/view/TouchManipulationManager.cs b/TheGameExtreme/view/TouchManipulationManager.cs
new file mode 100644
index 0000000..ae42cbb
--- /dev/null
+++ b/TheGameExtreme/view/TouchManipulationManager.cs
@@ -0,0 +1,107 @@
+using System;
+using SkiaSharp;
+
+namespace TheGameExtreme.view
+{
+ public class TouchManipulationManager
+ {
+
+ public TouchManipulationMode Mode { set; get; }
+
+ float Magnitude(SKPoint point)
+ {
+ return (float)Math.Sqrt(Math.Pow(point.X, 2) + Math.Pow(point.Y, 2));
+ }
+
+ public SKMatrix OneFingerManipulate(SKPoint prevPoint, SKPoint newPoint, SKPoint pivotPoint)
+ {
+ if (Mode == TouchManipulationMode.None)
+ {
+ return SKMatrix.MakeIdentity();
+ }
+
+ SKMatrix touchMatrix = SKMatrix.MakeIdentity();
+ SKPoint delta = newPoint - prevPoint;
+
+ if (Mode == TouchManipulationMode.ScaleDualRotate) // One-finger rotation
+ {
+ SKPoint oldVector = prevPoint - pivotPoint;
+ SKPoint newVector = newPoint - pivotPoint;
+
+ // Avoid rotation if fingers are too close to center
+ if (Magnitude(newVector) > 25 && Magnitude(oldVector) > 25)
+ {
+ float prevAngle = (float)Math.Atan2(oldVector.Y, oldVector.X);
+ float newAngle = (float)Math.Atan2(newVector.Y, newVector.X);
+
+ // Calculate rotation matrix
+ float angle = newAngle - prevAngle;
+ touchMatrix = SKMatrix.MakeRotation(angle, pivotPoint.X, pivotPoint.Y);
+
+ // Effectively rotate the old vector
+ float magnitudeRatio = Magnitude(oldVector) / Magnitude(newVector);
+ oldVector.X = magnitudeRatio * newVector.X;
+ oldVector.Y = magnitudeRatio * newVector.Y;
+
+ // Recalculate delta
+ delta = newVector - oldVector;
+ }
+ }
+
+ // Multiply the rotation matrix by a translation matrix
+ SKMatrix.PostConcat(ref touchMatrix, SKMatrix.MakeTranslation(delta.X, delta.Y));
+
+ return touchMatrix;
+ }
+
+ public SKMatrix TwoFingerManipulate(SKPoint prevPoint, SKPoint newPoint, SKPoint pivotPoint)
+ {
+ SKMatrix touchMatrix = SKMatrix.MakeIdentity();
+ SKPoint oldVector = prevPoint - pivotPoint;
+ SKPoint newVector = newPoint - pivotPoint;
+
+ if (Mode == TouchManipulationMode.ScaleRotate ||
+ Mode == TouchManipulationMode.ScaleDualRotate)
+ {
+ // Find angles from pivot point to touch points
+ float oldAngle = (float)Math.Atan2(oldVector.Y, oldVector.X);
+ float newAngle = (float)Math.Atan2(newVector.Y, newVector.X);
+
+ // Calculate rotation matrix
+ float angle = newAngle - oldAngle;
+ touchMatrix = SKMatrix.MakeRotation(angle, pivotPoint.X, pivotPoint.Y);
+
+ // Effectively rotate the old vector
+ float magnitudeRatio = Magnitude(oldVector) / Magnitude(newVector);
+ oldVector.X = magnitudeRatio * newVector.X;
+ oldVector.Y = magnitudeRatio * newVector.Y;
+ }
+
+ float scaleX = 1;
+ float scaleY = 1;
+
+ if (Mode == TouchManipulationMode.AnisotropicScale)
+ {
+ scaleX = newVector.X / oldVector.X;
+ scaleY = newVector.Y / oldVector.Y;
+
+ }
+ else if (Mode == TouchManipulationMode.IsotropicScale ||
+ Mode == TouchManipulationMode.ScaleRotate ||
+ Mode == TouchManipulationMode.ScaleDualRotate)
+ {
+ scaleX = scaleY = Magnitude(newVector) / Magnitude(oldVector);
+ }
+
+ if (!float.IsNaN(scaleX) && !float.IsInfinity(scaleX) &&
+ !float.IsNaN(scaleY) && !float.IsInfinity(scaleY))
+ {
+ SKMatrix.PostConcat(ref touchMatrix,
+ SKMatrix.MakeScale(scaleX, scaleY, pivotPoint.X, pivotPoint.Y));
+ }
+
+ return touchMatrix;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/TheGameExtreme/view/TouchManipulationMode.cs b/TheGameExtreme/view/TouchManipulationMode.cs
new file mode 100644
index 0000000..689c5a6
--- /dev/null
+++ b/TheGameExtreme/view/TouchManipulationMode.cs
@@ -0,0 +1,13 @@
+using System;
+namespace TheGameExtreme.view
+{
+ public enum TouchManipulationMode
+ {
+ None,
+ PanOnly,
+ IsotropicScale, // includes panning
+ AnisotropicScale, // includes panning
+ ScaleRotate, // implies isotropic scaling
+ ScaleDualRotate // adds one-finger rotation
+ }
+}