Skip to content

Instantly share code, notes, and snippets.

@thatcosmonaut
Created September 17, 2021 20:43
Show Gist options
  • Save thatcosmonaut/9394ff4573cc1bf661ac27cbb1e37795 to your computer and use it in GitHub Desktop.
Save thatcosmonaut/9394ff4573cc1bf661ac27cbb1e37795 to your computer and use it in GitHub Desktop.
Anathema Moonworks/ImGui Renderer
// 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