cleanup the ImGui code stuffs

This commit is contained in:
Mike 2019-02-14 17:34:12 -08:00
parent 1f1ef82697
commit 6ebd635a61
3 changed files with 456 additions and 452 deletions

View File

@ -1,28 +0,0 @@
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)
);
}
}
}

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Reflection; using System.Reflection;
using ImGuiNET; using ImGuiNET;
using ImGuiNET.SampleProgram.XNA;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
@ -11,68 +10,99 @@ namespace Nez
{ {
public Scene scene { get; set; } public Scene scene { get; set; }
ImGuiRenderer _imGuiRenderer; ImGuiRenderer _imGuiRenderer;
RenderTarget2D _lastRenderTarget; RenderTarget2D _lastRenderTarget;
IntPtr _renderTargetId; IntPtr _renderTargetId;
public ImGuiFinalRenderDelegate() public ImGuiFinalRenderDelegate()
{
_imGuiRenderer = new ImGuiRenderer(Core.instance);
_imGuiRenderer.RebuildFontAtlas();
ImGui.GetIO().ConfigWindowsMoveFromTitleBarOnly = true;
}
public void handleFinalRender( Color letterboxColor, RenderTarget2D source, Rectangle finalRenderDestinationRect, SamplerState samplerState )
{ {
if(_lastRenderTarget != source) _imGuiRenderer = new ImGuiRenderer( Core.instance );
{ _imGuiRenderer.rebuildFontAtlas();
// unbind the old texture if we had one
if(_lastRenderTarget != null)
_imGuiRenderer.UnbindTexture(_renderTargetId);
// bind the new texture
_lastRenderTarget = source;
_renderTargetId = _imGuiRenderer.BindTexture(source);
}
Core.graphicsDevice.setRenderTarget( null );
Core.graphicsDevice.Clear( letterboxColor );
_imGuiRenderer.BeforeLayout(Time.time);
layoutGui();
_imGuiRenderer.AfterLayout();
} }
void layoutGui() [Console.Command( "toggle-imgui", "Toggles the Dear ImGui renderer" )]
{ static void toggleImGui()
ImGui.ShowDemoWindow(); {
if( Core.scene.finalRenderDelegate == null )
Core.scene.finalRenderDelegate = new ImGuiFinalRenderDelegate();
else
Core.scene.finalRenderDelegate = null;
}
var maxSize = new System.Numerics.Vector2(_lastRenderTarget.Width, _lastRenderTarget.Height); void layoutGui()
var minSize = maxSize / 4; {
unsafe ImGui.ShowDemoWindow();
{
ImGui.SetNextWindowSizeConstraints(minSize, maxSize, data =>
{
var size = (*data).CurrentSize;
var ratio = size.X / _lastRenderTarget.Width;
(*data).DesiredSize.Y = ratio * _lastRenderTarget.Height;
});
}
ImGui.SetNextWindowPos(new System.Numerics.Vector2(0, 0), ImGuiCond.FirstUseEver); var maxSize = new System.Numerics.Vector2( _lastRenderTarget.Width, _lastRenderTarget.Height );
ImGui.Begin("Game Window"); var minSize = maxSize / 4;
ImGui.Image(_renderTargetId, ImGui.GetContentRegionAvail()); maxSize *= 4;
ImGui.End(); unsafe
} {
ImGui.SetNextWindowSizeConstraints( minSize, maxSize, data =>
{
var size = ( *data ).CurrentSize;
var ratio = size.X / _lastRenderTarget.Width;
( *data ).DesiredSize.Y = ratio * _lastRenderTarget.Height;
} );
}
ImGui.SetNextWindowPos( new System.Numerics.Vector2( 0, 0 ), ImGuiCond.FirstUseEver );
ImGui.PushStyleVar( ImGuiStyleVar.WindowPadding, new System.Numerics.Vector2( 0, 0 ) );
ImGui.Begin( "Game Window" );
Nugget.InputDisplay.cursorScreenPos = new Vector2( ImGui.GetCursorScreenPos().X, ImGui.GetCursorScreenPos().Y );
Nugget.InputDisplay.scaleX = ImGui.GetContentRegionAvail().X / _lastRenderTarget.Width;
Nugget.InputDisplay.scaleY = ImGui.GetContentRegionAvail().Y / _lastRenderTarget.Height;
//Debug.log( $"window pos: {ImGui.GetWindowPos()}" );
//Debug.log( $"avail size: {ImGui.GetContentRegionAvail()}" );
//Debug.log( $"rt {_lastRenderTarget.Width} x {_lastRenderTarget.Height}" );
//Debug.log( $"scaleX: {ImGui.GetContentRegionAvail().X / _lastRenderTarget.Width}" );
//Debug.log( $"scaleY: {ImGui.GetContentRegionAvail().Y / _lastRenderTarget.Height}" );
//Debug.log( ImGui.GetWindowSize() - ImGui.GetContentRegionAvail() );
//Debug.log( $"titleHeight: {titleHeight}" );
//Debug.log( $"screenPos: {ImGui.GetCursorScreenPos()}" );
ImGui.Image( _renderTargetId, ImGui.GetContentRegionAvail() );
ImGui.End();
ImGui.PopStyleVar();
}
#region IFinalRenderDelegate
public void handleFinalRender( RenderTarget2D finalRenderTarget, Color letterboxColor, RenderTarget2D source, Rectangle finalRenderDestinationRect, SamplerState samplerState )
{
if( _lastRenderTarget != source )
{
// unbind the old texture if we had one
if( _lastRenderTarget != null )
_imGuiRenderer.unbindTexture( _renderTargetId );
// bind the new texture
_lastRenderTarget = source;
_renderTargetId = _imGuiRenderer.bindTexture( source );
}
Core.graphicsDevice.setRenderTarget( finalRenderTarget );
Core.graphicsDevice.Clear( letterboxColor );
_imGuiRenderer.beforeLayout( Time.deltaTime );
layoutGui();
_imGuiRenderer.afterLayout();
}
public void onAddedToScene() public void onAddedToScene()
{} { }
public void onSceneBackBufferSizeChanged( int newWidth, int newHeight ) public void onSceneBackBufferSizeChanged( int newWidth, int newHeight )
{} { }
public void unload() public void unload()
{} { }
#endregion
} }
} }

View File

@ -1,387 +1,389 @@
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using Nez;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace ImGuiNET.SampleProgram.XNA namespace ImGuiNET
{ {
/// <summary> /// <summary>
/// ImGui renderer for use with XNA-likes (FNA & MonoGame) /// ImGui renderer for use with XNA-likes (FNA and MonoGame)
/// </summary> /// </summary>
public class ImGuiRenderer public class ImGuiRenderer
{ {
private Game _game; // Graphics
BasicEffect _effect;
// Graphics RasterizerState _rasterizerState;
private GraphicsDevice _graphicsDevice;
readonly VertexDeclaration _vertexDeclaration;
private BasicEffect _effect; readonly int _vertexDeclarationSize;
private RasterizerState _rasterizerState;
byte[] _vertexData;
private byte[] _vertexData; VertexBuffer _vertexBuffer;
private VertexBuffer _vertexBuffer; int _vertexBufferSize;
private int _vertexBufferSize;
byte[] _indexData;
private byte[] _indexData; IndexBuffer _indexBuffer;
private IndexBuffer _indexBuffer; int _indexBufferSize;
private int _indexBufferSize;
// Textures
// Textures Dictionary<IntPtr, Texture2D> _loadedTextures;
private Dictionary<IntPtr, Texture2D> _loadedTextures;
int _textureId;
private int _textureId; IntPtr? _fontTextureId;
private IntPtr? _fontTextureId;
// Input
// Input int _scrollWheelValue;
private int _scrollWheelValue;
List<int> _keys = new List<int>();
private List<int> _keys = new List<int>();
public ImGuiRenderer( Game game )
public ImGuiRenderer(Game game) {
{ unsafe { _vertexDeclarationSize = sizeof( ImDrawVert ); }
var context = ImGui.CreateContext(); _vertexDeclaration = new VertexDeclaration(
ImGui.SetCurrentContext(context); _vertexDeclarationSize,
// Position
_game = game ?? throw new ArgumentNullException(nameof(game)); new VertexElement( 0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0 ),
_graphicsDevice = game.GraphicsDevice; // UV
new VertexElement( 8, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0 ),
_loadedTextures = new Dictionary<IntPtr, Texture2D>(); // Color
new VertexElement( 16, VertexElementFormat.Color, VertexElementUsage.Color, 0 )
_rasterizerState = new RasterizerState() );
{
CullMode = CullMode.None, var context = ImGui.CreateContext();
DepthBias = 0, ImGui.SetCurrentContext( context );
FillMode = FillMode.Solid,
MultiSampleAntiAlias = false, _loadedTextures = new Dictionary<IntPtr, Texture2D>();
ScissorTestEnable = true,
SlopeScaleDepthBias = 0 _rasterizerState = new RasterizerState()
}; {
CullMode = CullMode.None,
SetupInput(); DepthBias = 0,
} FillMode = FillMode.Solid,
MultiSampleAntiAlias = false,
#region ImGuiRenderer ScissorTestEnable = true,
SlopeScaleDepthBias = 0
/// <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> setupInput();
public virtual unsafe void RebuildFontAtlas() }
{
// Get font texture from ImGui #region ImGuiRenderer
var io = ImGui.GetIO();
io.Fonts.GetTexDataAsRGBA32(out byte* pixelData, out int width, out int height, out int bytesPerPixel); /// <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
// Copy the data to a managed array /// </summary>
var pixels = new byte[width * height * bytesPerPixel]; public unsafe void rebuildFontAtlas()
unsafe { Marshal.Copy(new IntPtr(pixelData), pixels, 0, pixels.Length); } {
// Get font texture from ImGui
// Create and register the texture as an XNA texture var io = ImGui.GetIO();
var tex2d = new Texture2D(_graphicsDevice, width, height, false, SurfaceFormat.Color); io.Fonts.GetTexDataAsRGBA32( out byte* pixelData, out int width, out int height, out int bytesPerPixel );
tex2d.SetData(pixels);
// Copy the data to a managed array
// Should a texture already have been build previously, unbind it first so it can be deallocated var pixels = new byte[width * height * bytesPerPixel];
if (_fontTextureId.HasValue) UnbindTexture(_fontTextureId.Value); Marshal.Copy( new IntPtr( pixelData ), pixels, 0, pixels.Length );
// Bind the new texture to an ImGui-friendly id // Create and register the texture as an XNA texture
_fontTextureId = BindTexture(tex2d); var tex2d = new Texture2D( Core.graphicsDevice, width, height, false, SurfaceFormat.Color );
tex2d.SetData( pixels );
// Let ImGui know where to find the texture
io.Fonts.SetTexID(_fontTextureId.Value); // Should a texture already have been built previously, unbind it first so it can be deallocated
io.Fonts.ClearTexData(); // Clears CPU side texture data if( _fontTextureId.HasValue )
} unbindTexture( _fontTextureId.Value );
/// <summary> // Bind the new texture to an ImGui-friendly id
/// 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 _fontTextureId = bindTexture( tex2d );
/// </summary>
public virtual IntPtr BindTexture(Texture2D texture) // Let ImGui know where to find the texture
{ io.Fonts.SetTexID( _fontTextureId.Value );
var id = new IntPtr(_textureId++); io.Fonts.ClearTexData(); // Clears CPU side texture data
}
_loadedTextures.Add(id, texture);
/// <summary>
return id; /// 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 IntPtr bindTexture( Texture2D texture )
/// <summary> {
/// Removes a previously created texture pointer, releasing its reference and allowing it to be deallocated var id = new IntPtr( _textureId++ );
/// </summary> _loadedTextures.Add( id, texture );
public virtual void UnbindTexture(IntPtr textureId) return id;
{ }
_loadedTextures.Remove(textureId);
} /// <summary>
/// Removes a previously created texture pointer, releasing its reference and allowing it to be deallocated
/// <summary> /// </summary>
/// Sets up ImGui for a new frame, should be called at frame start public void unbindTexture( IntPtr textureId )
/// </summary> {
public virtual void BeforeLayout(float deltaTime) _loadedTextures.Remove( textureId );
{ }
ImGui.GetIO().DeltaTime = deltaTime;
UpdateInput(); /// <summary>
ImGui.NewFrame(); /// Sets up ImGui for a new frame, should be called at frame start
} /// </summary>
public void beforeLayout( float deltaTime )
/// <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 ImGui.GetIO().DeltaTime = deltaTime;
/// </summary> updateInput();
public virtual void AfterLayout() ImGui.NewFrame();
{ }
ImGui.Render();
/// <summary>
unsafe { RenderDrawData(ImGui.GetDrawData()); } /// 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 void afterLayout()
#endregion ImGuiRenderer {
ImGui.Render();
#region Setup & Update unsafe { renderDrawData( ImGui.GetDrawData() ); }
}
/// <summary>
/// Maps ImGui keys to XNA keys. We use this later on to tell ImGui what keys were pressed #endregion ImGuiRenderer
/// </summary>
protected virtual void SetupInput() #region Setup & Update
{
var io = ImGui.GetIO(); /// <summary>
/// Maps ImGui keys to XNA keys. We use this later on to tell ImGui what keys were pressed
_keys.Add(io.KeyMap[(int)ImGuiKey.Tab] = (int)Keys.Tab); /// </summary>
_keys.Add(io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)Keys.Left); void setupInput()
_keys.Add(io.KeyMap[(int)ImGuiKey.RightArrow] = (int)Keys.Right); {
_keys.Add(io.KeyMap[(int)ImGuiKey.UpArrow] = (int)Keys.Up); var io = ImGui.GetIO();
_keys.Add(io.KeyMap[(int)ImGuiKey.DownArrow] = (int)Keys.Down);
_keys.Add(io.KeyMap[(int)ImGuiKey.PageUp] = (int)Keys.PageUp); _keys.Add( io.KeyMap[(int)ImGuiKey.Tab] = (int)Keys.Tab );
_keys.Add(io.KeyMap[(int)ImGuiKey.PageDown] = (int)Keys.PageDown); _keys.Add( io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)Keys.Left );
_keys.Add(io.KeyMap[(int)ImGuiKey.Home] = (int)Keys.Home); _keys.Add( io.KeyMap[(int)ImGuiKey.RightArrow] = (int)Keys.Right );
_keys.Add(io.KeyMap[(int)ImGuiKey.End] = (int)Keys.End); _keys.Add( io.KeyMap[(int)ImGuiKey.UpArrow] = (int)Keys.Up );
_keys.Add(io.KeyMap[(int)ImGuiKey.Delete] = (int)Keys.Delete); _keys.Add( io.KeyMap[(int)ImGuiKey.DownArrow] = (int)Keys.Down );
_keys.Add(io.KeyMap[(int)ImGuiKey.Backspace] = (int)Keys.Back); _keys.Add( io.KeyMap[(int)ImGuiKey.PageUp] = (int)Keys.PageUp );
_keys.Add(io.KeyMap[(int)ImGuiKey.Enter] = (int)Keys.Enter); _keys.Add( io.KeyMap[(int)ImGuiKey.PageDown] = (int)Keys.PageDown );
_keys.Add(io.KeyMap[(int)ImGuiKey.Escape] = (int)Keys.Escape); _keys.Add( io.KeyMap[(int)ImGuiKey.Home] = (int)Keys.Home );
_keys.Add(io.KeyMap[(int)ImGuiKey.A] = (int)Keys.A); _keys.Add( io.KeyMap[(int)ImGuiKey.End] = (int)Keys.End );
_keys.Add(io.KeyMap[(int)ImGuiKey.C] = (int)Keys.C); _keys.Add( io.KeyMap[(int)ImGuiKey.Delete] = (int)Keys.Delete );
_keys.Add(io.KeyMap[(int)ImGuiKey.V] = (int)Keys.V); _keys.Add( io.KeyMap[(int)ImGuiKey.Backspace] = (int)Keys.Back );
_keys.Add(io.KeyMap[(int)ImGuiKey.X] = (int)Keys.X); _keys.Add( io.KeyMap[(int)ImGuiKey.Enter] = (int)Keys.Enter );
_keys.Add(io.KeyMap[(int)ImGuiKey.Y] = (int)Keys.Y); _keys.Add( io.KeyMap[(int)ImGuiKey.Escape] = (int)Keys.Escape );
_keys.Add(io.KeyMap[(int)ImGuiKey.Z] = (int)Keys.Z); _keys.Add( io.KeyMap[(int)ImGuiKey.A] = (int)Keys.A );
_keys.Add( io.KeyMap[(int)ImGuiKey.C] = (int)Keys.C );
_keys.Add( io.KeyMap[(int)ImGuiKey.V] = (int)Keys.V );
// MonoGame-specific ////////////////////// _keys.Add( io.KeyMap[(int)ImGuiKey.X] = (int)Keys.X );
// _game.Window.TextInput += (s, a) => _keys.Add( io.KeyMap[(int)ImGuiKey.Y] = (int)Keys.Y );
// { _keys.Add( io.KeyMap[(int)ImGuiKey.Z] = (int)Keys.Z );
// if (a.Character == '\t') return;
// io.AddInputCharacter(a.Character); // MonoGame-specific //////////////////////
// }; // _game.Window.TextInput += (s, a) =>
/////////////////////////////////////////// // {
// if (a.Character == '\t') return;
// FNA-specific ///////////////////////////
TextInputEXT.TextInput += c => // io.AddInputCharacter(a.Character);
{ // };
if (c == '\t') return; ///////////////////////////////////////////
ImGui.GetIO().AddInputCharacter(c); // FNA-specific ///////////////////////////
}; TextInputEXT.TextInput += c =>
/////////////////////////////////////////// {
if( c == '\t' ) return;
ImGui.GetIO().Fonts.AddFontDefault();
} ImGui.GetIO().AddInputCharacter( c );
};
/// <summary> ///////////////////////////////////////////
/// Updates the <see cref="Effect" /> to the current matrices and texture
/// </summary> ImGui.GetIO().Fonts.AddFontDefault();
protected virtual Effect UpdateEffect(Texture2D texture) }
{
_effect = _effect ?? new BasicEffect(_graphicsDevice); /// <summary>
/// Updates the <see cref="Effect" /> to the current matrices and texture
var io = ImGui.GetIO(); /// </summary>
Effect updateEffect( Texture2D texture )
// MonoGame-specific ////////////////////// {
//var offset = .5f; _effect = _effect ?? new BasicEffect( Core.graphicsDevice );
///////////////////////////////////////////
var io = ImGui.GetIO();
// FNA-specific ///////////////////////////
var offset = 0f; // MonoGame-specific //////////////////////
/////////////////////////////////////////// //var offset = .5f;
///////////////////////////////////////////
_effect.World = Matrix.Identity;
_effect.View = Matrix.Identity; // FNA-specific ///////////////////////////
_effect.Projection = Matrix.CreateOrthographicOffCenter(offset, io.DisplaySize.X + offset, io.DisplaySize.Y + offset, offset, -1f, 1f); var offset = 0f;
_effect.TextureEnabled = true; ///////////////////////////////////////////
_effect.Texture = texture;
_effect.VertexColorEnabled = true; _effect.World = Matrix.Identity;
_effect.View = Matrix.Identity;
return _effect; _effect.Projection = Matrix.CreateOrthographicOffCenter( offset, io.DisplaySize.X + offset, io.DisplaySize.Y + offset, offset, -1f, 1f );
} _effect.TextureEnabled = true;
_effect.Texture = texture;
/// <summary> _effect.VertexColorEnabled = true;
/// Sends XNA input state to ImGui
/// </summary> return _effect;
protected virtual void UpdateInput() }
{
var io = ImGui.GetIO(); /// <summary>
/// Sends XNA input state to ImGui
var mouse = Mouse.GetState(); /// </summary>
var keyboard = Keyboard.GetState(); void updateInput()
{
for (int i = 0; i < _keys.Count; i++) var io = ImGui.GetIO();
{
io.KeysDown[_keys[i]] = keyboard.IsKeyDown((Keys)_keys[i]); var mouse = Mouse.GetState();
} var keyboard = Keyboard.GetState();
io.KeyShift = keyboard.IsKeyDown(Keys.LeftShift) || keyboard.IsKeyDown(Keys.RightShift); for( int i = 0; i < _keys.Count; i++ )
io.KeyCtrl = keyboard.IsKeyDown(Keys.LeftControl) || keyboard.IsKeyDown(Keys.RightControl); {
io.KeyAlt = keyboard.IsKeyDown(Keys.LeftAlt) || keyboard.IsKeyDown(Keys.RightAlt); io.KeysDown[_keys[i]] = keyboard.IsKeyDown( (Keys)_keys[i] );
io.KeySuper = keyboard.IsKeyDown(Keys.LeftWindows) || keyboard.IsKeyDown(Keys.RightWindows); }
io.DisplaySize = new System.Numerics.Vector2(_graphicsDevice.PresentationParameters.BackBufferWidth, _graphicsDevice.PresentationParameters.BackBufferHeight); io.KeyShift = keyboard.IsKeyDown( Keys.LeftShift ) || keyboard.IsKeyDown( Keys.RightShift );
io.DisplayFramebufferScale = new System.Numerics.Vector2(1f, 1f); io.KeyCtrl = keyboard.IsKeyDown( Keys.LeftControl ) || keyboard.IsKeyDown( Keys.RightControl );
io.KeyAlt = keyboard.IsKeyDown( Keys.LeftAlt ) || keyboard.IsKeyDown( Keys.RightAlt );
io.MousePos = new System.Numerics.Vector2(mouse.X, mouse.Y); io.KeySuper = keyboard.IsKeyDown( Keys.LeftWindows ) || keyboard.IsKeyDown( Keys.RightWindows );
io.MouseDown[0] = mouse.LeftButton == ButtonState.Pressed; io.DisplaySize = new System.Numerics.Vector2( Core.graphicsDevice.PresentationParameters.BackBufferWidth, Core.graphicsDevice.PresentationParameters.BackBufferHeight );
io.MouseDown[1] = mouse.RightButton == ButtonState.Pressed; io.DisplayFramebufferScale = new System.Numerics.Vector2( 1f, 1f );
io.MouseDown[2] = mouse.MiddleButton == ButtonState.Pressed;
io.MousePos = new System.Numerics.Vector2( mouse.X, mouse.Y );
var scrollDelta = mouse.ScrollWheelValue - _scrollWheelValue;
io.MouseWheel = scrollDelta > 0 ? 1 : scrollDelta < 0 ? -1 : 0; io.MouseDown[0] = mouse.LeftButton == ButtonState.Pressed;
_scrollWheelValue = mouse.ScrollWheelValue; io.MouseDown[1] = mouse.RightButton == ButtonState.Pressed;
} io.MouseDown[2] = mouse.MiddleButton == ButtonState.Pressed;
#endregion Setup & Update var scrollDelta = mouse.ScrollWheelValue - _scrollWheelValue;
io.MouseWheel = scrollDelta > 0 ? 1 : scrollDelta < 0 ? -1 : 0;
#region Internals _scrollWheelValue = mouse.ScrollWheelValue;
}
/// <summary>
/// Gets the geometry as set up by ImGui and sends it to the graphics device #endregion Setup & Update
/// </summary>
private void RenderDrawData(ImDrawDataPtr drawData) #region Internals
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers /// <summary>
var lastViewport = _graphicsDevice.Viewport; /// Gets the geometry as set up by ImGui and sends it to the graphics device
var lastScissorBox = _graphicsDevice.ScissorRectangle; /// </summary>
void renderDrawData( ImDrawDataPtr drawData )
_graphicsDevice.BlendFactor = Color.White; {
_graphicsDevice.BlendState = BlendState.NonPremultiplied; // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers
_graphicsDevice.RasterizerState = _rasterizerState; var lastViewport = Core.graphicsDevice.Viewport;
_graphicsDevice.DepthStencilState = DepthStencilState.DepthRead; var lastScissorBox = Core.graphicsDevice.ScissorRectangle;
// Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) Core.graphicsDevice.BlendFactor = Color.White;
drawData.ScaleClipRects(ImGui.GetIO().DisplayFramebufferScale); Core.graphicsDevice.BlendState = BlendState.NonPremultiplied;
Core.graphicsDevice.RasterizerState = _rasterizerState;
// Setup projection Core.graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
_graphicsDevice.Viewport = new Viewport(0, 0, _graphicsDevice.PresentationParameters.BackBufferWidth, _graphicsDevice.PresentationParameters.BackBufferHeight);
// Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays)
UpdateBuffers(drawData); drawData.ScaleClipRects( ImGui.GetIO().DisplayFramebufferScale );
RenderCommandLists(drawData); // Setup projection
Core.graphicsDevice.Viewport = new Viewport( 0, 0, Core.graphicsDevice.PresentationParameters.BackBufferWidth, Core.graphicsDevice.PresentationParameters.BackBufferHeight );
// Restore modified state
_graphicsDevice.Viewport = lastViewport; updateBuffers( drawData );
_graphicsDevice.ScissorRectangle = lastScissorBox; renderCommandLists( drawData );
}
// Restore modified state
private unsafe void UpdateBuffers(ImDrawDataPtr drawData) Core.graphicsDevice.Viewport = lastViewport;
{ Core.graphicsDevice.ScissorRectangle = lastScissorBox;
if (drawData.TotalVtxCount == 0) }
{
return; unsafe void updateBuffers( ImDrawDataPtr drawData )
} {
if( drawData.TotalVtxCount == 0 )
// Expand buffers if we need more room {
if (drawData.TotalVtxCount > _vertexBufferSize) return;
{ }
_vertexBuffer?.Dispose();
// Expand buffers if we need more room
_vertexBufferSize = (int)(drawData.TotalVtxCount * 1.5f); if( drawData.TotalVtxCount > _vertexBufferSize )
_vertexBuffer = new VertexBuffer(_graphicsDevice, DrawVertDeclaration.Declaration, _vertexBufferSize, BufferUsage.None); {
_vertexData = new byte[_vertexBufferSize * DrawVertDeclaration.Size]; _vertexBuffer?.Dispose();
}
_vertexBufferSize = (int)( drawData.TotalVtxCount * 1.5f );
if (drawData.TotalIdxCount > _indexBufferSize) _vertexBuffer = new VertexBuffer( Core.graphicsDevice, _vertexDeclaration, _vertexBufferSize, BufferUsage.None );
{ _vertexData = new byte[_vertexBufferSize * _vertexDeclarationSize];
_indexBuffer?.Dispose(); }
_indexBufferSize = (int)(drawData.TotalIdxCount * 1.5f); if( drawData.TotalIdxCount > _indexBufferSize )
_indexBuffer = new IndexBuffer(_graphicsDevice, IndexElementSize.SixteenBits, _indexBufferSize, BufferUsage.None); {
_indexData = new byte[_indexBufferSize * sizeof(ushort)]; _indexBuffer?.Dispose();
}
_indexBufferSize = (int)( drawData.TotalIdxCount * 1.5f );
// Copy ImGui's vertices and indices to a set of managed byte arrays _indexBuffer = new IndexBuffer( Core.graphicsDevice, IndexElementSize.SixteenBits, _indexBufferSize, BufferUsage.None );
int vtxOffset = 0; _indexData = new byte[_indexBufferSize * sizeof( ushort )];
int idxOffset = 0; }
for (int n = 0; n < drawData.CmdListsCount; n++) // Copy ImGui's vertices and indices to a set of managed byte arrays
{ int vtxOffset = 0;
ImDrawListPtr cmdList = drawData.CmdListsRange[n]; int idxOffset = 0;
fixed (void* vtxDstPtr = &_vertexData[vtxOffset * DrawVertDeclaration.Size]) for( var n = 0; n < drawData.CmdListsCount; n++ )
fixed (void* idxDstPtr = &_indexData[idxOffset * sizeof(ushort)]) {
{ var cmdList = drawData.CmdListsRange[n];
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)); fixed ( void* vtxDstPtr = &_vertexData[vtxOffset * _vertexDeclarationSize] )
} fixed ( void* idxDstPtr = &_indexData[idxOffset * sizeof( ushort )] )
{
vtxOffset += cmdList.VtxBuffer.Size; Buffer.MemoryCopy( (void*)cmdList.VtxBuffer.Data, vtxDstPtr, _vertexData.Length, cmdList.VtxBuffer.Size * _vertexDeclarationSize );
idxOffset += cmdList.IdxBuffer.Size; Buffer.MemoryCopy( (void*)cmdList.IdxBuffer.Data, idxDstPtr, _indexData.Length, cmdList.IdxBuffer.Size * sizeof( ushort ) );
} }
// Copy the managed byte arrays to the gpu vertex- and index buffers vtxOffset += cmdList.VtxBuffer.Size;
_vertexBuffer.SetData(_vertexData, 0, drawData.TotalVtxCount * DrawVertDeclaration.Size); idxOffset += cmdList.IdxBuffer.Size;
_indexBuffer.SetData(_indexData, 0, drawData.TotalIdxCount * sizeof(ushort)); }
}
// Copy the managed byte arrays to the gpu vertex- and index buffers
private unsafe void RenderCommandLists(ImDrawDataPtr drawData) _vertexBuffer.SetData( _vertexData, 0, drawData.TotalVtxCount * _vertexDeclarationSize );
{ _indexBuffer.SetData( _indexData, 0, drawData.TotalIdxCount * sizeof( ushort ) );
_graphicsDevice.SetVertexBuffer(_vertexBuffer); }
_graphicsDevice.Indices = _indexBuffer;
unsafe void renderCommandLists( ImDrawDataPtr drawData )
int vtxOffset = 0; {
int idxOffset = 0; Core.graphicsDevice.SetVertexBuffer( _vertexBuffer );
Core.graphicsDevice.Indices = _indexBuffer;
for (int n = 0; n < drawData.CmdListsCount; n++)
{ int vtxOffset = 0;
ImDrawListPtr cmdList = drawData.CmdListsRange[n]; int idxOffset = 0;
for (int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; cmdi++) for( int n = 0; n < drawData.CmdListsCount; n++ )
{ {
ImDrawCmdPtr drawCmd = cmdList.CmdBuffer[cmdi]; var cmdList = drawData.CmdListsRange[n];
for( int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; cmdi++ )
if (!_loadedTextures.ContainsKey(drawCmd.TextureId)) {
{ var drawCmd = cmdList.CmdBuffer[cmdi];
throw new InvalidOperationException($"Could not find a texture with id '{drawCmd.TextureId}', please check your bindings"); 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, Core.graphicsDevice.ScissorRectangle = new Rectangle(
(int)(drawCmd.ClipRect.Z - drawCmd.ClipRect.X), (int)drawCmd.ClipRect.X,
(int)(drawCmd.ClipRect.W - drawCmd.ClipRect.Y) (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) var effect = updateEffect( _loadedTextures[drawCmd.TextureId] );
{ foreach( var pass in effect.CurrentTechnique.Passes )
pass.Apply(); {
pass.Apply();
#pragma warning disable CS0618 // // FNA does not expose an alternative method. #pragma warning disable CS0618 // // FNA does not expose an alternative method.
_graphicsDevice.DrawIndexedPrimitives( Core.graphicsDevice.DrawIndexedPrimitives(
primitiveType: PrimitiveType.TriangleList, primitiveType: PrimitiveType.TriangleList,
baseVertex: vtxOffset, baseVertex: vtxOffset,
minVertexIndex: 0, minVertexIndex: 0,
numVertices: cmdList.VtxBuffer.Size, numVertices: cmdList.VtxBuffer.Size,
startIndex: idxOffset, startIndex: idxOffset,
primitiveCount: (int)drawCmd.ElemCount / 3 primitiveCount: (int)drawCmd.ElemCount / 3
); );
#pragma warning restore CS0618 #pragma warning restore CS0618
} }
idxOffset += (int)drawCmd.ElemCount; idxOffset += (int)drawCmd.ElemCount;
} }
vtxOffset += cmdList.VtxBuffer.Size; vtxOffset += cmdList.VtxBuffer.Size;
} }
} }
#endregion Internals #endregion Internals
} }
} }