diff --git a/src/DotRecast.Core/Intersections.cs b/src/DotRecast.Core/Intersections.cs new file mode 100644 index 0000000..e48c5c8 --- /dev/null +++ b/src/DotRecast.Core/Intersections.cs @@ -0,0 +1,133 @@ +/* +recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +using System; +using DotRecast.Core; +using static DotRecast.Core.RecastMath; + +namespace DotRecast.Core +{ + public static class Intersections + { + public static float? intersectSegmentTriangle(Vector3f sp, Vector3f sq, Vector3f a, Vector3f b, Vector3f c) + { + float v, w; + Vector3f ab = vSub(b, a); + Vector3f ac = vSub(c, a); + Vector3f qp = vSub(sp, sq); + + // Compute triangle normal. Can be precalculated or cached if + // intersecting multiple segments against the same triangle + Vector3f norm = vCross(ab, ac); + + // Compute denominator d. If d <= 0, segment is parallel to or points + // away from triangle, so exit early + float d = vDot(qp, norm); + if (d <= 0.0f) + { + return null; + } + + // Compute intersection t value of pq with plane of triangle. A ray + // intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay + // dividing by d until intersection has been found to pierce triangle + Vector3f ap = vSub(sp, a); + float t = vDot(ap, norm); + if (t < 0.0f) + { + return null; + } + + if (t > d) + { + return null; // For segment; exclude this code line for a ray test + } + + // Compute barycentric coordinate components and test if within bounds + Vector3f e = vCross(qp, ap); + v = vDot(ac, e); + if (v < 0.0f || v > d) + { + return null; + } + + w = -vDot(ab, e); + if (w < 0.0f || v + w > d) + { + return null; + } + + // Segment/ray intersects triangle. Perform delayed division + t /= d; + + return t; + } + + public static float[] intersectSegmentAABB(Vector3f sp, Vector3f sq, Vector3f amin, Vector3f amax) + { + float EPS = 1e-6f; + + Vector3f d = new Vector3f(); + d[0] = sq[0] - sp[0]; + d[1] = sq[1] - sp[1]; + d[2] = sq[2] - sp[2]; + float tmin = 0.0f; + float tmax = 1.0f; + + for (int i = 0; i < 3; i++) + { + if (Math.Abs(d[i]) < EPS) + { + if (sp[i] < amin[i] || sp[i] > amax[i]) + { + return null; + } + } + else + { + float ood = 1.0f / d[i]; + float t1 = (amin[i] - sp[i]) * ood; + float t2 = (amax[i] - sp[i]) * ood; + if (t1 > t2) + { + float tmp = t1; + t1 = t2; + t2 = tmp; + } + + if (t1 > tmin) + { + tmin = t1; + } + + if (t2 < tmax) + { + tmax = t2; + } + + if (tmin > tmax) + { + return null; + } + } + } + + return new float[] { tmin, tmax }; + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Detour/DotRecast.Detour.csproj b/src/DotRecast.Detour/DotRecast.Detour.csproj index 4ee2241..b49b2e6 100644 --- a/src/DotRecast.Detour/DotRecast.Detour.csproj +++ b/src/DotRecast.Detour/DotRecast.Detour.csproj @@ -2,7 +2,6 @@ netstandard2.1 - diff --git a/src/DotRecast.Detour/NavMeshRaycast.cs b/src/DotRecast.Detour/NavMeshRaycast.cs new file mode 100644 index 0000000..b379d27 --- /dev/null +++ b/src/DotRecast.Detour/NavMeshRaycast.cs @@ -0,0 +1,98 @@ +/* +recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +using DotRecast.Core; + +namespace DotRecast.Detour +{ + + /** + * Simple helper to find an intersection between a ray and a nav mesh + */ + public static class NavMeshRaycast + { + public static float? raycast(NavMesh mesh, Vector3f src, Vector3f dst) + { + for (int t = 0; t < mesh.getMaxTiles(); ++t) + { + MeshTile tile = mesh.getTile(t); + if (tile != null && tile.data != null) + { + float? intersection = raycast(tile, src, dst); + if (null != intersection) + { + return intersection; + } + } + } + + return null; + } + + private static float? raycast(MeshTile tile, Vector3f sp, Vector3f sq) + { + for (int i = 0; i < tile.data.header.polyCount; ++i) + { + Poly p = tile.data.polys[i]; + if (p.getType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION) + { + continue; + } + + PolyDetail pd = tile.data.detailMeshes[i]; + + if (pd != null) + { + Vector3f[] verts = new Vector3f[3]; + for (int j = 0; j < pd.triCount; ++j) + { + int t = (pd.triBase + j) * 4; + for (int k = 0; k < 3; ++k) + { + int v = tile.data.detailTris[t + k]; + if (v < p.vertCount) + { + verts[k][0] = tile.data.verts[p.verts[v] * 3]; + verts[k][1] = tile.data.verts[p.verts[v] * 3 + 1]; + verts[k][2] = tile.data.verts[p.verts[v] * 3 + 2]; + } + else + { + verts[k][0] = tile.data.detailVerts[(pd.vertBase + v - p.vertCount) * 3]; + verts[k][1] = tile.data.detailVerts[(pd.vertBase + v - p.vertCount) * 3 + 1]; + verts[k][2] = tile.data.detailVerts[(pd.vertBase + v - p.vertCount) * 3 + 2]; + } + } + + float? intersection = Intersections.intersectSegmentTriangle(sp, sq, verts[0], verts[1], verts[2]); + if (null != intersection) + { + return intersection; + } + } + } + else + { + // FIXME: Use Poly if PolyDetail is unavailable + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Detour/NavMeshUtils.cs b/src/DotRecast.Detour/NavMeshUtils.cs new file mode 100644 index 0000000..1d25dc5 --- /dev/null +++ b/src/DotRecast.Detour/NavMeshUtils.cs @@ -0,0 +1,51 @@ +/* +recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +using System; +using DotRecast.Core; +using DotRecast.Detour; + +namespace DotRecast.Detour +{ + public static class NavMeshUtils + { + public static Vector3f[] getNavMeshBounds(NavMesh mesh) + { + Vector3f bmin = Vector3f.Of(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); + Vector3f bmax = Vector3f.Of(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); + for (int t = 0; t < mesh.getMaxTiles(); ++t) + { + MeshTile tile = mesh.getTile(t); + if (tile != null && tile.data != null) + { + for (int i = 0; i < tile.data.verts.Length; i += 3) + { + bmin[0] = Math.Min(bmin[0], tile.data.verts[i]); + bmin[1] = Math.Min(bmin[1], tile.data.verts[i + 1]); + bmin[2] = Math.Min(bmin[2], tile.data.verts[i + 2]); + bmax[0] = Math.Max(bmax[0], tile.data.verts[i]); + bmax[1] = Math.Max(bmax[1], tile.data.verts[i + 1]); + bmax[2] = Math.Max(bmax[2], tile.data.verts[i + 2]); + } + } + } + + return new[] { bmin, bmax }; + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Geom/Intersections.cs b/src/DotRecast.Recast.Demo/Geom/Intersections.cs deleted file mode 100644 index 886e47d..0000000 --- a/src/DotRecast.Recast.Demo/Geom/Intersections.cs +++ /dev/null @@ -1,132 +0,0 @@ -/* -recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. -*/ - -using System; -using DotRecast.Core; -using static DotRecast.Core.RecastMath; - -namespace DotRecast.Recast.Demo.Geom; - -public class Intersections -{ - public static float? intersectSegmentTriangle(Vector3f sp, Vector3f sq, Vector3f a, Vector3f b, Vector3f c) - { - float v, w; - Vector3f ab = vSub(b, a); - Vector3f ac = vSub(c, a); - Vector3f qp = vSub(sp, sq); - - // Compute triangle normal. Can be precalculated or cached if - // intersecting multiple segments against the same triangle - Vector3f norm = vCross(ab, ac); - - // Compute denominator d. If d <= 0, segment is parallel to or points - // away from triangle, so exit early - float d = vDot(qp, norm); - if (d <= 0.0f) - { - return null; - } - - // Compute intersection t value of pq with plane of triangle. A ray - // intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay - // dividing by d until intersection has been found to pierce triangle - Vector3f ap = vSub(sp, a); - float t = vDot(ap, norm); - if (t < 0.0f) - { - return null; - } - - if (t > d) - { - return null; // For segment; exclude this code line for a ray test - } - - // Compute barycentric coordinate components and test if within bounds - Vector3f e = vCross(qp, ap); - v = vDot(ac, e); - if (v < 0.0f || v > d) - { - return null; - } - - w = -vDot(ab, e); - if (w < 0.0f || v + w > d) - { - return null; - } - - // Segment/ray intersects triangle. Perform delayed division - t /= d; - - return t; - } - - public static float[] intersectSegmentAABB(Vector3f sp, Vector3f sq, Vector3f amin, Vector3f amax) - { - float EPS = 1e-6f; - - Vector3f d = new Vector3f(); - d[0] = sq[0] - sp[0]; - d[1] = sq[1] - sp[1]; - d[2] = sq[2] - sp[2]; - float tmin = 0.0f; - float tmax = 1.0f; - - for (int i = 0; i < 3; i++) - { - if (Math.Abs(d[i]) < EPS) - { - if (sp[i] < amin[i] || sp[i] > amax[i]) - { - return null; - } - } - else - { - float ood = 1.0f / d[i]; - float t1 = (amin[i] - sp[i]) * ood; - float t2 = (amax[i] - sp[i]) * ood; - if (t1 > t2) - { - float tmp = t1; - t1 = t2; - t2 = tmp; - } - - if (t1 > tmin) - { - tmin = t1; - } - - if (t2 < tmax) - { - tmax = t2; - } - - if (tmin > tmax) - { - return null; - } - } - } - - return new float[] { tmin, tmax }; - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Geom/NavMeshRaycast.cs b/src/DotRecast.Recast.Demo/Geom/NavMeshRaycast.cs deleted file mode 100644 index 4ed609c..0000000 --- a/src/DotRecast.Recast.Demo/Geom/NavMeshRaycast.cs +++ /dev/null @@ -1,97 +0,0 @@ -/* -recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. -*/ - -using DotRecast.Core; -using DotRecast.Detour; - -namespace DotRecast.Recast.Demo.Geom; - -/** - * Simple helper to find an intersection between a ray and a nav mesh - */ -public class NavMeshRaycast -{ - public static float? raycast(NavMesh mesh, Vector3f src, Vector3f dst) - { - for (int t = 0; t < mesh.getMaxTiles(); ++t) - { - MeshTile tile = mesh.getTile(t); - if (tile != null && tile.data != null) - { - float? intersection = raycast(tile, src, dst); - if (null != intersection) - { - return intersection; - } - } - } - - return null; - } - - private static float? raycast(MeshTile tile, Vector3f sp, Vector3f sq) - { - for (int i = 0; i < tile.data.header.polyCount; ++i) - { - Poly p = tile.data.polys[i]; - if (p.getType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION) - { - continue; - } - - PolyDetail pd = tile.data.detailMeshes[i]; - - if (pd != null) - { - Vector3f[] verts = new Vector3f[3]; - for (int j = 0; j < pd.triCount; ++j) - { - int t = (pd.triBase + j) * 4; - for (int k = 0; k < 3; ++k) - { - int v = tile.data.detailTris[t + k]; - if (v < p.vertCount) - { - verts[k][0] = tile.data.verts[p.verts[v] * 3]; - verts[k][1] = tile.data.verts[p.verts[v] * 3 + 1]; - verts[k][2] = tile.data.verts[p.verts[v] * 3 + 2]; - } - else - { - verts[k][0] = tile.data.detailVerts[(pd.vertBase + v - p.vertCount) * 3]; - verts[k][1] = tile.data.detailVerts[(pd.vertBase + v - p.vertCount) * 3 + 1]; - verts[k][2] = tile.data.detailVerts[(pd.vertBase + v - p.vertCount) * 3 + 2]; - } - } - - float? intersection = Intersections.intersectSegmentTriangle(sp, sq, verts[0], verts[1], verts[2]); - if (null != intersection) - { - return intersection; - } - } - } - else - { - // FIXME: Use Poly if PolyDetail is unavailable - } - } - - return null; - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Geom/NavMeshUtils.cs b/src/DotRecast.Recast.Demo/Geom/NavMeshUtils.cs deleted file mode 100644 index 9b2de0c..0000000 --- a/src/DotRecast.Recast.Demo/Geom/NavMeshUtils.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* -recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. -*/ - -using System; -using DotRecast.Core; -using DotRecast.Detour; - -namespace DotRecast.Recast.Demo.Geom; - -public class NavMeshUtils -{ - public static Vector3f[] getNavMeshBounds(NavMesh mesh) - { - Vector3f bmin = Vector3f.Of(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - Vector3f bmax = Vector3f.Of(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); - for (int t = 0; t < mesh.getMaxTiles(); ++t) - { - MeshTile tile = mesh.getTile(t); - if (tile != null && tile.data != null) - { - for (int i = 0; i < tile.data.verts.Length; i += 3) - { - bmin[0] = Math.Min(bmin[0], tile.data.verts[i]); - bmin[1] = Math.Min(bmin[1], tile.data.verts[i + 1]); - bmin[2] = Math.Min(bmin[2], tile.data.verts[i + 2]); - bmax[0] = Math.Max(bmax[0], tile.data.verts[i]); - bmax[1] = Math.Max(bmax[1], tile.data.verts[i + 1]); - bmax[2] = Math.Max(bmax[2], tile.data.verts[i + 2]); - } - } - } - - return new[] { bmin, bmax }; - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Geom/PolyMeshRaycast.cs b/src/DotRecast.Recast.Demo/Geom/PolyMeshRaycast.cs deleted file mode 100644 index 684562d..0000000 --- a/src/DotRecast.Recast.Demo/Geom/PolyMeshRaycast.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* -recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. -*/ - -using System.Collections.Generic; -using DotRecast.Core; - -namespace DotRecast.Recast.Demo.Geom; - -public class PolyMeshRaycast -{ - public static float? raycast(IList results, Vector3f src, Vector3f dst) - { - foreach (RecastBuilderResult result in results) - { - if (result.getMeshDetail() != null) - { - float? intersection = raycast(result.getMesh(), result.getMeshDetail(), src, dst); - if (null != intersection) - { - return intersection; - } - } - } - - return null; - } - - private static float? raycast(PolyMesh poly, PolyMeshDetail meshDetail, Vector3f sp, Vector3f sq) - { - if (meshDetail != null) - { - for (int i = 0; i < meshDetail.nmeshes; ++i) - { - int m = i * 4; - int bverts = meshDetail.meshes[m]; - int btris = meshDetail.meshes[m + 2]; - int ntris = meshDetail.meshes[m + 3]; - int verts = bverts * 3; - int tris = btris * 4; - for (int j = 0; j < ntris; ++j) - { - Vector3f[] vs = new Vector3f[3]; - for (int k = 0; k < 3; ++k) - { - vs[k][0] = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3]; - vs[k][1] = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3 + 1]; - vs[k][2] = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3 + 2]; - } - - float? intersection = Intersections.intersectSegmentTriangle(sp, sq, vs[0], vs[1], vs[2]); - if (null != intersection) - { - return intersection; - } - } - } - } - else - { - // TODO: check PolyMesh instead - } - - return null; - } -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/UI/RcViewSystem.cs b/src/DotRecast.Recast.Demo/UI/RcViewSystem.cs index f0a4eee..4aead3a 100644 --- a/src/DotRecast.Recast.Demo/UI/RcViewSystem.cs +++ b/src/DotRecast.Recast.Demo/UI/RcViewSystem.cs @@ -28,21 +28,13 @@ namespace DotRecast.Recast.Demo.UI; public class RcViewSystem { private static readonly ILogger Logger = Log.ForContext(); - // readonly NkAllocator allocator; - private readonly IWindow _window; - - private readonly GL _gl; - - // readonly NkColor background; - // readonly NkColor white; + private readonly IRcView[] _views; private bool _mouseOverUI; public bool IsMouseOverUI() => _mouseOverUI; public RcViewSystem(IWindow window, IInputContext input, params IRcView[] views) { - _window = window; - _gl = GL.GetApi(window); // setupClipboard(window); // glfwSetCharCallback(window, (w, codepoint) => nk_input_unicode(ctx, codepoint)); // glContext = new NuklearGL(this); diff --git a/src/DotRecast.Recast/PolyMeshRaycast.cs b/src/DotRecast.Recast/PolyMeshRaycast.cs new file mode 100644 index 0000000..fc29961 --- /dev/null +++ b/src/DotRecast.Recast/PolyMeshRaycast.cs @@ -0,0 +1,82 @@ +/* +recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +using System.Collections.Generic; +using DotRecast.Core; + +namespace DotRecast.Recast +{ + + public static class PolyMeshRaycast + { + public static float? raycast(IList results, Vector3f src, Vector3f dst) + { + foreach (RecastBuilderResult result in results) + { + if (result.getMeshDetail() != null) + { + float? intersection = raycast(result.getMesh(), result.getMeshDetail(), src, dst); + if (null != intersection) + { + return intersection; + } + } + } + + return null; + } + + private static float? raycast(PolyMesh poly, PolyMeshDetail meshDetail, Vector3f sp, Vector3f sq) + { + if (meshDetail != null) + { + for (int i = 0; i < meshDetail.nmeshes; ++i) + { + int m = i * 4; + int bverts = meshDetail.meshes[m]; + int btris = meshDetail.meshes[m + 2]; + int ntris = meshDetail.meshes[m + 3]; + int verts = bverts * 3; + int tris = btris * 4; + for (int j = 0; j < ntris; ++j) + { + Vector3f[] vs = new Vector3f[3]; + for (int k = 0; k < 3; ++k) + { + vs[k][0] = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3]; + vs[k][1] = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3 + 1]; + vs[k][2] = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3 + 2]; + } + + float? intersection = Intersections.intersectSegmentTriangle(sp, sq, vs[0], vs[1], vs[2]); + if (null != intersection) + { + return intersection; + } + } + } + } + else + { + // TODO: check PolyMesh instead + } + + return null; + } + } +} \ No newline at end of file