mirror of
https://github.com/prime31/FNA-VSCode-Template.git
synced 2025-10-31 21:50:44 +07:00
move to using Nez instead of Nez.FNA
This commit is contained in:
parent
ef9814253c
commit
2e933229b1
17
.vscode/settings.json
vendored
17
.vscode/settings.json
vendored
@ -11,22 +11,19 @@
|
||||
"**/.[^v]*": true, // hide any files that start with a '.' but keep the .vscode folder
|
||||
".vs": true, // Visual Studio settings
|
||||
"getFNA.sh": true,
|
||||
"imgui.ini": true,
|
||||
"MonoGameContent.targets": true,
|
||||
"project_name/obj": true,
|
||||
"project_name/bin": true,
|
||||
"**/obj": true,
|
||||
"**/bin": true,
|
||||
".gitignore": true,
|
||||
".gitmodules": true,
|
||||
"README.md": true,
|
||||
"fnalibs": true,
|
||||
"project_name/CompiledContent/bin": true,
|
||||
"project_name/CompiledContent/obj": true,
|
||||
"project_name/CompiledContent/.mgstats": true,
|
||||
"project_name/*.csproj*": true,
|
||||
"*.sln": true,
|
||||
"**/*.csproj*": true,
|
||||
"**/*.sln": true,
|
||||
"FNA/[^src]*": true, // hide everything but the src folder
|
||||
"Nez.FNA/[^Nez]*": true, // hide everything but the Nez folder
|
||||
"Nez.FNA/Nez.FNA*": true, // we miss the Nez.FNA* stuff with the above line so hide that too
|
||||
"Nez.FNA/Nez/{[^DN]*}": true, // hide everything except what begins with D or N
|
||||
"Nez.FNA/Nez/Nez.*.*": true,
|
||||
"Nez/{[^DN]*}": true, // hide everything except what begins with D or N
|
||||
"Nez/Nez.*.*": true, // hide the files in the root of the repo
|
||||
}
|
||||
}
|
||||
|
||||
3
.vscode/tasks.json
vendored
3
.vscode/tasks.json
vendored
@ -98,6 +98,9 @@
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"command": "msbuild /t:BuildContent",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/project_name"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
|
||||
|
||||
11
getFNA.sh
11
getFNA.sh
@ -82,6 +82,7 @@ function getLibs()
|
||||
tar xjC $MY_DIR/fnalibs -f $MY_DIR/fnalibs.tar.bz2
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Finished decompressing!"
|
||||
echo ""
|
||||
rm $MY_DIR/fnalibs.tar.bz2
|
||||
else
|
||||
>&2 echo "ERROR: Unable to decompress successfully."
|
||||
@ -142,7 +143,7 @@ if [[ $newProjectName = 'exit' || -z "$newProjectName" ]]; then
|
||||
fi
|
||||
|
||||
# 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
|
||||
sed -i '' "s/project_name/$newProjectName/g" $file
|
||||
done
|
||||
@ -154,16 +155,16 @@ mv project_name/project_name.csproj.user "project_name/$newProjectName.csproj.us
|
||||
mv project_name "$newProjectName"
|
||||
|
||||
git init
|
||||
git submodule add https://github.com/prime31/Nez.FNA.git
|
||||
cd Nez.FNA
|
||||
git submodule add https://github.com/prime31/Nez.git
|
||||
cd Nez
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
command -v pbcopy > /dev/null 2>&1
|
||||
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
|
||||
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 "A build command was copied to your clipboard. Paste and run it now."
|
||||
echo ""
|
||||
|
||||
@ -5,20 +5,21 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "project_name", "project_nam
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FNA", "FNA\FNA.csproj", "{35253CE1-C864-4CD3-8249-4D1319748E8F}"
|
||||
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
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nez.FNA.ImGui", "Nez\Nez.ImGui\Nez.FNA.ImGui.csproj", "{16DA6D66-4DFD-46D4-A367-C02B48B80CAA}"
|
||||
EndProject
|
||||
|
||||
Global
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8C576ECC-147D-4B4A-8EC1-56533D26A178}.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.ActiveCfg = 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.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.Build.0 = Debug|Any CPU
|
||||
{AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Debug|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Debug|Any CPU.Build.0 = Release|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
|
||||
{16DA6D66-4DFD-46D4-A367-C02B48B80CAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{16DA6D66-4DFD-46D4-A367-C02B48B80CAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Nez;
|
||||
using Nez.ImGuiTools;
|
||||
|
||||
namespace project_name
|
||||
{
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -13,7 +13,8 @@
|
||||
<!-- Reference FNA, Nez and ImGui projects -->
|
||||
<ItemGroup>
|
||||
<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>
|
||||
|
||||
<!-- Include the Content directory (except for .fx files, since we use .fxb at runtime) -->
|
||||
@ -71,32 +72,4 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user