|
| 1 | +using System.Reflection; |
| 2 | +using System.Runtime.InteropServices; |
| 3 | +using Silk.NET.Core; |
| 4 | +using Silk.NET.Input; |
| 5 | +using Silk.NET.Maths; |
| 6 | +using Silk.NET.OpenGL; |
| 7 | +using Silk.NET.Windowing; |
| 8 | +using SilkTrains; |
| 9 | +using SixLabors.ImageSharp; |
| 10 | +using SixLabors.ImageSharp.PixelFormats; |
| 11 | +using SkiaSharp; |
| 12 | +using Trains.NET.Rendering; |
| 13 | +using Trains.NET.Rendering.Skia; |
| 14 | +using Trains.Storage; |
| 15 | + |
| 16 | +// Game stuff |
| 17 | +string windowSizeFileName = FileSystemStorage.GetFilePath("WindowSize.txt"); |
| 18 | +IGame game = DI.ServiceLocator.GetService<IGame>(); |
| 19 | +IInteractionManager interactionManager = DI.ServiceLocator.GetService<IInteractionManager>(); |
| 20 | + |
| 21 | +// Get size from file |
| 22 | +Vector2D<int> size = new(1280, 720); |
| 23 | +if (File.Exists(windowSizeFileName)) |
| 24 | +{ |
| 25 | + string sizeString = File.ReadAllText(windowSizeFileName); |
| 26 | + string[] bits = sizeString.Split(','); |
| 27 | + if (bits.Length == 2) |
| 28 | + { |
| 29 | + if (double.TryParse(bits[0], out double width) && double.TryParse(bits[1], out double height)) |
| 30 | + { |
| 31 | + size = new((int)width, (int)height); |
| 32 | + } |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +// Create the Silk.NET window |
| 37 | +var options = WindowOptions.Default with |
| 38 | +{ |
| 39 | + Size = size, |
| 40 | + Title = "Trains - @davidwengier - " + ThisAssembly.AssemblyInformationalVersion, |
| 41 | + PreferredStencilBufferBits = 8, |
| 42 | + PreferredBitDepth = new(8) |
| 43 | +}; |
| 44 | + |
| 45 | +var window = Window.Create(options); |
| 46 | + |
| 47 | +// Silk.NET-Skia interop variables |
| 48 | +GRGlInterface grGlInterface = null!; |
| 49 | +GRContext grContext = null!; |
| 50 | +GRBackendRenderTarget renderTarget = null!; |
| 51 | +SKSurface surface = null!; |
| 52 | +SKCanvas canvas = null!; |
| 53 | +SKCanvasWrapper canvasWrapper = null!; |
| 54 | + |
| 55 | +// Other Silk.NET variables |
| 56 | +IInputContext inputContext = null!; |
| 57 | + |
| 58 | +// Input handling |
| 59 | +void BindMouse(IMouse mouse) |
| 60 | +{ |
| 61 | + mouse.Scroll += (_, deltaPos) => |
| 62 | + { |
| 63 | + var mousePos = window.NotBuggedPointToFramebuffer((Vector2D<int>)mouse.Position.ToGeneric()); |
| 64 | + if (deltaPos.Y > 0) |
| 65 | + { |
| 66 | + interactionManager.PointerZoomIn(mousePos.X, mousePos.Y); |
| 67 | + } |
| 68 | + else |
| 69 | + { |
| 70 | + interactionManager.PointerZoomOut(mousePos.X, mousePos.Y); |
| 71 | + } |
| 72 | + }; |
| 73 | + mouse.MouseMove += (_, newPosFloat) => |
| 74 | + { |
| 75 | + var mousePos = window.NotBuggedPointToFramebuffer((Vector2D<int>)newPosFloat.ToGeneric()); |
| 76 | + if (mouse.IsButtonPressed(MouseButton.Left)) |
| 77 | + { |
| 78 | + interactionManager.PointerDrag(mousePos.X, mousePos.Y); |
| 79 | + } |
| 80 | + else if (mouse.IsButtonPressed(MouseButton.Right)) |
| 81 | + { |
| 82 | + interactionManager.PointerAlternateDrag(mousePos.X, mousePos.Y); |
| 83 | + } |
| 84 | + else |
| 85 | + { |
| 86 | + interactionManager.PointerMove(mousePos.X, mousePos.Y); |
| 87 | + } |
| 88 | + }; |
| 89 | + mouse.MouseDown += (_, button) => |
| 90 | + { |
| 91 | + var mousePos = window.NotBuggedPointToFramebuffer((Vector2D<int>)mouse.Position.ToGeneric()); |
| 92 | + if (button == MouseButton.Left) |
| 93 | + { |
| 94 | + interactionManager.PointerClick(mousePos.X, mousePos.Y); |
| 95 | + } |
| 96 | + else if (button == MouseButton.Right) |
| 97 | + { |
| 98 | + interactionManager.PointerAlternateClick(mousePos.X, mousePos.Y); |
| 99 | + } |
| 100 | + }; |
| 101 | + mouse.MouseUp += (_, button) => |
| 102 | + { |
| 103 | + if (button != MouseButton.Left) |
| 104 | + { |
| 105 | + return; |
| 106 | + } |
| 107 | + |
| 108 | + var mousePos = window.NotBuggedPointToFramebuffer((Vector2D<int>)mouse.Position.ToGeneric()); |
| 109 | + interactionManager.PointerRelease(mousePos.X, mousePos.Y); |
| 110 | + }; |
| 111 | +} |
| 112 | + |
| 113 | +// Create the Skia-OpenGL link |
| 114 | +void HandleSize(Vector2D<int> fbSize) |
| 115 | +{ |
| 116 | + renderTarget = new(window.FramebufferSize.X, window.FramebufferSize.Y, 0, 8, new(0, (int)InternalFormat.Rgba8)); |
| 117 | + surface = SKSurface.Create(grContext, renderTarget, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888); |
| 118 | + canvas = surface.Canvas; |
| 119 | + canvasWrapper = new(canvas); |
| 120 | + game.SetSize(fbSize.X, fbSize.Y); |
| 121 | +} |
| 122 | + |
| 123 | +// Bind window events |
| 124 | +window.Load += () => |
| 125 | +{ |
| 126 | + grGlInterface = GRGlInterface.Create(name => window.GLContext!.TryGetProcAddress(name, out var addr) ? addr : 0); |
| 127 | + grGlInterface.Validate(); |
| 128 | + grContext = GRContext.CreateGl(grGlInterface); |
| 129 | + game.InitializeAsync(200, 200).GetAwaiter().GetResult(); |
| 130 | + HandleSize(window.FramebufferSize); |
| 131 | + inputContext = window.CreateInput(); |
| 132 | + if (inputContext.Mice.Count > 0) |
| 133 | + { |
| 134 | + BindMouse(inputContext.Mice[0]); |
| 135 | + } |
| 136 | + |
| 137 | + using var ers = Assembly.GetExecutingAssembly().GetManifestResourceStream("SilkTrains.RedTrain.png"); |
| 138 | + if (ers is null) |
| 139 | + { |
| 140 | + return; |
| 141 | + } |
| 142 | + |
| 143 | + using var img = Image.Load<Rgba32>(ers); |
| 144 | + var rowByteLen = img.Width * 4; |
| 145 | + var bytes = new byte[rowByteLen * img.Height]; |
| 146 | + for (int i = 0; i < img.Height; i++) |
| 147 | + { |
| 148 | + MemoryMarshal.Cast<Rgba32, byte>(img.GetPixelRowSpan(i)).CopyTo(bytes.AsSpan(i * rowByteLen, rowByteLen)); |
| 149 | + } |
| 150 | + var rawImage = new RawImage(img.Width, img.Height, bytes); |
| 151 | + window.SetWindowIcon(ref rawImage); |
| 152 | +}; |
| 153 | + |
| 154 | +window.FramebufferResize += HandleSize; |
| 155 | +window.Render += deltaSeconds => |
| 156 | +{ |
| 157 | + grContext.ResetContext(); |
| 158 | + game.Render(canvasWrapper); |
| 159 | + canvas.Flush(); |
| 160 | +}; |
| 161 | + |
| 162 | +window.Closing += () => |
| 163 | +{ |
| 164 | + game.Dispose(); |
| 165 | + File.WriteAllText(windowSizeFileName, $"{window.Size.X},{window.Size.Y}"); |
| 166 | +}; |
| 167 | + |
| 168 | +// Open the window! |
| 169 | +window.Run(); |
0 commit comments