From ab50f0fd533b066e6b0ea8387fc73514e763347b Mon Sep 17 00:00:00 2001 From: ikpil Date: Sun, 10 Sep 2023 16:03:10 +0900 Subject: [PATCH] refactor: DynamicUpdateSampleTool --- .../Tools/ColliderWithGizmo.cs | 193 +++++++++++++++++ .../Tools/DynamicUpdateSampleTool.cs | 33 +-- .../Tools/Gizmos/BoxGizmo.cs | 86 -------- .../Tools/Gizmos/CapsuleGizmo.cs | 88 -------- .../Tools/Gizmos/ColliderWithGizmo.cs | 15 -- .../Tools/Gizmos/CompositeGizmo.cs | 20 -- .../Tools/Gizmos/CylinderGizmo.cs | 94 --------- .../Tools/Gizmos/GizmoFactory.cs | 36 ---- .../Tools/Gizmos/GizmoHelper.cs | 197 ------------------ .../Tools/Gizmos/IColliderGizmo.cs | 8 - .../Tools/Gizmos/SphereGizmo.cs | 42 ---- .../Tools/Gizmos/TrimeshGizmo.cs | 32 --- .../Tools/Gizmos/BoxGizmo.cs | 50 +++++ .../Tools/Gizmos/CapsuleGizmo.cs | 70 +++++++ .../Tools/Gizmos/CompositeGizmo.cs | 12 ++ .../Tools/Gizmos/CylinderGizmo.cs | 76 +++++++ .../Tools/Gizmos/GizmoFactory.cs | 37 ++++ .../Tools/Gizmos/GizmoHelper.cs | 174 ++++++++++++++++ .../Tools/Gizmos/IRcGizmoMeshFilter.cs | 9 + .../Tools/Gizmos/SphereGizmo.cs | 22 ++ .../Tools/Gizmos/TrimeshGizmo.cs | 14 ++ 21 files changed, 674 insertions(+), 634 deletions(-) create mode 100644 src/DotRecast.Recast.Demo/Tools/ColliderWithGizmo.cs delete mode 100644 src/DotRecast.Recast.Demo/Tools/Gizmos/BoxGizmo.cs delete mode 100644 src/DotRecast.Recast.Demo/Tools/Gizmos/CapsuleGizmo.cs delete mode 100644 src/DotRecast.Recast.Demo/Tools/Gizmos/ColliderWithGizmo.cs delete mode 100644 src/DotRecast.Recast.Demo/Tools/Gizmos/CompositeGizmo.cs delete mode 100644 src/DotRecast.Recast.Demo/Tools/Gizmos/CylinderGizmo.cs delete mode 100644 src/DotRecast.Recast.Demo/Tools/Gizmos/GizmoFactory.cs delete mode 100644 src/DotRecast.Recast.Demo/Tools/Gizmos/GizmoHelper.cs delete mode 100644 src/DotRecast.Recast.Demo/Tools/Gizmos/IColliderGizmo.cs delete mode 100644 src/DotRecast.Recast.Demo/Tools/Gizmos/SphereGizmo.cs delete mode 100644 src/DotRecast.Recast.Demo/Tools/Gizmos/TrimeshGizmo.cs create mode 100644 src/DotRecast.Recast.Toolset/Tools/Gizmos/BoxGizmo.cs create mode 100644 src/DotRecast.Recast.Toolset/Tools/Gizmos/CapsuleGizmo.cs create mode 100644 src/DotRecast.Recast.Toolset/Tools/Gizmos/CompositeGizmo.cs create mode 100644 src/DotRecast.Recast.Toolset/Tools/Gizmos/CylinderGizmo.cs create mode 100644 src/DotRecast.Recast.Toolset/Tools/Gizmos/GizmoFactory.cs create mode 100644 src/DotRecast.Recast.Toolset/Tools/Gizmos/GizmoHelper.cs create mode 100644 src/DotRecast.Recast.Toolset/Tools/Gizmos/IRcGizmoMeshFilter.cs create mode 100644 src/DotRecast.Recast.Toolset/Tools/Gizmos/SphereGizmo.cs create mode 100644 src/DotRecast.Recast.Toolset/Tools/Gizmos/TrimeshGizmo.cs diff --git a/src/DotRecast.Recast.Demo/Tools/ColliderWithGizmo.cs b/src/DotRecast.Recast.Demo/Tools/ColliderWithGizmo.cs new file mode 100644 index 0000000..3deb051 --- /dev/null +++ b/src/DotRecast.Recast.Demo/Tools/ColliderWithGizmo.cs @@ -0,0 +1,193 @@ +using DotRecast.Core; +using DotRecast.Detour.Dynamic.Colliders; +using DotRecast.Recast.Toolset.Tools.Gizmos; +using DotRecast.Recast.Demo.Draw; +using static DotRecast.Core.RcMath; + +namespace DotRecast.Recast.Demo.Tools; + +public class ColliderWithGizmo +{ + public readonly IRcGizmoMeshFilter Gizmo; + public readonly ICollider Collider; + + public ColliderWithGizmo(ICollider collider, IRcGizmoMeshFilter gizmo) + { + Collider = collider; + Gizmo = gizmo; + } + + public void Render(RecastDebugDraw dd) + { + Render(dd, Gizmo); + } + + public static void Render(RecastDebugDraw dd, IRcGizmoMeshFilter gizmo) + { + if (gizmo is BoxGizmo box) + { + RenderBox(dd, box); + } + else if (gizmo is CapsuleGizmo capsule) + { + RenderCapsule(dd, capsule); + } + else if (gizmo is TrimeshGizmo trimesh) + { + RenderTrimesh(dd, trimesh); + } + else if (gizmo is CylinderGizmo cylinder) + { + RenderCylinder(dd, cylinder); + } + else if (gizmo is SphereGizmo sphere) + { + RenderSphere(dd, sphere); + } + else if (gizmo is CompositeGizmo composite) + { + RenderComposite(dd, composite); + } + } + + public static int GetColorByNormal(float[] vertices, int v0, int v1, int v2) + { + RcVec3f e0 = new RcVec3f(); + RcVec3f e1 = new RcVec3f(); + RcVec3f normal = new RcVec3f(); + for (int j = 0; j < 3; ++j) + { + e0[j] = vertices[v1 + j] - vertices[v0 + j]; + e1[j] = vertices[v2 + j] - vertices[v0 + j]; + } + + normal.x = e0.y * e1.z - e0.z * e1.y; + normal.y = e0.z * e1.x - e0.x * e1.z; + normal.z = e0.x * e1.y - e0.y * e1.x; + RcVec3f.Normalize(ref normal); + float c = Clamp(0.57735026f * (normal.x + normal.y + normal.z), -1, 1); + int col = DebugDraw.DuLerpCol( + DebugDraw.DuRGBA(32, 32, 0, 160), + DebugDraw.DuRGBA(220, 220, 0, 160), + (int)(127 * (1 + c)) + ); + return col; + } + + public static void RenderBox(RecastDebugDraw debugDraw, BoxGizmo box) + { + var trX = RcVec3f.Of(box.halfEdges[0].x, box.halfEdges[1].x, box.halfEdges[2].x); + var trY = RcVec3f.Of(box.halfEdges[0].y, box.halfEdges[1].y, box.halfEdges[2].y); + var trZ = RcVec3f.Of(box.halfEdges[0].z, box.halfEdges[1].z, box.halfEdges[2].z); + float[] vertices = new float[8 * 3]; + for (int i = 0; i < 8; i++) + { + vertices[i * 3 + 0] = RcVec3f.Dot(BoxGizmo.VERTS[i], trX) + box.center.x; + vertices[i * 3 + 1] = RcVec3f.Dot(BoxGizmo.VERTS[i], trY) + box.center.y; + vertices[i * 3 + 2] = RcVec3f.Dot(BoxGizmo.VERTS[i], trZ) + box.center.z; + } + + debugDraw.Begin(DebugDrawPrimitives.TRIS); + for (int i = 0; i < 12; i++) + { + int col = DebugDraw.DuRGBA(200, 200, 50, 160); + if (i == 4 || i == 5 || i == 8 || i == 9) + { + col = DebugDraw.DuRGBA(160, 160, 40, 160); + } + else if (i > 4) + { + col = DebugDraw.DuRGBA(120, 120, 30, 160); + } + + for (int j = 0; j < 3; j++) + { + int v = BoxGizmo.TRIANLGES[i * 3 + j] * 3; + debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col); + } + } + + debugDraw.End(); + } + + public static void RenderCapsule(RecastDebugDraw debugDraw, CapsuleGizmo capsule) + { + debugDraw.Begin(DebugDrawPrimitives.TRIS); + for (int i = 0; i < capsule.triangles.Length; i += 3) + { + for (int j = 0; j < 3; j++) + { + int v = capsule.triangles[i + j] * 3; + float c = capsule.gradient[capsule.triangles[i + j]]; + int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160), + (int)(127 * (1 + c))); + debugDraw.Vertex(capsule.vertices[v], capsule.vertices[v + 1], capsule.vertices[v + 2], col); + } + } + + debugDraw.End(); + } + + public static void RenderCylinder(RecastDebugDraw debugDraw, CylinderGizmo cylinder) + { + debugDraw.Begin(DebugDrawPrimitives.TRIS); + for (int i = 0; i < cylinder.triangles.Length; i += 3) + { + for (int j = 0; j < 3; j++) + { + int v = cylinder.triangles[i + j] * 3; + float c = cylinder.gradient[cylinder.triangles[i + j]]; + int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160), + (int)(127 * (1 + c))); + debugDraw.Vertex(cylinder.vertices[v], cylinder.vertices[v + 1], cylinder.vertices[v + 2], col); + } + } + + debugDraw.End(); + } + + public static void RenderSphere(RecastDebugDraw debugDraw, SphereGizmo sphere) + { + debugDraw.Begin(DebugDrawPrimitives.TRIS); + for (int i = 0; i < sphere.triangles.Length; i += 3) + { + for (int j = 0; j < 3; j++) + { + int v = sphere.triangles[i + j] * 3; + float c = Clamp(0.57735026f * (sphere.vertices[v] + sphere.vertices[v + 1] + sphere.vertices[v + 2]), -1, 1); + int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160), (int)(127 * (1 + c))); + + debugDraw.Vertex( + sphere.radius * sphere.vertices[v] + sphere.center.x, + sphere.radius * sphere.vertices[v + 1] + sphere.center.y, + sphere.radius * sphere.vertices[v + 2] + sphere.center.z, + col + ); + } + } + + debugDraw.End(); + } + + public static void RenderTrimesh(RecastDebugDraw debugDraw, TrimeshGizmo trimesh) + { + debugDraw.Begin(DebugDrawPrimitives.TRIS); + for (int i = 0; i < trimesh.triangles.Length; i += 3) + { + int v0 = 3 * trimesh.triangles[i]; + int v1 = 3 * trimesh.triangles[i + 1]; + int v2 = 3 * trimesh.triangles[i + 2]; + int col = GetColorByNormal(trimesh.vertices, v0, v1, v2); + debugDraw.Vertex(trimesh.vertices[v0], trimesh.vertices[v0 + 1], trimesh.vertices[v0 + 2], col); + debugDraw.Vertex(trimesh.vertices[v1], trimesh.vertices[v1 + 1], trimesh.vertices[v1 + 2], col); + debugDraw.Vertex(trimesh.vertices[v2], trimesh.vertices[v2 + 1], trimesh.vertices[v2 + 2], col); + } + + debugDraw.End(); + } + + public static void RenderComposite(RecastDebugDraw debugDraw, CompositeGizmo composite) + { + composite.gizmoMeshes.ForEach(g => Render(debugDraw, g)); + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs index e561f98..930acf3 100644 --- a/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs @@ -29,7 +29,7 @@ using DotRecast.Detour.Dynamic.Io; using DotRecast.Recast.Toolset.Builder; using DotRecast.Recast.Demo.Draw; using DotRecast.Recast.Toolset.Geom; -using DotRecast.Recast.Demo.Tools.Gizmos; +using DotRecast.Recast.Toolset.Tools.Gizmos; using DotRecast.Recast.Demo.UI; using DotRecast.Recast.Toolset; using DotRecast.Recast.Toolset.Tools; @@ -75,8 +75,7 @@ public class DynamicUpdateSampleTool : ISampleTool private DynamicNavMesh dynaMesh; private readonly TaskFactory executor; - private readonly Dictionary colliders = new(); - private readonly Dictionary colliderGizmos = new(); + private readonly Dictionary colliderGizmos = new(); private readonly Random random = Random.Shared; private readonly DemoInputGeomProvider bridgeGeom; private readonly DemoInputGeomProvider houseGeom; @@ -100,7 +99,7 @@ public class DynamicUpdateSampleTool : ISampleTool public void Layout() { var prevModeIdx = mode.Idx; - + ImGui.Text($"Dynamic Update Tool Modes"); ImGui.Separator(); ImGui.RadioButton(DynamicUpdateToolMode.BUILD.Label, ref prevModeIdx, DynamicUpdateToolMode.BUILD.Idx); @@ -280,7 +279,10 @@ public class DynamicUpdateSampleTool : ISampleTool { if (showColliders) { - colliderGizmos.Values.ForEach(g => g.Render(renderer.GetDebugDraw())); + colliderGizmos.Values.ForEach(g => + { + g.Render(renderer.GetDebugDraw()); + }); } } @@ -397,8 +399,7 @@ public class DynamicUpdateSampleTool : ISampleTool if (colliderWithGizmo != null) { long id = dynaMesh.AddCollider(colliderWithGizmo.Collider); - colliders.Add(id, colliderWithGizmo.Collider); - colliderGizmos.Add(id, colliderWithGizmo.Gizmo); + colliderGizmos.Add(id, colliderWithGizmo); } } } @@ -525,11 +526,11 @@ public class DynamicUpdateSampleTool : ISampleTool SphereCollider crown = new SphereCollider(crownCenter, 4f, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS, dynaMesh.config.walkableClimb); CompositeCollider collider = new CompositeCollider(@base, roof, trunk, crown); - IColliderGizmo baseGizmo = GizmoFactory.Box(baseCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(baseUp, forward, baseExtent)); - IColliderGizmo roofGizmo = GizmoFactory.Box(roofCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(roofUp, forward, roofExtent)); - IColliderGizmo trunkGizmo = GizmoFactory.Capsule(trunkStart, trunkEnd, 0.5f); - IColliderGizmo crownGizmo = GizmoFactory.Sphere(crownCenter, 4f); - IColliderGizmo gizmo = GizmoFactory.Composite(baseGizmo, roofGizmo, trunkGizmo, crownGizmo); + IRcGizmoMeshFilter baseGizmo = GizmoFactory.Box(baseCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(baseUp, forward, baseExtent)); + IRcGizmoMeshFilter roofGizmo = GizmoFactory.Box(roofCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(roofUp, forward, roofExtent)); + IRcGizmoMeshFilter trunkGizmo = GizmoFactory.Capsule(trunkStart, trunkEnd, 0.5f); + IRcGizmoMeshFilter crownGizmo = GizmoFactory.Sphere(crownCenter, 4f); + IRcGizmoMeshFilter gizmo = GizmoFactory.Composite(baseGizmo, roofGizmo, trunkGizmo, crownGizmo); return new ColliderWithGizmo(collider, gizmo); } @@ -610,12 +611,11 @@ public class DynamicUpdateSampleTool : ISampleTool { if (shift) { - foreach (var e in colliders) + foreach (var e in colliderGizmos) { - if (Hit(start, dir, e.Value.Bounds())) + if (Hit(start, dir, e.Value.Collider.Bounds())) { dynaMesh.RemoveCollider(e.Key); - colliders.Remove(e.Key); colliderGizmos.Remove(e.Key); break; } @@ -691,10 +691,11 @@ public class DynamicUpdateSampleTool : ISampleTool VoxelFile voxelFile = reader.Read(br); dynaMesh = new DynamicNavMesh(voxelFile); dynaMesh.config.keepIntermediateResults = true; + UpdateUI(); BuildDynaMesh(); - colliders.Clear(); + colliderGizmos.Clear(); } catch (Exception e) { diff --git a/src/DotRecast.Recast.Demo/Tools/Gizmos/BoxGizmo.cs b/src/DotRecast.Recast.Demo/Tools/Gizmos/BoxGizmo.cs deleted file mode 100644 index 1f8f91c..0000000 --- a/src/DotRecast.Recast.Demo/Tools/Gizmos/BoxGizmo.cs +++ /dev/null @@ -1,86 +0,0 @@ -using DotRecast.Core; -using DotRecast.Detour.Dynamic.Colliders; -using DotRecast.Recast.Demo.Draw; - -namespace DotRecast.Recast.Demo.Tools.Gizmos; - -public class BoxGizmo : IColliderGizmo -{ - private static readonly int[] TRIANLGES = - { - 0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, - 2, 6, 7, 2, 7, 3, 4, 0, 3, 4, 3, 7 - }; - - private static readonly RcVec3f[] VERTS = - { - RcVec3f.Of(-1f, -1f, -1f), - RcVec3f.Of(1f, -1f, -1f), - RcVec3f.Of(1f, -1f, 1f), - RcVec3f.Of(-1f, -1f, 1f), - RcVec3f.Of(-1f, 1f, -1f), - RcVec3f.Of(1f, 1f, -1f), - RcVec3f.Of(1f, 1f, 1f), - RcVec3f.Of(-1f, 1f, 1f), - }; - - private readonly float[] vertices = new float[8 * 3]; - private readonly RcVec3f center; - private readonly RcVec3f[] halfEdges; - - public BoxGizmo(RcVec3f center, RcVec3f extent, RcVec3f forward, RcVec3f up) : - this(center, BoxCollider.GetHalfEdges(up, forward, extent)) - { - } - - public BoxGizmo(RcVec3f center, RcVec3f[] halfEdges) - { - this.center = center; - this.halfEdges = halfEdges; - for (int i = 0; i < 8; ++i) - { - float s0 = (i & 1) != 0 ? 1f : -1f; - float s1 = (i & 2) != 0 ? 1f : -1f; - float s2 = (i & 4) != 0 ? 1f : -1f; - vertices[i * 3 + 0] = center.x + s0 * halfEdges[0].x + s1 * halfEdges[1].x + s2 * halfEdges[2].x; - vertices[i * 3 + 1] = center.y + s0 * halfEdges[0].y + s1 * halfEdges[1].y + s2 * halfEdges[2].y; - vertices[i * 3 + 2] = center.z + s0 * halfEdges[0].z + s1 * halfEdges[1].z + s2 * halfEdges[2].z; - } - } - - public void Render(RecastDebugDraw debugDraw) - { - var trX = RcVec3f.Of(halfEdges[0].x, halfEdges[1].x, halfEdges[2].x); - var trY = RcVec3f.Of(halfEdges[0].y, halfEdges[1].y, halfEdges[2].y); - var trZ = RcVec3f.Of(halfEdges[0].z, halfEdges[1].z, halfEdges[2].z); - float[] vertices = new float[8 * 3]; - for (int i = 0; i < 8; i++) - { - vertices[i * 3 + 0] = RcVec3f.Dot(VERTS[i], trX) + center.x; - vertices[i * 3 + 1] = RcVec3f.Dot(VERTS[i], trY) + center.y; - vertices[i * 3 + 2] = RcVec3f.Dot(VERTS[i], trZ) + center.z; - } - - debugDraw.Begin(DebugDrawPrimitives.TRIS); - for (int i = 0; i < 12; i++) - { - int col = DebugDraw.DuRGBA(200, 200, 50, 160); - if (i == 4 || i == 5 || i == 8 || i == 9) - { - col = DebugDraw.DuRGBA(160, 160, 40, 160); - } - else if (i > 4) - { - col = DebugDraw.DuRGBA(120, 120, 30, 160); - } - - for (int j = 0; j < 3; j++) - { - int v = TRIANLGES[i * 3 + j] * 3; - debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col); - } - } - - debugDraw.End(); - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/Gizmos/CapsuleGizmo.cs b/src/DotRecast.Recast.Demo/Tools/Gizmos/CapsuleGizmo.cs deleted file mode 100644 index 2f59554..0000000 --- a/src/DotRecast.Recast.Demo/Tools/Gizmos/CapsuleGizmo.cs +++ /dev/null @@ -1,88 +0,0 @@ -using DotRecast.Core; -using DotRecast.Recast.Demo.Draw; -using static DotRecast.Core.RcMath; -using static DotRecast.Recast.Demo.Tools.Gizmos.GizmoHelper; - -namespace DotRecast.Recast.Demo.Tools.Gizmos; - -public class CapsuleGizmo : IColliderGizmo -{ - private readonly float[] vertices; - private readonly int[] triangles; - private readonly float[] center; - private readonly float[] gradient; - - public CapsuleGizmo(RcVec3f start, RcVec3f end, float radius) - { - center = new float[] - { - 0.5f * (start.x + end.x), 0.5f * (start.y + end.y), - 0.5f * (start.z + end.z) - }; - RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); - RcVec3f[] normals = new RcVec3f[3]; - normals[1] = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); - RcVec3f.Normalize(ref normals[1]); - normals[0] = GetSideVector(axis); - normals[2] = RcVec3f.Zero; - RcVec3f.Cross(ref normals[2], normals[0], normals[1]); - RcVec3f.Normalize(ref normals[2]); - triangles = GenerateSphericalTriangles(); - var trX = RcVec3f.Of(normals[0].x, normals[1].x, normals[2].x); - var trY = RcVec3f.Of(normals[0].y, normals[1].y, normals[2].y); - var trZ = RcVec3f.Of(normals[0].z, normals[1].z, normals[2].z); - float[] spVertices = GenerateSphericalVertices(); - float halfLength = 0.5f * axis.Length(); - vertices = new float[spVertices.Length]; - gradient = new float[spVertices.Length / 3]; - RcVec3f v = new RcVec3f(); - for (int i = 0; i < spVertices.Length; i += 3) - { - float offset = (i >= spVertices.Length / 2) ? -halfLength : halfLength; - float x = radius * spVertices[i]; - float y = radius * spVertices[i + 1] + offset; - float z = radius * spVertices[i + 2]; - vertices[i] = x * trX.x + y * trX.y + z * trX.z + center[0]; - vertices[i + 1] = x * trY.x + y * trY.y + z * trY.z + center[1]; - vertices[i + 2] = x * trZ.x + y * trZ.y + z * trZ.z + center[2]; - v.x = vertices[i] - center[0]; - v.y = vertices[i + 1] - center[1]; - v.z = vertices[i + 2] - center[2]; - RcVec3f.Normalize(ref v); - gradient[i / 3] = Clamp(0.57735026f * (v.x + v.y + v.z), -1, 1); - } - } - - private RcVec3f GetSideVector(RcVec3f axis) - { - RcVec3f side = RcVec3f.Of(1, 0, 0); - if (axis.x > 0.8) - { - side = RcVec3f.Of(0, 0, 1); - } - - RcVec3f forward = new RcVec3f(); - RcVec3f.Cross(ref forward, side, axis); - RcVec3f.Cross(ref side, axis, forward); - RcVec3f.Normalize(ref side); - return side; - } - - public void Render(RecastDebugDraw debugDraw) - { - debugDraw.Begin(DebugDrawPrimitives.TRIS); - for (int i = 0; i < triangles.Length; i += 3) - { - for (int j = 0; j < 3; j++) - { - int v = triangles[i + j] * 3; - float c = gradient[triangles[i + j]]; - int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160), - (int)(127 * (1 + c))); - debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col); - } - } - - debugDraw.End(); - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/Gizmos/ColliderWithGizmo.cs b/src/DotRecast.Recast.Demo/Tools/Gizmos/ColliderWithGizmo.cs deleted file mode 100644 index 96be8bd..0000000 --- a/src/DotRecast.Recast.Demo/Tools/Gizmos/ColliderWithGizmo.cs +++ /dev/null @@ -1,15 +0,0 @@ -using DotRecast.Detour.Dynamic.Colliders; - -namespace DotRecast.Recast.Demo.Tools.Gizmos; - -public class ColliderWithGizmo -{ - public readonly ICollider Collider; - public readonly IColliderGizmo Gizmo; - - public ColliderWithGizmo(ICollider collider, IColliderGizmo gizmo) - { - Collider = collider; - Gizmo = gizmo; - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/Gizmos/CompositeGizmo.cs b/src/DotRecast.Recast.Demo/Tools/Gizmos/CompositeGizmo.cs deleted file mode 100644 index 84b6d23..0000000 --- a/src/DotRecast.Recast.Demo/Tools/Gizmos/CompositeGizmo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using DotRecast.Core; -using DotRecast.Recast.Demo.Draw; - -namespace DotRecast.Recast.Demo.Tools.Gizmos; - -public class CompositeGizmo : IColliderGizmo -{ - private readonly IColliderGizmo[] gizmos; - - public CompositeGizmo(params IColliderGizmo[] gizmos) - { - this.gizmos = gizmos; - } - - public void Render(RecastDebugDraw debugDraw) - { - gizmos.ForEach(g => g.Render(debugDraw)); - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/Gizmos/CylinderGizmo.cs b/src/DotRecast.Recast.Demo/Tools/Gizmos/CylinderGizmo.cs deleted file mode 100644 index 0a3d455..0000000 --- a/src/DotRecast.Recast.Demo/Tools/Gizmos/CylinderGizmo.cs +++ /dev/null @@ -1,94 +0,0 @@ -using DotRecast.Core; -using DotRecast.Recast.Demo.Draw; -using static DotRecast.Core.RcMath; -using static DotRecast.Recast.Demo.Tools.Gizmos.GizmoHelper; - - -namespace DotRecast.Recast.Demo.Tools.Gizmos; - -public class CylinderGizmo : IColliderGizmo -{ - private readonly float[] vertices; - private readonly int[] triangles; - private readonly RcVec3f center; - private readonly float[] gradient; - - public CylinderGizmo(RcVec3f start, RcVec3f end, float radius) - { - center = RcVec3f.Of( - 0.5f * (start.x + end.x), 0.5f * (start.y + end.y), - 0.5f * (start.z + end.z) - ); - RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); - RcVec3f[] normals = new RcVec3f[3]; - normals[1] = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); - RcVec3f.Normalize(ref normals[1]); - normals[0] = GetSideVector(axis); - normals[2] = RcVec3f.Zero; - RcVec3f.Cross(ref normals[2], normals[0], normals[1]); - RcVec3f.Normalize(ref normals[2]); - triangles = GenerateCylindricalTriangles(); - RcVec3f trX = RcVec3f.Of(normals[0].x, normals[1].x, normals[2].x); - RcVec3f trY = RcVec3f.Of(normals[0].y, normals[1].y, normals[2].y); - RcVec3f trZ = RcVec3f.Of(normals[0].z, normals[1].z, normals[2].z); - vertices = GenerateCylindricalVertices(); - float halfLength = 0.5f * axis.Length(); - gradient = new float[vertices.Length / 3]; - RcVec3f v = new RcVec3f(); - for (int i = 0; i < vertices.Length; i += 3) - { - float offset = (i >= vertices.Length / 2) ? -halfLength : halfLength; - float x = radius * vertices[i]; - float y = vertices[i + 1] + offset; - float z = radius * vertices[i + 2]; - vertices[i] = x * trX.x + y * trX.y + z * trX.z + center.x; - vertices[i + 1] = x * trY.x + y * trY.y + z * trY.z + center.y; - vertices[i + 2] = x * trZ.x + y * trZ.y + z * trZ.z + center.z; - if (i < vertices.Length / 4 || i >= 3 * vertices.Length / 4) - { - gradient[i / 3] = 1; - } - else - { - v.x = vertices[i] - center.x; - v.y = vertices[i + 1] - center.y; - v.z = vertices[i + 2] - center.z; - RcVec3f.Normalize(ref v); - gradient[i / 3] = Clamp(0.57735026f * (v.x + v.y + v.z), -1, 1); - } - } - } - - private RcVec3f GetSideVector(RcVec3f axis) - { - RcVec3f side = RcVec3f.Of(1, 0, 0); - if (axis.x > 0.8) - { - side = RcVec3f.Of(0, 0, 1); - } - - RcVec3f forward = new RcVec3f(); - RcVec3f.Cross(ref forward, side, axis); - RcVec3f.Cross(ref side, axis, forward); - RcVec3f.Normalize(ref side); - return side; - } - - public void Render(RecastDebugDraw debugDraw) - { - debugDraw.Begin(DebugDrawPrimitives.TRIS); - for (int i = 0; i < triangles.Length; i += 3) - { - for (int j = 0; j < 3; j++) - { - int v = triangles[i + j] * 3; - float c = gradient[triangles[i + j]]; - int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160), - (int)(127 * (1 + c))); - debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col); - } - } - - debugDraw.End(); - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/Gizmos/GizmoFactory.cs b/src/DotRecast.Recast.Demo/Tools/Gizmos/GizmoFactory.cs deleted file mode 100644 index bbc5a20..0000000 --- a/src/DotRecast.Recast.Demo/Tools/Gizmos/GizmoFactory.cs +++ /dev/null @@ -1,36 +0,0 @@ -using DotRecast.Core; - -namespace DotRecast.Recast.Demo.Tools.Gizmos; - -public static class GizmoFactory -{ - public static IColliderGizmo Box(RcVec3f center, RcVec3f[] halfEdges) - { - return new BoxGizmo(center, halfEdges); - } - - public static IColliderGizmo Sphere(RcVec3f center, float radius) - { - return new SphereGizmo(center, radius); - } - - public static IColliderGizmo Capsule(RcVec3f start, RcVec3f end, float radius) - { - return new CapsuleGizmo(start, end, radius); - } - - public static IColliderGizmo Cylinder(RcVec3f start, RcVec3f end, float radius) - { - return new CylinderGizmo(start, end, radius); - } - - public static IColliderGizmo Trimesh(float[] verts, int[] faces) - { - return new TrimeshGizmo(verts, faces); - } - - public static IColliderGizmo Composite(params IColliderGizmo[] gizmos) - { - return new CompositeGizmo(gizmos); - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/Gizmos/GizmoHelper.cs b/src/DotRecast.Recast.Demo/Tools/Gizmos/GizmoHelper.cs deleted file mode 100644 index 6d003a6..0000000 --- a/src/DotRecast.Recast.Demo/Tools/Gizmos/GizmoHelper.cs +++ /dev/null @@ -1,197 +0,0 @@ -using System; -using DotRecast.Core; -using DotRecast.Recast.Demo.Draw; -using static DotRecast.Core.RcMath; - -namespace DotRecast.Recast.Demo.Tools.Gizmos; - -public class GizmoHelper -{ - private static readonly int SEGMENTS = 16; - private static readonly int RINGS = 8; - - private static float[] sphericalVertices; - - public static float[] GenerateSphericalVertices() - { - if (sphericalVertices == null) - { - sphericalVertices = GenerateSphericalVertices(SEGMENTS, RINGS); - } - - return sphericalVertices; - } - - private static float[] GenerateSphericalVertices(int segments, int rings) - { - float[] vertices = new float[6 + 3 * (segments + 1) * (rings + 1)]; - // top - int vi = 0; - vertices[vi++] = 0; - vertices[vi++] = 1; - vertices[vi++] = 0; - for (int r = 0; r <= rings; r++) - { - double theta = Math.PI * (r + 1) / (rings + 2); - vi = GenerateRingVertices(segments, vertices, vi, theta); - } - - // bottom - vertices[vi++] = 0; - vertices[vi++] = -1; - vertices[vi++] = 0; - return vertices; - } - - public static float[] GenerateCylindricalVertices() - { - return GenerateCylindricalVertices(SEGMENTS); - } - - private static float[] GenerateCylindricalVertices(int segments) - { - float[] vertices = new float[3 * (segments + 1) * 4]; - int vi = 0; - for (int r = 0; r < 4; r++) - { - vi = GenerateRingVertices(segments, vertices, vi, Math.PI * 0.5); - } - - return vertices; - } - - private static int GenerateRingVertices(int segments, float[] vertices, int vi, double theta) - { - double cosTheta = Math.Cos(theta); - double sinTheta = Math.Sin(theta); - for (int p = 0; p <= segments; p++) - { - double phi = 2 * Math.PI * p / segments; - double cosPhi = Math.Cos(phi); - double sinPhi = Math.Sin(phi); - vertices[vi++] = (float)(sinTheta * cosPhi); - vertices[vi++] = (float)cosTheta; - vertices[vi++] = (float)(sinTheta * sinPhi); - } - - return vi; - } - - public static int[] GenerateSphericalTriangles() - { - return GenerateSphericalTriangles(SEGMENTS, RINGS); - } - - private static int[] GenerateSphericalTriangles(int segments, int rings) - { - int[] triangles = new int[6 * (segments + rings * (segments + 1))]; - int ti = GenerateSphereUpperCapTriangles(segments, triangles, 0); - ti = GenerateRingTriangles(segments, rings, triangles, 1, ti); - GenerateSphereLowerCapTriangles(segments, rings, triangles, ti); - return triangles; - } - - public static int GenerateRingTriangles(int segments, int rings, int[] triangles, int vertexOffset, int ti) - { - for (int r = 0; r < rings; r++) - { - for (int p = 0; p < segments; p++) - { - int current = p + r * (segments + 1) + vertexOffset; - int next = p + 1 + r * (segments + 1) + vertexOffset; - int currentBottom = p + (r + 1) * (segments + 1) + vertexOffset; - int nextBottom = p + 1 + (r + 1) * (segments + 1) + vertexOffset; - triangles[ti++] = current; - triangles[ti++] = next; - triangles[ti++] = nextBottom; - triangles[ti++] = current; - triangles[ti++] = nextBottom; - triangles[ti++] = currentBottom; - } - } - - return ti; - } - - private static int GenerateSphereUpperCapTriangles(int segments, int[] triangles, int ti) - { - for (int p = 0; p < segments; p++) - { - triangles[ti++] = p + 2; - triangles[ti++] = p + 1; - triangles[ti++] = 0; - } - - return ti; - } - - private static void GenerateSphereLowerCapTriangles(int segments, int rings, int[] triangles, int ti) - { - int lastVertex = 1 + (segments + 1) * (rings + 1); - for (int p = 0; p < segments; p++) - { - triangles[ti++] = lastVertex; - triangles[ti++] = lastVertex - (p + 2); - triangles[ti++] = lastVertex - (p + 1); - } - } - - public static int[] GenerateCylindricalTriangles() - { - return GenerateCylindricalTriangles(SEGMENTS); - } - - private static int[] GenerateCylindricalTriangles(int segments) - { - int circleTriangles = segments - 2; - int[] triangles = new int[6 * (circleTriangles + (segments + 1))]; - int vi = 0; - int ti = GenerateCircleTriangles(segments, triangles, vi, 0, false); - ti = GenerateRingTriangles(segments, 1, triangles, segments + 1, ti); - int vertexCount = (segments + 1) * 4; - ti = GenerateCircleTriangles(segments, triangles, vertexCount - segments, ti, true); - return triangles; - } - - private static int GenerateCircleTriangles(int segments, int[] triangles, int vi, int ti, bool invert) - { - for (int p = 0; p < segments - 2; p++) - { - if (invert) - { - triangles[ti++] = vi; - triangles[ti++] = vi + p + 1; - triangles[ti++] = vi + p + 2; - } - else - { - triangles[ti++] = vi + p + 2; - triangles[ti++] = vi + p + 1; - triangles[ti++] = vi; - } - } - - return ti; - } - - public static int GetColorByNormal(float[] vertices, int v0, int v1, int v2) - { - RcVec3f e0 = new RcVec3f(); - RcVec3f e1 = new RcVec3f(); - RcVec3f normal = new RcVec3f(); - for (int j = 0; j < 3; ++j) - { - e0[j] = vertices[v1 + j] - vertices[v0 + j]; - e1[j] = vertices[v2 + j] - vertices[v0 + j]; - } - - normal.x = e0.y * e1.z - e0.z * e1.y; - normal.y = e0.z * e1.x - e0.x * e1.z; - normal.z = e0.x * e1.y - e0.y * e1.x; - RcVec3f.Normalize(ref normal); - float c = Clamp(0.57735026f * (normal.x + normal.y + normal.z), -1, 1); - int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160), - (int)(127 * (1 + c))); - return col; - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/Gizmos/IColliderGizmo.cs b/src/DotRecast.Recast.Demo/Tools/Gizmos/IColliderGizmo.cs deleted file mode 100644 index dbcf621..0000000 --- a/src/DotRecast.Recast.Demo/Tools/Gizmos/IColliderGizmo.cs +++ /dev/null @@ -1,8 +0,0 @@ -using DotRecast.Recast.Demo.Draw; - -namespace DotRecast.Recast.Demo.Tools.Gizmos; - -public interface IColliderGizmo -{ - void Render(RecastDebugDraw debugDraw); -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/Gizmos/SphereGizmo.cs b/src/DotRecast.Recast.Demo/Tools/Gizmos/SphereGizmo.cs deleted file mode 100644 index 380c2e9..0000000 --- a/src/DotRecast.Recast.Demo/Tools/Gizmos/SphereGizmo.cs +++ /dev/null @@ -1,42 +0,0 @@ -using DotRecast.Core; -using DotRecast.Recast.Demo.Draw; -using static DotRecast.Core.RcMath; -using static DotRecast.Recast.Demo.Tools.Gizmos.GizmoHelper; - - -namespace DotRecast.Recast.Demo.Tools.Gizmos; - -public class SphereGizmo : IColliderGizmo -{ - private readonly float[] vertices; - private readonly int[] triangles; - private readonly float radius; - private readonly RcVec3f center; - - public SphereGizmo(RcVec3f center, float radius) - { - this.center = center; - this.radius = radius; - vertices = GenerateSphericalVertices(); - triangles = GenerateSphericalTriangles(); - } - - public void Render(RecastDebugDraw debugDraw) - { - debugDraw.Begin(DebugDrawPrimitives.TRIS); - for (int i = 0; i < triangles.Length; i += 3) - { - for (int j = 0; j < 3; j++) - { - int v = triangles[i + j] * 3; - float c = Clamp(0.57735026f * (vertices[v] + vertices[v + 1] + vertices[v + 2]), -1, 1); - int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160), - (int)(127 * (1 + c))); - debugDraw.Vertex(radius * vertices[v] + center.x, radius * vertices[v + 1] + center.y, - radius * vertices[v + 2] + center.z, col); - } - } - - debugDraw.End(); - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/Gizmos/TrimeshGizmo.cs b/src/DotRecast.Recast.Demo/Tools/Gizmos/TrimeshGizmo.cs deleted file mode 100644 index bed1efe..0000000 --- a/src/DotRecast.Recast.Demo/Tools/Gizmos/TrimeshGizmo.cs +++ /dev/null @@ -1,32 +0,0 @@ -using DotRecast.Recast.Demo.Draw; - -namespace DotRecast.Recast.Demo.Tools.Gizmos; - -public class TrimeshGizmo : IColliderGizmo -{ - private readonly float[] vertices; - private readonly int[] triangles; - - public TrimeshGizmo(float[] vertices, int[] triangles) - { - this.vertices = vertices; - this.triangles = triangles; - } - - public void Render(RecastDebugDraw debugDraw) - { - debugDraw.Begin(DebugDrawPrimitives.TRIS); - for (int i = 0; i < triangles.Length; i += 3) - { - int v0 = 3 * triangles[i]; - int v1 = 3 * triangles[i + 1]; - int v2 = 3 * triangles[i + 2]; - int col = GizmoHelper.GetColorByNormal(vertices, v0, v1, v2); - debugDraw.Vertex(vertices[v0], vertices[v0 + 1], vertices[v0 + 2], col); - debugDraw.Vertex(vertices[v1], vertices[v1 + 1], vertices[v1 + 2], col); - debugDraw.Vertex(vertices[v2], vertices[v2 + 1], vertices[v2 + 2], col); - } - - debugDraw.End(); - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/Gizmos/BoxGizmo.cs b/src/DotRecast.Recast.Toolset/Tools/Gizmos/BoxGizmo.cs new file mode 100644 index 0000000..fa0725e --- /dev/null +++ b/src/DotRecast.Recast.Toolset/Tools/Gizmos/BoxGizmo.cs @@ -0,0 +1,50 @@ +using DotRecast.Core; +using DotRecast.Detour.Dynamic.Colliders; + +namespace DotRecast.Recast.Toolset.Tools.Gizmos +{ + public class BoxGizmo : IRcGizmoMeshFilter + { + public static readonly int[] TRIANLGES = + { + 0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, + 2, 6, 7, 2, 7, 3, 4, 0, 3, 4, 3, 7 + }; + + public static readonly RcVec3f[] VERTS = + { + RcVec3f.Of(-1f, -1f, -1f), + RcVec3f.Of(1f, -1f, -1f), + RcVec3f.Of(1f, -1f, 1f), + RcVec3f.Of(-1f, -1f, 1f), + RcVec3f.Of(-1f, 1f, -1f), + RcVec3f.Of(1f, 1f, -1f), + RcVec3f.Of(1f, 1f, 1f), + RcVec3f.Of(-1f, 1f, 1f), + }; + + public readonly float[] vertices = new float[8 * 3]; + public readonly RcVec3f center; + public readonly RcVec3f[] halfEdges; + + public BoxGizmo(RcVec3f center, RcVec3f extent, RcVec3f forward, RcVec3f up) : + this(center, BoxCollider.GetHalfEdges(up, forward, extent)) + { + } + + public BoxGizmo(RcVec3f center, RcVec3f[] halfEdges) + { + this.center = center; + this.halfEdges = halfEdges; + for (int i = 0; i < 8; ++i) + { + float s0 = (i & 1) != 0 ? 1f : -1f; + float s1 = (i & 2) != 0 ? 1f : -1f; + float s2 = (i & 4) != 0 ? 1f : -1f; + vertices[i * 3 + 0] = center.x + s0 * halfEdges[0].x + s1 * halfEdges[1].x + s2 * halfEdges[2].x; + vertices[i * 3 + 1] = center.y + s0 * halfEdges[0].y + s1 * halfEdges[1].y + s2 * halfEdges[2].y; + vertices[i * 3 + 2] = center.z + s0 * halfEdges[0].z + s1 * halfEdges[1].z + s2 * halfEdges[2].z; + } + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/Gizmos/CapsuleGizmo.cs b/src/DotRecast.Recast.Toolset/Tools/Gizmos/CapsuleGizmo.cs new file mode 100644 index 0000000..a33ba22 --- /dev/null +++ b/src/DotRecast.Recast.Toolset/Tools/Gizmos/CapsuleGizmo.cs @@ -0,0 +1,70 @@ +using DotRecast.Core; +using static DotRecast.Core.RcMath; +using static DotRecast.Recast.Toolset.Tools.Gizmos.GizmoHelper; + +namespace DotRecast.Recast.Toolset.Tools.Gizmos +{ + public class CapsuleGizmo : IRcGizmoMeshFilter + { + public readonly float[] vertices; + public readonly int[] triangles; + public readonly float[] center; + public readonly float[] gradient; + + public CapsuleGizmo(RcVec3f start, RcVec3f end, float radius) + { + center = new float[] + { + 0.5f * (start.x + end.x), 0.5f * (start.y + end.y), + 0.5f * (start.z + end.z) + }; + RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); + RcVec3f[] normals = new RcVec3f[3]; + normals[1] = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); + RcVec3f.Normalize(ref normals[1]); + normals[0] = GetSideVector(axis); + normals[2] = RcVec3f.Zero; + RcVec3f.Cross(ref normals[2], normals[0], normals[1]); + RcVec3f.Normalize(ref normals[2]); + triangles = GenerateSphericalTriangles(); + var trX = RcVec3f.Of(normals[0].x, normals[1].x, normals[2].x); + var trY = RcVec3f.Of(normals[0].y, normals[1].y, normals[2].y); + var trZ = RcVec3f.Of(normals[0].z, normals[1].z, normals[2].z); + float[] spVertices = GenerateSphericalVertices(); + float halfLength = 0.5f * axis.Length(); + vertices = new float[spVertices.Length]; + gradient = new float[spVertices.Length / 3]; + RcVec3f v = new RcVec3f(); + for (int i = 0; i < spVertices.Length; i += 3) + { + float offset = (i >= spVertices.Length / 2) ? -halfLength : halfLength; + float x = radius * spVertices[i]; + float y = radius * spVertices[i + 1] + offset; + float z = radius * spVertices[i + 2]; + vertices[i] = x * trX.x + y * trX.y + z * trX.z + center[0]; + vertices[i + 1] = x * trY.x + y * trY.y + z * trY.z + center[1]; + vertices[i + 2] = x * trZ.x + y * trZ.y + z * trZ.z + center[2]; + v.x = vertices[i] - center[0]; + v.y = vertices[i + 1] - center[1]; + v.z = vertices[i + 2] - center[2]; + RcVec3f.Normalize(ref v); + gradient[i / 3] = Clamp(0.57735026f * (v.x + v.y + v.z), -1, 1); + } + } + + private RcVec3f GetSideVector(RcVec3f axis) + { + RcVec3f side = RcVec3f.Of(1, 0, 0); + if (axis.x > 0.8) + { + side = RcVec3f.Of(0, 0, 1); + } + + RcVec3f forward = new RcVec3f(); + RcVec3f.Cross(ref forward, side, axis); + RcVec3f.Cross(ref side, axis, forward); + RcVec3f.Normalize(ref side); + return side; + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/Gizmos/CompositeGizmo.cs b/src/DotRecast.Recast.Toolset/Tools/Gizmos/CompositeGizmo.cs new file mode 100644 index 0000000..96bad17 --- /dev/null +++ b/src/DotRecast.Recast.Toolset/Tools/Gizmos/CompositeGizmo.cs @@ -0,0 +1,12 @@ +namespace DotRecast.Recast.Toolset.Tools.Gizmos +{ + public class CompositeGizmo : IRcGizmoMeshFilter + { + public readonly IRcGizmoMeshFilter[] gizmoMeshes; + + public CompositeGizmo(params IRcGizmoMeshFilter[] gizmoMeshes) + { + this.gizmoMeshes = gizmoMeshes; + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/Gizmos/CylinderGizmo.cs b/src/DotRecast.Recast.Toolset/Tools/Gizmos/CylinderGizmo.cs new file mode 100644 index 0000000..aa72e2f --- /dev/null +++ b/src/DotRecast.Recast.Toolset/Tools/Gizmos/CylinderGizmo.cs @@ -0,0 +1,76 @@ +using DotRecast.Core; +using static DotRecast.Core.RcMath; +using static DotRecast.Recast.Toolset.Tools.Gizmos.GizmoHelper; + + +namespace DotRecast.Recast.Toolset.Tools.Gizmos +{ + public class CylinderGizmo : IRcGizmoMeshFilter + { + public readonly float[] vertices; + public readonly int[] triangles; + public readonly RcVec3f center; + public readonly float[] gradient; + + public CylinderGizmo(RcVec3f start, RcVec3f end, float radius) + { + center = RcVec3f.Of( + 0.5f * (start.x + end.x), 0.5f * (start.y + end.y), + 0.5f * (start.z + end.z) + ); + RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); + RcVec3f[] normals = new RcVec3f[3]; + normals[1] = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); + RcVec3f.Normalize(ref normals[1]); + normals[0] = GetSideVector(axis); + normals[2] = RcVec3f.Zero; + RcVec3f.Cross(ref normals[2], normals[0], normals[1]); + RcVec3f.Normalize(ref normals[2]); + triangles = GenerateCylindricalTriangles(); + RcVec3f trX = RcVec3f.Of(normals[0].x, normals[1].x, normals[2].x); + RcVec3f trY = RcVec3f.Of(normals[0].y, normals[1].y, normals[2].y); + RcVec3f trZ = RcVec3f.Of(normals[0].z, normals[1].z, normals[2].z); + vertices = GenerateCylindricalVertices(); + float halfLength = 0.5f * axis.Length(); + gradient = new float[vertices.Length / 3]; + RcVec3f v = new RcVec3f(); + for (int i = 0; i < vertices.Length; i += 3) + { + float offset = (i >= vertices.Length / 2) ? -halfLength : halfLength; + float x = radius * vertices[i]; + float y = vertices[i + 1] + offset; + float z = radius * vertices[i + 2]; + vertices[i] = x * trX.x + y * trX.y + z * trX.z + center.x; + vertices[i + 1] = x * trY.x + y * trY.y + z * trY.z + center.y; + vertices[i + 2] = x * trZ.x + y * trZ.y + z * trZ.z + center.z; + if (i < vertices.Length / 4 || i >= 3 * vertices.Length / 4) + { + gradient[i / 3] = 1; + } + else + { + v.x = vertices[i] - center.x; + v.y = vertices[i + 1] - center.y; + v.z = vertices[i + 2] - center.z; + RcVec3f.Normalize(ref v); + gradient[i / 3] = Clamp(0.57735026f * (v.x + v.y + v.z), -1, 1); + } + } + } + + private RcVec3f GetSideVector(RcVec3f axis) + { + RcVec3f side = RcVec3f.Of(1, 0, 0); + if (axis.x > 0.8) + { + side = RcVec3f.Of(0, 0, 1); + } + + RcVec3f forward = new RcVec3f(); + RcVec3f.Cross(ref forward, side, axis); + RcVec3f.Cross(ref side, axis, forward); + RcVec3f.Normalize(ref side); + return side; + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/Gizmos/GizmoFactory.cs b/src/DotRecast.Recast.Toolset/Tools/Gizmos/GizmoFactory.cs new file mode 100644 index 0000000..d48cfc2 --- /dev/null +++ b/src/DotRecast.Recast.Toolset/Tools/Gizmos/GizmoFactory.cs @@ -0,0 +1,37 @@ +using DotRecast.Core; + +namespace DotRecast.Recast.Toolset.Tools.Gizmos +{ + public static class GizmoFactory + { + public static BoxGizmo Box(RcVec3f center, RcVec3f[] halfEdges) + { + return new BoxGizmo(center, halfEdges); + } + + public static SphereGizmo Sphere(RcVec3f center, float radius) + { + return new SphereGizmo(center, radius); + } + + public static CapsuleGizmo Capsule(RcVec3f start, RcVec3f end, float radius) + { + return new CapsuleGizmo(start, end, radius); + } + + public static CylinderGizmo Cylinder(RcVec3f start, RcVec3f end, float radius) + { + return new CylinderGizmo(start, end, radius); + } + + public static TrimeshGizmo Trimesh(float[] verts, int[] faces) + { + return new TrimeshGizmo(verts, faces); + } + + public static CompositeGizmo Composite(params IRcGizmoMeshFilter[] gizmos) + { + return new CompositeGizmo(gizmos); + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/Gizmos/GizmoHelper.cs b/src/DotRecast.Recast.Toolset/Tools/Gizmos/GizmoHelper.cs new file mode 100644 index 0000000..4d7f070 --- /dev/null +++ b/src/DotRecast.Recast.Toolset/Tools/Gizmos/GizmoHelper.cs @@ -0,0 +1,174 @@ +using System; + +namespace DotRecast.Recast.Toolset.Tools.Gizmos +{ + public static class GizmoHelper + { + private static readonly int SEGMENTS = 16; + private static readonly int RINGS = 8; + + private static float[] sphericalVertices; + + public static float[] GenerateSphericalVertices() + { + if (sphericalVertices == null) + { + sphericalVertices = GenerateSphericalVertices(SEGMENTS, RINGS); + } + + return sphericalVertices; + } + + private static float[] GenerateSphericalVertices(int segments, int rings) + { + float[] vertices = new float[6 + 3 * (segments + 1) * (rings + 1)]; + // top + int vi = 0; + vertices[vi++] = 0; + vertices[vi++] = 1; + vertices[vi++] = 0; + for (int r = 0; r <= rings; r++) + { + double theta = Math.PI * (r + 1) / (rings + 2); + vi = GenerateRingVertices(segments, vertices, vi, theta); + } + + // bottom + vertices[vi++] = 0; + vertices[vi++] = -1; + vertices[vi++] = 0; + return vertices; + } + + public static float[] GenerateCylindricalVertices() + { + return GenerateCylindricalVertices(SEGMENTS); + } + + private static float[] GenerateCylindricalVertices(int segments) + { + float[] vertices = new float[3 * (segments + 1) * 4]; + int vi = 0; + for (int r = 0; r < 4; r++) + { + vi = GenerateRingVertices(segments, vertices, vi, Math.PI * 0.5); + } + + return vertices; + } + + private static int GenerateRingVertices(int segments, float[] vertices, int vi, double theta) + { + double cosTheta = Math.Cos(theta); + double sinTheta = Math.Sin(theta); + for (int p = 0; p <= segments; p++) + { + double phi = 2 * Math.PI * p / segments; + double cosPhi = Math.Cos(phi); + double sinPhi = Math.Sin(phi); + vertices[vi++] = (float)(sinTheta * cosPhi); + vertices[vi++] = (float)cosTheta; + vertices[vi++] = (float)(sinTheta * sinPhi); + } + + return vi; + } + + public static int[] GenerateSphericalTriangles() + { + return GenerateSphericalTriangles(SEGMENTS, RINGS); + } + + private static int[] GenerateSphericalTriangles(int segments, int rings) + { + int[] triangles = new int[6 * (segments + rings * (segments + 1))]; + int ti = GenerateSphereUpperCapTriangles(segments, triangles, 0); + ti = GenerateRingTriangles(segments, rings, triangles, 1, ti); + GenerateSphereLowerCapTriangles(segments, rings, triangles, ti); + return triangles; + } + + public static int GenerateRingTriangles(int segments, int rings, int[] triangles, int vertexOffset, int ti) + { + for (int r = 0; r < rings; r++) + { + for (int p = 0; p < segments; p++) + { + int current = p + r * (segments + 1) + vertexOffset; + int next = p + 1 + r * (segments + 1) + vertexOffset; + int currentBottom = p + (r + 1) * (segments + 1) + vertexOffset; + int nextBottom = p + 1 + (r + 1) * (segments + 1) + vertexOffset; + triangles[ti++] = current; + triangles[ti++] = next; + triangles[ti++] = nextBottom; + triangles[ti++] = current; + triangles[ti++] = nextBottom; + triangles[ti++] = currentBottom; + } + } + + return ti; + } + + private static int GenerateSphereUpperCapTriangles(int segments, int[] triangles, int ti) + { + for (int p = 0; p < segments; p++) + { + triangles[ti++] = p + 2; + triangles[ti++] = p + 1; + triangles[ti++] = 0; + } + + return ti; + } + + private static void GenerateSphereLowerCapTriangles(int segments, int rings, int[] triangles, int ti) + { + int lastVertex = 1 + (segments + 1) * (rings + 1); + for (int p = 0; p < segments; p++) + { + triangles[ti++] = lastVertex; + triangles[ti++] = lastVertex - (p + 2); + triangles[ti++] = lastVertex - (p + 1); + } + } + + public static int[] GenerateCylindricalTriangles() + { + return GenerateCylindricalTriangles(SEGMENTS); + } + + private static int[] GenerateCylindricalTriangles(int segments) + { + int circleTriangles = segments - 2; + int[] triangles = new int[6 * (circleTriangles + (segments + 1))]; + int vi = 0; + int ti = GenerateCircleTriangles(segments, triangles, vi, 0, false); + ti = GenerateRingTriangles(segments, 1, triangles, segments + 1, ti); + int vertexCount = (segments + 1) * 4; + ti = GenerateCircleTriangles(segments, triangles, vertexCount - segments, ti, true); + return triangles; + } + + private static int GenerateCircleTriangles(int segments, int[] triangles, int vi, int ti, bool invert) + { + for (int p = 0; p < segments - 2; p++) + { + if (invert) + { + triangles[ti++] = vi; + triangles[ti++] = vi + p + 1; + triangles[ti++] = vi + p + 2; + } + else + { + triangles[ti++] = vi + p + 2; + triangles[ti++] = vi + p + 1; + triangles[ti++] = vi; + } + } + + return ti; + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/Gizmos/IRcGizmoMeshFilter.cs b/src/DotRecast.Recast.Toolset/Tools/Gizmos/IRcGizmoMeshFilter.cs new file mode 100644 index 0000000..066d3ef --- /dev/null +++ b/src/DotRecast.Recast.Toolset/Tools/Gizmos/IRcGizmoMeshFilter.cs @@ -0,0 +1,9 @@ +//using DotRecast.Recast.Demo.Draw; + +namespace DotRecast.Recast.Toolset.Tools.Gizmos +{ + public interface IRcGizmoMeshFilter + { + //void Render(RecastDebugDraw debugDraw); + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/Gizmos/SphereGizmo.cs b/src/DotRecast.Recast.Toolset/Tools/Gizmos/SphereGizmo.cs new file mode 100644 index 0000000..af9e8dd --- /dev/null +++ b/src/DotRecast.Recast.Toolset/Tools/Gizmos/SphereGizmo.cs @@ -0,0 +1,22 @@ +using DotRecast.Core; +using static DotRecast.Recast.Toolset.Tools.Gizmos.GizmoHelper; + + +namespace DotRecast.Recast.Toolset.Tools.Gizmos +{ + public class SphereGizmo : IRcGizmoMeshFilter + { + public readonly float[] vertices; + public readonly int[] triangles; + public readonly float radius; + public readonly RcVec3f center; + + public SphereGizmo(RcVec3f center, float radius) + { + this.center = center; + this.radius = radius; + vertices = GenerateSphericalVertices(); + triangles = GenerateSphericalTriangles(); + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/Gizmos/TrimeshGizmo.cs b/src/DotRecast.Recast.Toolset/Tools/Gizmos/TrimeshGizmo.cs new file mode 100644 index 0000000..e07aae6 --- /dev/null +++ b/src/DotRecast.Recast.Toolset/Tools/Gizmos/TrimeshGizmo.cs @@ -0,0 +1,14 @@ +namespace DotRecast.Recast.Toolset.Tools.Gizmos +{ + public class TrimeshGizmo : IRcGizmoMeshFilter + { + public readonly float[] vertices; + public readonly int[] triangles; + + public TrimeshGizmo(float[] vertices, int[] triangles) + { + this.vertices = vertices; + this.triangles = triangles; + } + } +} \ No newline at end of file