diff --git a/data/font.fs b/data/font.fs
deleted file mode 100644
index dd84d034..00000000
--- a/data/font.fs
+++ /dev/null
@@ -1,16 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
-// SPDX-License-Identifier: MIT
-
-#version 330 core
-
-in vec4 color;
-in vec2 uv;
-
-uniform sampler2D FontAtlas;
-
-out vec4 fragColor;
-
-void main()
-{
- fragColor = vec4(color.rgb, color.a * texture(FontAtlas, uv).r);
-}
diff --git a/data/font.vs b/data/font.vs
deleted file mode 100644
index 5d4955d7..00000000
--- a/data/font.vs
+++ /dev/null
@@ -1,21 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
-// SPDX-License-Identifier: MIT
-
-#version 330 core
-
-layout (location = 0) in vec2 aPosition;
-layout (location = 1) in vec2 aUV;
-layout (location = 2) in vec4 aColor;
-
-out vec4 color;
-out vec2 uv;
-
-uniform mat4 ProjectionMatrix;
-
-void main()
-{
- gl_Position = ProjectionMatrix * vec4(aPosition, 0.0, 1.0);
-
- color = aColor;
- uv = aUV;
-}
diff --git a/src/Box2D.NET.Samples/Box2D.NET.Samples.csproj b/src/Box2D.NET.Samples/Box2D.NET.Samples.csproj
index 76597051..c3af722b 100644
--- a/src/Box2D.NET.Samples/Box2D.NET.Samples.csproj
+++ b/src/Box2D.NET.Samples/Box2D.NET.Samples.csproj
@@ -11,6 +11,11 @@
+
+
+
+
+
@@ -42,4 +47,4 @@
-
\ No newline at end of file
+
diff --git a/src/Box2D.NET.Samples/EmbeddedShaders.cs b/src/Box2D.NET.Samples/EmbeddedShaders.cs
new file mode 100644
index 00000000..fd2a2ee5
--- /dev/null
+++ b/src/Box2D.NET.Samples/EmbeddedShaders.cs
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: 2026 Erin Catto
+// SPDX-FileCopyrightText: 2026 Ikpil Choi(ikpil@naver.com)
+// SPDX-License-Identifier: MIT
+
+using System.IO;
+using System.Reflection;
+
+namespace Box2D.NET.Samples;
+
+// Embedded from data/*.vs and *.fs. Do not edit the shader strings here.
+public static class EmbeddedShaders
+{
+ public static readonly string k_background_vs = Load("background.vs");
+ public static readonly string k_background_fs = Load("background.fs");
+ public static readonly string k_circle_vs = Load("circle.vs");
+ public static readonly string k_circle_fs = Load("circle.fs");
+ public static readonly string k_line_vs = Load("line.vs");
+ public static readonly string k_line_fs = Load("line.fs");
+ public static readonly string k_point_vs = Load("point.vs");
+ public static readonly string k_point_fs = Load("point.fs");
+ public static readonly string k_solid_capsule_vs = Load("solid_capsule.vs");
+ public static readonly string k_solid_capsule_fs = Load("solid_capsule.fs");
+ public static readonly string k_solid_circle_vs = Load("solid_circle.vs");
+ public static readonly string k_solid_circle_fs = Load("solid_circle.fs");
+ public static readonly string k_solid_polygon_vs = Load("solid_polygon.vs");
+ public static readonly string k_solid_polygon_fs = Load("solid_polygon.fs");
+
+ private static string Load(string name)
+ {
+ Assembly assembly = typeof(EmbeddedShaders).Assembly;
+ using Stream stream = assembly.GetManifestResourceStream($"Box2D.NET.Samples.Shaders.{name}")!;
+ using StreamReader reader = new StreamReader(stream);
+ return reader.ReadToEnd();
+ }
+}
diff --git a/src/Box2D.NET.Samples/Graphics/Backgrounds.cs b/src/Box2D.NET.Samples/Graphics/Backgrounds.cs
index d4d56580..90b5892d 100644
--- a/src/Box2D.NET.Samples/Graphics/Backgrounds.cs
+++ b/src/Box2D.NET.Samples/Graphics/Backgrounds.cs
@@ -5,6 +5,7 @@
using System;
using Silk.NET.GLFW;
using Silk.NET.OpenGL;
+using static Box2D.NET.Samples.EmbeddedShaders;
namespace Box2D.NET.Samples.Graphics;
@@ -14,7 +15,7 @@ public static Background CreateBackground(GL gl)
{
Background background = new Background();
- background.programId = gl.CreateProgramFromFiles("data/background.vs", "data/background.fs");
+ background.programId = gl.CreateProgramFromStrings(k_background_vs, k_background_fs);
background.timeUniform = gl.GetUniformLocation(background.programId, "time");
background.resolutionUniform = gl.GetUniformLocation(background.programId, "resolution");
background.baseColorUniform = gl.GetUniformLocation(background.programId, "baseColor");
diff --git a/src/Box2D.NET.Samples/Graphics/Cameras.cs b/src/Box2D.NET.Samples/Graphics/Cameras.cs
index b4f261d2..0e1bb84a 100644
--- a/src/Box2D.NET.Samples/Graphics/Cameras.cs
+++ b/src/Box2D.NET.Samples/Graphics/Cameras.cs
@@ -94,29 +94,6 @@ public static void BuildProjectionMatrix(Camera camera, Span m, float zBi
m[15] = 1.0f;
}
- public static void MakeOrthographicMatrix(Span m, float left, float right, float bottom, float top, float near, float far)
- {
- m[0] = 2.0f / (right - left);
- m[1] = 0.0f;
- m[2] = 0.0f;
- m[3] = 0.0f;
-
- m[4] = 0.0f;
- m[5] = 2.0f / (top - bottom);
- m[6] = 0.0f;
- m[7] = 0.0f;
-
- m[8] = 0.0f;
- m[9] = 0.0f;
- m[10] = -2.0f / (far - near);
- m[11] = 0.0f;
-
- m[12] = -(right + left) / (right - left);
- m[13] = -(top + bottom) / (top - bottom);
- m[14] = -(far + near) / (far - near);
- m[15] = 1.0f;
- }
-
public static B2AABB GetViewBounds(Camera camera)
{
if (camera.height == 0.0f || camera.width == 0.0f)
diff --git a/src/Box2D.NET.Samples/Graphics/Circles.cs b/src/Box2D.NET.Samples/Graphics/Circles.cs
index 4193dda6..82b0e1f6 100644
--- a/src/Box2D.NET.Samples/Graphics/Circles.cs
+++ b/src/Box2D.NET.Samples/Graphics/Circles.cs
@@ -9,6 +9,7 @@
using Box2D.NET.Samples.Primitives;
using static Box2D.NET.B2MathFunction;
using static Box2D.NET.Samples.Graphics.Cameras;
+using static Box2D.NET.Samples.EmbeddedShaders;
namespace Box2D.NET.Samples.Graphics;
@@ -19,7 +20,7 @@ public static class Circles
public static CircleRender CreateCircles(GL gl)
{
CircleRender render = new CircleRender();
- render.programId = gl.CreateProgramFromFiles("data/circle.vs", "data/circle.fs");
+ render.programId = gl.CreateProgramFromStrings(k_circle_vs, k_circle_fs);
render.projectionUniform = gl.GetUniformLocation(render.programId, "projectionMatrix");
render.pixelScaleUniform = gl.GetUniformLocation(render.programId, "pixelScale");
uint vertexAttribute = 0;
@@ -144,4 +145,4 @@ public static void FlushCircles(GL gl, ref CircleRender render, Camera camera)
render.circles.Clear();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Graphics/Draw.cs b/src/Box2D.NET.Samples/Graphics/Draw.cs
index 09a54891..0f166209 100644
--- a/src/Box2D.NET.Samples/Graphics/Draw.cs
+++ b/src/Box2D.NET.Samples/Graphics/Draw.cs
@@ -20,6 +20,5 @@ public class Draw
public SolidCircleRender circles;
public SolidCapsuleRender capsules;
public SolidPolygonRender polygons;
- public Font font;
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Graphics/DrawText.cs b/src/Box2D.NET.Samples/Graphics/DrawText.cs
new file mode 100644
index 00000000..c6c5a7c0
--- /dev/null
+++ b/src/Box2D.NET.Samples/Graphics/DrawText.cs
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: 2023 Erin Catto
+// SPDX-FileCopyrightText: 2026 Ikpil Choi(ikpil@naver.com)
+// SPDX-License-Identifier: MIT
+
+using System.Numerics;
+using ImGuiNET;
+using static Box2D.NET.Samples.Graphics.Cameras;
+
+namespace Box2D.NET.Samples.Graphics;
+
+public static partial class Draws
+{
+ public static void DrawScreenString(Draw draw, float x, float y, B2HexColor color, string message)
+ {
+ message = message.Length > 255 ? message[..255] : message;
+ uint hex = (uint)color;
+
+ // b2HexColor packs as 0xRRGGBB; matches MakeRGBA8's byte order. Force alpha to opaque.
+ uint col = ImGui.ColorConvertFloat4ToU32(new Vector4(((hex >> 16) & 0xFF) / 255.0f, ((hex >> 8) & 0xFF) / 255.0f,
+ (hex & 0xFF) / 255.0f, 1.0f));
+
+ // Old STB path treated y as the text baseline; ImGui::AddText treats y as the top of the
+ // glyph. Shift up by the font ascent so existing callers work.
+ float ascent = ImGui.GetFont().Ascent;
+ Vector2 viewportPosition = ImGui.GetMainViewport().Pos;
+ ImGui.GetBackgroundDrawList().AddText(viewportPosition + new Vector2(x, y - ascent), col, message);
+ }
+
+ public static void DrawWorldString(Draw draw, Camera camera, B2Vec2 p, B2HexColor color, string message)
+ {
+ message = message.Length > 255 ? message[..255] : message;
+ B2Vec2 ps = ConvertWorldToScreen(camera, p);
+ DrawScreenString(draw, ps.X, ps.Y, color, message);
+ }
+}
diff --git a/src/Box2D.NET.Samples/Graphics/Draws.cs b/src/Box2D.NET.Samples/Graphics/Draws.cs
index 80c8b149..531a7a21 100644
--- a/src/Box2D.NET.Samples/Graphics/Draws.cs
+++ b/src/Box2D.NET.Samples/Graphics/Draws.cs
@@ -4,7 +4,6 @@
using System;
using static Box2D.NET.B2MathFunction;
-using static Box2D.NET.Samples.Graphics.Cameras;
using static Box2D.NET.Samples.Graphics.Backgrounds;
using static Box2D.NET.Samples.Graphics.Points;
using static Box2D.NET.Samples.Graphics.Circles;
@@ -12,11 +11,10 @@
using static Box2D.NET.Samples.Graphics.SolidCapsules;
using static Box2D.NET.Samples.Graphics.SolidCircles;
using static Box2D.NET.Samples.Graphics.SolidPolygons;
-using static Box2D.NET.Samples.Graphics.Fonts;
namespace Box2D.NET.Samples.Graphics;
-public static class Draws
+public static partial class Draws
{
public static Draw CreateDraw(SampleContext context)
{
@@ -30,8 +28,6 @@ public static Draw CreateDraw(SampleContext context)
draw.circles = CreateSolidCircles(context.gl);
draw.capsules = CreateSolidCapsule(context.gl);
draw.polygons = CreateSolidPolygons(context.gl);
- draw.font = CreateFont(context.gl, "data/droid_sans.ttf", 18.0f);
-
return draw;
}
@@ -44,7 +40,6 @@ public static void DestroyDraw(Draw draw)
DestroySolidCircles(draw.gl, ref draw.circles);
DestroyCapsules(draw.gl, ref draw.capsules);
DestroyPolygons(draw.gl, ref draw.polygons);
- DestroyFont(draw.gl, ref draw.font);
}
public static void DrawPolygon(Draw draw, ReadOnlySpan vertices, int vertexCount, B2HexColor color)
@@ -87,17 +82,6 @@ public static void DrawBounds(Draw draw, in B2AABB aabb, B2HexColor c)
AddLine(ref draw.lines, p4, p1, c);
}
- public static void DrawScreenString(Draw draw, float x, float y, B2HexColor color, string message)
- {
- AddText(ref draw.font, x, y, color, message);
- }
-
- public static void DrawWorldString(Draw draw, Camera camera, B2Vec2 p, B2HexColor color, string message)
- {
- B2Vec2 ps = ConvertWorldToScreen(camera, p);
- AddText(ref draw.font, ps.X, ps.Y, color, message);
- }
-
public static void DrawCircle(Draw draw, B2Vec2 center, float radius, B2HexColor color)
{
AddCircle(ref draw.hollowCircles, center, radius, color);
@@ -135,7 +119,6 @@ public static void FlushDraw(Draw draw, Camera camera)
FlushCircles(draw.gl, ref draw.hollowCircles, camera);
FlushLines(draw.gl, ref draw.lines, camera);
FlushPoints(draw.gl, ref draw.points, camera);
- FlushText(draw.gl, ref draw.font, camera);
draw.gl.CheckOpenGL();
}
}
diff --git a/src/Box2D.NET.Samples/Graphics/Font.cs b/src/Box2D.NET.Samples/Graphics/Font.cs
deleted file mode 100644
index 92f353c9..00000000
--- a/src/Box2D.NET.Samples/Graphics/Font.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
-// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
-// SPDX-License-Identifier: MIT
-
-using System.Collections.Generic;
-using Box2D.NET.Samples.Primitives;
-
-namespace Box2D.NET.Samples.Graphics;
-
-public struct FontV1
-{
- public float fontSize;
- public B2Array vertices;
- //public stbtt_bakedchar* characters;
- public byte[] characters;
- public uint[] textureId;
- public uint[] vaoId;
- public uint[] vboId;
- public uint programId;
-
- public FontV1()
- {
- textureId = new uint[1];
- vaoId = new uint[1];
- vboId = new uint[1];
- }
-}
-
-public struct Font
-{
- public float fontSize;
- public List texts;
-
- public Font()
- {
- texts = new List();
- }
-}
diff --git a/src/Box2D.NET.Samples/Graphics/Fonts.cs b/src/Box2D.NET.Samples/Graphics/Fonts.cs
deleted file mode 100644
index a72aa85a..00000000
--- a/src/Box2D.NET.Samples/Graphics/Fonts.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
-// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
-// SPDX-License-Identifier: MIT
-
-using System.Numerics;
-using Silk.NET.OpenGL;
-using Box2D.NET.Samples.Primitives;
-using ImGuiNET;
-
-namespace Box2D.NET.Samples.Graphics;
-
-public static class Fonts
-{
- public static Font CreateFont(GL gl, string trueTypeFile, float fontSize)
- {
- Font font = new Font();
- return font;
- }
-
- public static void DestroyFont(GL gl, ref Font font)
- {
- font.texts.Clear();
- }
-
- public static void AddText(ref Font font, float x, float y, B2HexColor color, string text)
- {
- var fontText = new FontText();
- fontText.x = x;
- fontText.y = y;
- fontText.color = color;
- fontText.text = text;
-
- font.texts.Add(fontText);
- }
-
- public static void FlushText(GL gl, ref Font font, Camera camera)
- {
- if (0 >= font.texts.Count)
- return;
-
- ImGui.Begin("Overlay",
- ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.AlwaysAutoResize |
- ImGuiWindowFlags.NoScrollbar);
-
- foreach (var text in font.texts)
- {
- int hex = (int)text.color;
- float r = ((hex >> 16) & 0xFF) / 255.0f;
- float g = ((hex >> 8) & 0xFF) / 255.0f;
- float b = (hex & 0xFF) / 255.0f;
-
- ImGui.SetCursorPos(new Vector2(text.x, text.y));
- ImGui.TextColored(new Vector4(r, g, b, 1.0f), text.text);
- }
-
- ImGui.End();
- font.texts.Clear();
- }
-}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Graphics/FontsV1.cs b/src/Box2D.NET.Samples/Graphics/FontsV1.cs
deleted file mode 100644
index 4f8a3464..00000000
--- a/src/Box2D.NET.Samples/Graphics/FontsV1.cs
+++ /dev/null
@@ -1,237 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
-// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
-// SPDX-License-Identifier: MIT
-
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-using Silk.NET.OpenGL;
-using Box2D.NET.Samples.Helpers;
-using Box2D.NET.Samples.Primitives;
-using static Box2D.NET.Samples.Graphics.Cameras;
-using static Box2D.NET.B2Arrays;
-using static Box2D.NET.B2Diagnostics;
-
-namespace Box2D.NET.Samples.Graphics;
-
-public static class FontsV1
-{
- public const int FONT_FIRST_CHARACTER = 32;
- public const int FONT_CHARACTER_COUNT = 96;
- public const int FONT_ATLAS_WIDTH = 512;
- public const int FONT_ATLAS_HEIGHT = 512;
-
- // The number of vertices the vbo can hold. Must be a multiple of 6.
- public const int FONT_BATCH_SIZE = (6 * 10000);
-
- public struct stbtt_bakedchar
- {
- public ushort x0, y0, x1, y1; // coordinates of bbox in bitmap
- public float xoff, yoff, xadvance;
- }
-
- public struct stbtt_aligned_quad
- {
- public float x0;
- public float y0;
- public float s0;
- public float t0; // top-left
- public float x1;
- public float y1;
- public float s1;
- public float t1; // bottom-right
- }
-
-
- public static FontV1 CreateFont(GL gl, string trueTypeFile, float fontSize)
- {
- FontV1 font = new FontV1();
-
- if (!File.Exists(trueTypeFile))
- {
- B2_ASSERT(false);
- return font;
- }
-
-
- nint unmanagedPtr = 0;
- try
- {
- //FontDescription description = FontDescription.LoadDescription(trueTypeFile);
- font.vertices = b2Array_Create(FONT_BATCH_SIZE);
- font.fontSize = fontSize;
- font.characters = new byte[FONT_CHARACTER_COUNT * B2SizeOf.Size];
-
- int fileBufferCapacity = 1 << 20;
- byte[] fileBuffer = File.ReadAllBytes(trueTypeFile);
-
- int pw = FONT_ATLAS_WIDTH;
- int ph = FONT_ATLAS_HEIGHT;
- byte[] tempBitmap = new byte[pw * ph * B2SizeOf.Size];
- // stbtt_BakeFontBitmap(fileBuffer, 0, font.fontSize, tempBitmap, pw, ph, FONT_FIRST_CHARACTER, FONT_CHARACTER_COUNT,
- // font.characters);
-
- unmanagedPtr = Marshal.AllocHGlobal(tempBitmap.Length);
- Marshal.Copy(tempBitmap, 0, unmanagedPtr, tempBitmap.Length);
-
- gl.GenTextures(1, font.textureId);
- gl.BindTexture(GLEnum.Texture2D, font.textureId[0]);
- //gl.TexImage2D(GLEnum.Texture2D, 0, InternalFormat.R8, (uint)pw, (uint)ph, 0, PixelFormat.Red, PixelType.UnsignedByte, unmanagedPtr);
- gl.TexParameter(GLEnum.Texture2D, GLEnum.TextureMinFilter, (int)GLEnum.Linear);
-
- // for debugging
- // stbi_write_png( "build/fontAtlas.png", pw, ph, 1, tempBitmap, pw );
- }
- finally
- {
- Marshal.FreeHGlobal(unmanagedPtr);
- }
-
- font.programId = gl.CreateProgramFromFiles("data/font.vs", "data/font.fs");
- if (font.programId == 0)
- {
- return font;
- }
-
- // Setting up the VAO and VBO
- gl.GenBuffers(1, font.vboId);
- gl.BindBuffer(GLEnum.ArrayBuffer, font.vboId[0]);
- gl.BufferData(GLEnum.ArrayBuffer, FONT_BATCH_SIZE * (uint)B2SizeOf.Size, null, GLEnum.DynamicDraw);
-
- gl.GenVertexArrays(1, font.vaoId);
- gl.BindVertexArray(font.vaoId[0]);
-
- // position attribute
- gl.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, (uint)B2SizeOf.Size, IntPtr.Zero); // position
- gl.EnableVertexAttribArray(0);
-
- // uv attribute
- gl.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, (uint)B2SizeOf.Size, IntPtr.Zero + 8); // uv
- gl.EnableVertexAttribArray(1);
-
- // color attribute will be expanded to floats using normalization
- gl.VertexAttribPointer(2, 4, VertexAttribPointerType.UnsignedByte, true, (uint)B2SizeOf.Size, IntPtr.Zero + 16); // color
- gl.EnableVertexAttribArray(2);
-
- gl.BindVertexArray(0);
-
- gl.CheckOpenGL();
-
- return font;
- }
-
- public static void DestroyFont(GL gl, ref FontV1 font)
- {
- if (font.programId != 0)
- {
- gl.DeleteProgram(font.programId);
- }
-
- gl.DeleteBuffers(1, font.vboId);
- gl.DeleteVertexArrays(1, font.vaoId);
-
- if (font.textureId[0] != 0)
- {
- gl.DeleteTextures(1, font.textureId);
- }
-
- font.characters = null;
-
- b2Array_Destroy(ref font.vertices);
- }
-
- public static void AddText(ref FontV1 font, float x, float y, B2HexColor color, string text)
- {
- if (text == null)
- {
- return;
- }
-
- B2Vec2 position = new B2Vec2(x, y);
- RGBA8 c = RGBA8.MakeRGBA8(color, 1.0f);
- int pw = FONT_ATLAS_WIDTH;
- int ph = FONT_ATLAS_HEIGHT;
-
- for (int i = 0; i < text.Length; ++i)
- {
- int index = (int)text[i] - FONT_FIRST_CHARACTER;
-
- if (0 <= index && index < FONT_CHARACTER_COUNT)
- {
- // 1=opengl
- stbtt_aligned_quad q = new stbtt_aligned_quad();
- //stbtt_GetBakedQuad(font.characters, pw, ph, index, &position.x, &position.y, &q, 1);
-
- FontVertex v1 = new FontVertex(new B2Vec2(q.x0, q.y0), new B2Vec2(q.s0, q.t0), c);
- FontVertex v2 = new FontVertex(new B2Vec2(q.x1, q.y0), new B2Vec2(q.s1, q.t0), c);
- FontVertex v3 = new FontVertex(new B2Vec2(q.x1, q.y1), new B2Vec2(q.s1, q.t1), c);
- FontVertex v4 = new FontVertex(new B2Vec2(q.x0, q.y1), new B2Vec2(q.s0, q.t1), c);
-
- b2Array_Push(ref font.vertices, v1);
- b2Array_Push(ref font.vertices, v3);
- b2Array_Push(ref font.vertices, v2);
- b2Array_Push(ref font.vertices, v1);
- b2Array_Push(ref font.vertices, v4);
- b2Array_Push(ref font.vertices, v3);
- }
-
- i += 1;
- }
- }
-
- public static void FlushText(GL gl, ref FontV1 font, Camera camera)
- {
- var tempProjectionMatrix = new B2FixedArray16();
- Span projectionMatrix = tempProjectionMatrix.AsSpan();
- MakeOrthographicMatrix(projectionMatrix, 0.0f, camera.width, camera.height, 0.0f, -1.0f, 1.0f);
-
- gl.UseProgram(font.programId);
-
- gl.Enable(GLEnum.Blend);
- gl.BlendFunc(GLEnum.SrcAlpha, GLEnum.OneMinusSrcAlpha);
-
- int slot = 0;
- gl.ActiveTexture(GLEnum.Texture0 + slot);
- gl.BindTexture(GLEnum.Texture2D, font.textureId[0]);
-
- gl.BindVertexArray(font.vaoId[0]);
- gl.BindBuffer(GLEnum.ArrayBuffer, font.vboId[0]);
-
- int textureUniform = gl.GetUniformLocation(font.programId, "FontAtlas");
- gl.Uniform1(textureUniform, slot);
-
- int matrixUniform = gl.GetUniformLocation(font.programId, "ProjectionMatrix");
- gl.UniformMatrix4(matrixUniform, 1, false, projectionMatrix);
-
- int totalVertexCount = font.vertices.count;
- int drawCallCount = (totalVertexCount / FONT_BATCH_SIZE) + 1;
-
- for (int i = 0; i < drawCallCount; i++)
- {
- Span data = font.vertices.data.AsSpan(i * FONT_BATCH_SIZE);
-
- int vertexCount;
- if (i == drawCallCount - 1)
- {
- vertexCount = totalVertexCount % FONT_BATCH_SIZE;
- }
- else
- {
- vertexCount = FONT_BATCH_SIZE;
- }
-
- gl.BufferSubData(GLEnum.ArrayBuffer, 0, data);
- gl.DrawArrays(GLEnum.Triangles, 0, (uint)vertexCount);
- }
-
- gl.BindBuffer(GLEnum.ArrayBuffer, 0);
- gl.BindVertexArray(0);
- gl.BindTexture(GLEnum.Texture2D, 0);
-
- gl.Disable(GLEnum.Blend);
-
- gl.CheckOpenGL();
-
- font.vertices.count = 0;
- }
-}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Graphics/Lines.cs b/src/Box2D.NET.Samples/Graphics/Lines.cs
index 4ceedf8f..0e51f537 100644
--- a/src/Box2D.NET.Samples/Graphics/Lines.cs
+++ b/src/Box2D.NET.Samples/Graphics/Lines.cs
@@ -10,6 +10,7 @@
using static Box2D.NET.B2MathFunction;
using static Box2D.NET.B2Diagnostics;
using static Box2D.NET.Samples.Graphics.Cameras;
+using static Box2D.NET.Samples.EmbeddedShaders;
namespace Box2D.NET.Samples.Graphics;
@@ -23,7 +24,7 @@ public static class Lines
public static LineRender CreateLineRender(GL gl)
{
var render = new LineRender();
- render.m_programId = gl.CreateProgramFromFiles("data/line.vs", "data/line.fs");
+ render.m_programId = gl.CreateProgramFromStrings(k_line_vs, k_line_fs);
render.m_projectionUniform = gl.GetUniformLocation(render.m_programId, "projectionMatrix");
uint vertexAttribute = 0;
uint colorAttribute = 1;
@@ -126,4 +127,4 @@ public static void FlushLines(GL gl, ref LineRender render, Camera camera)
render.m_points.Clear();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Graphics/Points.cs b/src/Box2D.NET.Samples/Graphics/Points.cs
index 2012c730..ee46f937 100644
--- a/src/Box2D.NET.Samples/Graphics/Points.cs
+++ b/src/Box2D.NET.Samples/Graphics/Points.cs
@@ -9,6 +9,7 @@
using Box2D.NET.Samples.Primitives;
using static Box2D.NET.B2MathFunction;
using static Box2D.NET.Samples.Graphics.Cameras;
+using static Box2D.NET.Samples.EmbeddedShaders;
namespace Box2D.NET.Samples.Graphics;
@@ -19,7 +20,7 @@ public static class Points
public static PointRender CreatePointDrawData(GL gl)
{
PointRender render = new PointRender();
- render.programId = gl.CreateProgramFromFiles("data/point.vs", "data/point.fs");
+ render.programId = gl.CreateProgramFromStrings(k_point_vs, k_point_fs);
render.projectionUniform = gl.GetUniformLocation(render.programId, "projectionMatrix");
uint vertexAttribute = 0;
uint sizeAttribute = 1;
@@ -120,4 +121,4 @@ public static void FlushPoints(GL gl, ref PointRender render, Camera camera)
render.points.Clear();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Graphics/SolidCapsules.cs b/src/Box2D.NET.Samples/Graphics/SolidCapsules.cs
index b56f5a25..8511fbf0 100644
--- a/src/Box2D.NET.Samples/Graphics/SolidCapsules.cs
+++ b/src/Box2D.NET.Samples/Graphics/SolidCapsules.cs
@@ -10,6 +10,7 @@
using Serilog;
using static Box2D.NET.B2MathFunction;
using static Box2D.NET.Samples.Graphics.Cameras;
+using static Box2D.NET.Samples.EmbeddedShaders;
namespace Box2D.NET.Samples.Graphics;
@@ -23,7 +24,7 @@ public static class SolidCapsules
public static SolidCapsuleRender CreateSolidCapsule(GL gl)
{
var render = new SolidCapsuleRender();
- render.programId = gl.CreateProgramFromFiles("data/solid_capsule.vs", "data/solid_capsule.fs");
+ render.programId = gl.CreateProgramFromStrings(k_solid_capsule_vs, k_solid_capsule_fs);
render.projectionUniform = gl.GetUniformLocation(render.programId, "projectionMatrix");
render.pixelScaleUniform = gl.GetUniformLocation(render.programId, "pixelScale");
@@ -169,4 +170,4 @@ public static void FlushCapsules(GL gl, ref SolidCapsuleRender render, Camera ca
render.capsules.Clear();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Graphics/SolidCircles.cs b/src/Box2D.NET.Samples/Graphics/SolidCircles.cs
index 562c06a4..42beea57 100644
--- a/src/Box2D.NET.Samples/Graphics/SolidCircles.cs
+++ b/src/Box2D.NET.Samples/Graphics/SolidCircles.cs
@@ -9,6 +9,7 @@
using Box2D.NET.Samples.Primitives;
using static Box2D.NET.B2MathFunction;
using static Box2D.NET.Samples.Graphics.Cameras;
+using static Box2D.NET.Samples.EmbeddedShaders;
namespace Box2D.NET.Samples.Graphics;
@@ -22,7 +23,7 @@ public static class SolidCircles
public static SolidCircleRender CreateSolidCircles(GL gl)
{
var render = new SolidCircleRender();
- render.programId = gl.CreateProgramFromFiles("data/solid_circle.vs", "data/solid_circle.fs");
+ render.programId = gl.CreateProgramFromStrings(k_solid_circle_vs, k_solid_circle_fs);
render.projectionUniform = gl.GetUniformLocation(render.programId, "projectionMatrix");
render.pixelScaleUniform = gl.GetUniformLocation(render.programId, "pixelScale");
@@ -149,4 +150,4 @@ public static void FlushSolidCircles(GL gl, ref SolidCircleRender render, Camera
render.circles.Clear();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Graphics/SolidPolygons.cs b/src/Box2D.NET.Samples/Graphics/SolidPolygons.cs
index bdfbc899..99f0f9bc 100644
--- a/src/Box2D.NET.Samples/Graphics/SolidPolygons.cs
+++ b/src/Box2D.NET.Samples/Graphics/SolidPolygons.cs
@@ -9,6 +9,7 @@
using Box2D.NET.Samples.Primitives;
using static Box2D.NET.B2MathFunction;
using static Box2D.NET.Samples.Graphics.Cameras;
+using static Box2D.NET.Samples.EmbeddedShaders;
namespace Box2D.NET.Samples.Graphics;
@@ -20,7 +21,7 @@ public static class SolidPolygons
public static SolidPolygonRender CreateSolidPolygons(GL gl)
{
var render = new SolidPolygonRender();
- render.programId = gl.CreateProgramFromFiles("data/solid_polygon.vs", "data/solid_polygon.fs");
+ render.programId = gl.CreateProgramFromStrings(k_solid_polygon_vs, k_solid_polygon_fs);
render.projectionUniform = gl.GetUniformLocation(render.programId, "projectionMatrix");
render.pixelScaleUniform = gl.GetUniformLocation(render.programId, "pixelScale");
@@ -177,4 +178,4 @@ public static void FlushPolygons(GL gl, ref SolidPolygonRender render, Camera ca
render.polygons.Clear();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Primitives/FontText.cs b/src/Box2D.NET.Samples/Primitives/FontText.cs
deleted file mode 100644
index 18e663ec..00000000
--- a/src/Box2D.NET.Samples/Primitives/FontText.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Box2D.NET.Samples.Primitives;
-
-public struct FontText
-{
- public float x;
- public float y;
- public B2HexColor color;
- public string text;
-}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Primitives/FontVertex.cs b/src/Box2D.NET.Samples/Primitives/FontVertex.cs
deleted file mode 100644
index 8954f3ec..00000000
--- a/src/Box2D.NET.Samples/Primitives/FontVertex.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
-// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
-// SPDX-License-Identifier: MIT
-
-namespace Box2D.NET.Samples.Primitives;
-
-public struct FontVertex
-{
- public B2Vec2 position;
- public B2Vec2 uv;
- public RGBA8 color;
-
- public FontVertex(B2Vec2 position, B2Vec2 uv, RGBA8 color)
- {
- this.position = position;
- this.uv = uv;
- this.color = color;
- }
-}
diff --git a/src/Box2D.NET.Samples/SampleApp.cs b/src/Box2D.NET.Samples/SampleApp.cs
index d6eae905..b14a2178 100644
--- a/src/Box2D.NET.Samples/SampleApp.cs
+++ b/src/Box2D.NET.Samples/SampleApp.cs
@@ -47,6 +47,9 @@ public class SampleApp
private B2Vec2 s_clickPointWS = b2Vec2_zero;
private float s_framebufferScale = 1.0f;
private float _frameTime = 0.0f;
+ private double _frameStartTime = 0.0;
+ private byte[] _fontData;
+ private GCHandle _fontDataHandle;
public SampleApp()
{
@@ -241,13 +244,12 @@ private void OnWindowLoad()
_context.glfw.SetScrollCallback(_context.window, ScrollCallback);
}
+ // todo put this in _context.settings
+ CreateUI(glslVersion);
_context.draw = CreateDraw(_context);
_context.sampleIndex = b2ClampInt(_context.sampleIndex, 0, SampleFactory.Shared.SampleCount - 1);
- // todo put this in _context.settings
- CreateUI(glslVersion);
-
_context.gl.ClearColor(0.2f, 0.2f, 0.2f, 1.0f);
}
@@ -271,7 +273,7 @@ private void OnWindowUpdate(double dt)
return;
}
- double time1 = _context.glfw.GetTime();
+ _frameStartTime = _context.glfw.GetTime();
if (GlfwHelpers.GetKey(_context, Keys.Z) == InputAction.Press)
{
@@ -297,30 +299,6 @@ private void OnWindowUpdate(double dt)
_context.glfw.GetCursorPos(_context.window, out cursorPosX, out cursorPosY);
}
- // For the Tracy profiler
- //FrameMark;
-
- if (_context.sample == null)
- {
- // delayed creation because imgui doesn't create fonts until NewFrame() is called
- _context.sample = SampleFactory.Shared.Create(_context.sampleIndex, _context);
- }
-
- _context.sample.Step();
-
- _context.glfw.PollEvents();
-
- // Limit frame rate to 60Hz
- double time2 = _context.glfw.GetTime();
- double targetTime = time1 + 1.0 / 60.0;
- while (time2 < targetTime)
- {
- b2Yield();
- time2 = _context.glfw.GetTime();
- }
-
- _frameTime = (float)(time2 - time1);
-
// ImGui_ImplGlfw_CursorPosCallback(_ctx.g_mainWindow, cursorPosX / s_windowScale, cursorPosY / s_windowScale);
// ImGui_ImplOpenGL3_NewFrame();
// ImGui_ImplGlfw_NewFrame();
@@ -333,6 +311,30 @@ private void OnWindowUpdate(double dt)
io.DeltaTime = (float)dt;
_imgui.Update((float)dt);
}
+
+ if (_context.sample == null)
+ {
+ // delayed creation because imgui doesn't create fonts until NewFrame() is called
+ _context.sample = SampleFactory.Shared.Create(_context.sampleIndex, _context);
+ }
+
+ _context.sample.ResetText();
+
+ if (_context.showUI)
+ {
+ _context.sample.DrawColoredTextLine(B2HexColor.b2_colorGoldenRod, SampleFactory.Shared.GetName(_context.sampleIndex));
+ _context.sample.DrawColoredTextLine(B2HexColor.b2_colorLightGray, SampleFactory.Shared.GetCategory(_context.sampleIndex));
+ _context.sample.DrawTextLine("");
+ _context.sample.DrawColoredTextLine(B2HexColor.b2_colorSeaGreen, $"{1000.0f * _frameTime:0.0} ms");
+ _context.sample.DrawColoredTextLine(B2HexColor.b2_colorSeaGreen, $"step {_context.sample.m_stepCount}");
+ _context.sample.DrawTextLine("");
+ _context.sample.DrawColoredTextLine(B2HexColor.b2_colorSeaGreen,
+ $"cam ({_context.camera.center.X:0.0}, {_context.camera.center.Y:0.0})");
+ _context.sample.DrawColoredTextLine(B2HexColor.b2_colorSeaGreen, $"zoom {_context.camera.zoom:0.00}");
+ }
+
+ _context.sample.Step();
+ _context.sample.Draw();
}
private void OnWindowRenderSafe(double dt)
@@ -351,22 +353,15 @@ private void OnWindowRender(double dt)
{
_context.gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
- ImGui.SetNextWindowPos(new Vector2(0.0f, 0.0f));
- ImGui.SetNextWindowSize(new Vector2(_context.camera.width, _context.camera.height));
- ImGui.SetNextWindowBgAlpha(0.0f);
- ImGui.Begin("Overlay", ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoScrollbar);
- ImGui.End();
-
- _context.sample.ResetText();
-
- var title = SampleFactory.Shared.GetTitle(_context.sampleIndex);
- _context.sample.DrawColoredTextLine(B2HexColor.b2_colorYellow, title);
-
- string buffer = $"{1000.0f * _frameTime:0.0} ms - step {_context.sample.m_stepCount} - " +
- $"camera ({_context.camera.center.X:G}, {_context.camera.center.Y:G}, {_context.camera.zoom:G})";
- DrawScreenString(_context.draw, 5.0f, _context.camera.height - 18.0f, B2HexColor.b2_colorSeaGreen, buffer);
+ if (_context.showUI == false)
+ {
+ float fontSize = ImGui.GetFontSize();
+ DrawScreenString(_context.draw, 5.0f, 1.5f * fontSize, B2HexColor.b2_colorYellow,
+ $"{SampleFactory.Shared.GetCategory(_context.sampleIndex)} : {SampleFactory.Shared.GetName(_context.sampleIndex)}");
+ DrawScreenString(_context.draw, 5.0f, _context.camera.height - 0.5f * fontSize, B2HexColor.b2_colorSeaGreen,
+ $"{1000.0f * _frameTime:0.0} ms step {_context.sample.m_stepCount}");
+ }
- _context.sample.Draw();
FlushDraw(_context.draw, _context.camera);
UpdateSampleUI(_context);
@@ -380,6 +375,22 @@ private void OnWindowRender(double dt)
{
_context.glfw.SwapBuffers(_context.window);
}
+
+ // For the Tracy profiler
+ //FrameMark;
+
+ // Silk.NET.Windowing polls events for the run loop.
+
+ // Limit frame rate to 60Hz
+ double time2 = _context.glfw.GetTime();
+ double targetTime = _frameStartTime + 1.0 / 60.0;
+ while (time2 < targetTime)
+ {
+ b2Yield();
+ time2 = _context.glfw.GetTime();
+ }
+
+ _frameTime = (float)(time2 - _frameStartTime);
}
@@ -426,6 +437,90 @@ private void glfwErrorCallback(ErrorCode error, string description)
Logger.Information($"GLFW error occurred. Code: {error}. Description: {description}");
}
+ private static void ApplyUIStyle()
+ {
+ ImGuiStylePtr style = ImGui.GetStyle();
+
+ // Metrics: containers round at 4px, controls at 3px - one deliberate
+ // system instead of the stock mix. Padding gives rows room to breathe.
+ style.WindowPadding = new Vector2(10.0f, 10.0f);
+ style.FramePadding = new Vector2(8.0f, 4.0f);
+ style.CellPadding = new Vector2(6.0f, 4.0f);
+ style.ItemSpacing = new Vector2(8.0f, 7.0f);
+ style.ItemInnerSpacing = new Vector2(7.0f, 4.0f);
+ style.IndentSpacing = 18.0f;
+ style.ScrollbarSize = 12.0f;
+ style.GrabMinSize = 10.0f;
+
+ style.WindowBorderSize = 1.0f;
+ style.FrameBorderSize = 0.0f;
+ style.PopupBorderSize = 1.0f;
+ style.TabBorderSize = 0.0f;
+ style.SeparatorTextBorderSize = 1.0f;
+
+ style.WindowRounding = 4.0f;
+ style.ChildRounding = 4.0f;
+ style.PopupRounding = 4.0f;
+ style.FrameRounding = 3.0f;
+ style.GrabRounding = 3.0f;
+ style.ScrollbarRounding = 3.0f;
+ style.TabRounding = 3.0f;
+
+ style.WindowTitleAlign = new Vector2(0.0f, 0.5f);
+
+ // Palette: neutral charcoal surfaces, one steel-blue accent at three
+ // brightnesses. Replaces stock ImGui's saturated cornflower blue.
+ Vector4 accent = new Vector4(0.28f, 0.48f, 0.66f, 1.00f);
+ Vector4 accentHi = new Vector4(0.38f, 0.60f, 0.80f, 1.00f);
+ Vector4 accentLo = new Vector4(0.22f, 0.36f, 0.50f, 1.00f);
+
+ style.Colors[(int)ImGuiCol.Text] = new Vector4(0.90f, 0.91f, 0.93f, 1.00f);
+ style.Colors[(int)ImGuiCol.TextDisabled] = new Vector4(0.49f, 0.51f, 0.55f, 1.00f);
+ style.Colors[(int)ImGuiCol.WindowBg] = new Vector4(0.110f, 0.115f, 0.125f, 0.97f);
+ style.Colors[(int)ImGuiCol.ChildBg] = new Vector4(0.00f, 0.00f, 0.00f, 0.00f);
+ style.Colors[(int)ImGuiCol.PopupBg] = new Vector4(0.100f, 0.105f, 0.115f, 0.98f);
+ style.Colors[(int)ImGuiCol.Border] = new Vector4(0.00f, 0.00f, 0.00f, 0.45f);
+ style.Colors[(int)ImGuiCol.BorderShadow] = new Vector4(0.00f, 0.00f, 0.00f, 0.00f);
+ style.Colors[(int)ImGuiCol.FrameBg] = new Vector4(0.18f, 0.19f, 0.21f, 1.00f);
+ style.Colors[(int)ImGuiCol.FrameBgHovered] = new Vector4(0.24f, 0.26f, 0.29f, 1.00f);
+ style.Colors[(int)ImGuiCol.FrameBgActive] = new Vector4(0.29f, 0.32f, 0.36f, 1.00f);
+ style.Colors[(int)ImGuiCol.TitleBg] = new Vector4(0.090f, 0.095f, 0.105f, 1.00f);
+ style.Colors[(int)ImGuiCol.TitleBgActive] = new Vector4(0.14f, 0.16f, 0.19f, 1.00f);
+ style.Colors[(int)ImGuiCol.TitleBgCollapsed] = new Vector4(0.090f, 0.095f, 0.105f, 0.75f);
+ style.Colors[(int)ImGuiCol.MenuBarBg] = new Vector4(0.13f, 0.14f, 0.16f, 1.00f);
+ style.Colors[(int)ImGuiCol.ScrollbarBg] = new Vector4(0.06f, 0.06f, 0.07f, 0.55f);
+ style.Colors[(int)ImGuiCol.ScrollbarGrab] = new Vector4(0.28f, 0.30f, 0.33f, 1.00f);
+ style.Colors[(int)ImGuiCol.ScrollbarGrabHovered] = new Vector4(0.36f, 0.39f, 0.43f, 1.00f);
+ style.Colors[(int)ImGuiCol.ScrollbarGrabActive] = accent;
+ style.Colors[(int)ImGuiCol.CheckMark] = accentHi;
+ style.Colors[(int)ImGuiCol.SliderGrab] = accent;
+ style.Colors[(int)ImGuiCol.SliderGrabActive] = accentHi;
+ style.Colors[(int)ImGuiCol.Button] = new Vector4(0.22f, 0.24f, 0.27f, 1.00f);
+ style.Colors[(int)ImGuiCol.ButtonHovered] = accentLo;
+ style.Colors[(int)ImGuiCol.ButtonActive] = accent;
+ style.Colors[(int)ImGuiCol.Header] = new Vector4(0.19f, 0.21f, 0.24f, 1.00f);
+ style.Colors[(int)ImGuiCol.HeaderHovered] = accentLo;
+ style.Colors[(int)ImGuiCol.HeaderActive] = accent;
+ style.Colors[(int)ImGuiCol.Separator] = new Vector4(1.00f, 1.00f, 1.00f, 0.09f);
+ style.Colors[(int)ImGuiCol.SeparatorHovered] = accentLo;
+ style.Colors[(int)ImGuiCol.SeparatorActive] = accent;
+ style.Colors[(int)ImGuiCol.ResizeGrip] = new Vector4(1.00f, 1.00f, 1.00f, 0.06f);
+ style.Colors[(int)ImGuiCol.ResizeGripHovered] = accentLo;
+ style.Colors[(int)ImGuiCol.ResizeGripActive] = accent;
+ style.Colors[(int)ImGuiCol.Tab] = new Vector4(0.15f, 0.16f, 0.18f, 1.00f);
+ style.Colors[(int)ImGuiCol.TabHovered] = accentLo;
+ style.Colors[(int)ImGuiCol.TabActive] = accent;
+ style.Colors[(int)ImGuiCol.TabUnfocused] = new Vector4(0.12f, 0.13f, 0.14f, 1.00f);
+ style.Colors[(int)ImGuiCol.TabUnfocusedActive] = accentLo;
+ style.Colors[(int)ImGuiCol.TextSelectedBg] = new Vector4(accent.X, accent.Y, accent.Z, 0.40f);
+ style.Colors[(int)ImGuiCol.DragDropTarget] = accentHi;
+ style.Colors[(int)ImGuiCol.NavHighlight] = accentHi;
+ style.Colors[(int)ImGuiCol.PlotLines] = new Vector4(0.70f, 0.72f, 0.75f, 1.00f);
+ style.Colors[(int)ImGuiCol.PlotLinesHovered] = accentHi;
+ style.Colors[(int)ImGuiCol.PlotHistogram] = accent;
+ style.Colors[(int)ImGuiCol.PlotHistogramHovered] = accentHi;
+ }
+
private void CreateUI(string glslVersion)
{
//IMGUI_CHECKVERSION();
@@ -446,39 +541,45 @@ private void CreateUI(string glslVersion)
// }
//
- var fontPath = Path.Combine("data", "droid_sans.ttf");
- if (!File.Exists(fontPath))
+ if (_context.uiScale != 1.0f)
{
- Logger.Information("ERROR: the Box2D samples working directory must be the top level Box2D directory (same as README.md)");
- //exit(EXIT_FAILURE);
- return;
+ // ImGui.NET 1.90 does not expose AddFontDefaultVector, so use the existing font as an embedded resource.
+ using Stream stream = typeof(SampleApp).Assembly.GetManifestResourceStream("Box2D.NET.Samples.Fonts.droid_sans.ttf")!;
+ _fontData = new byte[stream.Length];
+ stream.ReadExactly(_fontData);
+ _fontDataHandle = GCHandle.Alloc(_fontData, GCHandleType.Pinned);
}
// for windows : Microsoft Visual C++ Redistributable Package
// link - https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist
- var imGuiFontConfig = new ImGuiFontConfig(fontPath, 15, null);
- _imgui = new ImGuiController(_context.gl, _window, _input, imGuiFontConfig);
+ _imgui = new ImGuiController(_context.gl, _window, _input, () =>
+ {
+ ApplyUIStyle();
- ImGui.GetFontSize();
- ImGui.GetStyle().ScaleAllSizes(_context.uiScale);
+ ImGuiIOPtr io = ImGui.GetIO();
+ if (_context.uiScale == 1.0f)
+ {
+ io.Fonts.AddFontDefault();
+ }
+ else
+ {
+ unsafe
+ {
+ ImFontConfigPtr fontConfig = new ImFontConfigPtr(ImGuiNative.ImFontConfig_ImFontConfig());
+ // This brightens the font, improving readability when it is small.
+ fontConfig.RasterizerMultiply = _context.uiScale * s_framebufferScale;
+ fontConfig.FontDataOwnedByAtlas = false;
+
+ float regularSize = MathF.Floor(13.0f * _context.uiScale);
+ io.Fonts.AddFontFromMemoryTTF(_fontDataHandle.AddrOfPinnedObject(), _fontData.Length, regularSize, fontConfig);
+ ImGuiNative.ImFontConfig_destroy(fontConfig.NativePtr);
+ }
+ }
+ });
- unsafe
+ if (_context.uiScale != 1.0f)
{
- // ImFontConfigPtr fontConfig = new ImFontConfigPtr(ImGuiNative.ImFontConfig_ImFontConfig());
- // This brightens the font, improving readability when it is small.
- // fontConfig.RasterizerMultiply = _context.uiScale * s_framebufferScale;
- //
- // float regularSize = MathF.Floor(13.0f * _context.uiScale);
- // float mediumSize = MathF.Floor(40.0f * _context.uiScale);
- // float largeSize = MathF.Floor(64.0f * _context.uiScale);
- //
- // var io = ImGui.GetIO();
- //_context.regularFont = io.Fonts.AddFontFromFileTTF(fontPath, regularSize);
- //_context.regularFont = io.Fonts.AddFontFromFileTTF(fontPath, regularSize, fontConfig);
- // _context.mediumFont = io.Fonts.AddFontFromFileTTF(fontPath, mediumSize, fontConfig);
- // _context.largeFont = io.Fonts.AddFontFromFileTTF(fontPath, largeSize, fontConfig);
-
- //io.FontDefault = _context.regularFont;
+ ImGui.GetStyle().ScaleAllSizes(_context.uiScale);
}
}
@@ -487,6 +588,11 @@ public void DestroyUI()
var tmp = _imgui;
_imgui = null;
tmp.Dispose();
+ if (_fontDataHandle.IsAllocated)
+ {
+ _fontDataHandle.Free();
+ }
+ _fontData = null;
}
private unsafe void KeyCallback(WindowHandle* window, Keys key, int scancode, InputAction action, KeyModifiers mods)
@@ -576,7 +682,15 @@ private unsafe void KeyCallback(WindowHandle* window, Keys key, int scancode, In
break;
case Keys.O:
- _context.singleStep = true;
+ if (mods == KeyModifiers.Control)
+ {
+ _context.showUI = true;
+ _context.openSamplePicker = true;
+ }
+ else
+ {
+ _context.singleStep = true;
+ }
break;
case Keys.P:
@@ -615,6 +729,10 @@ private unsafe void KeyCallback(WindowHandle* window, Keys key, int scancode, In
_context.showUI = !_context.showUI;
break;
+ case Keys.M:
+ _context.showDiagnostics = !_context.showDiagnostics;
+ break;
+
default:
if (_context.sample != null)
{
diff --git a/src/Box2D.NET.Samples/SampleContext.cs b/src/Box2D.NET.Samples/SampleContext.cs
index 4798fe17..dfd32457 100644
--- a/src/Box2D.NET.Samples/SampleContext.cs
+++ b/src/Box2D.NET.Samples/SampleContext.cs
@@ -7,12 +7,12 @@
using System.Runtime.CompilerServices;
using Box2D.NET.Samples.Graphics;
using Box2D.NET.Samples.Samples;
-using ImGuiNET;
using Silk.NET.GLFW;
using Silk.NET.OpenGL;
using static Box2D.NET.B2Types;
using static Box2D.NET.B2Constants;
using static Box2D.NET.Samples.Graphics.Backgrounds;
+using static Box2D.NET.Samples.Graphics.Cameras;
using static Box2D.NET.Samples.Graphics.Draws;
namespace Box2D.NET.Samples;
@@ -29,9 +29,6 @@ public class SampleContext
public Sample sample = null;
public B2Capacity capacity;
public B2DebugDraw debugDraw;
- public ImFontPtr regularFont;
- public ImFontPtr mediumFont;
- public ImFontPtr largeFont;
public float uiScale = 1.0f;
public float hertz = 60.0f;
@@ -41,13 +38,16 @@ public class SampleContext
public bool restart = false;
public bool pause = false;
public bool singleStep = false;
- public bool drawCounters = false;
- public bool drawProfile = false;
public bool enableWarmStarting = true;
public bool enableContinuous = true;
public bool enableSleep = true;
public bool showUI = true;
- public bool frameTime = false;
+
+ // Diagnostics drawer visibility. D toggles.
+ public bool showDiagnostics = false;
+
+ // Set by Ctrl+O; consumed by UpdateSampleUI to open the fuzzy sample picker.
+ public bool openSamplePicker = false;
// These are persisted
public int sampleIndex = 0;
@@ -61,7 +61,7 @@ private SampleContext(string signature, Glfw glfw)
{
Signature = signature;
this.glfw = glfw;
- camera = new Camera();
+ camera = GetDefaultCamera();
draw = new Draw();
showUI = true;
@@ -83,9 +83,6 @@ private SampleContext(string signature, Glfw glfw)
debugDraw.context = this;
- mediumFont = default;
- largeFont = default;
- regularFont = default;
}
public void Load()
@@ -94,45 +91,11 @@ public void Load()
var settings = Settings.Load();
- //
- camera.width = settings.windowWidth;
- camera.height = settings.windowHeight;
-
- //
- uiScale = settings.uiScale;
- hertz = settings.hertz;
- subStepCount = settings.subStepCount;
- workerCount = settings.workerCount;
-
//
sampleIndex = settings.sampleIndex;
debugDraw.drawShapes = settings.drawShapes;
- debugDraw.drawChainNormals = settings.drawChainNormals;
debugDraw.drawJoints = settings.drawJoints;
-
- //
- debugDraw.drawShapes = settings.drawShapes;
- debugDraw.drawChainNormals = settings.drawChainNormals;
- debugDraw.drawJoints = settings.drawJoints;
- debugDraw.drawJointExtras = settings.drawJointExtras;
- debugDraw.drawBounds = settings.drawBounds;
- debugDraw.drawMass = settings.drawMass;
- debugDraw.drawGraphColors = settings.drawGraphColors;
- debugDraw.drawContactNormals = settings.drawContactNormals;
- debugDraw.drawContactForces = settings.drawContactForces;
- debugDraw.drawContactFeatures = settings.drawContactFeatures;
- debugDraw.drawFrictionForces = settings.drawFrictionForces;
- debugDraw.drawIslands = settings.drawIslands;
- drawCounters = settings.drawCounters;
- drawProfile = settings.drawProfile;
- frameTime = settings.frameTime;
- enableWarmStarting = settings.enableWarmStarting;
- enableContinuous = settings.enableContinuous;
- enableSleep = settings.enableSleep;
-
- //
- debugDraw.jointScale = settings.jointScale;
- debugDraw.forceScale = settings.forceScale;
+ showDiagnostics = settings.showDiagnostics;
}
diff --git a/src/Box2D.NET.Samples/SampleText.cs b/src/Box2D.NET.Samples/SampleText.cs
new file mode 100644
index 00000000..0a360d41
--- /dev/null
+++ b/src/Box2D.NET.Samples/SampleText.cs
@@ -0,0 +1,30 @@
+// SPDX-FileCopyrightText: 2026 Ikpil Choi(ikpil@naver.com)
+// SPDX-License-Identifier: MIT
+
+using System.Globalization;
+
+namespace Box2D.NET.Samples;
+
+public static class SampleText
+{
+ public static string FormatFloat(float value)
+ {
+ if (float.IsNaN(value))
+ {
+ return "nan";
+ }
+
+ if (float.IsPositiveInfinity(value))
+ {
+ return "inf";
+ }
+
+ if (float.IsNegativeInfinity(value))
+ {
+ return "-inf";
+ }
+
+ // C printf("%g") defaults to six significant digits and is not affected by the current .NET culture.
+ return value.ToString("g6", CultureInfo.InvariantCulture);
+ }
+}
diff --git a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkBarrel.cs b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkBarrel.cs
index c3b2ff71..864f761e 100644
--- a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkBarrel.cs
+++ b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkBarrel.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -302,16 +302,9 @@ void CreateScene()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 6.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(15.0f * fontSize, height));
-
- ImGui.Begin("Benchmark: Barrel", ImGuiWindowFlags.NoResize);
bool changed = false;
string[] shapeTypes = ["Circle", "Capsule", "Mix", "Compound", "Human"];
@@ -333,6 +326,6 @@ public override void UpdateGui()
CreateScene();
}
- ImGui.End();
+
}
}
diff --git a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkCast.cs b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkCast.cs
index 90824d54..b6f094e5 100644
--- a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkCast.cs
+++ b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkCast.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -321,18 +321,11 @@ public override void Step()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 17.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(13.0f * fontSize, height));
- ImGui.Begin("Cast", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
-
- ImGui.PushItemWidth(7.5f * fontSize);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
bool changed = false;
@@ -378,6 +371,8 @@ public override void UpdateGui()
changed = true;
}
+ ImGui.PopItemWidth();
+
if (ImGui.Checkbox("top down", ref m_topDown))
{
changed = true;
@@ -388,9 +383,6 @@ public override void UpdateGui()
m_drawIndex = (m_drawIndex + 1) % m_origins.Count;
}
- ImGui.PopItemWidth();
- ImGui.End();
-
if (changed)
{
BuildScene();
@@ -404,7 +396,7 @@ public override void Draw()
DrawTextLine($"build time ms = {m_buildTime:g}");
- DrawTextLine($"hit count = {hitCount}, node visits = {nodeVisits}, leaf visits = {leafVisits}");
+ DrawScreenTextLine($"hit count = {hitCount}, node visits = {nodeVisits}, leaf visits = {leafVisits}");
DrawTextLine($"total ms = {ms:F3}");
diff --git a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkCreateDestroy.cs b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkCreateDestroy.cs
index 37158e72..c22400bb 100644
--- a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkCreateDestroy.cs
+++ b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkCreateDestroy.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -10,6 +10,7 @@
using static Box2D.NET.B2Worlds;
using static Box2D.NET.B2Timers;
using static Box2D.NET.B2Diagnostics;
+using static Box2D.NET.Samples.SampleText;
namespace Box2D.NET.Samples.Samples.Benchmarks;
@@ -138,11 +139,11 @@ public override void Draw()
{
base.Draw();
- DrawTextLine($"total: create = {m_createTime} ms, destroy = {m_destroyTime} ms");
+ DrawScreenTextLine($"total: create = {FormatFloat(m_createTime)} ms, destroy = {FormatFloat(m_destroyTime)} ms");
float createPerBody = 1000.0f * m_createTime / m_iterations / m_bodyCount;
float destroyPerBody = 1000.0f * m_destroyTime / m_iterations / m_bodyCount;
- DrawTextLine($"body: create = {createPerBody} us, destroy = {destroyPerBody} us");
+ DrawScreenTextLine($"body: create = {FormatFloat(createPerBody)} us, destroy = {FormatFloat(destroyPerBody)} us");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkManyTumblers.cs b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkManyTumblers.cs
index e79e3efc..9cf6433d 100644
--- a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkManyTumblers.cs
+++ b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkManyTumblers.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -138,16 +138,10 @@ void CreateScene()
m_bodyIndex = 0;
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 8.5f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(15.5f * fontSize, height));
- ImGui.Begin("Benchmark: Many Tumblers", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(8.0f * fontSize);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
bool changed = false;
changed = changed || ImGui.SliderInt("Row Count", ref m_rowCount, 1, 32);
@@ -168,7 +162,7 @@ public override void UpdateGui()
}
ImGui.PopItemWidth();
- ImGui.End();
+
}
public override void Step()
diff --git a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkSensor.cs b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkSensor.cs
index d34dce2e..5e019c2c 100644
--- a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkSensor.cs
+++ b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkSensor.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -240,7 +240,7 @@ public override void Draw()
{
base.Draw();
- DrawTextLine($"max begin touch events = {m_maxBeginCount}");
- DrawTextLine($"max end touch events = {m_maxEndCount}");
+ DrawScreenTextLine($"max begin touch events = {m_maxBeginCount}");
+ DrawScreenTextLine($"max end touch events = {m_maxEndCount}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkShapeDistance.cs b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkShapeDistance.cs
index d24b56c3..bd297931 100644
--- a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkShapeDistance.cs
+++ b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkShapeDistance.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -11,6 +11,7 @@
using static Box2D.NET.B2Distances;
using static Box2D.NET.B2Timers;
using static Box2D.NET.Samples.Graphics.Draws;
+using static Box2D.NET.Samples.SampleText;
namespace Box2D.NET.Samples.Samples.Benchmarks;
@@ -97,17 +98,11 @@ public override void Dispose()
m_outputs = null;
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 5.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(17.0f * fontSize, height));
- ImGui.Begin("Benchmark: Shape Distance", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderInt("draw index", ref m_drawIndex, 0, m_count - 1);
-
- ImGui.End();
+ ImGui.PopItemWidth();
}
public override void Step()
@@ -145,7 +140,7 @@ public override void Draw()
if (m_context.pause == false || m_context.singleStep == true)
{
DrawTextLine($"count = {m_count}");
- DrawTextLine($"min ms = {m_minMilliseconds}, ave us = {1000.0f * m_minMilliseconds / (float)m_count}");
+ DrawScreenTextLine($"min ms = {FormatFloat(m_minMilliseconds)}, ave us = {FormatFloat(1000.0f * m_minMilliseconds / (float)m_count)}");
DrawTextLine($"average iterations = {totalIterations / (float)m_count}");
}
diff --git a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkSmash.cs b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkSmash.cs
index 9d1979cf..d7fc6ef5 100644
--- a/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkSmash.cs
+++ b/src/Box2D.NET.Samples/Samples/Benchmarks/BenchmarkSmash.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -54,14 +54,9 @@ private void CreateScene()
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float height = 110.0f;
- ImGui.SetNextWindowPos(new Vector2(10.0f, m_camera.height - height - 50.0f), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(220.0f, height));
- ImGui.Begin("Benchmark: Smash", ImGuiWindowFlags.NoResize);
bool changed = false;
if (ImGui.SliderInt("rows", ref m_rowCount, 1, MaxRowCount, "%d"))
@@ -84,6 +79,6 @@ public override void UpdateGui()
CreateScene();
}
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Bodies/BadBody.cs b/src/Box2D.NET.Samples/Samples/Bodies/BadBody.cs
index b7ce49a1..ddd08ac8 100644
--- a/src/Box2D.NET.Samples/Samples/Bodies/BadBody.cs
+++ b/src/Box2D.NET.Samples/Samples/Bodies/BadBody.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -86,9 +86,9 @@ public override void Draw()
{
base.Draw();
- DrawTextLine("A bad body is a dynamic body with no mass and behaves like a kinematic body.");
+ DrawScreenTextLine("A bad body is a dynamic body with no mass and behaves like a kinematic body.");
- DrawTextLine("Bad bodies are considered invalid and a user bug. Behavior is not guaranteed.");
+ DrawScreenTextLine("Bad bodies are considered invalid and a user bug. Behavior is not guaranteed.");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Bodies/BodyType.cs b/src/Box2D.NET.Samples/Samples/Bodies/BodyType.cs
index 09351df1..a23475ba 100644
--- a/src/Box2D.NET.Samples/Samples/Bodies/BodyType.cs
+++ b/src/Box2D.NET.Samples/Samples/Bodies/BodyType.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -220,15 +220,9 @@ public BodyType(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 11.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(9.0f * fontSize, height));
- ImGui.Begin("Body Type", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
if (ImGui.RadioButton("Static", m_type == B2BodyType.b2_staticBody))
{
@@ -281,7 +275,7 @@ public override void UpdateGui()
}
}
- ImGui.End();
+
}
public override void Step()
diff --git a/src/Box2D.NET.Samples/Samples/Bodies/Pivot.cs b/src/Box2D.NET.Samples/Samples/Bodies/Pivot.cs
index 2037e686..533331a6 100644
--- a/src/Box2D.NET.Samples/Samples/Bodies/Pivot.cs
+++ b/src/Box2D.NET.Samples/Samples/Bodies/Pivot.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -8,6 +8,7 @@
using static Box2D.NET.B2MathFunction;
using static Box2D.NET.B2Bodies;
using static Box2D.NET.B2Shapes;
+using static Box2D.NET.Samples.SampleText;
namespace Box2D.NET.Samples.Samples.Bodies;
@@ -76,7 +77,7 @@ public override void Draw()
B2Vec2 r = b2Body_GetWorldVector(m_bodyId, new B2Vec2(0.0f, -m_lever));
B2Vec2 vp = v + b2CrossSV(omega, r);
- DrawTextLine($"pivot velocity = ({vp.X:g}, {vp.Y:g})");
+ DrawScreenTextLine($"pivot velocity = ({FormatFloat(vp.X)}, {FormatFloat(vp.Y)})");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Bodies/Sleep.cs b/src/Box2D.NET.Samples/Samples/Bodies/Sleep.cs
index 531fc8e0..a259c261 100644
--- a/src/Box2D.NET.Samples/Samples/Bodies/Sleep.cs
+++ b/src/Box2D.NET.Samples/Samples/Bodies/Sleep.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -171,17 +171,11 @@ void ToggleInvoker()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 160.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
- ImGui.Begin("Sleep", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(120.0f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.Text("Pendulum Tuning");
@@ -217,7 +211,7 @@ public override void UpdateGui()
}
}
- ImGui.End();
+
}
public override void Step()
diff --git a/src/Box2D.NET.Samples/Samples/Bodies/WakeTouching.cs b/src/Box2D.NET.Samples/Samples/Bodies/WakeTouching.cs
index aa512ce2..7f0170d1 100644
--- a/src/Box2D.NET.Samples/Samples/Bodies/WakeTouching.cs
+++ b/src/Box2D.NET.Samples/Samples/Bodies/WakeTouching.cs
@@ -64,20 +64,15 @@ public WakeTouching(SampleContext context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 5.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(10.0f * fontSize, height));
- ImGui.Begin("Wake Touching", ImGuiWindowFlags.NoResize);
if (ImGui.Button("Wake Touching"))
{
b2Body_WakeTouching(m_groundId);
}
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Bodies/Weeble.cs b/src/Box2D.NET.Samples/Samples/Bodies/Weeble.cs
index 01728325..2116f325 100644
--- a/src/Box2D.NET.Samples/Samples/Bodies/Weeble.cs
+++ b/src/Box2D.NET.Samples/Samples/Bodies/Weeble.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2022 Erin Catto
+// SPDX-FileCopyrightText: 2022 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -91,15 +91,9 @@ static float RestitutionCallback(float restitutionA, ulong materialA, float rest
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 120.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(200.0f, height));
- ImGui.Begin("Weeble", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
if (ImGui.Button("Teleport"))
{
b2Body_SetTransform(m_weebleId, new B2Vec2(0.0f, 5.0f), b2MakeRot(0.95f * B2_PI));
@@ -115,12 +109,12 @@ public override void UpdateGui()
b2World_Explode(m_worldId, def);
}
- ImGui.PushItemWidth(100.0f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("Magnitude", ref m_explosionMagnitude, -100.0f, 100.0f, "%.1f");
ImGui.PopItemWidth();
- ImGui.End();
+
}
public override void Draw()
diff --git a/src/Box2D.NET.Samples/Samples/Characters/Mover.cs b/src/Box2D.NET.Samples/Samples/Characters/Mover.cs
index 157fed95..39f0e56c 100644
--- a/src/Box2D.NET.Samples/Samples/Characters/Mover.cs
+++ b/src/Box2D.NET.Samples/Samples/Characters/Mover.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2022 Erin Catto
+// SPDX-FileCopyrightText: 2022 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -459,16 +459,12 @@ void SolveMove(float timeStep, float throttle)
m_velocity = b2ClipVector(m_velocity, m_planes, m_planeCount);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 350.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 25.0f), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(340.0f, height));
+ ImGui.TextUnformatted("Mover");
+ ImGui.Spacing();
- ImGui.Begin("Mover", 0);
-
- ImGui.PushItemWidth(240.0f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("Jump Speed", ref m_jumpSpeed, 0.0f, 40.0f, "%.0f");
ImGui.SliderFloat("Min Speed", ref m_minSpeed, 0.0f, 1.0f, "%.2f");
@@ -485,7 +481,7 @@ public override void UpdateGui()
ImGui.Separator();
- ImGui.Text("Pogo Shape");
+ ImGui.TextUnformatted("Pogo Shape");
ImGui.RadioButton("Point", ref m_pogoShape, (int)PogoShape.PogoPoint);
ImGui.SameLine();
ImGui.RadioButton("Circle", ref m_pogoShape, (int)PogoShape.PogoCircle);
@@ -493,8 +489,6 @@ public override void UpdateGui()
ImGui.RadioButton("Segment", ref m_pogoShape, (int)PogoShape.PogoSegment);
ImGui.Checkbox("Lock Camera", ref m_lockCamera);
-
- ImGui.End();
}
static bool PlaneResultFcn(B2ShapeId shapeId, ref B2PlaneResult planeResult, object context)
diff --git a/src/Box2D.NET.Samples/Samples/Collisions/CastWorld.cs b/src/Box2D.NET.Samples/Samples/Collisions/CastWorld.cs
index 96e4a347..3d243cf1 100644
--- a/src/Box2D.NET.Samples/Samples/Collisions/CastWorld.cs
+++ b/src/Box2D.NET.Samples/Samples/Collisions/CastWorld.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -297,21 +297,15 @@ public override void MouseMove(B2Vec2 p)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 320.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(200.0f, height));
-
- ImGui.Begin("Ray-cast World", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
ImGui.Checkbox("Simple", ref m_simple);
if (m_simple == false)
{
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
string[] castTypes = ["Ray", "Circle", "Capsule", "Polygon"];
int castType = (int)m_castType;
if (ImGui.Combo("Type", ref castType, castTypes, castTypes.Length))
@@ -330,6 +324,7 @@ public override void UpdateGui()
{
m_mode = mode;
}
+ ImGui.PopItemWidth();
}
if (ImGui.Button("Polygon"))
@@ -373,8 +368,6 @@ public override void UpdateGui()
{
DestroyBody();
}
-
- ImGui.End();
}
public override void Step()
@@ -513,31 +506,31 @@ public override void Draw()
{
base.Draw();
- DrawTextLine("Click left mouse button and drag to modify ray cast");
- DrawTextLine("Shape 7 is intentionally ignored by the ray");
+ DrawScreenTextLine("Click left mouse button and drag to modify ray cast");
+ DrawScreenTextLine("Shape 7 is intentionally ignored by the ray");
if (m_simple)
{
- DrawTextLine("Simple closest point ray cast");
+ DrawScreenTextLine("Simple closest point ray cast");
}
else
{
switch ((Mode)m_mode)
{
case Mode.e_any:
- DrawTextLine("Cast mode: any - check for obstruction - unsorted");
+ DrawScreenTextLine("Cast mode: any - check for obstruction - unsorted");
break;
case Mode.e_closest:
- DrawTextLine("Cast mode: closest - find closest shape along the cast");
+ DrawScreenTextLine("Cast mode: closest - find closest shape along the cast");
break;
case Mode.e_multiple:
- DrawTextLine("Cast mode: multiple - gather up to 3 shapes - unsorted");
+ DrawScreenTextLine("Cast mode: multiple - gather up to 3 shapes - unsorted");
break;
case Mode.e_sorted:
- DrawTextLine("Cast mode: sorted - gather up to 3 shapes sorted by closeness");
+ DrawScreenTextLine("Cast mode: sorted - gather up to 3 shapes sorted by closeness");
break;
default:
diff --git a/src/Box2D.NET.Samples/Samples/Collisions/DynamicTree.cs b/src/Box2D.NET.Samples/Samples/Collisions/DynamicTree.cs
index ca7598b6..14dc28ef 100644
--- a/src/Box2D.NET.Samples/Samples/Collisions/DynamicTree.cs
+++ b/src/Box2D.NET.Samples/Samples/Collisions/DynamicTree.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -188,18 +188,11 @@ void BuildTree()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 320.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(200.0f, height));
- ImGui.Begin("Dynamic Tree", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
-
- ImGui.PushItemWidth(100.0f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
bool changed = false;
if (ImGui.SliderInt("rows", ref m_rowCount, 0, 1000, "%d"))
@@ -235,6 +228,8 @@ public override void UpdateGui()
{
}
+ ImGui.PopItemWidth();
+
if (ImGui.RadioButton("Incremental", m_updateType == (int)UpdateType.Update_Incremental))
{
m_updateType = (int)UpdateType.Update_Incremental;
@@ -258,9 +253,6 @@ public override void UpdateGui()
ImGui.Text("mouse button 1: ray cast");
ImGui.Text("mouse button 1 + shift: query");
- ImGui.PopItemWidth();
- ImGui.End();
-
if (changed)
{
BuildTree();
@@ -449,7 +441,7 @@ public override void Draw()
DrawPoint(m_draw, m_startPoint, 5.0f, B2HexColor.b2_colorGreen);
DrawPoint(m_draw, m_endPoint, 5.0f, B2HexColor.b2_colorRed);
- DrawTextLine($"node visits = {result.nodeVisits}, leaf visits = {result.leafVisits}");
+ DrawScreenTextLine($"node visits = {result.nodeVisits}, leaf visits = {result.leafVisits}");
}
switch ((UpdateType)m_updateType)
@@ -481,6 +473,6 @@ public override void Draw()
float areaRatio = b2DynamicTree_GetAreaRatio(m_tree);
int hmin = (int)(MathF.Ceiling(MathF.Log((float)m_proxyCount) / MathF.Log(2.0f) - 1.0f));
- DrawTextLine($"proxies = {m_proxyCount}, height = {height}, hmin = {hmin}, area ratio = {areaRatio:F1}");
+ DrawScreenTextLine($"proxies = {m_proxyCount}, height = {height}, hmin = {hmin}, area ratio = {areaRatio:F1}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Collisions/Manifold.cs b/src/Box2D.NET.Samples/Samples/Collisions/Manifold.cs
index 63bfde49..d790d7f2 100644
--- a/src/Box2D.NET.Samples/Samples/Collisions/Manifold.cs
+++ b/src/Box2D.NET.Samples/Samples/Collisions/Manifold.cs
@@ -86,18 +86,11 @@ public Manifold(SampleContext context) : base(context)
m_wedge = b2ComputeHull(points, 3);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 24.0f * fontSize;
- ImGui.SetNextWindowPos( new Vector2( 0.5f * fontSize, m_camera.height - height - 2.0f * fontSize ), ImGuiCond.Once );
- ImGui.SetNextWindowSize( new Vector2( 20.0f * fontSize, height ) );
- ImGui.Begin( "Manifold", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize );
-
- ImGui.PushItemWidth( 14.0f * fontSize );
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("x offset", ref m_transform.p.X, -2.0f, 2.0f, "%.2f");
ImGui.SliderFloat("y offset", ref m_transform.p.Y, -2.0f, 2.0f, "%.2f");
@@ -131,7 +124,7 @@ public override void UpdateGui()
ImGui.Text("mouse button 1: drag");
ImGui.Text("mouse button 1 + shift: rotate");
- ImGui.End();
+
}
public override void MouseDown(B2Vec2 p, MouseButton button, KeyModifiers mods)
diff --git a/src/Box2D.NET.Samples/Samples/Collisions/OverlapWorld.cs b/src/Box2D.NET.Samples/Samples/Collisions/OverlapWorld.cs
index 92978fc3..fb7d6e45 100644
--- a/src/Box2D.NET.Samples/Samples/Collisions/OverlapWorld.cs
+++ b/src/Box2D.NET.Samples/Samples/Collisions/OverlapWorld.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -266,16 +266,9 @@ public override void MouseMove(B2Vec2 p)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 330.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(140.0f, height));
-
- ImGui.Begin("Overlap World", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
if (ImGui.Button("Polygon 1"))
Create(0);
@@ -330,7 +323,7 @@ public override void UpdateGui()
ImGui.RadioButton("Capsule##Overlap", ref m_shapeType, e_capsuleShape);
ImGui.RadioButton("Box##Overlap", ref m_shapeType, e_boxShape);
- ImGui.End();
+
}
public override void Step()
@@ -392,9 +385,9 @@ public override void Draw()
{
base.Draw();
- DrawTextLine("left mouse button: drag query shape");
+ DrawScreenTextLine("left mouse button: drag query shape");
- DrawTextLine("left mouse button + shift: rotate query shape");
+ DrawScreenTextLine("left mouse button + shift: rotate query shape");
if (B2_IS_NON_NULL(m_bodyIds[m_ignoreIndex]))
@@ -404,4 +397,4 @@ public override void Draw()
DrawWorldString(m_draw, m_camera, p, B2HexColor.b2_colorWhite, "skip");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Collisions/RayCast.cs b/src/Box2D.NET.Samples/Samples/Collisions/RayCast.cs
index 6e0d85e5..5527b5cb 100644
--- a/src/Box2D.NET.Samples/Samples/Collisions/RayCast.cs
+++ b/src/Box2D.NET.Samples/Samples/Collisions/RayCast.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -80,18 +80,11 @@ public RayCast(SampleContext context) : base(context)
m_showFraction = false;
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 230.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(200.0f, height));
- ImGui.Begin("Ray-cast", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
-
- ImGui.PushItemWidth(100.0f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("x offset", ref m_transform.p.X, -2.0f, 2.0f, "%.2f");
ImGui.SliderFloat("y offset", ref m_transform.p.Y, -2.0f, 2.0f, "%.2f");
@@ -105,6 +98,8 @@ public override void UpdateGui()
//{
// }
+ ImGui.PopItemWidth();
+
ImGui.Checkbox("show fraction", ref m_showFraction);
if (ImGui.Button("Reset"))
@@ -119,9 +114,6 @@ public override void UpdateGui()
ImGui.Text("mouse btn 1 + shft: translate");
ImGui.Text("mouse btn 1 + ctrl: rotate");
- ImGui.PopItemWidth();
-
- ImGui.End();
}
public override void MouseDown(B2Vec2 p, MouseButton button, KeyModifiers mods)
@@ -340,4 +332,4 @@ public override void Step()
DrawRay(ref output);
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Collisions/ShapeCast.cs b/src/Box2D.NET.Samples/Samples/Collisions/ShapeCast.cs
index 0f5eb93e..00234fa7 100644
--- a/src/Box2D.NET.Samples/Samples/Collisions/ShapeCast.cs
+++ b/src/Box2D.NET.Samples/Samples/Collisions/ShapeCast.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -11,6 +11,7 @@
using static Box2D.NET.B2Geometries;
using static Box2D.NET.B2Diagnostics;
using static Box2D.NET.Samples.Graphics.Draws;
+using static Box2D.NET.Samples.SampleText;
namespace Box2D.NET.Samples.Samples.Collisions;
@@ -297,15 +298,9 @@ public override void MouseMove(B2Vec2 p)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 300.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Shape Distance", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
string[] shapeTypes = { "point", "segment", "triangle", "box" };
int shapeType = (int)m_typeA;
if (ImGui.Combo("shape A", ref shapeType, shapeTypes, shapeTypes.Length))
@@ -341,12 +336,12 @@ public override void UpdateGui()
m_transform.q = b2MakeRot(m_angle);
}
+ ImGui.PopItemWidth();
+
ImGui.Separator();
ImGui.Checkbox("show indices", ref m_showIndices);
ImGui.Checkbox("encroach", ref m_encroach);
-
- ImGui.End();
}
public override void Step()
@@ -387,7 +382,7 @@ public override void Draw()
{
base.Draw();
- DrawTextLine($"hit = {output.hit}, iterations = {output.iterations}, fraction = {output.fraction}, distance = {_distanceOutput.distance}");
+ DrawScreenTextLine($"hit = {(output.hit ? "true" : "false")}, iterations = {output.iterations}, fraction = {FormatFloat(output.fraction)}, distance = {FormatFloat(_distanceOutput.distance)}");
DrawShape(m_typeA, b2Transform_identity, m_radiusA, B2HexColor.b2_colorCyan);
DrawShape(m_typeB, m_transform, m_radiusB, B2HexColor.b2_colorLightGreen);
@@ -425,9 +420,9 @@ public override void Draw()
}
}
- DrawTextLine("mouse button 1: drag");
- DrawTextLine("mouse button 1 + shift: rotate");
- DrawTextLine("mouse button 1 + control: sweep");
- DrawTextLine($"distance = {_distanceOutput.distance:F2}, iterations = {output.iterations}");
+ DrawScreenTextLine("mouse button 1: drag");
+ DrawScreenTextLine("mouse button 1 + shift: rotate");
+ DrawScreenTextLine("mouse button 1 + control: sweep");
+ DrawScreenTextLine($"distance = {_distanceOutput.distance:F2}, iterations = {output.iterations}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Collisions/ShapeDistance.cs b/src/Box2D.NET.Samples/Samples/Collisions/ShapeDistance.cs
index c80e0df8..55b4d0f0 100644
--- a/src/Box2D.NET.Samples/Samples/Collisions/ShapeDistance.cs
+++ b/src/Box2D.NET.Samples/Samples/Collisions/ShapeDistance.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -212,17 +212,9 @@ void DrawShape(ShapeType type, in B2Transform transform, float radius, B2HexColo
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 21.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(19.0f * fontSize, height));
-
- ImGui.Begin("Shape Distance", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
string[] shapeTypes = ["point", "segment", "triangle", "box"];
int shapeType = (int)m_typeA;
if (ImGui.Combo("shape A", ref shapeType, shapeTypes, shapeTypes.Length))
@@ -258,6 +250,8 @@ public override void UpdateGui()
m_transform.q = b2MakeRot(m_angle);
}
+ ImGui.PopItemWidth();
+
ImGui.Separator();
ImGui.Checkbox("show indices", ref m_showIndices);
@@ -272,11 +266,11 @@ public override void UpdateGui()
if (m_drawSimplex && m_simplexCount > 0)
{
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderInt("index", ref m_simplexIndex, 0, m_simplexCount - 1);
m_simplexIndex = b2ClampInt(m_simplexIndex, 0, m_simplexCount - 1);
+ ImGui.PopItemWidth();
}
-
- ImGui.End();
}
public override void MouseDown(B2Vec2 p, MouseButton button, KeyModifiers mods)
@@ -442,24 +436,24 @@ public override void Draw()
}
}
- DrawTextLine("mouse button 1: drag");
+ DrawScreenTextLine("mouse button 1: drag");
- DrawTextLine("mouse button 1 + shift: rotate");
+ DrawScreenTextLine("mouse button 1 + shift: rotate");
- DrawTextLine($"distance = {_outputDistance:F2}, iterations = {_outputIterations}");
+ DrawScreenTextLine($"distance = {_outputDistance:F2}, iterations = {_outputIterations}");
if (m_cache.count == 1)
{
- DrawTextLine($"cache = {m_cache.indexA[0]}, {m_cache.indexB[0]}");
+ DrawTextLine($"cache = {{{m_cache.indexA[0]}}}, {{{m_cache.indexB[0]}}}");
}
else if (m_cache.count == 2)
{
- DrawTextLine($"cache = {m_cache.indexA[0]}, {m_cache.indexA[1]}, {m_cache.indexB[0]}, {m_cache.indexB[1]}");
+ DrawTextLine($"cache = {{{m_cache.indexA[0]}, {m_cache.indexA[1]}}}, {{{m_cache.indexB[0]}, {m_cache.indexB[1]}}}");
}
else if (m_cache.count == 3)
{
- DrawTextLine($"cache = {m_cache.indexA[0]}, {m_cache.indexA[1]}, {m_cache.indexA[2]}, {m_cache.indexB[0]}, {m_cache.indexB[1]}, {m_cache.indexB[2]}");
+ DrawScreenTextLine($"cache = {{{m_cache.indexA[0]}, {m_cache.indexA[1]}, {m_cache.indexA[2]}}}, {{{m_cache.indexB[0]}, {m_cache.indexB[1]}, {m_cache.indexB[2]}}}");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Collisions/SmoothManifold.cs b/src/Box2D.NET.Samples/Samples/Collisions/SmoothManifold.cs
index acf90c38..482d6c5b 100644
--- a/src/Box2D.NET.Samples/Samples/Collisions/SmoothManifold.cs
+++ b/src/Box2D.NET.Samples/Samples/Collisions/SmoothManifold.cs
@@ -133,17 +133,10 @@ public SmoothManifold(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 290.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(180.0f, height));
-
- ImGui.Begin("Smooth Manifold", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(100.0f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
{
string[] shapeTypes = { "Circle", "Box" };
@@ -161,6 +154,9 @@ public override void UpdateGui()
}
ImGui.SliderFloat("Round", ref m_round, 0.0f, 0.4f, "%.1f");
+
+ ImGui.PopItemWidth();
+
ImGui.Checkbox("Show Ids", ref m_showIds);
ImGui.Checkbox("Show Separation", ref m_showSeparation);
ImGui.Checkbox("Show Anchors", ref m_showAnchors);
@@ -176,8 +172,6 @@ public override void UpdateGui()
ImGui.Text("mouse button 1: drag");
ImGui.Text("mouse button 1 + shift: rotate");
- ImGui.PopItemWidth();
- ImGui.End();
}
public override void MouseDown(B2Vec2 p, MouseButton button, KeyModifiers mods)
@@ -305,4 +299,4 @@ public override void Draw()
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Collisions/TimeOfImpact.cs b/src/Box2D.NET.Samples/Samples/Collisions/TimeOfImpact.cs
index 8d9f0bd5..6eeb8042 100644
--- a/src/Box2D.NET.Samples/Samples/Collisions/TimeOfImpact.cs
+++ b/src/Box2D.NET.Samples/Samples/Collisions/TimeOfImpact.cs
@@ -76,8 +76,6 @@ public override void Draw()
DrawTextLine($"toi = {_output.fraction:g}");
- // DrawTextLine("max toi iters = %d, max root iters = %d", b2_toiMaxIters, b2_toiMaxRootIters);
-
B2Vec2[] vertices = new B2Vec2[B2_MAX_POLYGON_VERTICES];
// Draw A
@@ -144,4 +142,4 @@ public override void Draw()
}
#endif
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Continuous/BounceHouse.cs b/src/Box2D.NET.Samples/Samples/Continuous/BounceHouse.cs
index b7451c20..87caffa2 100644
--- a/src/Box2D.NET.Samples/Samples/Continuous/BounceHouse.cs
+++ b/src/Box2D.NET.Samples/Samples/Continuous/BounceHouse.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -125,17 +125,9 @@ void Launch()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 100.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Bounce House", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
string[] shapeTypes = { "Circle", "Capsule", "Box" };
int shapeType = (int)m_shapeType;
if (ImGui.Combo("Shape", ref shapeType, shapeTypes, shapeTypes.Length))
@@ -143,13 +135,14 @@ public override void UpdateGui()
m_shapeType = (ShapeType)shapeType;
Launch();
}
+ ImGui.PopItemWidth();
if (ImGui.Checkbox("hit events", ref m_enableHitEvents))
{
b2Body_EnableHitEvents(m_bodyId, m_enableHitEvents);
}
- ImGui.End();
+
}
public override void Step()
@@ -196,4 +189,4 @@ public override void Draw()
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Continuous/ChainDrop.cs b/src/Box2D.NET.Samples/Samples/Continuous/ChainDrop.cs
index 3730d27e..2535acee 100644
--- a/src/Box2D.NET.Samples/Samples/Continuous/ChainDrop.cs
+++ b/src/Box2D.NET.Samples/Samples/Continuous/ChainDrop.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -85,25 +85,18 @@ void Launch()
//m_shapeId = b2CreatePolygonShape( m_bodyId, &shapeDef, &box );
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 140.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Chain Drop", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("Speed", ref m_speed, -100.0f, 0.0f, "%.0f");
ImGui.SliderFloat("Y Offset", ref m_yOffset, -1.0f, 1.0f, "%.1f");
+ ImGui.PopItemWidth();
if (ImGui.Button("Launch"))
{
Launch();
}
- ImGui.End();
+
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Continuous/GhostBumps.cs b/src/Box2D.NET.Samples/Samples/Continuous/GhostBumps.cs
index 96e7afba..31511ecf 100644
--- a/src/Box2D.NET.Samples/Samples/Continuous/GhostBumps.cs
+++ b/src/Box2D.NET.Samples/Samples/Continuous/GhostBumps.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -267,17 +267,10 @@ void Launch()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 140.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(180.0f, height));
-
- ImGui.Begin("Ghost Bumps", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(100.0f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.Checkbox("Chain", ref m_useChain))
{
@@ -320,6 +313,6 @@ public override void UpdateGui()
}
ImGui.PopItemWidth();
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Continuous/PixelImperfect.cs b/src/Box2D.NET.Samples/Samples/Continuous/PixelImperfect.cs
index f5a2c56a..4370301f 100644
--- a/src/Box2D.NET.Samples/Samples/Continuous/PixelImperfect.cs
+++ b/src/Box2D.NET.Samples/Samples/Continuous/PixelImperfect.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -76,6 +76,6 @@ public override void Draw()
B2Vec2 p = b2Body_GetPosition(m_ballId);
B2Vec2 v = b2Body_GetLinearVelocity(m_ballId);
- DrawTextLine($"p.x = {p.X:F9}, v.y = {v.Y:F9}");
+ DrawScreenTextLine($"p.x = {p.X:F9}, v.y = {v.Y:F9}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Continuous/RestitutionThreshold.cs b/src/Box2D.NET.Samples/Samples/Continuous/RestitutionThreshold.cs
index 5155eb16..f2f5dd84 100644
--- a/src/Box2D.NET.Samples/Samples/Continuous/RestitutionThreshold.cs
+++ b/src/Box2D.NET.Samples/Samples/Continuous/RestitutionThreshold.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -81,6 +81,6 @@ public override void Draw()
B2Vec2 p = b2Body_GetPosition(m_ballId);
B2Vec2 v = b2Body_GetLinearVelocity(m_ballId);
- DrawTextLine($"p.x = {p.X:F9}, v.y = {v.Y:F9}");
+ DrawScreenTextLine($"p.x = {p.X:F9}, v.y = {v.Y:F9}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Continuous/SkinnyBox.cs b/src/Box2D.NET.Samples/Samples/Continuous/SkinnyBox.cs
index 1df29174..374c0def 100644
--- a/src/Box2D.NET.Samples/Samples/Continuous/SkinnyBox.cs
+++ b/src/Box2D.NET.Samples/Samples/Continuous/SkinnyBox.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -111,16 +111,9 @@ void Launch()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 110.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(140.0f, height));
-
- ImGui.Begin("Skinny Box", ImGuiWindowFlags.NoResize);
ImGui.Checkbox("Capsule", ref m_capsule);
@@ -131,7 +124,7 @@ public override void UpdateGui()
ImGui.Checkbox("Auto Test", ref m_autoTest);
- ImGui.End();
+
}
public override void Step()
diff --git a/src/Box2D.NET.Samples/Samples/Determinisms/FallingHinges.cs b/src/Box2D.NET.Samples/Samples/Determinisms/FallingHinges.cs
index 464c9fca..5192ef01 100644
--- a/src/Box2D.NET.Samples/Samples/Determinisms/FallingHinges.cs
+++ b/src/Box2D.NET.Samples/Samples/Determinisms/FallingHinges.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -60,7 +60,7 @@ public override void Draw()
if (m_done)
{
- DrawTextLine($"sleep step = {m_data.sleepStep}, hash = 0x{m_data.hash:X8}");
+ DrawScreenTextLine($"sleep step = {m_data.sleepStep}, hash = 0x{m_data.hash:X8}");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Events/BodyMove.cs b/src/Box2D.NET.Samples/Samples/Events/BodyMove.cs
index 8d053bc4..29036e15 100644
--- a/src/Box2D.NET.Samples/Samples/Events/BodyMove.cs
+++ b/src/Box2D.NET.Samples/Samples/Events/BodyMove.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -177,16 +177,9 @@ public override void Step()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 100.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Body Move", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
if (ImGui.Button("Explode"))
{
@@ -198,9 +191,9 @@ public override void UpdateGui()
b2World_Explode(m_worldId, def);
}
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("Magnitude", ref m_explosionMagnitude, -20.0f, 20.0f, "%.1f");
-
- ImGui.End();
+ ImGui.PopItemWidth();
}
public override void Draw()
@@ -211,4 +204,4 @@ public override void Draw()
DrawTextLine($"sleep count: {m_sleepCount}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Events/ContactEvent.cs b/src/Box2D.NET.Samples/Samples/Events/ContactEvent.cs
index 9ab8abe3..218a255c 100644
--- a/src/Box2D.NET.Samples/Samples/Events/ContactEvent.cs
+++ b/src/Box2D.NET.Samples/Samples/Events/ContactEvent.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -144,20 +144,11 @@ void SpawnDebris()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 60.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Contact Event", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("force", ref m_force, 100.0f, 500.0f, "%.1f");
-
- ImGui.End();
+ ImGui.PopItemWidth();
}
public override void Step()
@@ -435,6 +426,6 @@ public override void Draw()
{
base.Draw();
- DrawTextLine("move using WASD");
+ DrawScreenTextLine("move using WASD");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Events/Platform.cs b/src/Box2D.NET.Samples/Samples/Events/Platform.cs
index c772f269..988db39f 100644
--- a/src/Box2D.NET.Samples/Samples/Events/Platform.cs
+++ b/src/Box2D.NET.Samples/Samples/Events/Platform.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -154,21 +154,12 @@ public bool PreSolve(B2ShapeId shapeIdA, B2ShapeId shapeIdB, B2Vec2 point, B2Vec
return false;
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 100.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("One-Sided Platform", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("force", ref m_force, 0.0f, 50.0f, "%.1f");
ImGui.SliderFloat("impulse", ref m_impulse, 0.0f, 50.0f, "%.1f");
-
- ImGui.End();
+ ImGui.PopItemWidth();
}
public override void Step()
@@ -256,13 +247,13 @@ public override void Draw()
{
Span contactData = stackalloc B2ContactData[1];
int contactCount = b2Body_GetContactData(m_movingPlatformId, contactData, contactData.Length);
- DrawTextLine($"Platform contact count = {contactCount}, point count = {contactData[0].manifold.pointCount}");
+ DrawScreenTextLine($"Platform contact count = {contactCount}, point count = {contactData[0].manifold.pointCount}");
}
- DrawTextLine("Movement: A/D/Space");
+ DrawScreenTextLine("Movement: A/D/Space");
DrawTextLine($"Can jump = {m_canJump}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Events/ProjectileEvent.cs b/src/Box2D.NET.Samples/Samples/Events/ProjectileEvent.cs
index 83d363ae..030ade4b 100644
--- a/src/Box2D.NET.Samples/Samples/Events/ProjectileEvent.cs
+++ b/src/Box2D.NET.Samples/Samples/Events/ProjectileEvent.cs
@@ -176,7 +176,7 @@ public override void Draw()
{
base.Draw();
- DrawTextLine("Use Ctrl + Left Mouse to drag and shoot a projectile");
+ DrawScreenTextLine("Use Ctrl + Left Mouse to drag and shoot a projectile");
if (m_dragging)
{
@@ -185,4 +185,4 @@ public override void Draw()
DrawPoint(m_draw, m_point2, 5.0f, B2HexColor.b2_colorRed);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Events/SensorBookend.cs b/src/Box2D.NET.Samples/Samples/Events/SensorBookend.cs
index ced6844e..c3816d27 100644
--- a/src/Box2D.NET.Samples/Samples/Events/SensorBookend.cs
+++ b/src/Box2D.NET.Samples/Samples/Events/SensorBookend.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -120,14 +120,9 @@ void CreateVisitor()
m_visitorShapeId = b2CreateCircleShape(m_visitorBodyId, shapeDef, circle);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 19.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(12.0f * fontSize, height));
- ImGui.Begin("Sensor Bookend", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
if (B2_IS_NULL(m_visitorBodyId))
{
@@ -247,7 +242,7 @@ public override void UpdateGui()
}
}
- ImGui.End();
+
}
public override void Step()
diff --git a/src/Box2D.NET.Samples/Samples/Events/SensorFunnel.cs b/src/Box2D.NET.Samples/Samples/Events/SensorFunnel.cs
index 0fbf3dfe..abccd2ec 100644
--- a/src/Box2D.NET.Samples/Samples/Events/SensorFunnel.cs
+++ b/src/Box2D.NET.Samples/Samples/Events/SensorFunnel.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -261,17 +261,9 @@ void Clear()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 90.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize),
- ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(140.0f, height));
-
- ImGui.Begin("Sensor Event", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
if (ImGui.RadioButton("donut", m_type == (int)e_donut))
{
@@ -285,7 +277,7 @@ public override void UpdateGui()
m_type = (int)e_human;
}
- ImGui.End();
+
}
public override void Step()
diff --git a/src/Box2D.NET.Samples/Samples/Events/SensorHits.cs b/src/Box2D.NET.Samples/Samples/Events/SensorHits.cs
index ca227220..90877243 100644
--- a/src/Box2D.NET.Samples/Samples/Events/SensorHits.cs
+++ b/src/Box2D.NET.Samples/Samples/Events/SensorHits.cs
@@ -170,14 +170,9 @@ void Launch()
m_shapeId = b2CreateCircleShape(m_bodyId, shapeDef, circle);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 120.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(120.0f, height));
- ImGui.Begin("Sensor Hit", ImGuiWindowFlags.NoResize);
ImGui.Checkbox("Bullet", ref m_isBullet);
@@ -186,7 +181,7 @@ public override void UpdateGui()
Launch();
}
- ImGui.End();
+
}
void CollectTransforms(B2ShapeId sensorShapeId)
diff --git a/src/Box2D.NET.Samples/Samples/Events/SensorTypes.cs b/src/Box2D.NET.Samples/Samples/Events/SensorTypes.cs
index 67b4e7e2..b2553214 100644
--- a/src/Box2D.NET.Samples/Samples/Events/SensorTypes.cs
+++ b/src/Box2D.NET.Samples/Samples/Events/SensorTypes.cs
@@ -180,7 +180,7 @@ void PrintOverlaps(B2ShapeId sensorShapeId, string prefix)
start += entryByteCount;
}
- DrawTextLine(builder.ToString());
+ DrawScreenTextLine(builder.ToString());
}
private static int AppendUtf8(StringBuilder builder, string text, int maxByteCount)
diff --git a/src/Box2D.NET.Samples/Samples/Geometries/ConvexHull.cs b/src/Box2D.NET.Samples/Samples/Geometries/ConvexHull.cs
index 6e4980fe..a2611882 100644
--- a/src/Box2D.NET.Samples/Samples/Geometries/ConvexHull.cs
+++ b/src/Box2D.NET.Samples/Samples/Geometries/ConvexHull.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -191,7 +191,7 @@ public override void Draw()
{
base.Draw();
- DrawTextLine("Options: generate(g), auto(a), bulk(b)");
+ DrawScreenTextLine("Options: generate(g), auto(a), bulk(b)");
if (m_valid == false)
@@ -201,7 +201,7 @@ public override void Draw()
}
else
{
- DrawTextLine($"generation = {m_generation}, count = {m_hull.count}");
+ DrawScreenTextLine($"generation = {m_generation}, count = {m_hull.count}");
}
@@ -229,4 +229,4 @@ public override void Draw()
DrawPoint(m_draw, m_hull.points[i], 6.0f, B2HexColor.b2_colorGreen);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Issues/Crash01.cs b/src/Box2D.NET.Samples/Samples/Issues/Crash01.cs
index d22d663c..f114285e 100644
--- a/src/Box2D.NET.Samples/Samples/Issues/Crash01.cs
+++ b/src/Box2D.NET.Samples/Samples/Issues/Crash01.cs
@@ -106,13 +106,9 @@ public Crash01(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 11.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(9.0f * fontSize, height));
- ImGui.Begin("Crash 01", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
+
if (ImGui.RadioButton("Static", m_type == B2BodyType.b2_staticBody))
{
@@ -145,6 +141,6 @@ public override void UpdateGui()
}
}
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Issues/DisableCrash.cs b/src/Box2D.NET.Samples/Samples/Issues/DisableCrash.cs
index 14d67343..dc8c2501 100644
--- a/src/Box2D.NET.Samples/Samples/Issues/DisableCrash.cs
+++ b/src/Box2D.NET.Samples/Samples/Issues/DisableCrash.cs
@@ -73,15 +73,9 @@ public DisableCrash(SampleContext context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 11.0f * fontSize;
- float winX = 0.5f * fontSize;
- float winY = m_camera.height - height - 2.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(winX, winY), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(9.0f * fontSize, height));
- ImGui.Begin("Disable Crash", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
+
if (ImGui.Checkbox("Enable", ref m_isEnabled))
{
@@ -95,6 +89,6 @@ public override void UpdateGui()
}
}
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Joints/BallAndChain.cs b/src/Box2D.NET.Samples/Samples/Joints/BallAndChain.cs
index ceae195f..37f556b0 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/BallAndChain.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/BallAndChain.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -107,18 +107,11 @@ public BallAndChain(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 60.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Ball and Chain", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
bool updateFriction = ImGui.SliderFloat("Joint Friction", ref m_frictionTorque, 0.0f, 1000.0f, "%2.f");
+ ImGui.PopItemWidth();
if (updateFriction)
{
for (int i = 0; i <= m_count; ++i)
@@ -126,7 +119,5 @@ public override void UpdateGui()
b2RevoluteJoint_SetMaxMotorTorque(m_jointIds[i], m_frictionTorque);
}
}
-
- ImGui.End();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/BreakableJoint.cs b/src/Box2D.NET.Samples/Samples/Joints/BreakableJoint.cs
index 96415460..eed01365 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/BreakableJoint.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/BreakableJoint.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -200,17 +200,9 @@ public BreakableJoint(SampleContext context) : base(context)
m_breakForce = 1000.0f;
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 100.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Breakable Joint", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("break force", ref m_breakForce, 0.0f, 10000.0f, "%.1f");
B2Vec2 gravity = b2World_GetGravity(m_worldId);
@@ -218,8 +210,7 @@ public override void UpdateGui()
{
b2World_SetGravity(m_worldId, gravity);
}
-
- ImGui.End();
+ ImGui.PopItemWidth();
}
@@ -262,4 +253,4 @@ public override void Draw()
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/Bridge.cs b/src/Box2D.NET.Samples/Samples/Joints/Bridge.cs
index eb8cf985..7ab21d29 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/Bridge.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/Bridge.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -138,18 +138,11 @@ public Bridge(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 180.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(320.0f, height));
- ImGui.Begin("Bridge", ImGuiWindowFlags.NoResize);
-
- ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.6f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
bool updateFriction = ImGui.SliderFloat("Joint Friction", ref m_frictionTorque, 0.0f, 10000.0f, "%2.f");
if (updateFriction)
{
@@ -193,6 +186,6 @@ public override void UpdateGui()
ImGui.PopItemWidth();
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Joints/Cantilever.cs b/src/Box2D.NET.Samples/Samples/Joints/Cantilever.cs
index 9ec9e3c1..f7bb3fac 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/Cantilever.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/Cantilever.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -100,17 +100,10 @@ public Cantilever(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 14.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(19.0f * fontSize, height));
-
- ImGui.Begin("Cantilever", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(8.0f * fontSize);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Linear Hertz", ref m_linearHertz, 0.0f, 20.0f, "%.0f"))
{
@@ -144,24 +137,23 @@ public override void UpdateGui()
}
}
- if (ImGui.Checkbox("Collide Connected", ref m_collideConnected))
+ if (ImGui.SliderFloat("Gravity Scale", ref m_gravityScale, -1.0f, 1.0f, "%.1f"))
{
for (int i = 0; i < e_count; ++i)
{
- b2Joint_SetCollideConnected(m_jointIds[i], m_collideConnected);
+ b2Body_SetGravityScale(m_bodyIds[i], m_gravityScale);
}
}
- if (ImGui.SliderFloat("Gravity Scale", ref m_gravityScale, -1.0f, 1.0f, "%.1f"))
+ ImGui.PopItemWidth();
+
+ if (ImGui.Checkbox("Collide Connected", ref m_collideConnected))
{
for (int i = 0; i < e_count; ++i)
{
- b2Body_SetGravityScale(m_bodyIds[i], m_gravityScale);
+ b2Joint_SetCollideConnected(m_jointIds[i], m_collideConnected);
}
}
-
- ImGui.PopItemWidth();
- ImGui.End();
}
@@ -172,4 +164,4 @@ public override void Draw()
B2Vec2 tipPosition = b2Body_GetPosition(m_tipId);
DrawTextLine($"tip-y = {tipPosition.Y:F2}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/DistanceJoint.cs b/src/Box2D.NET.Samples/Samples/Joints/DistanceJoint.cs
index 5bba75ab..0a870b2b 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/DistanceJoint.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/DistanceJoint.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -129,17 +129,10 @@ void CreateScene(int newCount)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 20.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(18.0f * fontSize, height));
-
- ImGui.Begin("Distance Joint", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(10.0f * fontSize);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Length", ref m_length, 0.1f, 4.0f, "%3.1f"))
{
@@ -236,6 +229,6 @@ public override void UpdateGui()
}
ImGui.PopItemWidth();
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Joints/Door.cs b/src/Box2D.NET.Samples/Samples/Joints/Door.cs
index 13ce2b87..1b246d49 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/Door.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/Door.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -91,14 +91,9 @@ public Door(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 220.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
- ImGui.Begin("Door", ImGuiWindowFlags.NoResize);
if (ImGui.Button("impulse"))
{
@@ -107,12 +102,9 @@ public override void UpdateGui()
m_translationError = 0.0f;
}
- ImGui.SliderFloat("magnitude", ref m_impulse, 1000.0f, 100000.0f, "%.0f");
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
- if (ImGui.Checkbox("limit", ref m_enableLimit))
- {
- b2RevoluteJoint_EnableLimit(m_jointId, m_enableLimit);
- }
+ ImGui.SliderFloat("magnitude", ref m_impulse, 1000.0f, 100000.0f, "%.0f");
if (ImGui.SliderFloat("hertz", ref m_jointHertz, 15.0f, 480.0f, "%.0f"))
{
@@ -124,7 +116,12 @@ public override void UpdateGui()
b2Joint_SetConstraintTuning(m_jointId, m_jointHertz, m_jointDampingRatio);
}
- ImGui.End();
+ ImGui.PopItemWidth();
+
+ if (ImGui.Checkbox("limit", ref m_enableLimit))
+ {
+ b2RevoluteJoint_EnableLimit(m_jointId, m_enableLimit);
+ }
}
public override void Draw()
@@ -139,4 +136,4 @@ public override void Draw()
DrawTextLine($"translation error = {m_translationError}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/Driving.cs b/src/Box2D.NET.Samples/Samples/Joints/Driving.cs
index 6aa07904..a83cc801 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/Driving.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/Driving.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -211,18 +211,11 @@ public Driving(SampleContext context) : base(context)
m_car.Spawn(m_worldId, new B2Vec2(0.0f, 0.0f), 1.0f, m_hertz, m_dampingRatio, m_torque, B2UserData.Empty);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 10.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(16.0f * fontSize, height));
- ImGui.Begin("Driving", ImGuiWindowFlags.NoResize);
-
- ImGui.PushItemWidth(8.0f * fontSize);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Spring Hertz", ref m_hertz, 0.0f, 20.0f, "%.0f"))
{
m_car.SetHertz(m_hertz);
@@ -245,7 +238,7 @@ public override void UpdateGui()
ImGui.PopItemWidth();
- ImGui.End();
+
}
public override void Step()
@@ -275,7 +268,7 @@ public override void Draw()
{
base.Draw();
- DrawTextLine("Keys: left = a, brake = s, right = d");
+ DrawScreenTextLine("Keys: left = a, brake = s, right = d");
B2Vec2 linearVelocity = b2Body_GetLinearVelocity(m_car.m_chassisId);
@@ -286,4 +279,4 @@ public override void Draw()
B2Vec2 carPosition = b2Body_GetPosition(m_car.m_chassisId);
m_camera.center.X = carPosition.X;
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/GearLift.cs b/src/Box2D.NET.Samples/Samples/Joints/GearLift.cs
index 410330ea..5bdbe5a7 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/GearLift.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/GearLift.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -294,14 +294,9 @@ public GearLift(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 120.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 25.0f), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
- ImGui.Begin("Gear Lift", ImGuiWindowFlags.NoResize);
if (ImGui.Checkbox("Motor", ref m_enableMotor))
{
@@ -309,6 +304,8 @@ public override void UpdateGui()
b2Joint_WakeBodies(m_driverId);
}
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
+
if (ImGui.SliderFloat("Max Torque", ref m_motorTorque, 0.0f, 100.0f, "%.0f"))
{
b2RevoluteJoint_SetMaxMotorTorque(m_driverId, m_motorTorque);
@@ -320,8 +317,7 @@ public override void UpdateGui()
b2RevoluteJoint_SetMotorSpeed(m_driverId, m_motorSpeed);
b2Joint_WakeBodies(m_driverId);
}
-
- ImGui.End();
+ ImGui.PopItemWidth();
}
public override void Step()
@@ -342,4 +338,4 @@ public override void Step()
base.Step();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/JointSeparation.cs b/src/Box2D.NET.Samples/Samples/Joints/JointSeparation.cs
index 1ac5795d..05254203 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/JointSeparation.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/JointSeparation.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -176,30 +176,15 @@ public JointSeparation(SampleContext context) : base(context)
m_jointDampingRatio = 2.0f;
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 14.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(20.0f * fontSize, height));
-
- ImGui.Begin("Joint Separation", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
B2Vec2 gravity = b2World_GetGravity(m_worldId);
if (ImGui.SliderFloat("gravity", ref gravity.Y, -500.0f, 500.0f, "%.0f"))
{
b2World_SetGravity(m_worldId, gravity);
}
- if (ImGui.Button("impulse"))
- {
- for (int i = 0; i < e_count; ++i)
- {
- B2Vec2 p = b2Body_GetWorldPoint(m_bodyIds[i], new B2Vec2(1.0f, 1.0f));
- b2Body_ApplyLinearImpulse(m_bodyIds[i], new B2Vec2(m_impulse, -m_impulse), p, true);
- }
- }
-
ImGui.SliderFloat("magnitude", ref m_impulse, 0.0f, 1000.0f, "%.0f");
if (ImGui.SliderFloat("hertz", ref m_jointHertz, 15.0f, 120.0f, "%.0f"))
@@ -218,7 +203,16 @@ public override void UpdateGui()
}
}
- ImGui.End();
+ ImGui.PopItemWidth();
+
+ if (ImGui.Button("impulse"))
+ {
+ for (int i = 0; i < e_count; ++i)
+ {
+ B2Vec2 p = b2Body_GetWorldPoint(m_bodyIds[i], new B2Vec2(1.0f, 1.0f));
+ b2Body_ApplyLinearImpulse(m_bodyIds[i], new B2Vec2(m_impulse, -m_impulse), p, true);
+ }
+ }
}
public override void Draw()
@@ -238,4 +232,4 @@ public override void Draw()
DrawWorldString(m_draw, m_camera, localFrame.p, B2HexColor.b2_colorWhite, $"{linear:F2} m, {180.0f * angular / B2_PI:F1} deg");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/MotionLocks.cs b/src/Box2D.NET.Samples/Samples/Joints/MotionLocks.cs
index 664daf59..cb53e20f 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/MotionLocks.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/MotionLocks.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -198,16 +198,9 @@ public MotionLocks(SampleContext context) : base(context)
++index;
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 8.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(14.0f * fontSize, height));
-
- ImGui.Begin("Motion Locks", ImGuiWindowFlags.NoResize);
if (ImGui.Checkbox("Lock Linear X", ref m_motionLocks.linearX))
{
@@ -236,7 +229,7 @@ public override void UpdateGui()
}
}
- ImGui.End();
+
}
public override void Step()
diff --git a/src/Box2D.NET.Samples/Samples/Joints/MotorJoint.cs b/src/Box2D.NET.Samples/Samples/Joints/MotorJoint.cs
index 442167c6..eb93eaa0 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/MotorJoint.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/MotorJoint.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -123,17 +123,9 @@ public MotorJoint(SampleContext context) : base(context)
m_time = 0.0f;
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 180.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Motor Joint", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Speed", ref m_speed, -5.0f, 5.0f, "%.0f"))
{
}
@@ -148,12 +140,12 @@ public override void UpdateGui()
b2MotorJoint_SetMaxSpringTorque(m_jointId, m_maxTorque);
}
+ ImGui.PopItemWidth();
+
if (ImGui.Button("Apply Impulse"))
{
b2Body_ApplyLinearImpulseToCenter(m_bodyId, new B2Vec2(100.0f, 0.0f), true);
}
-
- ImGui.End();
}
@@ -196,7 +188,7 @@ public override void Draw()
B2Vec2 force = b2Joint_GetConstraintForce(m_jointId);
float torque = b2Joint_GetConstraintTorque(m_jointId);
- DrawTextLine($"force = {force.X:3,F0}, {force.Y:3,F0}, torque = {torque:3,F0}");
+ DrawScreenTextLine(FormattableString.Invariant($"force = {{{force.X,3:F0}, {force.Y,3:F0}}}, torque = {torque,3:F0}"));
DrawTransform(m_draw, _transform, 1.0f);
}
}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/PrismaticJoint.cs b/src/Box2D.NET.Samples/Samples/Joints/PrismaticJoint.cs
index 1dd586b7..6958d2da 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/PrismaticJoint.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/PrismaticJoint.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -91,16 +91,9 @@ public PrismaticJoint(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 240.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Prismatic Joint", ImGuiWindowFlags.NoResize);
if (ImGui.Checkbox("Limit", ref m_enableLimit))
{
@@ -116,6 +109,7 @@ public override void UpdateGui()
if (m_enableMotor)
{
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Max Force", ref m_motorForce, 0.0f, 200.0f, "%.0f"))
{
b2PrismaticJoint_SetMaxMotorForce(m_jointId, m_motorForce);
@@ -127,6 +121,7 @@ public override void UpdateGui()
b2PrismaticJoint_SetMotorSpeed(m_jointId, m_motorSpeed);
b2Joint_WakeBodies(m_jointId);
}
+ ImGui.PopItemWidth();
}
if (ImGui.Checkbox("Spring", ref m_enableSpring))
@@ -137,6 +132,7 @@ public override void UpdateGui()
if (m_enableSpring)
{
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Hertz", ref m_hertz, 0.0f, 10.0f, "%.1f"))
{
b2PrismaticJoint_SetSpringHertz(m_jointId, m_hertz);
@@ -154,9 +150,8 @@ public override void UpdateGui()
b2PrismaticJoint_SetTargetTranslation(m_jointId, m_translation);
b2Joint_WakeBodies(m_jointId);
}
+ ImGui.PopItemWidth();
}
-
- ImGui.End();
}
public override void Draw()
@@ -174,4 +169,4 @@ public override void Draw()
float speed = b2PrismaticJoint_GetSpeed(m_jointId);
DrawTextLine($"Speed = {speed:4,F8}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/Ragdoll.cs b/src/Box2D.NET.Samples/Samples/Joints/Ragdoll.cs
index 36f71be4..ccd479b6 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/Ragdoll.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/Ragdoll.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -61,17 +61,10 @@ void Spawn()
//Human_ApplyRandomAngularImpulse(ref m_human, 10.0f);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 10.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(14.0f * fontSize, height));
-
- ImGui.Begin("Ragdoll", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(8.0f * fontSize);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Friction", ref m_jointFrictionTorque, 0.0f, 1.0f, "%3.2f"))
{
@@ -88,13 +81,13 @@ public override void UpdateGui()
Human_SetJointDampingRatio(ref m_human, m_jointDampingRatio);
}
+ ImGui.PopItemWidth();
+
if (ImGui.Button("Respawn"))
{
DestroyHuman(ref m_human);
Spawn();
}
- ImGui.PopItemWidth();
- ImGui.End();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/RevoluteJoint.cs b/src/Box2D.NET.Samples/Samples/Joints/RevoluteJoint.cs
index 9f2a4988..17a059c4 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/RevoluteJoint.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/RevoluteJoint.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -143,16 +143,9 @@ public RevoluteJoint(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 8.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(8.0f * fontSize, height));
-
- ImGui.Begin("Revolute Joint", ImGuiWindowFlags.NoResize);
if (ImGui.Checkbox("Limit", ref m_enableLimit))
{
@@ -168,6 +161,7 @@ public override void UpdateGui()
if (m_enableMotor)
{
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Max Torque", ref m_motorTorque, 0.0f, 5000.0f, "%.0f"))
{
b2RevoluteJoint_SetMaxMotorTorque(m_jointId1, m_motorTorque);
@@ -179,6 +173,7 @@ public override void UpdateGui()
b2RevoluteJoint_SetMotorSpeed(m_jointId1, m_motorSpeed);
b2Joint_WakeBodies(m_jointId1);
}
+ ImGui.PopItemWidth();
}
if (ImGui.Checkbox("Spring", ref m_enableSpring))
@@ -189,6 +184,7 @@ public override void UpdateGui()
if (m_enableSpring)
{
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Hertz", ref m_hertz, 0.0f, 30.0f, "%.1f"))
{
b2RevoluteJoint_SetSpringHertz(m_jointId1, m_hertz);
@@ -207,9 +203,8 @@ public override void UpdateGui()
b2RevoluteJoint_SetTargetAngle(m_jointId1, B2_PI * m_targetDegrees / 180.0f);
b2Joint_WakeBodies(m_jointId1);
}
+ ImGui.PopItemWidth();
}
-
- ImGui.End();
}
public override void Draw()
@@ -226,4 +221,4 @@ public override void Draw()
float torque2 = b2RevoluteJoint_GetMotorTorque(m_jointId2);
DrawTextLine($"Motor Torque 2 = {torque2:F1}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/ScaleRagdoll.cs b/src/Box2D.NET.Samples/Samples/Joints/ScaleRagdoll.cs
index de718a38..7f52f5bb 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/ScaleRagdoll.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/ScaleRagdoll.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -56,18 +56,13 @@ void Spawn()
float jointHertz = 1.0f;
float jointDampingRatio = 0.5f;
CreateHuman(ref m_human, m_worldId, new B2Vec2(0.0f, 5.0f), m_scale, jointFrictionTorque, jointHertz, jointDampingRatio, 1, B2UserData.Empty, false);
- Human_ApplyRandomAngularImpulse(ref m_human, 10.0f);
+ Human_ApplyRandomAngularImpulse(ref m_human, 0.1f);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 4.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(20.0f * fontSize, height));
- ImGui.Begin("Scale Ragdoll", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(15.0f * fontSize);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Scale", ref m_scale, 0.1f, 10.0f, "%3.2f", ImGuiSliderFlags.AlwaysClamp))
{
@@ -75,6 +70,6 @@ public override void UpdateGui()
}
ImGui.PopItemWidth();
- ImGui.End();
+
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/ScissorLift.cs b/src/Box2D.NET.Samples/Samples/Joints/ScissorLift.cs
index 928648a4..9ca95117 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/ScissorLift.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/ScissorLift.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -204,16 +204,9 @@ public ScissorLift(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 140.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Scissor Lift", ImGuiWindowFlags.NoResize);
if (ImGui.Checkbox("Motor", ref m_enableMotor))
{
@@ -221,6 +214,8 @@ public override void UpdateGui()
b2Joint_WakeBodies(m_liftJointId);
}
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
+
if (ImGui.SliderFloat("Max Force", ref m_motorForce, 0.0f, 3000.0f, "%.0f"))
{
b2DistanceJoint_SetMaxMotorForce(m_liftJointId, m_motorForce);
@@ -232,7 +227,6 @@ public override void UpdateGui()
b2DistanceJoint_SetMotorSpeed(m_liftJointId, m_motorSpeed);
b2Joint_WakeBodies(m_liftJointId);
}
-
- ImGui.End();
+ ImGui.PopItemWidth();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Joints/TopDownFriction.cs b/src/Box2D.NET.Samples/Samples/Joints/TopDownFriction.cs
index 69a7002a..c319750c 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/TopDownFriction.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/TopDownFriction.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -109,14 +109,9 @@ private TopDownFriction(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 180.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
- ImGui.Begin("Top Down Friction", ImGuiWindowFlags.NoResize);
if (ImGui.Button("Explode"))
{
@@ -130,6 +125,6 @@ public override void UpdateGui()
DrawCircle(m_draw, def.position, 10.0f, B2HexColor.b2_colorWhite);
}
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Joints/WheelJoint.cs b/src/Box2D.NET.Samples/Samples/Joints/WheelJoint.cs
index d160e57e..4dc6e519 100644
--- a/src/Box2D.NET.Samples/Samples/Joints/WheelJoint.cs
+++ b/src/Box2D.NET.Samples/Samples/Joints/WheelJoint.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -85,16 +85,9 @@ public WheelJoint(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 15.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(18.0f, height));
-
- ImGui.Begin("Wheel Joint", ImGuiWindowFlags.NoResize);
if (ImGui.Checkbox("Limit", ref m_enableLimit))
{
@@ -108,6 +101,7 @@ public override void UpdateGui()
if (m_enableMotor)
{
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Torque", ref m_motorTorque, 0.0f, 20.0f, "%.0f"))
{
b2WheelJoint_SetMaxMotorTorque(m_jointId, m_motorTorque);
@@ -117,6 +111,7 @@ public override void UpdateGui()
{
b2WheelJoint_SetMotorSpeed(m_jointId, m_motorSpeed);
}
+ ImGui.PopItemWidth();
}
if (ImGui.Checkbox("Spring", ref m_enableSpring))
@@ -126,6 +121,7 @@ public override void UpdateGui()
if (m_enableSpring)
{
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Hertz", ref m_hertz, 0.0f, 10.0f, "%.1f"))
{
b2WheelJoint_SetSpringHertz(m_jointId, m_hertz);
@@ -135,9 +131,8 @@ public override void UpdateGui()
{
b2WheelJoint_SetSpringDampingRatio(m_jointId, m_dampingRatio);
}
+ ImGui.PopItemWidth();
}
-
- ImGui.End();
}
public override void Draw()
@@ -147,4 +142,4 @@ public override void Draw()
float torque = b2WheelJoint_GetMotorTorque(m_jointId);
DrawTextLine($"Motor Torque = {torque,4:F1}");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Robustness/Cart.cs b/src/Box2D.NET.Samples/Samples/Robustness/Cart.cs
index 0b5e9e06..05433688 100644
--- a/src/Box2D.NET.Samples/Samples/Robustness/Cart.cs
+++ b/src/Box2D.NET.Samples/Samples/Robustness/Cart.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -141,17 +141,10 @@ void CreateScene()
b2Joint_SetConstraintTuning(m_jointId2, m_constraintHertz, m_constraintDampingRatio);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 240.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(320.0f, height));
-
- ImGui.Begin("Cart", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(200.0f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
bool changed = false;
ImGui.Text("Contact");
@@ -184,6 +177,6 @@ public override void UpdateGui()
}
ImGui.PopItemWidth();
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Robustness/OverlapRecovery.cs b/src/Box2D.NET.Samples/Samples/Robustness/OverlapRecovery.cs
index 56aa0e05..7af4c2a7 100644
--- a/src/Box2D.NET.Samples/Samples/Robustness/OverlapRecovery.cs
+++ b/src/Box2D.NET.Samples/Samples/Robustness/OverlapRecovery.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -101,17 +101,10 @@ void CreateScene()
B2_ASSERT(bodyIndex == m_bodyCount);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 210.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(220.0f, height));
-
- ImGui.Begin("Overlap Recovery", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(100.0f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
bool changed = false;
changed = changed || ImGui.SliderFloat("Extent", ref m_extent, 0.1f, 1.0f, "%.1f");
@@ -128,6 +121,6 @@ public override void UpdateGui()
}
ImGui.PopItemWidth();
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Sample.cs b/src/Box2D.NET.Samples/Samples/Sample.cs
index c14e2f3a..bb9ec5a3 100644
--- a/src/Box2D.NET.Samples/Samples/Sample.cs
+++ b/src/Box2D.NET.Samples/Samples/Sample.cs
@@ -1,8 +1,9 @@
-// SPDX-FileCopyrightText: 2023 Erin Catto
+// SPDX-FileCopyrightText: 2023 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
using System;
+using System.Diagnostics;
using System.Numerics;
using Box2D.NET.Samples.Graphics;
using Box2D.NET.Samples.Helpers;
@@ -22,6 +23,8 @@
using static Box2D.NET.Samples.Graphics.Draws;
using static Box2D.NET.Samples.Graphics.Cameras;
using static Box2D.NET.B2Constants;
+using static Box2D.NET.B2Cores;
+using static Box2D.NET.Samples.SampleText;
namespace Box2D.NET.Samples.Samples;
@@ -30,6 +33,34 @@ public class Sample : IDisposable
public const int m_maxTasks = 512;
public const int m_maxThreads = 64;
public const int m_profileCapacity = 512;
+ public const int m_maxHudLines = 64;
+ private const int MAX_SAMPLES = 256;
+
+ public struct HudLine
+ {
+ public B2HexColor color;
+ public string text;
+ }
+
+ private readonly struct ProfileRowDef
+ {
+ public readonly string name;
+ public readonly int indent;
+ public readonly Vector4 color;
+
+ public ProfileRowDef(string name, int indent, Vector4 color)
+ {
+ this.name = name;
+ this.indent = indent;
+ this.color = color;
+ }
+ }
+
+ private struct ScoredSample
+ {
+ public int index;
+ public int score;
+ }
#if DEBUG
public const bool m_isDebug = true;
@@ -49,8 +80,10 @@ public class Sample : IDisposable
private B2Vec2 m_mousePoint;
protected float m_mouseForceScale;
public int m_stepCount;
- private int m_textLine;
- private int m_textIncrement;
+
+ public readonly HudLine[] m_hudLines;
+ public int m_hudLineCount;
+ private float m_screenTextY;
//
private readonly B2Profile[] m_profiles;
@@ -61,6 +94,17 @@ public class Sample : IDisposable
//
private static bool s_showProfilePlots;
private static readonly bool[] s_profileRowOpen = new bool[22];
+ private static bool s_showHelp;
+ private static bool s_showAbout;
+ private static string s_pickerQuery = string.Empty;
+ private static string s_previousPickerQuery = string.Empty;
+ private static int s_pickerHighlight;
+ private static int s_previousPickerHighlight;
+ private static readonly int[] s_filteredSamples = new int[MAX_SAMPLES];
+ private static readonly ScoredSample[] s_scoredSamples = new ScoredSample[MAX_SAMPLES];
+ private static int s_filteredCount;
+ private static bool s_pickerJustOpened;
+ private static bool s_forcePickerScroll;
//
private bool m_didStep;
@@ -76,12 +120,13 @@ public Sample(SampleContext context)
m_worldId = b2_nullWorldId;
- m_textIncrement = 26;
- m_textLine = m_textIncrement;
m_mouseJointId = b2_nullJointId;
m_stepCount = 0;
m_didStep = false;
+ m_hudLines = new HudLine[m_maxHudLines];
+ m_hudLineCount = 0;
+ m_screenTextY = 0.0f;
m_mouseBodyId = b2_nullBodyId;
m_mousePoint = new B2Vec2();
@@ -157,344 +202,406 @@ public virtual void UpdateGui()
{
float fontSize = ImGui.GetFontSize();
- if (m_context.drawProfile)
+ if (m_context.showDiagnostics == false)
{
- ImGui.SetNextWindowPos(new Vector2(fontSize, 8.0f * fontSize), ImGuiCond.FirstUseEver);
- ImGui.Begin("Profile (ms)", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysAutoResize);
+ return;
+ }
- int count = (int)(m_profileWriteIndex - m_profileReadIndex);
+ float menuWidth = 14.0f * fontSize;
+ float drawerHeight = 16.0f * fontSize;
+ float drawerWidth = m_camera.width - menuWidth - 1.5f * fontSize;
- // Unroll ring buffer into per-field histories.
- const int kRowCount = 22;
- float[][] histories = new float[kRowCount][];
- float[] totals = new float[kRowCount];
- for (int i = 0; i < kRowCount; ++i)
- {
- histories[i] = new float[m_profileCapacity];
- }
+ ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - drawerHeight - 0.5f * fontSize));
+ ImGui.SetNextWindowSize(new Vector2(drawerWidth, drawerHeight));
- for (int i = 0; i < count; ++i)
- {
- int idx = (int)((m_profileReadIndex + (ulong)i) & (m_profileCapacity - 1));
- ref readonly B2Profile p = ref m_profiles[idx];
- histories[0][i] = p.step;
- histories[1][i] = p.pairs;
- histories[2][i] = p.collide;
- histories[3][i] = p.solve;
- histories[4][i] = p.solverSetup;
- histories[5][i] = p.constraints;
- histories[6][i] = p.prepareConstraints;
- histories[7][i] = p.integrateVelocities;
- histories[8][i] = p.warmStart;
- histories[9][i] = p.solveImpulses;
- histories[10][i] = p.integratePositions;
- histories[11][i] = p.relaxImpulses;
- histories[12][i] = p.applyRestitution;
- histories[13][i] = p.storeImpulses;
- histories[14][i] = p.splitIslands;
- histories[15][i] = p.transforms;
- histories[16][i] = p.jointEvents;
- histories[17][i] = p.hitEvents;
- histories[18][i] = p.refit;
- histories[19][i] = p.sleepIslands;
- histories[20][i] = p.bullets;
- histories[21][i] = p.sensors;
-
- totals[0] += p.step;
- totals[1] += p.pairs;
- totals[2] += p.collide;
- totals[3] += p.solve;
- totals[4] += p.solverSetup;
- totals[5] += p.constraints;
- totals[6] += p.prepareConstraints;
- totals[7] += p.integrateVelocities;
- totals[8] += p.warmStart;
- totals[9] += p.solveImpulses;
- totals[10] += p.integratePositions;
- totals[11] += p.relaxImpulses;
- totals[12] += p.applyRestitution;
- totals[13] += p.storeImpulses;
- totals[14] += p.splitIslands;
- totals[15] += p.transforms;
- totals[16] += p.jointEvents;
- totals[17] += p.hitEvents;
- totals[18] += p.refit;
- totals[19] += p.sleepIslands;
- totals[20] += p.bullets;
- totals[21] += p.sensors;
- }
+ ImGui.Begin("Diagnostics",
+ ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse |
+ ImGuiWindowFlags.NoTitleBar);
- ref readonly B2Profile cur = ref m_profiles[m_currentProfileIndex];
- float[] now =
- [
- cur.step, cur.pairs, cur.collide, cur.solve, cur.solverSetup,
- cur.constraints, cur.prepareConstraints, cur.integrateVelocities, cur.warmStart,
- cur.solveImpulses, cur.integratePositions, cur.relaxImpulses, cur.applyRestitution,
- cur.storeImpulses, cur.splitIslands, cur.transforms, cur.jointEvents,
- cur.hitEvents, cur.refit, cur.sleepIslands, cur.bullets, cur.sensors
- ];
-
- // Rolling average
- float[] avg = new float[kRowCount];
- if (count > 0)
+ if (ImGui.BeginTabBar("DiagnosticsTabs", ImGuiTabBarFlags.None))
+ {
+ if (ImGui.BeginTabItem("Profile"))
{
- float scale = 1.0f / count;
+ int count = (int)(m_profileWriteIndex - m_profileReadIndex);
+
+ const int kRowCount = 22;
+ float[][] histories = new float[kRowCount][];
+ float[] totals = new float[kRowCount];
for (int i = 0; i < kRowCount; ++i)
{
- avg[i] = scale * totals[i];
+ histories[i] = new float[m_profileCapacity];
}
- }
- string[] names =
- [
- "step", "pairs", "collide", "solve", "setup", "constraints", "prepare",
- "velocities", "warm start", "bias", "positions", "relax",
- "restitution", "store", "split islands", "transforms", "joint events",
- "hit events", "refit BVH", "sleep", "bullets", "sensors"
- ];
- int[] indents = [0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0];
- // Derive parent/child links from the indent levels so we can collapse subtrees.
- int[] parents = new int[kRowCount];
- bool[] hasChildren = new bool[kRowCount];
- int[] stack = new int[8];
- int stackSize = 0;
- for (int i = 0; i < kRowCount; ++i)
- {
- while (stackSize > 0 && indents[stack[stackSize - 1]] >= indents[i])
+ for (int i = 0; i < count; ++i)
{
- stackSize -= 1;
+ int idx = (int)((m_profileReadIndex + (ulong)i) & (m_profileCapacity - 1));
+ ref readonly B2Profile p = ref m_profiles[idx];
+ histories[0][i] = p.step;
+ histories[1][i] = p.pairs;
+ histories[2][i] = p.collide;
+ histories[3][i] = p.solve;
+ histories[4][i] = p.solverSetup;
+ histories[5][i] = p.constraints;
+ histories[6][i] = p.prepareConstraints;
+ histories[7][i] = p.integrateVelocities;
+ histories[8][i] = p.warmStart;
+ histories[9][i] = p.solveImpulses;
+ histories[10][i] = p.integratePositions;
+ histories[11][i] = p.relaxImpulses;
+ histories[12][i] = p.applyRestitution;
+ histories[13][i] = p.storeImpulses;
+ histories[14][i] = p.splitIslands;
+ histories[15][i] = p.transforms;
+ histories[16][i] = p.jointEvents;
+ histories[17][i] = p.hitEvents;
+ histories[18][i] = p.refit;
+ histories[19][i] = p.sleepIslands;
+ histories[20][i] = p.bullets;
+ histories[21][i] = p.sensors;
+ for (int j = 0; j < kRowCount; ++j)
+ {
+ totals[j] += histories[j][i];
+ }
}
- parents[i] = stackSize > 0 ? stack[stackSize - 1] : -1;
- stack[stackSize] = i;
- stackSize += 1;
-
- if (parents[i] >= 0)
+ // "now" smoothed over the last few frames so bars don't jitter visibly.
+ const int kNowWindow = 10;
+ float[] now = new float[kRowCount];
{
- hasChildren[parents[i]] = true;
+ int n = count < kNowWindow ? count : kNowWindow;
+ if (n > 0)
+ {
+ float inv = 1.0f / n;
+ for (int r = 0; r < kRowCount; ++r)
+ {
+ float sum = 0.0f;
+ for (int i = count - n; i < count; ++i)
+ {
+ sum += histories[r][i];
+ }
+ now[r] = sum * inv;
+ }
+ }
}
- }
-
- // Match Frame Time chart's first three colors so rows read with the line plot.
- Vector4 colorStep = new Vector4(102.0f / 255.0f, 153.0f / 255.0f, 1.0f, 1.0f);
- Vector4 colorCollide = new Vector4(1.0f, 140.0f / 255.0f, 51.0f / 255.0f, 1.0f);
- Vector4 colorSolve = new Vector4(102.0f / 255.0f, 204.0f / 255.0f, 102.0f / 255.0f, 1.0f);
- Vector4 colorDefault = new Vector4(220.0f / 255.0f, 220.0f / 255.0f, 220.0f / 255.0f, 1.0f);
-
- Vector4[] colors =
- [
- colorStep, colorDefault, colorCollide, colorSolve, colorDefault, colorDefault,
- colorDefault, colorDefault, colorDefault, colorDefault, colorDefault, colorDefault,
- colorDefault, colorDefault, colorDefault, colorDefault, colorDefault, colorDefault,
- colorDefault, colorDefault, colorDefault, colorDefault
- ];
- if (ImGui.Button("Reset"))
- {
- ResetProfile();
- }
- ImGui.SameLine();
- ImGui.Checkbox("Show plots", ref s_showProfilePlots);
-
- ImGuiTableFlags tableFlags = ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit;
- int columnCount = s_showProfilePlots ? 6 : 5;
- if (ImGui.BeginTable("profile", columnCount, tableFlags))
- {
- ImGui.TableSetupColumn("section", ImGuiTableColumnFlags.WidthFixed, 8.0f * fontSize);
- ImGui.TableSetupColumn("now", ImGuiTableColumnFlags.WidthFixed, 3.0f * fontSize);
- ImGui.TableSetupColumn("avg", ImGuiTableColumnFlags.WidthFixed, 3.0f * fontSize);
- ImGui.TableSetupColumn("max", ImGuiTableColumnFlags.WidthFixed, 3.0f * fontSize);
- ImGui.TableSetupColumn("% step", ImGuiTableColumnFlags.WidthFixed, 8.0f * fontSize);
- if (s_showProfilePlots)
+ float[] avg = new float[kRowCount];
+ if (count > 0)
{
- ImGui.TableSetupColumn("history", ImGuiTableColumnFlags.WidthFixed, 16.0f * fontSize);
+ float scale = 1.0f / count;
+ for (int i = 0; i < kRowCount; ++i)
+ {
+ avg[i] = scale * totals[i];
+ }
}
- ImGui.TableHeadersRow();
-
- float rowHeight = 1.5f * fontSize;
-
- // Bars are drawn relative to the step row so the proportions are visually consistent.
- float stepNow = b2MaxFloat(cur.step, 0.001f);
- for (int row = 0; row < kRowCount; ++row)
+ float[] rowMax = new float[kRowCount];
+ for (int r = 0; r < kRowCount; ++r)
{
- bool visible = true;
- for (int parent = parents[row]; parent >= 0; parent = parents[parent])
+ for (int i = 0; i < count; ++i)
{
- if (s_profileRowOpen[parent] == false)
+ if (histories[r][i] > rowMax[r])
{
- visible = false;
- break;
+ rowMax[r] = histories[r][i];
}
}
+ }
- if (visible == false)
+ Vector4 colorStep = new Vector4(102.0f / 255.0f, 153.0f / 255.0f, 1.0f, 1.0f);
+ Vector4 colorPairs = new Vector4(220.0f / 255.0f, 220.0f / 255.0f, 220.0f / 255.0f, 1.0f);
+ Vector4 colorCollide = new Vector4(1.0f, 140.0f / 255.0f, 51.0f / 255.0f, 1.0f);
+ Vector4 colorSolve = new Vector4(102.0f / 255.0f, 204.0f / 255.0f, 102.0f / 255.0f, 1.0f);
+ Vector4 colorSensors = new Vector4(200.0f / 255.0f, 120.0f / 255.0f, 220.0f / 255.0f, 1.0f);
+ Vector4 colorOther = new Vector4(90.0f / 255.0f, 90.0f / 255.0f, 90.0f / 255.0f, 1.0f);
+ Vector4 colorDefault = new Vector4(220.0f / 255.0f, 220.0f / 255.0f, 220.0f / 255.0f, 1.0f);
+
+ ProfileRowDef[] rows =
+ [
+ new("step", 0, colorStep), new("pairs", 0, colorPairs), new("collide", 0, colorCollide),
+ new("solve", 0, colorSolve), new("setup", 1, colorDefault), new("constraints", 1, colorDefault),
+ new("prepare", 2, colorDefault), new("velocities", 2, colorDefault), new("warm start", 2, colorDefault),
+ new("bias", 2, colorDefault), new("positions", 2, colorDefault), new("relax", 2, colorDefault),
+ new("restitution", 2, colorDefault), new("store", 2, colorDefault), new("split islands", 2, colorDefault),
+ new("transforms", 1, colorDefault), new("joint events", 1, colorDefault), new("hit events", 1, colorDefault),
+ new("refit BVH", 1, colorDefault), new("sleep", 1, colorDefault), new("bullets", 1, colorDefault),
+ new("sensors", 0, colorSensors),
+ ];
+
+ int[] parents = new int[kRowCount];
+ bool[] hasChildren = new bool[kRowCount];
+ {
+ int[] stack = new int[8];
+ int stackSize = 0;
+ for (int i = 0; i < kRowCount; ++i)
{
- continue;
+ while (stackSize > 0 && rows[stack[stackSize - 1]].indent >= rows[i].indent)
+ {
+ --stackSize;
+ }
+ parents[i] = stackSize > 0 ? stack[stackSize - 1] : -1;
+ stack[stackSize++] = i;
+ if (parents[i] >= 0)
+ {
+ hasChildren[parents[i]] = true;
+ }
}
+ }
- float[] history = histories[row];
+ float stepNow = b2MaxFloat(now[0], 0.001f);
- // Rolling max from live history, replacing the old session-sticky max.
- float rollingMax = 0.0f;
- for (int i = 0; i < count; ++i)
- {
- rollingMax = b2MaxFloat(rollingMax, history[i]);
- }
+ if (ImGui.Button("Reset"))
+ {
+ ResetProfile();
+ }
+ ImGui.SameLine();
+ ImGui.Checkbox("Show plots", ref s_showProfilePlots);
+ ImGui.SameLine();
+ ImGui.Text($" step {now[0]:F2} ms");
- ImGui.TableNextRow();
- ImGui.TableNextColumn();
- if (indents[row] > 0)
- {
- ImGui.Indent(indents[row] * fontSize);
- }
- if (hasChildren[row])
+ // Flame strip: step subdivided by top-level children.
+ {
+ float pairsT = now[1];
+ float collideT = now[2];
+ float solveT = now[3];
+ float sensorsT = now[21];
+ float otherT = b2MaxFloat(stepNow - pairsT - collideT - solveT - sensorsT, 0.0f);
+
+ float availWidth = ImGui.GetContentRegionAvail().X;
+ float barHeight = 1.5f * fontSize;
+ ImDrawListPtr drawList = ImGui.GetWindowDrawList();
+ Vector2 cursor = ImGui.GetCursorScreenPos();
+ float x = cursor.X;
+
+ void AddSegment(float t, Vector4 color)
{
- ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.OpenOnArrow | ImGuiTreeNodeFlags.OpenOnDoubleClick |
- ImGuiTreeNodeFlags.NoTreePushOnOpen;
- ImGui.PushStyleColor(ImGuiCol.Text, colors[row]);
- s_profileRowOpen[row] = ImGui.TreeNodeEx(names[row], flags);
- ImGui.PopStyleColor();
+ float width = availWidth * (t / stepNow);
+ if (width > 0.0f)
+ {
+ drawList.AddRectFilled(new Vector2(x, cursor.Y), new Vector2(x + width, cursor.Y + barHeight), ImGui.ColorConvertFloat4ToU32(color));
+ x += width;
+ }
}
- else
+
+ AddSegment(pairsT, colorPairs);
+ AddSegment(collideT, colorCollide);
+ AddSegment(solveT, colorSolve);
+ AddSegment(sensorsT, colorSensors);
+ AddSegment(otherT, colorOther);
+
+ ImGui.Dummy(new Vector2(availWidth, barHeight));
+ }
+
+ ImGuiTableFlags tableFlags = ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.RowBg |
+ ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollY;
+
+ int columnCount = s_showProfilePlots ? 6 : 5;
+ Vector2 tableSize = ImGui.GetContentRegionAvail();
+ if (ImGui.BeginTable("profile", columnCount, tableFlags, tableSize))
+ {
+ ImGui.TableSetupColumn("section", ImGuiTableColumnFlags.WidthFixed, 8.0f * fontSize);
+ ImGui.TableSetupColumn("now", ImGuiTableColumnFlags.WidthFixed, 3.0f * fontSize);
+ ImGui.TableSetupColumn("avg", ImGuiTableColumnFlags.WidthFixed, 3.0f * fontSize);
+ ImGui.TableSetupColumn("max", ImGuiTableColumnFlags.WidthFixed, 3.0f * fontSize);
+ ImGui.TableSetupColumn("% step", ImGuiTableColumnFlags.WidthFixed, 8.0f * fontSize);
+ if (s_showProfilePlots)
{
- float leafIndent = ImGui.GetTreeNodeToLabelSpacing();
- ImGui.Indent(leafIndent);
- ImGui.PushStyleColor(ImGuiCol.Text, colors[row]);
- ImGui.TextUnformatted(names[row]);
- ImGui.PopStyleColor();
- ImGui.Unindent(leafIndent);
+ ImGui.TableSetupColumn("history", ImGuiTableColumnFlags.WidthFixed, 16.0f * fontSize);
}
- if (indents[row] > 0)
+ ImGui.TableHeadersRow();
+
+ float rowHeight = 1.5f * fontSize;
+
+ for (int r = 0; r < kRowCount; ++r)
{
- ImGui.Unindent(indents[row] * fontSize);
- }
+ bool visible = true;
+ for (int p = parents[r]; p >= 0; p = parents[p])
+ {
+ if (s_profileRowOpen[p] == false)
+ {
+ visible = false;
+ break;
+ }
+ }
+ if (visible == false)
+ {
+ continue;
+ }
- ImGui.TableNextColumn();
- ImGui.Text($"{now[row],6:F2}");
- ImGui.TableNextColumn();
- ImGui.Text($"{avg[row],6:F2}");
- ImGui.TableNextColumn();
- ImGui.Text($"{rollingMax,6:F2}");
+ // Hide leaf rows that are entirely zero; parents stay so structure reads.
+ if (hasChildren[r] == false && now[r] == 0.0f && avg[r] == 0.0f && rowMax[r] == 0.0f)
+ {
+ continue;
+ }
- ImGui.TableNextColumn();
- float frac = b2ClampFloat(now[row] / stepNow, 0.0f, 1.0f);
- ImGui.PushStyleColor(ImGuiCol.PlotHistogram, colors[row]);
- ImGui.ProgressBar(frac, new Vector2(-float.Epsilon, 0.0f), "");
- ImGui.PopStyleColor();
+ ProfileRowDef row = rows[r];
+ float[] history = histories[r];
+
+ ImGui.TableNextRow();
- if (s_showProfilePlots)
- {
ImGui.TableNextColumn();
- if (count > 1)
+ if (row.indent > 0)
+ {
+ ImGui.Indent(row.indent * fontSize);
+ }
+ if (hasChildren[r])
{
- ImGui.PushStyleColor(ImGuiCol.PlotLines, colors[row]);
- ImGui.PlotLines($"##h{row}", ref history[0], count, 0, null, 0.0f, rollingMax * 1.05f + 0.001f, new Vector2(-float.Epsilon, rowHeight));
+ ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.OpenOnArrow | ImGuiTreeNodeFlags.OpenOnDoubleClick |
+ ImGuiTreeNodeFlags.NoTreePushOnOpen;
+ ImGui.PushStyleColor(ImGuiCol.Text, row.color);
+ s_profileRowOpen[r] = ImGui.TreeNodeEx(row.name, flags);
ImGui.PopStyleColor();
}
+ else
+ {
+ float leafIndent = ImGui.GetTreeNodeToLabelSpacing();
+ ImGui.Indent(leafIndent);
+ ImGui.PushStyleColor(ImGuiCol.Text, row.color);
+ ImGui.TextUnformatted(row.name);
+ ImGui.PopStyleColor();
+ ImGui.Unindent(leafIndent);
+ }
+ if (row.indent > 0)
+ {
+ ImGui.Unindent(row.indent * fontSize);
+ }
+
+ ImGui.TableNextColumn();
+ ImGui.Text($"{now[r],6:F2}");
+ ImGui.TableNextColumn();
+ ImGui.Text($"{avg[r],6:F2}");
+ ImGui.TableNextColumn();
+ ImGui.Text($"{rowMax[r],6:F2}");
+
+ ImGui.TableNextColumn();
+ float fraction = b2ClampFloat(now[r] / stepNow, 0.0f, 1.0f);
+ ImGui.PushStyleColor(ImGuiCol.PlotHistogram, row.color);
+ ImGui.ProgressBar(fraction, new Vector2(-float.Epsilon, 0.0f), "");
+ ImGui.PopStyleColor();
+
+ if (s_showProfilePlots)
+ {
+ ImGui.TableNextColumn();
+ if (count > 1)
+ {
+ ImGui.PushStyleColor(ImGuiCol.PlotLines, row.color);
+ ImGui.PlotLines($"##h{r}", ref history[0], count, 0, null, 0.0f, rowMax[r] * 1.05f + 0.001f,
+ new Vector2(-float.Epsilon, rowHeight));
+ ImGui.PopStyleColor();
+ }
+ }
}
+ ImGui.EndTable();
}
- ImGui.EndTable();
+ ImGui.EndTabItem();
}
- ImGui.End();
- }
-
- if (m_context.drawCounters)
- {
- B2Counters s = b2World_GetCounters(m_worldId);
- int colorCount = s.colorCounts.Length;
- int overflowIndex = colorCount - 1;
-
- // Bars are scaled to the largest non-overflow color so the distribution shape reads clearly;
- // overflow gets its own bar against the same scale, with a red tint to flag coupling problems.
- int totalCount = 0;
- int maxCount = 1;
- for (int i = 0; i < colorCount; ++i)
+ if (ImGui.BeginTabItem("Frame Time"))
{
- totalCount += s.colorCounts[i];
- if (i != overflowIndex && s.colorCounts[i] > maxCount)
+ float maxValue = 0.0f;
+ int count = (int)(m_profileWriteIndex - m_profileReadIndex);
+ for (int i = 0; i < count; ++i)
{
- maxCount = s.colorCounts[i];
+ int index = (int)((m_profileReadIndex + (ulong)i) & (m_profileCapacity - 1));
+ m_frameTimes[i] = i / 60.0f;
+ maxValue = b2MaxFloat(m_profiles[index].step, maxValue);
}
- }
- ImGui.SetNextWindowPos(new Vector2(fontSize, 8.0f * fontSize), ImGuiCond.FirstUseEver);
- ImGui.Begin("Counters", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysAutoResize);
- ImGui.Text($"bodies/shapes/contacts/joints = {s.bodyCount}/{s.shapeCount}/{s.contactCount}/{s.jointCount}");
+ // This project does not depend on ImPlot, so draw the same profile data with ImGui's draw list.
+ DrawProfilePlot("Profile", count, maxValue, m_profileCapacity / 60.0f, ImGui.GetContentRegionAvail());
- float recycledFraction = s.awakeContactCount > 0
- ? b2ClampFloat((float)s.recycledContactCount / s.awakeContactCount, 0.0f, 1.0f)
- : 0.0f;
- ImGui.TextUnformatted("recycled contacts");
- ImGui.SameLine();
- ImGui.ProgressBar(recycledFraction, new Vector2(-float.Epsilon, 0.0f), $"{s.recycledContactCount} / {s.awakeContactCount}");
+ ImGui.EndTabItem();
+ }
- ImGui.Text($"islands/tasks = {s.islandCount}/{s.taskCount}");
- ImGui.Text($"tree height static/movable = {s.staticTreeHeight}/{s.treeHeight}");
- ImGui.Text($"stack allocator size = {s.stackUsed / 1024} K");
- ImGui.Text($"total allocation = {s.byteCount / 1024} K");
+ if (ImGui.BeginTabItem("Counters"))
+ {
+ B2Counters counters = b2World_GetCounters(m_worldId);
+ B2Capacity capacity = b2World_GetMaxCapacity(m_worldId);
+ int colorCount = counters.colorCounts.Length;
+ int overflowIndex = colorCount - 1;
- ImGui.Separator();
- B2Capacity capacity = b2World_GetMaxCapacity(m_worldId);
- ImGui.TextUnformatted("max capacities");
- ImGui.BulletText($"static shapes/bodies = {capacity.staticShapeCount}/{capacity.staticBodyCount}");
- ImGui.BulletText($"dynamic shapes/bodies = {capacity.dynamicShapeCount}/{capacity.dynamicBodyCount}");
- ImGui.BulletText($"contacts = {capacity.contactCount}");
+ if (ImGui.BeginTable("counters_layout", 2, ImGuiTableFlags.SizingFixedFit))
+ {
+ ImGui.TableSetupColumn("left", ImGuiTableColumnFlags.WidthFixed, 22.0f * fontSize);
+ ImGui.TableSetupColumn("right", ImGuiTableColumnFlags.WidthStretch);
+ ImGui.TableNextRow();
+ ImGui.TableNextColumn();
- ImGui.Separator();
- ImGui.Text($"{totalCount} constraints across {colorCount} colors");
+ ImGui.Text($"bodies {counters.bodyCount} / {capacity.staticBodyCount + capacity.dynamicBodyCount}");
+ ImGui.Text($"shapes {counters.shapeCount} / {capacity.staticShapeCount + capacity.dynamicShapeCount}");
+ ImGui.Text($"contacts {counters.contactCount} / {capacity.contactCount}");
+ ImGui.Text($"joints {counters.jointCount}");
+ ImGui.Text($"islands/tasks {counters.islandCount} / {counters.taskCount}");
+ ImGui.Text($"tree height static/movable {counters.staticTreeHeight} / {counters.treeHeight}");
+ ImGui.Text($"alloc {counters.byteCount / 1024} K stack {counters.stackUsed / 1024} K");
- ImGuiTableFlags tableFlags = ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit;
- if (ImGui.BeginTable("graphColors", 3, tableFlags))
- {
- ImGui.TableSetupColumn("color", ImGuiTableColumnFlags.WidthFixed, 3.5f * fontSize);
- ImGui.TableSetupColumn("count", ImGuiTableColumnFlags.WidthFixed, 5.0f * fontSize);
- ImGui.TableSetupColumn("share", ImGuiTableColumnFlags.WidthFixed, 16.0f * fontSize);
- ImGui.TableHeadersRow();
+ {
+ float fraction = counters.awakeContactCount > 0
+ ? b2ClampFloat((float)counters.recycledContactCount / counters.awakeContactCount, 0.0f, 1.0f)
+ : 0.0f;
+ ImGui.TextUnformatted("recycled");
+ ImGui.SameLine();
+ ImGui.ProgressBar(fraction, new Vector2(-float.Epsilon, 0.0f),
+ $"{counters.recycledContactCount} / {counters.awakeContactCount}");
+ }
- float invMax = 1.0f / maxCount;
- for (int i = 0; i < colorCount; ++i)
- {
- int count = s.colorCounts[i];
- bool isOverflow = i == overflowIndex;
+ ImGui.TableNextColumn();
- // Skip empty slots, but always show overflow -- a non-zero overflow row is the signal we care about.
- if (count == 0 && isOverflow == false)
+ int totalCount = 0;
+ int normalCount = 0;
+ for (int i = 0; i < colorCount; ++i)
{
- continue;
+ totalCount += counters.colorCounts[i];
+ if (i != overflowIndex)
+ {
+ normalCount += counters.colorCounts[i];
+ }
}
+ int overflowCount = counters.colorCounts[overflowIndex];
- Vector4 color = isOverflow
- ? new Vector4(220.0f / 255.0f, 60.0f / 255.0f, 60.0f / 255.0f, 1.0f)
- : HexToColor(b2GetGraphColor(i));
+ ImGui.Text($"{totalCount} constraints across {colorCount - 1} colors");
- ImGui.TableNextRow();
- ImGui.TableNextColumn();
- ImGui.PushStyleColor(ImGuiCol.Text, color);
- ImGui.TextUnformatted(isOverflow ? "over" : i.ToString());
- ImGui.PopStyleColor();
+ float availableWidth = ImGui.GetContentRegionAvail().X;
+ float barHeight = 2.0f * fontSize;
+ ImDrawListPtr drawList = ImGui.GetWindowDrawList();
- ImGui.TableNextColumn();
- ImGui.Text(count.ToString());
+ Vector2 cursor = ImGui.GetCursorScreenPos();
+ drawList.AddRectFilled(cursor, new Vector2(cursor.X + availableWidth, cursor.Y + barHeight),
+ ImGui.ColorConvertFloat4ToU32(new Vector4(40.0f / 255.0f, 40.0f / 255.0f, 40.0f / 255.0f, 1.0f)));
+ if (normalCount > 0)
+ {
+ float x = cursor.X;
+ float invTotal = 1.0f / normalCount;
+ for (int i = 0; i < overflowIndex; ++i)
+ {
+ int itemCount = counters.colorCounts[i];
+ if (itemCount == 0)
+ {
+ continue;
+ }
+ float segmentWidth = availableWidth * itemCount * invTotal;
+ uint color = ImGui.ColorConvertFloat4ToU32(HexToColor(b2GetGraphColor(i)));
+ drawList.AddRectFilled(new Vector2(x, cursor.Y), new Vector2(x + segmentWidth, cursor.Y + barHeight), color);
+ x += segmentWidth;
+ }
+ }
+ ImGui.Dummy(new Vector2(availableWidth, barHeight));
- ImGui.TableNextColumn();
- ImGui.PushStyleColor(ImGuiCol.PlotHistogram, color);
- ImGui.ProgressBar(b2ClampFloat(count * invMax, 0.0f, 1.0f), new Vector2(-float.Epsilon, 0.0f), "");
+ ImGui.Spacing();
+ float overflowFraction = totalCount > 0 ? (float)overflowCount / totalCount : 0.0f;
+ ImGui.PushStyleColor(ImGuiCol.PlotHistogram, new Vector4(220.0f / 255.0f, 60.0f / 255.0f, 60.0f / 255.0f, 1.0f));
+ ImGui.ProgressBar(overflowFraction, new Vector2(-float.Epsilon, 0.0f), $"overflow {overflowCount}");
ImGui.PopStyleColor();
+
+ ImGui.EndTable();
}
- ImGui.EndTable();
+ ImGui.EndTabItem();
}
- ImGui.End();
+ ImGui.EndTabBar();
}
- if (m_context.frameTime)
- {
- UpdateFrameTimeGui(fontSize);
- }
+ ImGui.End();
}
private static Vector4 HexToColor(B2HexColor color)
@@ -503,43 +610,8 @@ private static Vector4 HexToColor(B2HexColor color)
return new Vector4(((hex >> 16) & 0xFF) / 255.0f, ((hex >> 8) & 0xFF) / 255.0f, (hex & 0xFF) / 255.0f, 1.0f);
}
- private void UpdateFrameTimeGui(float fontSize)
+ private void DrawProfilePlot(string label, int count, float maxValue, float maxTime, Vector2 size)
{
- float frameTimeHeight = 30.0f * fontSize;
- float frameTimeWidth = 50.0f * fontSize;
-
- ImGui.SetNextWindowPos(new Vector2(3.0f * fontSize, 3.0f * fontSize), ImGuiCond.FirstUseEver);
- ImGui.SetNextWindowSize(new Vector2(frameTimeWidth, frameTimeHeight), ImGuiCond.FirstUseEver);
-
- ImGui.Begin("Frame Time", ref m_context.frameTime, ImGuiWindowFlags.NoCollapse);
- ImGui.PushItemWidth(ImGui.GetWindowWidth() - 2.0f * fontSize);
-
- int count = (int)(m_profileWriteIndex - m_profileReadIndex);
- float maxValue = 0.0f;
- for (int i = 0; i < count; ++i)
- {
- int index = (int)((m_profileReadIndex + (ulong)i) & (m_profileCapacity - 1));
- m_frameTimes[i] = i / 60.0f;
- maxValue = b2MaxFloat(maxValue, m_profiles[index].step);
- }
-
- // This is the pixel size, not the range.
- Vector2 plotSize = new Vector2(-1.0f, 22.0f * fontSize);
- DrawProfilePlot("Profile", count, maxValue, plotSize);
-
- ImGui.PopItemWidth();
- ImGui.End();
- }
-
- private void DrawProfilePlot(string label, int count, float maxValue, Vector2 size)
- {
- if (count == 0)
- {
- ImGui.TextUnformatted("No frame data");
- return;
- }
-
- maxValue = b2MaxFloat(maxValue, 0.001f);
Vector2 canvasPos = ImGui.GetCursorScreenPos();
Vector2 canvasSize = size;
if (canvasSize.X < 0.0f)
@@ -552,29 +624,57 @@ private void DrawProfilePlot(string label, int count, float maxValue, Vector2 si
ImGui.InvisibleButton(label, canvasSize);
- Vector2 min = canvasPos;
- Vector2 max = canvasPos + canvasSize;
+ Vector2 min = canvasPos + new Vector2(42.0f, 8.0f);
+ Vector2 max = canvasPos + canvasSize - new Vector2(12.0f, 28.0f);
+ Vector2 plotSize = max - min;
ImDrawListPtr drawList = ImGui.GetWindowDrawList();
uint borderColor = ImGui.ColorConvertFloat4ToU32(new Vector4(0.35f, 0.35f, 0.35f, 1.0f));
uint gridColor = ImGui.ColorConvertFloat4ToU32(new Vector4(0.20f, 0.20f, 0.20f, 1.0f));
uint textColor = ImGui.ColorConvertFloat4ToU32(new Vector4(0.85f, 0.85f, 0.85f, 1.0f));
+ Vector4 stepColor = new Vector4(0.20f, 0.70f, 1.00f, 1.0f);
+ Vector4 collideColor = new Vector4(0.95f, 0.65f, 0.20f, 1.0f);
+ Vector4 solveColor = new Vector4(0.30f, 0.85f, 0.45f, 1.0f);
drawList.AddRect(min, max, borderColor);
for (int i = 1; i < 4; ++i)
{
- float y = min.Y + canvasSize.Y * i / 4.0f;
+ float y = min.Y + plotSize.Y * i / 4.0f;
drawList.AddLine(new Vector2(min.X, y), new Vector2(max.X, y), gridColor);
+
+ float x = min.X + plotSize.X * i / 4.0f;
+ drawList.AddLine(new Vector2(x, min.Y), new Vector2(x, max.Y), gridColor);
}
- DrawProfileSeries(drawList, min, canvasSize, count, maxValue, p => p.step, new Vector4(0.20f, 0.70f, 1.00f, 1.0f));
- DrawProfileSeries(drawList, min, canvasSize, count, maxValue, p => p.collide, new Vector4(0.95f, 0.65f, 0.20f, 1.0f));
- DrawProfileSeries(drawList, min, canvasSize, count, maxValue, p => p.solve, new Vector4(0.30f, 0.85f, 0.45f, 1.0f));
+ float plotMaxValue = maxValue > 0.0f ? maxValue : 1.0f;
+ DrawProfileSeries(drawList, min, plotSize, count, plotMaxValue, maxTime, p => p.step, stepColor);
+ DrawProfileSeries(drawList, min, plotSize, count, plotMaxValue, maxTime, p => p.collide, collideColor);
+ DrawProfileSeries(drawList, min, plotSize, count, plotMaxValue, maxTime, p => p.solve, solveColor);
+
+ drawList.AddText(new Vector2(canvasPos.X + 4.0f, min.Y), textColor, "ms");
+ drawList.AddText(new Vector2(canvasPos.X + 4.0f, min.Y + ImGui.GetFontSize()), textColor, FormatFloat(maxValue));
+ drawList.AddText(new Vector2(min.X, max.Y + 4.0f), textColor, "0");
+ drawList.AddText(new Vector2(max.X - 36.0f, max.Y + 4.0f), textColor, FormatFloat(maxTime));
+ drawList.AddText(new Vector2(max.X + 2.0f, max.Y + 4.0f), textColor, "t");
+
+ Vector2 legend = min + new Vector2(8.0f, 6.0f);
+ legend = DrawProfileLegendItem(drawList, legend, "step", stepColor, textColor);
+ legend = DrawProfileLegendItem(drawList, legend, "collide", collideColor, textColor);
+ DrawProfileLegendItem(drawList, legend, "solve", solveColor, textColor);
+ }
- drawList.AddText(min + new Vector2(8.0f, 6.0f), textColor, $"step / collide / solve max {maxValue:F2} ms");
- drawList.AddText(new Vector2(min.X + 8.0f, max.Y - 22.0f), textColor, $"0s .. {m_frameTimes[count - 1]:F1}s");
+ private static Vector2 DrawProfileLegendItem(ImDrawListPtr drawList, Vector2 position, string name, Vector4 color, uint textColor)
+ {
+ uint lineColor = ImGui.ColorConvertFloat4ToU32(color);
+ float centerY = position.Y + 0.5f * ImGui.GetFontSize();
+ drawList.AddLine(new Vector2(position.X, centerY), new Vector2(position.X + 14.0f, centerY), lineColor, 2.0f);
+ position.X += 18.0f;
+ drawList.AddText(position, textColor, name);
+ position.X += ImGui.CalcTextSize(name).X + 12.0f;
+ return position;
}
- private void DrawProfileSeries(ImDrawListPtr drawList, Vector2 origin, Vector2 size, int count, float maxValue, Func selector, Vector4 color)
+ private void DrawProfileSeries(ImDrawListPtr drawList, Vector2 origin, Vector2 size, int count, float maxValue, float maxTime,
+ Func selector, Vector4 color)
{
if (count < 2)
{
@@ -583,13 +683,12 @@ private void DrawProfileSeries(ImDrawListPtr drawList, Vector2 origin, Vector2 s
uint lineColor = ImGui.ColorConvertFloat4ToU32(color);
Vector2 previous = default;
- float invCount = 1.0f / (count - 1);
for (int i = 0; i < count; ++i)
{
int index = (int)((m_profileReadIndex + (ulong)i) & (m_profileCapacity - 1));
float value = selector(m_profiles[index]);
- float x = origin.X + size.X * i * invCount;
+ float x = origin.X + size.X * m_frameTimes[i] / maxTime;
float y = origin.Y + size.Y * (1.0f - b2ClampFloat(value / maxValue, 0.0f, 1.0f));
Vector2 current = new Vector2(x, y);
@@ -601,9 +700,19 @@ private void DrawProfileSeries(ImDrawListPtr drawList, Vector2 origin, Vector2 s
previous = current;
}
}
+
public void ResetText()
{
- m_textLine = m_textIncrement;
+ m_hudLineCount = 0;
+ float fontSize = ImGui.GetFontSize();
+ if (m_context.showUI)
+ {
+ m_screenTextY = ImGui.GetFrameHeight() + 1.5f * fontSize;
+ }
+ else
+ {
+ m_screenTextY = 3.0f * fontSize;
+ }
}
public bool QueryCallback(B2ShapeId shapeId, object context)
@@ -711,25 +820,44 @@ public virtual void MouseMove(B2Vec2 p)
public void DrawColoredTextLine(B2HexColor color, string text)
{
- if (m_context.showUI == false)
+ if (m_context.showUI == false || m_hudLineCount >= m_maxHudLines)
{
return;
}
- DrawScreenString(m_draw, 5, m_textLine, color, text);
- m_textLine += m_textIncrement;
+ m_hudLines[m_hudLineCount].color = color;
+ m_hudLines[m_hudLineCount].text = TruncateText(text);
+ m_hudLineCount += 1;
}
public void DrawTextLine(string text)
{
- if (m_context.showUI == false)
+ if (m_context.showUI == false || m_hudLineCount >= m_maxHudLines)
{
return;
}
- DrawScreenString(m_draw, 5, m_textLine, B2HexColor.b2_colorWhite, text);
- m_textLine += m_textIncrement;
+ m_hudLines[m_hudLineCount].color = B2HexColor.b2_colorWhite;
+ m_hudLines[m_hudLineCount].text = TruncateText(text);
+ m_hudLineCount += 1;
+ }
+
+ public void DrawScreenTextLine(string text)
+ {
+ DrawScreenString(m_draw, 5.0f, m_screenTextY, B2HexColor.b2_colorWhite, TruncateText(text));
+ m_screenTextY += 1.5f * ImGui.GetFontSize();
+ }
+
+ public void DrawColoredScreenTextLine(B2HexColor color, string text)
+ {
+ DrawScreenString(m_draw, 5.0f, m_screenTextY, color, TruncateText(text));
+ m_screenTextY += 1.5f * ImGui.GetFontSize();
+ }
+
+ private static string TruncateText(string text)
+ {
+ return text.Length > 255 ? text[..255] : text;
}
public void ResetProfile()
@@ -753,6 +881,12 @@ public virtual void Step()
{
timeStep = 0.0f;
}
+
+ if (m_context.showUI)
+ {
+ DrawTextLine("****PAUSED****");
+ DrawTextLine("");
+ }
}
if (B2_IS_NON_NULL(m_mouseJointId) && b2Joint_IsValid(m_mouseJointId) == false)
@@ -801,20 +935,16 @@ public virtual void Step()
public virtual void Draw()
{
- if (m_context.pause)
- {
- if (m_context.showUI)
- {
- DrawTextLine("****PAUSED****");
- }
- }
-
m_context.debugDraw.drawingBounds = GetViewBounds(m_context.camera);
b2World_Draw(m_worldId, m_context.debugDraw);
}
+ public virtual void BuildSamplePanel()
+ {
+ }
+
public void ShiftOrigin(B2Vec2 newOrigin)
{
// m_world.ShiftOrigin(newOrigin);
@@ -843,184 +973,496 @@ public static void SelectSample(SampleContext context, int selection, bool resta
context.restart = false;
}
- public static void UpdateSampleUI(SampleContext context)
+ // Case-insensitive subsequence match. Returns >=0 score on match, -1 on no match.
+ // Empty needle returns 0 so an empty query lets all samples through with a neutral score.
+ private static int FuzzyScore(string needle, string haystack)
{
- int maxWorkers = B2_MAX_WORKERS;
- B2WorldId worldId = context.sample.m_worldId;
+ if (string.IsNullOrEmpty(needle))
+ {
+ return 0;
+ }
- float fontSize = ImGui.GetFontSize();
- float menuWidth = 13.0f * fontSize;
- if (context.showUI)
+ int score = 0;
+ int hi = 0;
+ int previousMatchHi = -2;
+
+ for (int ni = 0; ni < needle.Length; ++ni)
{
- ImGui.SetNextWindowPos(new Vector2(context.camera.width - menuWidth - 0.5f * fontSize, 0.5f * fontSize));
- ImGui.SetNextWindowSize(new Vector2(menuWidth, context.camera.height - fontSize));
+ char nc = char.ToLowerInvariant(needle[ni]);
+ while (hi < haystack.Length && char.ToLowerInvariant(haystack[hi]) != nc)
+ {
+ ++hi;
+ }
+ if (hi == haystack.Length)
+ {
+ return -1;
+ }
+
+ int bonus = 1;
+ if (hi == 0)
+ {
+ bonus += 10; // prefix match
+ }
+ else if (char.IsLetterOrDigit(haystack[hi - 1]) == false)
+ {
+ bonus += 5; // word-start (after _, space, etc.)
+ }
+ if (hi == previousMatchHi + 1)
+ {
+ bonus += 3; // contiguous run
+ }
+
+ score += bonus;
+ previousMatchHi = hi;
+ ++hi;
+ }
- ImGui.Begin("Tools", ref context.showUI, ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse);
+ return score;
+ }
- if (ImGui.BeginTabBar("ControlTabs", ImGuiTabBarFlags.None))
+ private static void RebuildSampleFilter(string query)
+ {
+ int sampleCount = Math.Min(SampleFactory.Shared.SampleCount, MAX_SAMPLES);
+ int count = 0;
+ for (int i = 0; i < sampleCount; ++i)
+ {
+ int nameScore = FuzzyScore(query, SampleFactory.Shared.GetName(i));
+ int categoryScore = FuzzyScore(query, SampleFactory.Shared.GetCategory(i));
+ int best = -1;
+ if (nameScore >= 0)
{
- if (ImGui.BeginTabItem("Controls"))
- {
- ImGui.PushItemWidth(100.0f);
- ImGui.SliderInt("Sub-steps", ref context.subStepCount, 1, 32);
- ImGui.SliderFloat("Hertz", ref context.hertz, 5.0f, 240.0f, "%.0f hz");
+ best = nameScore * 2; // name matches outweigh category-only matches
+ }
+ if (categoryScore >= 0 && categoryScore > best)
+ {
+ best = categoryScore;
+ }
+ if (best < 0)
+ {
+ continue;
+ }
+ s_scoredSamples[count].index = i;
+ s_scoredSamples[count].score = best;
+ ++count;
+ }
- if (ImGui.SliderInt("Workers", ref context.workerCount, 1, maxWorkers))
- {
- context.workerCount = b2ClampInt(context.workerCount, 1, maxWorkers);
- SelectSample(context, context.sampleIndex, true);
- }
- ImGui.PopItemWidth();
+ // Stable insertion sort by score desc; equal scores keep registry order
+ // (which main.cpp sorts by category then name).
+ for (int i = 1; i < count; ++i)
+ {
+ ScoredSample temporary = s_scoredSamples[i];
+ int j = i - 1;
+ while (j >= 0 && s_scoredSamples[j].score < temporary.score)
+ {
+ s_scoredSamples[j + 1] = s_scoredSamples[j];
+ --j;
+ }
+ s_scoredSamples[j + 1] = temporary;
+ }
+ for (int i = 0; i < count; ++i)
+ {
+ s_filteredSamples[i] = s_scoredSamples[i].index;
+ }
+ s_filteredCount = count;
+ }
- ImGui.Separator();
+ private static void AddHelpRow(string key, string description)
+ {
+ ImGui.TableNextRow();
+ ImGui.TableSetColumnIndex(0);
+ ImGui.TextUnformatted(key);
+ ImGui.TableSetColumnIndex(1);
+ ImGui.TextUnformatted(description);
+ }
- ImGui.Checkbox("Sleep", ref context.enableSleep);
- ImGui.Checkbox("Warm Starting", ref context.enableWarmStarting);
- ImGui.Checkbox("Continuous", ref context.enableContinuous);
+ private static void TextLinkOpenURL(string label, string url)
+ {
+ // ImGui.NET 1.90 does not expose TextLinkOpenURL, so preserve the same appearance and click behavior here.
+ Vector4 color = new Vector4(0.26f, 0.59f, 0.98f, 1.0f);
+ ImGui.PushStyleColor(ImGuiCol.Text, color);
+ ImGui.TextUnformatted(label);
+ ImGui.PopStyleColor();
+ if (ImGui.IsItemHovered())
+ {
+ Vector2 min = ImGui.GetItemRectMin();
+ Vector2 max = ImGui.GetItemRectMax();
+ uint underlineColor = ImGui.ColorConvertFloat4ToU32(color);
+ ImGui.GetWindowDrawList().AddLine(new Vector2(min.X, max.Y), max, underlineColor);
+ ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
+ }
- ImGui.PushItemWidth(100.0f);
- float recyclingCentimeters = 100.0f * context.recycleDistance;
- if (ImGui.SliderFloat("Recycle", ref recyclingCentimeters, 0.0f, 10.0f, "%.1f cm"))
- {
- context.recycleDistance = 0.01f * recyclingCentimeters;
- b2World_SetContactRecycleDistance(worldId, context.recycleDistance);
- }
- ImGui.PopItemWidth();
+ if (ImGui.IsItemClicked())
+ {
+ Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
+ }
+ }
- ImGui.Separator();
+ public static void UpdateSampleUI(SampleContext context)
+ {
+ int maxWorkers = B2_MAX_WORKERS;
- ImGui.Checkbox("Shapes", ref context.debugDraw.drawShapes);
- ImGui.Checkbox("Chain Normals", ref context.debugDraw.drawChainNormals);
- ImGui.Checkbox("Joints", ref context.debugDraw.drawJoints);
- ImGui.Checkbox("Joint Extras", ref context.debugDraw.drawJointExtras);
- ImGui.Checkbox("Bounds", ref context.debugDraw.drawBounds);
- ImGui.Checkbox("Mass", ref context.debugDraw.drawMass);
- ImGui.Checkbox("Body Names", ref context.debugDraw.drawBodyNames);
- ImGui.Checkbox("Graph Colors", ref context.debugDraw.drawGraphColors);
- ImGui.Checkbox("Islands", ref context.debugDraw.drawIslands);
- ImGui.Checkbox("Counters", ref context.drawCounters);
- ImGui.Checkbox("Profile", ref context.drawProfile);
- ImGui.Checkbox("Frame Time", ref context.frameTime);
+ float fontSize = ImGui.GetFontSize();
+ float menuWidth = 14.0f * fontSize;
- ImGui.Separator();
+ if (context.showUI == false)
+ {
+ return;
+ }
- ImGui.Checkbox("Contact Points", ref context.debugDraw.drawContacts);
+ if (ImGui.BeginMainMenuBar())
+ {
+ if (ImGui.BeginMenu("Sim"))
+ {
+ ImGui.MenuItem("Pause", "P", ref context.pause);
+ if (ImGui.MenuItem("Single Step", "O"))
+ {
+ context.singleStep = true;
+ }
+ if (ImGui.MenuItem("Restart", "R"))
+ {
+ SelectSample(context, context.sampleIndex, true);
+ }
+ ImGui.Separator();
+ if (ImGui.MenuItem("Previous Sample", "["))
+ {
+ int selection = context.sampleIndex - 1;
+ if (selection < 0)
+ {
+ selection = SampleFactory.Shared.SampleCount - 1;
+ }
+ SelectSample(context, selection, false);
+ }
+ if (ImGui.MenuItem("Next Sample", "]"))
+ {
+ int selection = context.sampleIndex + 1;
+ if (selection == SampleFactory.Shared.SampleCount)
+ {
+ selection = 0;
+ }
+ SelectSample(context, selection, false);
+ }
+ ImGui.Separator();
+ if (ImGui.MenuItem("Reset Profile"))
+ {
+ context.sample.ResetProfile();
+ }
+ if (ImGui.MenuItem("Dump Mem Stats"))
+ {
+ b2World_DumpMemoryStats(context.sample.m_worldId);
+ }
+ ImGui.Separator();
+ if (ImGui.MenuItem("Quit", "Esc"))
+ {
+ unsafe
+ {
+ context.glfw.SetWindowShouldClose(context.window, true);
+ }
+ }
+ ImGui.EndMenu();
+ }
- if (ImGui.RadioButton("Anchor A", context.debugDraw.drawAnchorA == true))
+ if (ImGui.BeginMenu("View"))
+ {
+ if (ImGui.MenuItem("Hide UI", "Tab"))
+ {
+ context.showUI = false;
+ }
+ if (ImGui.MenuItem("Reset Camera", "Home"))
+ {
+ ResetView(context.camera);
+ }
+ ImGui.Separator();
+ ImGui.MenuItem("Shapes", null, ref context.debugDraw.drawShapes);
+ ImGui.MenuItem("Chain Normals", null, ref context.debugDraw.drawChainNormals);
+ ImGui.MenuItem("Joints", null, ref context.debugDraw.drawJoints);
+ ImGui.MenuItem("Joint Extras", null, ref context.debugDraw.drawJointExtras);
+ ImGui.MenuItem("Bounds", null, ref context.debugDraw.drawBounds);
+ ImGui.MenuItem("Mass", null, ref context.debugDraw.drawMass);
+ ImGui.MenuItem("Body Names", null, ref context.debugDraw.drawBodyNames);
+ ImGui.MenuItem("Graph Colors", null, ref context.debugDraw.drawGraphColors);
+ ImGui.MenuItem("Islands", null, ref context.debugDraw.drawIslands);
+ ImGui.Separator();
+ ImGui.MenuItem("Contact Points", null, ref context.debugDraw.drawContacts);
+ ImGui.MenuItem("Contact Normals", null, ref context.debugDraw.drawContactNormals);
+ ImGui.MenuItem("Contact Features", null, ref context.debugDraw.drawContactFeatures);
+ ImGui.MenuItem("Contact Forces", null, ref context.debugDraw.drawContactForces);
+ ImGui.MenuItem("Friction Forces", null, ref context.debugDraw.drawFrictionForces);
+ if (ImGui.BeginMenu("Anchor"))
+ {
+ if (ImGui.MenuItem("Anchor A", null, context.debugDraw.drawAnchorA))
{
context.debugDraw.drawAnchorA = true;
}
- ImGui.SameLine();
- if (ImGui.RadioButton("Anchor B", context.debugDraw.drawAnchorA == false))
+ if (ImGui.MenuItem("Anchor B", null, context.debugDraw.drawAnchorA == false))
{
context.debugDraw.drawAnchorA = false;
}
- ImGui.Checkbox("Contact Normals", ref context.debugDraw.drawContactNormals);
- ImGui.Checkbox("Contact Features", ref context.debugDraw.drawContactFeatures);
- ImGui.Checkbox("Contact Forces", ref context.debugDraw.drawContactForces);
- ImGui.Checkbox("Friction Forces", ref context.debugDraw.drawFrictionForces);
-
- ImGui.Separator();
-
- ImGui.PushItemWidth(80.0f);
- ImGui.InputFloat("Joint Scale", ref context.debugDraw.jointScale);
- ImGui.InputFloat("Force Scale", ref context.debugDraw.forceScale);
+ ImGui.EndMenu();
+ }
+ ImGui.Separator();
+ ImGui.MenuItem("Diagnostics", "M", ref context.showDiagnostics);
+ ImGui.Separator();
+ if (ImGui.BeginMenu("Scale"))
+ {
+ ImGui.PushItemWidth(6.0f * fontSize);
+ ImGui.InputFloat("Joint", ref context.debugDraw.jointScale);
+ ImGui.InputFloat("Force", ref context.debugDraw.forceScale);
ImGui.PopItemWidth();
+ ImGui.EndMenu();
+ }
+ ImGui.EndMenu();
+ }
- Vector2 button_sz = new Vector2(-1, 0);
- if (ImGui.Button("Pause (P)", button_sz))
+ if (ImGui.BeginMenu("Samples"))
+ {
+ int i = 0;
+ while (i < SampleFactory.Shared.SampleCount)
+ {
+ string category = SampleFactory.Shared.GetCategory(i);
+ if (ImGui.BeginMenu(category))
{
- context.pause = !context.pause;
+ while (i < SampleFactory.Shared.SampleCount && category == SampleFactory.Shared.GetCategory(i))
+ {
+ bool selected = i == context.sampleIndex;
+ if (ImGui.MenuItem(SampleFactory.Shared.GetName(i), null, selected))
+ {
+ SelectSample(context, i, false);
+ }
+ ++i;
+ }
+ ImGui.EndMenu();
}
-
- if (ImGui.Button("Single Step (O)", button_sz))
+ else
{
- context.singleStep = !context.singleStep;
+ while (i < SampleFactory.Shared.SampleCount && category == SampleFactory.Shared.GetCategory(i))
+ {
+ ++i;
+ }
}
+ }
+ ImGui.EndMenu();
+ }
+
+ if (ImGui.BeginMenu("Help"))
+ {
+ ImGui.MenuItem("Controls", null, ref s_showHelp);
+ ImGui.MenuItem("About", null, ref s_showAbout);
+ ImGui.EndMenu();
+ }
+
+ ImGui.EndMainMenuBar();
- if (ImGui.Button("Dump Mem Stats", button_sz))
+ {
+ float menuBarBottom = ImGui.GetFrameHeight();
+ uint borderColor = ImGui.GetColorU32(ImGuiCol.Border);
+ Vector2 displaySize = ImGui.GetIO().DisplaySize;
+ ImGui.GetForegroundDrawList().AddLine(new Vector2(0.0f, menuBarBottom),
+ new Vector2(displaySize.X, menuBarBottom), borderColor, 1.0f);
+ }
+
+ if (s_showHelp)
+ {
+ ImGui.SetNextWindowPos(new Vector2(context.camera.width * 0.5f, context.camera.height * 0.5f),
+ ImGuiCond.Appearing, new Vector2(0.5f, 0.5f));
+ ImGui.SetNextWindowSize(new Vector2(24.0f * fontSize, 0.0f), ImGuiCond.Appearing);
+
+ if (ImGui.Begin("Controls", ref s_showHelp,
+ ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysAutoResize))
+ {
+ ImGui.SeparatorText("Keyboard");
+ if (ImGui.BeginTable("keys", 2, ImGuiTableFlags.SizingFixedFit))
{
- b2World_DumpMemoryStats(context.sample.m_worldId);
+ AddHelpRow("Tab", "Show / hide UI");
+ AddHelpRow("M", "Show / hide diagnostics");
+ AddHelpRow("P", "Pause / resume");
+ AddHelpRow("O", "Single step");
+ AddHelpRow("R", "Restart sample");
+ AddHelpRow("[ ]", "Previous / next sample");
+ AddHelpRow("Ctrl+O", "Open sample picker");
+ AddHelpRow("Arrows", "Pan camera");
+ AddHelpRow("Ctrl+Arrows", "Shift origin");
+ AddHelpRow("Z X", "Zoom out / in");
+ AddHelpRow("Home", "Reset camera");
+ AddHelpRow("Esc", "Quit");
+ ImGui.EndTable();
}
- if (ImGui.Button("Reset Profile", button_sz))
+ ImGui.SeparatorText("Mouse");
+ if (ImGui.BeginTable("mouse", 2, ImGuiTableFlags.SizingFixedFit))
{
- context.sample.ResetProfile();
+ AddHelpRow("Left drag", "Move bodies (mouse joint)");
+ AddHelpRow("Right drag", "Pan camera");
+ AddHelpRow("Scroll wheel", "Zoom");
+ ImGui.EndTable();
}
+ }
+ ImGui.End();
+ }
+
+ if (s_showAbout)
+ {
+ ImGui.SetNextWindowPos(new Vector2(context.camera.width * 0.5f, context.camera.height * 0.5f),
+ ImGuiCond.Appearing, new Vector2(0.5f, 0.5f));
+ ImGui.SetNextWindowSize(new Vector2(22.0f * fontSize, 0.0f), ImGuiCond.Appearing);
+
+ if (ImGui.Begin("About", ref s_showAbout,
+ ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysAutoResize))
+ {
+ B2Version version = b2GetVersion();
+ ImGui.Text($"Box2D {version.major}.{version.minor}.{version.revision}");
+ ImGui.Spacing();
+ TextLinkOpenURL("box2d.org", "https://box2d.org/");
+ TextLinkOpenURL("github.com/ikpil/Box2D.NET", "https://github.com/ikpil/Box2D.NET");
+ }
+ ImGui.End();
+ }
+ }
+
+ // Fuzzy sample picker (Ctrl+O). Opens a transient popup; type to filter by
+ // name or category, Up/Down to navigate, Enter to select, Esc / click-outside to dismiss.
+ {
+ if (context.openSamplePicker)
+ {
+ ImGui.OpenPopup("##sample_picker");
+ context.openSamplePicker = false;
+ s_pickerQuery = string.Empty;
+ s_previousPickerQuery = string.Empty;
+ s_pickerHighlight = 0;
+ s_previousPickerHighlight = 0;
+ RebuildSampleFilter(s_pickerQuery);
+ s_pickerJustOpened = true;
+ s_forcePickerScroll = true;
+ }
+
+ ImGui.SetNextWindowPos(new Vector2(context.camera.width * 0.5f, context.camera.height * 0.35f),
+ ImGuiCond.Appearing, new Vector2(0.5f, 0.5f));
+ ImGui.SetNextWindowSize(new Vector2(32.0f * fontSize, 0.0f), ImGuiCond.Appearing);
+
+ if (ImGui.BeginPopup("##sample_picker",
+ ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoSavedSettings))
+ {
+ if (s_pickerJustOpened)
+ {
+ ImGui.SetKeyboardFocusHere();
+ s_pickerJustOpened = false;
+ }
- if (ImGui.Button("Restart (R)", button_sz))
+ ImGui.PushItemWidth(-1.0f);
+ ImGui.InputTextWithHint("##q", "Search by name or category...", ref s_pickerQuery, 64);
+ ImGui.PopItemWidth();
+
+ if (s_pickerQuery != s_previousPickerQuery)
+ {
+ RebuildSampleFilter(s_pickerQuery);
+ s_previousPickerQuery = s_pickerQuery;
+ s_pickerHighlight = 0;
+ s_forcePickerScroll = true;
+ }
+
+ if (s_filteredCount > 0)
+ {
+ if (ImGui.IsKeyPressed(ImGuiKey.DownArrow, true))
{
- SelectSample(context, context.sampleIndex, true);
+ s_pickerHighlight = (s_pickerHighlight + 1) % s_filteredCount;
}
+ if (ImGui.IsKeyPressed(ImGuiKey.UpArrow, true))
+ {
+ s_pickerHighlight = (s_pickerHighlight + s_filteredCount - 1) % s_filteredCount;
+ }
+ }
+ bool commit = ImGui.IsKeyPressed(ImGuiKey.Enter, false) || ImGui.IsKeyPressed(ImGuiKey.KeypadEnter, false);
- if (ImGui.Button("Quit", button_sz))
+ ImGui.BeginChild("##results", new Vector2(0.0f, 14.0f * fontSize), ImGuiChildFlags.Border);
+ for (int row = 0; row < s_filteredCount; ++row)
+ {
+ int i = s_filteredSamples[row];
+ string label = $"{SampleFactory.Shared.GetCategory(i)} > {SampleFactory.Shared.GetName(i)}";
+ bool selected = row == s_pickerHighlight;
+ if (ImGui.Selectable(label, selected))
{
- unsafe
- {
- context.glfw.SetWindowShouldClose(context.window, true);
- }
+ s_pickerHighlight = row;
+ commit = true;
+ }
+ if (selected && (s_forcePickerScroll || s_pickerHighlight != s_previousPickerHighlight))
+ {
+ ImGui.SetScrollHereY();
}
+ }
+ ImGui.EndChild();
+ s_previousPickerHighlight = s_pickerHighlight;
+ s_forcePickerScroll = false;
- ImGui.EndTabItem();
+ if (commit && s_filteredCount > 0)
+ {
+ SelectSample(context, s_filteredSamples[s_pickerHighlight], false);
+ ImGui.CloseCurrentPopup();
}
- ImGuiTreeNodeFlags leafNodeFlags = ImGuiTreeNodeFlags.OpenOnArrow | ImGuiTreeNodeFlags.OpenOnDoubleClick;
- leafNodeFlags |= ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.NoTreePushOnOpen;
+ ImGui.EndPopup();
+ }
+ }
- ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags.OpenOnArrow | ImGuiTreeNodeFlags.OpenOnDoubleClick;
+ float menuBarHeight = ImGui.GetFrameHeight();
- if (ImGui.BeginTabItem("Samples"))
- {
- int categoryIndex = 0;
- string category = SampleFactory.Shared.GetCategory(categoryIndex);
- int i = 0;
- while (i < SampleFactory.Shared.SampleCount)
- {
- bool categorySelected = category == SampleFactory.Shared.GetCategory(context.sampleIndex);
- ImGuiTreeNodeFlags nodeSelectionFlags = categorySelected ? ImGuiTreeNodeFlags.Selected : 0;
- bool nodeOpen = ImGui.TreeNodeEx(category, nodeFlags | nodeSelectionFlags);
+ ImGui.SetNextWindowPos(new Vector2(context.camera.width - menuWidth - 0.5f * fontSize,
+ menuBarHeight + 0.5f * fontSize));
+ ImGui.SetNextWindowSize(new Vector2(menuWidth, context.camera.height - menuBarHeight - fontSize));
- if (nodeOpen)
- {
- while (i < SampleFactory.Shared.SampleCount && category == SampleFactory.Shared.GetCategory(i))
- {
- ImGuiTreeNodeFlags selectionFlags = 0;
- if (context.sampleIndex == i)
- {
- selectionFlags = ImGuiTreeNodeFlags.Selected;
- }
-
- ImGui.TreeNodeEx(SampleFactory.Shared.GetName(i), leafNodeFlags | selectionFlags);
- if (ImGui.IsItemClicked())
- {
- SelectSample(context, i, false);
- }
- ++i;
- }
- ImGui.TreePop();
- }
- else
- {
- while (i < SampleFactory.Shared.SampleCount && category == SampleFactory.Shared.GetCategory(i))
- {
- ++i;
- }
- }
+ ImGui.Begin("Info",
+ ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse |
+ ImGuiWindowFlags.NoTitleBar);
- if (i < SampleFactory.Shared.SampleCount)
- {
- category = SampleFactory.Shared.GetCategory(i);
- categoryIndex = i;
- }
- }
- ImGui.EndTabItem();
- }
- ImGui.EndTabBar();
+ for (int i = 0; i < context.sample.m_hudLineCount; ++i)
+ {
+ HudLine line = context.sample.m_hudLines[i];
+ if (string.IsNullOrEmpty(line.text))
+ {
+ ImGui.Separator();
+ continue;
}
+ ImGui.PushStyleColor(ImGuiCol.Text, HexToColor(line.color));
+ ImGui.TextUnformatted(line.text);
+ ImGui.PopStyleColor();
+ }
+
+ if (context.sample.m_hudLineCount > 0)
+ {
+ ImGui.Separator();
+ }
- ImGui.End();
+ context.sample.BuildSamplePanel();
+
+ ImGui.Separator();
+
+ if (ImGui.CollapsingHeader("Solver", ImGuiTreeNodeFlags.DefaultOpen))
+ {
+ ImGui.PushItemWidth(6.0f * fontSize);
+ ImGui.SliderInt("Sub-steps", ref context.subStepCount, 1, 32);
+ ImGui.SliderFloat("Hertz", ref context.hertz, 5.0f, 240.0f, "%.0f hz");
- context.sample.UpdateGui();
+ if (ImGui.SliderInt("Workers", ref context.workerCount, 1, maxWorkers))
+ {
+ context.workerCount = b2ClampInt(context.workerCount, 1, maxWorkers);
+ SelectSample(context, context.sampleIndex, true);
+ }
+
+ float recyclingCentimeters = 100.0f * context.recycleDistance;
+ if (ImGui.SliderFloat("Recycle", ref recyclingCentimeters, 0.0f, 10.0f, "%.1f cm"))
+ {
+ context.recycleDistance = 0.01f * recyclingCentimeters;
+ b2World_SetContactRecycleDistance(context.sample.m_worldId, context.recycleDistance);
+ }
+ ImGui.PopItemWidth();
+
+ ImGui.Checkbox("Sleep", ref context.enableSleep);
+ ImGui.Checkbox("Warm Starting", ref context.enableWarmStarting);
+ ImGui.Checkbox("Continuous", ref context.enableContinuous);
}
+
+ ImGui.End();
+
+ context.sample.UpdateGui();
}
+
+
}
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/ChainLink.cs b/src/Box2D.NET.Samples/Samples/Shapes/ChainLink.cs
index c49e8ce2..559ef6b2 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/ChainLink.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/ChainLink.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -95,7 +95,7 @@ public override void Draw()
{
base.Draw();
- DrawTextLine("This shows how to link together two chain shapes");
+ DrawScreenTextLine("This shows how to link together two chain shapes");
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/ChainSegmentShape.cs b/src/Box2D.NET.Samples/Samples/Shapes/ChainSegmentShape.cs
index 25cad6ba..0eadbb1e 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/ChainSegmentShape.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/ChainSegmentShape.cs
@@ -162,15 +162,9 @@ public void Mutate()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 130.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Chain Segment Shape", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
string[] shapeTypes = { "Circle", "Capsule", "Box" };
int shapeType = (int)m_shapeType;
if (ImGui.Combo("Shape", ref shapeType, shapeTypes, shapeTypes.Length))
@@ -179,6 +173,8 @@ public override void UpdateGui()
Launch();
}
+ ImGui.PopItemWidth();
+
if (ImGui.Button("Launch"))
{
Launch();
@@ -188,8 +184,6 @@ public override void UpdateGui()
{
Mutate();
}
-
- ImGui.End();
}
public override void Step()
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/ChainShape.cs b/src/Box2D.NET.Samples/Samples/Shapes/ChainShape.cs
index eca24bcf..3ebb102e 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/ChainShape.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/ChainShape.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -185,17 +185,9 @@ public override void Draw()
// DrawTextLine($"toi calls, hits = {b2_toiCalls}, {b2_toiHitCount}");
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 155.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Chain Shape", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
string[] shapeTypes = { "Circle", "Capsule", "Box" };
int shapeType = (int)m_shapeType;
if (ImGui.Combo("Shape", ref shapeType, shapeTypes, shapeTypes.Length))
@@ -215,11 +207,11 @@ public override void UpdateGui()
b2Shape_SetSurfaceMaterial(m_shapeId, m_material);
}
+ ImGui.PopItemWidth();
+
if (ImGui.Button("Launch"))
{
Launch();
}
-
- ImGui.End();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/CompoundShapes.cs b/src/Box2D.NET.Samples/Samples/Shapes/CompoundShapes.cs
index cd2a3da7..c0b1b951 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/CompoundShapes.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/CompoundShapes.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -194,16 +194,9 @@ void Spawn()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 100.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(180.0f, height));
-
- ImGui.Begin("Compound Shapes", ImGuiWindowFlags.NoResize);
if (ImGui.Button("Intrude"))
{
@@ -212,7 +205,7 @@ public override void UpdateGui()
ImGui.Checkbox("Body AABBs", ref m_drawBodyAABBs);
- ImGui.End();
+
}
public override void Draw()
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/CustomFilter.cs b/src/Box2D.NET.Samples/Samples/Shapes/CustomFilter.cs
index eb3d6d67..a4a485b0 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/CustomFilter.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/CustomFilter.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -100,7 +100,7 @@ public override void Draw()
{
base.Draw();
- DrawTextLine("Custom filter disables collision between odd and even shapes");
+ DrawScreenTextLine("Custom filter disables collision between odd and even shapes");
for (int i = 0; i < e_count; ++i)
@@ -109,4 +109,4 @@ public override void Draw()
DrawWorldString(m_draw, m_camera, new B2Vec2(p.X, p.Y), B2HexColor.b2_colorWhite, $"{i}");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/Explosion.cs b/src/Box2D.NET.Samples/Samples/Shapes/Explosion.cs
index 10121ac8..ef2c6afd 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/Explosion.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/Explosion.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -80,16 +80,9 @@ public Explosion(SampleContext context) : base(context)
m_impulse = 10.0f;
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 160.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Explosion", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
if (ImGui.Button("Explode"))
{
@@ -101,11 +94,11 @@ public override void UpdateGui()
b2World_Explode(m_worldId, def);
}
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("radius", ref m_radius, 0.0f, 20.0f, "%.1f");
ImGui.SliderFloat("falloff", ref m_falloff, 0.0f, 20.0f, "%.1f");
ImGui.SliderFloat("impulse", ref m_impulse, -20.0f, 20.0f, "%.1f");
-
- ImGui.End();
+ ImGui.PopItemWidth();
}
public override void Step()
@@ -136,4 +129,4 @@ public override void Draw()
DrawCircle(m_draw, b2Vec2_zero, m_radius + m_falloff, B2HexColor.b2_colorBox2DBlue);
DrawCircle(m_draw, b2Vec2_zero, m_radius, B2HexColor.b2_colorBox2DYellow);
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/ModifyGeometry.cs b/src/Box2D.NET.Samples/Samples/Shapes/ModifyGeometry.cs
index 4a6d9c74..87472e9c 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/ModifyGeometry.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/ModifyGeometry.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -108,16 +108,9 @@ void UpdateShape()
b2Body_ApplyMassFromShapes(bodyId);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 230.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(200.0f, height));
-
- ImGui.Begin("Modify Geometry", ImGuiWindowFlags.NoResize);
if (ImGui.RadioButton("Circle", m_shapeType == B2ShapeType.b2_circleShape))
{
@@ -143,10 +136,12 @@ public override void UpdateGui()
UpdateShape();
}
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Scale", ref m_scale, 0.1f, 10.0f, "%.2f"))
{
UpdateShape();
}
+ ImGui.PopItemWidth();
B2BodyId bodyId = b2Shape_GetBody(m_shapeId);
B2BodyType bodyType = b2Body_GetType(bodyId);
@@ -165,7 +160,5 @@ public override void UpdateGui()
{
b2Body_SetType(bodyId, B2BodyType.b2_dynamicBody);
}
-
- ImGui.End();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/Restitution.cs b/src/Box2D.NET.Samples/Samples/Shapes/Restitution.cs
index dd7294ec..853cca59 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/Restitution.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/Restitution.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -104,17 +104,9 @@ void CreateBodies()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 100.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Restitution", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
bool changed = false;
string[] shapeTypes = ["Circle", "Box"];
@@ -122,13 +114,13 @@ public override void UpdateGui()
changed = changed || ImGui.Combo("Shape", ref shapeType, shapeTypes, shapeTypes.Length);
m_shapeType = (ShapeType)shapeType;
+ ImGui.PopItemWidth();
+
changed = changed || ImGui.Button("Reset");
if (changed)
{
CreateBodies();
}
-
- ImGui.End();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/ShapeFilter.cs b/src/Box2D.NET.Samples/Samples/Shapes/ShapeFilter.cs
index 5525f99a..e788f101 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/ShapeFilter.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/ShapeFilter.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -88,16 +88,9 @@ public ShapeFilter(SampleContext context) : base(context)
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 240.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(240.0f, height));
-
- ImGui.Begin("Shape Filter", ImGuiWindowFlags.NoResize);
ImGui.Text("Player 1 Collides With");
{
@@ -205,7 +198,7 @@ public override void UpdateGui()
}
}
- ImGui.End();
+
}
public override void Draw()
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/TangentSpeed.cs b/src/Box2D.NET.Samples/Samples/Shapes/TangentSpeed.cs
index ed99329e..8db394b8 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/TangentSpeed.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/TangentSpeed.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -114,15 +114,10 @@ void Reset()
m_bodyIds.Clear();
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 80.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(260.0f, height));
- ImGui.Begin("Ball Parameters", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(140.0f);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
if (ImGui.SliderFloat("Friction", ref m_friction, 0.0f, 2.0f, "%.2f"))
{
@@ -133,8 +128,7 @@ public override void UpdateGui()
{
Reset();
}
-
- ImGui.End();
+ ImGui.PopItemWidth();
}
public override void Step()
@@ -147,4 +141,4 @@ public override void Step()
base.Step();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Samples/Shapes/Wind.cs b/src/Box2D.NET.Samples/Samples/Shapes/Wind.cs
index 5b71095a..dd485261 100644
--- a/src/Box2D.NET.Samples/Samples/Shapes/Wind.cs
+++ b/src/Box2D.NET.Samples/Samples/Shapes/Wind.cs
@@ -128,15 +128,10 @@ private void CreateScene()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 15.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(24.0f * fontSize, height));
- ImGui.Begin("Wind", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(18.0f * fontSize);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
string[] shapeTypes = { "Circle", "Capsule", "Box" };
int shapeType = (int)m_shapeType;
@@ -157,7 +152,7 @@ public override void UpdateGui()
}
ImGui.PopItemWidth();
- ImGui.End();
+
}
public override void Step()
diff --git a/src/Box2D.NET.Samples/Samples/Stackings/CircleImpulse.cs b/src/Box2D.NET.Samples/Samples/Stackings/CircleImpulse.cs
index d7261876..04afd85c 100644
--- a/src/Box2D.NET.Samples/Samples/Stackings/CircleImpulse.cs
+++ b/src/Box2D.NET.Samples/Samples/Stackings/CircleImpulse.cs
@@ -13,6 +13,7 @@
using static Box2D.NET.B2Worlds;
using static Box2D.NET.B2Contacts;
using static Box2D.NET.Samples.Graphics.Draws;
+using static Box2D.NET.Samples.SampleText;
namespace Box2D.NET.Samples.Samples.Stackings;
@@ -104,14 +105,9 @@ void Spawn()
b2Body_SetMassData(m_bodyId, massData);
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- float fontSize = ImGui.GetFontSize();
- float height = 6.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(10.0f * fontSize, height));
- ImGui.Begin("Circle Impulse", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize);
if (ImGui.Checkbox("gravity", ref m_useGravity))
{
@@ -123,7 +119,7 @@ public override void UpdateGui()
Spawn();
}
- ImGui.End();
+
}
public override void Step()
@@ -151,14 +147,14 @@ public override void Step()
m_events.Add(e);
}
- DrawTextLine($"mass = {m_mass}, gravity = {(m_useGravity ? 10.0f : 0.0f)}, restitution = {(m_useRestitution ? m_restitution : 0.0f)}");
+ DrawScreenTextLine($"mass = {FormatFloat(m_mass)}, gravity = {FormatFloat(m_useGravity ? 10.0f : 0.0f)}, restitution = {FormatFloat(m_useRestitution ? m_restitution : 0.0f)}");
int eventCount = m_events.Count;
var eventsSpan = CollectionsMarshal.AsSpan(m_events);
for (int i = 0; i < eventCount; ++i)
{
ref readonly Event e = ref eventsSpan[i];
- DrawTextLine($"hit speed = {e.speed}, hit momentum = {m_mass * e.speed}, final impulse = {e.impulse}, total impulse = {e.totalImpulse}");
+ DrawScreenTextLine($"hit speed = {FormatFloat(e.speed)}, hit momentum = {FormatFloat(m_mass * e.speed)}, final impulse = {FormatFloat(e.impulse)}, total impulse = {FormatFloat(e.totalImpulse)}");
}
}
}
diff --git a/src/Box2D.NET.Samples/Samples/Stackings/Cliff.cs b/src/Box2D.NET.Samples/Samples/Stackings/Cliff.cs
index d80f482a..c6432e3b 100644
--- a/src/Box2D.NET.Samples/Samples/Stackings/Cliff.cs
+++ b/src/Box2D.NET.Samples/Samples/Stackings/Cliff.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -142,16 +142,9 @@ void CreateBodies()
}
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 60.0f;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(160.0f, height));
-
- ImGui.Begin("Cliff", ImGuiWindowFlags.NoResize);
if (ImGui.Button("Flip"))
{
@@ -159,6 +152,6 @@ public override void UpdateGui()
CreateBodies();
}
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Stackings/VerticalStack.cs b/src/Box2D.NET.Samples/Samples/Stackings/VerticalStack.cs
index 0d8744ca..e80d7b24 100644
--- a/src/Box2D.NET.Samples/Samples/Stackings/VerticalStack.cs
+++ b/src/Box2D.NET.Samples/Samples/Stackings/VerticalStack.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -242,18 +242,11 @@ public override void Keyboard(Keys key)
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
- float fontSize = ImGui.GetFontSize();
- float height = 16.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(20.0f * fontSize, height));
-
- ImGui.Begin("Vertical Stack", ImGuiWindowFlags.NoResize);
- ImGui.PushItemWidth(13.0f * fontSize);
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
bool changed = false;
string[] shapeTypes = ["Circle", "Box"];
@@ -292,6 +285,6 @@ public override void UpdateGui()
CreateStacks();
}
- ImGui.End();
+
}
}
\ No newline at end of file
diff --git a/src/Box2D.NET.Samples/Samples/Worlds/LargeWorld.cs b/src/Box2D.NET.Samples/Samples/Worlds/LargeWorld.cs
index 3b3cf668..fc3f2178 100644
--- a/src/Box2D.NET.Samples/Samples/Worlds/LargeWorld.cs
+++ b/src/Box2D.NET.Samples/Samples/Worlds/LargeWorld.cs
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Erin Catto
+// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com)
// SPDX-License-Identifier: MIT
@@ -167,18 +167,11 @@ public LargeWorld(SampleContext context) : base(context)
m_followCar = false;
}
- public override void UpdateGui()
+ public override void BuildSamplePanel()
{
- base.UpdateGui();
-
- float fontSize = ImGui.GetFontSize();
- float height = 13.0f * fontSize;
- ImGui.SetNextWindowPos(new Vector2(0.5f * fontSize, m_camera.height - height - 2.0f * fontSize), ImGuiCond.Once);
- ImGui.SetNextWindowSize(new Vector2(18.0f * fontSize, height));
-
- ImGui.Begin("Large World", ImGuiWindowFlags.NoResize);
-
+ ImGui.PushItemWidth(6.0f * ImGui.GetFontSize());
ImGui.SliderFloat("speed", ref m_speed, -400.0f, 400.0f, "%.0f");
+ ImGui.PopItemWidth();
if (ImGui.Button("stop"))
{
m_speed = 0.0f;
@@ -188,7 +181,7 @@ public override void UpdateGui()
ImGui.Checkbox("follow car", ref m_followCar);
ImGui.Text($"world size = {m_gridSize * m_gridCount / 1000.0f} kilometers");
- ImGui.End();
+
}
public override void Step()
@@ -251,4 +244,4 @@ public override void Step()
base.Step();
}
-}
\ No newline at end of file
+}
diff --git a/src/Box2D.NET.Samples/Settings.cs b/src/Box2D.NET.Samples/Settings.cs
index b98fbc03..3d172a7e 100644
--- a/src/Box2D.NET.Samples/Settings.cs
+++ b/src/Box2D.NET.Samples/Settings.cs
@@ -14,41 +14,10 @@ public class Settings
public const int MAX_TOKENS = 32;
public const string fileName = "settings.ini";
- public int windowWidth = 1920;
- public int windowHeight = 1080;
-
- //
- public float uiScale = 1.0f;
- public float hertz = 60.0f;
- public float jointScale = 1.0f;
- public float forceScale = 1.0f;
- public int subStepCount = 4;
- public int workerCount = 1;
-
- //
- public bool singleStep = false;
- public bool drawJointExtras = false;
- public bool drawBounds = false;
- public bool drawMass = false;
- public bool drawBodyNames = false;
- public bool drawContactNormals = false;
- public bool drawContactFeatures = false;
- public bool drawContactForces = false;
- public bool drawFrictionForces = false;
- public bool drawIslands = false;
- public bool drawGraphColors = false;
- public bool drawCounters = false;
- public bool drawProfile = false;
- public bool frameTime = false;
- public bool enableWarmStarting = true;
- public bool enableContinuous = true;
- public bool enableSleep = true;
-
- //
public int sampleIndex = 0;
public bool drawShapes = true;
- public bool drawChainNormals = false;
public bool drawJoints = true;
+ public bool showDiagnostics = false;
public static void Save(SampleContext context)
{
@@ -73,39 +42,10 @@ public static Settings Load()
public static Settings CopyFrom(SampleContext context)
{
var setting = new Settings();
- setting.windowWidth = (int)context.camera.width;
- setting.windowHeight = (int)context.camera.height;
-
setting.sampleIndex = context.sampleIndex;
- //
- setting.uiScale = context.uiScale;
- setting.hertz = context.hertz;
- setting.subStepCount = context.subStepCount;
- setting.workerCount = context.workerCount;
-
- //
- setting.drawCounters = context.drawCounters;
- setting.drawProfile = context.drawProfile;
- setting.frameTime = context.frameTime;
- setting.enableWarmStarting = context.enableWarmStarting;
- setting.enableContinuous = context.enableContinuous;
- setting.enableSleep = context.enableSleep;
- setting.singleStep = context.singleStep;
-
- //
setting.drawShapes = context.debugDraw.drawShapes;
- setting.drawChainNormals = context.debugDraw.drawChainNormals;
setting.drawJoints = context.debugDraw.drawJoints;
- setting.drawJointExtras = context.debugDraw.drawJointExtras;
- setting.drawBounds = context.debugDraw.drawBounds;
- setting.drawMass = context.debugDraw.drawMass;
- setting.drawBodyNames = context.debugDraw.drawBodyNames;
- setting.drawContactNormals = context.debugDraw.drawContactNormals;
- setting.drawContactForces = context.debugDraw.drawContactForces;
- setting.drawContactFeatures = context.debugDraw.drawContactFeatures;
- setting.drawFrictionForces = context.debugDraw.drawFrictionForces;
- setting.drawIslands = context.debugDraw.drawIslands;
- setting.drawGraphColors = context.debugDraw.drawGraphColors;
+ setting.showDiagnostics = context.showDiagnostics;
return setting;
}
diff --git a/src/Box2D.NET.Samples/Shader.cs b/src/Box2D.NET.Samples/Shader.cs
index c144f309..6f2f9f61 100644
--- a/src/Box2D.NET.Samples/Shader.cs
+++ b/src/Box2D.NET.Samples/Shader.cs
@@ -3,8 +3,6 @@
// SPDX-License-Identifier: MIT
using System;
-using System.IO;
-using System.Text;
using Serilog;
using Silk.NET.OpenGL;
using static Box2D.NET.B2Diagnostics;
@@ -131,67 +129,4 @@ public static uint CreateProgramFromStrings(this GL gl, string vertexString, str
return program;
}
- public static uint sCreateShaderFromFile(this GL gl, string filename, GLEnum type)
- {
- if (!File.Exists(filename))
- {
- Logger.Information($"Error opening {filename}");
- return 0;
- }
-
- byte[] bytes = File.ReadAllBytes(filename);
- var source = Encoding.UTF8.GetString(bytes);
-
-
- uint shader = gl.CreateShader(type);
-
- gl.ShaderSource(shader, source);
- gl.CompileShader(shader);
-
- Span success = stackalloc int[1];
- gl.GetShader(shader, GLEnum.CompileStatus, success);
-
- if (success[0] == 0)
- {
- Logger.Information($"Error compiling shader of type {type}!");
- gl.PrintLogGL(shader);
- }
-
- return shader;
- }
-
- public static uint CreateProgramFromFiles(this GL gl, string vertexPath, string fragmentPath)
- {
- uint vertex = gl.sCreateShaderFromFile(vertexPath, GLEnum.VertexShader);
- if (vertex == 0)
- {
- return 0;
- }
-
- uint fragment = gl.sCreateShaderFromFile(fragmentPath, GLEnum.FragmentShader);
- if (fragment == 0)
- {
- return 0;
- }
-
- uint program = gl.CreateProgram();
- gl.AttachShader(program, vertex);
- gl.AttachShader(program, fragment);
-
- gl.LinkProgram(program);
-
- Span success = stackalloc int[1];
- gl.GetProgram(program, GLEnum.LinkStatus, success);
- if (success[0] == 0)
- {
- Logger.Information("glLinkProgram:");
- gl.PrintLogGL(program);
- return 0;
- }
-
- gl.DeleteShader(vertex);
- gl.DeleteShader(fragment);
-
- return program;
- }
-}
\ No newline at end of file
+}
diff --git a/test/Box2D.NET.Test/Box2D.NET.Test.csproj b/test/Box2D.NET.Test/Box2D.NET.Test.csproj
index a85885b7..ee9f72b8 100644
--- a/test/Box2D.NET.Test/Box2D.NET.Test.csproj
+++ b/test/Box2D.NET.Test/Box2D.NET.Test.csproj
@@ -31,6 +31,7 @@
+
diff --git a/test/Box2D.NET.Test/SampleTextTests.cs b/test/Box2D.NET.Test/SampleTextTests.cs
new file mode 100644
index 00000000..329aedb3
--- /dev/null
+++ b/test/Box2D.NET.Test/SampleTextTests.cs
@@ -0,0 +1,36 @@
+// SPDX-FileCopyrightText: 2026 Ikpil Choi(ikpil@naver.com)
+// SPDX-License-Identifier: MIT
+
+using System.Globalization;
+using Box2D.NET.Samples;
+using NUnit.Framework;
+
+namespace Box2D.NET.Test;
+
+public class SampleTextTests
+{
+ [TestCase(1.2345678f, "1.23457")]
+ [TestCase(0.0000001f, "1e-07")]
+ [TestCase(10000000.0f, "1e+07")]
+ [TestCase(float.PositiveInfinity, "inf")]
+ [TestCase(float.NegativeInfinity, "-inf")]
+ public void FormatFloatMatchesPrintfGeneralFormat(float value, string expected)
+ {
+ Assert.That(SampleText.FormatFloat(value), Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void FormatFloatDoesNotUseCurrentCulture()
+ {
+ CultureInfo previousCulture = CultureInfo.CurrentCulture;
+ try
+ {
+ CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("de-DE");
+ Assert.That(SampleText.FormatFloat(1.25f), Is.EqualTo("1.25"));
+ }
+ finally
+ {
+ CultureInfo.CurrentCulture = previousCulture;
+ }
+ }
+}