Created
September 17, 2021 20:43
-
-
Save thatcosmonaut/9394ff4573cc1bf661ac27cbb1e37795 to your computer and use it in GitHub Desktop.
Anathema Moonworks/ImGui Renderer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Heavily based on prime31's Nez ImGuiRenderer | |
// https://github.com/prime31/Nez/blob/master/Nez.ImGui/Core/ImGuiRenderer.cs | |
#if DEBUG | |
using System.Runtime.InteropServices; | |
using Encompass; | |
using ImGuiNET; | |
using MoonWorks.Graphics; | |
using Anathema.Data; | |
using System.Collections.Generic; | |
using MoonWorks.Math; | |
using MoonWorks.Input; | |
using Anathema.Components; | |
using Anathema.Utility; | |
using System; | |
using Anathema.Physics; | |
namespace Anathema.Renderers | |
{ | |
// Assumes that the ImGui context has been initialized and set | |
public class ImGuiRenderer : DebugRenderer | |
{ | |
public ImFontPtr DefaultFontPtr { get; private set; } | |
private GraphicsDevice GraphicsDevice { get; } | |
private RenderPass RenderPass { get; } | |
private Framebuffer Framebuffer { get; } | |
private Rect UIArea { get; } | |
private GraphicsPipeline Pipeline { get; } | |
private Inputs Inputs { get; } | |
private byte[] vertexData; | |
private MoonWorks.Graphics.Buffer vertexBuffer; | |
private uint vertexCount = 0; | |
private byte[] indexData; | |
private MoonWorks.Graphics.Buffer indexBuffer; | |
private uint indexCount = 0; | |
private Dictionary<IntPtr, Texture> loadedTextures = new Dictionary<IntPtr, Texture>(); | |
private Dictionary<Texture, IntPtr> textureHandles = new Dictionary<Texture, IntPtr>(); | |
int textureID = 0; | |
System.IntPtr? fontTextureID; | |
private Sampler sampler; | |
private HashSet<Entity> openEntities = new HashSet<Entity>(); | |
private HashSet<Entity> closedEntities = new HashSet<Entity>(); | |
private HashSet<Type> openComponentTypes = new HashSet<Type>(); | |
private HashSet<Type> closedComponentTypes = new HashSet<Type>(); | |
private Dictionary<Type, Action<Entity>> componentTypeToInspectorAction; | |
List<int> _keys = new List<int>(); | |
private bool entitySearchActive = false; | |
private string componentSearchInput = ""; | |
private bool debugHelpActive = true; | |
public ImGuiRenderer( | |
GraphicsDevice graphicsDevice, | |
RenderPass imGuiRenderPass, | |
Framebuffer imGuiFramebuffer, | |
GraphicsPipeline imGuiPipeline, | |
Inputs inputs, | |
uint presentWidth, | |
uint presentHeight | |
) { | |
GraphicsDevice = graphicsDevice; | |
RenderPass = imGuiRenderPass; | |
Framebuffer = imGuiFramebuffer; | |
UIArea = new Rect | |
{ | |
X = 0, | |
Y = 0, | |
W = (int) presentWidth, | |
H = (int) presentHeight | |
}; | |
Pipeline = imGuiPipeline; | |
Inputs = inputs; | |
sampler = new Sampler( | |
GraphicsDevice, | |
SamplerCreateInfo.PointClamp | |
); | |
DefaultFontPtr = ImGui.GetIO().Fonts.AddFontDefault(); | |
RebuildFontAtlas(); | |
var io = ImGui.GetIO(); | |
Inputs.TextInput += c => | |
{ | |
if (c == '\t') { return; } | |
io.AddInputCharacter(c); | |
}; | |
_keys.Add(io.KeyMap[(int) ImGuiKey.Tab] = (int) Keycode.Tab); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.LeftArrow] = (int) Keycode.Left); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.RightArrow] = (int) Keycode.Right); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.UpArrow] = (int) Keycode.Up); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.DownArrow] = (int) Keycode.Down); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.PageUp] = (int) Keycode.PageUp); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.PageDown] = (int) Keycode.PageDown); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.Home] = (int) Keycode.Home); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.End] = (int) Keycode.End); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.Delete] = (int) Keycode.Delete); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.Backspace] = (int) Keycode.Backspace); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.Enter] = (int) Keycode.Return); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.Escape] = (int) Keycode.Escape); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.A] = (int) Keycode.C); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.V] = (int) Keycode.V); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.X] = (int) Keycode.X); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.Y] = (int) Keycode.Y); | |
_keys.Add(io.KeyMap[(int) ImGuiKey.Z] = (int) Keycode.Z); | |
componentTypeToInspectorAction = new Dictionary<Type, Action<Entity>> | |
{ | |
{ typeof(Texture2DComponent), DrawTexture2DComponent }, | |
{ typeof(Transform3DComponent), DrawTransform3DComponent }, | |
{ typeof(LightIntensityCurveComponent), DrawLightIntensityCurveComponent }, | |
{ typeof(RigidbodyComponent), DrawRigidbodyComponent }, | |
{ typeof(HealthComponent), DrawHealthComponent }, | |
{ typeof(SpeedComponent), DrawSpeedComponent }, | |
{ typeof(AttackRateComponent), DrawAttackRateComponent }, | |
{ typeof(AtlasAnimationComponent), DrawAtlasAnimationComponent } | |
}; | |
} | |
public override void Render(double dt, double alpha) | |
{ | |
if (!SomeComponent<DebugModeComponent>()) { return; } | |
var io = ImGuiNET.ImGui.GetIO(); | |
io.DeltaTime = (float) dt; | |
io.KeyShift = Inputs.Keyboard.IsDown(Keycode.LeftShift) || Inputs.Keyboard.IsDown(Keycode.RightShift); | |
io.KeyCtrl = Inputs.Keyboard.IsDown(Keycode.LeftControl) || Inputs.Keyboard.IsDown(Keycode.RightControl); | |
io.KeyAlt = Inputs.Keyboard.IsDown(Keycode.LeftAlt) || Inputs.Keyboard.IsDown(Keycode.RightAlt); | |
io.KeySuper = Inputs.Keyboard.IsDown(Keycode.LeftMeta) || Inputs.Keyboard.IsDown(Keycode.RightMeta); | |
io.KeyMap[(int)ImGuiKey.Backspace] = (int)Keycode.Backspace; | |
io.MousePos = new System.Numerics.Vector2(Inputs.Mouse.X, Inputs.Mouse.Y); | |
io.MouseDown[0] = Inputs.Mouse.LeftButton.IsDown; | |
io.MouseDown[1] = Inputs.Mouse.RightButton.IsDown; | |
io.MouseDown[2] = Inputs.Mouse.MiddleButton.IsDown; | |
io.MouseWheel = Inputs.Mouse.Wheel > 0 ? 1 : Inputs.Mouse.Wheel < 0 ? -1 : 0; | |
for (int i = 0; i < _keys.Count; i++) | |
{ | |
io.KeysDown[_keys[i]] = Inputs.Keyboard.IsDown((Keycode) _keys[i]); | |
} | |
ImGui.NewFrame(); | |
// TODO: mouse scroll | |
if (!io.WantCaptureKeyboard) | |
{ | |
if ( | |
Inputs.Keyboard.IsDown(Keycode.LeftControl) && | |
Inputs.Keyboard.IsPressed(Keycode.H) | |
) { | |
debugHelpActive = !debugHelpActive; | |
} | |
if ( | |
Inputs.Keyboard.IsDown(Keycode.LeftControl) && | |
Inputs.Keyboard.IsPressed(Keycode.E) | |
) { | |
entitySearchActive = !entitySearchActive; | |
} | |
} | |
if ( | |
!io.WantCaptureMouse && | |
SomeComponent<DebugPhysicsSimulationComponent>() && | |
SomeComponent<CameraComponent>() | |
) { | |
var physicsComponent = ReadComponent<DebugPhysicsSimulationComponent>(); | |
var simulation = physicsComponent.Simulation; | |
// FIXME: this is weirdly duplicative | |
var cameraEntity = ReadEntity<CameraComponent>(); | |
var cameraComponent = GetComponent<CameraComponent>(cameraEntity); | |
var cameraTransform = GetComponent<Transform3DComponent>(cameraEntity); | |
var cameraRightVector = cameraTransform.Right; | |
var cameraForwardVector = Vector3.Transform( | |
cameraTransform.Forward, | |
Quaternion.CreateFromAxisAngle( | |
cameraRightVector, | |
cameraComponent.VerticalTilt | |
) | |
); | |
var cameraUpVector = Vector3.Transform( | |
cameraTransform.Up, | |
Quaternion.CreateFromAxisAngle( | |
cameraRightVector, | |
cameraComponent.VerticalTilt | |
) | |
); | |
var camera = new PerspectiveCamera( | |
cameraTransform.Position + cameraComponent.Offset, | |
cameraForwardVector, | |
cameraUpVector, | |
cameraComponent.FieldOfView, | |
16f / 9f, | |
cameraComponent.NearPlane, | |
cameraComponent.FarPlane | |
); | |
var cameraMatrix = camera.View * camera.Projection; | |
if (Inputs.Mouse.LeftButton.IsPressed) | |
{ | |
var mousePosition = new Vector2(Inputs.Mouse.X, Inputs.Mouse.Y) / 2; | |
var mouseNDC = new Vector3( | |
2f * mousePosition.X / 640 - 1f, // FIXME: MAGIC VALUE | |
2f * mousePosition.Y / 360 - 1f, | |
1f | |
); | |
var rayClip = new Vector4(mouseNDC.X, mouseNDC.Y, -1, 1); | |
var rayEye = Vector4.Transform(rayClip, Matrix4x4.Invert(camera.Projection)); | |
rayEye.Z = -1; | |
rayEye.W = 0; | |
var rayWorld4 = Vector4.Transform(rayEye, Matrix4x4.Invert(camera.View)); | |
var rayWorld = Vector3.Normalize(new Vector3(rayWorld4.X, rayWorld4.Y, rayWorld4.Z)).ToNumericsVector(); | |
var from = (cameraTransform.Position + cameraComponent.Offset).ToNumericsVector(); | |
var rayHitHandler = new ClosestRayHitHandler(physicsComponent.CollisionFilters, CollisionGroups.All); | |
simulation.RayCast( | |
from, | |
rayWorld, | |
100f, | |
ref rayHitHandler | |
); | |
if (rayHitHandler.Hit.IsHit) | |
{ | |
var entity = physicsComponent.BodyHandles[rayHitHandler.Hit.Collidable.BodyHandle]; | |
openEntities.Add(entity); | |
} | |
} | |
} | |
if (debugHelpActive) | |
{ | |
ImGui.SetNextWindowSize(new System.Numerics.Vector2(400, 200)); | |
ImGui.Begin("Help", ref debugHelpActive); | |
ImGui.Columns(2); | |
ImGui.Text("F7"); | |
ImGui.NextColumn(); | |
ImGui.Text("Pause Action"); | |
ImGui.NextColumn(); | |
ImGui.Text("Ctrl-E"); | |
ImGui.NextColumn(); | |
ImGui.Text("Entity Search"); | |
ImGui.NextColumn(); | |
ImGui.Text("Left Click"); | |
ImGui.NextColumn(); | |
ImGui.Text("Inspect Entity"); | |
ImGui.NextColumn(); | |
ImGui.Text("Ctrl-H"); | |
ImGui.NextColumn(); | |
ImGui.Text("Help"); | |
ImGui.NextColumn(); | |
ImGui.End(); | |
} | |
if (entitySearchActive) | |
{ | |
ImGui.SetNextWindowSize(new System.Numerics.Vector2(400, 200)); | |
ImGui.Begin("Entity Search", ref entitySearchActive); | |
var entered = ImGui.InputText("Component Name", ref componentSearchInput, 120); | |
if (componentSearchInput != "") | |
{ | |
foreach (var type in Debug_SearchComponentType(componentSearchInput)) | |
{ | |
if (ImGui.Button(type.ToString())) | |
{ | |
openComponentTypes.Add(type); | |
} | |
} | |
} | |
ImGui.End(); | |
} | |
foreach (var componentType in openComponentTypes) | |
{ | |
ImGui.PushID(componentType.ToString()); | |
var open = true; | |
ImGui.SetNextWindowSize(new System.Numerics.Vector2(400, 200)); | |
ImGui.Begin(componentType.ToString(), ref open); | |
foreach (var entity in Debug_Entities(componentType)) | |
{ | |
if (ImGui.Button($"Entity {entity.ID}")) | |
{ | |
openEntities.Add(entity); | |
} | |
} | |
ImGui.End(); | |
ImGui.PopID(); | |
if (!open) | |
{ | |
closedComponentTypes.Add(componentType); | |
} | |
} | |
foreach (var closedComponentType in closedComponentTypes) | |
{ | |
openComponentTypes.Remove(closedComponentType); | |
} | |
closedComponentTypes.Clear(); | |
foreach (var entity in openEntities) | |
{ | |
ImGui.PushID(entity.ID); | |
var open = true; | |
if (ImGui.Begin($"Entity {entity.ID}", ref open)) | |
{ | |
foreach (var component in Debug_GetAllComponents(entity)) | |
{ | |
DrawComponentInspector(entity, component); | |
} | |
ImGui.End(); | |
} | |
ImGui.PopID(); | |
if (!open) | |
{ | |
closedEntities.Add(entity); | |
} | |
} | |
foreach (var entity in closedEntities) | |
{ | |
openEntities.Remove(entity); | |
} | |
closedEntities.Clear(); | |
ImGui.Render(); | |
var drawData = ImGui.GetDrawData(); | |
UpdateBuffers(drawData); | |
RenderCommandLists(drawData); | |
} | |
public System.IntPtr BindTexture(Texture texture) | |
{ | |
var id = new System.IntPtr(textureID++); | |
loadedTextures.Add(id, texture); | |
textureHandles.Add(texture, id); | |
return id; | |
} | |
public void UnbindTexture(System.IntPtr textureId) | |
{ | |
var texture = loadedTextures[textureId]; | |
loadedTextures.Remove(textureId); | |
textureHandles.Remove(texture); | |
} | |
public unsafe void RebuildFontAtlas() | |
{ | |
var io = ImGui.GetIO(); | |
io.Fonts.GetTexDataAsRGBA32( | |
out byte* pixelData, | |
out int width, | |
out int height, | |
out int bytesPerPixel | |
); | |
var pixels = new byte[width * height * bytesPerPixel]; | |
Marshal.Copy(new System.IntPtr(pixelData), pixels, 0, pixels.Length); | |
var tex2D = Texture.CreateTexture2D( | |
GraphicsDevice, | |
(uint) width, | |
(uint) height, | |
TextureFormat.R8G8B8A8, | |
TextureUsageFlags.Sampler | |
); | |
tex2D.SetData(pixels); | |
if (fontTextureID.HasValue) | |
{ | |
UnbindTexture(fontTextureID.Value); | |
} | |
fontTextureID = BindTexture(tex2D); | |
io.Fonts.SetTexID(fontTextureID.Value); | |
io.Fonts.ClearTexData(); | |
} | |
private void DrawComponentInspector(Entity entity, object component) | |
{ | |
if (componentTypeToInspectorAction.ContainsKey(component.GetType())) | |
{ | |
var expanded = ImGui.CollapsingHeader(component.GetType().ToString()); | |
if (expanded) | |
{ | |
componentTypeToInspectorAction[component.GetType()].Invoke(entity); | |
} | |
} | |
else | |
{ | |
ImGui.Text(component.GetType().ToString()); | |
} | |
} | |
// COMPONENT INSPECTOR IMPLEMENTATIONS | |
private void DrawHealthComponent(Entity entity) | |
{ | |
var healthComponent = GetComponent<HealthComponent>(entity); | |
var health = healthComponent.Health; | |
ImGui.InputInt("Health", ref health); | |
if (health != healthComponent.Health) | |
{ | |
Debug_SetComponent(entity, new HealthComponent(health)); | |
} | |
} | |
private void DrawRigidbodyComponent(Entity entity) | |
{ | |
var physicsSimulationComponent = ReadComponent<DebugPhysicsSimulationComponent>(); | |
var rigidbodyComponent = GetComponent<RigidbodyComponent>(entity); | |
var rigidbody = physicsSimulationComponent.Simulation.Bodies.GetBodyReference(rigidbodyComponent.Handle); | |
var awake = rigidbody.Awake; | |
var kinematic = rigidbody.Kinematic; | |
var linearVelocity = rigidbody.Velocity.Linear; | |
var angularVelocity = rigidbody.Velocity.Angular; | |
var inverseMass = rigidbody.LocalInertia.InverseMass; | |
ImGui.Checkbox("Awake", ref awake); | |
ImGui.Checkbox("Kinematic", ref kinematic); | |
ImGui.InputFloat3("Linear Velocity", ref linearVelocity); | |
ImGui.InputFloat3("Angular Velocity", ref angularVelocity); | |
ImGui.InputFloat("Inverse Mass", ref inverseMass); | |
} | |
private void DrawTexture2DComponent(Entity entity) | |
{ | |
IntPtr textureHandle; | |
var texture = GetComponent<Texture2DComponent>(entity).Texture; | |
if (textureHandles.ContainsKey(texture)) | |
{ | |
textureHandle = textureHandles[texture]; | |
} | |
else | |
{ | |
textureHandle = BindTexture(texture); | |
} | |
if (HasComponent<UVDataComponent>(entity)) | |
{ | |
ImGui.Text("Displaying atlased image using UVData"); | |
var uvData = GetComponent<UVDataComponent>(entity).UVData; | |
ImGui.Image( | |
textureHandle, | |
new System.Numerics.Vector2(texture.Width * uvData.Percentage.X, texture.Height * uvData.Percentage.Y), | |
uvData.Offset.ToNumericsVector(), | |
(uvData.Offset + uvData.Percentage).ToNumericsVector() | |
); | |
} | |
else | |
{ | |
ImGui.Image(textureHandle, new System.Numerics.Vector2(texture.Width, texture.Height)); | |
} | |
} | |
private void DrawTransform3DComponent(Entity entity) | |
{ | |
var transformComponent = GetComponent<Transform3DComponent>(entity); | |
var position = transformComponent.Position.ToNumericsVector(); | |
var scale = transformComponent.Scale.X; | |
var forward = transformComponent.Forward.ToNumericsVector(); | |
var up = transformComponent.Up.ToNumericsVector(); | |
var right = transformComponent.Right.ToNumericsVector(); | |
ImGui.InputFloat3("Position", ref position); | |
ImGui.InputFloat("Scale", ref scale); | |
ImGui.InputFloat3("Forward", ref forward); | |
ImGui.InputFloat3("Up", ref up); | |
ImGui.InputFloat3("Right", ref right); | |
if ( | |
position.ToMoonWorksVector() != transformComponent.Position || | |
scale != transformComponent.Scale.X || | |
forward.ToMoonWorksVector() != transformComponent.Forward || | |
up.ToMoonWorksVector() != transformComponent.Up || | |
right.ToMoonWorksVector() != transformComponent.Right | |
) { | |
var newForward = Vector3.Normalize(forward.ToMoonWorksVector()); | |
var newUp = Vector3.Normalize(up.ToMoonWorksVector()); | |
var newRight = Vector3.Normalize(right.ToMoonWorksVector()); | |
Debug_SetComponent(entity, new Transform3DComponent( | |
position.ToMoonWorksVector(), | |
Quaternion.LookAt(newForward, newUp), | |
new Vector3(scale, scale, scale) | |
)); | |
} | |
} | |
private void DrawLightIntensityCurveComponent(Entity entity) | |
{ | |
var sampleCount = 24; | |
var curve = GetComponent<LightIntensityCurveComponent>(entity); | |
var floats = new float[sampleCount + 1]; | |
for (var i = 0; i <= sampleCount; i++) | |
{ | |
floats[i] = curve.Curve.Point(i * (curve.Curve.TotalTime / sampleCount)); | |
} | |
ImGui.PlotLines("Intensity Curve", ref floats[0], floats.Length); | |
} | |
private void DrawSpeedComponent(Entity entity) | |
{ | |
var speedComponent = GetComponent<SpeedComponent>(entity); | |
var speed = speedComponent.Speed; | |
var speedMultiplier = speedComponent.SpeedMultiplier; | |
var dampingFactor = speedComponent.DampingFactor; | |
ImGui.InputFloat("Speed", ref speed); | |
ImGui.InputFloat("Speed Multiplier", ref speedMultiplier); | |
ImGui.InputFloat("Damping Factor", ref dampingFactor); | |
if ( | |
speed != speedComponent.Speed || | |
speedMultiplier != speedComponent.SpeedMultiplier || | |
dampingFactor != speedComponent.DampingFactor | |
) { | |
Debug_SetComponent(entity, new SpeedComponent(speed, speedMultiplier, dampingFactor)); | |
} | |
} | |
private void DrawAttackRateComponent(Entity entity) | |
{ | |
var attackRateComponent = GetComponent<AttackRateComponent>(entity); | |
var attackRate = attackRateComponent.AttackRate; | |
ImGui.InputFloat("Attack Rate", ref attackRate); | |
if ( | |
attackRate != attackRateComponent.AttackRate | |
) { | |
Debug_SetComponent(entity, new AttackRateComponent(attackRate)); | |
} | |
} | |
private void DrawAtlasAnimationComponent(Entity entity) | |
{ | |
var atlasAnimationComponent = GetComponent<AtlasAnimationComponent>(entity); | |
var animation = atlasAnimationComponent.AtlasAnimation; | |
var currentFrameIndex = atlasAnimationComponent.CurrentFrame; | |
var loopTime = (float)atlasAnimationComponent.LoopTime; | |
var elapsedTime = (float)atlasAnimationComponent.ElapsedTime % loopTime; | |
var loop = atlasAnimationComponent.Loop; | |
ImGui.Text(animation.Name); | |
ImGui.SliderFloat("Elapsed Time", ref elapsedTime, 0, loopTime); | |
ImGui.Checkbox("Loop", ref loop); | |
ImGui.Columns(2); | |
ImGui.Text("Current Frame Index"); | |
ImGui.NextColumn(); | |
ImGui.Text(currentFrameIndex.ToString()); | |
ImGui.NextColumn(); | |
ImGui.Text("Loop Time"); | |
ImGui.NextColumn(); | |
ImGui.Text(String.Format("{0:0.00}", loopTime)); | |
ImGui.NextColumn(); | |
ImGui.Columns(1); | |
if ( | |
currentFrameIndex != atlasAnimationComponent.CurrentFrame || | |
elapsedTime != atlasAnimationComponent.ElapsedTime || | |
loopTime != atlasAnimationComponent.LoopTime || | |
loop != atlasAnimationComponent.Loop | |
) { | |
Debug_SetComponent(entity, new AtlasAnimationComponent( | |
animation, | |
elapsedTime, | |
loop | |
)); | |
} | |
} | |
// RENDERING IMGUI DATA | |
private unsafe void UpdateBuffers(ImDrawDataPtr drawData) | |
{ | |
if (drawData.TotalVtxCount == 0) { return; } | |
var vertexSize = Marshal.SizeOf<VertexPosition2DTextureColor>(); | |
if (drawData.TotalVtxCount > vertexCount) | |
{ | |
vertexBuffer?.Dispose(); | |
vertexCount = (uint) (drawData.TotalVtxCount * 1.5f); | |
var bufferSizeInBytes = (uint)(vertexCount * vertexSize); | |
vertexBuffer = new MoonWorks.Graphics.Buffer( | |
GraphicsDevice, | |
BufferUsageFlags.Vertex, | |
bufferSizeInBytes | |
); | |
vertexData = new byte[bufferSizeInBytes]; | |
} | |
if (drawData.TotalIdxCount > indexCount) | |
{ | |
indexBuffer?.Dispose(); | |
indexCount = (uint) (drawData.TotalIdxCount * 1.5f); | |
var bufferSizeInBytes = (uint)(indexCount * sizeof(ushort)); | |
indexBuffer = new MoonWorks.Graphics.Buffer( | |
GraphicsDevice, | |
BufferUsageFlags.Index, | |
bufferSizeInBytes | |
); | |
indexData = new byte[bufferSizeInBytes]; | |
} | |
int vertexOffset = 0; | |
int indexOffset = 0; | |
for (var n = 0; n < drawData.CmdListsCount; n++) | |
{ | |
var cmdList = drawData.CmdListsRange[n]; | |
fixed (void* vertexDstPtr = &vertexData[vertexOffset * vertexSize]) | |
fixed (void* indexDstPtr = &indexData[indexOffset * sizeof(ushort)]) | |
{ | |
System.Buffer.MemoryCopy( | |
(void*)cmdList.VtxBuffer.Data, | |
vertexDstPtr, | |
vertexData.Length, | |
cmdList.VtxBuffer.Size * vertexSize | |
); | |
System.Buffer.MemoryCopy( | |
(void*)cmdList.IdxBuffer.Data, | |
indexDstPtr, | |
indexData.Length, | |
cmdList.IdxBuffer.Size * sizeof(ushort) | |
); | |
} | |
vertexOffset += cmdList.VtxBuffer.Size; | |
indexOffset += cmdList.IdxBuffer.Size; | |
} | |
vertexBuffer.SetData(vertexData, 0, (uint) (drawData.TotalVtxCount * vertexSize)); | |
indexBuffer.SetData(indexData, 0, (uint)(drawData.TotalIdxCount * sizeof(ushort))); | |
} | |
private void RenderCommandLists(ImDrawDataPtr drawData) | |
{ | |
if (vertexBuffer == null) { return; } | |
var io = ImGui.GetIO(); | |
var commandBuffer = GraphicsDevice.AcquireCommandBuffer(); | |
commandBuffer.BeginRenderPass( | |
RenderPass, | |
Framebuffer, | |
UIArea, | |
new DepthStencilValue { Depth = 1f, Stencil = 0 }, | |
Color.Transparent.ToVector4() | |
); | |
var vertexUniformOffset = Pipeline.PushVertexShaderUniforms( | |
Matrix4x4.CreateOrthographicOffCenter(0, io.DisplaySize.X, io.DisplaySize.Y, 0, -1, 1) | |
); | |
commandBuffer.BindGraphicsPipeline(Pipeline); | |
commandBuffer.BindVertexBuffers(vertexBuffer); | |
commandBuffer.BindIndexBuffer(indexBuffer, IndexElementSize.Sixteen); | |
uint vertexOffset = 0; | |
uint indexOffset = 0; | |
for (int n = 0; n < drawData.CmdListsCount; n++) | |
{ | |
var cmdList = drawData.CmdListsRange[n]; | |
for (int cmdIndex = 0; cmdIndex < cmdList.CmdBuffer.Size; cmdIndex++) | |
{ | |
var drawCmd = cmdList.CmdBuffer[cmdIndex]; | |
// TODO: check for loaded textures | |
commandBuffer.BindFragmentSamplers( | |
new TextureSamplerBinding(loadedTextures[drawCmd.TextureId], sampler) | |
); | |
commandBuffer.DrawIndexedPrimitives( | |
vertexOffset, | |
indexOffset, | |
drawCmd.ElemCount / 3, | |
vertexUniformOffset, | |
0 | |
); | |
indexOffset += drawCmd.ElemCount; | |
} | |
vertexOffset += (uint) cmdList.VtxBuffer.Size; | |
} | |
commandBuffer.EndRenderPass(); | |
GraphicsDevice.Submit(commandBuffer); | |
} | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment