Built a MonoGame skeleton.
This commit is contained in:
parent
16b5682fd4
commit
5fdd55f732
6
.gitignore
vendored
6
.gitignore
vendored
@ -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
|
||||
|
||||
120
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/BaseGame.cs
Normal file
120
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/BaseGame.cs
Normal file
@ -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<ImGuiRenderable>();
|
||||
_graphicsDevice = _graphics.GraphicsDevice;
|
||||
_spriteBatch = new SpriteBatch(GraphicsDevice);
|
||||
_gameObjects = new List<GameObject>();
|
||||
Window.AllowUserResizing = false;
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
|
||||
protected List<GameObject> _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<ImGuiRenderable> _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);
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
10
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/GameObject.cs
Normal file
10
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/GameObject.cs
Normal file
@ -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);
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
namespace ImGuiNET.SampleProgram.XNA;
|
||||
|
||||
public interface ImGuiRenderable : IDisposable
|
||||
{
|
||||
void Update();
|
||||
void Render();
|
||||
|
||||
bool WasClosed();
|
||||
}
|
||||
443
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ImGuiRenderer.cs
Normal file
443
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ImGuiRenderer.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// ImGui renderer for use with XNA-likes (FNA & MonoGame)
|
||||
/// </summary>
|
||||
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<IntPtr, Texture2D> _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<Keys>();
|
||||
|
||||
public ImGuiRenderer(Game game)
|
||||
{
|
||||
var context = ImGui.CreateContext();
|
||||
ImGui.SetCurrentContext(context);
|
||||
|
||||
_game = game ?? throw new ArgumentNullException(nameof(game));
|
||||
_graphicsDevice = game.GraphicsDevice;
|
||||
|
||||
_loadedTextures = new Dictionary<IntPtr, Texture2D>();
|
||||
|
||||
_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;
|
||||
/// <summary>
|
||||
/// Creates a texture and loads the font data from ImGui. Should be called when the <see cref="GraphicsDevice" /> is initialized but before any rendering is done
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a pointer to a texture, which can be passed through ImGui calls such as <see cref="ImGui.Image" />. That pointer is then used by ImGui to let us know what texture to draw
|
||||
/// </summary>
|
||||
public virtual IntPtr BindTexture(Texture2D texture)
|
||||
{
|
||||
var id = new IntPtr(_textureId++);
|
||||
|
||||
_loadedTextures.Add(id, texture);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a previously created texture pointer, releasing its reference and allowing it to be deallocated
|
||||
/// </summary>
|
||||
public virtual void UnbindTexture(IntPtr textureId)
|
||||
{
|
||||
_loadedTextures.Remove(textureId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up ImGui for a new frame, should be called at frame start
|
||||
/// </summary>
|
||||
public virtual void BeforeLayout(GameTime gameTime)
|
||||
{
|
||||
ImGui.GetIO().DeltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
|
||||
|
||||
UpdateInput();
|
||||
|
||||
|
||||
ImGui.NewFrame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
public virtual void AfterLayout()
|
||||
{
|
||||
ImGui.Render();
|
||||
|
||||
unsafe { RenderDrawData(ImGui.GetDrawData()); }
|
||||
}
|
||||
|
||||
#endregion ImGuiRenderer
|
||||
|
||||
#region Setup & Update
|
||||
|
||||
/// <summary>
|
||||
/// Setup key input event handler.
|
||||
/// </summary>
|
||||
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);
|
||||
//};
|
||||
///////////////////////////////////////////
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the <see cref="Effect" /> to the current matrices and texture
|
||||
/// </summary>
|
||||
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; }
|
||||
/// <summary>
|
||||
/// Sends XNA input state to ImGui
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Gets the geometry as set up by ImGui and sends it to the graphics device
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
41
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/IqWindow.cs
Normal file
41
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/IqWindow.cs
Normal file
@ -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<Tuple<byte, byte>>();
|
||||
colorBuffer = new Color[256 * 256];
|
||||
zBuffer = new byte[256 * 256];
|
||||
_texture.GetData(colorBuffer);
|
||||
Array.Fill(colorBuffer, Color.Transparent);
|
||||
}
|
||||
|
||||
private Queue<Tuple<byte, byte>> sampleQueue;
|
||||
|
||||
public void EnqueueSample(byte i, byte q)
|
||||
{
|
||||
sampleQueue.Enqueue(new Tuple<byte, byte>(i, q));
|
||||
}
|
||||
|
||||
private byte[] zBuffer;
|
||||
private Color[] colorBuffer;
|
||||
public override void Update()
|
||||
{
|
||||
while (sampleQueue.Count > 0)
|
||||
{
|
||||
Tuple<byte, byte> 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();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
namespace ImGuiNET.SampleProgram.XNA;
|
||||
|
||||
public static class RandomExtension
|
||||
{
|
||||
public static T NextItem<T>(this Random rng, T[] array)
|
||||
{
|
||||
return array[rng.Next(array.Length)];
|
||||
}
|
||||
}
|
||||
62
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ScottPlotWindow.cs
Normal file
62
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ScottPlotWindow.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
186
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/Ziggurat.cs
Normal file
186
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/Ziggurat.cs
Normal file
@ -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<double, ulong>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
83
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ZigguratStream.cs
Normal file
83
GUIs/skyscraper8.UI.ImGui.MonoGame.Bridge/ZigguratStream.cs
Normal file
@ -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(); }
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ImGui.NET" Version="1.91.6.1" />
|
||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.4" />
|
||||
<PackageReference Include="ScottPlot" Version="5.0.55" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
13
GUIs/skyscraper8.UI.ImGui.MonoGame/Program.cs
Normal file
13
GUIs/skyscraper8.UI.ImGui.MonoGame/Program.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
32
GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/0_Blank.cs
Normal file
32
GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/0_Blank.cs
Normal file
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
372
GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/2_Substrate.cs
Normal file
372
GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/2_Substrate.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
193
GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/Processing.cs
Normal file
193
GUIs/skyscraper8.UI.ImGui.MonoGame/Screenhacks/Processing.cs
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<int, ConstructorInfo> knownScreenhacks;
|
||||
|
||||
public ScreenhackManager()
|
||||
{
|
||||
knownScreenhacks = new Dictionary<int, ConstructorInfo>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
GUIs/skyscraper8.UI.ImGui.MonoGame/SkyscraperGame.cs
Normal file
47
GUIs/skyscraper8.UI.ImGui.MonoGame/SkyscraperGame.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\skyscraper8\skyscraper8.csproj" />
|
||||
<ProjectReference Include="..\skyscraper8.UI.ImGui.MonoGame.Bridge\skyscraper8.UI.ImGui.MonoGame.Bridge.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -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()))
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user