move to using Nez instead of Nez.FNA

This commit is contained in:
Mike 2019-02-17 13:09:54 -08:00
parent ef9814253c
commit 2e933229b1
8 changed files with 27 additions and 661 deletions

17
.vscode/settings.json vendored
View File

@ -11,22 +11,19 @@
"**/.[^v]*": true, // hide any files that start with a '.' but keep the .vscode folder "**/.[^v]*": true, // hide any files that start with a '.' but keep the .vscode folder
".vs": true, // Visual Studio settings ".vs": true, // Visual Studio settings
"getFNA.sh": true, "getFNA.sh": true,
"imgui.ini": true,
"MonoGameContent.targets": true, "MonoGameContent.targets": true,
"project_name/obj": true, "**/obj": true,
"project_name/bin": true, "**/bin": true,
".gitignore": true, ".gitignore": true,
".gitmodules": true, ".gitmodules": true,
"README.md": true, "README.md": true,
"fnalibs": true, "fnalibs": true,
"project_name/CompiledContent/bin": true,
"project_name/CompiledContent/obj": true,
"project_name/CompiledContent/.mgstats": true, "project_name/CompiledContent/.mgstats": true,
"project_name/*.csproj*": true, "**/*.csproj*": true,
"*.sln": true, "**/*.sln": true,
"FNA/[^src]*": true, // hide everything but the src folder "FNA/[^src]*": true, // hide everything but the src folder
"Nez.FNA/[^Nez]*": true, // hide everything but the Nez folder "Nez/{[^DN]*}": true, // hide everything except what begins with D or N
"Nez.FNA/Nez.FNA*": true, // we miss the Nez.FNA* stuff with the above line so hide that too "Nez/Nez.*.*": true, // hide the files in the root of the repo
"Nez.FNA/Nez/{[^DN]*}": true, // hide everything except what begins with D or N
"Nez.FNA/Nez/Nez.*.*": true,
} }
} }

3
.vscode/tasks.json vendored
View File

@ -98,6 +98,9 @@
"type": "shell", "type": "shell",
"group": "build", "group": "build",
"command": "msbuild /t:BuildContent", "command": "msbuild /t:BuildContent",
"options": {
"cwd": "${workspaceFolder}/project_name"
},
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },

View File

@ -82,6 +82,7 @@ function getLibs()
tar xjC $MY_DIR/fnalibs -f $MY_DIR/fnalibs.tar.bz2 tar xjC $MY_DIR/fnalibs -f $MY_DIR/fnalibs.tar.bz2
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "Finished decompressing!" echo "Finished decompressing!"
echo ""
rm $MY_DIR/fnalibs.tar.bz2 rm $MY_DIR/fnalibs.tar.bz2
else else
>&2 echo "ERROR: Unable to decompress successfully." >&2 echo "ERROR: Unable to decompress successfully."
@ -142,7 +143,7 @@ if [[ $newProjectName = 'exit' || -z "$newProjectName" ]]; then
fi fi
# any files that need to have project_name replaced with the new project name should be here # any files that need to have project_name replaced with the new project name should be here
files=(project_name.sln .gitignore project_name/project_name.sln project_name/project_name.csproj project_name/Game1.cs project_name/Program.cs .vscode/tasks.json .vscode/settings.json .vscode/launch.json .vscode/buildEffects.sh .vscode/processT4Templates.sh) files=(project_name.sln .gitignore project_name/project_name.csproj project_name/Game1.cs project_name/Program.cs .vscode/tasks.json .vscode/settings.json .vscode/launch.json .vscode/buildEffects.sh .vscode/processT4Templates.sh)
for file in "${files[@]}"; do for file in "${files[@]}"; do
sed -i '' "s/project_name/$newProjectName/g" $file sed -i '' "s/project_name/$newProjectName/g" $file
done done
@ -154,16 +155,16 @@ mv project_name/project_name.csproj.user "project_name/$newProjectName.csproj.us
mv project_name "$newProjectName" mv project_name "$newProjectName"
git init git init
git submodule add https://github.com/prime31/Nez.FNA.git git submodule add https://github.com/prime31/Nez.git
cd Nez.FNA cd Nez
git submodule init git submodule init
git submodule update git submodule update
command -v pbcopy > /dev/null 2>&1 command -v pbcopy > /dev/null 2>&1
if [ ! $? -eq 0 ]; then if [ ! $? -eq 0 ]; then
printf "\n\nManually run the following command:\n\nnuget restore Nez.FNA/Nez/Nez.sln && msbuild Nez.FNA/Nez/Nez.sln && msbuild /t:restore $newProjectName\n\n" printf "\n\nManually run the following command:\n\nnuget restore Nez/Nez.sln && msbuild Nez/Nez.sln && msbuild /t:restore $newProjectName\n\n"
else else
echo "nuget restore Nez.FNA/Nez/Nez.sln && msbuild Nez.FNA/Nez/Nez.sln && msbuild /t:restore $newProjectName" | pbcopy echo "nuget restore Nez/Nez.sln && msbuild Nez/Nez.sln && msbuild /t:restore $newProjectName" | pbcopy
echo "" echo ""
echo "A build command was copied to your clipboard. Paste and run it now." echo "A build command was copied to your clipboard. Paste and run it now."
echo "" echo ""

View File

@ -5,20 +5,21 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "project_name", "project_nam
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FNA", "FNA\FNA.csproj", "{35253CE1-C864-4CD3-8249-4D1319748E8F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FNA", "FNA\FNA.csproj", "{35253CE1-C864-4CD3-8249-4D1319748E8F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nez.FNA", "Nez.FNA\Nez.FNA\Nez.FNA.csproj", "{11A5855C-B12C-4F8D-B935-56F3D0B671C3}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nez.FNA", "Nez\Nez.Portable\Nez.FNA.csproj", "{11A5855C-B12C-4F8D-B935-56F3D0B671C3}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nez.FNA.ImGui", "Nez\Nez.ImGui\Nez.FNA.ImGui.csproj", "{16DA6D66-4DFD-46D4-A367-C02B48B80CAA}"
EndProject
Global Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8C576ECC-147D-4B4A-8EC1-56533D26A178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3CB9E917-FEF7-453F-A88D-6B85B552B058}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C576ECC-147D-4B4A-8EC1-56533D26A178}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CB9E917-FEF7-453F-A88D-6B85B552B058}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.Build.0 = Debug|Any CPU {35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11A5855C-B12C-4F8D-B935-56F3D0B671C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {11A5855C-B12C-4F8D-B935-56F3D0B671C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11A5855C-B12C-4F8D-B935-56F3D0B671C3}.Debug|Any CPU.Build.0 = Debug|Any CPU {11A5855C-B12C-4F8D-B935-56F3D0B671C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Debug|Any CPU.ActiveCfg = Release|Any CPU {16DA6D66-4DFD-46D4-A367-C02B48B80CAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Debug|Any CPU.Build.0 = Release|Any CPU {16DA6D66-4DFD-46D4-A367-C02B48B80CAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3CB9E917-FEF7-453F-A88D-6B85B552B058}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3CB9E917-FEF7-453F-A88D-6B85B552B058}.Debug|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU

View File

@ -1,4 +1,5 @@
using Nez; using Nez;
using Nez.ImGuiTools;
namespace project_name namespace project_name
{ {

View File

@ -1,221 +0,0 @@
using Nez;
using ImGuiNET;
using Microsoft.Xna.Framework;
using System;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
namespace Nez
{
public class ImGuiManager : GlobalManager, IFinalRenderDelegate, IDisposable
{
public Scene scene { get; set; }
public List<Action> drawCommands = new List<Action>();
public ImGuiRenderer renderer { get; private set; }
RenderTarget2D _lastRenderTarget;
IntPtr _renderTargetId;
bool _isGameWindowFocused;
public ImGuiManager( string pathToFontFile, float fontSizePixels )
{
renderer = new ImGuiRenderer( Core.instance );
if( pathToFontFile != null )
ImGui.GetIO().Fonts.AddFontFromFileTTF( pathToFontFile, fontSizePixels );
renderer.rebuildFontAtlas();
Core.emitter.addObserver( CoreEvents.SceneChanged, onSceneChanged );
}
public ImGuiManager() : this( null, -1 )
{}
void onSceneChanged()
{
// when the Scene changes we need to rewire ourselves up as the IFinalRenderDelegate in the new Scene
// if we were previously enabled
drawCommands.Clear();
if( enabled )
onEnabled();
}
/// <summary>
/// this is where we issue any and all ImGui commands to be drawn
/// </summary>
void layoutGui()
{
for( var i = drawCommands.Count - 1; i >= 0; i-- )
drawCommands[i]();
ImGui.ShowDemoWindow();
if( _lastRenderTarget == null )
return;
var maxSize = new System.Numerics.Vector2( _lastRenderTarget.Width, _lastRenderTarget.Height );
var minSize = maxSize / 4;
maxSize *= 4;
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" );
_isGameWindowFocused = ImGui.IsWindowFocused();
//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 Public API
/// <summary>
/// registers an Action that will be called and any ImGui drawing can be done in it
/// </summary>
/// <param name="drawCommand"></param>
public void registerDrawCommand( Action drawCommand )
{
drawCommands.Add( drawCommand );
}
/// <summary>
/// removes the Action from the draw commands
/// </summary>
/// <param name="drawCommand"></param>
public void unregisterDrawCommand( Action drawCommand )
{
drawCommands.Remove( drawCommand );
}
/// <summary>
/// adds the font to the atlas and regenerates it
/// </summary>
/// <param name="pathToFontFile"></param>
/// <param name="fontSizePixels"></param>
/// <returns></returns>
public ImFontPtr addFontAndRegenerateAtlas( string pathToFontFile, float fontSizePixels )
{
var fontPtr = ImGui.GetIO().Fonts.AddFontFromFileTTF( pathToFontFile, fontSizePixels );
renderer.rebuildFontAtlas();
return fontPtr;
}
#endregion
#region GlobalManager Lifecycle
public override void onEnabled()
{
Core.scene.finalRenderDelegate = this;
}
public override void onDisabled()
{
Core.scene.finalRenderDelegate = null;
}
public override void update()
{
renderer.beforeLayout( Time.deltaTime );
layoutGui();
}
#endregion
#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 )
renderer.unbindTexture( _renderTargetId );
// bind the new texture
_lastRenderTarget = source;
_renderTargetId = renderer.bindTexture( source );
}
Core.graphicsDevice.setRenderTarget( finalRenderTarget );
Core.graphicsDevice.Clear( letterboxColor );
renderer.afterLayout();
}
public void onAddedToScene()
{ }
public void onSceneBackBufferSizeChanged( int newWidth, int newHeight )
{ }
public void unload()
{ }
#endregion
#region IDisposable Support
bool _isDisposed = false; // To detect redundant calls
protected virtual void Dispose( bool disposing )
{
if( !_isDisposed )
{
if( disposing )
{
Core.emitter.removeObserver( CoreEvents.SceneChanged, onSceneChanged );
}
_isDisposed = true;
}
}
void IDisposable.Dispose()
{
Dispose( true );
}
#endregion
[Console.Command( "toggle-imgui", "Toggles the Dear ImGui renderer" )]
static void toggleImGui()
{
// install the service if it isnt already there
var service = Core.getGlobalManager<ImGuiManager>();
if( service == null )
{
service = new ImGuiManager();
Core.registerGlobalManager( service );
}
service.setEnabled( !service.enabled );
}
}
}

View File

@ -1,389 +0,0 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Nez;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace ImGuiNET
{
/// <summary>
/// ImGui renderer for use with XNA-likes (FNA & MonoGame)
/// </summary>
public class ImGuiRenderer
{
public ImFontPtr defaultFontPtr { get; private set; }
// Graphics
BasicEffect _effect;
RasterizerState _rasterizerState;
readonly VertexDeclaration _vertexDeclaration;
readonly int _vertexDeclarationSize;
byte[] _vertexData;
VertexBuffer _vertexBuffer;
int _vertexBufferSize;
byte[] _indexData;
IndexBuffer _indexBuffer;
int _indexBufferSize;
// Textures
Dictionary<IntPtr, Texture2D> _loadedTextures = new Dictionary<IntPtr, Texture2D>();
int _textureId;
IntPtr? _fontTextureId;
// Input
int _scrollWheelValue;
List<int> _keys = new List<int>();
public ImGuiRenderer( Game game )
{
unsafe { _vertexDeclarationSize = sizeof( ImDrawVert ); }
_vertexDeclaration = new VertexDeclaration(
_vertexDeclarationSize,
// 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 )
);
ImGui.SetCurrentContext( ImGui.CreateContext() );
_rasterizerState = new RasterizerState()
{
CullMode = CullMode.None,
DepthBias = 0,
FillMode = FillMode.Solid,
MultiSampleAntiAlias = false,
ScissorTestEnable = true,
SlopeScaleDepthBias = 0
};
setupInput();
}
#region ImGuiRenderer
/// <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 unsafe void rebuildFontAtlas()
{
// Get font texture from ImGui
var io = ImGui.GetIO();
defaultFontPtr = ImGui.GetIO().Fonts.AddFontDefault();
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];
Marshal.Copy( new IntPtr( pixelData ), pixels, 0, pixels.Length );
// Create and register the texture as an XNA texture
var tex2d = new Texture2D( Core.graphicsDevice, width, height, false, SurfaceFormat.Color );
tex2d.SetData( pixels );
// Should a texture already have been built 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 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 void unbindTexture( IntPtr textureId )
{
_loadedTextures.Remove( textureId );
}
/// <summary>
/// Sets up ImGui for a new frame, should be called at frame start
/// </summary>
public void beforeLayout( float deltaTime )
{
ImGui.GetIO().DeltaTime = deltaTime;
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 void afterLayout()
{
ImGui.Render();
unsafe { renderDrawData( ImGui.GetDrawData() ); }
}
#endregion ImGuiRenderer
#region Setup & Update
/// <summary>
/// Maps ImGui keys to XNA keys. We use this later on to tell ImGui what keys were pressed
/// </summary>
void setupInput()
{
var io = ImGui.GetIO();
_keys.Add( io.KeyMap[(int)ImGuiKey.Tab] = (int)Keys.Tab );
_keys.Add( io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)Keys.Left );
_keys.Add( io.KeyMap[(int)ImGuiKey.RightArrow] = (int)Keys.Right );
_keys.Add( io.KeyMap[(int)ImGuiKey.UpArrow] = (int)Keys.Up );
_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.PageDown] = (int)Keys.PageDown );
_keys.Add( io.KeyMap[(int)ImGuiKey.Home] = (int)Keys.Home );
_keys.Add( io.KeyMap[(int)ImGuiKey.End] = (int)Keys.End );
_keys.Add( io.KeyMap[(int)ImGuiKey.Delete] = (int)Keys.Delete );
_keys.Add( io.KeyMap[(int)ImGuiKey.Backspace] = (int)Keys.Back );
_keys.Add( io.KeyMap[(int)ImGuiKey.Enter] = (int)Keys.Enter );
_keys.Add( io.KeyMap[(int)ImGuiKey.Escape] = (int)Keys.Escape );
_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 );
_keys.Add( io.KeyMap[(int)ImGuiKey.X] = (int)Keys.X );
_keys.Add( io.KeyMap[(int)ImGuiKey.Y] = (int)Keys.Y );
_keys.Add( io.KeyMap[(int)ImGuiKey.Z] = (int)Keys.Z );
// 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>
Effect updateEffect( Texture2D texture )
{
_effect = _effect ?? new BasicEffect( Core.graphicsDevice );
var io = ImGui.GetIO();
// MonoGame-specific //////////////////////
//var offset = .5f;
///////////////////////////////////////////
// FNA-specific ///////////////////////////
var offset = 0f;
///////////////////////////////////////////
_effect.World = Matrix.Identity;
_effect.View = Matrix.Identity;
_effect.Projection = Matrix.CreateOrthographicOffCenter( offset, io.DisplaySize.X + offset, io.DisplaySize.Y + offset, offset, -1f, 1f );
_effect.TextureEnabled = true;
_effect.Texture = texture;
_effect.VertexColorEnabled = true;
return _effect;
}
/// <summary>
/// Sends XNA input state to ImGui
/// </summary>
void updateInput()
{
var io = ImGui.GetIO();
var mouse = Mouse.GetState();
var keyboard = Keyboard.GetState();
for( int i = 0; i < _keys.Count; i++ )
{
io.KeysDown[_keys[i]] = keyboard.IsKeyDown( (Keys)_keys[i] );
}
io.KeyShift = keyboard.IsKeyDown( Keys.LeftShift ) || keyboard.IsKeyDown( Keys.RightShift );
io.KeyCtrl = keyboard.IsKeyDown( Keys.LeftControl ) || keyboard.IsKeyDown( Keys.RightControl );
io.KeyAlt = keyboard.IsKeyDown( Keys.LeftAlt ) || keyboard.IsKeyDown( Keys.RightAlt );
io.KeySuper = keyboard.IsKeyDown( Keys.LeftWindows ) || keyboard.IsKeyDown( Keys.RightWindows );
io.DisplaySize = new System.Numerics.Vector2( Core.graphicsDevice.PresentationParameters.BackBufferWidth, Core.graphicsDevice.PresentationParameters.BackBufferHeight );
io.DisplayFramebufferScale = new System.Numerics.Vector2( 1f, 1f );
io.MousePos = new System.Numerics.Vector2( mouse.X, mouse.Y );
io.MouseDown[0] = mouse.LeftButton == ButtonState.Pressed;
io.MouseDown[1] = mouse.RightButton == ButtonState.Pressed;
io.MouseDown[2] = mouse.MiddleButton == ButtonState.Pressed;
var scrollDelta = mouse.ScrollWheelValue - _scrollWheelValue;
io.MouseWheel = scrollDelta > 0 ? 1 : scrollDelta < 0 ? -1 : 0;
_scrollWheelValue = mouse.ScrollWheelValue;
}
#endregion Setup & Update
#region Internals
/// <summary>
/// Gets the geometry as set up by ImGui and sends it to the graphics device
/// </summary>
void renderDrawData( ImDrawDataPtr drawData )
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers
var lastViewport = Core.graphicsDevice.Viewport;
var lastScissorBox = Core.graphicsDevice.ScissorRectangle;
Core.graphicsDevice.BlendFactor = Color.White;
Core.graphicsDevice.BlendState = BlendState.NonPremultiplied;
Core.graphicsDevice.RasterizerState = _rasterizerState;
Core.graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
// Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays)
drawData.ScaleClipRects( ImGui.GetIO().DisplayFramebufferScale );
// Setup projection
Core.graphicsDevice.Viewport = new Viewport( 0, 0, Core.graphicsDevice.PresentationParameters.BackBufferWidth, Core.graphicsDevice.PresentationParameters.BackBufferHeight );
updateBuffers( drawData );
renderCommandLists( drawData );
// Restore modified state
Core.graphicsDevice.Viewport = lastViewport;
Core.graphicsDevice.ScissorRectangle = lastScissorBox;
}
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( Core.graphicsDevice, _vertexDeclaration, _vertexBufferSize, BufferUsage.None );
_vertexData = new byte[_vertexBufferSize * _vertexDeclarationSize];
}
if( drawData.TotalIdxCount > _indexBufferSize )
{
_indexBuffer?.Dispose();
_indexBufferSize = (int)( drawData.TotalIdxCount * 1.5f );
_indexBuffer = new IndexBuffer( Core.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( var n = 0; n < drawData.CmdListsCount; n++ )
{
var cmdList = drawData.CmdListsRange[n];
fixed ( void* vtxDstPtr = &_vertexData[vtxOffset * _vertexDeclarationSize] )
fixed ( void* idxDstPtr = &_indexData[idxOffset * sizeof( ushort )] )
{
Buffer.MemoryCopy( (void*)cmdList.VtxBuffer.Data, vtxDstPtr, _vertexData.Length, cmdList.VtxBuffer.Size * _vertexDeclarationSize );
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 * _vertexDeclarationSize );
_indexBuffer.SetData( _indexData, 0, drawData.TotalIdxCount * sizeof( ushort ) );
}
unsafe void renderCommandLists( ImDrawDataPtr drawData )
{
Core.graphicsDevice.SetVertexBuffer( _vertexBuffer );
Core.graphicsDevice.Indices = _indexBuffer;
int vtxOffset = 0;
int idxOffset = 0;
for( int n = 0; n < drawData.CmdListsCount; n++ )
{
var cmdList = drawData.CmdListsRange[n];
for( int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; cmdi++ )
{
var drawCmd = cmdList.CmdBuffer[cmdi];
if( !_loadedTextures.ContainsKey( drawCmd.TextureId ) )
{
throw new InvalidOperationException( $"Could not find a texture with id '{drawCmd.TextureId}', please check your bindings" );
}
Core.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.
Core.graphicsDevice.DrawIndexedPrimitives(
primitiveType: PrimitiveType.TriangleList,
baseVertex: vtxOffset,
minVertexIndex: 0,
numVertices: cmdList.VtxBuffer.Size,
startIndex: idxOffset,
primitiveCount: (int)drawCmd.ElemCount / 3
);
#pragma warning restore CS0618
}
idxOffset += (int)drawCmd.ElemCount;
}
vtxOffset += cmdList.VtxBuffer.Size;
}
}
#endregion Internals
}
}

View File

@ -13,7 +13,8 @@
<!-- Reference FNA, Nez and ImGui projects --> <!-- Reference FNA, Nez and ImGui projects -->
<ItemGroup> <ItemGroup>
<ProjectReference Include="../FNA/FNA.csproj"/> <ProjectReference Include="../FNA/FNA.csproj"/>
<ProjectReference Include="../Nez.FNA/Nez.FNA/Nez.FNA.csproj"/> <ProjectReference Include="../Nez/Nez.Portable/Nez.FNA.csproj"/>
<ProjectReference Include="../Nez/Nez.ImGui/Nez.FNA.ImGui.csproj"/>
</ItemGroup> </ItemGroup>
<!-- Include the Content directory (except for .fx files, since we use .fxb at runtime) --> <!-- Include the Content directory (except for .fx files, since we use .fxb at runtime) -->
@ -71,32 +72,4 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<!-- Copy ImGui native code to output -->
<PropertyGroup>
<ImGuiRuntimes>$(NuGetPackageRoot)\imgui.net\**\runtimes\</ImGuiRuntimes>
</PropertyGroup>
<ItemGroup>
<Content Include="$(ImGuiRuntimes)win-x86\native\cimgui.dll" Condition="'$(OS)' == 'Windows_NT' AND '$(Platform)' != 'x64'">
<Link>%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(ImGuiRuntimes)win-x64\native\cimgui.dll" Condition="'$(OS)' == 'Windows_NT' AND '$(Platform)' != 'x86'">
<Link>%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(ImGuiRuntimes)osx-x64\native\cimgui.dylib" Condition="'$(OS)' != 'Windows_NT' AND $(IsOSX) == 'true'">
<Link>libcimgui.dylib</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include=".$(ImGuiRuntimes)linux-x64\native\cimgui.so" Condition="'$(OS)' != 'Windows_NT' AND $(IsLinux) == 'true'">
<Link>%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="ImGui.NET" Version="1.67.0" />
</ItemGroup>
</Project> </Project>