From 5fdd55f732d694125123e992753c3780c30ac482 Mon Sep 17 00:00:00 2001 From: feyris-tan <4116042+feyris-tan@users.noreply.github.com> Date: Mon, 11 Aug 2025 19:36:09 +0200 Subject: [PATCH] Built a MonoGame skeleton. --- .gitignore | 6 + .../BaseGame.cs | 120 +++++ .../DrawVertDeclaration.cs | 29 ++ .../FpsCounterWindow.cs | 77 +++ .../GameObject.cs | 10 + .../ImGuiRenderable.cs | 9 + .../ImGuiRenderer.cs | 443 ++++++++++++++++++ .../IqWindow.cs | 41 ++ .../RandomExtension.cs | 9 + .../ScottPlotWindow.cs | 62 +++ .../TextureDisplayWindow.cs | 79 ++++ .../Ziggurat.cs | 186 ++++++++ .../ZigguratStream.cs | 83 ++++ ...kyscraper8.UI.ImGui.MonoGame.Bridge.csproj | 17 + GUIs/skyscraper8.UI.ImGui.MonoGame/Program.cs | 13 + .../Screenhacks/0_Blank.cs | 32 ++ .../Screenhacks/1_YourWaifu.cs | 58 +++ .../Screenhacks/2_Substrate.cs | 372 +++++++++++++++ .../Screenhacks/IScreenhack.cs | 17 + .../Screenhacks/Processing.cs | 193 ++++++++ .../Screenhacks/ScreenhackException.cs | 23 + .../Screenhacks/ScreenhackManager.cs | 66 +++ .../SkyscraperGame.cs | 47 ++ .../skyscraper8.UI.ImGui.MonoGame.csproj | 15 + GUIs/skyscraper8.UI.ImGui/Program.cs | 2 +- ...sproj => skyscraper8.UI.ImGui.SDL2.csproj} | 0 skyscraper8.sln | 16 +- skyscraper8/Program.cs | 16 +- 28 files changed, 2030 insertions(+), 11 deletions(-) create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/BaseGame.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/DrawVertDeclaration.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/FpsCounterWindow.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/GameObject.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ImGuiRenderable.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ImGuiRenderer.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/IqWindow.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/RandomExtension.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ScottPlotWindow.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/TextureDisplayWindow.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/Ziggurat.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ZigguratStream.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/skyscraper8.UI.ImGui.MonoGame.Bridge.csproj create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame/Program.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/0_Blank.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/1_YourWaifu.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/2_Substrate.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/IScreenhack.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/Processing.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/ScreenhackException.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/ScreenhackManager.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame/SkyscraperGame.cs create mode 100644 GUIs/skyscraper8.UI.ImGui.MonoGame/skyscraper8.UI.ImGui.MonoGame.csproj rename GUIs/skyscraper8.UI.ImGui/{skyscraper8.UI.ImGui.csproj => skyscraper8.UI.ImGui.SDL2.csproj} (100%) diff --git a/.gitignore b/.gitignore index 26e55e0..5d88d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -116,3 +116,9 @@ imgui.ini /.vs/skyscraper8/CopilotIndices/17.14.827.52834 /GUIs/skyscraper8.AnagramViewer/obj /GUIs/skyscraper8.AnagramViewer/bin/Debug/net8.0-windows +/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/bin/Debug/net8.0 +/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/obj/Debug/net8.0 +/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/obj +/GUIs/skyscraper8.UI.ImGui.MonoGame/bin/Debug/net8.0 +/GUIs/skyscraper8.UI.ImGui.MonoGame/obj/Debug/net8.0 +/GUIs/skyscraper8.UI.ImGui.MonoGame/obj diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/BaseGame.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/BaseGame.cs new file mode 100644 index 0000000..391c2e4 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/BaseGame.cs @@ -0,0 +1,120 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace ImGuiNET.SampleProgram.XNA; + +public class BaseGame : Game +{ + protected GraphicsDeviceManager _graphics; + protected GraphicsDevice _graphicsDevice; + protected ImGuiRenderer _imGuiRenderer; + protected Random _rng; + protected SpriteBatch _spriteBatch; + + protected BaseGame() + { + _graphics = new GraphicsDeviceManager(this); + + _rng = new Random(); + ChangeResolutionMode(1280, 720, true); + + IsMouseVisible = true; + } + + protected void ChangeResolutionMode(int width, int height, bool multisampling) + { + _graphics.PreferredBackBufferWidth = width; + _graphics.PreferredBackBufferHeight = height; + _graphics.PreferMultiSampling = multisampling; + _windowBounds = new Rectangle(0, 0, width, height); + } + + private Rectangle _windowBounds; + protected Rectangle WindowBounds + { + get + { + return _windowBounds; + } + } + + protected override void Initialize() + { + _imGuiRenderer = new ImGuiRenderer(this); + _imGuiRenderer.RebuildFontAtlas(); + _imGuiRenderables = new List(); + _graphicsDevice = _graphics.GraphicsDevice; + _spriteBatch = new SpriteBatch(GraphicsDevice); + _gameObjects = new List(); + Window.AllowUserResizing = false; + base.Initialize(); + } + + + protected List _gameObjects; + protected override void Update(GameTime gameTime) + { + Monitor.Enter(_gameObjects); + foreach (GameObject gameObject in _gameObjects) + { + gameObject.Update(gameTime, _graphicsDevice); + } + Monitor.Exit(_gameObjects); + + Monitor.Enter(_imGuiRenderables); + for (int i = 0; i < _imGuiRenderables.Count; i++) + { + if (_imGuiRenderables.Count == 0) + continue; + if (_imGuiRenderables[i].WasClosed()) + { + _imGuiRenderables[i].Dispose(); + _imGuiRenderables.RemoveAt(i); + i = 0; + continue; + } + } + foreach (ImGuiRenderable renderable in _imGuiRenderables) + { + renderable.Update(); + } + Monitor.Exit(_imGuiRenderables); + } + + protected override void Draw(GameTime gameTime) + { + // Call BeforeLayout first to set things up + _imGuiRenderer.BeforeLayout(gameTime); + + //Draw our other stuff. + _spriteBatch.Begin(); + Monitor.Enter(_gameObjects); + foreach (GameObject gameObject in _gameObjects) + { + gameObject.Draw(gameTime,_spriteBatch,WindowBounds); + } + Monitor.Exit(_gameObjects); + _spriteBatch.End(); + + // Draw our UI + ImGuiLayout(); + + // Call AfterLayout now to finish up and draw all the things + _imGuiRenderer.AfterLayout(); + + base.Draw(gameTime); + } + + protected List _imGuiRenderables; + protected virtual void ImGuiLayout() + { + Monitor.Enter(_imGuiRenderables); + foreach (ImGuiRenderable renderable in _imGuiRenderables) + { + renderable.Render(); + } + Monitor.Exit(_imGuiRenderables); + + Console.WriteLine("X = {0}, Y = {1}", _imGuiRenderer.LastKnownMouseX,_imGuiRenderer.LastKnownMouseY); + } +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/DrawVertDeclaration.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/DrawVertDeclaration.cs new file mode 100644 index 0000000..ce79d64 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/DrawVertDeclaration.cs @@ -0,0 +1,29 @@ +using Microsoft.Xna.Framework.Graphics; + +namespace ImGuiNET.SampleProgram.XNA +{ + public static class DrawVertDeclaration + { + public static readonly VertexDeclaration Declaration; + + public static readonly int Size; + + static DrawVertDeclaration() + { + unsafe { Size = sizeof(ImDrawVert); } + + Declaration = new VertexDeclaration( + Size, + + // Position + new VertexElement(0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0), + + // UV + new VertexElement(8, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0), + + // Color + new VertexElement(16, VertexElementFormat.Color, VertexElementUsage.Color, 0) + ); + } + } +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/FpsCounterWindow.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/FpsCounterWindow.cs new file mode 100644 index 0000000..85e78fd --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/FpsCounterWindow.cs @@ -0,0 +1,77 @@ +using ImGuiNET; +using ImGuiNET.SampleProgram.XNA; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace MgExample.Bridges; + +public class FpsCounterWindow : ImGuiRenderable, GameObject +{ + public FpsCounterWindow() + { + open = true; + } + public void Dispose() + { + } + + public void Update() + { + } + + private bool open; + public void Render() + { + ImGui.Begin("FPS Counter", ref open); + if (!samplingDone) + { + ImGui.Text("Sampling..."); + } + else + { + ImGui.Text(String.Format("FPS: {0}", lastCallsPerSecond)); + } + + ImGui.End(); + } + + public bool WasClosed() + { + return !open; + } + + private bool samplingDone; + private int secondsPassed; + private DateTime lastSeconds; + private int thisCallsPerSecond; + private int lastCallsPerSecond; + public void Update(GameTime gameTime, GraphicsDevice graphicsDevice) + { + thisCallsPerSecond++; + DateTime currentSeconds = DateTime.Now; + if (lastSeconds.Second != currentSeconds.Second) + { + lastCallsPerSecond = thisCallsPerSecond; + secondsPassed++; + lastSeconds = currentSeconds; + thisCallsPerSecond = 0; + if (samplingDone) + { + OnSampleAvailable?.Invoke(currentSeconds, lastCallsPerSecond); + } + } + + if (secondsPassed >= 2) + { + samplingDone = true; + } + } + + public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Rectangle windowBounds) + { + + } + + public delegate void SampleAvailable(DateTime time, int fps); + public event SampleAvailable OnSampleAvailable; +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/GameObject.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/GameObject.cs new file mode 100644 index 0000000..07efc72 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/GameObject.cs @@ -0,0 +1,10 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace ImGuiNET.SampleProgram.XNA; + +public interface GameObject +{ + void Update(GameTime gameTime, GraphicsDevice graphicsDevice); + void Draw(GameTime gameTime, SpriteBatch spriteBatch, Rectangle windowBounds); +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ImGuiRenderable.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ImGuiRenderable.cs new file mode 100644 index 0000000..e6aff5e --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ImGuiRenderable.cs @@ -0,0 +1,9 @@ +namespace ImGuiNET.SampleProgram.XNA; + +public interface ImGuiRenderable : IDisposable +{ + void Update(); + void Render(); + + bool WasClosed(); +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ImGuiRenderer.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ImGuiRenderer.cs new file mode 100644 index 0000000..7439250 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ImGuiRenderer.cs @@ -0,0 +1,443 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace ImGuiNET.SampleProgram.XNA +{ + /// + /// ImGui renderer for use with XNA-likes (FNA & MonoGame) + /// + public class ImGuiRenderer + { + private Game _game; + + // Graphics + private GraphicsDevice _graphicsDevice; + + private BasicEffect _effect; + private RasterizerState _rasterizerState; + + private byte[] _vertexData; + private VertexBuffer _vertexBuffer; + private int _vertexBufferSize; + + private byte[] _indexData; + private IndexBuffer _indexBuffer; + private int _indexBufferSize; + + // Textures + private Dictionary _loadedTextures; + + private int _textureId; + private IntPtr? _fontTextureId; + + // Input + private int _scrollWheelValue; + private int _horizontalScrollWheelValue; + private readonly float WHEEL_DELTA = 120; + private Keys[] _allKeys = Enum.GetValues(); + + public ImGuiRenderer(Game game) + { + var context = ImGui.CreateContext(); + ImGui.SetCurrentContext(context); + + _game = game ?? throw new ArgumentNullException(nameof(game)); + _graphicsDevice = game.GraphicsDevice; + + _loadedTextures = new Dictionary(); + + _rasterizerState = new RasterizerState() + { + CullMode = CullMode.None, + DepthBias = 0, + FillMode = FillMode.Solid, + MultiSampleAntiAlias = false, + ScissorTestEnable = true, + SlopeScaleDepthBias = 0 + }; + + SetupInput(); + } + + #region ImGuiRenderer + + private const bool DISABLE_FONT_ATLAS = false; + /// + /// Creates a texture and loads the font data from ImGui. Should be called when the is initialized but before any rendering is done + /// + public virtual unsafe void RebuildFontAtlas() + { + if (DISABLE_FONT_ATLAS) + return; + + // Get font texture from ImGui + var io = ImGui.GetIO(); + io.Fonts.GetTexDataAsRGBA32(out byte* pixelData, out int width, out int height, out int bytesPerPixel); + + // Copy the data to a managed array + var pixels = new byte[width * height * bytesPerPixel]; + unsafe { Marshal.Copy(new IntPtr(pixelData), pixels, 0, pixels.Length); } + + // Create and register the texture as an XNA texture + var tex2d = new Texture2D(_graphicsDevice, width, height, false, SurfaceFormat.Color); + tex2d.SetData(pixels); + + // Should a texture already have been build previously, unbind it first so it can be deallocated + if (_fontTextureId.HasValue) UnbindTexture(_fontTextureId.Value); + + // Bind the new texture to an ImGui-friendly id + _fontTextureId = BindTexture(tex2d); + + // Let ImGui know where to find the texture + io.Fonts.SetTexID(_fontTextureId.Value); + io.Fonts.ClearTexData(); // Clears CPU side texture data + } + + /// + /// Creates a pointer to a texture, which can be passed through ImGui calls such as . That pointer is then used by ImGui to let us know what texture to draw + /// + public virtual IntPtr BindTexture(Texture2D texture) + { + var id = new IntPtr(_textureId++); + + _loadedTextures.Add(id, texture); + + return id; + } + + /// + /// Removes a previously created texture pointer, releasing its reference and allowing it to be deallocated + /// + public virtual void UnbindTexture(IntPtr textureId) + { + _loadedTextures.Remove(textureId); + } + + /// + /// Sets up ImGui for a new frame, should be called at frame start + /// + public virtual void BeforeLayout(GameTime gameTime) + { + ImGui.GetIO().DeltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; + + UpdateInput(); + + + ImGui.NewFrame(); + } + + /// + /// Asks ImGui for the generated geometry data and sends it to the graphics pipeline, should be called after the UI is drawn using ImGui.** calls + /// + public virtual void AfterLayout() + { + ImGui.Render(); + + unsafe { RenderDrawData(ImGui.GetDrawData()); } + } + + #endregion ImGuiRenderer + + #region Setup & Update + + /// + /// Setup key input event handler. + /// + protected virtual void SetupInput() + { + var io = ImGui.GetIO(); + + // MonoGame-specific ////////////////////// + _game.Window.TextInput += (s, a) => + { + if (a.Character == '\t') return; + io.AddInputCharacter(a.Character); + }; + + /////////////////////////////////////////// + + // FNA-specific /////////////////////////// + //TextInputEXT.TextInput += c => + //{ + // if (c == '\t') return; + + // ImGui.GetIO().AddInputCharacter(c); + //}; + /////////////////////////////////////////// + } + + /// + /// Updates the to the current matrices and texture + /// + protected virtual Effect UpdateEffect(Texture2D texture) + { + _effect = _effect ?? new BasicEffect(_graphicsDevice); + + var io = ImGui.GetIO(); + + _effect.World = Matrix.Identity; + _effect.View = Matrix.Identity; + _effect.Projection = Matrix.CreateOrthographicOffCenter(0f, io.DisplaySize.X, io.DisplaySize.Y, 0f, -1f, 1f); + _effect.TextureEnabled = true; + _effect.Texture = texture; + _effect.VertexColorEnabled = true; + + return _effect; + } + + public int LastKnownMouseX { get; set; } + public int LastKnownMouseY { get; set; } + /// + /// Sends XNA input state to ImGui + /// + protected virtual void UpdateInput() + { + if (!_game.IsActive) return; + + var io = ImGui.GetIO(); + + var mouse = Mouse.GetState(); + LastKnownMouseX = mouse.X; + LastKnownMouseY = mouse.Y; + var keyboard = Keyboard.GetState(); + io.AddMousePosEvent(mouse.X, mouse.Y); + io.AddMouseButtonEvent(0, mouse.LeftButton == ButtonState.Pressed); + io.AddMouseButtonEvent(1, mouse.RightButton == ButtonState.Pressed); + io.AddMouseButtonEvent(2, mouse.MiddleButton == ButtonState.Pressed); + io.AddMouseButtonEvent(3, mouse.XButton1 == ButtonState.Pressed); + io.AddMouseButtonEvent(4, mouse.XButton2 == ButtonState.Pressed); + + io.AddMouseWheelEvent( + (mouse.HorizontalScrollWheelValue - _horizontalScrollWheelValue) / WHEEL_DELTA, + (mouse.ScrollWheelValue - _scrollWheelValue) / WHEEL_DELTA); + _scrollWheelValue = mouse.ScrollWheelValue; + _horizontalScrollWheelValue = mouse.HorizontalScrollWheelValue; + + foreach (var key in _allKeys) + { + if (TryMapKeys(key, out ImGuiKey imguikey)) + { + io.AddKeyEvent(imguikey, keyboard.IsKeyDown(key)); + } + } + + io.DisplaySize = new System.Numerics.Vector2(_graphicsDevice.PresentationParameters.BackBufferWidth, _graphicsDevice.PresentationParameters.BackBufferHeight); + io.DisplayFramebufferScale = new System.Numerics.Vector2(1f, 1f); + } + + private bool TryMapKeys(Keys key, out ImGuiKey imguikey) + { + //Special case not handed in the switch... + //If the actual key we put in is "None", return none and true. + //otherwise, return none and false. + if (key == Keys.None) + { + imguikey = ImGuiKey.None; + return true; + } + + imguikey = key switch + { + Keys.Back => ImGuiKey.Backspace, + Keys.Tab => ImGuiKey.Tab, + Keys.Enter => ImGuiKey.Enter, + Keys.CapsLock => ImGuiKey.CapsLock, + Keys.Escape => ImGuiKey.Escape, + Keys.Space => ImGuiKey.Space, + Keys.PageUp => ImGuiKey.PageUp, + Keys.PageDown => ImGuiKey.PageDown, + Keys.End => ImGuiKey.End, + Keys.Home => ImGuiKey.Home, + Keys.Left => ImGuiKey.LeftArrow, + Keys.Right => ImGuiKey.RightArrow, + Keys.Up => ImGuiKey.UpArrow, + Keys.Down => ImGuiKey.DownArrow, + Keys.PrintScreen => ImGuiKey.PrintScreen, + Keys.Insert => ImGuiKey.Insert, + Keys.Delete => ImGuiKey.Delete, + >= Keys.D0 and <= Keys.D9 => ImGuiKey._0 + (key - Keys.D0), + >= Keys.A and <= Keys.Z => ImGuiKey.A + (key - Keys.A), + >= Keys.NumPad0 and <= Keys.NumPad9 => ImGuiKey.Keypad0 + (key - Keys.NumPad0), + Keys.Multiply => ImGuiKey.KeypadMultiply, + Keys.Add => ImGuiKey.KeypadAdd, + Keys.Subtract => ImGuiKey.KeypadSubtract, + Keys.Decimal => ImGuiKey.KeypadDecimal, + Keys.Divide => ImGuiKey.KeypadDivide, + >= Keys.F1 and <= Keys.F24 => ImGuiKey.F1 + (key - Keys.F1), + Keys.NumLock => ImGuiKey.NumLock, + Keys.Scroll => ImGuiKey.ScrollLock, + Keys.LeftShift => ImGuiKey.LeftShift, + Keys.LeftControl => ImGuiKey.LeftCtrl, + Keys.LeftAlt => ImGuiKey.LeftAlt, + Keys.OemSemicolon => ImGuiKey.Semicolon, + Keys.OemPlus => ImGuiKey.Equal, + Keys.OemComma => ImGuiKey.Comma, + Keys.OemMinus => ImGuiKey.Minus, + Keys.OemPeriod => ImGuiKey.Period, + Keys.OemQuestion => ImGuiKey.Slash, + Keys.OemTilde => ImGuiKey.GraveAccent, + Keys.OemOpenBrackets => ImGuiKey.LeftBracket, + Keys.OemCloseBrackets => ImGuiKey.RightBracket, + Keys.OemPipe => ImGuiKey.Backslash, + Keys.OemQuotes => ImGuiKey.Apostrophe, + _ => ImGuiKey.None, + }; + + return imguikey != ImGuiKey.None; + } + + #endregion Setup & Update + + #region Internals + + /// + /// Gets the geometry as set up by ImGui and sends it to the graphics device + /// + private void RenderDrawData(ImDrawDataPtr drawData) + { + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers + var lastViewport = _graphicsDevice.Viewport; + var lastScissorBox = _graphicsDevice.ScissorRectangle; + var lastRasterizer = _graphicsDevice.RasterizerState; + var lastDepthStencil = _graphicsDevice.DepthStencilState; + var lastBlendFactor = _graphicsDevice.BlendFactor; + var lastBlendState = _graphicsDevice.BlendState; + + _graphicsDevice.BlendFactor = Color.White; + _graphicsDevice.BlendState = BlendState.NonPremultiplied; + _graphicsDevice.RasterizerState = _rasterizerState; + _graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; + + // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) + drawData.ScaleClipRects(ImGui.GetIO().DisplayFramebufferScale); + + // Setup projection + _graphicsDevice.Viewport = new Viewport(0, 0, _graphicsDevice.PresentationParameters.BackBufferWidth, _graphicsDevice.PresentationParameters.BackBufferHeight); + + UpdateBuffers(drawData); + + RenderCommandLists(drawData); + + // Restore modified state + _graphicsDevice.Viewport = lastViewport; + _graphicsDevice.ScissorRectangle = lastScissorBox; + _graphicsDevice.RasterizerState = lastRasterizer; + _graphicsDevice.DepthStencilState = lastDepthStencil; + _graphicsDevice.BlendState = lastBlendState; + _graphicsDevice.BlendFactor = lastBlendFactor; + } + + private unsafe void UpdateBuffers(ImDrawDataPtr drawData) + { + if (drawData.TotalVtxCount == 0) + { + return; + } + + // Expand buffers if we need more room + if (drawData.TotalVtxCount > _vertexBufferSize) + { + _vertexBuffer?.Dispose(); + + _vertexBufferSize = (int)(drawData.TotalVtxCount * 1.5f); + _vertexBuffer = new VertexBuffer(_graphicsDevice, DrawVertDeclaration.Declaration, _vertexBufferSize, BufferUsage.None); + _vertexData = new byte[_vertexBufferSize * DrawVertDeclaration.Size]; + } + + if (drawData.TotalIdxCount > _indexBufferSize) + { + _indexBuffer?.Dispose(); + + _indexBufferSize = (int)(drawData.TotalIdxCount * 1.5f); + _indexBuffer = new IndexBuffer(_graphicsDevice, IndexElementSize.SixteenBits, _indexBufferSize, BufferUsage.None); + _indexData = new byte[_indexBufferSize * sizeof(ushort)]; + } + + // Copy ImGui's vertices and indices to a set of managed byte arrays + int vtxOffset = 0; + int idxOffset = 0; + + for (int n = 0; n < drawData.CmdListsCount; n++) + { + ImDrawListPtr cmdList = drawData.CmdLists[n]; + + fixed (void* vtxDstPtr = &_vertexData[vtxOffset * DrawVertDeclaration.Size]) + fixed (void* idxDstPtr = &_indexData[idxOffset * sizeof(ushort)]) + { + Buffer.MemoryCopy((void*)cmdList.VtxBuffer.Data, vtxDstPtr, _vertexData.Length, cmdList.VtxBuffer.Size * DrawVertDeclaration.Size); + Buffer.MemoryCopy((void*)cmdList.IdxBuffer.Data, idxDstPtr, _indexData.Length, cmdList.IdxBuffer.Size * sizeof(ushort)); + } + + vtxOffset += cmdList.VtxBuffer.Size; + idxOffset += cmdList.IdxBuffer.Size; + } + + // Copy the managed byte arrays to the gpu vertex- and index buffers + _vertexBuffer.SetData(_vertexData, 0, drawData.TotalVtxCount * DrawVertDeclaration.Size); + _indexBuffer.SetData(_indexData, 0, drawData.TotalIdxCount * sizeof(ushort)); + } + + private unsafe void RenderCommandLists(ImDrawDataPtr drawData) + { + _graphicsDevice.SetVertexBuffer(_vertexBuffer); + _graphicsDevice.Indices = _indexBuffer; + + int vtxOffset = 0; + int idxOffset = 0; + + for (int n = 0; n < drawData.CmdListsCount; n++) + { + ImDrawListPtr cmdList = drawData.CmdLists[n]; + + for (int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; cmdi++) + { + ImDrawCmdPtr drawCmd = cmdList.CmdBuffer[cmdi]; + + if (drawCmd.ElemCount == 0) + { + continue; + } + + if (!_loadedTextures.ContainsKey(drawCmd.TextureId)) + { + throw new InvalidOperationException($"Could not find a texture with id '{drawCmd.TextureId}', please check your bindings"); + } + + _graphicsDevice.ScissorRectangle = new Rectangle( + (int)drawCmd.ClipRect.X, + (int)drawCmd.ClipRect.Y, + (int)(drawCmd.ClipRect.Z - drawCmd.ClipRect.X), + (int)(drawCmd.ClipRect.W - drawCmd.ClipRect.Y) + ); + + var effect = UpdateEffect(_loadedTextures[drawCmd.TextureId]); + + foreach (var pass in effect.CurrentTechnique.Passes) + { + pass.Apply(); + +#pragma warning disable CS0618 // // FNA does not expose an alternative method. + _graphicsDevice.DrawIndexedPrimitives( + primitiveType: PrimitiveType.TriangleList, + baseVertex: (int)drawCmd.VtxOffset + vtxOffset, + minVertexIndex: 0, + numVertices: cmdList.VtxBuffer.Size, + startIndex: (int)drawCmd.IdxOffset + idxOffset, + primitiveCount: (int)drawCmd.ElemCount / 3 + ); +#pragma warning restore CS0618 + } + } + + vtxOffset += cmdList.VtxBuffer.Size; + idxOffset += cmdList.IdxBuffer.Size; + } + } + + #endregion Internals + } +} diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/IqWindow.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/IqWindow.cs new file mode 100644 index 0000000..7940649 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/IqWindow.cs @@ -0,0 +1,41 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace ImGuiNET.SampleProgram.XNA; + +public class IqWindow : TextureDisplayWindow +{ + public IqWindow(GraphicsDevice graphicsDevice, ImGuiRenderer renderer, string name = "IQ", bool closeable = false) + : base(renderer, new Texture2D(graphicsDevice,256,256), name, closeable) + { + sampleQueue = new Queue>(); + colorBuffer = new Color[256 * 256]; + zBuffer = new byte[256 * 256]; + _texture.GetData(colorBuffer); + Array.Fill(colorBuffer, Color.Transparent); + } + + private Queue> sampleQueue; + + public void EnqueueSample(byte i, byte q) + { + sampleQueue.Enqueue(new Tuple(i, q)); + } + + private byte[] zBuffer; + private Color[] colorBuffer; + public override void Update() + { + while (sampleQueue.Count > 0) + { + Tuple dequeue = sampleQueue.Dequeue(); + int offset = dequeue.Item2 * 256; + offset += dequeue.Item1; + byte z = zBuffer[offset]++; + colorBuffer[offset] = new Color(z, 0, 255 - z, 255); + } + + _texture.SetData(colorBuffer); + base.Update(); + } +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/RandomExtension.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/RandomExtension.cs new file mode 100644 index 0000000..e1200a1 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/RandomExtension.cs @@ -0,0 +1,9 @@ +namespace ImGuiNET.SampleProgram.XNA; + +public static class RandomExtension +{ + public static T NextItem(this Random rng, T[] array) + { + return array[rng.Next(array.Length)]; + } +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ScottPlotWindow.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ScottPlotWindow.cs new file mode 100644 index 0000000..f812ee8 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ScottPlotWindow.cs @@ -0,0 +1,62 @@ +using System.Runtime.InteropServices; +using Microsoft.Xna.Framework.Graphics; +using ScottPlot; +using SkiaSharp; + +namespace ImGuiNET.SampleProgram.XNA; + +public class ScottPlotWindow : TextureDisplayWindow +{ + public Plot Plot { get; private set; } + private SKImageInfo _imageInfo; + private SKBitmap _bitmap; + private SKCanvas _canvas; + + public ScottPlotWindow(ImGuiRenderer renderer, GraphicsDevice graphicsDevice, Plot plot, int width, int height, string name = null, bool closeable = false) + : base(renderer, new Texture2D(graphicsDevice,width,height), name, closeable) + { + if (renderer == null) + throw new ArgumentNullException(nameof(renderer)); + + if (graphicsDevice == null) + throw new ArgumentNullException(nameof(graphicsDevice)); + + if (plot == null) + throw new ArgumentNullException(nameof(plot)); + Plot = plot; + + _imageInfo = new SKImageInfo(width, height, GuessSKColorType(graphicsDevice)); + _bitmap = new SKBitmap(width, height); + _canvas = new SKCanvas(_bitmap); + } + + private SKColorType GuessSKColorType(GraphicsDevice graphicsDevice) + { + SurfaceFormat xnaSurfaceFormat = graphicsDevice.PresentationParameters.BackBufferFormat; + switch (xnaSurfaceFormat) + { + case SurfaceFormat.Color: + return SKColorType.Rgba8888; + default: + throw new NotImplementedException(xnaSurfaceFormat.ToString()); + } + } + + + + private byte[] buffer; + public override void Update() + { + Plot.Render(_canvas, _imageInfo.Width, _imageInfo.Height); + + IntPtr pixelPointer = _bitmap.GetPixels(); + int size = (_bitmap.Width * _bitmap.Height) * 4; + if (buffer == null) + buffer = new byte[size]; + Marshal.Copy(pixelPointer, buffer, 0, size); + + _texture.SetData(buffer); + + base.Update(); + } +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/TextureDisplayWindow.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/TextureDisplayWindow.cs new file mode 100644 index 0000000..9d3ba92 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/TextureDisplayWindow.cs @@ -0,0 +1,79 @@ +using System.Numerics; +using Microsoft.Xna.Framework.Graphics; +using ScottPlot.Plottables; + +namespace ImGuiNET.SampleProgram.XNA; + +public class TextureDisplayWindow : ImGuiRenderable +{ + protected Texture2D _texture; + protected string _name; + protected bool open; + private bool closeable; + protected ImGuiRenderer _renderer; + + public TextureDisplayWindow(ImGuiRenderer renderer, Texture2D texture, string name = null, bool closeable = false) + { + if (renderer == null) + throw new ArgumentNullException(nameof(renderer)); + _renderer = renderer; + + this._texture = texture; + this._name = name; + if (string.IsNullOrEmpty(name)) + { + this._name = texture.ToString(); + } + + this.open = true; + this.closeable = closeable; + } + + private bool bound; + private IntPtr _texturePointer; + protected System.Numerics.Vector2 windowSize; + public virtual void Update() + { + if (_texture == null) + return; + + if (!bound) + { + _texturePointer = _renderer.BindTexture(_texture); + windowSize = new Vector2(_texture.Width, _texture.Height); + bound = true; + } + } + + public void Render() + { + if (!bound) + return; + + ImGui.SetNextWindowSize(windowSize); + if (closeable) + ImGui.Begin(_name, ref open); + else + ImGui.Begin(_name); + + ImGui.Image(_texturePointer, windowSize); + + ImGui.End(); + } + + public bool WasClosed() + { + return !open; + } + + public void Dispose() + { + if (bound) + { + _renderer.UnbindTexture(_texturePointer); + bound = false; + } + + _texture.Dispose(); + } +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/Ziggurat.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/Ziggurat.cs new file mode 100644 index 0000000..9c4fc3a --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/Ziggurat.cs @@ -0,0 +1,186 @@ +namespace ConsoleApp1.Math; + +//This one is heavily inspired from https://github.com/colgreen/Redzen/blob/main/Redzen/Numerics/Distributions/Double/ZigguratGaussian.cs +//To understand how this algorithm works, please read those Github comments. +using System.Diagnostics; +using System.Runtime.CompilerServices; +public class Ziggurat +{ + const int __blockCount = 128; + const double __R = 3.442619855899; + const double __A = 9.91256303526217e-3; + const ulong __MAXINT = (1UL << 53) - 1; + const double __INCR = 1.0 / __MAXINT; + private double[] __x; + private double[] __y; + private ulong[] __xComp; + private double __A_Div_Y0; + private Random rng; + + public Ziggurat() + : this(null) + { + rng = new Random((int)DateTime.Now.Ticks); + } + + public Ziggurat(int seed) + : this(null) + { + rng = new Random(seed); + } + public Ziggurat(Random randomSrc) + { + this.rng = randomSrc; + // Initialise rectangle position data. + // __x[i] and __y[i] describe the top-right position of Box i. + + // Allocate storage. We add one to the length of _x so that we have an entry at __x[__blockCount], this avoids having + // to do a special case test when sampling from the top box. + __x = new double[__blockCount + 1]; + __y = new double[__blockCount]; + + // Determine top right position of the base rectangle/box (the rectangle with the Gaussian tale attached). + // We call this Box 0 or B0 for short. + // Note. x[0] also describes the right-hand edge of B1. (See diagram). + __x[0] = __R; + __y[0] = GaussianPdfDenorm(__R); + + // The next box (B1) has a right hand X edge the same as B0. + // Note. B1's height is the box area divided by its width, hence B1 has a smaller height than B0 because + // B0's total area includes the attached distribution tail. + __x[1] = __R; + __y[1] = __y[0] + (__A / __x[1]); + + // Calc positions of all remaining rectangles. + for(int i=2; i < __blockCount; i++) + { + __x[i] = GaussianPdfDenormInv(__y[i-1]); + __y[i] = __y[i-1] + (__A / __x[i]); + } + + // For completeness we define the right-hand edge of a notional box 6 as being zero (a box with no area). + __x[__blockCount] = 0.0; + + // Useful precomputed values. + __A_Div_Y0 = __A / __y[0]; + __xComp = new ulong[__blockCount]; + + // Special case for base box. __xComp[0] stores the area of B0 as a proportion of __R + // (recalling that all segments have area __A, but that the base segment is the combination of B0 and the distribution tail). + // Thus __xComp[0] is the probability that a sample point is within the box part of the segment. + __xComp[0] = (ulong)(((__R * __y[0]) / __A) * (double)__MAXINT); + + for(int i=1; i < __blockCount-1; i++) + { + __xComp[i] = (ulong)((__x[i+1] / __x[i]) * (double)__MAXINT); + } + __xComp[__blockCount-1] = 0; // Shown for completeness. + + // Sanity check. Test that the top edge of the topmost rectangle is at y=1.0. + // Note. We expect there to be a tiny drift away from 1.0 due to the inexactness of floating + // point arithmetic. + Debug.Assert(System.Math.Abs(1.0 - __y[__blockCount-1]) < 1e-10); + } + + private static double GaussianPdfDenorm(double x) + { + return System.Math.Exp(-(x * x * 0.5)); + } + + private static double GaussianPdfDenormInv(double y) + { + // Operates over the y interval (0,1], which happens to be the y interval of the pdf, + // with the exception that it does not include y=0, but we would never call with + // y=0 so it doesn't matter. Note that a Gaussian effectively has a tail going + // into infinity on the x-axis, hence asking what is x when y=0 is an invalid question + // in the context of this class. + return System.Math.Sqrt(-2.0 * System.Math.Log(y)); + } + + private void SampleTail(out double x) + { + double y; + do + { + // Note. we use NextDoubleNonZero() because Log(0) returns -Infinity and will also tend to be a very slow execution path (when it occurs, which is rarely). + x = -System.Math.Log(rng.NextDouble()) / __R; + y = -System.Math.Log(rng.NextDouble()); + } + while(y + y < x * x); + x += __R; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void SetSignBit(ref double x, ref ulong signBit) + { + Unsafe.As(ref x) |= signBit; + } + + public double Sample() + { + double x = 0.0; + while(true) + { + // Generate 64 random bits. + ulong u = (ulong)rng.NextInt64(); + + // Note. 61 random bits are required and therefore the lowest three bits are discarded + // (a typical characteristic of PRNGs is that the least significant bits exhibit lower + // quality randomness than the higher bits). + // Note. The bit index values in comments are zero based, i..e the first bit is bit 0. + // Select a segment (7 bits, bits 3 to 9). + int s = (int)((u >> 3) & 0x7f); + + // Select the sign bit (bit 10), and shift it to the sign bit position for IEEE754 + // double-precision floating-point format. + // Previously, the sign bit handling used a conditional branch that optionally multiplied the + // positive Gaussian sample by -1. However, that approach is considerably slower because modern + // superscalar CPUs rely heavily on branch prediction, but the sign bit here is randomly generated + // and therefore entirely unpredictable, i.e. the absolute worse case scenario for a branch + // predictor! + ulong signBit = (u & 0x400UL) << 53; + + // Get a uniform random value with interval [0, 2^53-1], or in hexadecimal [0, 0x1f_ffff_ffff_ffff] + // (i.e. a random 53 bit number) (bits 11 to 63). + ulong u2 = u >> 11; + + // Special case for the base segment. + if(s == 0) + { + if(u2 < __xComp[0]) + { + // Generated x is within R0. + x = u2 * __INCR * __A_Div_Y0; + } + else + { + // Generated x is in the tail of the distribution. + SampleTail(out x); + } + + SetSignBit(ref x, ref signBit); + return x; + } + + // All other segments. + if(u2 < __xComp[s]) + { + // Generated x is within the rectangle. + x = u2 * __INCR * __x[s]; + SetSignBit(ref x, ref signBit); + return x; + } + + // Generated x is outside of the rectangle. + // Generate a random y coordinate and test if our (x,y) is within the distribution curve. + // This execution path is relatively slow/expensive (makes a call to Math.Exp()) but is relatively rarely executed, + // although more often than the 'tail' path (above). + x = u2 * __INCR * __x[s]; + if(__y[s-1] + ((__y[s] - __y[s-1]) * rng.NextDouble()) < GaussianPdfDenorm(x)) + { + SetSignBit(ref x, ref signBit); + return x; + } + } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ZigguratStream.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ZigguratStream.cs new file mode 100644 index 0000000..787613d --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ZigguratStream.cs @@ -0,0 +1,83 @@ +using System.Diagnostics; +using ConsoleApp1.Math; + +namespace ConsoleApp1.IO; + +public class ZigguratStream : Stream +{ + public ZigguratStream() + { + _ziggurat = new Ziggurat(); + } + + public ZigguratStream(int seed) + { + _ziggurat = new Ziggurat(seed); + } + + public ZigguratStream(Random random) + { + _ziggurat = new Ziggurat(random); + } + + private Ziggurat _ziggurat; + private double minZig, maxZig; + private byte getNextByte() + { + double sample = _ziggurat.Sample(); + double oldMin = minZig; + double oldMax = maxZig; + minZig = System.Math.Min(minZig, sample); + maxZig = System.Math.Max(maxZig, sample); + if (oldMin != minZig || oldMax != maxZig) + { + return getNextByte(); + } + + sample += (minZig / -1.0); + double span = (minZig / -1.0) + maxZig; + double sampleScaled = sample / span; + Debug.Assert(sampleScaled <= 1.0); + sampleScaled *= 255.0; + byte scaledByte = (byte)sampleScaled; + + return scaledByte; + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + private long internalPosition; + public override int Read(byte[] buffer, int offset, int count) + { + for (int i = 0; i < count; i++) + { + buffer[offset + i] = getNextByte(); + internalPosition++; + } + return count; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override bool CanRead => true; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length => throw new NotSupportedException(); + public override long Position { get => internalPosition; set => throw new NotSupportedException(); } +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/skyscraper8.UI.ImGui.MonoGame.Bridge.csproj b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/skyscraper8.UI.ImGui.MonoGame.Bridge.csproj new file mode 100644 index 0000000..4648290 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/skyscraper8.UI.ImGui.MonoGame.Bridge.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + x64 + True + + + + + + + + + diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame/Program.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame/Program.cs new file mode 100644 index 0000000..a851edb --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame/Program.cs @@ -0,0 +1,13 @@ +using skyscraper8.UI.ImGui.MonoGame; + +namespace moe.yo3explorer.skyscraper8.UI.MonoGame +{ + class Program + { + public static void Main(string[] args) + { + SkyscraperGame game = new SkyscraperGame(); + game.Run(); + } + } +} \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/0_Blank.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/0_Blank.cs new file mode 100644 index 0000000..1e64dfd --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/0_Blank.cs @@ -0,0 +1,32 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper5.Skyscraper.Plugins; + +namespace skyscraper8.UI.ImGui.MonoGame.Screenhacks +{ + [PluginPriority(0)] + [DisplayName("Blank")] + internal class _0_Blank : IScreenhack + { + public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Rectangle windowBounds) + { + + } + + public void SetGraphicsDevice(GraphicsDevice graphicsDevice, Rectangle presentationParametersBounds) + { + + } + + public void Dispose() + { + + } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/1_YourWaifu.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/1_YourWaifu.cs new file mode 100644 index 0000000..be14392 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/1_YourWaifu.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using System.Threading.Tasks; +using ImGuiNET.SampleProgram.XNA; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using skyscraper5.Skyscraper.Plugins; + +namespace skyscraper8.UI.ImGui.MonoGame.Screenhacks +{ + [PluginPriority(1)] + [DisplayName("Your Waifu")] + internal class _1_YourWaifu : IScreenhack + { + private bool disabled; + private FileInfo fileInfo; + public _1_YourWaifu() + { + DirectoryInfo di = new DirectoryInfo("wallpapers"); + if (!di.Exists) + { + disabled = true; + return; + } + + FileInfo[] files = di.GetFiles("*.png"); + fileInfo = new Random().NextItem(files); + } + + public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Rectangle windowBounds) + { + if (disabled) + return; + if (texture2D == null) + return; + + spriteBatch.Draw(texture2D, windowBounds, Color.White); + } + + private Texture2D texture2D; + public void SetGraphicsDevice(GraphicsDevice graphicsDevice, Rectangle presentationParametersBounds) + { + if (disabled) + return; + + texture2D = Texture2D.FromFile(graphicsDevice, fileInfo.FullName); + } + + public void Dispose() + { + texture2D.Dispose(); + } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/2_Substrate.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/2_Substrate.cs new file mode 100644 index 0000000..1784512 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/2_Substrate.cs @@ -0,0 +1,372 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using skyscraper5.Skyscraper.Plugins; +using Color = System.Drawing.Color; + +namespace skyscraper8.UI.ImGui.MonoGame.Screenhacks +{ + [PluginPriority(2)] + [DisplayName("Substrate")] + internal class _2_Substrate : Processing, IScreenhack + { + int dimx = 250; + int dimy = 250; + int num = 0; + int maxnum = 100; + + // grid of cracks + int[] cgrid; + Crack[] cracks; + + // color parameters + int maxpal = 512; + int numpal = 0; + private Color[] goodcolor; + + // sand painters + SandPainter[] sands; + + private void Begin() + { + // erase crack grid + for (int y = 0; y < dimy; y++) + { + for (int x = 0; x < dimx; x++) + { + cgrid[y * dimx + x] = 10001; + } + } + + // make random crack seeds + for (int k = 0; k < 16; k++) + { + int i = (Random(dimx * dimy - 1)); + cgrid[i] = (Random(360)); + } + + // make just three cracks + num = 0; + for (int k = 0; k < 3; k++) + { + MakeCrack(); + } + //Background(Color.FromArgb(255, 255, 255, 255)); + } + + private void MakeCrack() + { + if (num < maxnum) + { + // make a new crack instance + cracks[num] = new Crack(this); + num++; + } + } + + private void TakeColor() + { + uint[] srcArrays = + { + 0x201F21, 0x262C2E, 0x352626, 0x372B27, + 0x302C2E, 0x392B2D, 0x323229, 0x3F3229, + 0x38322E, 0x2E333D, 0x333A3D, 0x473329, + 0x40392C, 0x40392E, 0x47402C, 0x47402E, + 0x4E402C, 0x4F402E, 0x4E4738, 0x584037, + 0x65472D, 0x6D5D3D, 0x745530, 0x755532, + 0x745D32, 0x746433, 0x7C6C36, 0x523152, + 0x444842, 0x4C5647, 0x655D45, 0x6D5D44, + 0x6C5D4E, 0x746C43, 0x7C6C42, 0x7C6C4B, + 0x6B734B, 0x73734B, 0x7B7B4A, 0x6B6C55, + 0x696D5E, 0x7B6C5D, 0x6B7353, 0x6A745D, + 0x727B52, 0x7B7B52, 0x57746E, 0x687466, + 0x9C542B, 0x9D5432, 0x9D5B35, 0x936B36, + 0xAA7330, 0xC45A27, 0xD95223, 0xD85A20, + 0xDB5A23, 0xE57037, 0x836C4B, 0x8C6B4B, + 0x82735C, 0x937352, 0x817B63, 0x817B6D, + 0x927B63, 0xD9893B, 0xE49832, 0xDFA133, + 0xE5A037, 0xF0AB3B, 0x8A8A59, 0xB29A58, + 0x89826B, 0x9A8262, 0x888B7C, 0x909A7A, + 0xA28262, 0xA18A69, 0xA99968, 0x99A160, + 0x99A168, 0xCA8148, 0xEB8D43, 0xC29160, + 0xC29168, 0xD1A977, 0xC9B97F, 0xF0E27B, + 0x9F928B, 0xC0B999, 0xE6B88F, 0xC8C187, + 0xE0C886, 0xF2CC85, 0xF5DA83, 0xECDE9D, + 0xF5D294, 0xF5DA94, 0xF4E784, 0xF4E18A, + 0xF4E193, 0xE7D8A7, 0xF1D4A5, 0xF1DCA5, + 0xF4DBAD, 0xF1DCAE, 0xF4DBB5, 0xF5DBBD, + 0xF4E2AD, 0xF5E9AD, 0xF4E3BE, 0xF5EABE, + 0xF7F0B6, 0xD9D1C1, 0xE0D0C0, 0xE7D8C0, + 0xF1DDC6, 0xE8E1C0, 0xF3EDC7, 0xF6ECCE, + 0xF8F2C7, 0xEFEFD0, 0 + }; + for (int i = 0; i < srcArrays.Length; i++) + { + srcArrays[i] |= 0xff000000; + goodcolor[i] = Color.FromArgb((int)srcArrays[i]); + } + + numpal = srcArrays.Length; + } + + class Crack + { + private readonly _2_Substrate _parent; + private float x, y, t; + private SandPainter sp; + + public Crack(_2_Substrate parent) + { + _parent = parent; + FindStart(); + sp = new SandPainter(_parent); + } + + private void FindStart() + { + // pick random point + int px = 0; + int py = 0; + + // shift until crack is found + bool found = false; + int timeout = 0; + while ((!found) || (timeout++ > 1000)) + { + px = (_parent.Random(_parent.dimx)); + py = (_parent.Random(_parent.dimy)); + if (_parent.cgrid[py * _parent.dimx + px] < 10000) + { + found = true; + } + } + + if (found) + { + // start crack + int a = _parent.cgrid[py * _parent.dimx + px]; + if (_parent.Random(100) < 50) + { + a -= 90 + (int)(_parent.Random(-2.0f, 2.1f)); + } + else + { + a += 90 + (int)(_parent.Random(-2.0f, 2.1f)); + } + + StartCrack(px, py, a); + } + else + { + //println("timeout: "+timeout); + } + } + + private void StartCrack(int X, int Y, int T) + { + x = X; + y = Y; + t = T; //%360; + x += 0.61f * (float)Math.Cos(t * Math.PI / 180.0); + y += 0.61f * (float)Math.Sin(t * Math.PI / 180.0); + } + + public void Move() + { + // continue cracking + x += 0.42f * (float)Math.Cos(t * Math.PI / 180); + y += 0.42f * (float)Math.Sin(t * Math.PI / 180); + + // bound check + float z = 0.33f; + int cx = (int)(x + _parent.Random(-z, z)); // add fuzz + int cy = (int)(y + _parent.Random(-z, z)); + + // draw sand painter + RegionColor(); + + // draw black crack + _parent.Stroke(0.0f, 85.0f); + _parent.Point(x + _parent.Random(-z, z), y + _parent.Random(-z, z)); + + + if ((cx >= 0) && (cx < _parent.dimx) && (cy >= 0) && (cy < _parent.dimy)) + { + // safe to check + if ((_parent.cgrid[cy * _parent.dimx + cx] > 10000) || + (Math.Abs(_parent.cgrid[cy * _parent.dimx + cx] - t) < 5)) + { + // continue cracking + _parent.cgrid[cy * _parent.dimx + cx] = (int)(t); + } + else if (Math.Abs(_parent.cgrid[cy * _parent.dimx + cx] - t) > 2) + { + // crack encountered (not self), stop cracking + FindStart(); + _parent.MakeCrack(); + } + } + else + { + // out of bounds, stop cracking + FindStart(); + _parent.MakeCrack(); + } + } + + private void RegionColor() + { + // start checking one step away + float rx = x; + float ry = y; + bool openspace = true; + + // find extents of open space + while (openspace) + { + // move perpendicular to crack + rx += 0.81f * (float)Math.Sin(t * Math.PI / 180.0); + ry -= 0.81f * (float)Math.Cos(t * Math.PI / 180.0); + int cx = (int)(rx); + int cy = (int)(ry); + if ((cx >= 0) && (cx < _parent.dimx) && (cy >= 0) && (cy < _parent.dimy)) + { + // safe to check + if (_parent.cgrid[cy * _parent.dimx + cx] > 10000) + { + // space is open + } + else + { + openspace = false; + } + } + else + { + openspace = false; + } + } + + // draw sand painter + sp.Render(rx, ry, x, y); + } + } + + class SandPainter + { + private readonly _2_Substrate _parent; + + public SandPainter(_2_Substrate _parent) + { + this._parent = _parent; + c = _parent.SomeColor(); + g = _parent.Random(0.01f, 0.1f); + } + + private Color c; + private float g; + + public void Render(float x, float y, float ox, float oy) + { + // modulate gain + g += _parent.Random(-0.050f, 0.050f); + float maxg = 1.0f; + if (g < 0) g = 0; + if (g > maxg) g = maxg; + + // calculate grains by distance + //int grains = (int)(Math.Sqrt((ox-x)*(ox-x)+(oy-y)*(oy-y))); + int grains = 64; + + // lay down grains of sand (transparent pixels) + float w = g / (grains - 1); + for (int i = 0; i < grains; i++) + { + float a = 0.1f - i / (grains * 10.0f); + _parent.Stroke(c.R, c.G, c.B, a * 256); + _parent.Point(ox + (x - ox) * (float)Math.Sin(Math.Sin(i * w)), + oy + (y - oy) * (float)Math.Sin(Math.Sin(i * w))); + } + } + } + + private Color SomeColor() + { + if (rng == null) + rng = new Random(); + return goodcolor[rng.Next(numpal)]; + } + + public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Rectangle windowBounds) + { + for (int n = 0; n < num; n++) + { + cracks[n].Move(); + } + + texture.SetData(textureColors); + + spriteBatch.Draw(texture, windowBounds, Microsoft.Xna.Framework.Color.White); + } + + private Texture2D texture; + private Microsoft.Xna.Framework.Color[] textureColors; + private int screenWidth, screenHeight; + + public void SetGraphicsDevice(GraphicsDevice graphicsDevice, Rectangle presentationParametersBounds) + { + screenWidth = presentationParametersBounds.Width; + screenHeight = presentationParametersBounds.Height; + + texture = new Texture2D(graphicsDevice, presentationParametersBounds.Width, + presentationParametersBounds.Height); + textureColors = + new Microsoft.Xna.Framework.Color[presentationParametersBounds.Width * + presentationParametersBounds.Height]; + texture.GetData(textureColors); + for (int i = 0; i < textureColors.Length; i++) + { + textureColors[i] = Microsoft.Xna.Framework.Color.White; + } + + goodcolor = new Color[maxpal]; + //Background(Color.FromArgb(255, 255, 255, 255)); + TakeColor(); + + dimx = presentationParametersBounds.Width; + dimy = presentationParametersBounds.Height; + cgrid = new int[dimx * dimy]; + cracks = new Crack[maxnum]; + + Begin(); + } + + public void Dispose() + { + } + + protected override void Point(float x, float y) + { + int ix = (int)x; + int iy = (int)y; + if (y < 0) + return; + if (y >= screenHeight) + return; + if (x < 0) + return; + if (x > screenWidth) + return; + + textureColors[(iy * screenWidth) + ix].A = strokeColorObject.A; + textureColors[(iy * screenWidth) + ix].R = strokeColorObject.R; + textureColors[(iy * screenWidth) + ix].G = strokeColorObject.G; + textureColors[(iy * screenWidth) + ix].B = strokeColorObject.B; + } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/IScreenhack.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/IScreenhack.cs new file mode 100644 index 0000000..37334dd --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/IScreenhack.cs @@ -0,0 +1,17 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.UI.ImGui.MonoGame.Screenhacks +{ + internal interface IScreenhack : IDisposable + { + void Draw(GameTime gameTime, SpriteBatch spriteBatch, Rectangle windowBounds); + + void SetGraphicsDevice(GraphicsDevice graphicsDevice, Rectangle presentationParametersBounds); + } +} diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/Processing.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/Processing.cs new file mode 100644 index 0000000..011bdce --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/Processing.cs @@ -0,0 +1,193 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.UI.ImGui.MonoGame.Screenhacks +{ + internal abstract class Processing + { + protected Random rng; + protected int Random(int max) + { + if (rng == null) + rng = new Random(); + return rng.Next(max); + } + + protected float Random(float min, float max) + { + if (min >= max) + return min; + float diff = max - min; + return Random(diff) + min; + } + + protected float Random(float max) + { + if (rng == null) + rng = new Random(); + if (max == 0.0F) + return 0.0F; + + float f = 0.0F; + while (true) + { + f = rng.NextSingle() * max; + if (f != max) + return f; + } + } + + private bool stroke; + private float strokeR, strokeG, strokeB, strokeA; + private int strokeRi, strokeGi, strokeBi, strokeAi; + private int strokeColor; + private bool strokeAlpha; + protected void Stroke(float paramFloat1, float paramFloat2) + { + ColorCalc(paramFloat1, paramFloat2); + ColorStroke(); + } + + private void ColorStroke() + { + this.stroke = true; + this.strokeR = this.calcR; + this.strokeG = this.calcG; + this.strokeB = this.calcB; + this.strokeA = this.calcA; + this.strokeRi = this.calcRi; + this.strokeGi = this.calcGi; + this.strokeBi = this.calcBi; + this.strokeAi = this.calcAi; + this.strokeColor = this.calcColor; + this.strokeAlpha = this.calcAlpha; + this.strokeColorObject = new Color(); + this.strokeColorObject.A = (byte)this.strokeAi; + this.strokeColorObject.R = (byte)this.strokeRi; + this.strokeColorObject.G = (byte)this.strokeGi; + this.strokeColorObject.B = (byte)this.strokeBi; + } + + + private float colorModeX, colorModeA, calcR, calcG, calcB, calcA; + + private bool colorScale; + + private int calcRi, calcGi, calcBi, calcAi, calcColor; + + private bool calcAlpha; + protected Color strokeColorObject; + + protected int colorMode = 1; + private float colorModeY, colorModeZ; + protected void ColorCalc(float paramFloat1, float paramFloat2) + { + this.calcR = this.colorScale ? (paramFloat1 / this.colorModeX) : paramFloat1; + this.calcG = this.calcR; + this.calcB = this.calcR; + this.calcA = this.colorScale ? (paramFloat2 / this.colorModeA) : paramFloat2; + this.calcRi = (int)(this.calcR); + this.calcGi = (int)(this.calcG); + this.calcBi = (int)(this.calcB); + this.calcAi = (int)(this.calcA); + this.calcColor = this.calcAi << 24 | this.calcRi << 16 | this.calcGi << 8 | this.calcBi; + if (this.calcAi != 255) + this.calcAlpha = false; + this.calcAlpha = true; + } + + protected void Stroke(float r, float g, float b, float a) + { + ColorCalc(r, g, b, a); + ColorStroke(); + } + + protected void ColorCalc(float paramFloat1, float paramFloat2, float paramFloat3, float paramFloat4) + { + float f1, f2, f3, f4, f5; + + switch (this.colorMode) + { + case 1: + if (this.colorScale) + { + this.calcR = paramFloat1 / this.colorModeX; + this.calcG = paramFloat2 / this.colorModeY; + this.calcB = paramFloat3 / this.colorModeZ; + this.calcA = paramFloat4 / this.colorModeA; + break; + } + this.calcR = paramFloat1; + this.calcG = paramFloat2; + this.calcB = paramFloat3; + this.calcA = paramFloat4; + break; + case 3: + paramFloat1 /= this.colorModeX; + paramFloat2 /= this.colorModeY; + paramFloat3 /= this.colorModeZ; + this.calcA = this.colorScale ? (paramFloat4 / this.colorModeA) : paramFloat4; + if (paramFloat2 == 0.0F) + { + this.calcR = this.calcG = this.calcB = paramFloat3; + break; + } + f1 = (paramFloat1 - (int)paramFloat1) * 6.0F; + f2 = f1 - (int)f1; + f3 = paramFloat3 * (1.0F - paramFloat2); + f4 = paramFloat3 * (1.0F - paramFloat2 * f2); + f5 = paramFloat3 * (1.0F - paramFloat2 * (1.0F - f2)); + switch ((int)f1) + { + case 0: + this.calcR = paramFloat3; + this.calcG = f5; + this.calcB = f3; + break; + case 1: + this.calcR = f4; + this.calcG = paramFloat3; + this.calcB = f3; + break; + case 2: + this.calcR = f3; + this.calcG = paramFloat3; + this.calcB = f5; + break; + case 3: + this.calcR = f3; + this.calcG = f4; + this.calcB = paramFloat3; + break; + case 4: + this.calcR = f5; + this.calcG = f3; + this.calcB = paramFloat3; + break; + case 5: + this.calcR = paramFloat3; + this.calcG = f3; + this.calcB = f4; + break; + } + break; + } + this.calcRi = (int)(1.0f * this.calcR); + this.calcGi = (int)(1.0f * this.calcG); + this.calcBi = (int)(1.0f * this.calcB); + this.calcAi = (int)(1.0f * this.calcA); + this.calcColor = this.calcAi << 24 | this.calcRi << 16 | this.calcGi << 8 | this.calcBi; + if (this.calcAi != 255) + this.calcAlpha = false; + this.calcAlpha = true; + } + + + protected abstract void Point(float x, float y); + } +} diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/ScreenhackException.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/ScreenhackException.cs new file mode 100644 index 0000000..60cbb29 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/ScreenhackException.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.UI.ImGui.MonoGame.Screenhacks +{ + public class ScreenhackException : Exception + { + public ScreenhackException() + { + } + + public ScreenhackException(string message) : base(message) + { + } + + public ScreenhackException(string message, Exception inner) : base(message, inner) + { + } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/ScreenhackManager.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/ScreenhackManager.cs new file mode 100644 index 0000000..b71e422 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/ScreenhackManager.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using ImGuiNET.SampleProgram.XNA; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using skyscraper5.Skyscraper.Plugins; + +namespace skyscraper8.UI.ImGui.MonoGame.Screenhacks +{ + internal class ScreenhackManager : GameObject + { + private Dictionary knownScreenhacks; + + public ScreenhackManager() + { + knownScreenhacks = new Dictionary(); + Assembly assembly = GetType().Assembly; + Type screenhackBaseType = typeof(IScreenhack); + Type pluginPriorityTYpe = typeof(PluginPriorityAttribute); + Type[] types = assembly.GetTypes(); + foreach (Type type in types) + { + if (!type.IsAssignableTo(screenhackBaseType)) + continue; + if (type.IsInterface) + continue; + ConstructorInfo constructor = type.GetConstructor(new Type[] { }); + Attribute attribute = type.GetCustomAttributes(pluginPriorityTYpe).FirstOrDefault(); + if (attribute == null) + { + throw new ScreenhackException(String.Format("{0} is missing the {1} attribute.", type.Name, nameof(PluginPriorityAttribute))); + } + + PluginPriorityAttribute ppa = (PluginPriorityAttribute)attribute; + knownScreenhacks.Add(ppa.Priority, constructor); + } + } + + private IScreenhack currentScreenhack; + private int currentScreenhackId; + + public int WantedScreenhackId { get; set; } + + + public void Update(GameTime gameTime, GraphicsDevice graphicsDevice) + { + if (currentScreenhack == null || currentScreenhackId != WantedScreenhackId) + { + ConstructorInfo constructorInfo = knownScreenhacks[WantedScreenhackId]; + object invoke = constructorInfo.Invoke(new object[] { }); + currentScreenhack = (IScreenhack)invoke; + currentScreenhack.SetGraphicsDevice(graphicsDevice,graphicsDevice.PresentationParameters.Bounds); + currentScreenhackId = WantedScreenhackId; + } + } + + public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Rectangle windowBounds) + { + currentScreenhack.Draw(gameTime, spriteBatch, windowBounds); + } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame/SkyscraperGame.cs b/GUIs/skyscraper8.UI.ImGui.MonoGame/SkyscraperGame.cs new file mode 100644 index 0000000..4cabe3d --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame/SkyscraperGame.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ImGuiNET; +using ImGuiNET.SampleProgram.XNA; +using Microsoft.Xna.Framework; +using skyscraper8.UI.ImGui.MonoGame.Screenhacks; + +namespace moe.yo3explorer.skyscraper8.UI.MonoGame +{ + internal class SkyscraperGame : BaseGame + { + private ScreenhackManager screenhackManager; + protected override void LoadContent() + { + screenhackManager = new ScreenhackManager(); + screenhackManager.WantedScreenhackId = 1; + _gameObjects.Add(screenhackManager); + base.LoadContent(); + } + + protected override void Draw(GameTime gameTime) + { + GraphicsDevice.Clear(Color.White); + + base.Draw(gameTime); + } + + protected override void ImGuiLayout() + { + ImGui.BeginMainMenuBar(); + if (ImGui.BeginMenu("Jobs")) + { + if (ImGui.MenuItem("Quit")) + { + Exit(); + } + ImGui.EndMenu(); + } + ImGui.EndMainMenuBar(); + + base.ImGuiLayout(); + } + } +} diff --git a/GUIs/skyscraper8.UI.ImGui.MonoGame/skyscraper8.UI.ImGui.MonoGame.csproj b/GUIs/skyscraper8.UI.ImGui.MonoGame/skyscraper8.UI.ImGui.MonoGame.csproj new file mode 100644 index 0000000..506f2e9 --- /dev/null +++ b/GUIs/skyscraper8.UI.ImGui.MonoGame/skyscraper8.UI.ImGui.MonoGame.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + diff --git a/GUIs/skyscraper8.UI.ImGui/Program.cs b/GUIs/skyscraper8.UI.ImGui/Program.cs index 7839f4e..60405ed 100644 --- a/GUIs/skyscraper8.UI.ImGui/Program.cs +++ b/GUIs/skyscraper8.UI.ImGui/Program.cs @@ -464,7 +464,7 @@ namespace SkyscraperUI if (showMainMenu) { - ImGui.BeginMainMenuBar(); + ImGui.BeginMainMenuBar(); if (ImGui.BeginMenu("Jobs")) { if (ImGui.MenuItem("Connect to TCP/IP Stream", CanScrapeFromTcpIp())) diff --git a/GUIs/skyscraper8.UI.ImGui/skyscraper8.UI.ImGui.csproj b/GUIs/skyscraper8.UI.ImGui/skyscraper8.UI.ImGui.SDL2.csproj similarity index 100% rename from GUIs/skyscraper8.UI.ImGui/skyscraper8.UI.ImGui.csproj rename to GUIs/skyscraper8.UI.ImGui/skyscraper8.UI.ImGui.SDL2.csproj diff --git a/skyscraper8.sln b/skyscraper8.sln index 5980047..4770684 100644 --- a/skyscraper8.sln +++ b/skyscraper8.sln @@ -57,12 +57,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UIs", "UIs", "{E23457C5-3A3 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper5.UI.WindowsForms", "GUIs\skyscraper5.UI\skyscraper5.UI.WindowsForms.csproj", "{46CACA1C-F9B2-2FE0-2068-716F381325E9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.UI.ImGui", "GUIs\skyscraper8.UI.ImGui\skyscraper8.UI.ImGui.csproj", "{BDBDB7A9-D0A4-9B89-0801-2935B2066551}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.UI.ImGui.SDL2", "GUIs\skyscraper8.UI.ImGui\skyscraper8.UI.ImGui.SDL2.csproj", "{BDBDB7A9-D0A4-9B89-0801-2935B2066551}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.EPGCollectorPort", "PrivateDataSpecifiers\skyscraper8.EPGCollectorPort\skyscraper8.EPGCollectorPort.csproj", "{CF21D250-9804-4191-89F5-95821E3AF39D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.AnagramViewer", "GUIs\skyscraper8.AnagramViewer\skyscraper8.AnagramViewer.csproj", "{EBB6B1CF-2597-4962-AA31-2B42B4C28C7D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.UI.ImGui.MonoGame", "GUIs\skyscraper8.UI.ImGui.MonoGame\skyscraper8.UI.ImGui.MonoGame.csproj", "{839C3783-020F-77D6-C22C-D50DCC97CDD6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.UI.ImGui.MonoGame.Bridge", "GUIs\skyscraper8.UI.ImGui.MonoGame.Bridge\skyscraper8.UI.ImGui.MonoGame.Bridge.csproj", "{1A29F6E6-4B6A-DCCD-1DF1-AA8D020E17D2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -157,6 +161,14 @@ Global {EBB6B1CF-2597-4962-AA31-2B42B4C28C7D}.Debug|Any CPU.Build.0 = Debug|Any CPU {EBB6B1CF-2597-4962-AA31-2B42B4C28C7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {EBB6B1CF-2597-4962-AA31-2B42B4C28C7D}.Release|Any CPU.Build.0 = Release|Any CPU + {839C3783-020F-77D6-C22C-D50DCC97CDD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {839C3783-020F-77D6-C22C-D50DCC97CDD6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {839C3783-020F-77D6-C22C-D50DCC97CDD6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {839C3783-020F-77D6-C22C-D50DCC97CDD6}.Release|Any CPU.Build.0 = Release|Any CPU + {1A29F6E6-4B6A-DCCD-1DF1-AA8D020E17D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A29F6E6-4B6A-DCCD-1DF1-AA8D020E17D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A29F6E6-4B6A-DCCD-1DF1-AA8D020E17D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A29F6E6-4B6A-DCCD-1DF1-AA8D020E17D2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -182,6 +194,8 @@ Global {BDBDB7A9-D0A4-9B89-0801-2935B2066551} = {E23457C5-3A34-48EE-8107-C91E2C174B2D} {CF21D250-9804-4191-89F5-95821E3AF39D} = {56729C39-B90E-4DF3-A557-DB93436FB5FF} {EBB6B1CF-2597-4962-AA31-2B42B4C28C7D} = {E23457C5-3A34-48EE-8107-C91E2C174B2D} + {839C3783-020F-77D6-C22C-D50DCC97CDD6} = {E23457C5-3A34-48EE-8107-C91E2C174B2D} + {1A29F6E6-4B6A-DCCD-1DF1-AA8D020E17D2} = {E23457C5-3A34-48EE-8107-C91E2C174B2D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5147EFA3-3D4E-4FDE-8A36-5840E8F1B80E} diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs index 5776a74..b2d8dbf 100644 --- a/skyscraper8/Program.cs +++ b/skyscraper8/Program.cs @@ -12,28 +12,20 @@ using skyscraper5.Skyscraper.Plugins; using skyscraper5.Skyscraper.RecordingImporter; using skyscraper5.Skyscraper.Scraper; using skyscraper5.Skyscraper.Scraper.FrameGrabber; -using skyscraper5.Skyscraper.Scraper.Storage; using skyscraper5.Skyscraper.Scraper.Storage.Filesystem; using skyscraper5.Skyscraper.Scraper.Storage.InMemory; -using skyscraper5.Skyscraper.Scraper.StreamAutodetection; using skyscraper5.Skyscraper.Webserver; using skyscraper5.src.Aac; using skyscraper5.src.Mpeg2.PacketFilter; -using skyscraper5.src.Skyscraper.FrequencyListGenerator; using skyscraper5.T2MI; using skyscraper8.Skyscraper.IO; using skyscraper8.Skyscraper.Scraper.Storage; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Configuration; using System.Diagnostics; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Runtime.InteropServices; -using skyscraper5.Dvb.Descriptors; -using skyscraper8.Skyscraper.Drawing; +using skyscraper5.Skyscraper.Scraper.StreamAutodetection; [assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config")] namespace skyscraper5 @@ -43,6 +35,12 @@ namespace skyscraper5 private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); private static void IntegrationTest() { + FileStream fileStream = File.OpenRead("C:\\Temp\\ule-iww.ts"); + TsContext tesContext = new TsContext(); + SkyscraperContext skyscraperContext = new SkyscraperContext(tesContext, new InMemoryScraperStorage(), new NullObjectStorage()); + skyscraperContext.InitalizeFilterChain(); + tesContext.RegisterPacketProcessor(0x666, new StreamTypeAutodetection(0x666, skyscraperContext)); + skyscraperContext.IngestFromStream(fileStream); } static void Main(string[] args)