forked from mirror/DotRecast
Compare commits
233 Commits
feature/un
...
master
Author | SHA1 | Date |
---|---|---|
wrenge | 0b888b16fb | |
wrenge | 088edcd655 | |
wrenge | 12e09475f0 | |
wrenge | 7de4b51135 | |
wrenge | 4824f29db7 | |
wrenge | 2cf9d9de18 | |
wrenge | d2082c6586 | |
wrenge | 0876d3adcf | |
wrenge | 1fa0320845 | |
wrenge | 815a83e3cb | |
wrenge | 592ecebe1e | |
wrenge | b2a217d4a3 | |
wrenge | 5c0ba9dba1 | |
wrenge | 38a8029b6e | |
wrenge | 418a39a576 | |
wrenge | 05613f196f | |
wrenge | 4dee6b20b5 | |
wrenge | 49da3fb454 | |
wrenge | 2c6f6a50cc | |
wrenge | dbc92a9aef | |
wrenge | c7c6e53d61 | |
wrenge | 858e094ea0 | |
wrenge | acd3f8d879 | |
wrenge | fff0998613 | |
wrenge | 2397f23fc3 | |
wrenge | b6a1a81fdc | |
wrenge | c989276f5e | |
wrenge | c0b916a0d1 | |
wrenge | 3e754529e5 | |
wrenge | 8642d47738 | |
wrenge | ff930712ee | |
wrenge | 6fe6844efd | |
wrenge | c8104cec4d | |
wrenge | db0717a77e | |
wrenge | 724be6f3b2 | |
wrenge | 0f28fa26ec | |
ikpil | fba594724c | |
Georgiy Sadovnikov | 20a86b5bae | |
ikpil | 193fe6dce5 | |
Семенов Иван | c84fb0b11e | |
ikpil | 43446d4443 | |
Семенов Иван | 4a1b430ee6 | |
Семенов Иван | 53aac60713 | |
ikpil | 4ec36fb8b4 | |
ikpil | 5de6e06a94 | |
ikpil | 1bf2ff48f2 | |
ikpil | ea437ef020 | |
ikpil | ecc02f12e4 | |
ikpil | a225e32a5a | |
ikpil | e9ca704ab7 | |
ikpil | 62f9cfe034 | |
ikpil | 36795dc909 | |
ikpil | 85e2484505 | |
ikpil | 2d0e2f8525 | |
ikpil | e9a05843da | |
ikpil | 5735c98c79 | |
ikpil | f18bedb02d | |
ikpil | 1179f87d02 | |
ikpil | a9e4ca377d | |
ikpil | 1eb65ca856 | |
ikpil | e73ec9acda | |
ikpil | 4a19d597c1 | |
ikpil | 201401b54f | |
ikpil | e6bea60db3 | |
ikpil | 887294af1b | |
Sarofc | 997d3f1a9b | |
ikpil | 13be6d5bd8 | |
ikpil | cd7c668caf | |
ikpil | 153b523ea7 | |
ikpil | 89214accfb | |
ikpil | 8a655528c3 | |
Sarofc | c036501879 | |
Sarofc | 5aeb1e465c | |
Sarofc | ab04256cdf | |
ikpil | 7ffda46c2f | |
ikpil | 8ba8c04895 | |
ikpil | bc7818a1c5 | |
ikpil | a87f34e738 | |
ikpil | cf7aec90ee | |
ikpil | 84419b1d52 | |
ikpil | c562f8f6a1 | |
ikpil | eccce01cff | |
ikpil | 990dbcf97f | |
ikpil | 00950b1210 | |
ikpil | c5820af20b | |
ikpil | afe93d084e | |
ikpil | c1e7b84efa | |
ikpil | fbce7f40f4 | |
ikpil | b34b17e89c | |
ikpil | 31b7eaf9a3 | |
ikpil | 9ebaa3fc65 | |
ikpil | 76e5ade4d1 | |
ikpil | 1894a56889 | |
ikpil | 828b9644cc | |
ikpil | ab2c520076 | |
ikpil | 4743ba68f9 | |
ikpil | fa2ff6f133 | |
ikpil | 355a08e7ef | |
ikpil | a282a80356 | |
ikpil | ba6815769a | |
ikpil | 27751522f9 | |
ikpil | ee48892223 | |
ikpil | d472d71795 | |
ikpil | bdb9463d88 | |
ikpil | 35f5c63d77 | |
ikpil | e5d5867c56 | |
ikpil | 72b7cfd6db | |
ikpil | 267e15fd4c | |
ikpil | 35ef64d9b4 | |
ikpil | 0092761742 | |
ikpil | 5911510544 | |
ikpil | f54b586d75 | |
ikpil | 5827a43dd8 | |
ikpil | 650849b11b | |
ikpil | b88b6096f6 | |
ikpil | 65c572a4c2 | |
ikpil | 3417ecae36 | |
ikpil | 320c7b4c65 | |
ikpil | fd03f0f12f | |
ikpil | ed7173dd51 | |
ikpil | face8eb48e | |
ikpil | 759e335961 | |
ikpil | 8ad34dc0d8 | |
ikpil | ebab0a11f3 | |
ikpil | b18845a749 | |
ikpil | 0f20db44bb | |
ikpil | 099636cd7c | |
ikpil | f8ae77a192 | |
ikpil | 01b7b4add9 | |
ikpil | 2a45ec021c | |
ikpil | d94408f7a1 | |
ikpil | e9a5512bb2 | |
ikpil | 17ecdb1cc7 | |
ikpil | 2acbdf8c53 | |
ikpil | e9c8b3eddf | |
ikpil | 104b5b02b2 | |
ikpil | 34d2ef639a | |
ikpil | e6f515f08a | |
ikpil | 7664ae9f3d | |
ikpil | aeefed7fbb | |
ikpil | 1b4f5af155 | |
ikpil | 2f50768909 | |
ikpil | 886be3712f | |
ikpil | 99224251dc | |
ikpil | 5b6905bd8f | |
ikpil | c7f03d00ff | |
ikpil | 9a03ade6c9 | |
ikpil | 8f8db51542 | |
ikpil | ec9ebe28b9 | |
ikpil | c9a54d4b4e | |
ikpil | 3808c13876 | |
ikpil | 0ce8ffba32 | |
ikpil | 3b5e85eeb6 | |
ikpil | 72d042b1ea | |
ikpil | 7212afaac6 | |
ikpil | 886afd20cd | |
ikpil | c3208f7968 | |
ikpil | 4543df0b90 | |
ikpil | a649081a5b | |
ikpil | 4e7afa64c6 | |
ikpil | 47be4eca70 | |
ikpil | 40306a5302 | |
ikpil | 3f750ba499 | |
ikpil | 61e7b7a443 | |
ikpil | dfbd1b2cae | |
ikpil | 1bf0a88492 | |
ikpil | e926c23195 | |
ikpil | 59849e1dac | |
ikpil | deb02778cc | |
ikpil | cfdcc1336c | |
ikpil | 19e358bdfc | |
ikpil | fc673b2c25 | |
ikpil | 741200b559 | |
ikpil | b165a3afed | |
ikpil | 884789a934 | |
ikpil | 5b9adf73e2 | |
ikpil | 3c43623769 | |
ikpil | 08c8db2d19 | |
ikpil | 4acb0a163a | |
ikpil | a5a101c0c2 | |
ikpil | bef346a8cb | |
ikpil | 9e9a3f0dc2 | |
ikpil | daf552b4b7 | |
ikpil | 1e0ef4f5cc | |
ikpil | a84d66195e | |
ikpil | 29fab9f5b2 | |
ikpil | f81975d97a | |
wrenge | e67dbfa604 | |
wrenge | b09eada4cf | |
wrenge | b8832e50e7 | |
wrenge | 005ab583f7 | |
ikpil | 3ae7582043 | |
ikpil | 15384cacb0 | |
ikpil | 2ef6c0b27c | |
ikpil | adbb265ca2 | |
ikpil | fb49a5bca6 | |
ikpil | 94e66ed318 | |
ikpil | 97777511a7 | |
ikpil | f22ec94038 | |
ikpil | 4a80473e2f | |
ikpil | bf6ee495d2 | |
wrenge | 0ed414f08c | |
wrenge | 897748285f | |
wrenge | 331e35ecbb | |
ikpil | f49f9eb558 | |
ikpil | 6b2bd27b71 | |
wrenge | 3157c1e764 | |
ikpil | 50ea674cce | |
ikpil | 8fe46a6450 | |
ikpil | 80e07ebb3c | |
ikpil | 97ffaf8700 | |
ikpil | 17c1c18372 | |
ikpil | 9210eb58fe | |
ikpil | da82d6ba4d | |
ikpil | 26a1dfddeb | |
ikpil | 668ebd0128 | |
ikpil | 402b25a436 | |
ikpil | 7874b4403c | |
ikpil | 82027dffd7 | |
ikpil | 573386c473 | |
ikpil | daf826f5f4 | |
wreng | b67ebeaec3 | |
Andrew Gilewsky | 7dfac39408 | |
ikpil | 4b8cd8e31b | |
wrenge | 7f1b9e63bb | |
wrenge | d625e83fad | |
wrenge | 838064f3b6 | |
ikpil | 6a57c067ac | |
ikpil | 0c6921ad6b | |
ikpil | b0644a70b7 | |
ikpil | 2f2d68c29f | |
ikpil | 30bce34eaf | |
ikpil | d8ae9f2297 |
|
@ -20,6 +20,7 @@ dotnet_sort_system_directives_first = true
|
|||
csharp_preserve_single_line_statements = false
|
||||
csharp_preserve_single_line_blocks = true
|
||||
|
||||
#
|
||||
# ReSharper properties
|
||||
resharper_csharp_wrap_lines = false
|
||||
resharper_csharp_space_before_trailing_comment = true
|
||||
resharper_csharp_space_after_operator_keyword = true
|
||||
|
|
|
@ -49,7 +49,7 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up .NET 8.0
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.x
|
||||
|
||||
|
|
|
@ -37,9 +37,12 @@ jobs:
|
|||
fetch-depth: 0 # Get all history to allow automatic versioning using MinVer
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: ${{ matrix.dotnet-version }}.x
|
||||
dotnet-version: |
|
||||
6
|
||||
7
|
||||
8
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
fetch-depth: 0 # Get all history to allow automatic versioning using MinVer
|
||||
|
||||
- name: Setup Dotnet
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.x'
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
fetch-depth: 0 # Get all history to allow automatic versioning using MinVer
|
||||
|
||||
- name: Setup Dotnet
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.x'
|
||||
|
||||
|
|
110
CHANGELOG.md
110
CHANGELOG.md
|
@ -6,12 +6,122 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
|
||||
## [Unreleased] - yyyy-mm-dd
|
||||
|
||||
### Added
|
||||
- Added RcBinaryMinHeap ([@Sarofc](https://github.com/Sarofc))
|
||||
- Added DotRecast.Benchmark ([@Sarofc](https://github.com/Sarofc))
|
||||
|
||||
### Fixed
|
||||
- Fix raycast shortcuts ([@Sarofc](https://github.com/Sarofc)) [#72](https://github.com/ikpil/DotRecast/issues/72)
|
||||
- Fix dynamic mesh bounds calculation ([@ppiastucki](https://github.com/ppiastucki)) [#77](https://github.com/ikpil/DotRecast/issues/77)
|
||||
- issuer : [@OhJeongrok](https://github.com/OhJeongrok)
|
||||
- Fix Support non-tiled dynamic nav meshes ([@ppiastucki](https://github.com/ppiastucki))
|
||||
|
||||
### Changed
|
||||
- Changed data structure of 'neis' from List<byte> to byte[] for optimized memory usage and improved access speed in `DtLayerMonotoneRegion`
|
||||
- Changed new RcVec3f[3] to stackalloc RcVec3f[3] in DtNavMesh.GetPolyHeight() to reduce heap allocation
|
||||
- Changed memory handling to use stackalloc in DtNavMeshQuery.GetPolyWallSegments for reducing SOH
|
||||
- Changed DtNavMeshQuery.GetPolyWallSegments() to use Span<T> for enhanced performance, memory efficiency.
|
||||
- Changed bmin/bmax from int[] to RcVec3i for improved memory efficiency
|
||||
|
||||
### Removed
|
||||
- Nothing
|
||||
|
||||
### Special Thanks
|
||||
- [@Doprez](https://github.com/Doprez)
|
||||
|
||||
|
||||
## [2024.3.1] - 2024-07-09
|
||||
|
||||
### Added
|
||||
- Nothing
|
||||
|
||||
### Fixed
|
||||
- Fixed bug where the dynamic voxel save file browser doesn't appear in `Recast.Demo`
|
||||
|
||||
### Changed
|
||||
- Changed to reuse samples and edges list in `BuildPolyDetail()`
|
||||
- Changed `heights`, `areas`, `cons`, and `regs` arrays to byte arrays for uniformity and efficiency in `DtTileCacheLayer`
|
||||
- Changed `reg`, `area` arrays to byte arrays for uniformity and efficiency in `DtTileCacheContour`
|
||||
- Changed `RcChunkyTriMesh` to separate the function and variable.
|
||||
- Changed to consolidate vector-related functions into one place.
|
||||
- Changed stack handling from List to a fixed-size array with manual index management for optimization in `RcLayers.BuildHeightfieldLayers()`
|
||||
- Changed to use Span<byte> and stackalloc for improved performance and memory management in `RcLayers.BuildHeightfieldLayers()`
|
||||
- Changed vertCount and triCount to byte in `DtPolyDetail`
|
||||
- Changed `new float[]` to `stackalloc float[]` in `DtConvexConvexIntersections.Intersect()`
|
||||
- Changed agents management from list to dictionary in `DtCrowd`
|
||||
- Changed to efficiently stack nearby DtCrowdAgents in `DtCrowd.GetNeighbours()`
|
||||
- Changed to limit neighbor search to a maximum count and use array for memory efficiency in `DtCrowd.AddNeighbour()`
|
||||
|
||||
### Removed
|
||||
- Removed RcMeshDetails.VdistSq2(float[], float[])
|
||||
- Removed RcVecUtils.Dot()
|
||||
- Removed RcVecUtils.Scale()
|
||||
- Removed RcVecUtils.Subtract(RcVec3f i, float[] verts, int j)
|
||||
- Removed RcVecUtils.Subtract(float[] verts, int i, int j)
|
||||
- Removed RcVecUtils.Min(), RcVecUtils.Max()
|
||||
- Removed RcVecUtils.Create(float[] values)
|
||||
- Removed RcVecUtils.Dot2D(this RcVec3f @this, Span<float> v, int vi)
|
||||
|
||||
### Special Thanks
|
||||
- [@Doprez](https://github.com/Doprez)
|
||||
|
||||
## [2024.2.3] - 2024-06-03
|
||||
|
||||
### Added
|
||||
- Added `DtCollectPolysQuery` and `FindCollectPolyTest`
|
||||
|
||||
### Fixed
|
||||
- Nothing
|
||||
|
||||
### Changed
|
||||
- Changed `IDtPolyQuery` interface to make `Process()` more versatile
|
||||
- Changed `PolyQueryInvoker` to `DtActionPolyQuery`
|
||||
- Changed `DtTileCacheBuilder` to a static class
|
||||
- Changed `DtTileCacheLayerHeaderReader` to a static class
|
||||
- Changed `Dictionary<int, List<DtMeshTile>>` to `DtMeshTile[]` to optimize memory usage
|
||||
- Changed `MAX_STEER_POINTS` from class constant to local.
|
||||
- Changed `List<DtStraightPath>` to `Span<DtStraightPath>` for enhanced memory efficiency
|
||||
- Changed `DtWriter` to a static class and renamed it to `RcIO`
|
||||
- Changed class `Trajectory` to interface `ITrajectory`
|
||||
|
||||
### Removed
|
||||
- Nothing
|
||||
|
||||
### Special Thanks
|
||||
- [@Doprez](https://github.com/Doprez)
|
||||
|
||||
|
||||
## [2024.2.2] - 2024-05-18
|
||||
|
||||
### Added
|
||||
- Added RcSpans UnitTest
|
||||
|
||||
### Fixed
|
||||
- Nothing
|
||||
|
||||
### Changed
|
||||
- Changed class name of static functions to RcRecast and DtDetour
|
||||
- Changed DtLink class member variable type from int to byte
|
||||
- Changed initialization in DtNavMesh constructor to Init() function.
|
||||
|
||||
### Removed
|
||||
- Nothing
|
||||
|
||||
### Special Thanks
|
||||
- [@Doprez](https://github.com/Doprez)
|
||||
|
||||
|
||||
## [2024.2.1] - 2024-05-04
|
||||
|
||||
### Added
|
||||
- Added RcCircularBuffer<T> [@ikpil](https://github.com/ikpil)
|
||||
- Added struct DtCrowdScopedTimer to avoid allocations in scoped timer calls. [@wrenge](https://github.com/wrenge)
|
||||
- Added struct RcScopedTimer to avoid allocations in RcContext scoped timer [@ikpil](https://github.com/ikpil)
|
||||
- Added RcSpans [@ikpil](https://github.com/ikpil)
|
||||
|
||||
### Fixed
|
||||
- SOH issue [#14](https://github.com/ikpil/DotRecast/issues/41)
|
||||
- Optimization: reduce number of allocations on hot path. [@awgil](https://github.com/awgil)
|
||||
|
||||
### Changed
|
||||
- Changed DtPathCorridor.Init(int maxPath) function to allow setting the maximum path [@ikpil](https://github.com/ikpil)
|
||||
|
|
|
@ -39,6 +39,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotRecast.Detour.Extras.Tes
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotRecast.Detour.TileCache.Test", "test\DotRecast.Detour.TileCache.Test\DotRecast.Detour.TileCache.Test.csproj", "{3CAA7306-088E-4373-A406-99755CC2B605}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotRecast.Benchmark", "test\DotRecast.Benchmark\DotRecast.Benchmark.csproj", "{D1EFC625-D095-4208-98A2-112B73CB40B0}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tool", "tool", "{9C213609-BF13-4024-816E-A6ADD641DF24}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotRecast.Tool.PublishToUniRecast", "tool\DotRecast.Tool.PublishToUniRecast\DotRecast.Tool.PublishToUniRecast.csproj", "{1822BBA8-FE4E-4C5F-B9C0-3E20E6353446}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -112,23 +118,33 @@ Global
|
|||
{10395C8F-DFBD-4263-8A20-EA3500A6E55A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{10395C8F-DFBD-4263-8A20-EA3500A6E55A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{10395C8F-DFBD-4263-8A20-EA3500A6E55A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D1EFC625-D095-4208-98A2-112B73CB40B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D1EFC625-D095-4208-98A2-112B73CB40B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D1EFC625-D095-4208-98A2-112B73CB40B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D1EFC625-D095-4208-98A2-112B73CB40B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1822BBA8-FE4E-4C5F-B9C0-3E20E6353446}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1822BBA8-FE4E-4C5F-B9C0-3E20E6353446}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1822BBA8-FE4E-4C5F-B9C0-3E20E6353446}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1822BBA8-FE4E-4C5F-B9C0-3E20E6353446}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{FFE40BBF-843B-41FA-8504-F4ABD166762E} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
|
||||
{38933A87-4568-40A5-A3DA-E2445E8C2B99} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
|
||||
{C19E4BFA-63A0-4815-9815-869A9DC52DBC} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
|
||||
{88754FE2-A05A-4D4D-A81A-90418AD32362} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{554CB5BD-D58A-4856-BFE1-666A62C9BEA3} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{FA7EF26A-BA47-43FD-86F8-0A33CFDF643F} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
|
||||
{F9C5B52E-C01D-4514-94E9-B1A6895352E2} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{53AF87DA-37F8-4504-B623-B2113F4438CA} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
|
||||
{67C68B34-118A-439C-88E1-D6D1ED78DC59} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{17E4F2F0-FC27-416E-9CB6-9F2CAAC49C9D} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
|
||||
{7BAA69B2-EDC7-4603-B16F-BC7B24353F81} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{DEB16B90-CCD4-497E-A2E9-4CC66FD7EF47} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
|
||||
{3CAA7306-088E-4373-A406-99755CC2B605} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{023E1E6A-4895-4573-89AE-3D5D8E0B39C8} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
|
||||
{DF987948-8C23-4337-AF83-D87D6407518D} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
|
||||
{88754FE2-A05A-4D4D-A81A-90418AD32362} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{554CB5BD-D58A-4856-BFE1-666A62C9BEA3} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{F9C5B52E-C01D-4514-94E9-B1A6895352E2} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{67C68B34-118A-439C-88E1-D6D1ED78DC59} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{7BAA69B2-EDC7-4603-B16F-BC7B24353F81} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{3CAA7306-088E-4373-A406-99755CC2B605} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{10395C8F-DFBD-4263-8A20-EA3500A6E55A} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{D1EFC625-D095-4208-98A2-112B73CB40B0} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
|
||||
{1822BBA8-FE4E-4C5F-B9C0-3E20E6353446} = {9C213609-BF13-4024-816E-A6ADD641DF24}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
38
README.md
38
README.md
|
@ -1,28 +1,22 @@
|
|||
<h1 align="center">DotRecast</h1>
|
||||
<p align="center">
|
||||
<i>DotRecast is C# Recast & Detour, a port of <a href="https://github.com/recastnavigation/recastnavigation">recastnavigation</a> and <a href="https://github.com/ppiastucki/recast4j">recast4j</a> to the C# language.</i>
|
||||
</p>
|
||||
<p align="center">
|
||||
<i>If you'd like to support the project, we'd appreciate starring(⭐) our repos on Github for more visibility.</i>
|
||||
</p>
|
||||
# DotRecast
|
||||
|
||||
*DotRecast is C# Recast & Detour, a port of [recastnavigation](https://github.com/recastnavigation/recastnavigation) and [recast4j](https://github.com/ppiastucki/recast4j) to the C# language.*
|
||||
*If you'd like to support the project, we'd appreciate starring(⭐) our repos on Github for more visibility.*
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
<img alt="![GitHub License]" src="https://img.shields.io/github/license/ikpil/DotRecast?style=for-the-badge">
|
||||
<img alt="Languages" src="https://img.shields.io/github/languages/top/ikpil/DotRecast?style=for-the-badge">
|
||||
<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/ikpil/DotRecast?style=for-the-badge">
|
||||
<a href="https://github.com/ikpil/DotRecast"><img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ikpil/DotRecast?style=for-the-badge&logo=github"></a>
|
||||
<a href="https://github.com/ikpil/DotRecast/actions/workflows/dotnet.yml"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/ikpil/DotRecast/dotnet.yml?style=for-the-badge&logo=github"></a>
|
||||
<a href="https://github.com/ikpil/DotRecast/actions/workflows/codeql.yml"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/ikpil/DotRecast/codeql.yml?style=for-the-badge&logo=github&label=CODEQL"></a>
|
||||
<a href="https://github.com/ikpil/DotRecast/commits"><img alt="GitHub commit activity" src="https://img.shields.io/github/commit-activity/m/ikpil/DotRecast?style=for-the-badge&logo=github"></a>
|
||||
<a href="https://github.com/ikpil/DotRecast/issues"><img alt="GitHub issues" src="https://img.shields.io/github/issues-raw/ikpil/DotRecast?style=for-the-badge&logo=github&color=44cc11"></a>
|
||||
<a href="https://github.com/ikpil/DotRecast/issues"><img alt="GitHub closed issues" src="https://img.shields.io/github/issues-closed-raw/ikpil/DotRecast?style=for-the-badge&logo=github&color=a371f7"></a>
|
||||
<a href="https://www.nuget.org/packages/DotRecast.Core"><img alt="NuGet Version" src="https://img.shields.io/nuget/vpre/DotRecast.Core?style=for-the-badge&logo=nuget"></a>
|
||||
<a href="https://www.nuget.org/packages/DotRecast.Core"><img alt="NuGet Downloads" src="https://img.shields.io/nuget/dt/DotRecast.Core?style=for-the-badge&logo=nuget"></a>
|
||||
<a href="https://visitorbadge.io/status?path=ikpil%2FDotRecast"><img alt="Visitors" src="https://api.visitorbadge.io/api/daily?path=ikpil%2FDotRecast&countColor=%23263759"></a>
|
||||
<a href="https://github.com/sponsors/ikpil"><img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/ikpil?style=for-the-badge&logo=GitHub-Sponsors&link=https%3A%2F%2Fgithub.com%2Fsponsors%2Fikpil"></a>
|
||||
</p>
|
||||
![GitHub License](https://img.shields.io/github/license/ikpil/DotRecast?style=for-the-badge)
|
||||
![Languages](https://img.shields.io/github/languages/top/ikpil/DotRecast?style=for-the-badge)
|
||||
![GitHub repo size](https://img.shields.io/github/repo-size/ikpil/DotRecast?style=for-the-badge)
|
||||
[![GitHub Repo stars](https://img.shields.io/github/stars/ikpil/DotRecast?style=for-the-badge&logo=github)](https://github.com/ikpil/DotRecast)
|
||||
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/ikpil/DotRecast/dotnet.yml?style=for-the-badge&logo=github)](https://github.com/ikpil/DotRecast/actions/workflows/dotnet.yml)
|
||||
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/ikpil/DotRecast/codeql.yml?style=for-the-badge&logo=github&label=CODEQL)](https://github.com/ikpil/DotRecast/actions/workflows/codeql.yml)
|
||||
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/ikpil/DotRecast?style=for-the-badge&logo=github)](https://github.com/ikpil/DotRecast/commits)
|
||||
[![GitHub issues](https://img.shields.io/github/issues-raw/ikpil/DotRecast?style=for-the-badge&logo=github&color=44cc11)](https://github.com/ikpil/DotRecast/issues)
|
||||
[![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/ikpil/DotRecast?style=for-the-badge&logo=github&color=a371f7)](https://github.com/ikpil/DotRecast/issues)
|
||||
[![NuGet Version](https://img.shields.io/nuget/vpre/DotRecast.Core?style=for-the-badge&logo=nuget)](https://www.nuget.org/packages/DotRecast.Core)
|
||||
[![NuGet Downloads](https://img.shields.io/nuget/dt/DotRecast.Core?style=for-the-badge&logo=nuget)](https://www.nuget.org/packages/DotRecast.Core)
|
||||
[![GitHub Sponsors](https://img.shields.io/github/sponsors/ikpil?style=for-the-badge&logo=GitHub-Sponsors&link=https%3A%2F%2Fgithub.com%2Fsponsors%2Fikpil)](https://github.com/sponsors/ikpil)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "rnd/dotrecastnetsim",
|
||||
"description": "DotRecast",
|
||||
"homepage": "https://git.bit5.ru/rnd/DotRecastNetSim.git",
|
||||
"require": {
|
||||
"php": ">=7.4"
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Security;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Core.Buffers
|
||||
{
|
||||
// This implementation is thread unsafe
|
||||
public class RcObjectPool<T> where T : class
|
||||
{
|
||||
private readonly Queue<T> _items = new Queue<T>();
|
||||
private readonly Func<T> _createFunc;
|
||||
|
||||
public RcObjectPool(Func<T> createFunc)
|
||||
{
|
||||
_createFunc = createFunc;
|
||||
}
|
||||
|
||||
public T Get()
|
||||
{
|
||||
if (_items.TryDequeue(out var result))
|
||||
return result;
|
||||
|
||||
return _createFunc();
|
||||
}
|
||||
|
||||
public void Return(T obj)
|
||||
{
|
||||
_items.Enqueue(obj);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ namespace DotRecast.Core.Buffers
|
|||
}
|
||||
}
|
||||
|
||||
public class RcRentedArray<T> : IDisposable
|
||||
public struct RcRentedArray<T> : IDisposable
|
||||
{
|
||||
private ArrayPool<T> _owner;
|
||||
private T[] _array;
|
||||
|
@ -43,6 +43,11 @@ namespace DotRecast.Core.Buffers
|
|||
return _array;
|
||||
}
|
||||
|
||||
public Span<T> AsSpan()
|
||||
{
|
||||
return new Span<T>(_array, 0, Length);
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
@ -45,5 +45,11 @@ namespace DotRecast.Core.Collections
|
|||
(list[k], list[n]) = (list[n], list[k]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddRange<T>(this IList<T> list, Span<T> span)
|
||||
{
|
||||
foreach (var i in span)
|
||||
list.Add(i);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
{
|
||||
public sealed class RcBinaryMinHeap<T>
|
||||
{
|
||||
private readonly List<T> _items;
|
||||
private readonly Comparison<T> _comparision;
|
||||
|
||||
public int Count => _items.Count;
|
||||
public int Capacity => _items.Capacity;
|
||||
|
||||
public RcBinaryMinHeap(Comparison<T> comparision)
|
||||
{
|
||||
_items = new List<T>();
|
||||
_comparision = comparision;
|
||||
}
|
||||
|
||||
public RcBinaryMinHeap(int capacity, Comparison<T> comparison) : this(comparison)
|
||||
{
|
||||
if (capacity <= 0)
|
||||
throw new ArgumentException("capacity must greater than zero");
|
||||
|
||||
_items = new List<T>(capacity);
|
||||
_comparision = comparison;
|
||||
}
|
||||
|
||||
public void Push(T val)
|
||||
{
|
||||
_items.Add(val);
|
||||
SiftUp(_items.Count - 1);
|
||||
}
|
||||
|
||||
public T Pop()
|
||||
{
|
||||
var min = Peek();
|
||||
RemoveMin();
|
||||
return min;
|
||||
}
|
||||
|
||||
private void RemoveMin()
|
||||
{
|
||||
if (_items.Count == 0)
|
||||
{
|
||||
Throw();
|
||||
static void Throw() => throw new InvalidOperationException("no element to pop");
|
||||
}
|
||||
|
||||
int last = _items.Count - 1;
|
||||
Swap(0, last);
|
||||
_items.RemoveAt(last);
|
||||
|
||||
MinHeapify(0, last - 1);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T Top()
|
||||
{
|
||||
return _items[0];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T Peek()
|
||||
{
|
||||
if (IsEmpty())
|
||||
{
|
||||
throw new Exception("Heap is empty.");
|
||||
}
|
||||
|
||||
return _items[0];
|
||||
}
|
||||
|
||||
|
||||
public bool Modify(T node)
|
||||
{
|
||||
for (int i = 0; i < _items.Count; i++)
|
||||
{
|
||||
if (_items[i].Equals(node))
|
||||
{
|
||||
SiftUp(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Clear()
|
||||
{
|
||||
_items.Clear();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return 0 == _items.Count;
|
||||
}
|
||||
|
||||
private void SiftUp(int nodeIndex)
|
||||
{
|
||||
int parent = (nodeIndex - 1) / 2;
|
||||
while (_comparision.Invoke(_items[nodeIndex], _items[parent]) < 0)
|
||||
{
|
||||
Swap(parent, nodeIndex);
|
||||
nodeIndex = parent;
|
||||
parent = (nodeIndex - 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void MinHeapify(int nodeIndex, int lastIndex)
|
||||
{
|
||||
int left = (nodeIndex * 2) + 1;
|
||||
int right = left + 1;
|
||||
int smallest = nodeIndex;
|
||||
|
||||
if (left <= lastIndex && _comparision.Invoke(_items[left], _items[nodeIndex]) < 0)
|
||||
smallest = left;
|
||||
|
||||
if (right <= lastIndex && _comparision.Invoke(_items[right], _items[smallest]) < 0)
|
||||
smallest = right;
|
||||
|
||||
if (smallest == nodeIndex)
|
||||
return;
|
||||
|
||||
Swap(nodeIndex, smallest);
|
||||
MinHeapify(smallest, lastIndex);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void Swap(int x, int y)
|
||||
{
|
||||
if (x == y)
|
||||
return;
|
||||
|
||||
(_items[y], _items[x]) = (_items[x], _items[y]);
|
||||
}
|
||||
|
||||
|
||||
public T[] ToArray()
|
||||
{
|
||||
return _items.ToArray();
|
||||
}
|
||||
|
||||
public List<T> ToList()
|
||||
{
|
||||
return new List<T>(_items);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Core.Collections
|
||||
namespace DotRecast.Core.Collections
|
||||
{
|
||||
public readonly partial struct RcImmutableArray<T>
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -27,12 +27,12 @@ namespace DotRecast.Core.Collections
|
|||
{
|
||||
private bool _dirty;
|
||||
private readonly List<T> _items;
|
||||
private readonly Comparer<T> _comparer;
|
||||
private readonly Comparison<T> _comparison;
|
||||
|
||||
public RcSortedQueue(Comparison<T> comp)
|
||||
{
|
||||
_items = new List<T>();
|
||||
_comparer = Comparer<T>.Create((x, y) => comp.Invoke(x, y) * -1);
|
||||
_comparison = (x, y) => comp(x, y) * -1;
|
||||
}
|
||||
|
||||
public int Count()
|
||||
|
@ -55,7 +55,7 @@ namespace DotRecast.Core.Collections
|
|||
{
|
||||
if (_dirty)
|
||||
{
|
||||
_items.Sort(_comparer); // reverse
|
||||
_items.Sort(_comparison); // reverse
|
||||
_dirty = false;
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ namespace DotRecast.Core.Collections
|
|||
return false;
|
||||
|
||||
//int idx = _items.BinarySearch(item, _comparer); // don't use this! Because reference types can be reused externally.
|
||||
int idx = _items.FindLastIndex(x => item.Equals(x));
|
||||
int idx = _items.LastIndexOf(item);
|
||||
if (0 > idx)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Collections
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
namespace DotRecast.Core
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
public interface IRcRand
|
||||
{
|
||||
float Next();
|
||||
double NextDouble();
|
||||
int NextInt32();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Numerics
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core.Numerics
|
||||
{
|
||||
public static class RcVecUtils
|
||||
public static class RcVec
|
||||
{
|
||||
public const float EPSILON = 1e-6f;
|
||||
public static readonly float EQUAL_THRESHOLD = RcMath.Sqr(1.0f / 16384.0f);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RcVec3f Create(float[] values)
|
||||
{
|
||||
return Create(values, 0);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RcVec3f Create(float[] values, int n)
|
||||
public static RcVec3f Create(Span<float> values, int n)
|
||||
{
|
||||
return new RcVec3f(values[n + 0], values[n + 1], values[n + 2]);
|
||||
}
|
||||
|
@ -42,10 +37,73 @@ namespace DotRecast.Core.Numerics
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RcVec3f Scale(this RcVec3f v, float scale)
|
||||
/// Performs a 'sloppy' colocation check of the specified points.
|
||||
/// @param[in] p0 A point. [(x, y, z)]
|
||||
/// @param[in] p1 A point. [(x, y, z)]
|
||||
/// @return True if the points are considered to be at the same location.
|
||||
///
|
||||
/// Basically, this function will return true if the specified points are
|
||||
/// close enough to eachother to be considered colocated.
|
||||
public static bool Equal(RcVec3f p0, RcVec3f p1)
|
||||
{
|
||||
return v * scale;
|
||||
float d = RcVec3f.DistanceSquared(p0, p1);
|
||||
return d < EQUAL_THRESHOLD;
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Dot2(RcVec3f a, RcVec3f b)
|
||||
{
|
||||
return a.X * b.X + a.Z * b.Z;
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float DistSq2(float[] verts, int p, int q)
|
||||
{
|
||||
float dx = verts[q + 0] - verts[p + 0];
|
||||
float dy = verts[q + 2] - verts[p + 2];
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Dist2(float[] verts, int p, int q)
|
||||
{
|
||||
return MathF.Sqrt(DistSq2(verts, p, q));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float DistSq2(RcVec3f p, RcVec3f q)
|
||||
{
|
||||
float dx = q.X - p.X;
|
||||
float dy = q.Z - p.Z;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Dist2(RcVec3f p, RcVec3f q)
|
||||
{
|
||||
return MathF.Sqrt(DistSq2(p, q));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Cross2(float[] verts, int p1, int p2, int p3)
|
||||
{
|
||||
float u1 = verts[p2 + 0] - verts[p1 + 0];
|
||||
float v1 = verts[p2 + 2] - verts[p1 + 2];
|
||||
float u2 = verts[p3 + 0] - verts[p1 + 0];
|
||||
float v2 = verts[p3 + 2] - verts[p1 + 2];
|
||||
return u1 * v2 - v1 * u2;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Cross2(RcVec3f p1, RcVec3f p2, RcVec3f p3)
|
||||
{
|
||||
float u1 = p2.X - p1.X;
|
||||
float v1 = p2.Z - p1.Z;
|
||||
float u2 = p3.X - p1.X;
|
||||
float v2 = p3.Z - p1.Z;
|
||||
return u1 * v2 - v1 * u2;
|
||||
}
|
||||
|
||||
/// Derives the dot product of two vectors on the xz-plane. (@p u . @p v)
|
||||
|
@ -62,46 +120,6 @@ namespace DotRecast.Core.Numerics
|
|||
@this.Z * v.Z;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Dot2D(this RcVec3f @this, float[] v, int vi)
|
||||
{
|
||||
return @this.X * v[vi] +
|
||||
@this.Z * v[vi + 2];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RcVec3f Add(RcVec3f a, float[] verts, int i)
|
||||
{
|
||||
return new RcVec3f(
|
||||
a.X + verts[i],
|
||||
a.Y + verts[i + 1],
|
||||
a.Z + verts[i + 2]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RcVec3f Subtract(float[] verts, int i, int j)
|
||||
{
|
||||
return new RcVec3f(
|
||||
verts[i] - verts[j],
|
||||
verts[i + 1] - verts[j + 1],
|
||||
verts[i + 2] - verts[j + 2]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RcVec3f Subtract(RcVec3f i, float[] verts, int j)
|
||||
{
|
||||
return new RcVec3f(
|
||||
i.X - verts[j],
|
||||
i.Y - verts[j + 1],
|
||||
i.Z - verts[j + 2]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Cross(float[] dest, float[] v1, float[] v2)
|
||||
{
|
||||
|
@ -119,19 +137,11 @@ namespace DotRecast.Core.Numerics
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Dot(float[] v1, float[] v2)
|
||||
public static void Copy(Span<float> @out, int n, Span<float> @in, int m)
|
||||
{
|
||||
return v1[0] * v2[0] +
|
||||
v1[1] * v2[1] +
|
||||
v1[2] * v2[2];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Dot(float[] v1, RcVec3f vector2)
|
||||
{
|
||||
return v1[0] * vector2.X +
|
||||
v1[1] * vector2.Y +
|
||||
v1[2] * vector2.Z;
|
||||
@out[n + 0] = @in[m + 0];
|
||||
@out[n + 1] = @in[m + 1];
|
||||
@out[n + 2] = @in[m + 2];
|
||||
}
|
||||
|
||||
/// Returns the distance between two points.
|
||||
|
@ -167,26 +177,6 @@ namespace DotRecast.Core.Numerics
|
|||
return v;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RcVec3f Min(RcVec3f v, float[] @in, int i)
|
||||
{
|
||||
return new RcVec3f(
|
||||
(v.X < @in[i + 0]) ? v.X : @in[i + 0],
|
||||
(v.Y < @in[i + 1]) ? v.Y : @in[i + 1],
|
||||
(v.Z < @in[i + 2]) ? v.Z : @in[i + 2]
|
||||
);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RcVec3f Max(RcVec3f v, float[] @in, int i)
|
||||
{
|
||||
return new RcVec3f(
|
||||
(v.X > @in[i + 0]) ? v.X : @in[i + 0],
|
||||
(v.Y > @in[i + 1]) ? v.Y : @in[i + 1],
|
||||
(v.Z > @in[i + 2]) ? v.Z : @in[i + 2]
|
||||
);
|
||||
}
|
||||
|
||||
/// Derives the distance between the specified points on the xz-plane.
|
||||
/// @param[in] v1 A point. [(x, y, z)]
|
||||
/// @param[in] v2 A point. [(x, y, z)]
|
||||
|
@ -202,6 +192,10 @@ namespace DotRecast.Core.Numerics
|
|||
return (float)MathF.Sqrt(dx * dx + dz * dz);
|
||||
}
|
||||
|
||||
/// Derives the square of the distance between the specified points on the xz-plane.
|
||||
/// @param[in] v1 A point. [(x, y, z)]
|
||||
/// @param[in] v2 A point. [(x, y, z)]
|
||||
/// @return The square of the distance between the point on the xz-plane.
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Dist2DSqr(RcVec3f v1, RcVec3f v2)
|
||||
{
|
||||
|
@ -211,7 +205,7 @@ namespace DotRecast.Core.Numerics
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Dist2DSqr(RcVec3f p, float[] verts, int i)
|
||||
public static float Dist2DSqr(RcVec3f p, Span<float> verts, int i)
|
||||
{
|
||||
float dx = verts[i] - p.X;
|
||||
float dz = verts[i + 2] - p.Z;
|
||||
|
@ -262,7 +256,7 @@ namespace DotRecast.Core.Numerics
|
|||
/// @param[in] v2 The destination vector.
|
||||
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static RcVec3f Lerp(float[] verts, int v1, int v2, float t)
|
||||
public static RcVec3f Lerp(Span<float> verts, int v1, int v2, float t)
|
||||
{
|
||||
return new RcVec3f(
|
||||
verts[v1 + 0] + (verts[v2 + 0] - verts[v1 + 0]) * t,
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -49,6 +50,19 @@ namespace DotRecast.Core.Numerics
|
|||
Z = f;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public RcVec3f(ReadOnlySpan<float> values)
|
||||
{
|
||||
if (values.Length < 3)
|
||||
{
|
||||
RcThrowHelper.ThrowArgumentOutOfRangeException(nameof(values));
|
||||
}
|
||||
|
||||
X = values[0];
|
||||
Y = values[1];
|
||||
Z = values[2];
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly float Length()
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
namespace DotRecast.Core.Numerics
|
||||
{
|
||||
public struct RcVec3i
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
public int Z;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Threading;
|
||||
using System.Threading;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Threading;
|
||||
using System.Threading;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Threading;
|
||||
using System.Threading;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace DotRecast.Core
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Core
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
public enum RcByteOrder
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace DotRecast.Core
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Core
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
public class RcEdge
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace DotRecast.Core
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
Recast4J Copyright (c) 2015 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 System.IO;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
public static class RcIO
|
||||
{
|
||||
public static RcByteBuffer ToByteBuffer(BinaryReader br, bool direct)
|
||||
{
|
||||
byte[] data = ToByteArray(br);
|
||||
if (direct)
|
||||
{
|
||||
Array.Reverse(data);
|
||||
}
|
||||
|
||||
return new RcByteBuffer(data);
|
||||
}
|
||||
|
||||
public static byte[] ToByteArray(BinaryReader br)
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
Span<byte> buffer = stackalloc byte[4096];
|
||||
int l;
|
||||
while ((l = br.Read(buffer)) > 0)
|
||||
{
|
||||
ms.Write(buffer.Slice(0, l));
|
||||
}
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
|
||||
public static RcByteBuffer ToByteBuffer(BinaryReader br)
|
||||
{
|
||||
var bytes = ToByteArray(br);
|
||||
return new RcByteBuffer(bytes);
|
||||
}
|
||||
|
||||
public static int SwapEndianness(int i)
|
||||
{
|
||||
var s = (((uint)i >> 24) & 0xFF) | (((uint)i >> 8) & 0xFF00) | (((uint)i << 8) & 0xFF0000) | ((i << 24) & 0xFF000000);
|
||||
return (int)s;
|
||||
}
|
||||
|
||||
public static byte[] ReadFileIfFound(string filename)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
return null;
|
||||
|
||||
string filePath = filename;
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
var searchFilePath = RcDirectory.SearchFile($"{filename}");
|
||||
if (!File.Exists(searchFilePath))
|
||||
{
|
||||
searchFilePath = RcDirectory.SearchFile($"resources/{filename}");
|
||||
}
|
||||
|
||||
if (File.Exists(searchFilePath))
|
||||
{
|
||||
filePath = searchFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
byte[] buffer = new byte[fs.Length];
|
||||
var read = fs.Read(buffer, 0, buffer.Length);
|
||||
if (read != buffer.Length)
|
||||
return null;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static void Write(BinaryWriter ws, float value, RcByteOrder order)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
int i = BitConverter.ToInt32(bytes, 0);
|
||||
Write(ws, i, order);
|
||||
}
|
||||
|
||||
public static void Write(BinaryWriter ws, short value, RcByteOrder order)
|
||||
{
|
||||
if (order == RcByteOrder.BIG_ENDIAN)
|
||||
{
|
||||
ws.Write((byte)((value >> 8) & 0xFF));
|
||||
ws.Write((byte)(value & 0xFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
ws.Write((byte)(value & 0xFF));
|
||||
ws.Write((byte)((value >> 8) & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(BinaryWriter ws, long value, RcByteOrder order)
|
||||
{
|
||||
if (order == RcByteOrder.BIG_ENDIAN)
|
||||
{
|
||||
Write(ws, (int)((ulong)value >> 32), order);
|
||||
Write(ws, (int)(value & 0xFFFFFFFF), order);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write(ws, (int)(value & 0xFFFFFFFF), order);
|
||||
Write(ws, (int)((ulong)value >> 32), order);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(BinaryWriter ws, int value, RcByteOrder order)
|
||||
{
|
||||
if (order == RcByteOrder.BIG_ENDIAN)
|
||||
{
|
||||
ws.Write((byte)((value >> 24) & 0xFF));
|
||||
ws.Write((byte)((value >> 16) & 0xFF));
|
||||
ws.Write((byte)((value >> 8) & 0xFF));
|
||||
ws.Write((byte)(value & 0xFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
ws.Write((byte)(value & 0xFF));
|
||||
ws.Write((byte)((value >> 8) & 0xFF));
|
||||
ws.Write((byte)((value >> 16) & 0xFF));
|
||||
ws.Write((byte)((value >> 24) & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(BinaryWriter ws, bool value)
|
||||
{
|
||||
Write(ws, (byte)(value ? 1 : 0));
|
||||
}
|
||||
|
||||
public static void Write(BinaryWriter ws, byte value)
|
||||
{
|
||||
ws.Write(value);
|
||||
}
|
||||
|
||||
public static void Write(BinaryWriter ws, MemoryStream ms)
|
||||
{
|
||||
ms.Position = 0;
|
||||
byte[] buffer = new byte[ms.Length];
|
||||
ms.Read(buffer, 0, buffer.Length);
|
||||
ws.Write(buffer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -29,5 +29,11 @@ namespace DotRecast.Core
|
|||
{
|
||||
return f * f;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Lerp(float value1, float value2, float amount)
|
||||
{
|
||||
return (value1 * (1.0f - amount)) + (value2 * amount);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
|
@ -6,9 +6,13 @@ namespace DotRecast.Core
|
|||
{
|
||||
private readonly Random _r;
|
||||
|
||||
public RcRand()
|
||||
public RcRand() : this(new Random())
|
||||
{
|
||||
_r = new Random();
|
||||
}
|
||||
|
||||
public RcRand(Random r)
|
||||
{
|
||||
_r = r;
|
||||
}
|
||||
|
||||
public RcRand(long seed)
|
||||
|
@ -21,6 +25,11 @@ namespace DotRecast.Core
|
|||
return (float)_r.NextDouble();
|
||||
}
|
||||
|
||||
public double NextDouble()
|
||||
{
|
||||
return _r.NextDouble();
|
||||
}
|
||||
|
||||
public int NextInt32()
|
||||
{
|
||||
return _r.Next();
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
using System.IO;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
public static class RcResources
|
||||
{
|
||||
public static byte[] Load(string filename)
|
||||
{
|
||||
var filepath = filename;
|
||||
if (!File.Exists(filepath))
|
||||
{
|
||||
filepath = RcDirectory.SearchFile($"resources/{filename}");
|
||||
}
|
||||
|
||||
using var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
byte[] buffer = new byte[fs.Length];
|
||||
fs.Read(buffer, 0, buffer.Length);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
public static class RcSpans
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Copy<T>(Span<T> src, Span<T> dst)
|
||||
{
|
||||
src.CopyTo(dst);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Copy<T>(Span<T> src, int srcIdx, Span<T> dst, int dstIdx, int length)
|
||||
{
|
||||
var slicedSrc = src.Slice(srcIdx, length);
|
||||
var slicedDst = dst.Slice(dstIdx);
|
||||
slicedSrc.CopyTo(slicedDst);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Move<T>(Span<T> src, int srcIdx, int dstIdx, int length)
|
||||
{
|
||||
var slicedSrc = src.Slice(srcIdx, length);
|
||||
var slicedDst = src.Slice(dstIdx, length);
|
||||
slicedSrc.CopyTo(slicedDst);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Fill<T>(Span<T> span, T value, int start, int count)
|
||||
{
|
||||
span.Slice(start, count).Fill(value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using DotRecast.Core.Collections;
|
||||
|
||||
|
@ -15,6 +15,12 @@ namespace DotRecast.Core
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ThrowArgumentOutOfRangeException(string argument)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(argument);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void StackOverflow()
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Core
|
||||
namespace DotRecast.Core
|
||||
{
|
||||
/// Recast performance timer categories.
|
||||
/// @see rcContext
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -20,8 +20,9 @@ freely, subject to the following restrictions:
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Buffers;
|
||||
using DotRecast.Core.Collections;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
|
@ -120,15 +121,16 @@ namespace DotRecast.Detour.Crowd
|
|||
/// @ingroup crowd
|
||||
public class DtCrowd
|
||||
{
|
||||
private readonly RcAtomicInteger _agentId = new RcAtomicInteger();
|
||||
private readonly List<DtCrowdAgent> _agents;
|
||||
private readonly RcAtomicInteger _agentIdx;
|
||||
private readonly Dictionary<int, DtCrowdAgent> _agents;
|
||||
private readonly List<DtCrowdAgent> _activeAgents;
|
||||
|
||||
private readonly DtPathQueue _pathQ;
|
||||
|
||||
private readonly DtObstacleAvoidanceParams[] _obstacleQueryParams;
|
||||
private readonly DtObstacleAvoidanceQuery _obstacleQuery;
|
||||
|
||||
private DtProximityGrid _grid;
|
||||
private readonly DtProximityGrid _grid;
|
||||
|
||||
private int _maxPathResult;
|
||||
private readonly RcVec3f _agentPlacementHalfExtents;
|
||||
|
@ -170,7 +172,10 @@ namespace DotRecast.Detour.Crowd
|
|||
// Allocate temp buffer for merging paths.
|
||||
_maxPathResult = DtCrowdConst.MAX_PATH_RESULT;
|
||||
_pathQ = new DtPathQueue(config);
|
||||
_agents = new List<DtCrowdAgent>();
|
||||
_agentIdx = new RcAtomicInteger(0);
|
||||
_agents = new Dictionary<int, DtCrowdAgent>();
|
||||
_activeAgents = new List<DtCrowdAgent>();
|
||||
_grid = new DtProximityGrid(_config.maxAgentRadius * 3);
|
||||
|
||||
// The navQuery is mostly used for local searches, no need for large node pool.
|
||||
SetNavMesh(nav);
|
||||
|
@ -235,11 +240,10 @@ namespace DotRecast.Detour.Crowd
|
|||
/// @return The index of the agent in the agent pool. Or -1 if the agent could not be added.
|
||||
public DtCrowdAgent AddAgent(RcVec3f pos, DtCrowdAgentParams option)
|
||||
{
|
||||
int idx = _agentId.GetAndIncrement();
|
||||
int idx = _agentIdx.GetAndIncrement();
|
||||
DtCrowdAgent ag = new DtCrowdAgent(idx);
|
||||
ag.corridor.Init(_maxPathResult);
|
||||
_agents.Add(ag);
|
||||
|
||||
AddAgent(ag);
|
||||
UpdateAgentParameters(ag, option);
|
||||
|
||||
// Find nearest position on navmesh and place the agent there.
|
||||
|
@ -256,6 +260,7 @@ namespace DotRecast.Detour.Crowd
|
|||
|
||||
ag.topologyOptTime = 0;
|
||||
ag.targetReplanTime = 0;
|
||||
ag.nneis = 0;
|
||||
|
||||
ag.dvel = RcVec3f.Zero;
|
||||
ag.nvel = RcVec3f.Zero;
|
||||
|
@ -278,15 +283,27 @@ namespace DotRecast.Detour.Crowd
|
|||
return ag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the agent from the crowd.
|
||||
*
|
||||
* @param agent
|
||||
* Agent to be removed
|
||||
*/
|
||||
public DtCrowdAgent GetAgent(int idx)
|
||||
{
|
||||
return _agents.GetValueOrDefault(idx);
|
||||
}
|
||||
|
||||
// Add the agent from the crowd.
|
||||
public void AddAgent(DtCrowdAgent agent)
|
||||
{
|
||||
if (_agents.TryAdd(agent.idx, agent))
|
||||
{
|
||||
_activeAgents.Add(agent);
|
||||
}
|
||||
}
|
||||
|
||||
// Removes the agent from the crowd.
|
||||
public void RemoveAgent(DtCrowdAgent agent)
|
||||
{
|
||||
_agents.Remove(agent);
|
||||
if (_agents.Remove(agent.idx))
|
||||
{
|
||||
_activeAgents.Remove(agent);
|
||||
}
|
||||
}
|
||||
|
||||
private bool RequestMoveTargetReplan(DtCrowdAgent ag, long refs, RcVec3f pos)
|
||||
|
@ -358,7 +375,7 @@ namespace DotRecast.Detour.Crowd
|
|||
*/
|
||||
public IList<DtCrowdAgent> GetActiveAgents()
|
||||
{
|
||||
return _agents;
|
||||
return _activeAgents;
|
||||
}
|
||||
|
||||
public RcVec3f GetQueryExtents()
|
||||
|
@ -549,14 +566,18 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
}
|
||||
|
||||
private readonly RcSortedQueue<DtCrowdAgent> UpdateMoveRequest_queue = new RcSortedQueue<DtCrowdAgent>((a1, a2) => a2.targetReplanTime.CompareTo(a1.targetReplanTime));
|
||||
private readonly List<long> UpdateMoveRequest_reqPath = new List<long>();
|
||||
private void UpdateMoveRequest(IList<DtCrowdAgent> agents, float dt)
|
||||
{
|
||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.UpdateMoveRequest);
|
||||
|
||||
RcSortedQueue<DtCrowdAgent> queue = new RcSortedQueue<DtCrowdAgent>((a1, a2) => a2.targetReplanTime.CompareTo(a1.targetReplanTime));
|
||||
RcSortedQueue<DtCrowdAgent> queue = UpdateMoveRequest_queue;
|
||||
queue.Clear();
|
||||
|
||||
// Fire off new requests.
|
||||
List<long> reqPath = new List<long>();
|
||||
List<long> reqPath = UpdateMoveRequest_reqPath;
|
||||
reqPath.Clear();
|
||||
for (var i = 0; i < agents.Count; i++)
|
||||
{
|
||||
var ag = agents[i];
|
||||
|
@ -589,7 +610,7 @@ namespace DotRecast.Detour.Crowd
|
|||
if (ag.targetReplan) // && npath > 10)
|
||||
{
|
||||
// Try to use existing steady path during replan if possible.
|
||||
status = _navQuery.FinalizeSlicedFindPathPartial(path, ref reqPath);
|
||||
status = _navQuery.FinalizeSlicedFindPathPartial(path, path.Count, ref reqPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -849,7 +870,7 @@ namespace DotRecast.Detour.Crowd
|
|||
{
|
||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.BuildProximityGrid);
|
||||
|
||||
_grid = new DtProximityGrid(_config.maxAgentRadius * 3);
|
||||
_grid.Clear();
|
||||
|
||||
for (var i = 0; i < agents.Count; i++)
|
||||
{
|
||||
|
@ -875,7 +896,7 @@ namespace DotRecast.Detour.Crowd
|
|||
// Update the collision boundary after certain distance has been passed or
|
||||
// if it has become invalid.
|
||||
float updateThr = ag.option.collisionQueryRange * 0.25f;
|
||||
if (RcVecUtils.Dist2DSqr(ag.npos, ag.boundary.GetCenter()) > RcMath.Sqr(updateThr)
|
||||
if (RcVec.Dist2DSqr(ag.npos, ag.boundary.GetCenter()) > RcMath.Sqr(updateThr)
|
||||
|| !ag.boundary.IsValid(_navQuery, _filters[ag.option.queryFilterType]))
|
||||
{
|
||||
ag.boundary.Update(ag.corridor.GetFirstPoly(), ag.npos, ag.option.collisionQueryRange, _navQuery,
|
||||
|
@ -883,21 +904,66 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
|
||||
// Query neighbour agents
|
||||
GetNeighbours(ag.npos, ag.option.height, ag.option.collisionQueryRange, ag, ref ag.neis, _grid);
|
||||
ag.nneis = GetNeighbours(ag.npos, ag.option.height, ag.option.collisionQueryRange, ag, ag.neis, DtCrowdConst.DT_CROWDAGENT_MAX_NEIGHBOURS, _grid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int GetNeighbours(RcVec3f pos, float height, float range, DtCrowdAgent skip, ref List<DtCrowdNeighbour> result, DtProximityGrid grid)
|
||||
public static int AddNeighbour(DtCrowdAgent idx, float dist, Span<DtCrowdNeighbour> neis, int nneis, int maxNeis)
|
||||
{
|
||||
result.Clear();
|
||||
// Insert neighbour based on the distance.
|
||||
int nei = 0;
|
||||
if (0 == nneis)
|
||||
{
|
||||
nei = nneis;
|
||||
}
|
||||
else if (dist >= neis[nneis - 1].dist)
|
||||
{
|
||||
if (nneis >= maxNeis)
|
||||
return nneis;
|
||||
nei = nneis;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nneis; ++i)
|
||||
{
|
||||
if (dist <= neis[i].dist)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int tgt = i + 1;
|
||||
int n = Math.Min(nneis - i, maxNeis - tgt);
|
||||
|
||||
Debug.Assert(tgt + n <= maxNeis);
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
RcSpans.Move(neis, i, tgt, n);
|
||||
}
|
||||
|
||||
nei = i;
|
||||
}
|
||||
|
||||
neis[nei] = new DtCrowdNeighbour(idx, dist);
|
||||
|
||||
return Math.Min(nneis + 1, maxNeis);
|
||||
}
|
||||
|
||||
private int GetNeighbours(RcVec3f pos, float height, float range, DtCrowdAgent skip, DtCrowdNeighbour[] result, int maxResult, DtProximityGrid grid)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
const int MAX_NEIS = 32;
|
||||
Span<int> ids = stackalloc int[MAX_NEIS];
|
||||
int nids = grid.QueryItems(pos.X - range, pos.Z - range,
|
||||
pos.X + range, pos.Z + range,
|
||||
ids, ids.Length);
|
||||
|
||||
int MAX_NEIS = 32;
|
||||
var ids = new DtCrowdAgent[MAX_NEIS];
|
||||
int nids = grid.QueryItems(pos.X - range, pos.Z - range, pos.X + range, pos.Z + range, ids, ids.Length);
|
||||
for (int i = 0; i < nids; ++i)
|
||||
{
|
||||
var ag = ids[i];
|
||||
var ag = GetAgent(ids[i]);
|
||||
if (ag == skip)
|
||||
{
|
||||
continue;
|
||||
|
@ -917,11 +983,10 @@ namespace DotRecast.Detour.Crowd
|
|||
continue;
|
||||
}
|
||||
|
||||
result.Add(new DtCrowdNeighbour(ag, distSqr));
|
||||
n = AddNeighbour(ag, distSqr, result, n, maxResult);
|
||||
}
|
||||
|
||||
result.Sort((o1, o2) => o1.dist.CompareTo(o2.dist));
|
||||
return result.Count;
|
||||
return n;
|
||||
}
|
||||
|
||||
private void FindCorners(IList<DtCrowdAgent> agents, DtCrowdAgentDebugInfo debug)
|
||||
|
@ -944,13 +1009,13 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
|
||||
// Find corners for steering
|
||||
ag.corridor.FindCorners(ref ag.corners, DtCrowdConst.DT_CROWDAGENT_MAX_CORNERS, _navQuery, _filters[ag.option.queryFilterType]);
|
||||
ag.ncorners = ag.corridor.FindCorners(ag.corners, DtCrowdConst.DT_CROWDAGENT_MAX_CORNERS, _navQuery, _filters[ag.option.queryFilterType]);
|
||||
|
||||
// Check to see if the corner after the next corner is directly visible,
|
||||
// and short cut to there.
|
||||
if ((ag.option.updateFlags & DtCrowdAgentUpdateFlags.DT_CROWD_OPTIMIZE_VIS) != 0 && ag.corners.Count > 0)
|
||||
if ((ag.option.updateFlags & DtCrowdAgentUpdateFlags.DT_CROWD_OPTIMIZE_VIS) != 0 && ag.ncorners > 0)
|
||||
{
|
||||
RcVec3f target = ag.corners[Math.Min(1, ag.corners.Count - 1)].pos;
|
||||
RcVec3f target = ag.corners[Math.Min(1, ag.ncorners - 1)].pos;
|
||||
ag.corridor.OptimizePathVisibility(target, ag.option.pathOptimizationRange, _navQuery,
|
||||
_filters[ag.option.queryFilterType]);
|
||||
|
||||
|
@ -992,7 +1057,7 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
|
||||
// Check
|
||||
float triggerRadius = ag.option.radius * 2.25f;
|
||||
float triggerRadius = ag.option.radius * 0.25f;//todo make parameterizable
|
||||
if (ag.OverOffmeshConnection(triggerRadius))
|
||||
{
|
||||
// Prepare to off-mesh connection.
|
||||
|
@ -1000,18 +1065,18 @@ namespace DotRecast.Detour.Crowd
|
|||
|
||||
// Adjust the path over the off-mesh connection.
|
||||
long[] refs = new long[2];
|
||||
if (ag.corridor.MoveOverOffmeshConnection(ag.corners[ag.corners.Count - 1].refs, refs, ref anim.startPos,
|
||||
if (ag.corridor.MoveOverOffmeshConnection(ag.corners[ag.ncorners - 1].refs, refs, ref anim.startPos,
|
||||
ref anim.endPos, _navQuery))
|
||||
{
|
||||
anim.initPos = ag.npos;
|
||||
anim.polyRef = refs[1];
|
||||
anim.active = true;
|
||||
anim.t = 0.0f;
|
||||
anim.tmax = (RcVecUtils.Dist2D(anim.startPos, anim.endPos) / ag.option.maxSpeed) * 0.5f;
|
||||
anim.tmax = (RcVec.Dist2D(anim.startPos, anim.endPos) / ag.option.maxSpeed) * 0.5f;
|
||||
|
||||
ag.state = DtCrowdAgentState.DT_CROWDAGENT_STATE_OFFMESH;
|
||||
ag.corners.Clear();
|
||||
ag.neis.Clear();
|
||||
ag.ncorners = 0;
|
||||
ag.nneis = 0;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
@ -1063,7 +1128,7 @@ namespace DotRecast.Detour.Crowd
|
|||
float speedScale = ag.GetDistanceToGoal(slowDownRadius) / slowDownRadius;
|
||||
|
||||
ag.desiredSpeed = ag.option.maxSpeed;
|
||||
dvel = dvel.Scale(ag.desiredSpeed * speedScale);
|
||||
dvel = dvel * (ag.desiredSpeed * speedScale);
|
||||
}
|
||||
|
||||
// Separation
|
||||
|
@ -1076,7 +1141,7 @@ namespace DotRecast.Detour.Crowd
|
|||
float w = 0;
|
||||
RcVec3f disp = new RcVec3f();
|
||||
|
||||
for (int j = 0; j < ag.neis.Count; ++j)
|
||||
for (int j = 0; j < ag.nneis; ++j)
|
||||
{
|
||||
DtCrowdAgent nei = ag.neis[j].agent;
|
||||
|
||||
|
@ -1097,20 +1162,20 @@ namespace DotRecast.Detour.Crowd
|
|||
float dist = MathF.Sqrt(distSqr);
|
||||
float weight = separationWeight * (1.0f - RcMath.Sqr(dist * invSeparationDist));
|
||||
|
||||
disp = RcVecUtils.Mad(disp, diff, weight / dist);
|
||||
disp = RcVec.Mad(disp, diff, weight / dist);
|
||||
w += 1.0f;
|
||||
}
|
||||
|
||||
if (w > 0.0001f)
|
||||
{
|
||||
// Adjust desired velocity.
|
||||
dvel = RcVecUtils.Mad(dvel, disp, 1.0f / w);
|
||||
dvel = RcVec.Mad(dvel, disp, 1.0f / w);
|
||||
// Clamp desired velocity to desired speed.
|
||||
float speedSqr = dvel.LengthSquared();
|
||||
float desiredSqr = RcMath.Sqr(ag.desiredSpeed);
|
||||
if (speedSqr > desiredSqr)
|
||||
{
|
||||
dvel = dvel.Scale(desiredSqr / speedSqr);
|
||||
dvel = dvel * (desiredSqr / speedSqr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1138,9 +1203,12 @@ namespace DotRecast.Detour.Crowd
|
|||
_obstacleQuery.Reset();
|
||||
|
||||
// Add neighbours as obstacles.
|
||||
for (int j = 0; j < ag.neis.Count; ++j)
|
||||
for (int j = 0; j < ag.nneis; ++j)
|
||||
{
|
||||
DtCrowdAgent nei = ag.neis[j].agent;
|
||||
if(!nei.option.contributeObstacleAvoidance || nei.option.obstacleAvoidanceWeight < ag.option.obstacleAvoidanceWeight)
|
||||
continue;
|
||||
|
||||
_obstacleQuery.AddCircle(nei.npos, nei.option.radius, nei.vel, nei.dvel);
|
||||
}
|
||||
|
||||
|
@ -1226,7 +1294,7 @@ namespace DotRecast.Detour.Crowd
|
|||
|
||||
float w = 0;
|
||||
|
||||
for (int j = 0; j < ag.neis.Count; ++j)
|
||||
for (int j = 0; j < ag.nneis; ++j)
|
||||
{
|
||||
DtCrowdAgent nei = ag.neis[j].agent;
|
||||
long idx1 = nei.idx;
|
||||
|
@ -1260,7 +1328,7 @@ namespace DotRecast.Detour.Crowd
|
|||
pen = (1.0f / dist) * (pen * 0.5f) * _config.collisionResolveFactor;
|
||||
}
|
||||
|
||||
ag.disp = RcVecUtils.Mad(ag.disp, diff, pen);
|
||||
ag.disp = RcVec.Mad(ag.disp, diff, pen);
|
||||
|
||||
w += 1.0f;
|
||||
}
|
||||
|
@ -1268,7 +1336,7 @@ namespace DotRecast.Detour.Crowd
|
|||
if (w > 0.0001f)
|
||||
{
|
||||
float iw = 1.0f / w;
|
||||
ag.disp = ag.disp.Scale(iw);
|
||||
ag.disp = ag.disp * iw;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -28,7 +28,7 @@ namespace DotRecast.Detour.Crowd
|
|||
/// @ingroup crowd
|
||||
public class DtCrowdAgent
|
||||
{
|
||||
public readonly long idx;
|
||||
public readonly int idx;
|
||||
|
||||
/// The type of mesh polygon the agent is traversing. (See: #CrowdAgentState)
|
||||
public DtCrowdAgentState state;
|
||||
|
@ -37,16 +37,19 @@ namespace DotRecast.Detour.Crowd
|
|||
public bool partial;
|
||||
|
||||
/// The path corridor the agent is using.
|
||||
public DtPathCorridor corridor;
|
||||
public readonly DtPathCorridor corridor;
|
||||
|
||||
/// The local boundary data for the agent.
|
||||
public DtLocalBoundary boundary;
|
||||
public readonly DtLocalBoundary boundary;
|
||||
|
||||
/// Time since the agent's path corridor was optimized.
|
||||
public float topologyOptTime;
|
||||
|
||||
/// The known neighbors of the agent.
|
||||
public List<DtCrowdNeighbour> neis = new List<DtCrowdNeighbour>();
|
||||
public readonly DtCrowdNeighbour[] neis = new DtCrowdNeighbour[DtCrowdConst.DT_CROWDAGENT_MAX_NEIGHBOURS];
|
||||
|
||||
/// The number of neighbors.
|
||||
public int nneis;
|
||||
|
||||
/// The desired speed.
|
||||
public float desiredSpeed;
|
||||
|
@ -61,7 +64,10 @@ namespace DotRecast.Detour.Crowd
|
|||
public DtCrowdAgentParams option;
|
||||
|
||||
/// The local path corridor corners for the agent.
|
||||
public List<DtStraightPath> corners = new List<DtStraightPath>();
|
||||
public DtStraightPath[] corners = new DtStraightPath[DtCrowdConst.DT_CROWDAGENT_MAX_CORNERS];
|
||||
|
||||
/// The number of corners.
|
||||
public int ncorners;
|
||||
|
||||
public DtMoveRequestState targetState; // < State of the movement request.
|
||||
public long targetRef; // < Target polyref of the movement request.
|
||||
|
@ -88,28 +94,28 @@ namespace DotRecast.Detour.Crowd
|
|||
RcVec3f dv = RcVec3f.Subtract(nvel, vel);
|
||||
float ds = dv.Length();
|
||||
if (ds > maxDelta)
|
||||
dv = dv.Scale(maxDelta / ds);
|
||||
dv = dv * (maxDelta / ds);
|
||||
vel = RcVec3f.Add(vel, dv);
|
||||
|
||||
// Integrate
|
||||
if (vel.Length() > 0.0001f)
|
||||
npos = RcVecUtils.Mad(npos, vel, dt);
|
||||
npos = RcVec.Mad(npos, vel, dt);
|
||||
else
|
||||
vel = RcVec3f.Zero;
|
||||
}
|
||||
|
||||
public bool OverOffmeshConnection(float radius)
|
||||
{
|
||||
if (0 == corners.Count)
|
||||
if (0 == ncorners)
|
||||
return false;
|
||||
|
||||
bool offMeshConnection = ((corners[corners.Count - 1].flags
|
||||
bool offMeshConnection = ((corners[ncorners - 1].flags
|
||||
& DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
||||
? true
|
||||
: false;
|
||||
if (offMeshConnection)
|
||||
{
|
||||
float distSq = RcVecUtils.Dist2DSqr(npos, corners[corners.Count - 1].pos);
|
||||
float distSq = RcVec.Dist2DSqr(npos, corners[ncorners - 1].pos);
|
||||
if (distSq < radius * radius)
|
||||
return true;
|
||||
}
|
||||
|
@ -119,12 +125,12 @@ namespace DotRecast.Detour.Crowd
|
|||
|
||||
public float GetDistanceToGoal(float range)
|
||||
{
|
||||
if (0 == corners.Count)
|
||||
if (0 == ncorners)
|
||||
return range;
|
||||
|
||||
bool endOfPath = ((corners[corners.Count - 1].flags & DtStraightPathFlags.DT_STRAIGHTPATH_END) != 0) ? true : false;
|
||||
bool endOfPath = ((corners[ncorners - 1].flags & DtStraightPathFlags.DT_STRAIGHTPATH_END) != 0) ? true : false;
|
||||
if (endOfPath)
|
||||
return Math.Min(RcVecUtils.Dist2D(npos, corners[corners.Count - 1].pos), range);
|
||||
return Math.Min(RcVec.Dist2D(npos, corners[ncorners - 1].pos), range);
|
||||
|
||||
return range;
|
||||
}
|
||||
|
@ -132,10 +138,10 @@ namespace DotRecast.Detour.Crowd
|
|||
public RcVec3f CalcSmoothSteerDirection()
|
||||
{
|
||||
RcVec3f dir = new RcVec3f();
|
||||
if (0 < corners.Count)
|
||||
if (0 < ncorners)
|
||||
{
|
||||
int ip0 = 0;
|
||||
int ip1 = Math.Min(1, corners.Count - 1);
|
||||
int ip1 = Math.Min(1, ncorners - 1);
|
||||
var p0 = corners[ip0].pos;
|
||||
var p1 = corners[ip1].pos;
|
||||
|
||||
|
@ -147,7 +153,7 @@ namespace DotRecast.Detour.Crowd
|
|||
float len0 = dir0.Length();
|
||||
float len1 = dir1.Length();
|
||||
if (len1 > 0.001f)
|
||||
dir1 = dir1.Scale(1.0f / len1);
|
||||
dir1 = dir1 * (1.0f / len1);
|
||||
|
||||
dir.X = dir0.X - dir1.X * len0 * 0.5f;
|
||||
dir.Y = 0;
|
||||
|
@ -161,7 +167,7 @@ namespace DotRecast.Detour.Crowd
|
|||
public RcVec3f CalcStraightSteerDirection()
|
||||
{
|
||||
RcVec3f dir = new RcVec3f();
|
||||
if (0 < corners.Count)
|
||||
if (0 < ncorners)
|
||||
{
|
||||
dir = RcVec3f.Subtract(corners[0].pos, npos);
|
||||
dir.Y = 0;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour.Crowd
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
public class DtCrowdAgentConfig
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -24,23 +24,15 @@ namespace DotRecast.Detour.Crowd
|
|||
/// @ingroup crowd
|
||||
public class DtCrowdAgentParams
|
||||
{
|
||||
/// < Agent radius. [Limit: >= 0]
|
||||
public float radius;
|
||||
|
||||
/// < Agent height. [Limit: > 0]
|
||||
public float height;
|
||||
|
||||
/// < Maximum allowed acceleration. [Limit: >= 0]
|
||||
public float maxAcceleration;
|
||||
|
||||
/// < Maximum allowed speed. [Limit: >= 0]
|
||||
public float maxSpeed;
|
||||
public float radius; // < Agent radius. [Limit: >= 0]
|
||||
public float height; // < Agent height. [Limit: > 0]
|
||||
public float maxAcceleration; // < Maximum allowed acceleration. [Limit: >= 0]
|
||||
public float maxSpeed; // < Maximum allowed speed. [Limit: >= 0]
|
||||
|
||||
/// Defines how close a collision element must be before it is considered for steering behaviors. [Limits: > 0]
|
||||
public float collisionQueryRange;
|
||||
|
||||
/// < The path visibility optimization range. [Limit: > 0]
|
||||
public float pathOptimizationRange;
|
||||
public float pathOptimizationRange; // < The path visibility optimization range. [Limit: > 0]
|
||||
|
||||
/// How aggresive the agent manager should be at avoiding collisions with this agent. [Limit: >= 0]
|
||||
public float separationWeight;
|
||||
|
@ -53,6 +45,9 @@ namespace DotRecast.Detour.Crowd
|
|||
/// [Limits: 0 <= value < #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
|
||||
public int obstacleAvoidanceType;
|
||||
|
||||
public bool contributeObstacleAvoidance;
|
||||
public float obstacleAvoidanceWeight;
|
||||
|
||||
/// The index of the query filter used by this agent.
|
||||
public int queryFilterType;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour.Crowd
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
/// The type of navigation mesh polygon the agent is currently traversing.
|
||||
/// @ingroup crowd
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour.Crowd
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
/// Crowd agent update flags.
|
||||
/// @ingroup crowd
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour.Crowd
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
public static class DtCrowdConst
|
||||
{
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
namespace DotRecast.Detour.Crowd
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
/// Provides neighbor data for agents managed by the crowd.
|
||||
/// @ingroup crowd
|
||||
/// @see dtCrowdAgent::neis, dtCrowd
|
||||
public readonly struct DtCrowdNeighbour
|
||||
{
|
||||
public readonly DtCrowdAgent agent;
|
||||
public readonly DtCrowdAgent agent; // < The index of the neighbor in the crowd.
|
||||
public readonly float dist; // < The distance between the current agent and the neighbor.
|
||||
|
||||
/// < The index of the neighbor in the crowd.
|
||||
public readonly float dist;
|
||||
|
||||
/// < The distance between the current agent and the neighbor.
|
||||
public DtCrowdNeighbour(DtCrowdAgent agent, float dist)
|
||||
{
|
||||
this.agent = agent;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour.Crowd
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
public class DtCrowdTimerLabel
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,6 +18,7 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
@ -90,6 +91,8 @@ namespace DotRecast.Detour.Crowd
|
|||
|
||||
public void Update(long startRef, RcVec3f pos, float collisionQueryRange, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||
{
|
||||
const int MAX_SEGS_PER_POLY = DtDetour.DT_VERTS_PER_POLYGON * 3;
|
||||
|
||||
if (startRef == 0)
|
||||
{
|
||||
Reset();
|
||||
|
@ -104,18 +107,17 @@ namespace DotRecast.Detour.Crowd
|
|||
{
|
||||
// Secondly, store all polygon edges.
|
||||
m_segs.Clear();
|
||||
|
||||
var segmentVerts = new List<RcSegmentVert>();
|
||||
var segmentRefs = new List<long>();
|
||||
Span<RcSegmentVert> segs = stackalloc RcSegmentVert[MAX_SEGS_PER_POLY];
|
||||
int nsegs = 0;
|
||||
|
||||
for (int j = 0; j < m_polys.Count; ++j)
|
||||
{
|
||||
var result = navquery.GetPolyWallSegments(m_polys[j], false, filter, ref segmentVerts, ref segmentRefs);
|
||||
var result = navquery.GetPolyWallSegments(m_polys[j], filter, segs, null, ref nsegs, MAX_SEGS_PER_POLY);
|
||||
if (result.Succeeded())
|
||||
{
|
||||
for (int k = 0; k < segmentRefs.Count; ++k)
|
||||
for (int k = 0; k < nsegs; ++k)
|
||||
{
|
||||
RcSegmentVert s = segmentVerts[k];
|
||||
ref RcSegmentVert s = ref segs[k];
|
||||
var s0 = s.vmin;
|
||||
var s3 = s.vmax;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour.Crowd
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
public enum DtMoveRequestState
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour.Crowd
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
public class DtObstacleAvoidanceParams
|
||||
{
|
||||
|
@ -8,18 +8,11 @@
|
|||
public float weightSide;
|
||||
public float weightToi;
|
||||
public float horizTime;
|
||||
public int gridSize;
|
||||
public int gridSize; // < grid
|
||||
public int adaptiveDivs; // < adaptive
|
||||
public int adaptiveRings; // < adaptive
|
||||
public int adaptiveDepth; // < adaptive
|
||||
|
||||
/// < grid
|
||||
public int adaptiveDivs;
|
||||
|
||||
/// < adaptive
|
||||
public int adaptiveRings;
|
||||
|
||||
/// < adaptive
|
||||
public int adaptiveDepth;
|
||||
|
||||
/// < adaptive
|
||||
public DtObstacleAvoidanceParams()
|
||||
{
|
||||
velBias = 0.4f;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
|
@ -27,11 +28,9 @@ namespace DotRecast.Detour.Crowd
|
|||
{
|
||||
public class DtObstacleAvoidanceQuery
|
||||
{
|
||||
public const int DT_MAX_PATTERN_DIVS = 32;
|
||||
|
||||
/// < Max numver of adaptive divs.
|
||||
public const int DT_MAX_PATTERN_DIVS = 32; // < Max numver of adaptive divs.
|
||||
public const int DT_MAX_PATTERN_RINGS = 4;
|
||||
|
||||
public const float DT_PI = 3.14159265f;
|
||||
|
||||
private DtObstacleAvoidanceParams m_params;
|
||||
private float m_invHorizTime;
|
||||
|
@ -187,16 +186,16 @@ namespace DotRecast.Detour.Crowd
|
|||
{
|
||||
RcVec3f v = RcVec3f.Subtract(bq, bp);
|
||||
RcVec3f w = RcVec3f.Subtract(ap, bp);
|
||||
float d = RcVecUtils.Perp2D(u, v);
|
||||
float d = RcVec.Perp2D(u, v);
|
||||
if (MathF.Abs(d) < 1e-6f)
|
||||
return false;
|
||||
|
||||
d = 1.0f / d;
|
||||
t = RcVecUtils.Perp2D(v, w) * d;
|
||||
t = RcVec.Perp2D(v, w) * d;
|
||||
if (t < 0 || t > 1)
|
||||
return false;
|
||||
|
||||
float s = RcVecUtils.Perp2D(u, w) * d;
|
||||
float s = RcVec.Perp2D(u, w) * d;
|
||||
if (s < 0 || s > 1)
|
||||
return false;
|
||||
|
||||
|
@ -217,8 +216,8 @@ namespace DotRecast.Detour.Crowd
|
|||
float minPenalty, DtObstacleAvoidanceDebugData debug)
|
||||
{
|
||||
// penalty for straying away from the desired and current velocities
|
||||
float vpen = m_params.weightDesVel * (RcVecUtils.Dist2D(vcand, dvel) * m_invVmax);
|
||||
float vcpen = m_params.weightCurVel * (RcVecUtils.Dist2D(vcand, vel) * m_invVmax);
|
||||
float vpen = m_params.weightDesVel * (RcVec.Dist2D(vcand, dvel) * m_invVmax);
|
||||
float vcpen = m_params.weightCurVel * (RcVec.Dist2D(vcand, vel) * m_invVmax);
|
||||
|
||||
// find the threshold hit time to bail out based on the early out penalty
|
||||
// (see how the penalty is calculated below to understand)
|
||||
|
@ -237,7 +236,7 @@ namespace DotRecast.Detour.Crowd
|
|||
DtObstacleCircle cir = m_circles[i];
|
||||
|
||||
// RVO
|
||||
RcVec3f vab = vcand.Scale(2);
|
||||
RcVec3f vab = vcand * 2;
|
||||
vab = RcVec3f.Subtract(vab, vel);
|
||||
vab = RcVec3f.Subtract(vab, cir.vel);
|
||||
|
||||
|
@ -362,7 +361,8 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
|
||||
// vector normalization that ignores the y-component.
|
||||
void DtNormalize2D(float[] v)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void DtNormalize2D(Span<float> v)
|
||||
{
|
||||
float d = MathF.Sqrt(v[0] * v[0] + v[2] * v[2]);
|
||||
if (d == 0)
|
||||
|
@ -373,7 +373,8 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
|
||||
// vector normalization that ignores the y-component.
|
||||
RcVec3f DtRotate2D(float[] v, float ang)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
RcVec3f DtRotate2D(Span<float> v, float ang)
|
||||
{
|
||||
RcVec3f dest = new RcVec3f();
|
||||
float c = MathF.Cos(ang);
|
||||
|
@ -384,7 +385,6 @@ namespace DotRecast.Detour.Crowd
|
|||
return dest;
|
||||
}
|
||||
|
||||
static readonly float DT_PI = 3.14159265f;
|
||||
|
||||
public int SampleVelocityAdaptive(RcVec3f pos, float rad, float vmax, RcVec3f vel, RcVec3f dvel, out RcVec3f nvel,
|
||||
DtObstacleAvoidanceParams option,
|
||||
|
@ -402,7 +402,7 @@ namespace DotRecast.Detour.Crowd
|
|||
debug.Reset();
|
||||
|
||||
// Build sampling pattern aligned to desired velocity.
|
||||
float[] pat = new float[(DT_MAX_PATTERN_DIVS * DT_MAX_PATTERN_RINGS + 1) * 2];
|
||||
Span<float> pat = stackalloc float[(DT_MAX_PATTERN_DIVS * DT_MAX_PATTERN_RINGS + 1) * 2];
|
||||
int npat = 0;
|
||||
|
||||
int ndivs = m_params.adaptiveDivs;
|
||||
|
@ -416,7 +416,7 @@ namespace DotRecast.Detour.Crowd
|
|||
float sa = MathF.Sin(da);
|
||||
|
||||
// desired direction
|
||||
float[] ddir = new float[6];
|
||||
Span<float> ddir = stackalloc float[6];
|
||||
ddir[0] = dvel.X;
|
||||
ddir[1] = dvel.Y;
|
||||
ddir[2] = dvel.Z;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -33,7 +33,8 @@ namespace DotRecast.Detour.Crowd
|
|||
private RcVec3f m_pos;
|
||||
private RcVec3f m_target;
|
||||
|
||||
private List<long> m_path;
|
||||
private List<long> m_path = new List<long>();
|
||||
private int m_npath;
|
||||
private int m_maxPath;
|
||||
|
||||
/**
|
||||
|
@ -88,7 +89,9 @@ namespace DotRecast.Detour.Crowd
|
|||
/// @return True if the initialization succeeded.
|
||||
public bool Init(int maxPath)
|
||||
{
|
||||
m_path = new List<long>();
|
||||
if (m_path.Capacity < maxPath)
|
||||
m_path.Capacity = maxPath;
|
||||
m_npath = 0;
|
||||
m_maxPath = maxPath;
|
||||
return true;
|
||||
}
|
||||
|
@ -107,6 +110,7 @@ namespace DotRecast.Detour.Crowd
|
|||
m_target = pos;
|
||||
m_path.Clear();
|
||||
m_path.Add(refs);
|
||||
m_npath = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,42 +134,42 @@ namespace DotRecast.Detour.Crowd
|
|||
/// @param[in] navquery The query object used to build the corridor.
|
||||
/// @param[in] filter The filter to apply to the operation.
|
||||
/// @return The number of corners returned in the corner buffers. [0 <= value <= @p maxCorners]
|
||||
public int FindCorners(ref List<DtStraightPath> corners, int maxCorners, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||
public int FindCorners(Span<DtStraightPath> corners, int maxCorners, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||
{
|
||||
const float MIN_TARGET_DIST = 0.01f;
|
||||
|
||||
var result = navquery.FindStraightPath(m_pos, m_target, m_path, ref corners, maxCorners, 0);
|
||||
if (result.Succeeded())
|
||||
{
|
||||
int ncorners = 0;
|
||||
navquery.FindStraightPath(m_pos, m_target, m_path, m_npath, corners, out ncorners, maxCorners, 0);
|
||||
|
||||
// Prune points in the beginning of the path which are too close.
|
||||
int start = 0;
|
||||
foreach (DtStraightPath spi in corners)
|
||||
while (0 < ncorners)
|
||||
{
|
||||
if ((spi.flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0
|
||||
|| RcVecUtils.Dist2DSqr(spi.pos, m_pos) > RcMath.Sqr(MIN_TARGET_DIST))
|
||||
if ((corners[0].flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0 ||
|
||||
RcVec.Dist2DSqr(corners[0].pos, m_pos) > RcMath.Sqr(MIN_TARGET_DIST))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
start++;
|
||||
ncorners--;
|
||||
if (0 < ncorners)
|
||||
{
|
||||
RcSpans.Move(corners, 1, 0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
int end = corners.Count;
|
||||
|
||||
// Prune points after an off-mesh connection.
|
||||
for (int i = start; i < corners.Count; i++)
|
||||
for (int i = 0; i < ncorners; ++i)
|
||||
{
|
||||
DtStraightPath spi = corners[i];
|
||||
if ((spi.flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
||||
if ((corners[i].flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
||||
{
|
||||
end = i + 1;
|
||||
ncorners = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
corners = corners.GetRange(start, end - start);
|
||||
}
|
||||
|
||||
return corners.Count;
|
||||
return ncorners;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -194,7 +198,7 @@ namespace DotRecast.Detour.Crowd
|
|||
public void OptimizePathVisibility(RcVec3f next, float pathOptimizationRange, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||
{
|
||||
// Clamp the ray to max distance.
|
||||
float dist = RcVecUtils.Dist2D(m_pos, next);
|
||||
float dist = RcVec.Dist2D(m_pos, next);
|
||||
|
||||
// If too close to the goal, do not try to optimize.
|
||||
if (dist < 0.01f)
|
||||
|
@ -207,7 +211,7 @@ namespace DotRecast.Detour.Crowd
|
|||
|
||||
// Adjust ray length.
|
||||
var delta = RcVec3f.Subtract(next, m_pos);
|
||||
RcVec3f goal = RcVecUtils.Mad(m_pos, delta, pathOptimizationRange / dist);
|
||||
RcVec3f goal = RcVec.Mad(m_pos, delta, pathOptimizationRange / dist);
|
||||
|
||||
var res = new List<long>();
|
||||
var status = navquery.Raycast(m_path[0], m_pos, goal, filter, out var t, out var norm, ref res);
|
||||
|
@ -215,7 +219,7 @@ namespace DotRecast.Detour.Crowd
|
|||
{
|
||||
if (res.Count > 1 && t > 0.99f)
|
||||
{
|
||||
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, m_path.Count, m_maxPath, res);
|
||||
m_npath = DtPathUtils.MergeCorridorStartShortcut(m_path, m_npath, m_maxPath, res, res.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +239,7 @@ namespace DotRecast.Detour.Crowd
|
|||
/// @param[in] filter The filter to apply to the operation.
|
||||
public bool OptimizePathTopology(DtNavMeshQuery navquery, IDtQueryFilter filter, int maxIterations)
|
||||
{
|
||||
if (m_path.Count < 3)
|
||||
if (m_npath < 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -243,11 +247,11 @@ namespace DotRecast.Detour.Crowd
|
|||
var res = new List<long>();
|
||||
navquery.InitSlicedFindPath(m_path[0], m_path[^1], m_pos, m_target, filter, 0);
|
||||
navquery.UpdateSlicedFindPath(maxIterations, out var _);
|
||||
var status = navquery.FinalizeSlicedFindPathPartial(m_path, ref res);
|
||||
var status = navquery.FinalizeSlicedFindPathPartial(m_path, m_npath, ref res);
|
||||
|
||||
if (status.Succeeded() && res.Count > 0)
|
||||
{
|
||||
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, m_path.Count, m_maxPath, res);
|
||||
m_npath = DtPathUtils.MergeCorridorStartShortcut(m_path, m_npath, m_maxPath, res, res.Count);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -259,21 +263,23 @@ namespace DotRecast.Detour.Crowd
|
|||
// Advance the path up to and over the off-mesh connection.
|
||||
long prevRef = 0, polyRef = m_path[0];
|
||||
int npos = 0;
|
||||
while (npos < m_path.Count && polyRef != offMeshConRef)
|
||||
while (npos < m_npath && polyRef != offMeshConRef)
|
||||
{
|
||||
prevRef = polyRef;
|
||||
polyRef = m_path[npos];
|
||||
npos++;
|
||||
}
|
||||
|
||||
if (npos == m_path.Count)
|
||||
if (npos == m_npath)
|
||||
{
|
||||
// Could not find offMeshConRef
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prune path
|
||||
m_path = m_path.GetRange(npos, m_path.Count - npos);
|
||||
m_path.RemoveRange(0, npos);
|
||||
m_npath -= npos;
|
||||
|
||||
refs[0] = prevRef;
|
||||
refs[1] = polyRef;
|
||||
|
||||
|
@ -312,11 +318,12 @@ namespace DotRecast.Detour.Crowd
|
|||
public bool MovePosition(RcVec3f npos, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||
{
|
||||
// Move along navmesh and update new position.
|
||||
var visited = new List<long>();
|
||||
var status = navquery.MoveAlongSurface(m_path[0], m_pos, npos, filter, out var result, ref visited);
|
||||
const int MAX_VISITED = 16;
|
||||
Span<long> visited = stackalloc long[MAX_VISITED];
|
||||
var status = navquery.MoveAlongSurface(m_path[0], m_pos, npos, filter, out var result, visited, out var nvisited, MAX_VISITED);
|
||||
if (status.Succeeded())
|
||||
{
|
||||
m_path = DtPathUtils.MergeCorridorStartMoved(m_path, m_path.Count, m_maxPath, visited);
|
||||
m_npath = DtPathUtils.MergeCorridorStartMoved(m_path, m_npath, m_maxPath, visited, nvisited);
|
||||
|
||||
// Adjust the position to stay on top of the navmesh.
|
||||
m_pos = result;
|
||||
|
@ -354,11 +361,14 @@ namespace DotRecast.Detour.Crowd
|
|||
public bool MoveTargetPosition(RcVec3f npos, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||
{
|
||||
// Move along navmesh and update new position.
|
||||
var visited = new List<long>();
|
||||
var status = navquery.MoveAlongSurface(m_path[^1], m_target, npos, filter, out var result, ref visited);
|
||||
const int MAX_VISITED = 16;
|
||||
Span<long> visited = stackalloc long[MAX_VISITED];
|
||||
int nvisited = 0;
|
||||
var status = navquery.MoveAlongSurface(m_path[^1], m_target, npos, filter, out var result, visited, out nvisited, MAX_VISITED);
|
||||
if (status.Succeeded())
|
||||
{
|
||||
m_path = DtPathUtils.MergeCorridorEndMoved(m_path, m_path.Count, m_maxPath, visited);
|
||||
m_npath = DtPathUtils.MergeCorridorEndMoved(m_path, m_npath, m_maxPath, visited, nvisited);
|
||||
|
||||
// TODO: should we do that?
|
||||
// Adjust the position to stay on top of the navmesh.
|
||||
/*
|
||||
|
@ -385,25 +395,32 @@ namespace DotRecast.Detour.Crowd
|
|||
public void SetCorridor(RcVec3f target, List<long> path)
|
||||
{
|
||||
m_target = target;
|
||||
m_path = new List<long>(path);
|
||||
if(path != m_path)
|
||||
{
|
||||
m_path.Clear();
|
||||
m_path.AddRange(path);
|
||||
}
|
||||
m_npath = path.Count;
|
||||
}
|
||||
|
||||
public void FixPathStart(long safeRef, RcVec3f safePos)
|
||||
{
|
||||
m_pos = safePos;
|
||||
if (m_path.Count < 3 && m_path.Count > 0)
|
||||
if (m_npath < 3 && m_npath > 0)
|
||||
{
|
||||
long p = m_path[m_path.Count - 1];
|
||||
long p = m_path[m_npath - 1];
|
||||
m_path.Clear();
|
||||
m_path.Add(safeRef);
|
||||
m_path.Add(0L);
|
||||
m_path.Add(p);
|
||||
m_npath = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_path.Clear();
|
||||
m_path.Add(safeRef);
|
||||
m_path.Add(0L);
|
||||
m_npath = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,12 +428,12 @@ namespace DotRecast.Detour.Crowd
|
|||
{
|
||||
// Keep valid path as far as possible.
|
||||
int n = 0;
|
||||
while (n < m_path.Count && navquery.IsValidPolyRef(m_path[n], filter))
|
||||
while (n < m_npath && navquery.IsValidPolyRef(m_path[n], filter))
|
||||
{
|
||||
n++;
|
||||
}
|
||||
|
||||
if (m_path.Count == n)
|
||||
if (m_npath == n)
|
||||
{
|
||||
// All valid, no need to fix.
|
||||
return true;
|
||||
|
@ -424,18 +441,20 @@ namespace DotRecast.Detour.Crowd
|
|||
else if (n == 0)
|
||||
{
|
||||
// The first polyref is bad, use current safe values.
|
||||
m_pos = RcVecUtils.Create(safePos);
|
||||
m_pos = new RcVec3f(safePos);
|
||||
m_path.Clear();
|
||||
m_path.Add(safeRef);
|
||||
m_npath = 1;
|
||||
}
|
||||
else if (n < m_path.Count)
|
||||
else if (n < m_npath)
|
||||
{
|
||||
// The path is partially usable.
|
||||
m_path = m_path.GetRange(0, n);
|
||||
m_path.RemoveRange(n, m_path.Count - n);
|
||||
m_npath = n;
|
||||
}
|
||||
|
||||
// Clamp target pos to last poly
|
||||
navquery.ClosestPointOnPolyBoundary(m_path[m_path.Count - 1], m_target, out m_target);
|
||||
navquery.ClosestPointOnPolyBoundary(m_path[m_npath - 1], m_target, out m_target);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -451,7 +470,7 @@ namespace DotRecast.Detour.Crowd
|
|||
public bool IsValid(int maxLookAhead, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||
{
|
||||
// Check that all polygons still pass query filter.
|
||||
int n = Math.Min(m_path.Count, maxLookAhead);
|
||||
int n = Math.Min(m_npath, maxLookAhead);
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (!navquery.IsValidPolyRef(m_path[i], filter))
|
||||
|
@ -481,14 +500,14 @@ namespace DotRecast.Detour.Crowd
|
|||
/// @return The polygon reference id of the first polygon in the corridor. (Or zero if there is no path.)
|
||||
public long GetFirstPoly()
|
||||
{
|
||||
return 0 == m_path.Count ? 0 : m_path[0];
|
||||
return 0 == m_npath ? 0 : m_path[0];
|
||||
}
|
||||
|
||||
/// The polygon reference id of the last polygon in the corridor, the polygon containing the target.
|
||||
/// @return The polygon reference id of the last polygon in the corridor. (Or zero if there is no path.)
|
||||
public long GetLastPoly()
|
||||
{
|
||||
return 0 == m_path.Count ? 0 : m_path[m_path.Count - 1];
|
||||
return 0 == m_npath ? 0 : m_path[m_npath - 1];
|
||||
}
|
||||
|
||||
/// The corridor's path.
|
||||
|
@ -502,7 +521,7 @@ namespace DotRecast.Detour.Crowd
|
|||
/// @return The number of polygons in the current corridor path.
|
||||
public int GetPathCount()
|
||||
{
|
||||
return m_path.Count;
|
||||
return m_npath;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -22,6 +22,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using DotRecast.Core.Buffers;
|
||||
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
|
@ -30,12 +31,14 @@ namespace DotRecast.Detour.Crowd
|
|||
private readonly float _cellSize;
|
||||
private readonly float _invCellSize;
|
||||
private readonly Dictionary<long, List<DtCrowdAgent>> _items;
|
||||
private readonly RcObjectPool<List<DtCrowdAgent>> _listPool;
|
||||
|
||||
public DtProximityGrid(float cellSize)
|
||||
{
|
||||
_cellSize = cellSize;
|
||||
_invCellSize = 1.0f / cellSize;
|
||||
_items = new Dictionary<long, List<DtCrowdAgent>>();
|
||||
_listPool = new RcObjectPool<List<DtCrowdAgent>>(() => new List<DtCrowdAgent>());
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -57,6 +60,8 @@ namespace DotRecast.Detour.Crowd
|
|||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var pair in _items)
|
||||
_listPool.Return(pair.Value);
|
||||
_items.Clear();
|
||||
}
|
||||
|
||||
|
@ -74,7 +79,8 @@ namespace DotRecast.Detour.Crowd
|
|||
long key = CombineKey(x, y);
|
||||
if (!_items.TryGetValue(key, out var ids))
|
||||
{
|
||||
ids = new List<DtCrowdAgent>();
|
||||
ids = _listPool.Get();
|
||||
ids.Clear();
|
||||
_items.Add(key, ids);
|
||||
}
|
||||
|
||||
|
@ -83,7 +89,7 @@ namespace DotRecast.Detour.Crowd
|
|||
}
|
||||
}
|
||||
|
||||
public int QueryItems(float minx, float miny, float maxx, float maxy, DtCrowdAgent[] ids, int maxIds)
|
||||
public int QueryItems(float minx, float miny, float maxx, float maxy, Span<int> ids, int maxIds)
|
||||
{
|
||||
int iminx = (int)MathF.Floor(minx * _invCellSize);
|
||||
int iminy = (int)MathF.Floor(miny * _invCellSize);
|
||||
|
@ -110,7 +116,7 @@ namespace DotRecast.Detour.Crowd
|
|||
// Check if the id exists already.
|
||||
int end = n;
|
||||
int i = 0;
|
||||
while (i != end && ids[i] != item)
|
||||
while (i != end && ids[i] != item.idx)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
@ -118,7 +124,7 @@ namespace DotRecast.Detour.Crowd
|
|||
// Item not found, add it.
|
||||
if (i == n)
|
||||
{
|
||||
ids[n++] = item;
|
||||
ids[n++] = item.idx;
|
||||
|
||||
if (n >= maxIds)
|
||||
return n;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.Crowd
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -23,6 +23,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Collections;
|
||||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
using DotRecast.Detour.Dynamic.Io;
|
||||
using DotRecast.Recast;
|
||||
|
@ -40,7 +41,7 @@ namespace DotRecast.Detour.Dynamic
|
|||
private readonly BlockingCollection<IDtDaynmicTileJob> updateQueue = new BlockingCollection<IDtDaynmicTileJob>();
|
||||
private readonly RcAtomicLong currentColliderId = new RcAtomicLong(0);
|
||||
private DtNavMesh _navMesh;
|
||||
private bool dirty = true;
|
||||
private bool _dirty = true;
|
||||
|
||||
public DtDynamicNavMesh(DtVoxelFile voxelFile)
|
||||
{
|
||||
|
@ -62,8 +63,8 @@ namespace DotRecast.Detour.Dynamic
|
|||
navMeshParams.orig.X = voxelFile.bounds[0];
|
||||
navMeshParams.orig.Y = voxelFile.bounds[1];
|
||||
navMeshParams.orig.Z = voxelFile.bounds[2];
|
||||
navMeshParams.tileWidth = voxelFile.cellSize * voxelFile.tileSizeX;
|
||||
navMeshParams.tileHeight = voxelFile.cellSize * voxelFile.tileSizeZ;
|
||||
navMeshParams.tileWidth = voxelFile.useTiles ? voxelFile.cellSize * voxelFile.tileSizeX : voxelFile.bounds[3] - voxelFile.bounds[0];
|
||||
navMeshParams.tileHeight = voxelFile.useTiles ? voxelFile.cellSize * voxelFile.tileSizeZ : voxelFile.bounds[5] - voxelFile.bounds[2];
|
||||
navMeshParams.maxTiles = voxelFile.tiles.Count;
|
||||
navMeshParams.maxPolys = 0x8000;
|
||||
foreach (var t in voxelFile.tiles)
|
||||
|
@ -105,29 +106,6 @@ namespace DotRecast.Detour.Dynamic
|
|||
updateQueue.Add(new DtDynamicTileColliderRemovalJob(colliderId, GetTilesByCollider(colliderId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform full build of the nav mesh
|
||||
*/
|
||||
public void Build()
|
||||
{
|
||||
ProcessQueue();
|
||||
Rebuild(_tiles.Values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform incremental update of the nav mesh
|
||||
*/
|
||||
public bool Update()
|
||||
{
|
||||
return Rebuild(ProcessQueue());
|
||||
}
|
||||
|
||||
private bool Rebuild(ICollection<DtDynamicTile> stream)
|
||||
{
|
||||
foreach (var dynamicTile in stream)
|
||||
Rebuild(dynamicTile);
|
||||
return UpdateNavMesh();
|
||||
}
|
||||
|
||||
private HashSet<DtDynamicTile> ProcessQueue()
|
||||
{
|
||||
|
@ -159,27 +137,49 @@ namespace DotRecast.Detour.Dynamic
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform full build concurrently using the given {@link ExecutorService}
|
||||
*/
|
||||
public Task<bool> Build(TaskFactory executor)
|
||||
// Perform full build of the navmesh
|
||||
public void Build()
|
||||
{
|
||||
ProcessQueue();
|
||||
Rebuild(_tiles.Values);
|
||||
}
|
||||
|
||||
// Perform full build concurrently using the given {@link ExecutorService}
|
||||
public bool Build(TaskFactory executor)
|
||||
{
|
||||
ProcessQueue();
|
||||
return Rebuild(_tiles.Values, executor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform incremental update concurrently using the given {@link ExecutorService}
|
||||
*/
|
||||
public Task<bool> Update(TaskFactory executor)
|
||||
|
||||
// Perform incremental update of the navmesh
|
||||
public bool Update()
|
||||
{
|
||||
return Rebuild(ProcessQueue());
|
||||
}
|
||||
|
||||
// Perform incremental update concurrently using the given {@link ExecutorService}
|
||||
public bool Update(TaskFactory executor)
|
||||
{
|
||||
return Rebuild(ProcessQueue(), executor);
|
||||
}
|
||||
|
||||
private Task<bool> Rebuild(ICollection<DtDynamicTile> tiles, TaskFactory executor)
|
||||
private bool Rebuild(ICollection<DtDynamicTile> tiles)
|
||||
{
|
||||
var tasks = tiles.Select(tile => executor.StartNew(() => Rebuild(tile))).ToArray();
|
||||
return Task.WhenAll(tasks).ContinueWith(k => UpdateNavMesh());
|
||||
foreach (var tile in tiles)
|
||||
Rebuild(tile);
|
||||
|
||||
return UpdateNavMesh();
|
||||
}
|
||||
|
||||
private bool Rebuild(ICollection<DtDynamicTile> tiles, TaskFactory executor)
|
||||
{
|
||||
var tasks = tiles
|
||||
.Select(tile => executor.StartNew(() => Rebuild(tile)))
|
||||
.ToArray();
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
return UpdateNavMesh();
|
||||
}
|
||||
|
||||
private ICollection<DtDynamicTile> GetTiles(float[] bounds)
|
||||
|
@ -189,17 +189,17 @@ namespace DotRecast.Detour.Dynamic
|
|||
return _tiles.Values;
|
||||
}
|
||||
|
||||
int minx = (int)MathF.Floor((bounds[0] - navMeshParams.orig.X) / navMeshParams.tileWidth);
|
||||
int minz = (int)MathF.Floor((bounds[2] - navMeshParams.orig.Z) / navMeshParams.tileHeight);
|
||||
int maxx = (int)MathF.Floor((bounds[3] - navMeshParams.orig.X) / navMeshParams.tileWidth);
|
||||
int maxz = (int)MathF.Floor((bounds[5] - navMeshParams.orig.Z) / navMeshParams.tileHeight);
|
||||
int minx = (int)MathF.Floor((bounds[0] - navMeshParams.orig.X) / navMeshParams.tileWidth) - 1;
|
||||
int minz = (int)MathF.Floor((bounds[2] - navMeshParams.orig.Z) / navMeshParams.tileHeight) - 1;
|
||||
int maxx = (int)MathF.Floor((bounds[3] - navMeshParams.orig.X) / navMeshParams.tileWidth) + 1;
|
||||
int maxz = (int)MathF.Floor((bounds[5] - navMeshParams.orig.Z) / navMeshParams.tileHeight) + 1;
|
||||
List<DtDynamicTile> tiles = new List<DtDynamicTile>();
|
||||
for (int z = minz; z <= maxz; ++z)
|
||||
{
|
||||
for (int x = minx; x <= maxx; ++x)
|
||||
{
|
||||
DtDynamicTile tile = GetTileAt(x, z);
|
||||
if (tile != null)
|
||||
if (tile != null && IntersectsXZ(tile, bounds))
|
||||
{
|
||||
tiles.Add(tile);
|
||||
}
|
||||
|
@ -209,6 +209,12 @@ namespace DotRecast.Detour.Dynamic
|
|||
return tiles;
|
||||
}
|
||||
|
||||
private bool IntersectsXZ(DtDynamicTile tile, float[] bounds)
|
||||
{
|
||||
return tile.voxelTile.boundsMin.X <= bounds[3] && tile.voxelTile.boundsMax.X >= bounds[0] &&
|
||||
tile.voxelTile.boundsMin.Z <= bounds[5] && tile.voxelTile.boundsMax.Z >= bounds[2];
|
||||
}
|
||||
|
||||
private List<DtDynamicTile> GetTilesByCollider(long cid)
|
||||
{
|
||||
return _tiles.Values.Where(t => t.ContainsCollider(cid)).ToList();
|
||||
|
@ -218,19 +224,24 @@ namespace DotRecast.Detour.Dynamic
|
|||
{
|
||||
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
|
||||
option.walkableHeight = config.walkableHeight;
|
||||
dirty = dirty | tile.Build(builder, config, _context);
|
||||
_dirty = _dirty | tile.Build(builder, config, _context);
|
||||
}
|
||||
|
||||
private bool UpdateNavMesh()
|
||||
{
|
||||
if (dirty)
|
||||
if (_dirty)
|
||||
{
|
||||
DtNavMesh navMesh = new DtNavMesh(navMeshParams, MAX_VERTS_PER_POLY);
|
||||
foreach (var t in _tiles.Values)
|
||||
t.AddTo(navMesh);
|
||||
_dirty = false;
|
||||
|
||||
this._navMesh = navMesh;
|
||||
dirty = false;
|
||||
DtNavMesh navMesh = new DtNavMesh();
|
||||
navMesh.Init(navMeshParams, MAX_VERTS_PER_POLY);
|
||||
|
||||
foreach (var t in _tiles.Values)
|
||||
{
|
||||
t.AddTo(navMesh);
|
||||
}
|
||||
|
||||
_navMesh = navMesh;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -258,5 +269,21 @@ namespace DotRecast.Detour.Dynamic
|
|||
{
|
||||
return _tiles.Values.Select(t => t.recastResult).ToList();
|
||||
}
|
||||
|
||||
public void NavMesh(DtNavMesh mesh)
|
||||
{
|
||||
_tiles.Values.ForEach(t =>
|
||||
{
|
||||
const int MAX_NEIS = 32;
|
||||
DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS];
|
||||
int nneis = mesh.GetTilesAt(t.voxelTile.tileX, t.voxelTile.tileZ, tiles, MAX_NEIS);
|
||||
if (0 < nneis)
|
||||
{
|
||||
t.SetMeshData(tiles[0].data);
|
||||
}
|
||||
});
|
||||
_navMesh = mesh;
|
||||
_dirty = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -100,7 +100,7 @@ namespace DotRecast.Detour.Dynamic
|
|||
Math.Min(DtDynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly),
|
||||
config.detailSampleDistance, config.detailSampleMaxError,
|
||||
true, true, true, default, true);
|
||||
RcBuilderResult r = builder.Build(context, vt.tileX, vt.tileZ, null, rcConfig, heightfield);
|
||||
RcBuilderResult r = builder.Build(context, vt.tileX, vt.tileZ, null, rcConfig, heightfield, false);
|
||||
if (config.keepIntermediateResults)
|
||||
{
|
||||
recastResult = r;
|
||||
|
@ -132,8 +132,8 @@ namespace DotRecast.Detour.Dynamic
|
|||
private DtNavMeshCreateParams NavMeshCreateParams(int tilex, int tileZ, float cellSize, float cellHeight,
|
||||
DtDynamicNavMeshConfig config, RcBuilderResult rcResult)
|
||||
{
|
||||
RcPolyMesh m_pmesh = rcResult.GetMesh();
|
||||
RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
|
||||
RcPolyMesh m_pmesh = rcResult.Mesh;
|
||||
RcPolyMeshDetail m_dmesh = rcResult.MeshDetail;
|
||||
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
|
||||
for (int i = 0; i < m_pmesh.npolys; ++i)
|
||||
{
|
||||
|
@ -168,12 +168,12 @@ namespace DotRecast.Detour.Dynamic
|
|||
option.buildBvTree = true;
|
||||
|
||||
option.offMeshConCount = 0;
|
||||
option.offMeshConVerts = new float[0];
|
||||
option.offMeshConRad = new float[0];
|
||||
option.offMeshConDir = new int[0];
|
||||
option.offMeshConAreas = new int[0];
|
||||
option.offMeshConFlags = new int[0];
|
||||
option.offMeshConUserID = new int[0];
|
||||
option.offMeshConVerts = Array.Empty<float>();
|
||||
option.offMeshConRad = Array.Empty<float>();
|
||||
option.offMeshConDir = Array.Empty<int>();
|
||||
option.offMeshConAreas = Array.Empty<int>();
|
||||
option.offMeshConFlags = Array.Empty<int>();
|
||||
option.offMeshConUserID = Array.Empty<int>();
|
||||
return option;
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ namespace DotRecast.Detour.Dynamic
|
|||
{
|
||||
if (meshData != null)
|
||||
{
|
||||
id = navMesh.AddTile(meshData, 0, 0);
|
||||
navMesh.AddTile(meshData, 0, 0, out var id);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -189,5 +189,10 @@ namespace DotRecast.Detour.Dynamic
|
|||
id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetMeshData(DtMeshData data)
|
||||
{
|
||||
this.meshData = data;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -78,7 +78,7 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
walkbableAreaMod, buildMeshDetail);
|
||||
}
|
||||
|
||||
public static DtVoxelFile From(RcConfig config, List<RcBuilderResult> results)
|
||||
public static DtVoxelFile From(RcConfig config, IList<RcBuilderResult> results)
|
||||
{
|
||||
DtVoxelFile f = new DtVoxelFile();
|
||||
f.version = 1;
|
||||
|
@ -109,13 +109,14 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
};
|
||||
foreach (RcBuilderResult r in results)
|
||||
{
|
||||
f.tiles.Add(new DtVoxelTile(r.tileX, r.tileZ, r.GetSolidHeightfield()));
|
||||
f.bounds[0] = Math.Min(f.bounds[0], r.GetSolidHeightfield().bmin.X);
|
||||
f.bounds[1] = Math.Min(f.bounds[1], r.GetSolidHeightfield().bmin.Y);
|
||||
f.bounds[2] = Math.Min(f.bounds[2], r.GetSolidHeightfield().bmin.Z);
|
||||
f.bounds[3] = Math.Max(f.bounds[3], r.GetSolidHeightfield().bmax.X);
|
||||
f.bounds[4] = Math.Max(f.bounds[4], r.GetSolidHeightfield().bmax.Y);
|
||||
f.bounds[5] = Math.Max(f.bounds[5], r.GetSolidHeightfield().bmax.Z);
|
||||
float pad = r.SolidHeightfiled.borderSize * r.SolidHeightfiled.cs;
|
||||
f.tiles.Add(new DtVoxelTile(r.TileX, r.TileZ, r.SolidHeightfiled));
|
||||
f.bounds[0] = Math.Min(f.bounds[0], r.SolidHeightfiled.bmin.X + pad);
|
||||
f.bounds[1] = Math.Min(f.bounds[1], r.SolidHeightfiled.bmin.Y);
|
||||
f.bounds[2] = Math.Min(f.bounds[2], r.SolidHeightfiled.bmin.Z + pad);
|
||||
f.bounds[3] = Math.Max(f.bounds[3], r.SolidHeightfiled.bmax.X - pad);
|
||||
f.bounds[4] = Math.Max(f.bounds[4], r.SolidHeightfiled.bmax.Y);
|
||||
f.bounds[5] = Math.Max(f.bounds[5], r.SolidHeightfiled.bmax.Z - pad);
|
||||
}
|
||||
|
||||
return f;
|
||||
|
@ -155,12 +156,13 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
{
|
||||
RcHeightfield heightfield = vt.Heightfield();
|
||||
f.tiles.Add(new DtVoxelTile(vt.tileX, vt.tileZ, heightfield));
|
||||
f.bounds[0] = Math.Min(f.bounds[0], vt.boundsMin.X);
|
||||
float pad = vt.borderSize * vt.cellSize;
|
||||
f.bounds[0] = Math.Min(f.bounds[0], vt.boundsMin.X + pad);
|
||||
f.bounds[1] = Math.Min(f.bounds[1], vt.boundsMin.Y);
|
||||
f.bounds[2] = Math.Min(f.bounds[2], vt.boundsMin.Z);
|
||||
f.bounds[3] = Math.Max(f.bounds[3], vt.boundsMax.X);
|
||||
f.bounds[2] = Math.Min(f.bounds[2], vt.boundsMin.Z + pad);
|
||||
f.bounds[3] = Math.Max(f.bounds[3], vt.boundsMax.X - pad);
|
||||
f.bounds[4] = Math.Max(f.bounds[4], vt.boundsMax.Y);
|
||||
f.bounds[5] = Math.Max(f.bounds[5], vt.boundsMax.Z);
|
||||
f.bounds[5] = Math.Max(f.bounds[5], vt.boundsMax.Z - pad);
|
||||
}
|
||||
|
||||
return f;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -35,12 +35,12 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
|
||||
public DtVoxelFile Read(BinaryReader stream)
|
||||
{
|
||||
RcByteBuffer buf = IOUtils.ToByteBuffer(stream);
|
||||
RcByteBuffer buf = RcIO.ToByteBuffer(stream);
|
||||
DtVoxelFile file = new DtVoxelFile();
|
||||
int magic = buf.GetInt();
|
||||
if (magic != DtVoxelFile.MAGIC)
|
||||
{
|
||||
magic = IOUtils.SwapEndianness(magic);
|
||||
magic = RcIO.SwapEndianness(magic);
|
||||
if (magic != DtVoxelFile.MAGIC)
|
||||
{
|
||||
throw new IOException("Invalid magic");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -19,12 +19,11 @@ freely, subject to the following restrictions:
|
|||
|
||||
using System.IO;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Detour.Io;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Io
|
||||
{
|
||||
public class DtVoxelFileWriter : DtWriter
|
||||
public class DtVoxelFileWriter
|
||||
{
|
||||
private readonly IRcCompressor _compressor;
|
||||
|
||||
|
@ -40,34 +39,34 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
|
||||
public void Write(BinaryWriter stream, DtVoxelFile f, RcByteOrder byteOrder, bool compression)
|
||||
{
|
||||
Write(stream, DtVoxelFile.MAGIC, byteOrder);
|
||||
Write(stream, DtVoxelFile.VERSION_EXPORTER_RECAST4J | (compression ? DtVoxelFile.VERSION_COMPRESSION_LZ4 : 0), byteOrder);
|
||||
Write(stream, f.walkableRadius, byteOrder);
|
||||
Write(stream, f.walkableHeight, byteOrder);
|
||||
Write(stream, f.walkableClimb, byteOrder);
|
||||
Write(stream, f.walkableSlopeAngle, byteOrder);
|
||||
Write(stream, f.cellSize, byteOrder);
|
||||
Write(stream, f.maxSimplificationError, byteOrder);
|
||||
Write(stream, f.maxEdgeLen, byteOrder);
|
||||
Write(stream, f.minRegionArea, byteOrder);
|
||||
Write(stream, f.regionMergeArea, byteOrder);
|
||||
Write(stream, f.vertsPerPoly, byteOrder);
|
||||
Write(stream, f.buildMeshDetail);
|
||||
Write(stream, f.detailSampleDistance, byteOrder);
|
||||
Write(stream, f.detailSampleMaxError, byteOrder);
|
||||
Write(stream, f.useTiles);
|
||||
Write(stream, f.tileSizeX, byteOrder);
|
||||
Write(stream, f.tileSizeZ, byteOrder);
|
||||
Write(stream, f.rotation.X, byteOrder);
|
||||
Write(stream, f.rotation.Y, byteOrder);
|
||||
Write(stream, f.rotation.Z, byteOrder);
|
||||
Write(stream, f.bounds[0], byteOrder);
|
||||
Write(stream, f.bounds[1], byteOrder);
|
||||
Write(stream, f.bounds[2], byteOrder);
|
||||
Write(stream, f.bounds[3], byteOrder);
|
||||
Write(stream, f.bounds[4], byteOrder);
|
||||
Write(stream, f.bounds[5], byteOrder);
|
||||
Write(stream, f.tiles.Count, byteOrder);
|
||||
RcIO.Write(stream, DtVoxelFile.MAGIC, byteOrder);
|
||||
RcIO.Write(stream, DtVoxelFile.VERSION_EXPORTER_RECAST4J | (compression ? DtVoxelFile.VERSION_COMPRESSION_LZ4 : 0), byteOrder);
|
||||
RcIO.Write(stream, f.walkableRadius, byteOrder);
|
||||
RcIO.Write(stream, f.walkableHeight, byteOrder);
|
||||
RcIO.Write(stream, f.walkableClimb, byteOrder);
|
||||
RcIO.Write(stream, f.walkableSlopeAngle, byteOrder);
|
||||
RcIO.Write(stream, f.cellSize, byteOrder);
|
||||
RcIO.Write(stream, f.maxSimplificationError, byteOrder);
|
||||
RcIO.Write(stream, f.maxEdgeLen, byteOrder);
|
||||
RcIO.Write(stream, f.minRegionArea, byteOrder);
|
||||
RcIO.Write(stream, f.regionMergeArea, byteOrder);
|
||||
RcIO.Write(stream, f.vertsPerPoly, byteOrder);
|
||||
RcIO.Write(stream, f.buildMeshDetail);
|
||||
RcIO.Write(stream, f.detailSampleDistance, byteOrder);
|
||||
RcIO.Write(stream, f.detailSampleMaxError, byteOrder);
|
||||
RcIO.Write(stream, f.useTiles);
|
||||
RcIO.Write(stream, f.tileSizeX, byteOrder);
|
||||
RcIO.Write(stream, f.tileSizeZ, byteOrder);
|
||||
RcIO.Write(stream, f.rotation.X, byteOrder);
|
||||
RcIO.Write(stream, f.rotation.Y, byteOrder);
|
||||
RcIO.Write(stream, f.rotation.Z, byteOrder);
|
||||
RcIO.Write(stream, f.bounds[0], byteOrder);
|
||||
RcIO.Write(stream, f.bounds[1], byteOrder);
|
||||
RcIO.Write(stream, f.bounds[2], byteOrder);
|
||||
RcIO.Write(stream, f.bounds[3], byteOrder);
|
||||
RcIO.Write(stream, f.bounds[4], byteOrder);
|
||||
RcIO.Write(stream, f.bounds[5], byteOrder);
|
||||
RcIO.Write(stream, f.tiles.Count, byteOrder);
|
||||
foreach (DtVoxelTile t in f.tiles)
|
||||
{
|
||||
WriteTile(stream, t, byteOrder, compression);
|
||||
|
@ -76,26 +75,26 @@ namespace DotRecast.Detour.Dynamic.Io
|
|||
|
||||
public void WriteTile(BinaryWriter stream, DtVoxelTile tile, RcByteOrder byteOrder, bool compression)
|
||||
{
|
||||
Write(stream, tile.tileX, byteOrder);
|
||||
Write(stream, tile.tileZ, byteOrder);
|
||||
Write(stream, tile.width, byteOrder);
|
||||
Write(stream, tile.depth, byteOrder);
|
||||
Write(stream, tile.borderSize, byteOrder);
|
||||
Write(stream, tile.boundsMin.X, byteOrder);
|
||||
Write(stream, tile.boundsMin.Y, byteOrder);
|
||||
Write(stream, tile.boundsMin.Z, byteOrder);
|
||||
Write(stream, tile.boundsMax.X, byteOrder);
|
||||
Write(stream, tile.boundsMax.Y, byteOrder);
|
||||
Write(stream, tile.boundsMax.Z, byteOrder);
|
||||
Write(stream, tile.cellSize, byteOrder);
|
||||
Write(stream, tile.cellHeight, byteOrder);
|
||||
RcIO.Write(stream, tile.tileX, byteOrder);
|
||||
RcIO.Write(stream, tile.tileZ, byteOrder);
|
||||
RcIO.Write(stream, tile.width, byteOrder);
|
||||
RcIO.Write(stream, tile.depth, byteOrder);
|
||||
RcIO.Write(stream, tile.borderSize, byteOrder);
|
||||
RcIO.Write(stream, tile.boundsMin.X, byteOrder);
|
||||
RcIO.Write(stream, tile.boundsMin.Y, byteOrder);
|
||||
RcIO.Write(stream, tile.boundsMin.Z, byteOrder);
|
||||
RcIO.Write(stream, tile.boundsMax.X, byteOrder);
|
||||
RcIO.Write(stream, tile.boundsMax.Y, byteOrder);
|
||||
RcIO.Write(stream, tile.boundsMax.Z, byteOrder);
|
||||
RcIO.Write(stream, tile.cellSize, byteOrder);
|
||||
RcIO.Write(stream, tile.cellHeight, byteOrder);
|
||||
byte[] bytes = tile.spanData;
|
||||
if (compression)
|
||||
{
|
||||
bytes = _compressor.Compress(bytes);
|
||||
}
|
||||
|
||||
Write(stream, bytes.Length, byteOrder);
|
||||
RcIO.Write(stream, bytes.Length, byteOrder);
|
||||
stream.Write(bytes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -40,20 +40,20 @@ namespace DotRecast.Detour.Extras
|
|||
BVItem it = new BVItem();
|
||||
items[i] = it;
|
||||
it.i = i;
|
||||
RcVec3f bmin = RcVecUtils.Create(data.verts, data.polys[i].verts[0] * 3);
|
||||
RcVec3f bmax = RcVecUtils.Create(data.verts, data.polys[i].verts[0] * 3);
|
||||
RcVec3f bmin = RcVec.Create(data.verts, data.polys[i].verts[0] * 3);
|
||||
RcVec3f bmax = RcVec.Create(data.verts, data.polys[i].verts[0] * 3);
|
||||
for (int j = 1; j < data.polys[i].vertCount; j++)
|
||||
{
|
||||
bmin = RcVecUtils.Min(bmin, data.verts, data.polys[i].verts[j] * 3);
|
||||
bmax = RcVecUtils.Max(bmax, data.verts, data.polys[i].verts[j] * 3);
|
||||
bmin = RcVec3f.Min(bmin, RcVec.Create(data.verts, data.polys[i].verts[j] * 3));
|
||||
bmax = RcVec3f.Max(bmax, RcVec.Create(data.verts, data.polys[i].verts[j] * 3));
|
||||
}
|
||||
|
||||
it.bmin[0] = Math.Clamp((int)((bmin.X - data.header.bmin.X) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmin[1] = Math.Clamp((int)((bmin.Y - data.header.bmin.Y) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmin[2] = Math.Clamp((int)((bmin.Z - data.header.bmin.Z) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmax[0] = Math.Clamp((int)((bmax.X - data.header.bmin.X) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmax[1] = Math.Clamp((int)((bmax.Y - data.header.bmin.Y) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmax[2] = Math.Clamp((int)((bmax.Z - data.header.bmin.Z) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmin.X = Math.Clamp((int)((bmin.X - data.header.bmin.X) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmin.Y = Math.Clamp((int)((bmin.Y - data.header.bmin.Y) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmin.Z = Math.Clamp((int)((bmin.Z - data.header.bmin.Z) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmax.X = Math.Clamp((int)((bmax.X - data.header.bmin.X) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmax.Y = Math.Clamp((int)((bmax.Y - data.header.bmin.Y) * quantFactor), 0, 0x7fffffff);
|
||||
it.bmax.Z = Math.Clamp((int)((bmax.Z - data.header.bmin.Z) * quantFactor), 0, 0x7fffffff);
|
||||
}
|
||||
|
||||
return DtNavMeshBuilder.Subdivide(items, data.header.polyCount, 0, data.header.polyCount, 0, nodes);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
protected void SampleGround(JumpLinkBuilderConfig acfg, EdgeSampler es, ComputeNavMeshHeight heightFunc)
|
||||
{
|
||||
float cs = acfg.cellSize;
|
||||
float dist = MathF.Sqrt(RcVecUtils.Dist2DSqr(es.start.p, es.start.q));
|
||||
float dist = MathF.Sqrt(RcVec.Dist2DSqr(es.start.p, es.start.q));
|
||||
int ngsamples = Math.Max(2, (int)MathF.Ceiling(dist / cs));
|
||||
|
||||
SampleGroundSegment(heightFunc, es.start, ngsamples);
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.Extras.Jumplink
|
||||
{
|
||||
public class ClimbTrajectory : Trajectory
|
||||
public class ClimbTrajectory : ITrajectory
|
||||
{
|
||||
public override RcVec3f Apply(RcVec3f start, RcVec3f end, float u)
|
||||
public RcVec3f Apply(RcVec3f start, RcVec3f end, float u)
|
||||
{
|
||||
return new RcVec3f()
|
||||
{
|
||||
X = Lerp(start.X, end.X, Math.Min(2f * u, 1f)),
|
||||
Y = Lerp(start.Y, end.Y, Math.Max(0f, 2f * u - 1f)),
|
||||
Z = Lerp(start.Z, end.Z, Math.Min(2f * u, 1f))
|
||||
X = RcMath.Lerp(start.X, end.X, Math.Min(2f * u, 1f)),
|
||||
Y = RcMath.Lerp(start.Y, end.Y, Math.Max(0f, 2f * u - 1f)),
|
||||
Z = RcMath.Lerp(start.Z, end.Z, Math.Min(2f * u, 1f))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast;
|
||||
using static DotRecast.Recast.RcConstants;
|
||||
|
||||
|
||||
namespace DotRecast.Detour.Extras.Jumplink
|
||||
{
|
||||
using static RcRecast;
|
||||
|
||||
public class EdgeExtractor
|
||||
{
|
||||
public JumpEdge[] ExtractEdges(RcPolyMesh mesh)
|
||||
|
|
|
@ -7,13 +7,13 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
public readonly GroundSegment start = new GroundSegment();
|
||||
public readonly List<GroundSegment> end = new List<GroundSegment>();
|
||||
public readonly Trajectory trajectory;
|
||||
public readonly ITrajectory trajectory;
|
||||
|
||||
public readonly RcVec3f ax = new RcVec3f();
|
||||
public readonly RcVec3f ay = new RcVec3f();
|
||||
public readonly RcVec3f az = new RcVec3f();
|
||||
|
||||
public EdgeSampler(JumpEdge edge, Trajectory trajectory)
|
||||
public EdgeSampler(JumpEdge edge, ITrajectory trajectory)
|
||||
{
|
||||
this.trajectory = trajectory;
|
||||
ax = RcVec3f.Subtract(edge.sq, edge.sp);
|
||||
|
|
|
@ -3,7 +3,7 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Detour.Extras.Jumplink
|
||||
{
|
||||
class EdgeSamplerFactory
|
||||
public class EdgeSamplerFactory
|
||||
{
|
||||
public EdgeSampler Get(JumpLinkBuilderConfig acfg, JumpLinkType type, JumpEdge edge)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
public class GroundSample
|
||||
{
|
||||
public RcVec3f p = new RcVec3f();
|
||||
public RcVec3f p;
|
||||
public bool validTrajectory;
|
||||
public bool validHeight;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
public class GroundSegment
|
||||
{
|
||||
public RcVec3f p = new RcVec3f();
|
||||
public RcVec3f q = new RcVec3f();
|
||||
public RcVec3f p;
|
||||
public RcVec3f q;
|
||||
public GroundSample[] gsamples;
|
||||
public float height;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.Extras.Jumplink
|
||||
{
|
||||
public interface ITrajectory
|
||||
{
|
||||
RcVec3f Apply(RcVec3f start, RcVec3f end, float u);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,6 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
public GroundSample[] endSamples;
|
||||
public GroundSegment start;
|
||||
public GroundSegment end;
|
||||
public Trajectory trajectory;
|
||||
public ITrajectory trajectory;
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
public JumpLinkBuilder(IList<RcBuilderResult> results)
|
||||
{
|
||||
this.results = results;
|
||||
edges = results.Select(r => edgeExtractor.ExtractEdges(r.GetMesh())).ToList();
|
||||
edges = results.Select(r => edgeExtractor.ExtractEdges(r.Mesh)).ToList();
|
||||
}
|
||||
|
||||
public List<JumpLink> Build(JumpLinkBuilderConfig acfg, JumpLinkType type)
|
||||
|
@ -43,7 +43,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
{
|
||||
EdgeSampler es = edgeSamplerFactory.Get(acfg, type, edge);
|
||||
groundSampler.Sample(acfg, result, es);
|
||||
trajectorySampler.Sample(acfg, result.GetSolidHeightfield(), es);
|
||||
trajectorySampler.Sample(acfg, result.SolidHeightfiled, es);
|
||||
JumpSegment[] jumpSegments = jumpSegmentBuilder.Build(acfg, es);
|
||||
return BuildJumpLinks(acfg, es, jumpSegments);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
GroundSegment end = es.end[js.groundSegment];
|
||||
RcVec3f ep = end.gsamples[js.startSample].p;
|
||||
RcVec3f eq = end.gsamples[js.startSample + js.samples - 1].p;
|
||||
float d = Math.Min(RcVecUtils.Dist2DSqr(sp, sq), RcVecUtils.Dist2DSqr(ep, eq));
|
||||
float d = Math.Min(RcVec.Dist2DSqr(sp, sq), RcVec.Dist2DSqr(ep, eq));
|
||||
if (d >= 4 * acfg.agentRadius * acfg.agentRadius)
|
||||
{
|
||||
JumpLink link = new JumpLink();
|
||||
|
|
|
@ -4,7 +4,7 @@ using DotRecast.Core;
|
|||
|
||||
namespace DotRecast.Detour.Extras.Jumplink
|
||||
{
|
||||
class JumpSegmentBuilder
|
||||
public class JumpSegmentBuilder
|
||||
{
|
||||
public JumpSegment[] Build(JumpLinkBuilderConfig acfg, EdgeSampler es)
|
||||
{
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.Extras.Jumplink
|
||||
{
|
||||
public class JumpTrajectory : Trajectory
|
||||
public class JumpTrajectory : ITrajectory
|
||||
{
|
||||
private readonly float jumpHeight;
|
||||
|
||||
|
@ -12,13 +13,13 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
this.jumpHeight = jumpHeight;
|
||||
}
|
||||
|
||||
public override RcVec3f Apply(RcVec3f start, RcVec3f end, float u)
|
||||
public RcVec3f Apply(RcVec3f start, RcVec3f end, float u)
|
||||
{
|
||||
return new RcVec3f
|
||||
{
|
||||
X = Lerp(start.X, end.X, u),
|
||||
X = RcMath.Lerp(start.X, end.X, u),
|
||||
Y = InterpolateHeight(start.Y, end.Y, u),
|
||||
Z = Lerp(start.Z, end.Z, u)
|
||||
Z = RcMath.Lerp(start.Z, end.Z, u)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
using DotRecast.Recast;
|
||||
|
||||
namespace DotRecast.Detour.Extras.Jumplink
|
||||
{
|
||||
class NavMeshGroundSampler : AbstractGroundSampler
|
||||
public class NavMeshGroundSampler : AbstractGroundSampler
|
||||
{
|
||||
public override void Sample(JumpLinkBuilderConfig acfg, RcBuilderResult result, EdgeSampler es)
|
||||
{
|
||||
|
@ -16,27 +15,34 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
private DtNavMeshQuery CreateNavMesh(RcBuilderResult r, float agentRadius, float agentHeight, float agentClimb)
|
||||
{
|
||||
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
|
||||
option.verts = r.GetMesh().verts;
|
||||
option.vertCount = r.GetMesh().nverts;
|
||||
option.polys = r.GetMesh().polys;
|
||||
option.polyAreas = r.GetMesh().areas;
|
||||
option.polyFlags = r.GetMesh().flags;
|
||||
option.polyCount = r.GetMesh().npolys;
|
||||
option.nvp = r.GetMesh().nvp;
|
||||
option.detailMeshes = r.GetMeshDetail().meshes;
|
||||
option.detailVerts = r.GetMeshDetail().verts;
|
||||
option.detailVertsCount = r.GetMeshDetail().nverts;
|
||||
option.detailTris = r.GetMeshDetail().tris;
|
||||
option.detailTriCount = r.GetMeshDetail().ntris;
|
||||
option.verts = r.Mesh.verts;
|
||||
option.vertCount = r.Mesh.nverts;
|
||||
option.polys = r.Mesh.polys;
|
||||
option.polyAreas = r.Mesh.areas;
|
||||
option.polyFlags = r.Mesh.flags;
|
||||
option.polyCount = r.Mesh.npolys;
|
||||
option.nvp = r.Mesh.nvp;
|
||||
option.detailMeshes = r.MeshDetail.meshes;
|
||||
option.detailVerts = r.MeshDetail.verts;
|
||||
option.detailVertsCount = r.MeshDetail.nverts;
|
||||
option.detailTris = r.MeshDetail.tris;
|
||||
option.detailTriCount = r.MeshDetail.ntris;
|
||||
option.walkableRadius = agentRadius;
|
||||
option.walkableHeight = agentHeight;
|
||||
option.walkableClimb = agentClimb;
|
||||
option.bmin = r.GetMesh().bmin;
|
||||
option.bmax = r.GetMesh().bmax;
|
||||
option.cs = r.GetMesh().cs;
|
||||
option.ch = r.GetMesh().ch;
|
||||
option.bmin = r.Mesh.bmin;
|
||||
option.bmax = r.Mesh.bmax;
|
||||
option.cs = r.Mesh.cs;
|
||||
option.ch = r.Mesh.ch;
|
||||
option.buildBvTree = true;
|
||||
return new DtNavMeshQuery(new DtNavMesh(DtNavMeshBuilder.CreateNavMeshData(option), option.nvp, 0));
|
||||
var mesh = new DtNavMesh();
|
||||
var status = mesh.Init(DtNavMeshBuilder.CreateNavMeshData(option), option.nvp, 0);
|
||||
if (status.Failed())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DtNavMeshQuery(mesh);
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,25 +52,12 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
|
||||
RcVec3f halfExtents = new RcVec3f { X = cs, Y = heightRange, Z = cs };
|
||||
float maxHeight = pt.Y + heightRange;
|
||||
RcAtomicBoolean found = new RcAtomicBoolean();
|
||||
RcAtomicFloat minHeight = new RcAtomicFloat(pt.Y);
|
||||
var query = new DtHeightSamplePolyQuery(navMeshQuery, pt, pt.Y, maxHeight);
|
||||
navMeshQuery.QueryPolygons(pt, halfExtents, DtQueryNoOpFilter.Shared, ref query);
|
||||
|
||||
navMeshQuery.QueryPolygons(pt, halfExtents, DtQueryNoOpFilter.Shared, new PolyQueryInvoker((tile, poly, refs) =>
|
||||
if (query.Found)
|
||||
{
|
||||
var status = navMeshQuery.GetPolyHeight(refs, pt, out var h);
|
||||
if (status.Succeeded())
|
||||
{
|
||||
if (h > minHeight.Get() && h < maxHeight)
|
||||
{
|
||||
minHeight.Exchange(h);
|
||||
found.Set(true);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
if (found.Get())
|
||||
{
|
||||
height = minHeight.Get();
|
||||
height = query.MinHeight;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace DotRecast.Detour.Extras.Jumplink
|
||||
{
|
||||
public class PolyQueryInvoker : IDtPolyQuery
|
||||
{
|
||||
public readonly Action<DtMeshTile, DtPoly, long> _callback;
|
||||
|
||||
public PolyQueryInvoker(Action<DtMeshTile, DtPoly, long> callback)
|
||||
{
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
public void Process(DtMeshTile tile, DtPoly poly, long refs)
|
||||
{
|
||||
_callback?.Invoke(tile, poly, refs);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.Extras.Jumplink
|
||||
{
|
||||
public class Trajectory
|
||||
{
|
||||
public float Lerp(float f, float g, float u)
|
||||
{
|
||||
return u * g + (1f - u) * f;
|
||||
}
|
||||
|
||||
public virtual RcVec3f Apply(RcVec3f start, RcVec3f end, float u)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ using DotRecast.Recast;
|
|||
|
||||
namespace DotRecast.Detour.Extras.Jumplink
|
||||
{
|
||||
class TrajectorySampler
|
||||
public class TrajectorySampler
|
||||
{
|
||||
public void Sample(JumpLinkBuilderConfig acfg, RcHeightfield heightfield, EdgeSampler es)
|
||||
{
|
||||
|
@ -32,10 +32,10 @@ namespace DotRecast.Detour.Extras.Jumplink
|
|||
}
|
||||
}
|
||||
|
||||
private bool SampleTrajectory(JumpLinkBuilderConfig acfg, RcHeightfield solid, RcVec3f pa, RcVec3f pb, Trajectory tra)
|
||||
private bool SampleTrajectory(JumpLinkBuilderConfig acfg, RcHeightfield solid, RcVec3f pa, RcVec3f pb, ITrajectory tra)
|
||||
{
|
||||
float cs = Math.Min(acfg.cellSize, acfg.cellHeight);
|
||||
float d = RcVecUtils.Dist2D(pa, pb) + MathF.Abs(pa.Y - pb.Y);
|
||||
float d = RcVec.Dist2D(pa, pb) + MathF.Abs(pa.Y - pb.Y);
|
||||
int nsamples = Math.Max(2, (int)MathF.Ceiling(d / cs));
|
||||
for (int i = 0; i < nsamples; ++i)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -22,6 +23,8 @@ using DotRecast.Core;
|
|||
|
||||
namespace DotRecast.Detour.Extras.Unity.Astar
|
||||
{
|
||||
using static DtDetour;
|
||||
|
||||
public class GraphMeshDataReader : ZipBinaryReader
|
||||
{
|
||||
public const float INT_PRECISION_FACTOR = 1000f;
|
||||
|
@ -76,7 +79,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
int nodeCount = buffer.GetInt();
|
||||
DtPoly[] nodes = new DtPoly[nodeCount];
|
||||
DtPolyDetail[] detailNodes = new DtPolyDetail[nodeCount];
|
||||
float[] detailVerts = new float[0];
|
||||
float[] detailVerts = Array.Empty<float>();
|
||||
int[] detailTris = new int[4 * nodeCount];
|
||||
int vertMask = GetVertMask(vertsCount);
|
||||
float ymin = float.PositiveInfinity;
|
||||
|
@ -98,9 +101,9 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
ymax = Math.Max(ymax, verts[nodes[i].verts[1] * 3 + 1]);
|
||||
ymax = Math.Max(ymax, verts[nodes[i].verts[2] * 3 + 1]);
|
||||
int vertBase = 0;
|
||||
int vertCount = 0;
|
||||
byte vertCount = 0;
|
||||
int triBase = i;
|
||||
int triCount = 1;
|
||||
byte triCount = 1;
|
||||
detailNodes[i] = new DtPolyDetail(vertBase, triBase, vertCount, triCount);
|
||||
detailTris[4 * i] = 0;
|
||||
detailTris[4 * i + 1] = 1;
|
||||
|
@ -116,15 +119,15 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
tiles[tileIndex].detailVerts = detailVerts;
|
||||
tiles[tileIndex].detailTris = detailTris;
|
||||
DtMeshHeader header = new DtMeshHeader();
|
||||
header.magic = DtNavMesh.DT_NAVMESH_MAGIC;
|
||||
header.version = DtNavMesh.DT_NAVMESH_VERSION;
|
||||
header.magic = DT_NAVMESH_MAGIC;
|
||||
header.version = DT_NAVMESH_VERSION;
|
||||
header.x = x;
|
||||
header.y = z;
|
||||
header.polyCount = nodeCount;
|
||||
header.vertCount = vertsCount;
|
||||
header.detailMeshCount = nodeCount;
|
||||
header.detailTriCount = nodeCount;
|
||||
header.maxLinkCount = nodeCount * 3 * 2; // XXX: Needed by Recast, not needed by recast4j
|
||||
header.maxLinkCount = nodeCount * 3 * 2; // needed by Recast, not needed by recast4j, needed by DotRecast
|
||||
header.bmin.X = meta.forcedBoundsCenter.x - 0.5f * meta.forcedBoundsSize.x +
|
||||
meta.cellSize * meta.tileSizeX * x;
|
||||
header.bmin.Y = ymin;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -21,6 +22,8 @@ using System.Collections.Generic;
|
|||
|
||||
namespace DotRecast.Detour.Extras.Unity.Astar
|
||||
{
|
||||
using static DtDetour;
|
||||
|
||||
public class LinkBuilder
|
||||
{
|
||||
// Process connections and transform them into recast neighbour flags
|
||||
|
@ -65,19 +68,19 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
{
|
||||
if (neighbourTile.header.bmin.X > tile.header.bmin.X)
|
||||
{
|
||||
node.neis[DtPolyUtils.FindEdge(node, tile, neighbourTile.header.bmin.X, 0)] = DtNavMesh.DT_EXT_LINK;
|
||||
node.neis[DtPolyUtils.FindEdge(node, tile, neighbourTile.header.bmin.X, 0)] = DT_EXT_LINK;
|
||||
}
|
||||
else if (neighbourTile.header.bmin.X < tile.header.bmin.X)
|
||||
{
|
||||
node.neis[DtPolyUtils.FindEdge(node, tile, tile.header.bmin.X, 0)] = DtNavMesh.DT_EXT_LINK | 4;
|
||||
node.neis[DtPolyUtils.FindEdge(node, tile, tile.header.bmin.X, 0)] = DT_EXT_LINK | 4;
|
||||
}
|
||||
else if (neighbourTile.header.bmin.Z > tile.header.bmin.Z)
|
||||
{
|
||||
node.neis[DtPolyUtils.FindEdge(node, tile, neighbourTile.header.bmin.Z, 2)] = DtNavMesh.DT_EXT_LINK | 2;
|
||||
node.neis[DtPolyUtils.FindEdge(node, tile, neighbourTile.header.bmin.Z, 2)] = DT_EXT_LINK | 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.neis[DtPolyUtils.FindEdge(node, tile, tile.header.bmin.Z, 2)] = DtNavMesh.DT_EXT_LINK | 6;
|
||||
node.neis[DtPolyUtils.FindEdge(node, tile, tile.header.bmin.Z, 2)] = DT_EXT_LINK | 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -65,10 +66,11 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
option.orig.X = -0.5f * graphMeta.forcedBoundsSize.x + graphMeta.forcedBoundsCenter.x;
|
||||
option.orig.Y = -0.5f * graphMeta.forcedBoundsSize.y + graphMeta.forcedBoundsCenter.y;
|
||||
option.orig.Z = -0.5f * graphMeta.forcedBoundsSize.z + graphMeta.forcedBoundsCenter.z;
|
||||
DtNavMesh mesh = new DtNavMesh(option, 3);
|
||||
DtNavMesh mesh = new DtNavMesh();
|
||||
mesh.Init(option, 3);
|
||||
foreach (DtMeshData t in graphMeshData.tiles)
|
||||
{
|
||||
mesh.AddTile(t, 0, 0);
|
||||
mesh.AddTile(t, 0, 0, out _);
|
||||
}
|
||||
|
||||
meshes[graphIndex] = mesh;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -31,7 +32,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
|||
ZipArchiveEntry graphReferences = file.GetEntry(filename);
|
||||
using var entryStream = graphReferences.Open();
|
||||
using var br = new BinaryReader(entryStream);
|
||||
RcByteBuffer buffer = IOUtils.ToByteBuffer(br);
|
||||
RcByteBuffer buffer = RcIO.ToByteBuffer(br);
|
||||
buffer.Order(RcByteOrder.LITTLE_ENDIAN);
|
||||
return buffer;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour.TileCache
|
||||
namespace DotRecast.Detour.TileCache
|
||||
{
|
||||
/// Flags for addTile
|
||||
public class DtCompressedTileFlags
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Detour.TileCache
|
||||
{
|
||||
|
@ -7,8 +7,9 @@ namespace DotRecast.Detour.TileCache
|
|||
public const int DT_LAYER_MAX_NEIS = 16;
|
||||
|
||||
public int area;
|
||||
public List<int> neis = new List<int>(DT_LAYER_MAX_NEIS);
|
||||
public int regId;
|
||||
public int areaId;
|
||||
public byte[] neis = new byte[DT_LAYER_MAX_NEIS];
|
||||
public byte nneis;
|
||||
public byte regId;
|
||||
public byte areaId;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.TileCache
|
||||
{
|
||||
public class DtObstacleBox
|
||||
{
|
||||
public RcVec3f bmin;
|
||||
public RcVec3f bmax;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.TileCache
|
||||
{
|
||||
public class DtObstacleCylinder
|
||||
{
|
||||
public RcVec3f pos;
|
||||
public float radius;
|
||||
public float height;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.TileCache
|
||||
{
|
||||
public class DtObstacleOrientedBox
|
||||
{
|
||||
public RcVec3f center;
|
||||
public RcVec3f extents;
|
||||
public readonly float[] rotAux = new float[2]; // { Cos(0.5f*angle)*Sin(-0.5f*angle); Cos(0.5f*angle)*Cos(0.5f*angle) - 0.5 }
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Detour.TileCache
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -26,6 +26,8 @@ using DotRecast.Detour.TileCache.Io;
|
|||
|
||||
namespace DotRecast.Detour.TileCache
|
||||
{
|
||||
using static DtDetour;
|
||||
|
||||
public class DtTileCache
|
||||
{
|
||||
private int m_tileLutSize; // < Tile hash lookup size (must be pot).
|
||||
|
@ -51,9 +53,6 @@ namespace DotRecast.Detour.TileCache
|
|||
private readonly List<DtObstacleRequest> m_reqs = new List<DtObstacleRequest>();
|
||||
private readonly List<long> m_update = new List<long>();
|
||||
|
||||
private readonly DtTileCacheBuilder builder = new DtTileCacheBuilder();
|
||||
private readonly DtTileCacheLayerHeaderReader tileReader = new DtTileCacheLayerHeaderReader();
|
||||
|
||||
public DtTileCache(DtTileCacheParams option, DtTileCacheStorageParams storageParams, DtNavMesh navmesh, IRcCompressor tcomp, IDtTileCacheMeshProcess tmprocs)
|
||||
{
|
||||
m_params = option;
|
||||
|
@ -160,7 +159,7 @@ namespace DotRecast.Detour.TileCache
|
|||
List<long> tiles = new List<long>();
|
||||
|
||||
// Find tile based on hash.
|
||||
int h = DtNavMesh.ComputeTileHash(tx, ty, m_tileLutMask);
|
||||
int h = ComputeTileHash(tx, ty, m_tileLutMask);
|
||||
DtCompressedTile tile = m_posLookup[h];
|
||||
while (tile != null)
|
||||
{
|
||||
|
@ -178,7 +177,7 @@ namespace DotRecast.Detour.TileCache
|
|||
DtCompressedTile GetTileAt(int tx, int ty, int tlayer)
|
||||
{
|
||||
// Find tile based on hash.
|
||||
int h = DtNavMesh.ComputeTileHash(tx, ty, m_tileLutMask);
|
||||
int h = ComputeTileHash(tx, ty, m_tileLutMask);
|
||||
DtCompressedTile tile = m_posLookup[h];
|
||||
while (tile != null)
|
||||
{
|
||||
|
@ -243,7 +242,7 @@ namespace DotRecast.Detour.TileCache
|
|||
// Make sure the data is in right format.
|
||||
RcByteBuffer buf = new RcByteBuffer(data);
|
||||
buf.Order(m_storageParams.Order);
|
||||
DtTileCacheLayerHeader header = tileReader.Read(buf, m_storageParams.Compatibility);
|
||||
DtTileCacheLayerHeader header = DtTileCacheLayerHeaderReader.Read(buf, m_storageParams.Compatibility);
|
||||
// Make sure the location is free.
|
||||
if (GetTileAt(header.tx, header.ty, header.tlayer) != null)
|
||||
{
|
||||
|
@ -266,7 +265,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// Insert tile into the position lut.
|
||||
int h = DtNavMesh.ComputeTileHash(header.tx, header.ty, m_tileLutMask);
|
||||
int h = ComputeTileHash(header.tx, header.ty, m_tileLutMask);
|
||||
tile.next = m_posLookup[h];
|
||||
m_posLookup[h] = tile;
|
||||
|
||||
|
@ -305,7 +304,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// Remove tile from hash lookup.
|
||||
int h = DtNavMesh.ComputeTileHash(tile.header.tx, tile.header.ty, m_tileLutMask);
|
||||
int h = ComputeTileHash(tile.header.tx, tile.header.ty, m_tileLutMask);
|
||||
DtCompressedTile prev = null;
|
||||
DtCompressedTile cur = m_posLookup[h];
|
||||
while (cur != null)
|
||||
|
@ -349,11 +348,11 @@ namespace DotRecast.Detour.TileCache
|
|||
public long AddObstacle(RcVec3f pos, float radius, float height)
|
||||
{
|
||||
DtTileCacheObstacle ob = AllocObstacle();
|
||||
ob.type = DtTileCacheObstacleType.CYLINDER;
|
||||
ob.type = DtTileCacheObstacleType.DT_OBSTACLE_CYLINDER;
|
||||
|
||||
ob.pos = pos;
|
||||
ob.radius = radius;
|
||||
ob.height = height;
|
||||
ob.cylinder.pos = pos;
|
||||
ob.cylinder.radius = radius;
|
||||
ob.cylinder.height = height;
|
||||
|
||||
return AddObstacleRequest(ob).refs;
|
||||
}
|
||||
|
@ -362,10 +361,10 @@ namespace DotRecast.Detour.TileCache
|
|||
public long AddBoxObstacle(RcVec3f bmin, RcVec3f bmax)
|
||||
{
|
||||
DtTileCacheObstacle ob = AllocObstacle();
|
||||
ob.type = DtTileCacheObstacleType.BOX;
|
||||
ob.type = DtTileCacheObstacleType.DT_OBSTACLE_BOX;
|
||||
|
||||
ob.bmin = bmin;
|
||||
ob.bmax = bmax;
|
||||
ob.box.bmin = bmin;
|
||||
ob.box.bmax = bmax;
|
||||
|
||||
return AddObstacleRequest(ob).refs;
|
||||
}
|
||||
|
@ -374,13 +373,13 @@ namespace DotRecast.Detour.TileCache
|
|||
public long AddBoxObstacle(RcVec3f center, RcVec3f extents, float yRadians)
|
||||
{
|
||||
DtTileCacheObstacle ob = AllocObstacle();
|
||||
ob.type = DtTileCacheObstacleType.ORIENTED_BOX;
|
||||
ob.center = center;
|
||||
ob.extents = extents;
|
||||
ob.type = DtTileCacheObstacleType.DT_OBSTACLE_ORIENTED_BOX;
|
||||
ob.orientedBox.center = center;
|
||||
ob.orientedBox.extents = extents;
|
||||
float coshalf = MathF.Cos(0.5f * yRadians);
|
||||
float sinhalf = MathF.Sin(-0.5f * yRadians);
|
||||
ob.rotAux[0] = coshalf * sinhalf;
|
||||
ob.rotAux[1] = coshalf * coshalf - 0.5f;
|
||||
ob.orientedBox.rotAux[0] = coshalf * sinhalf;
|
||||
ob.orientedBox.rotAux[1] = coshalf * coshalf - 0.5f;
|
||||
return AddObstacleRequest(ob).refs;
|
||||
}
|
||||
|
||||
|
@ -613,26 +612,26 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
if (Contains(ob.touched, refs))
|
||||
{
|
||||
if (ob.type == DtTileCacheObstacleType.CYLINDER)
|
||||
if (ob.type == DtTileCacheObstacleType.DT_OBSTACLE_CYLINDER)
|
||||
{
|
||||
builder.MarkCylinderArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.pos, ob.radius, ob.height, 0);
|
||||
DtTileCacheBuilder.MarkCylinderArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.cylinder.pos, ob.cylinder.radius, ob.cylinder.height, 0);
|
||||
}
|
||||
else if (ob.type == DtTileCacheObstacleType.BOX)
|
||||
else if (ob.type == DtTileCacheObstacleType.DT_OBSTACLE_BOX)
|
||||
{
|
||||
builder.MarkBoxArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.bmin, ob.bmax, 0);
|
||||
DtTileCacheBuilder.MarkBoxArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.box.bmin, ob.box.bmax, 0);
|
||||
}
|
||||
else if (ob.type == DtTileCacheObstacleType.ORIENTED_BOX)
|
||||
else if (ob.type == DtTileCacheObstacleType.DT_OBSTACLE_ORIENTED_BOX)
|
||||
{
|
||||
builder.MarkBoxArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.center, ob.extents, ob.rotAux, 0);
|
||||
DtTileCacheBuilder.MarkBoxArea(layer, tile.header.bmin, m_params.cs, m_params.ch, ob.orientedBox.center, ob.orientedBox.extents, ob.orientedBox.rotAux, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build navmesh
|
||||
builder.BuildTileCacheRegions(layer, walkableClimbVx);
|
||||
DtTileCacheContourSet lcset = builder.BuildTileCacheContours(layer, walkableClimbVx,
|
||||
m_params.maxSimplificationError);
|
||||
DtTileCachePolyMesh polyMesh = builder.BuildTileCachePolyMesh(lcset, m_navmesh.GetMaxVertsPerPoly());
|
||||
DtTileCacheBuilder.BuildTileCacheRegions(layer, walkableClimbVx);
|
||||
DtTileCacheContourSet lcset = DtTileCacheBuilder.BuildTileCacheContours(layer, walkableClimbVx, m_params.maxSimplificationError);
|
||||
DtTileCachePolyMesh polyMesh = DtTileCacheBuilder.BuildTileCachePolyMesh(lcset, m_navmesh.GetMaxVertsPerPoly());
|
||||
|
||||
// Early out if the mesh tile is empty.
|
||||
if (polyMesh.npolys == 0)
|
||||
{
|
||||
|
@ -670,13 +669,13 @@ namespace DotRecast.Detour.TileCache
|
|||
// Add new tile, or leave the location empty. if (navData) { // Let the
|
||||
if (meshData != null)
|
||||
{
|
||||
m_navmesh.AddTile(meshData, 0, 0);
|
||||
m_navmesh.AddTile(meshData, 0, 0, out var result);
|
||||
}
|
||||
}
|
||||
|
||||
public DtTileCacheLayer DecompressTile(DtCompressedTile tile)
|
||||
{
|
||||
DtTileCacheLayer layer = builder.DecompressTileCacheLayer(m_tcomp, tile.data, m_storageParams.Order, m_storageParams.Compatibility);
|
||||
DtTileCacheLayer layer = DtTileCacheBuilder.DecompressTileCacheLayer(m_tcomp, tile.data, m_storageParams.Order, m_storageParams.Compatibility);
|
||||
return layer;
|
||||
}
|
||||
|
||||
|
@ -693,29 +692,29 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
public void GetObstacleBounds(DtTileCacheObstacle ob, ref RcVec3f bmin, ref RcVec3f bmax)
|
||||
{
|
||||
if (ob.type == DtTileCacheObstacleType.CYLINDER)
|
||||
if (ob.type == DtTileCacheObstacleType.DT_OBSTACLE_CYLINDER)
|
||||
{
|
||||
bmin.X = ob.pos.X - ob.radius;
|
||||
bmin.Y = ob.pos.Y;
|
||||
bmin.Z = ob.pos.Z - ob.radius;
|
||||
bmax.X = ob.pos.X + ob.radius;
|
||||
bmax.Y = ob.pos.Y + ob.height;
|
||||
bmax.Z = ob.pos.Z + ob.radius;
|
||||
bmin.X = ob.cylinder.pos.X - ob.cylinder.radius;
|
||||
bmin.Y = ob.cylinder.pos.Y;
|
||||
bmin.Z = ob.cylinder.pos.Z - ob.cylinder.radius;
|
||||
bmax.X = ob.cylinder.pos.X + ob.cylinder.radius;
|
||||
bmax.Y = ob.cylinder.pos.Y + ob.cylinder.height;
|
||||
bmax.Z = ob.cylinder.pos.Z + ob.cylinder.radius;
|
||||
}
|
||||
else if (ob.type == DtTileCacheObstacleType.BOX)
|
||||
else if (ob.type == DtTileCacheObstacleType.DT_OBSTACLE_BOX)
|
||||
{
|
||||
bmin = ob.bmin;
|
||||
bmax = ob.bmax;
|
||||
bmin = ob.box.bmin;
|
||||
bmax = ob.box.bmax;
|
||||
}
|
||||
else if (ob.type == DtTileCacheObstacleType.ORIENTED_BOX)
|
||||
else if (ob.type == DtTileCacheObstacleType.DT_OBSTACLE_ORIENTED_BOX)
|
||||
{
|
||||
float maxr = 1.41f * Math.Max(ob.extents.X, ob.extents.Z);
|
||||
bmin.X = ob.center.X - maxr;
|
||||
bmax.X = ob.center.X + maxr;
|
||||
bmin.Y = ob.center.Y - ob.extents.Y;
|
||||
bmax.Y = ob.center.Y + ob.extents.Y;
|
||||
bmin.Z = ob.center.Z - maxr;
|
||||
bmax.Z = ob.center.Z + maxr;
|
||||
float maxr = 1.41f * Math.Max(ob.orientedBox.extents.X, ob.orientedBox.extents.Z);
|
||||
bmin.X = ob.orientedBox.center.X - maxr;
|
||||
bmax.X = ob.orientedBox.center.X + maxr;
|
||||
bmin.Y = ob.orientedBox.center.Y - ob.orientedBox.extents.Y;
|
||||
bmax.Y = ob.orientedBox.center.Y + ob.orientedBox.extents.Y;
|
||||
bmin.Z = ob.orientedBox.center.Z - maxr;
|
||||
bmax.Z = ob.orientedBox.center.Z + maxr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -29,22 +29,21 @@ using DotRecast.Recast;
|
|||
|
||||
namespace DotRecast.Detour.TileCache
|
||||
{
|
||||
public class DtTileCacheBuilder
|
||||
public static class DtTileCacheBuilder
|
||||
{
|
||||
public const int DT_TILECACHE_NULL_AREA = 0;
|
||||
public const int DT_TILECACHE_WALKABLE_AREA = 63;
|
||||
public const byte DT_TILECACHE_NULL_AREA = 0;
|
||||
public const byte DT_TILECACHE_WALKABLE_AREA = 63;
|
||||
public const int DT_TILECACHE_NULL_IDX = 0xffff;
|
||||
|
||||
private static readonly int[] DirOffsetX = { -1, 0, 1, 0, };
|
||||
private static readonly int[] DirOffsetY = { 0, 1, 0, -1 };
|
||||
|
||||
private readonly DtTileCacheLayerHeaderReader reader = new DtTileCacheLayerHeaderReader();
|
||||
|
||||
public void BuildTileCacheRegions(DtTileCacheLayer layer, int walkableClimb)
|
||||
public static void BuildTileCacheRegions(DtTileCacheLayer layer, int walkableClimb)
|
||||
{
|
||||
int w = layer.header.width;
|
||||
int h = layer.header.height;
|
||||
|
||||
Array.Fill(layer.regs, (short)0x00FF);
|
||||
Array.Fill(layer.regs, (byte)0xFF);
|
||||
int nsweeps = w;
|
||||
RcLayerSweepSpan[] sweeps = new RcLayerSweepSpan[nsweeps];
|
||||
for (int i = 0; i < sweeps.Length; i++)
|
||||
|
@ -53,14 +52,14 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// Partition walkable area into monotone regions.
|
||||
int[] prevCount = new int[256];
|
||||
int regId = 0;
|
||||
Span<byte> prevCount = stackalloc byte[256];
|
||||
byte regId = 0;
|
||||
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
if (regId > 0)
|
||||
{
|
||||
Array.Fill(prevCount, 0, 0, regId);
|
||||
RcSpans.Fill<byte>(prevCount, 0, 0, regId);
|
||||
}
|
||||
|
||||
// Memset(prevCount,0,Sizeof(char)*regId);
|
||||
|
@ -93,7 +92,7 @@ namespace DotRecast.Detour.TileCache
|
|||
int yidx = x + (y - 1) * w;
|
||||
if (y > 0 && IsConnected(layer, idx, yidx, walkableClimb))
|
||||
{
|
||||
int nr = layer.regs[yidx];
|
||||
byte nr = layer.regs[yidx];
|
||||
if (nr != 0xff)
|
||||
{
|
||||
// Set neighbour when first valid neighbour is
|
||||
|
@ -147,12 +146,12 @@ namespace DotRecast.Detour.TileCache
|
|||
{
|
||||
int idx = x + y * w;
|
||||
if (layer.regs[idx] != 0xff)
|
||||
layer.regs[idx] = (short)sweeps[layer.regs[idx]].id;
|
||||
layer.regs[idx] = sweeps[layer.regs[idx]].id;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate and init layer regions.
|
||||
int nregs = regId;
|
||||
byte nregs = regId;
|
||||
DtLayerMonotoneRegion[] regs = new DtLayerMonotoneRegion[nregs];
|
||||
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
|
@ -167,7 +166,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
int idx = x + y * w;
|
||||
int ri = layer.regs[idx];
|
||||
byte ri = layer.regs[idx];
|
||||
if (ri == 0xff)
|
||||
continue;
|
||||
|
||||
|
@ -179,17 +178,17 @@ namespace DotRecast.Detour.TileCache
|
|||
int ymi = x + (y - 1) * w;
|
||||
if (y > 0 && IsConnected(layer, idx, ymi, walkableClimb))
|
||||
{
|
||||
int rai = layer.regs[ymi];
|
||||
byte rai = layer.regs[ymi];
|
||||
if (rai != 0xff && rai != ri)
|
||||
{
|
||||
AddUniqueLast(regs[ri].neis, rai);
|
||||
AddUniqueLast(regs[rai].neis, ri);
|
||||
AddUniqueLast(regs[ri].neis, ref regs[ri].nneis, rai);
|
||||
AddUniqueLast(regs[rai].neis, ref regs[rai].nneis, ri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
for (byte i = 0; i < nregs; ++i)
|
||||
regs[i].regId = i;
|
||||
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
|
@ -198,8 +197,9 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
int merge = -1;
|
||||
int mergea = 0;
|
||||
foreach (int nei in reg.neis)
|
||||
for (int j = 0; j < reg.nneis; ++j)
|
||||
{
|
||||
byte nei = reg.neis[j];
|
||||
DtLayerMonotoneRegion regn = regs[nei];
|
||||
if (reg.regId == regn.regId)
|
||||
continue;
|
||||
|
@ -218,7 +218,7 @@ namespace DotRecast.Detour.TileCache
|
|||
if (merge != -1)
|
||||
{
|
||||
int oldId = reg.regId;
|
||||
int newId = regs[merge].regId;
|
||||
byte newId = regs[merge].regId;
|
||||
for (int j = 0; j < nregs; ++j)
|
||||
if (regs[j].regId == oldId)
|
||||
regs[j].regId = newId;
|
||||
|
@ -226,7 +226,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// Compact ids.
|
||||
int[] remap = new int[256];
|
||||
Span<byte> remap = stackalloc byte[256];
|
||||
// Find number of unique regions.
|
||||
regId = 0;
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
|
@ -243,19 +243,20 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int i = 0; i < w * h; ++i)
|
||||
{
|
||||
if (layer.regs[i] != 0xff)
|
||||
layer.regs[i] = (short)regs[layer.regs[i]].regId;
|
||||
layer.regs[i] = regs[layer.regs[i]].regId;
|
||||
}
|
||||
}
|
||||
|
||||
void AddUniqueLast(List<int> a, int v)
|
||||
public static void AddUniqueLast(byte[] a, ref byte an, byte v)
|
||||
{
|
||||
int n = a.Count;
|
||||
int n = an;
|
||||
if (n > 0 && a[n - 1] == v)
|
||||
return;
|
||||
a.Add(v);
|
||||
a[an] = v;
|
||||
an++;
|
||||
}
|
||||
|
||||
bool IsConnected(DtTileCacheLayer layer, int ia, int ib, int walkableClimb)
|
||||
public static bool IsConnected(DtTileCacheLayer layer, int ia, int ib, int walkableClimb)
|
||||
{
|
||||
if (layer.areas[ia] != layer.areas[ib])
|
||||
return false;
|
||||
|
@ -264,7 +265,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CanMerge(int oldRegId, int newRegId, DtLayerMonotoneRegion[] regs, int nregs)
|
||||
public static bool CanMerge(int oldRegId, int newRegId, DtLayerMonotoneRegion[] regs, int nregs)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
|
@ -272,9 +273,11 @@ namespace DotRecast.Detour.TileCache
|
|||
DtLayerMonotoneRegion reg = regs[i];
|
||||
if (reg.regId != oldRegId)
|
||||
continue;
|
||||
foreach (int nei in reg.neis)
|
||||
|
||||
int nnei = reg.nneis;
|
||||
for (int j = 0; j < nnei ; ++j)
|
||||
{
|
||||
if (regs[nei].regId == newRegId)
|
||||
if (regs[reg.neis[j]].regId == newRegId)
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -282,7 +285,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return count == 1;
|
||||
}
|
||||
|
||||
private void AppendVertex(DtTempContour cont, int x, int y, int z, int r)
|
||||
public static void AppendVertex(DtTempContour cont, int x, int y, int z, int r)
|
||||
{
|
||||
// Try to merge with existing segments.
|
||||
if (cont.nverts > 1)
|
||||
|
@ -316,7 +319,7 @@ namespace DotRecast.Detour.TileCache
|
|||
cont.nverts++;
|
||||
}
|
||||
|
||||
private int GetNeighbourReg(DtTileCacheLayer layer, int ax, int ay, int dir)
|
||||
public static int GetNeighbourReg(DtTileCacheLayer layer, int ax, int ay, int dir)
|
||||
{
|
||||
int w = layer.header.width;
|
||||
int ia = ax + ay * w;
|
||||
|
@ -339,17 +342,17 @@ namespace DotRecast.Detour.TileCache
|
|||
return layer.regs[ib];
|
||||
}
|
||||
|
||||
private int GetDirOffsetX(int dir)
|
||||
public static int GetDirOffsetX(int dir)
|
||||
{
|
||||
return DirOffsetX[dir & 0x03];
|
||||
}
|
||||
|
||||
private int GetDirOffsetY(int dir)
|
||||
public static int GetDirOffsetY(int dir)
|
||||
{
|
||||
return DirOffsetY[dir & 0x03];
|
||||
}
|
||||
|
||||
private void WalkContour(DtTileCacheLayer layer, int x, int y, DtTempContour cont)
|
||||
public static void WalkContour(DtTileCacheLayer layer, int x, int y, DtTempContour cont)
|
||||
{
|
||||
int w = layer.header.width;
|
||||
int h = layer.header.height;
|
||||
|
@ -434,7 +437,7 @@ namespace DotRecast.Detour.TileCache
|
|||
cont.nverts--;
|
||||
}
|
||||
|
||||
private float DistancePtSeg(int x, int z, int px, int pz, int qx, int qz)
|
||||
public static float DistancePtSeg(int x, int z, int px, int pz, int qx, int qz)
|
||||
{
|
||||
float pqx = qx - px;
|
||||
float pqz = qz - pz;
|
||||
|
@ -455,7 +458,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return dx * dx + dz * dz;
|
||||
}
|
||||
|
||||
private void SimplifyContour(DtTempContour cont, float maxError)
|
||||
public static void SimplifyContour(DtTempContour cont, float maxError)
|
||||
{
|
||||
cont.poly.Clear();
|
||||
|
||||
|
@ -584,7 +587,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
}
|
||||
|
||||
static int GetCornerHeight(DtTileCacheLayer layer, int x, int y, int z, int walkableClimb, out bool shouldRemove)
|
||||
public static int GetCornerHeight(DtTileCacheLayer layer, int x, int y, int z, int walkableClimb, out bool shouldRemove)
|
||||
{
|
||||
int w = layer.header.width;
|
||||
int h = layer.header.height;
|
||||
|
@ -634,7 +637,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// TODO: move this somewhere else, once the layer meshing is done.
|
||||
public DtTileCacheContourSet BuildTileCacheContours(DtTileCacheLayer layer, int walkableClimb, float maxError)
|
||||
public static DtTileCacheContourSet BuildTileCacheContours(DtTileCacheLayer layer, int walkableClimb, float maxError)
|
||||
{
|
||||
int w = layer.header.width;
|
||||
int h = layer.header.height;
|
||||
|
@ -656,7 +659,7 @@ namespace DotRecast.Detour.TileCache
|
|||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
int idx = x + y * w;
|
||||
int ri = layer.regs[idx];
|
||||
byte ri = layer.regs[idx];
|
||||
if (ri == 0xff)
|
||||
continue;
|
||||
|
||||
|
@ -711,7 +714,7 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
const uint VERTEX_BUCKET_COUNT2 = (1 << 8);
|
||||
|
||||
private int ComputeVertexHash2(int x, int y, int z)
|
||||
public static int ComputeVertexHash2(int x, int y, int z)
|
||||
{
|
||||
uint h1 = 0x8da6b343; // Large multiplicative constants;
|
||||
uint h2 = 0xd8163841; // here arbitrarily chosen primes
|
||||
|
@ -720,7 +723,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return (int)(n & (VERTEX_BUCKET_COUNT2 - 1));
|
||||
}
|
||||
|
||||
private int AddVertex(int x, int y, int z, int[] verts, int[] firstVert, int[] nextVert, int nv)
|
||||
public static int AddVertex(int x, int y, int z, int[] verts, int[] firstVert, int[] nextVert, int nv)
|
||||
{
|
||||
int bucket = ComputeVertexHash2(x, 0, z);
|
||||
int i = firstVert[bucket];
|
||||
|
@ -743,7 +746,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return i;
|
||||
}
|
||||
|
||||
private void BuildMeshAdjacency(int[] polys, int npolys, int[] verts, int nverts, DtTileCacheContourSet lcset,
|
||||
public static void BuildMeshAdjacency(int[] polys, int npolys, int[] verts, int nverts, DtTileCacheContourSet lcset,
|
||||
int maxVertsPerPoly)
|
||||
{
|
||||
// Based on code by Eric Lengyel from:
|
||||
|
@ -954,22 +957,22 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
}
|
||||
|
||||
private bool OverlapRangeExl(int amin, int amax, int bmin, int bmax)
|
||||
public static bool OverlapRangeExl(int amin, int amax, int bmin, int bmax)
|
||||
{
|
||||
return (amin >= bmax || amax <= bmin) ? false : true;
|
||||
}
|
||||
|
||||
private int Prev(int i, int n)
|
||||
public static int Prev(int i, int n)
|
||||
{
|
||||
return i - 1 >= 0 ? i - 1 : n - 1;
|
||||
}
|
||||
|
||||
private int Next(int i, int n)
|
||||
public static int Next(int i, int n)
|
||||
{
|
||||
return i + 1 < n ? i + 1 : 0;
|
||||
}
|
||||
|
||||
private int Area2(int[] verts, int a, int b, int c)
|
||||
public static int Area2(int[] verts, int a, int b, int c)
|
||||
{
|
||||
return (verts[b] - verts[a]) * (verts[c + 2] - verts[a + 2])
|
||||
- (verts[c] - verts[a]) * (verts[b + 2] - verts[a + 2]);
|
||||
|
@ -977,17 +980,17 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// Returns true iff c is strictly to the left of the directed
|
||||
// line through a to b.
|
||||
private bool Left(int[] verts, int a, int b, int c)
|
||||
public static bool Left(int[] verts, int a, int b, int c)
|
||||
{
|
||||
return Area2(verts, a, b, c) < 0;
|
||||
}
|
||||
|
||||
private bool LeftOn(int[] verts, int a, int b, int c)
|
||||
public static bool LeftOn(int[] verts, int a, int b, int c)
|
||||
{
|
||||
return Area2(verts, a, b, c) <= 0;
|
||||
}
|
||||
|
||||
private bool Collinear(int[] verts, int a, int b, int c)
|
||||
public static bool Collinear(int[] verts, int a, int b, int c)
|
||||
{
|
||||
return Area2(verts, a, b, c) == 0;
|
||||
}
|
||||
|
@ -995,7 +998,7 @@ namespace DotRecast.Detour.TileCache
|
|||
// Returns true iff ab properly intersects cd: they share
|
||||
// a point interior to both segments. The properness of the
|
||||
// intersection is ensured by using strict leftness.
|
||||
private bool IntersectProp(int[] verts, int a, int b, int c, int d)
|
||||
public static bool IntersectProp(int[] verts, int a, int b, int c, int d)
|
||||
{
|
||||
// Eliminate improper cases.
|
||||
if (Collinear(verts, a, b, c) || Collinear(verts, a, b, d) || Collinear(verts, c, d, a)
|
||||
|
@ -1007,7 +1010,7 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// Returns T iff (a,b,c) are collinear and point c lies
|
||||
// on the closed segment ab.
|
||||
private bool Between(int[] verts, int a, int b, int c)
|
||||
public static bool Between(int[] verts, int a, int b, int c)
|
||||
{
|
||||
if (!Collinear(verts, a, b, c))
|
||||
return false;
|
||||
|
@ -1021,7 +1024,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
|
||||
// Returns true iff segments ab and cd intersect, properly or improperly.
|
||||
private bool Intersect(int[] verts, int a, int b, int c, int d)
|
||||
public static bool Intersect(int[] verts, int a, int b, int c, int d)
|
||||
{
|
||||
if (IntersectProp(verts, a, b, c, d))
|
||||
return true;
|
||||
|
@ -1032,14 +1035,14 @@ namespace DotRecast.Detour.TileCache
|
|||
return false;
|
||||
}
|
||||
|
||||
private bool Vequal(int[] verts, int a, int b)
|
||||
public static bool Vequal(int[] verts, int a, int b)
|
||||
{
|
||||
return verts[a] == verts[b] && verts[a + 2] == verts[b + 2];
|
||||
}
|
||||
|
||||
// Returns T iff (v_i, v_j) is a proper internal *or* external
|
||||
// diagonal of P, *ignoring edges incident to v_i and v_j*.
|
||||
private bool Diagonalie(int i, int j, int n, int[] verts, int[] indices)
|
||||
public static bool Diagonalie(int i, int j, int n, int[] verts, int[] indices)
|
||||
{
|
||||
int d0 = (indices[i] & 0x7fff) * 4;
|
||||
int d1 = (indices[j] & 0x7fff) * 4;
|
||||
|
@ -1067,7 +1070,7 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// Returns true iff the diagonal (i,j) is strictly internal to the
|
||||
// polygon P in the neighborhood of the i endpoint.
|
||||
private bool InCone(int i, int j, int n, int[] verts, int[] indices)
|
||||
public static bool InCone(int i, int j, int n, int[] verts, int[] indices)
|
||||
{
|
||||
int pi = (indices[i] & 0x7fff) * 4;
|
||||
int pj = (indices[j] & 0x7fff) * 4;
|
||||
|
@ -1084,12 +1087,12 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
// Returns T iff (v_i, v_j) is a proper internal
|
||||
// diagonal of P.
|
||||
private bool Diagonal(int i, int j, int n, int[] verts, int[] indices)
|
||||
public static bool Diagonal(int i, int j, int n, int[] verts, int[] indices)
|
||||
{
|
||||
return InCone(i, j, n, verts, indices) && Diagonalie(i, j, n, verts, indices);
|
||||
}
|
||||
|
||||
private int Triangulate(int n, int[] verts, int[] indices, int[] tris)
|
||||
public static int Triangulate(int n, int[] verts, int[] indices, int[] tris)
|
||||
{
|
||||
int ntris = 0;
|
||||
int dst = 0; // tris;
|
||||
|
@ -1174,7 +1177,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return ntris;
|
||||
}
|
||||
|
||||
private int CountPolyVerts(int[] polys, int p, int maxVertsPerPoly)
|
||||
public static int CountPolyVerts(int[] polys, int p, int maxVertsPerPoly)
|
||||
{
|
||||
for (int i = 0; i < maxVertsPerPoly; ++i)
|
||||
if (polys[p + i] == DT_TILECACHE_NULL_IDX)
|
||||
|
@ -1182,13 +1185,13 @@ namespace DotRecast.Detour.TileCache
|
|||
return maxVertsPerPoly;
|
||||
}
|
||||
|
||||
private bool Uleft(int[] verts, int a, int b, int c)
|
||||
public static bool Uleft(int[] verts, int a, int b, int c)
|
||||
{
|
||||
return (verts[b] - verts[a]) * (verts[c + 2] - verts[a + 2])
|
||||
- (verts[c] - verts[a]) * (verts[b + 2] - verts[a + 2]) < 0;
|
||||
}
|
||||
|
||||
private int GetPolyMergeValue(int[] polys, int pa, int pb, int[] verts, out int ea, out int eb, int maxVertsPerPoly)
|
||||
public static int GetPolyMergeValue(int[] polys, int pa, int pb, int[] verts, out int ea, out int eb, int maxVertsPerPoly)
|
||||
{
|
||||
ea = 0;
|
||||
eb = 0;
|
||||
|
@ -1259,7 +1262,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return (dx * dx) + (dy * dy);
|
||||
}
|
||||
|
||||
private void MergePolys(int[] polys, int pa, int pb, int ea, int eb, int maxVertsPerPoly)
|
||||
public static void MergePolys(int[] polys, int pa, int pb, int ea, int eb, int maxVertsPerPoly)
|
||||
{
|
||||
int[] tmp = new int[maxVertsPerPoly * 2];
|
||||
|
||||
|
@ -1278,19 +1281,19 @@ namespace DotRecast.Detour.TileCache
|
|||
RcArrays.Copy(tmp, 0, polys, pa, maxVertsPerPoly);
|
||||
}
|
||||
|
||||
private int PushFront(int v, List<int> arr)
|
||||
public static int PushFront(int v, List<int> arr)
|
||||
{
|
||||
arr.Insert(0, v);
|
||||
return arr.Count;
|
||||
}
|
||||
|
||||
private int PushBack(int v, List<int> arr)
|
||||
public static int PushBack(int v, List<int> arr)
|
||||
{
|
||||
arr.Add(v);
|
||||
return arr.Count;
|
||||
}
|
||||
|
||||
private bool CanRemoveVertex(DtTileCachePolyMesh mesh, int rem)
|
||||
public static bool CanRemoveVertex(DtTileCachePolyMesh mesh, int rem)
|
||||
{
|
||||
// Count number of polygons to remove.
|
||||
int maxVertsPerPoly = mesh.nvp;
|
||||
|
@ -1388,7 +1391,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return true;
|
||||
}
|
||||
|
||||
private void RemoveVertex(DtTileCachePolyMesh mesh, int rem, int maxTris)
|
||||
public static void RemoveVertex(DtTileCachePolyMesh mesh, int rem, int maxTris)
|
||||
{
|
||||
// Count number of polygons to remove.
|
||||
int maxVertsPerPoly = mesh.nvp;
|
||||
|
@ -1627,7 +1630,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
}
|
||||
|
||||
public DtTileCachePolyMesh BuildTileCachePolyMesh(DtTileCacheContourSet lcset, int maxVertsPerPoly)
|
||||
public static DtTileCachePolyMesh BuildTileCachePolyMesh(DtTileCacheContourSet lcset, int maxVertsPerPoly)
|
||||
{
|
||||
int maxVertices = 0;
|
||||
int maxTris = 0;
|
||||
|
@ -1801,7 +1804,7 @@ namespace DotRecast.Detour.TileCache
|
|||
return mesh;
|
||||
}
|
||||
|
||||
public void MarkCylinderArea(DtTileCacheLayer layer, RcVec3f orig, float cs, float ch, RcVec3f pos, float radius, float height, int areaId)
|
||||
public static void MarkCylinderArea(DtTileCacheLayer layer, RcVec3f orig, float cs, float ch, RcVec3f pos, float radius, float height, byte areaId)
|
||||
{
|
||||
RcVec3f bmin = new RcVec3f();
|
||||
RcVec3f bmax = new RcVec3f();
|
||||
|
@ -1857,12 +1860,12 @@ namespace DotRecast.Detour.TileCache
|
|||
int y = layer.heights[x + z * w];
|
||||
if (y < miny || y > maxy)
|
||||
continue;
|
||||
layer.areas[x + z * w] = (short)areaId;
|
||||
layer.areas[x + z * w] = areaId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkBoxArea(DtTileCacheLayer layer, RcVec3f orig, float cs, float ch, RcVec3f bmin, RcVec3f bmax, int areaId)
|
||||
public static void MarkBoxArea(DtTileCacheLayer layer, RcVec3f orig, float cs, float ch, RcVec3f bmin, RcVec3f bmax, byte areaId)
|
||||
{
|
||||
int w = layer.header.width;
|
||||
int h = layer.header.height;
|
||||
|
@ -1901,12 +1904,12 @@ namespace DotRecast.Detour.TileCache
|
|||
int y = layer.heights[x + z * w];
|
||||
if (y < miny || y > maxy)
|
||||
continue;
|
||||
layer.areas[x + z * w] = (short)areaId;
|
||||
layer.areas[x + z * w] = areaId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] CompressTileCacheLayer(IRcCompressor comp, DtTileCacheLayer layer, RcByteOrder order, bool cCompatibility)
|
||||
public static byte[] CompressTileCacheLayer(IRcCompressor comp, DtTileCacheLayer layer, RcByteOrder order, bool cCompatibility)
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
using var bw = new BinaryWriter(ms);
|
||||
|
@ -1933,7 +1936,7 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
}
|
||||
|
||||
public byte[] CompressTileCacheLayer(DtTileCacheLayerHeader header, int[] heights, int[] areas, int[] cons, RcByteOrder order, bool cCompatibility, IRcCompressor comp)
|
||||
public static byte[] CompressTileCacheLayer(DtTileCacheLayerHeader header, int[] heights, int[] areas, int[] cons, RcByteOrder order, bool cCompatibility, IRcCompressor comp)
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
using var bw = new BinaryWriter(ms);
|
||||
|
@ -1960,14 +1963,14 @@ namespace DotRecast.Detour.TileCache
|
|||
}
|
||||
}
|
||||
|
||||
public DtTileCacheLayer DecompressTileCacheLayer(IRcCompressor comp, byte[] compressed, RcByteOrder order, bool cCompatibility)
|
||||
public static DtTileCacheLayer DecompressTileCacheLayer(IRcCompressor comp, byte[] compressed, RcByteOrder order, bool cCompatibility)
|
||||
{
|
||||
RcByteBuffer buf = new RcByteBuffer(compressed);
|
||||
buf.Order(order);
|
||||
DtTileCacheLayer layer = new DtTileCacheLayer();
|
||||
try
|
||||
{
|
||||
layer.header = reader.Read(buf, cCompatibility);
|
||||
layer.header = DtTileCacheLayerHeaderReader.Read(buf, cCompatibility);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
@ -1976,22 +1979,22 @@ namespace DotRecast.Detour.TileCache
|
|||
|
||||
int gridSize = layer.header.width * layer.header.height;
|
||||
byte[] grids = comp.Decompress(compressed, buf.Position(), compressed.Length - buf.Position(), gridSize * 3);
|
||||
layer.heights = new short[gridSize];
|
||||
layer.areas = new short[gridSize];
|
||||
layer.cons = new short[gridSize];
|
||||
layer.regs = new short[gridSize];
|
||||
layer.heights = new byte[gridSize];
|
||||
layer.areas = new byte[gridSize];
|
||||
layer.cons = new byte[gridSize];
|
||||
layer.regs = new byte[gridSize];
|
||||
for (int i = 0; i < gridSize; i++)
|
||||
{
|
||||
layer.heights[i] = (short)(grids[i] & 0xFF);
|
||||
layer.areas[i] = (short)(grids[i + gridSize] & 0xFF);
|
||||
layer.cons[i] = (short)(grids[i + gridSize * 2] & 0xFF);
|
||||
layer.heights[i] = (byte)(grids[i] & 0xFF);
|
||||
layer.areas[i] = (byte)(grids[i + gridSize] & 0xFF);
|
||||
layer.cons[i] = (byte)(grids[i + gridSize * 2] & 0xFF);
|
||||
}
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
public void MarkBoxArea(DtTileCacheLayer layer, RcVec3f orig, float cs, float ch, RcVec3f center, RcVec3f extents,
|
||||
float[] rotAux, int areaId)
|
||||
public static void MarkBoxArea(DtTileCacheLayer layer, RcVec3f orig, float cs, float ch, RcVec3f center, RcVec3f extents,
|
||||
float[] rotAux, byte areaId)
|
||||
{
|
||||
int w = layer.header.width;
|
||||
int h = layer.header.height;
|
||||
|
@ -2044,7 +2047,7 @@ namespace DotRecast.Detour.TileCache
|
|||
int y = layer.heights[x + z * w];
|
||||
if (y < miny || y > maxy)
|
||||
continue;
|
||||
layer.areas[x + z * w] = (short)areaId;
|
||||
layer.areas[x + z * w] = areaId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -24,7 +24,7 @@ namespace DotRecast.Detour.TileCache
|
|||
{
|
||||
public int nverts;
|
||||
public int[] verts;
|
||||
public int reg;
|
||||
public int area;
|
||||
public byte reg;
|
||||
public byte area;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -23,13 +23,10 @@ namespace DotRecast.Detour.TileCache
|
|||
public class DtTileCacheLayer
|
||||
{
|
||||
public DtTileCacheLayerHeader header;
|
||||
public int regCount;
|
||||
|
||||
/// < Region count.
|
||||
public short[] heights; // char
|
||||
|
||||
public short[] areas; // char
|
||||
public short[] cons; // char
|
||||
public short[] regs; // char
|
||||
public byte regCount; // < Region count.
|
||||
public byte[] heights; // unsigned char
|
||||
public byte[] areas; // unsigned char
|
||||
public byte[] cons; // unsigned char
|
||||
public byte[] regs; // unsigned char
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotRecast.Detour.TileCache
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -100,7 +100,6 @@ namespace DotRecast.Detour.TileCache
|
|||
List<byte[]> result = new List<byte[]>();
|
||||
if (lset != null)
|
||||
{
|
||||
DtTileCacheBuilder builder = new DtTileCacheBuilder();
|
||||
for (int i = 0; i < lset.layers.Length; ++i)
|
||||
{
|
||||
RcHeightfieldLayer layer = lset.layers[i];
|
||||
|
@ -128,7 +127,7 @@ namespace DotRecast.Detour.TileCache
|
|||
header.hmax = layer.hmax;
|
||||
|
||||
var comp = _compFactory.Create(storageParams.Compatibility ? 0 : 1);
|
||||
var bytes = builder.CompressTileCacheLayer(header, layer.heights, layer.areas, layer.cons, storageParams.Order, storageParams.Compatibility, comp);
|
||||
var bytes = DtTileCacheBuilder.CompressTileCacheLayer(header, layer.heights, layer.areas, layer.cons, storageParams.Order, storageParams.Compatibility, comp);
|
||||
result.Add(bytes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -19,32 +19,28 @@ freely, subject to the following restrictions:
|
|||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour.TileCache
|
||||
{
|
||||
public class DtTileCacheObstacle
|
||||
{
|
||||
public readonly int index;
|
||||
public DtTileCacheObstacleType type;
|
||||
public RcVec3f pos = new RcVec3f();
|
||||
public RcVec3f bmin = new RcVec3f();
|
||||
public RcVec3f bmax = new RcVec3f();
|
||||
public float radius, height;
|
||||
public RcVec3f center = new RcVec3f();
|
||||
public RcVec3f extents = new RcVec3f();
|
||||
public readonly float[] rotAux = new float[2]; // { Cos(0.5f*angle)*Sin(-0.5f*angle); Cos(0.5f*angle)*Cos(0.5f*angle) - 0.5 }
|
||||
|
||||
public DtObstacleCylinder cylinder = new DtObstacleCylinder();
|
||||
public DtObstacleBox box = new DtObstacleBox();
|
||||
public DtObstacleOrientedBox orientedBox = new DtObstacleOrientedBox();
|
||||
|
||||
public List<long> touched = new List<long>();
|
||||
public readonly List<long> pending = new List<long>();
|
||||
public int salt;
|
||||
public DtTileCacheObstacleType type;
|
||||
public DtObstacleState state = DtObstacleState.DT_OBSTACLE_EMPTY;
|
||||
public DtTileCacheObstacle next;
|
||||
|
||||
public DtTileCacheObstacle(int index)
|
||||
{
|
||||
salt = 1;
|
||||
this.index = index;
|
||||
salt = 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
namespace DotRecast.Detour.TileCache
|
||||
namespace DotRecast.Detour.TileCache
|
||||
{
|
||||
public enum DtTileCacheObstacleType
|
||||
{
|
||||
CYLINDER,
|
||||
BOX,
|
||||
ORIENTED_BOX
|
||||
DT_OBSTACLE_CYLINDER,
|
||||
DT_OBSTACLE_BOX, // AABB
|
||||
DT_OBSTACLE_ORIENTED_BOX // OBB
|
||||
};
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -23,24 +23,13 @@ namespace DotRecast.Detour.TileCache
|
|||
public class DtTileCachePolyMesh
|
||||
{
|
||||
public int nvp;
|
||||
public int nverts;
|
||||
public int nverts; // < Number of vertices.
|
||||
public int npolys; // < Number of polygons.
|
||||
public int[] verts; // < Vertices of the mesh, 3 elements per vertex.
|
||||
public int[] polys; // < Polygons of the mesh, nvp*2 elements per polygon.
|
||||
public int[] flags; // < Per polygon flags.
|
||||
public int[] areas; // < Area ID of polygons.
|
||||
|
||||
/// < Number of vertices.
|
||||
public int npolys;
|
||||
|
||||
/// < Number of polygons.
|
||||
public int[] verts;
|
||||
|
||||
/// < Vertices of the mesh, 3 elements per vertex.
|
||||
public int[] polys;
|
||||
|
||||
/// < Polygons of the mesh, nvp*2 elements per polygon.
|
||||
public int[] flags;
|
||||
|
||||
/// < Per polygon flags.
|
||||
public int[] areas;
|
||||
|
||||
/// < Area ID of polygons.
|
||||
public DtTileCachePolyMesh(int nvp)
|
||||
{
|
||||
this.nvp = nvp;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
|
||||
namespace DotRecast.Detour.TileCache.Io.Compress
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -23,9 +23,9 @@ using DotRecast.Core;
|
|||
|
||||
namespace DotRecast.Detour.TileCache.Io
|
||||
{
|
||||
public class DtTileCacheLayerHeaderReader
|
||||
public static class DtTileCacheLayerHeaderReader
|
||||
{
|
||||
public DtTileCacheLayerHeader Read(RcByteBuffer data, bool cCompatibility)
|
||||
public static DtTileCacheLayerHeader Read(RcByteBuffer data, bool cCompatibility)
|
||||
{
|
||||
DtTileCacheLayerHeader header = new DtTileCacheLayerHeader();
|
||||
header.magic = data.GetInt();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -24,34 +24,34 @@ using DotRecast.Detour.Io;
|
|||
|
||||
namespace DotRecast.Detour.TileCache.Io
|
||||
{
|
||||
public class DtTileCacheLayerHeaderWriter : DtWriter
|
||||
public class DtTileCacheLayerHeaderWriter
|
||||
{
|
||||
public void Write(BinaryWriter stream, DtTileCacheLayerHeader header, RcByteOrder order, bool cCompatibility)
|
||||
{
|
||||
Write(stream, header.magic, order);
|
||||
Write(stream, header.version, order);
|
||||
Write(stream, header.tx, order);
|
||||
Write(stream, header.ty, order);
|
||||
Write(stream, header.tlayer, order);
|
||||
RcIO.Write(stream, header.magic, order);
|
||||
RcIO.Write(stream, header.version, order);
|
||||
RcIO.Write(stream, header.tx, order);
|
||||
RcIO.Write(stream, header.ty, order);
|
||||
RcIO.Write(stream, header.tlayer, order);
|
||||
|
||||
Write(stream, header.bmin.X, order);
|
||||
Write(stream, header.bmin.Y, order);
|
||||
Write(stream, header.bmin.Z, order);
|
||||
Write(stream, header.bmax.X, order);
|
||||
Write(stream, header.bmax.Y, order);
|
||||
Write(stream, header.bmax.Z, order);
|
||||
RcIO.Write(stream, header.bmin.X, order);
|
||||
RcIO.Write(stream, header.bmin.Y, order);
|
||||
RcIO.Write(stream, header.bmin.Z, order);
|
||||
RcIO.Write(stream, header.bmax.X, order);
|
||||
RcIO.Write(stream, header.bmax.Y, order);
|
||||
RcIO.Write(stream, header.bmax.Z, order);
|
||||
|
||||
Write(stream, (short)header.hmin, order);
|
||||
Write(stream, (short)header.hmax, order);
|
||||
Write(stream, (byte)header.width);
|
||||
Write(stream, (byte)header.height);
|
||||
Write(stream, (byte)header.minx);
|
||||
Write(stream, (byte)header.maxx);
|
||||
Write(stream, (byte)header.miny);
|
||||
Write(stream, (byte)header.maxy);
|
||||
RcIO.Write(stream, (short)header.hmin, order);
|
||||
RcIO.Write(stream, (short)header.hmax, order);
|
||||
RcIO.Write(stream, (byte)header.width);
|
||||
RcIO.Write(stream, (byte)header.height);
|
||||
RcIO.Write(stream, (byte)header.minx);
|
||||
RcIO.Write(stream, (byte)header.maxx);
|
||||
RcIO.Write(stream, (byte)header.miny);
|
||||
RcIO.Write(stream, (byte)header.maxy);
|
||||
if (cCompatibility)
|
||||
{
|
||||
Write(stream, (short)0, order); // C struct padding
|
||||
RcIO.Write(stream, (short)0, order); // C struct padding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -37,7 +37,7 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
|
||||
public DtTileCache Read(BinaryReader @is, int maxVertPerPoly, IDtTileCacheMeshProcess meshProcessor)
|
||||
{
|
||||
RcByteBuffer bb = IOUtils.ToByteBuffer(@is);
|
||||
RcByteBuffer bb = RcIO.ToByteBuffer(@is);
|
||||
return Read(bb, maxVertPerPoly, meshProcessor);
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
header.magic = bb.GetInt();
|
||||
if (header.magic != DtTileCacheSetHeader.TILECACHESET_MAGIC)
|
||||
{
|
||||
header.magic = IOUtils.SwapEndianness(header.magic);
|
||||
header.magic = RcIO.SwapEndianness(header.magic);
|
||||
if (header.magic != DtTileCacheSetHeader.TILECACHESET_MAGIC)
|
||||
{
|
||||
throw new IOException("Invalid magic");
|
||||
|
@ -69,7 +69,8 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
header.numTiles = bb.GetInt();
|
||||
header.meshParams = paramReader.Read(bb);
|
||||
header.cacheParams = ReadCacheParams(bb, cCompatibility);
|
||||
DtNavMesh mesh = new DtNavMesh(header.meshParams, maxVertPerPoly);
|
||||
DtNavMesh mesh = new DtNavMesh();
|
||||
mesh.Init(header.meshParams, maxVertPerPoly);
|
||||
IRcCompressor comp = _compFactory.Create(cCompatibility ? 0 : 1);
|
||||
DtTileCacheStorageParams storageParams = new DtTileCacheStorageParams(bb.Order(), cCompatibility);
|
||||
DtTileCache tc = new DtTileCache(header.cacheParams, storageParams, mesh, comp, meshProcessor);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -25,10 +25,9 @@ using DotRecast.Detour.TileCache.Io.Compress;
|
|||
|
||||
namespace DotRecast.Detour.TileCache.Io
|
||||
{
|
||||
public class DtTileCacheWriter : DtWriter
|
||||
public class DtTileCacheWriter
|
||||
{
|
||||
private readonly DtNavMeshParamWriter paramWriter = new DtNavMeshParamWriter();
|
||||
private readonly DtTileCacheBuilder builder = new DtTileCacheBuilder();
|
||||
private readonly IDtTileCacheCompressorFactory _compFactory;
|
||||
|
||||
public DtTileCacheWriter(IDtTileCacheCompressorFactory compFactory)
|
||||
|
@ -39,8 +38,8 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
|
||||
public void Write(BinaryWriter stream, DtTileCache cache, RcByteOrder order, bool cCompatibility)
|
||||
{
|
||||
Write(stream, DtTileCacheSetHeader.TILECACHESET_MAGIC, order);
|
||||
Write(stream, cCompatibility
|
||||
RcIO.Write(stream, DtTileCacheSetHeader.TILECACHESET_MAGIC, order);
|
||||
RcIO.Write(stream, cCompatibility
|
||||
? DtTileCacheSetHeader.TILECACHESET_VERSION
|
||||
: DtTileCacheSetHeader.TILECACHESET_VERSION_RECAST4J, order);
|
||||
int numTiles = 0;
|
||||
|
@ -52,7 +51,7 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
numTiles++;
|
||||
}
|
||||
|
||||
Write(stream, numTiles, order);
|
||||
RcIO.Write(stream, numTiles, order);
|
||||
paramWriter.Write(stream, cache.GetNavMesh().GetParams(), order);
|
||||
WriteCacheParams(stream, cache.GetParams(), order);
|
||||
for (int i = 0; i < cache.GetTileCount(); i++)
|
||||
|
@ -60,32 +59,32 @@ namespace DotRecast.Detour.TileCache.Io
|
|||
DtCompressedTile tile = cache.GetTile(i);
|
||||
if (tile == null || tile.data == null)
|
||||
continue;
|
||||
Write(stream, (int)cache.GetTileRef(tile), order);
|
||||
RcIO.Write(stream, (int)cache.GetTileRef(tile), order);
|
||||
byte[] data = tile.data;
|
||||
DtTileCacheLayer layer = cache.DecompressTile(tile);
|
||||
var comp = _compFactory.Create(cCompatibility ? 0 : 1);
|
||||
data = builder.CompressTileCacheLayer(comp, layer, order, cCompatibility);
|
||||
Write(stream, data.Length, order);
|
||||
data = DtTileCacheBuilder.CompressTileCacheLayer(comp, layer, order, cCompatibility);
|
||||
RcIO.Write(stream, data.Length, order);
|
||||
stream.Write(data);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteCacheParams(BinaryWriter stream, DtTileCacheParams option, RcByteOrder order)
|
||||
{
|
||||
Write(stream, option.orig.X, order);
|
||||
Write(stream, option.orig.Y, order);
|
||||
Write(stream, option.orig.Z, order);
|
||||
RcIO.Write(stream, option.orig.X, order);
|
||||
RcIO.Write(stream, option.orig.Y, order);
|
||||
RcIO.Write(stream, option.orig.Z, order);
|
||||
|
||||
Write(stream, option.cs, order);
|
||||
Write(stream, option.ch, order);
|
||||
Write(stream, option.width, order);
|
||||
Write(stream, option.height, order);
|
||||
Write(stream, option.walkableHeight, order);
|
||||
Write(stream, option.walkableRadius, order);
|
||||
Write(stream, option.walkableClimb, order);
|
||||
Write(stream, option.maxSimplificationError, order);
|
||||
Write(stream, option.maxTiles, order);
|
||||
Write(stream, option.maxObstacles, order);
|
||||
RcIO.Write(stream, option.cs, order);
|
||||
RcIO.Write(stream, option.ch, order);
|
||||
RcIO.Write(stream, option.width, order);
|
||||
RcIO.Write(stream, option.height, order);
|
||||
RcIO.Write(stream, option.walkableHeight, order);
|
||||
RcIO.Write(stream, option.walkableRadius, order);
|
||||
RcIO.Write(stream, option.walkableClimb, order);
|
||||
RcIO.Write(stream, option.maxSimplificationError, order);
|
||||
RcIO.Write(stream, option.maxTiles, order);
|
||||
RcIO.Write(stream, option.maxObstacles, order);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
namespace DotRecast.Detour
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public class BVItem
|
||||
{
|
||||
public readonly int[] bmin = new int[3];
|
||||
public readonly int[] bmax = new int[3];
|
||||
public RcVec3i bmin;
|
||||
public RcVec3i bmax;
|
||||
public int i;
|
||||
};
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ namespace DotRecast.Detour
|
|||
|
||||
public int Compare(BVItem a, BVItem b)
|
||||
{
|
||||
return a.bmin[0].CompareTo(b.bmin[0]);
|
||||
return a.bmin.X.CompareTo(b.bmin.X);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ namespace DotRecast.Detour
|
|||
|
||||
public int Compare(BVItem a, BVItem b)
|
||||
{
|
||||
return a.bmin[1].CompareTo(b.bmin[1]);
|
||||
return a.bmin.Y.CompareTo(b.bmin.Y);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ namespace DotRecast.Detour
|
|||
|
||||
public int Compare(BVItem a, BVItem b)
|
||||
{
|
||||
return a.bmin[2].CompareTo(b.bmin[2]);
|
||||
return a.bmin.Z.CompareTo(b.bmin.Z);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,23 +18,17 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/**
|
||||
* Bounding volume node.
|
||||
*
|
||||
* @note This structure is rarely if ever used by the end user.
|
||||
* @see MeshTile
|
||||
*/
|
||||
/// Bounding volume node.
|
||||
/// @note This structure is rarely if ever used by the end user.
|
||||
/// @see dtMeshTile
|
||||
public class DtBVNode
|
||||
{
|
||||
/** Minimum bounds of the node's AABB. [(x, y, z)] */
|
||||
public int[] bmin = new int[3];
|
||||
|
||||
/** Maximum bounds of the node's AABB. [(x, y, z)] */
|
||||
public int[] bmax = new int[3];
|
||||
|
||||
/** The node's index. (Negative for escape sequence.) */
|
||||
public int i;
|
||||
public RcVec3i bmin; //< Minimum bounds of the node's AABB. [(x, y, z)]
|
||||
public RcVec3i bmax; //< Maximum bounds of the node's AABB. [(x, y, z)]
|
||||
public int i; //< The node's index. (Negative for escape sequence.)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public struct DtCallbackPolyQuery : IDtPolyQuery
|
||||
{
|
||||
private readonly Action<DtMeshTile, DtPoly, long> _callback;
|
||||
|
||||
public DtCallbackPolyQuery(Action<DtMeshTile, DtPoly, long> callback)
|
||||
{
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
public void Process(DtMeshTile tile, Span<DtPoly> poly, Span<long> refs, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
_callback?.Invoke(tile, poly[i], refs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using DotRecast.Core;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public class DtCollectPolysQuery : IDtPolyQuery
|
||||
{
|
||||
private long[] m_polys;
|
||||
private int m_maxPolys;
|
||||
private int m_numCollected;
|
||||
private bool m_overflow;
|
||||
|
||||
public DtCollectPolysQuery(long[] polys, int maxPolys)
|
||||
{
|
||||
m_polys = polys;
|
||||
m_maxPolys = maxPolys;
|
||||
}
|
||||
|
||||
public int NumCollected()
|
||||
{
|
||||
return m_numCollected;
|
||||
}
|
||||
|
||||
public bool Overflowed()
|
||||
{
|
||||
return m_overflow;
|
||||
}
|
||||
|
||||
public void Process(DtMeshTile tile, Span<DtPoly> poly, Span<long> refs, int count)
|
||||
{
|
||||
int numLeft = m_maxPolys - m_numCollected;
|
||||
int toCopy = count;
|
||||
if (toCopy > numLeft)
|
||||
{
|
||||
m_overflow = true;
|
||||
toCopy = numLeft;
|
||||
}
|
||||
|
||||
RcSpans.Copy<long>(refs, 0, m_polys, m_numCollected, toCopy);
|
||||
m_numCollected += toCopy;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public enum DtConvexConvexInFlag
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public enum DtConvexConvexIntersection
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,23 +18,20 @@ freely, subject to the following restrictions:
|
|||
*/
|
||||
|
||||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/**
|
||||
* Convex-convex intersection based on "Computational Geometry in C" by Joseph O'Rourke
|
||||
*/
|
||||
// Convex-convex intersection based on "Computational Geometry in C" by Joseph O'Rourke
|
||||
public static class DtConvexConvexIntersections
|
||||
{
|
||||
private static readonly float EPSILON = 0.0001f;
|
||||
private const float EPSILON = 0.0001f;
|
||||
|
||||
public static float[] Intersect(float[] p, float[] q)
|
||||
public static Span<float> Intersect(Span<float> p, Span<float> q, Span<float> buffer)
|
||||
{
|
||||
int n = p.Length / 3;
|
||||
int m = q.Length / 3;
|
||||
float[] inters = new float[Math.Max(m, n) * 3 * 3];
|
||||
Span<float> inters = stackalloc float[Math.Max(m, n) * 3 * 3];
|
||||
int ii = 0;
|
||||
/* Initialize variables. */
|
||||
RcVec3f a = new RcVec3f();
|
||||
|
@ -54,10 +51,10 @@ namespace DotRecast.Detour
|
|||
|
||||
do
|
||||
{
|
||||
a = RcVecUtils.Create(p, 3 * (ai % n));
|
||||
b = RcVecUtils.Create(q, 3 * (bi % m));
|
||||
a1 = RcVecUtils.Create(p, 3 * ((ai + n - 1) % n)); // prev a
|
||||
b1 = RcVecUtils.Create(q, 3 * ((bi + m - 1) % m)); // prev b
|
||||
a = RcVec.Create(p, 3 * (ai % n));
|
||||
b = RcVec.Create(q, 3 * (bi % m));
|
||||
a1 = RcVec.Create(p, 3 * ((ai + n - 1) % n)); // prev a
|
||||
b1 = RcVec.Create(q, 3 * ((bi + m - 1) % m)); // prev b
|
||||
|
||||
RcVec3f A = RcVec3f.Subtract(a, a1);
|
||||
RcVec3f B = RcVec3f.Subtract(b, b1);
|
||||
|
@ -98,7 +95,7 @@ namespace DotRecast.Detour
|
|||
/* Special case: A & B parallel and separated. */
|
||||
if (parallel && aHB < 0f && bHA < 0f)
|
||||
{
|
||||
return null;
|
||||
return Span<float>.Empty;
|
||||
}
|
||||
/* Special case: A & B collinear. */
|
||||
else if (parallel && MathF.Abs(aHB) < EPSILON && MathF.Abs(bHA) < EPSILON)
|
||||
|
@ -171,12 +168,12 @@ namespace DotRecast.Detour
|
|||
return null;
|
||||
}
|
||||
|
||||
float[] copied = new float[ii];
|
||||
RcArrays.Copy(inters, copied, ii);
|
||||
return copied;
|
||||
Span<float> result = buffer.Slice(0, ii);
|
||||
inters.Slice(0, ii).CopyTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int AddVertex(float[] inters, int ii, RcVec3f p)
|
||||
private static int AddVertex(Span<float> inters, int ii, RcVec3f p)
|
||||
{
|
||||
if (ii > 0)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public static class DtDetailTriEdgeFlags
|
||||
{
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public static class DtDetour
|
||||
{
|
||||
/// The maximum number of vertices per navigation polygon.
|
||||
/// @ingroup detour
|
||||
public const int DT_VERTS_PER_POLYGON = 6;
|
||||
|
||||
/** A magic number used to detect compatibility of navigation tile data. */
|
||||
public const int DT_NAVMESH_MAGIC = 'D' << 24 | 'N' << 16 | 'A' << 8 | 'V';
|
||||
|
||||
/** A version number used to detect compatibility of navigation tile data. */
|
||||
public const int DT_NAVMESH_VERSION = 7;
|
||||
|
||||
public const int DT_NAVMESH_VERSION_RECAST4J_FIRST = 0x8807;
|
||||
public const int DT_NAVMESH_VERSION_RECAST4J_NO_POLY_FIRSTLINK = 0x8808;
|
||||
public const int DT_NAVMESH_VERSION_RECAST4J_32BIT_BVTREE = 0x8809;
|
||||
public const int DT_NAVMESH_VERSION_RECAST4J_LAST = 0x8809;
|
||||
|
||||
/** A magic number used to detect the compatibility of navigation tile states. */
|
||||
public const int DT_NAVMESH_STATE_MAGIC = 'D' << 24 | 'N' << 16 | 'M' << 8 | 'S';
|
||||
|
||||
/** A version number used to detect compatibility of navigation tile states. */
|
||||
public const int DT_NAVMESH_STATE_VERSION = 1;
|
||||
|
||||
public const int DT_SALT_BITS = 16;
|
||||
public const int DT_TILE_BITS = 28;
|
||||
public const int DT_POLY_BITS = 20;
|
||||
|
||||
/// A flag that indicates that an entity links to an external entity.
|
||||
/// (E.g. A polygon edge is a portal that links to another polygon.)
|
||||
public const int DT_EXT_LINK = 0x8000;
|
||||
|
||||
/// A value that indicates the entity does not link to anything.
|
||||
public const int DT_NULL_LINK = unchecked((int)0xffffffff);
|
||||
|
||||
public const int DT_NODE_PARENT_BITS = 24;
|
||||
public const int DT_NODE_STATE_BITS = 2;
|
||||
public const int DT_MAX_STATES_PER_NODE = 1 << DT_NODE_STATE_BITS; // number of extra states per node. See dtNode::state
|
||||
|
||||
/// A flag that indicates that an off-mesh connection can be traversed in
|
||||
/// both directions. (Is bidirectional.)
|
||||
public const int DT_OFFMESH_CON_BIDIR = 1;
|
||||
|
||||
/// The maximum number of user defined area ids.
|
||||
public const int DT_MAX_AREAS = 64;
|
||||
|
||||
/// Limit raycasting during any angle pahfinding
|
||||
/// The limit is given as a multiple of the character radius
|
||||
public const float DT_RAY_CAST_LIMIT_PROPORTIONS = 50.0f;
|
||||
|
||||
/// @{
|
||||
/// @name Encoding and Decoding
|
||||
/// These functions are generally meant for internal use only.
|
||||
/// Derives a standard polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] salt The tile's salt value.
|
||||
/// @param[in] it The index of the tile.
|
||||
/// @param[in] ip The index of the polygon within the tile.
|
||||
public static long EncodePolyId(int salt, int it, int ip)
|
||||
{
|
||||
return (((long)salt) << (DT_POLY_BITS + DT_TILE_BITS)) | ((long)it << DT_POLY_BITS) | (long)ip;
|
||||
}
|
||||
|
||||
/// Decodes a standard polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference to decode.
|
||||
/// @param[out] salt The tile's salt value.
|
||||
/// @param[out] it The index of the tile.
|
||||
/// @param[out] ip The index of the polygon within the tile.
|
||||
/// @see #encodePolyId
|
||||
public static void DecodePolyId(long refs, out int salt, out int it, out int ip)
|
||||
{
|
||||
long saltMask = (1L << DT_SALT_BITS) - 1;
|
||||
long tileMask = (1L << DT_TILE_BITS) - 1;
|
||||
long polyMask = (1L << DT_POLY_BITS) - 1;
|
||||
salt = (int)((refs >> (DT_POLY_BITS + DT_TILE_BITS)) & saltMask);
|
||||
it = (int)((refs >> DT_POLY_BITS) & tileMask);
|
||||
ip = (int)(refs & polyMask);
|
||||
}
|
||||
|
||||
/// Extracts a tile's salt value from the specified polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @see #encodePolyId
|
||||
public static int DecodePolyIdSalt(long refs)
|
||||
{
|
||||
long saltMask = (1L << DT_SALT_BITS) - 1;
|
||||
return (int)((refs >> (DT_POLY_BITS + DT_TILE_BITS)) & saltMask);
|
||||
}
|
||||
|
||||
/// Extracts the tile's index from the specified polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @see #encodePolyId
|
||||
public static int DecodePolyIdTile(long refs)
|
||||
{
|
||||
long tileMask = (1L << DT_TILE_BITS) - 1;
|
||||
return (int)((refs >> DT_POLY_BITS) & tileMask);
|
||||
}
|
||||
|
||||
/// Extracts the polygon's index (within its tile) from the specified
|
||||
/// polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @see #encodePolyId
|
||||
public static int DecodePolyIdPoly(long refs)
|
||||
{
|
||||
long polyMask = (1L << DT_POLY_BITS) - 1;
|
||||
return (int)(refs & polyMask);
|
||||
}
|
||||
|
||||
public static int ComputeTileHash(int x, int y, int mask)
|
||||
{
|
||||
uint h1 = 0x8da6b343; // Large multiplicative constants;
|
||||
uint h2 = 0xd8163841; // here arbitrarily chosen primes
|
||||
uint n = h1 * (uint)x + h2 * (uint)y;
|
||||
return (int)(n & mask);
|
||||
}
|
||||
|
||||
public static float GetSlabCoord(float[] verts, int va, int side)
|
||||
{
|
||||
if (side == 0 || side == 4)
|
||||
{
|
||||
return verts[va];
|
||||
}
|
||||
else if (side == 2 || side == 6)
|
||||
{
|
||||
return verts[va + 2];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void CalcSlabEndPoints(float[] verts, int va, int vb, ref RcVec2f bmin, ref RcVec2f bmax, int side)
|
||||
{
|
||||
if (side == 0 || side == 4)
|
||||
{
|
||||
if (verts[va + 2] < verts[vb + 2])
|
||||
{
|
||||
bmin.X = verts[va + 2];
|
||||
bmin.Y = verts[va + 1];
|
||||
bmax.X = verts[vb + 2];
|
||||
bmax.Y = verts[vb + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
bmin.X = verts[vb + 2];
|
||||
bmin.Y = verts[vb + 1];
|
||||
bmax.X = verts[va + 2];
|
||||
bmax.Y = verts[va + 1];
|
||||
}
|
||||
}
|
||||
else if (side == 2 || side == 6)
|
||||
{
|
||||
if (verts[va + 0] < verts[vb + 0])
|
||||
{
|
||||
bmin.X = verts[va + 0];
|
||||
bmin.Y = verts[va + 1];
|
||||
bmax.X = verts[vb + 0];
|
||||
bmax.Y = verts[vb + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
bmin.X = verts[vb + 0];
|
||||
bmin.Y = verts[vb + 1];
|
||||
bmax.X = verts[va + 0];
|
||||
bmax.Y = verts[va + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get flags for edge in detail triangle.
|
||||
/// @param[in] triFlags The flags for the triangle (last component of detail vertices above).
|
||||
/// @param[in] edgeIndex The index of the first vertex of the edge. For instance, if 0,
|
||||
/// returns flags for edge AB.
|
||||
public static int GetDetailTriEdgeFlags(int triFlags, int edgeIndex)
|
||||
{
|
||||
return (triFlags >> (edgeIndex * 2)) & 0x3;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,31 +3,38 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public class DtFindNearestPolyQuery : IDtPolyQuery
|
||||
public struct DtFindNearestPolyQuery : IDtPolyQuery
|
||||
{
|
||||
private readonly DtNavMeshQuery _query;
|
||||
private readonly RcVec3f _center;
|
||||
private long _nearestRef;
|
||||
private RcVec3f _nearestPt;
|
||||
private bool _overPoly;
|
||||
private float _nearestDistanceSqr;
|
||||
private long _nearestRef;
|
||||
private RcVec3f _nearestPoint;
|
||||
private bool _overPoly;
|
||||
|
||||
public DtFindNearestPolyQuery(DtNavMeshQuery query, RcVec3f center)
|
||||
{
|
||||
this._query = query;
|
||||
this._center = center;
|
||||
_query = query;
|
||||
_center = center;
|
||||
_nearestDistanceSqr = float.MaxValue;
|
||||
_nearestPt = center;
|
||||
_nearestPoint = center;
|
||||
|
||||
_nearestRef = default;
|
||||
_overPoly = default;
|
||||
}
|
||||
|
||||
public void Process(DtMeshTile tile, DtPoly poly, long refs)
|
||||
public void Process(DtMeshTile tile, Span<DtPoly> poly, Span<long> refs, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
long polyRef = refs[i];
|
||||
float d;
|
||||
|
||||
// Find nearest polygon amongst the nearby polygons.
|
||||
_query.ClosestPointOnPoly(refs, _center, out var closestPtPoly, out var posOverPoly);
|
||||
_query.ClosestPointOnPoly(polyRef, _center, out var closestPtPoly, out var posOverPoly);
|
||||
|
||||
// If a point is directly over a polygon and closer than
|
||||
// climb height, favor that instead of straight line nearest point.
|
||||
float d = 0;
|
||||
RcVec3f diff = RcVec3f.Subtract(_center, closestPtPoly);
|
||||
if (posOverPoly)
|
||||
{
|
||||
|
@ -41,12 +48,13 @@ namespace DotRecast.Detour
|
|||
|
||||
if (d < _nearestDistanceSqr)
|
||||
{
|
||||
_nearestPt = closestPtPoly;
|
||||
_nearestPoint = closestPtPoly;
|
||||
_nearestDistanceSqr = d;
|
||||
_nearestRef = refs;
|
||||
_nearestRef = polyRef;
|
||||
_overPoly = posOverPoly;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long NearestRef()
|
||||
{
|
||||
|
@ -55,7 +63,7 @@ namespace DotRecast.Detour
|
|||
|
||||
public RcVec3f NearestPt()
|
||||
{
|
||||
return _nearestPt;
|
||||
return _nearestPoint;
|
||||
}
|
||||
|
||||
public bool OverPoly()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public readonly struct DtFindPathOption
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/// Options for dtNavMeshQuery::initSlicedFindPath and updateSlicedFindPath
|
||||
public static class DtFindPathOptions
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public struct DtHeightSamplePolyQuery : IDtPolyQuery
|
||||
{
|
||||
private readonly DtNavMeshQuery _navMeshQuery;
|
||||
private readonly RcVec3f _pt;
|
||||
private readonly float _maxHeight;
|
||||
public float MinHeight { get; private set; }
|
||||
public bool Found { get; private set; }
|
||||
|
||||
public DtHeightSamplePolyQuery(DtNavMeshQuery navMeshQuery, RcVec3f pt, float minHeight, float maxHeight)
|
||||
{
|
||||
_navMeshQuery = navMeshQuery;
|
||||
_pt = pt;
|
||||
MinHeight = minHeight;
|
||||
_maxHeight = maxHeight;
|
||||
Found = default;
|
||||
}
|
||||
|
||||
public void Process(DtMeshTile tile, Span<DtPoly> poly, Span<long> refs, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
ProcessSingle(refs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessSingle(long refs)
|
||||
{
|
||||
var status = _navMeshQuery.GetPolyHeight(refs, _pt, out var h);
|
||||
if (!status.Succeeded())
|
||||
return;
|
||||
|
||||
if (!(h > MinHeight) || !(h < _maxHeight))
|
||||
return;
|
||||
|
||||
MinHeight = h;
|
||||
Found = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,32 +18,20 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/**
|
||||
* Defines a link between polygons.
|
||||
*
|
||||
* @note This structure is rarely if ever used by the end user.
|
||||
* @see MeshTile
|
||||
*/
|
||||
/// Defines a link between polygons.
|
||||
/// @note This structure is rarely if ever used by the end user.
|
||||
/// @see dtMeshTile
|
||||
public class DtLink
|
||||
{
|
||||
/** Neighbour reference. (The neighbor that is linked to.) */
|
||||
public long refs;
|
||||
|
||||
/** Index of the next link. */
|
||||
public int next;
|
||||
|
||||
/** Index of the polygon edge that owns this link. */
|
||||
public int edge;
|
||||
|
||||
/** If a boundary link, defines on which side the link is. */
|
||||
public int side;
|
||||
|
||||
/** If a boundary link, defines the minimum sub-edge area. */
|
||||
public int bmin;
|
||||
|
||||
/** If a boundary link, defines the maximum sub-edge area. */
|
||||
public int bmax;
|
||||
public long refs; //< Neighbour reference. (The neighbor that is linked to.)
|
||||
public int next; //< Index of the next link.
|
||||
public byte edge; //< Index of the polygon edge that owns this link.
|
||||
public byte side; //< If a boundary link, defines on which side the link is.
|
||||
public byte bmin; //< If a boundary link, defines the minimum sub-edge area.
|
||||
public byte bmax; //< If a boundary link, defines the maximum sub-edge area.
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,37 +18,29 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
[Serializable]
|
||||
public class DtMeshData
|
||||
{
|
||||
/** The tile header. */
|
||||
public DtMeshHeader header;
|
||||
public DtMeshHeader header; //< The tile header.
|
||||
public DtPoly[] polys; //< The tile polygons. [Size: dtMeshHeader::polyCount]
|
||||
public float[] verts; //< The tile vertices. [(x, y, z) * dtMeshHeader::vertCount]
|
||||
public DtPolyDetail[] detailMeshes; //< The tile's detail sub-meshes. [Size: dtMeshHeader::detailMeshCount]
|
||||
|
||||
/** The tile vertices. [Size: MeshHeader::vertCount] */
|
||||
public float[] verts;
|
||||
|
||||
/** The tile polygons. [Size: MeshHeader::polyCount] */
|
||||
public DtPoly[] polys;
|
||||
|
||||
/** The tile's detail sub-meshes. [Size: MeshHeader::detailMeshCount] */
|
||||
public DtPolyDetail[] detailMeshes;
|
||||
|
||||
/** The detail mesh's unique vertices. [(x, y, z) * MeshHeader::detailVertCount] */
|
||||
/// The detail mesh's unique vertices. [(x, y, z) * dtMeshHeader::detailVertCount]
|
||||
public float[] detailVerts;
|
||||
|
||||
/**
|
||||
* The detail mesh's triangles. [(vertA, vertB, vertC) * MeshHeader::detailTriCount] See DetailTriEdgeFlags and
|
||||
* NavMesh::getDetailTriEdgeFlags.
|
||||
*/
|
||||
/// The detail mesh's triangles. [(vertA, vertB, vertC, triFlags) * dtMeshHeader::detailTriCount].
|
||||
/// See dtDetailTriEdgeFlags and dtGetDetailTriEdgeFlags.
|
||||
public int[] detailTris;
|
||||
|
||||
/**
|
||||
* The tile bounding volume nodes. [Size: MeshHeader::bvNodeCount] (Will be null if bounding volumes are disabled.)
|
||||
*/
|
||||
/// The tile bounding volume nodes. [Size: dtMeshHeader::bvNodeCount]
|
||||
/// (Will be null if bounding volumes are disabled.)
|
||||
public DtBVNode[] bvTree;
|
||||
|
||||
/** The tile off-mesh connections. [Size: MeshHeader::offMeshConCount] */
|
||||
public DtOffMeshConnection[] offMeshCons;
|
||||
public DtOffMeshConnection[] offMeshCons; //< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,11 +18,13 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/** Provides high level information related to a dtMeshTile object. */
|
||||
[Serializable]
|
||||
public class DtMeshHeader
|
||||
{
|
||||
/** Tile magic number. (Used to identify the data format.) */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,33 +18,22 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/**
|
||||
* Defines a navigation mesh tile.
|
||||
*/
|
||||
using static DtDetour;
|
||||
|
||||
/// Defines a navigation mesh tile.
|
||||
/// @ingroup detour
|
||||
public class DtMeshTile
|
||||
{
|
||||
public readonly int index;
|
||||
public readonly int index; // DtNavMesh.m_tiles array index
|
||||
public int linksFreeList = DT_NULL_LINK; //< Index to the next free link.
|
||||
public int salt; //< Counter describing modifications to the tile.
|
||||
public DtMeshData data; // The tile data.
|
||||
public DtLink[] links; // The tile links. [Size: dtMeshHeader::maxLinkCount]
|
||||
|
||||
/** Counter describing modifications to the tile. */
|
||||
public int salt;
|
||||
|
||||
/** The tile data. */
|
||||
public DtMeshData data;
|
||||
|
||||
public int[] polyLinks;
|
||||
|
||||
/** The tile links. */
|
||||
public readonly List<DtLink> links = new List<DtLink>();
|
||||
|
||||
/** Index to the next free link. */
|
||||
public int linksFreeList = DtNavMesh.DT_NULL_LINK; // FIXME: Remove
|
||||
|
||||
/** Tile flags. (See: #dtTileFlags) */
|
||||
public int flags;
|
||||
public int flags; //< Tile flags. (See: #dtTileFlags)
|
||||
public DtMeshTile next; //< The next free tile, or the next tile in the spatial grid.
|
||||
|
||||
public DtMeshTile(int index)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -25,99 +25,66 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
using static DtDetour;
|
||||
|
||||
/// A navigation mesh based on tiles of convex polygons.
|
||||
/// @ingroup detour
|
||||
public class DtNavMesh
|
||||
{
|
||||
/** A magic number used to detect compatibility of navigation tile data. */
|
||||
public const int DT_NAVMESH_MAGIC = 'D' << 24 | 'N' << 16 | 'A' << 8 | 'V';
|
||||
private DtNavMeshParams m_params; //< Current initialization params. TODO: do not store this info twice.
|
||||
private RcVec3f m_orig; // < Origin of the tile (0,0)
|
||||
private float m_tileWidth; // < Dimensions of each tile.
|
||||
private float m_tileHeight; // < Dimensions of each tile.
|
||||
private int m_maxTiles; // < Max number of tiles.
|
||||
private int m_tileLutSize; //< Tile hash lookup size (must be pot).
|
||||
private int m_tileLutMask; // < Tile hash lookup mask.
|
||||
|
||||
/** A version number used to detect compatibility of navigation tile data. */
|
||||
public const int DT_NAVMESH_VERSION = 7;
|
||||
private DtMeshTile[] m_posLookup; //< Tile hash lookup.
|
||||
private DtMeshTile m_nextFree; //< Freelist of tiles.
|
||||
private DtMeshTile[] m_tiles; //< List of tiles.
|
||||
|
||||
public const int DT_NAVMESH_VERSION_RECAST4J_FIRST = 0x8807;
|
||||
public const int DT_NAVMESH_VERSION_RECAST4J_NO_POLY_FIRSTLINK = 0x8808;
|
||||
public const int DT_NAVMESH_VERSION_RECAST4J_32BIT_BVTREE = 0x8809;
|
||||
public const int DT_NAVMESH_VERSION_RECAST4J_LAST = 0x8809;
|
||||
|
||||
/** A magic number used to detect the compatibility of navigation tile states. */
|
||||
public const int DT_NAVMESH_STATE_MAGIC = 'D' << 24 | 'N' << 16 | 'M' << 8 | 'S';
|
||||
|
||||
/** A version number used to detect compatibility of navigation tile states. */
|
||||
public const int DT_NAVMESH_STATE_VERSION = 1;
|
||||
|
||||
public const int DT_SALT_BITS = 16;
|
||||
public const int DT_TILE_BITS = 28;
|
||||
public const int DT_POLY_BITS = 20;
|
||||
|
||||
/// A flag that indicates that an entity links to an external entity.
|
||||
/// (E.g. A polygon edge is a portal that links to another polygon.)
|
||||
public const int DT_EXT_LINK = 0x8000;
|
||||
|
||||
/// A value that indicates the entity does not link to anything.
|
||||
public const int DT_NULL_LINK = unchecked((int)0xffffffff);
|
||||
|
||||
/// A flag that indicates that an off-mesh connection can be traversed in
|
||||
/// both directions. (Is bidirectional.)
|
||||
public const int DT_OFFMESH_CON_BIDIR = 1;
|
||||
|
||||
/// The maximum number of user defined area ids.
|
||||
public const int DT_MAX_AREAS = 64;
|
||||
|
||||
/// Limit raycasting during any angle pahfinding
|
||||
/// The limit is given as a multiple of the character radius
|
||||
public const float DT_RAY_CAST_LIMIT_PROPORTIONS = 50.0f;
|
||||
|
||||
private readonly DtNavMeshParams m_params;
|
||||
|
||||
/// < Current initialization params. TODO: do not store this info twice.
|
||||
private readonly RcVec3f m_orig;
|
||||
|
||||
/// < Origin of the tile (0,0)
|
||||
// float m_orig[3]; ///< Origin of the tile (0,0)
|
||||
private float m_tileWidth;
|
||||
|
||||
private float m_tileHeight;
|
||||
|
||||
/// < Dimensions of each tile.
|
||||
int m_maxTiles;
|
||||
|
||||
/// < Max number of tiles.
|
||||
private readonly int m_tileLutMask;
|
||||
|
||||
/// < Tile hash lookup mask.
|
||||
private readonly Dictionary<int, List<DtMeshTile>> posLookup = new Dictionary<int, List<DtMeshTile>>();
|
||||
|
||||
private readonly LinkedList<DtMeshTile> availableTiles = new LinkedList<DtMeshTile>();
|
||||
private readonly DtMeshTile[] m_tiles;
|
||||
|
||||
/// < List of tiles.
|
||||
/** The maximum number of vertices per navigation polygon. */
|
||||
private readonly int m_maxVertPerPoly;
|
||||
private int m_maxVertPerPoly;
|
||||
|
||||
private int m_tileCount;
|
||||
|
||||
public DtNavMesh(DtMeshData data, int maxVertsPerPoly, int flags)
|
||||
: this(GetNavMeshParams(data), maxVertsPerPoly)
|
||||
public DtStatus Init(DtNavMeshParams param, int maxVertsPerPoly)
|
||||
{
|
||||
AddTile(data, flags, 0);
|
||||
}
|
||||
m_params = param;
|
||||
m_orig = param.orig;
|
||||
m_tileWidth = param.tileWidth;
|
||||
m_tileHeight = param.tileHeight;
|
||||
|
||||
public DtNavMesh(DtNavMeshParams option, int maxVertsPerPoly)
|
||||
{
|
||||
m_params = option;
|
||||
m_orig = option.orig;
|
||||
m_tileWidth = option.tileWidth;
|
||||
m_tileHeight = option.tileHeight;
|
||||
// Init tiles
|
||||
m_maxTiles = option.maxTiles;
|
||||
m_maxVertPerPoly = maxVertsPerPoly;
|
||||
m_tileLutMask = Math.Max(1, DtUtils.NextPow2(option.maxTiles)) - 1;
|
||||
m_maxTiles = param.maxTiles;
|
||||
m_tileLutSize = DtUtils.NextPow2(param.maxTiles);
|
||||
if (0 == m_tileLutSize)
|
||||
m_tileLutSize = 1;
|
||||
m_tileLutMask = m_tileLutSize - 1;
|
||||
|
||||
m_tiles = new DtMeshTile[m_maxTiles];
|
||||
for (int i = 0; i < m_maxTiles; i++)
|
||||
m_posLookup = new DtMeshTile[m_tileLutSize];
|
||||
m_nextFree = null;
|
||||
for (int i = m_maxTiles - 1; i >= 0; --i)
|
||||
{
|
||||
m_tiles[i] = new DtMeshTile(i);
|
||||
m_tiles[i].salt = 1;
|
||||
availableTiles.AddLast(m_tiles[i]);
|
||||
m_tiles[i].next = m_nextFree;
|
||||
m_nextFree = m_tiles[i];
|
||||
}
|
||||
|
||||
return DtStatus.DT_SUCCESS;
|
||||
}
|
||||
|
||||
public DtStatus Init(DtMeshData data, int maxVertsPerPoly, int flags)
|
||||
{
|
||||
var option = GetNavMeshParams(data);
|
||||
DtStatus status = Init(option, maxVertsPerPoly);
|
||||
if (status.Failed())
|
||||
return status;
|
||||
|
||||
return AddTile(data, flags, 0, out _);
|
||||
}
|
||||
|
||||
private static DtNavMeshParams GetNavMeshParams(DtMeshData data)
|
||||
|
@ -168,76 +135,10 @@ namespace DotRecast.Detour
|
|||
return EncodePolyId(tile.salt, it, 0);
|
||||
}
|
||||
|
||||
/// @{
|
||||
/// @name Encoding and Decoding
|
||||
/// These functions are generally meant for internal use only.
|
||||
/// Derives a standard polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] salt The tile's salt value.
|
||||
/// @param[in] it The index of the tile.
|
||||
/// @param[in] ip The index of the polygon within the tile.
|
||||
public static long EncodePolyId(int salt, int it, int ip)
|
||||
{
|
||||
return (((long)salt) << (DT_POLY_BITS + DT_TILE_BITS)) | ((long)it << DT_POLY_BITS) | (long)ip;
|
||||
}
|
||||
|
||||
/// Decodes a standard polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference to decode.
|
||||
/// @param[out] salt The tile's salt value.
|
||||
/// @param[out] it The index of the tile.
|
||||
/// @param[out] ip The index of the polygon within the tile.
|
||||
/// @see #encodePolyId
|
||||
static void DecodePolyId(long refs, out int salt, out int it, out int ip)
|
||||
{
|
||||
long saltMask = (1L << DT_SALT_BITS) - 1;
|
||||
long tileMask = (1L << DT_TILE_BITS) - 1;
|
||||
long polyMask = (1L << DT_POLY_BITS) - 1;
|
||||
salt = (int)((refs >> (DT_POLY_BITS + DT_TILE_BITS)) & saltMask);
|
||||
it = (int)((refs >> DT_POLY_BITS) & tileMask);
|
||||
ip = (int)(refs & polyMask);
|
||||
}
|
||||
|
||||
/// Extracts a tile's salt value from the specified polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @see #encodePolyId
|
||||
static int DecodePolyIdSalt(long refs)
|
||||
{
|
||||
long saltMask = (1L << DT_SALT_BITS) - 1;
|
||||
return (int)((refs >> (DT_POLY_BITS + DT_TILE_BITS)) & saltMask);
|
||||
}
|
||||
|
||||
/// Extracts the tile's index from the specified polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @see #encodePolyId
|
||||
public static int DecodePolyIdTile(long refs)
|
||||
{
|
||||
long tileMask = (1L << DT_TILE_BITS) - 1;
|
||||
return (int)((refs >> DT_POLY_BITS) & tileMask);
|
||||
}
|
||||
|
||||
/// Extracts the polygon's index (within its tile) from the specified
|
||||
/// polygon reference.
|
||||
/// @note This function is generally meant for internal use only.
|
||||
/// @param[in] ref The polygon reference.
|
||||
/// @see #encodePolyId
|
||||
static int DecodePolyIdPoly(long refs)
|
||||
{
|
||||
long polyMask = (1L << DT_POLY_BITS) - 1;
|
||||
return (int)(refs & polyMask);
|
||||
}
|
||||
|
||||
private int AllocLink(DtMeshTile tile)
|
||||
{
|
||||
if (tile.linksFreeList == DT_NULL_LINK)
|
||||
{
|
||||
DtLink link = new DtLink();
|
||||
link.next = DT_NULL_LINK;
|
||||
tile.links.Add(link);
|
||||
return tile.links.Count - 1;
|
||||
}
|
||||
return DT_NULL_LINK;
|
||||
|
||||
int linkIdx = tile.linksFreeList;
|
||||
tile.linksFreeList = tile.links[linkIdx].next;
|
||||
|
@ -358,8 +259,8 @@ namespace DotRecast.Detour
|
|||
var tbmax = tile.data.header.bmax;
|
||||
float qfac = tile.data.header.bvQuantFactor;
|
||||
// Calculate quantized box
|
||||
int[] bmin = new int[3];
|
||||
int[] bmax = new int[3];
|
||||
RcVec3i bmin;
|
||||
RcVec3i bmax;
|
||||
// dtClamp query box to world box.
|
||||
float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X;
|
||||
float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
|
||||
|
@ -368,12 +269,12 @@ namespace DotRecast.Detour
|
|||
float maxy = Math.Clamp(qmax.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
|
||||
float maxz = Math.Clamp(qmax.Z, tbmin.Z, tbmax.Z) - tbmin.Z;
|
||||
// Quantize
|
||||
bmin[0] = (int)(qfac * minx) & 0x7ffffffe;
|
||||
bmin[1] = (int)(qfac * miny) & 0x7ffffffe;
|
||||
bmin[2] = (int)(qfac * minz) & 0x7ffffffe;
|
||||
bmax[0] = (int)(qfac * maxx + 1) | 1;
|
||||
bmax[1] = (int)(qfac * maxy + 1) | 1;
|
||||
bmax[2] = (int)(qfac * maxz + 1) | 1;
|
||||
bmin.X = (int)(qfac * minx) & 0x7ffffffe;
|
||||
bmin.Y = (int)(qfac * miny) & 0x7ffffffe;
|
||||
bmin.Z = (int)(qfac * minz) & 0x7ffffffe;
|
||||
bmax.X = (int)(qfac * maxx + 1) | 1;
|
||||
bmax.Y = (int)(qfac * maxy + 1) | 1;
|
||||
bmax.Z = (int)(qfac * maxz + 1) | 1;
|
||||
|
||||
// Traverse tree
|
||||
long @base = GetPolyRefBase(tile);
|
||||
|
@ -381,7 +282,7 @@ namespace DotRecast.Detour
|
|||
while (nodeIndex < end)
|
||||
{
|
||||
DtBVNode node = tile.data.bvTree[nodeIndex];
|
||||
bool overlap = DtUtils.OverlapQuantBounds(bmin, bmax, node.bmin, node.bmax);
|
||||
bool overlap = DtUtils.OverlapQuantBounds(ref bmin, ref bmax, ref node.bmin, ref node.bmax);
|
||||
bool isLeafNode = node.i >= 0;
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
|
@ -418,13 +319,13 @@ namespace DotRecast.Detour
|
|||
|
||||
// Calc polygon bounds.
|
||||
int v = p.verts[0] * 3;
|
||||
bmin = RcVecUtils.Create(tile.data.verts, v);
|
||||
bmax = RcVecUtils.Create(tile.data.verts, v);
|
||||
bmin = RcVec.Create(tile.data.verts, v);
|
||||
bmax = RcVec.Create(tile.data.verts, v);
|
||||
for (int j = 1; j < p.vertCount; ++j)
|
||||
{
|
||||
v = p.verts[j] * 3;
|
||||
bmin = RcVecUtils.Min(bmin, tile.data.verts, v);
|
||||
bmax = RcVecUtils.Max(bmax, tile.data.verts, v);
|
||||
bmin = RcVec3f.Min(bmin, RcVec.Create(tile.data.verts, v));
|
||||
bmax = RcVec3f.Max(bmax, RcVec.Create(tile.data.verts, v));
|
||||
}
|
||||
|
||||
if (DtUtils.OverlapBounds(qmin, qmax, bmin, bmax))
|
||||
|
@ -437,30 +338,20 @@ namespace DotRecast.Detour
|
|||
}
|
||||
}
|
||||
|
||||
public long UpdateTile(DtMeshData data, int flags)
|
||||
public DtStatus UpdateTile(DtMeshData data, int flags)
|
||||
{
|
||||
long refs = GetTileRefAt(data.header.x, data.header.y, data.header.layer);
|
||||
refs = RemoveTile(refs);
|
||||
return AddTile(data, flags, refs);
|
||||
return AddTile(data, flags, refs, out _);
|
||||
}
|
||||
|
||||
/// Adds a tile to the navigation mesh.
|
||||
/// @param[in] data Data for the new tile mesh. (See: #dtCreateNavMeshData)
|
||||
/// @param[in] dataSize Data size of the new tile mesh.
|
||||
/// @param[in] flags Tile flags. (See: #dtTileFlags)
|
||||
/// @param[in] lastRef The desired reference for the tile. (When reloading a
|
||||
/// tile.) [opt] [Default: 0]
|
||||
/// @param[out] result The tile reference. (If the tile was succesfully
|
||||
/// added.) [opt]
|
||||
/// @return The status flags for the operation.
|
||||
/// @par
|
||||
///
|
||||
/// The add operation will fail if the data is in the wrong format, the
|
||||
/// allocated tile
|
||||
/// The add operation will fail if the data is in the wrong format, the allocated tile
|
||||
/// space is full, or there is a tile already at the specified reference.
|
||||
///
|
||||
/// The lastRef parameter is used to restore a tile with the same tile
|
||||
/// reference it had previously used. In this case the #long's for the
|
||||
/// reference it had previously used. In this case the #dtPolyRef's for the
|
||||
/// tile will be restored to the same values they were before the tile was
|
||||
/// removed.
|
||||
///
|
||||
|
@ -470,64 +361,91 @@ namespace DotRecast.Detour
|
|||
/// removed from this nav mesh.
|
||||
///
|
||||
/// @see dtCreateNavMeshData, #removeTile
|
||||
public long AddTile(DtMeshData data, int flags, long lastRef)
|
||||
/// Adds a tile to the navigation mesh.
|
||||
/// @param[in] data Data for the new tile mesh. (See: #dtCreateNavMeshData)
|
||||
/// @param[in] dataSize Data size of the new tile mesh.
|
||||
/// @param[in] flags Tile flags. (See: #dtTileFlags)
|
||||
/// @param[in] lastRef The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
|
||||
/// @param[out] result The tile reference. (If the tile was succesfully added.) [opt]
|
||||
/// @return The status flags for the operation.
|
||||
public DtStatus AddTile(DtMeshData data, int flags, long lastRef, out long result)
|
||||
{
|
||||
result = 0;
|
||||
|
||||
// Make sure the data is in right format.
|
||||
DtMeshHeader header = data.header;
|
||||
|
||||
// Make sure the location is free.
|
||||
if (GetTileAt(header.x, header.y, header.layer) != null)
|
||||
{
|
||||
throw new Exception("Tile already exists");
|
||||
return DtStatus.DT_FAILURE | DtStatus.DT_ALREADY_OCCUPIED;
|
||||
}
|
||||
|
||||
// Allocate a tile.
|
||||
DtMeshTile tile = null;
|
||||
if (lastRef == 0)
|
||||
{
|
||||
// Make sure we could allocate a tile.
|
||||
if (0 == availableTiles.Count)
|
||||
if (null != m_nextFree)
|
||||
{
|
||||
throw new Exception("Could not allocate a tile");
|
||||
}
|
||||
|
||||
tile = availableTiles.First?.Value;
|
||||
availableTiles.RemoveFirst();
|
||||
tile = m_nextFree;
|
||||
m_nextFree = tile.next;
|
||||
tile.next = null;
|
||||
m_tileCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to relocate the tile to specific index with same salt.
|
||||
int tileIndex = DecodePolyIdTile(lastRef);
|
||||
if (tileIndex >= m_maxTiles)
|
||||
{
|
||||
throw new Exception("Tile index too high");
|
||||
return DtStatus.DT_FAILURE | DtStatus.DT_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Try to find the specific tile id from the free list.
|
||||
DtMeshTile target = m_tiles[tileIndex];
|
||||
// Remove from freelist
|
||||
if (!availableTiles.Remove(target))
|
||||
DtMeshTile prev = null;
|
||||
tile = m_nextFree;
|
||||
|
||||
while (null != tile && tile != target)
|
||||
{
|
||||
// Could not find the correct location.
|
||||
throw new Exception("Could not find tile");
|
||||
prev = tile;
|
||||
tile = tile.next;
|
||||
}
|
||||
|
||||
tile = target;
|
||||
// Could not find the correct location.
|
||||
if (tile != target)
|
||||
return DtStatus.DT_FAILURE | DtStatus.DT_OUT_OF_MEMORY;
|
||||
|
||||
// Remove from freelist
|
||||
if (null == prev)
|
||||
m_nextFree = tile.next;
|
||||
else
|
||||
prev.next = tile.next;
|
||||
|
||||
// Restore salt.
|
||||
tile.salt = DecodePolyIdSalt(lastRef);
|
||||
}
|
||||
|
||||
tile.data = data;
|
||||
tile.flags = flags;
|
||||
tile.links.Clear();
|
||||
tile.polyLinks = new int[data.polys.Length];
|
||||
Array.Fill(tile.polyLinks, DtNavMesh.DT_NULL_LINK);
|
||||
// Make sure we could allocate a tile.
|
||||
if (null == tile)
|
||||
{
|
||||
return DtStatus.DT_FAILURE | DtStatus.DT_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Insert tile into the position lut.
|
||||
GetTileListByPos(header.x, header.y).Add(tile);
|
||||
int h = ComputeTileHash(header.x, header.y, m_tileLutMask);
|
||||
tile.next = m_posLookup[h];
|
||||
m_posLookup[h] = tile;
|
||||
|
||||
|
||||
// Patch header pointers.
|
||||
tile.data = data;
|
||||
tile.links = new DtLink[data.header.maxLinkCount];
|
||||
for (int i = 0; i < tile.links.Length; ++i)
|
||||
{
|
||||
tile.links[i] = new DtLink();
|
||||
}
|
||||
|
||||
// If there are no items in the bvtree, reset the tree pointer.
|
||||
if (tile.data.bvTree != null && tile.data.bvTree.Length == 0)
|
||||
|
@ -535,16 +453,29 @@ namespace DotRecast.Detour
|
|||
tile.data.bvTree = null;
|
||||
}
|
||||
|
||||
// Build links freelist
|
||||
tile.linksFreeList = 0;
|
||||
tile.links[data.header.maxLinkCount - 1].next = DT_NULL_LINK;
|
||||
for (int i = 0; i < data.header.maxLinkCount - 1; ++i)
|
||||
tile.links[i].next = i + 1;
|
||||
|
||||
// Init tile.
|
||||
tile.flags = flags;
|
||||
|
||||
ConnectIntLinks(tile);
|
||||
|
||||
// Base off-mesh connections to their starting polygons and connect connections inside the tile.
|
||||
BaseOffMeshLinks(tile);
|
||||
ConnectExtOffMeshLinks(tile, tile, -1);
|
||||
|
||||
// Create connections with neighbour tiles.
|
||||
const int MAX_NEIS = 32;
|
||||
DtMeshTile[] neis = new DtMeshTile[MAX_NEIS];
|
||||
int nneis;
|
||||
|
||||
// Connect with layers in current tile.
|
||||
List<DtMeshTile> neis = GetTilesAt(header.x, header.y);
|
||||
for (int j = 0; j < neis.Count; ++j)
|
||||
nneis = GetTilesAt(header.x, header.y, neis, MAX_NEIS);
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
if (neis[j] == tile)
|
||||
{
|
||||
|
@ -560,8 +491,8 @@ namespace DotRecast.Detour
|
|||
// Connect with neighbour tiles.
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
neis = GetNeighbourTilesAt(header.x, header.y, i);
|
||||
for (int j = 0; j < neis.Count; ++j)
|
||||
nneis = GetNeighbourTilesAt(header.x, header.y, i, neis, MAX_NEIS);
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
ConnectExtLinks(tile, neis[j], i);
|
||||
ConnectExtLinks(neis[j], tile, DtUtils.OppositeTile(i));
|
||||
|
@ -570,7 +501,8 @@ namespace DotRecast.Detour
|
|||
}
|
||||
}
|
||||
|
||||
return GetTileRef(tile);
|
||||
result = GetTileRef(tile);
|
||||
return DtStatus.DT_SUCCESS;
|
||||
}
|
||||
|
||||
/// Removes the specified tile from the navigation mesh.
|
||||
|
@ -603,39 +535,52 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
// Remove tile from hash lookup.
|
||||
GetTileListByPos(tile.data.header.x, tile.data.header.y).Remove(tile);
|
||||
|
||||
// Remove connections to neighbour tiles.
|
||||
// Create connections with neighbour tiles.
|
||||
|
||||
// Disconnect from other layers in current tile.
|
||||
List<DtMeshTile> nneis = GetTilesAt(tile.data.header.x, tile.data.header.y);
|
||||
foreach (DtMeshTile j in nneis)
|
||||
int h = ComputeTileHash(tile.data.header.x, tile.data.header.y, m_tileLutMask);
|
||||
DtMeshTile prev = null;
|
||||
DtMeshTile cur = m_posLookup[h];
|
||||
while (null != cur)
|
||||
{
|
||||
if (j == tile)
|
||||
if (cur == tile)
|
||||
{
|
||||
continue;
|
||||
if (null != prev)
|
||||
prev.next = cur.next;
|
||||
else
|
||||
m_posLookup[h] = cur.next;
|
||||
break;
|
||||
}
|
||||
|
||||
UnconnectLinks(j, tile);
|
||||
prev = cur;
|
||||
cur = cur.next;
|
||||
}
|
||||
|
||||
// Remove connections to neighbour tiles.
|
||||
const int MAX_NEIS = 32;
|
||||
DtMeshTile[] neis = new DtMeshTile[MAX_NEIS];
|
||||
int nneis = 0;
|
||||
|
||||
// Disconnect from other layers in current tile.
|
||||
nneis = GetTilesAt(tile.data.header.x, tile.data.header.y, neis, MAX_NEIS);
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
if (neis[j] == tile) continue;
|
||||
UnconnectLinks(neis[j], tile);
|
||||
}
|
||||
|
||||
// Disconnect from neighbour tiles.
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
nneis = GetNeighbourTilesAt(tile.data.header.x, tile.data.header.y, i);
|
||||
foreach (DtMeshTile j in nneis)
|
||||
nneis = GetNeighbourTilesAt(tile.data.header.x, tile.data.header.y, i, neis, MAX_NEIS);
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
UnconnectLinks(j, tile);
|
||||
UnconnectLinks(neis[j], tile);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset tile.
|
||||
tile.data = null;
|
||||
|
||||
tile.flags = 0;
|
||||
tile.links.Clear();
|
||||
tile.linksFreeList = DtNavMesh.DT_NULL_LINK;
|
||||
tile.links = null;
|
||||
tile.linksFreeList = DT_NULL_LINK;
|
||||
|
||||
// Update salt, salt should never be zero.
|
||||
tile.salt = (tile.salt + 1) & ((1 << DT_SALT_BITS) - 1);
|
||||
|
@ -645,7 +590,8 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
// Add to free list.
|
||||
availableTiles.AddFirst(tile);
|
||||
tile.next = m_nextFree;
|
||||
m_nextFree = tile;
|
||||
m_tileCount--;
|
||||
return GetTileRef(tile);
|
||||
}
|
||||
|
@ -663,7 +609,7 @@ namespace DotRecast.Detour
|
|||
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
||||
{
|
||||
DtPoly poly = tile.data.polys[i];
|
||||
tile.polyLinks[poly.index] = DT_NULL_LINK;
|
||||
poly.firstLink = DT_NULL_LINK;
|
||||
|
||||
if (poly.GetPolyType() == DtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
{
|
||||
|
@ -683,17 +629,17 @@ namespace DotRecast.Detour
|
|||
int idx = AllocLink(tile);
|
||||
DtLink link = tile.links[idx];
|
||||
link.refs = @base | (long)(poly.neis[j] - 1);
|
||||
link.edge = j;
|
||||
link.edge = (byte)j;
|
||||
link.side = 0xff;
|
||||
link.bmin = link.bmax = 0;
|
||||
// Add to linked list.
|
||||
link.next = tile.polyLinks[poly.index];
|
||||
tile.polyLinks[poly.index] = idx;
|
||||
link.next = poly.firstLink;
|
||||
poly.firstLink = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes external links at specified side.V
|
||||
/// Removes external links at specified side.
|
||||
void UnconnectLinks(DtMeshTile tile, DtMeshTile target)
|
||||
{
|
||||
if (tile == null || target == null)
|
||||
|
@ -706,7 +652,7 @@ namespace DotRecast.Detour
|
|||
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
||||
{
|
||||
DtPoly poly = tile.data.polys[i];
|
||||
int j = tile.polyLinks[poly.index];
|
||||
int j = poly.firstLink;
|
||||
int pj = DT_NULL_LINK;
|
||||
while (j != DT_NULL_LINK)
|
||||
{
|
||||
|
@ -716,7 +662,7 @@ namespace DotRecast.Detour
|
|||
int nj = tile.links[j].next;
|
||||
if (pj == DT_NULL_LINK)
|
||||
{
|
||||
tile.polyLinks[poly.index] = nj;
|
||||
poly.firstLink = nj;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -776,13 +722,15 @@ namespace DotRecast.Detour
|
|||
foreach (var connectPoly in connectPolys)
|
||||
{
|
||||
int idx = AllocLink(tile);
|
||||
if (idx != DT_NULL_LINK)
|
||||
{
|
||||
DtLink link = tile.links[idx];
|
||||
link.refs = connectPoly.refs;
|
||||
link.edge = j;
|
||||
link.side = dir;
|
||||
link.edge = (byte)j;
|
||||
link.side = (byte)dir;
|
||||
|
||||
link.next = tile.polyLinks[poly.index];
|
||||
tile.polyLinks[poly.index] = idx;
|
||||
link.next = poly.firstLink;
|
||||
poly.firstLink = idx;
|
||||
|
||||
// Compress portal limits to a byte value.
|
||||
if (dir == 0 || dir == 4)
|
||||
|
@ -798,8 +746,8 @@ namespace DotRecast.Detour
|
|||
tmax = temp;
|
||||
}
|
||||
|
||||
link.bmin = (int)MathF.Round(Math.Clamp(tmin, 0.0f, 1.0f) * 255.0f);
|
||||
link.bmax = (int)MathF.Round(Math.Clamp(tmax, 0.0f, 1.0f) * 255.0f);
|
||||
link.bmin = (byte)MathF.Round(Math.Clamp(tmin, 0.0f, 1.0f) * 255.0f);
|
||||
link.bmax = (byte)MathF.Round(Math.Clamp(tmax, 0.0f, 1.0f) * 255.0f);
|
||||
}
|
||||
else if (dir == 2 || dir == 6)
|
||||
{
|
||||
|
@ -814,8 +762,9 @@ namespace DotRecast.Detour
|
|||
tmax = temp;
|
||||
}
|
||||
|
||||
link.bmin = (int)MathF.Round(Math.Clamp(tmin, 0.0f, 1.0f) * 255.0f);
|
||||
link.bmax = (int)MathF.Round(Math.Clamp(tmax, 0.0f, 1.0f) * 255.0f);
|
||||
link.bmin = (byte)MathF.Round(Math.Clamp(tmin, 0.0f, 1.0f) * 255.0f);
|
||||
link.bmax = (byte)MathF.Round(Math.Clamp(tmax, 0.0f, 1.0f) * 255.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -845,7 +794,7 @@ namespace DotRecast.Detour
|
|||
DtPoly targetPoly = target.data.polys[targetCon.poly];
|
||||
// Skip off-mesh connections which start location could not be
|
||||
// connected at all.
|
||||
if (target.polyLinks[targetPoly.index] == DT_NULL_LINK)
|
||||
if (targetPoly.firstLink == DT_NULL_LINK)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -883,11 +832,11 @@ namespace DotRecast.Detour
|
|||
DtLink link = target.links[idx];
|
||||
link.refs = refs;
|
||||
link.edge = 1;
|
||||
link.side = oppositeSide;
|
||||
link.side = (byte)oppositeSide;
|
||||
link.bmin = link.bmax = 0;
|
||||
// Add to linked list.
|
||||
link.next = target.polyLinks[targetPoly.index];
|
||||
target.polyLinks[targetPoly.index] = idx;
|
||||
link.next = targetPoly.firstLink;
|
||||
targetPoly.firstLink = idx;
|
||||
|
||||
// Link target poly to off-mesh connection.
|
||||
if ((targetCon.flags & DT_OFFMESH_CON_BIDIR) != 0)
|
||||
|
@ -898,11 +847,11 @@ namespace DotRecast.Detour
|
|||
link = tile.links[tidx];
|
||||
link.refs = GetPolyRefBase(target) | (long)targetCon.poly;
|
||||
link.edge = 0xff;
|
||||
link.side = (side == -1 ? 0xff : side);
|
||||
link.side = (byte)(side == -1 ? 0xff : side);
|
||||
link.bmin = link.bmax = 0;
|
||||
// Add to linked list.
|
||||
link.next = tile.polyLinks[landPoly.index];
|
||||
tile.polyLinks[landPoly.index] = tidx;
|
||||
link.next = landPoly.firstLink;
|
||||
landPoly.firstLink = tidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -969,59 +918,7 @@ namespace DotRecast.Detour
|
|||
return n;
|
||||
}
|
||||
|
||||
static float GetSlabCoord(float[] verts, int va, int side)
|
||||
{
|
||||
if (side == 0 || side == 4)
|
||||
{
|
||||
return verts[va];
|
||||
}
|
||||
else if (side == 2 || side == 6)
|
||||
{
|
||||
return verts[va + 2];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void CalcSlabEndPoints(float[] verts, int va, int vb, ref RcVec2f bmin, ref RcVec2f bmax, int side)
|
||||
{
|
||||
if (side == 0 || side == 4)
|
||||
{
|
||||
if (verts[va + 2] < verts[vb + 2])
|
||||
{
|
||||
bmin.X = verts[va + 2];
|
||||
bmin.Y = verts[va + 1];
|
||||
bmax.X = verts[vb + 2];
|
||||
bmax.Y = verts[vb + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
bmin.X = verts[vb + 2];
|
||||
bmin.Y = verts[vb + 1];
|
||||
bmax.X = verts[va + 2];
|
||||
bmax.Y = verts[va + 1];
|
||||
}
|
||||
}
|
||||
else if (side == 2 || side == 6)
|
||||
{
|
||||
if (verts[va + 0] < verts[vb + 0])
|
||||
{
|
||||
bmin.X = verts[va + 0];
|
||||
bmin.Y = verts[va + 1];
|
||||
bmax.X = verts[vb + 0];
|
||||
bmax.Y = verts[vb + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
bmin.X = verts[vb + 0];
|
||||
bmin.Y = verts[vb + 1];
|
||||
bmax.X = verts[va + 0];
|
||||
bmax.Y = verts[va + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OverlapSlabs(RcVec2f amin, RcVec2f amax, RcVec2f bmin, RcVec2f bmax, float px, float py)
|
||||
private bool OverlapSlabs(RcVec2f amin, RcVec2f amax, RcVec2f bmin, RcVec2f bmax, float px, float py)
|
||||
{
|
||||
// Check for horizontal overlap.
|
||||
// The segment is shrunken a little so that slabs which touch
|
||||
|
@ -1112,8 +1009,8 @@ namespace DotRecast.Detour
|
|||
link.side = 0xff;
|
||||
link.bmin = link.bmax = 0;
|
||||
// Add to linked list.
|
||||
link.next = tile.polyLinks[poly.index];
|
||||
tile.polyLinks[poly.index] = idx;
|
||||
link.next = poly.firstLink;
|
||||
poly.firstLink = idx;
|
||||
|
||||
// Start end-point is always connect back to off-mesh connection.
|
||||
int tidx = AllocLink(tile);
|
||||
|
@ -1125,8 +1022,8 @@ namespace DotRecast.Detour
|
|||
link.side = 0xff;
|
||||
link.bmin = link.bmax = 0;
|
||||
// Add to linked list.
|
||||
link.next = tile.polyLinks[landPoly.index];
|
||||
tile.polyLinks[landPoly.index] = tidx;
|
||||
link.next = landPoly.firstLink;
|
||||
landPoly.firstLink = tidx;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1148,6 +1045,7 @@ namespace DotRecast.Detour
|
|||
RcVec3f pmin = new RcVec3f();
|
||||
RcVec3f pmax = new RcVec3f();
|
||||
|
||||
Span<RcVec3f> tempV = stackalloc RcVec3f[3];
|
||||
if (tile.data.detailMeshes != null)
|
||||
{
|
||||
ref DtPolyDetail pd = ref tile.data.detailMeshes[ip];
|
||||
|
@ -1160,7 +1058,7 @@ namespace DotRecast.Detour
|
|||
continue;
|
||||
}
|
||||
|
||||
RcVec3f[] v = new RcVec3f[3];
|
||||
Span<RcVec3f> v = tempV;
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
if (tris[ti + j] < poly.vertCount)
|
||||
|
@ -1208,7 +1106,7 @@ namespace DotRecast.Detour
|
|||
}
|
||||
else
|
||||
{
|
||||
RcVec3f[] v = new RcVec3f[2];
|
||||
Span<RcVec3f> v = tempV.Slice(0, 2);
|
||||
for (int j = 0; j < poly.vertCount; ++j)
|
||||
{
|
||||
int k = (j + 1) % poly.vertCount;
|
||||
|
@ -1246,11 +1144,11 @@ namespace DotRecast.Detour
|
|||
|
||||
int ip = poly.index;
|
||||
|
||||
float[] verts = new float[m_maxVertPerPoly * 3];
|
||||
Span<float> verts = stackalloc float[m_maxVertPerPoly * 3];
|
||||
int nv = poly.vertCount;
|
||||
for (int i = 0; i < nv; ++i)
|
||||
{
|
||||
RcArrays.Copy(tile.data.verts, poly.verts[i] * 3, verts, i * 3, 3);
|
||||
RcSpans.Copy(tile.data.verts, poly.verts[i] * 3, verts, i * 3, 3);
|
||||
}
|
||||
|
||||
if (!DtUtils.PointInPolygon(pos, verts, nv))
|
||||
|
@ -1259,13 +1157,14 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
// Find height at the location.
|
||||
Span<RcVec3f> tempV = stackalloc RcVec3f[3];
|
||||
if (tile.data.detailMeshes != null)
|
||||
{
|
||||
ref DtPolyDetail pd = ref tile.data.detailMeshes[ip];
|
||||
for (int j = 0; j < pd.triCount; ++j)
|
||||
{
|
||||
int t = (pd.triBase + j) * 4;
|
||||
RcVec3f[] v = new RcVec3f[3];
|
||||
Span<RcVec3f> v = tempV;
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
if (tile.data.detailTris[t + k] < poly.vertCount)
|
||||
|
@ -1299,7 +1198,7 @@ namespace DotRecast.Detour
|
|||
}
|
||||
else
|
||||
{
|
||||
RcVec3f[] v = new RcVec3f[3];
|
||||
Span<RcVec3f> v = tempV;
|
||||
v[0].X = tile.data.verts[poly.verts[0] * 3];
|
||||
v[0].Y = tile.data.verts[poly.verts[0] * 3 + 1];
|
||||
v[0].Z = tile.data.verts[poly.verts[0] * 3 + 2];
|
||||
|
@ -1407,19 +1306,27 @@ namespace DotRecast.Detour
|
|||
|
||||
DtMeshTile GetTileAt(int x, int y, int layer)
|
||||
{
|
||||
foreach (DtMeshTile tile in GetTileListByPos(x, y))
|
||||
// Find tile based on hash.
|
||||
int h = ComputeTileHash(x, y, m_tileLutMask);
|
||||
DtMeshTile tile = m_posLookup[h];
|
||||
while (null != tile)
|
||||
{
|
||||
if (tile.data.header != null && tile.data.header.x == x && tile.data.header.y == y
|
||||
&& tile.data.header.layer == layer)
|
||||
if (null != tile.data &&
|
||||
null != tile.data.header &&
|
||||
tile.data.header.x == x &&
|
||||
tile.data.header.y == y &&
|
||||
tile.data.header.layer == layer)
|
||||
{
|
||||
return tile;
|
||||
}
|
||||
|
||||
tile = tile.next;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
List<DtMeshTile> GetNeighbourTilesAt(int x, int y, int side)
|
||||
int GetNeighbourTilesAt(int x, int y, int side, DtMeshTile[] tiles, int maxTiles)
|
||||
{
|
||||
int nx = x, ny = y;
|
||||
switch (side)
|
||||
|
@ -1454,21 +1361,36 @@ namespace DotRecast.Detour
|
|||
break;
|
||||
}
|
||||
|
||||
return GetTilesAt(nx, ny);
|
||||
return GetTilesAt(nx, ny, tiles, maxTiles);
|
||||
}
|
||||
|
||||
public List<DtMeshTile> GetTilesAt(int x, int y)
|
||||
public int GetTilesAt(int x, int y, DtMeshTile[] tiles, int maxTiles)
|
||||
{
|
||||
List<DtMeshTile> tiles = new List<DtMeshTile>();
|
||||
foreach (DtMeshTile tile in GetTileListByPos(x, y))
|
||||
{
|
||||
if (tile.data.header != null && tile.data.header.x == x && tile.data.header.y == y)
|
||||
{
|
||||
tiles.Add(tile);
|
||||
}
|
||||
return GetTilesAt(x, y, (Span<DtMeshTile>)tiles, maxTiles);
|
||||
}
|
||||
|
||||
return tiles;
|
||||
public int GetTilesAt(int x, int y, Span<DtMeshTile> tiles, int maxTiles)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
// Find tile based on hash.
|
||||
int h = ComputeTileHash(x, y, m_tileLutMask);
|
||||
DtMeshTile tile = m_posLookup[h];
|
||||
while (null != tile)
|
||||
{
|
||||
if (null != tile.data &&
|
||||
null != tile.data.header &&
|
||||
tile.data.header.x == x &&
|
||||
tile.data.header.y == y)
|
||||
{
|
||||
if (n < maxTiles)
|
||||
tiles[n++] = tile;
|
||||
}
|
||||
|
||||
tile = tile.next;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
public long GetTileRefAt(int x, int y, int layer)
|
||||
|
@ -1509,14 +1431,6 @@ namespace DotRecast.Detour
|
|||
return EncodePolyId(tile.salt, tile.index, 0);
|
||||
}
|
||||
|
||||
public static int ComputeTileHash(int x, int y, int mask)
|
||||
{
|
||||
uint h1 = 0x8da6b343; // Large multiplicative constants;
|
||||
uint h2 = 0xd8163841; // here arbitrarily chosen primes
|
||||
uint n = h1 * (uint)x + h2 * (uint)y;
|
||||
return (int)(n & mask);
|
||||
}
|
||||
|
||||
/// Gets the endpoints for an off-mesh connection, ordered by "direction of travel".
|
||||
/// @param[in] prevRef The reference of the polygon before the connection.
|
||||
/// @param[in] polyRef The reference of the off-mesh connection polygon.
|
||||
|
@ -1568,7 +1482,7 @@ namespace DotRecast.Detour
|
|||
int idx0 = 0, idx1 = 1;
|
||||
|
||||
// Find link that points to first vertex.
|
||||
for (int i = tile.polyLinks[poly.index]; i != DT_NULL_LINK; i = tile.links[i].next)
|
||||
for (int i = poly.firstLink; i != DT_NULL_LINK; i = tile.links[i].next)
|
||||
{
|
||||
if (tile.links[i].edge == 0)
|
||||
{
|
||||
|
@ -1582,8 +1496,8 @@ namespace DotRecast.Detour
|
|||
}
|
||||
}
|
||||
|
||||
startPos = RcVecUtils.Create(tile.data.verts, poly.verts[idx0] * 3);
|
||||
endPos = RcVecUtils.Create(tile.data.verts, poly.verts[idx1] * 3);
|
||||
startPos = RcVec.Create(tile.data.verts, poly.verts[idx0] * 3);
|
||||
endPos = RcVec.Create(tile.data.verts, poly.verts[idx1] * 3);
|
||||
|
||||
return DtStatus.DT_SUCCESS;
|
||||
}
|
||||
|
@ -1598,9 +1512,9 @@ namespace DotRecast.Detour
|
|||
return m_tileCount;
|
||||
}
|
||||
|
||||
public int GetAvailableTileCount()
|
||||
public bool IsAvailableTileCount()
|
||||
{
|
||||
return availableTiles.Count;
|
||||
return null != m_nextFree;
|
||||
}
|
||||
|
||||
public DtStatus SetPolyFlags(long refs, int flags)
|
||||
|
@ -1758,32 +1672,6 @@ namespace DotRecast.Detour
|
|||
return center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get flags for edge in detail triangle.
|
||||
*
|
||||
* @param triFlags
|
||||
* The flags for the triangle (last component of detail vertices above).
|
||||
* @param edgeIndex
|
||||
* The index of the first vertex of the edge. For instance, if 0,
|
||||
* @return flags for edge AB.
|
||||
*/
|
||||
public static int GetDetailTriEdgeFlags(int triFlags, int edgeIndex)
|
||||
{
|
||||
return (triFlags >> (edgeIndex * 2)) & 0x3;
|
||||
}
|
||||
|
||||
private List<DtMeshTile> GetTileListByPos(int x, int z)
|
||||
{
|
||||
var tileHash = ComputeTileHash(x, z, m_tileLutMask);
|
||||
if (!posLookup.TryGetValue(tileHash, out var tiles))
|
||||
{
|
||||
tiles = new List<DtMeshTile>();
|
||||
posLookup.Add(tileHash, tiles);
|
||||
}
|
||||
|
||||
return tiles;
|
||||
}
|
||||
|
||||
public void ComputeBounds(out RcVec3f bmin, out RcVec3f bmax)
|
||||
{
|
||||
bmin = new RcVec3f(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -24,42 +24,35 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
using static DtDetour;
|
||||
|
||||
public static class DtNavMeshBuilder
|
||||
{
|
||||
const int MESH_NULL_IDX = 0xffff;
|
||||
|
||||
|
||||
private static int[][] CalcExtends(BVItem[] items, int nitems, int imin, int imax)
|
||||
private static void CalcExtends(BVItem[] items, int nitems, int imin, int imax, ref RcVec3i bmin, ref RcVec3i bmax)
|
||||
{
|
||||
int[] bmin = new int[3];
|
||||
int[] bmax = new int[3];
|
||||
bmin[0] = items[imin].bmin[0];
|
||||
bmin[1] = items[imin].bmin[1];
|
||||
bmin[2] = items[imin].bmin[2];
|
||||
|
||||
bmax[0] = items[imin].bmax[0];
|
||||
bmax[1] = items[imin].bmax[1];
|
||||
bmax[2] = items[imin].bmax[2];
|
||||
bmin = items[imin].bmin;
|
||||
bmax = items[imin].bmax;
|
||||
|
||||
for (int i = imin + 1; i < imax; ++i)
|
||||
{
|
||||
BVItem it = items[i];
|
||||
if (it.bmin[0] < bmin[0])
|
||||
bmin[0] = it.bmin[0];
|
||||
if (it.bmin[1] < bmin[1])
|
||||
bmin[1] = it.bmin[1];
|
||||
if (it.bmin[2] < bmin[2])
|
||||
bmin[2] = it.bmin[2];
|
||||
if (it.bmin.X < bmin.X)
|
||||
bmin.X = it.bmin.X;
|
||||
if (it.bmin.Y < bmin.Y)
|
||||
bmin.Y = it.bmin.Y;
|
||||
if (it.bmin.Z < bmin.Z)
|
||||
bmin.Z = it.bmin.Z;
|
||||
|
||||
if (it.bmax[0] > bmax[0])
|
||||
bmax[0] = it.bmax[0];
|
||||
if (it.bmax[1] > bmax[1])
|
||||
bmax[1] = it.bmax[1];
|
||||
if (it.bmax[2] > bmax[2])
|
||||
bmax[2] = it.bmax[2];
|
||||
if (it.bmax.X > bmax.X)
|
||||
bmax.X = it.bmax.X;
|
||||
if (it.bmax.Y > bmax.Y)
|
||||
bmax.Y = it.bmax.Y;
|
||||
if (it.bmax.Z > bmax.Z)
|
||||
bmax.Z = it.bmax.Z;
|
||||
}
|
||||
|
||||
return new int[][] { bmin, bmax };
|
||||
}
|
||||
|
||||
private static int LongestAxis(int x, int y, int z)
|
||||
|
@ -92,25 +85,21 @@ namespace DotRecast.Detour
|
|||
if (inum == 1)
|
||||
{
|
||||
// Leaf
|
||||
node.bmin[0] = items[imin].bmin[0];
|
||||
node.bmin[1] = items[imin].bmin[1];
|
||||
node.bmin[2] = items[imin].bmin[2];
|
||||
|
||||
node.bmax[0] = items[imin].bmax[0];
|
||||
node.bmax[1] = items[imin].bmax[1];
|
||||
node.bmax[2] = items[imin].bmax[2];
|
||||
node.bmin = items[imin].bmin;
|
||||
node.bmax = items[imin].bmax;
|
||||
|
||||
node.i = items[imin].i;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Split
|
||||
int[][] minmax = CalcExtends(items, nitems, imin, imax);
|
||||
node.bmin = minmax[0];
|
||||
node.bmax = minmax[1];
|
||||
CalcExtends(items, nitems, imin, imax, ref node.bmin, ref node.bmax);
|
||||
|
||||
int axis = LongestAxis(node.bmax[0] - node.bmin[0], node.bmax[1] - node.bmin[1],
|
||||
node.bmax[2] - node.bmin[2]);
|
||||
int axis = LongestAxis(
|
||||
node.bmax.X - node.bmin.X,
|
||||
node.bmax.Y - node.bmin.Y,
|
||||
node.bmax.Z - node.bmin.Z
|
||||
);
|
||||
|
||||
if (axis == 0)
|
||||
{
|
||||
|
@ -159,29 +148,29 @@ namespace DotRecast.Detour
|
|||
int vb = option.detailMeshes[i * 4 + 0];
|
||||
int ndv = option.detailMeshes[i * 4 + 1];
|
||||
int dv = vb * 3;
|
||||
var bmin = RcVecUtils.Create(option.detailVerts, dv);
|
||||
var bmax = RcVecUtils.Create(option.detailVerts, dv);
|
||||
var bmin = RcVec.Create(option.detailVerts, dv);
|
||||
var bmax = RcVec.Create(option.detailVerts, dv);
|
||||
for (int j = 1; j < ndv; j++)
|
||||
{
|
||||
bmin = RcVecUtils.Min(bmin, option.detailVerts, dv + j * 3);
|
||||
bmax = RcVecUtils.Max(bmax, option.detailVerts, dv + j * 3);
|
||||
bmin = RcVec3f.Min(bmin, RcVec.Create(option.detailVerts, dv + j * 3));
|
||||
bmax = RcVec3f.Max(bmax, RcVec.Create(option.detailVerts, dv + j * 3));
|
||||
}
|
||||
|
||||
// BV-tree uses cs for all dimensions
|
||||
it.bmin[0] = Math.Clamp((int)((bmin.X - option.bmin.X) * quantFactor), 0, int.MaxValue);
|
||||
it.bmin[1] = Math.Clamp((int)((bmin.Y - option.bmin.Y) * quantFactor), 0, int.MaxValue);
|
||||
it.bmin[2] = Math.Clamp((int)((bmin.Z - option.bmin.Z) * quantFactor), 0, int.MaxValue);
|
||||
it.bmin.X = Math.Clamp((int)((bmin.X - option.bmin.X) * quantFactor), 0, int.MaxValue);
|
||||
it.bmin.Y = Math.Clamp((int)((bmin.Y - option.bmin.Y) * quantFactor), 0, int.MaxValue);
|
||||
it.bmin.Z = Math.Clamp((int)((bmin.Z - option.bmin.Z) * quantFactor), 0, int.MaxValue);
|
||||
|
||||
it.bmax[0] = Math.Clamp((int)((bmax.X - option.bmin.X) * quantFactor), 0, int.MaxValue);
|
||||
it.bmax[1] = Math.Clamp((int)((bmax.Y - option.bmin.Y) * quantFactor), 0, int.MaxValue);
|
||||
it.bmax[2] = Math.Clamp((int)((bmax.Z - option.bmin.Z) * quantFactor), 0, int.MaxValue);
|
||||
it.bmax.X = Math.Clamp((int)((bmax.X - option.bmin.X) * quantFactor), 0, int.MaxValue);
|
||||
it.bmax.Y = Math.Clamp((int)((bmax.Y - option.bmin.Y) * quantFactor), 0, int.MaxValue);
|
||||
it.bmax.Z = Math.Clamp((int)((bmax.Z - option.bmin.Z) * quantFactor), 0, int.MaxValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
int p = i * option.nvp * 2;
|
||||
it.bmin[0] = it.bmax[0] = option.verts[option.polys[p] * 3 + 0];
|
||||
it.bmin[1] = it.bmax[1] = option.verts[option.polys[p] * 3 + 1];
|
||||
it.bmin[2] = it.bmax[2] = option.verts[option.polys[p] * 3 + 2];
|
||||
it.bmin.X = it.bmax.X = option.verts[option.polys[p] * 3 + 0];
|
||||
it.bmin.Y = it.bmax.Y = option.verts[option.polys[p] * 3 + 1];
|
||||
it.bmin.Z = it.bmax.Z = option.verts[option.polys[p] * 3 + 2];
|
||||
|
||||
for (int j = 1; j < option.nvp; ++j)
|
||||
{
|
||||
|
@ -191,24 +180,24 @@ namespace DotRecast.Detour
|
|||
int y = option.verts[option.polys[p + j] * 3 + 1];
|
||||
int z = option.verts[option.polys[p + j] * 3 + 2];
|
||||
|
||||
if (x < it.bmin[0])
|
||||
it.bmin[0] = x;
|
||||
if (y < it.bmin[1])
|
||||
it.bmin[1] = y;
|
||||
if (z < it.bmin[2])
|
||||
it.bmin[2] = z;
|
||||
if (x < it.bmin.X)
|
||||
it.bmin.X = x;
|
||||
if (y < it.bmin.Y)
|
||||
it.bmin.Y = y;
|
||||
if (z < it.bmin.Z)
|
||||
it.bmin.Z = z;
|
||||
|
||||
if (x > it.bmax[0])
|
||||
it.bmax[0] = x;
|
||||
if (y > it.bmax[1])
|
||||
it.bmax[1] = y;
|
||||
if (z > it.bmax[2])
|
||||
it.bmax[2] = z;
|
||||
if (x > it.bmax.X)
|
||||
it.bmax.X = x;
|
||||
if (y > it.bmax.Y)
|
||||
it.bmax.Y = y;
|
||||
if (z > it.bmax.Z)
|
||||
it.bmax.Z = z;
|
||||
}
|
||||
|
||||
// Remap y
|
||||
it.bmin[1] = (int)MathF.Floor(it.bmin[1] * option.ch * quantFactor);
|
||||
it.bmax[1] = (int)MathF.Ceiling(it.bmax[1] * option.ch * quantFactor);
|
||||
it.bmin.Y = (int)MathF.Floor(it.bmin.Y * option.ch * quantFactor);
|
||||
it.bmax.Y = (int)MathF.Ceiling(it.bmax.Y * option.ch * quantFactor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,14 +240,15 @@ namespace DotRecast.Detour
|
|||
return 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds navigation mesh tile data from the provided tile creation data.
|
||||
*
|
||||
* @param option
|
||||
* Tile creation data.
|
||||
*
|
||||
* @return created tile data
|
||||
*/
|
||||
// TODO: Better error handling.
|
||||
|
||||
/// @par
|
||||
///
|
||||
/// The output data array is allocated using the detour allocator (dtAlloc()). The method
|
||||
/// used to free the memory will be determined by how the tile is added to the navigation
|
||||
/// mesh.
|
||||
///
|
||||
/// @see dtNavMesh, dtNavMesh::addTile()
|
||||
public static DtMeshData CreateNavMeshData(DtNavMeshCreateParams option)
|
||||
{
|
||||
if (option.vertCount >= 0xffff)
|
||||
|
@ -316,8 +306,8 @@ namespace DotRecast.Detour
|
|||
|
||||
for (int i = 0; i < option.offMeshConCount; ++i)
|
||||
{
|
||||
var p0 = RcVecUtils.Create(option.offMeshConVerts, (i * 2 + 0) * 3);
|
||||
var p1 = RcVecUtils.Create(option.offMeshConVerts, (i * 2 + 1) * 3);
|
||||
var p0 = RcVec.Create(option.offMeshConVerts, (i * 2 + 0) * 3);
|
||||
var p1 = RcVec.Create(option.offMeshConVerts, (i * 2 + 1) * 3);
|
||||
|
||||
offMeshConClass[i * 2 + 0] = ClassifyOffMeshPoint(p0, bmin, bmax);
|
||||
offMeshConClass[i * 2 + 1] = ClassifyOffMeshPoint(p1, bmin, bmax);
|
||||
|
@ -424,8 +414,8 @@ namespace DotRecast.Detour
|
|||
DtOffMeshConnection[] offMeshCons = new DtOffMeshConnection[storedOffMeshConCount];
|
||||
|
||||
// Store header
|
||||
header.magic = DtNavMesh.DT_NAVMESH_MAGIC;
|
||||
header.version = DtNavMesh.DT_NAVMESH_VERSION;
|
||||
header.magic = DT_NAVMESH_MAGIC;
|
||||
header.version = DT_NAVMESH_VERSION;
|
||||
header.x = option.tileX;
|
||||
header.y = option.tileZ;
|
||||
header.layer = option.tileLayer;
|
||||
|
@ -497,13 +487,13 @@ namespace DotRecast.Detour
|
|||
if (dir == 0xf) // Border
|
||||
p.neis[j] = 0;
|
||||
else if (dir == 0) // Portal x-
|
||||
p.neis[j] = DtNavMesh.DT_EXT_LINK | 4;
|
||||
p.neis[j] = DT_EXT_LINK | 4;
|
||||
else if (dir == 1) // Portal z+
|
||||
p.neis[j] = DtNavMesh.DT_EXT_LINK | 2;
|
||||
p.neis[j] = DT_EXT_LINK | 2;
|
||||
else if (dir == 2) // Portal x+
|
||||
p.neis[j] = DtNavMesh.DT_EXT_LINK | 0;
|
||||
p.neis[j] = DT_EXT_LINK | 0;
|
||||
else if (dir == 3) // Portal z-
|
||||
p.neis[j] = DtNavMesh.DT_EXT_LINK | 6;
|
||||
p.neis[j] = DT_EXT_LINK | 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -550,9 +540,9 @@ namespace DotRecast.Detour
|
|||
int ndv = option.detailMeshes[i * 4 + 1];
|
||||
int nv = navPolys[i].vertCount;
|
||||
int vertBase = vbase;
|
||||
int vertCount = (ndv - nv);
|
||||
byte vertCount = (byte)(ndv - nv);
|
||||
int triBase = option.detailMeshes[i * 4 + 2];
|
||||
int triCount = option.detailMeshes[i * 4 + 3];
|
||||
byte triCount = (byte)option.detailMeshes[i * 4 + 3];
|
||||
navDMeshes[i] = new DtPolyDetail(vertBase, triBase, vertCount, triCount);
|
||||
// Copy vertices except the first 'nv' verts which are equal to
|
||||
// nav poly verts.
|
||||
|
@ -574,9 +564,9 @@ namespace DotRecast.Detour
|
|||
{
|
||||
int nv = navPolys[i].vertCount;
|
||||
int vertBase = 0;
|
||||
int vertCount = 0;
|
||||
byte vertCount = 0;
|
||||
int triBase = tbase;
|
||||
int triCount = (nv - 2);
|
||||
byte triCount = (byte)(nv - 2);
|
||||
navDMeshes[i] = new DtPolyDetail(vertBase, triBase, vertCount, triCount);
|
||||
// Triangulate polygon (local indices).
|
||||
for (int j = 2; j < nv; ++j)
|
||||
|
@ -618,11 +608,11 @@ namespace DotRecast.Detour
|
|||
int endPts = i * 2 * 3;
|
||||
for (int j = 0; j < 2; ++j)
|
||||
{
|
||||
con.pos[j] = RcVecUtils.Create(option.offMeshConVerts, endPts + (j * 3));
|
||||
con.pos[j] = RcVec.Create(option.offMeshConVerts, endPts + (j * 3));
|
||||
}
|
||||
|
||||
con.rad = option.offMeshConRad[i];
|
||||
con.flags = option.offMeshConDir[i] != 0 ? DtNavMesh.DT_OFFMESH_CON_BIDIR : 0;
|
||||
con.flags = option.offMeshConDir[i] != 0 ? DT_OFFMESH_CON_BIDIR : 0;
|
||||
con.side = offMeshConClass[i * 2 + 1];
|
||||
if (option.offMeshConUserID != null)
|
||||
con.userId = option.offMeshConUserID[i];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,31 +18,21 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/**
|
||||
* Configuration parameters used to define multi-tile navigation meshes. The values are used to allocate space during
|
||||
* the initialization of a navigation mesh.
|
||||
*
|
||||
* @see NavMesh
|
||||
*/
|
||||
/// Configuration parameters used to define multi-tile navigation meshes.
|
||||
/// The values are used to allocate space during the initialization of a navigation mesh.
|
||||
/// @see dtNavMesh::init()
|
||||
/// @ingroup detour
|
||||
public struct DtNavMeshParams
|
||||
{
|
||||
/** The world space origin of the navigation mesh's tile space. [(x, y, z)] */
|
||||
public RcVec3f orig;
|
||||
|
||||
/** The width of each tile. (Along the x-axis.) */
|
||||
public float tileWidth;
|
||||
|
||||
/** The height of each tile. (Along the z-axis.) */
|
||||
public float tileHeight;
|
||||
|
||||
/** The maximum number of tiles the navigation mesh can contain. */
|
||||
public int maxTiles;
|
||||
|
||||
/** The maximum number of polygons each tile can contain. */
|
||||
public int maxPolys;
|
||||
public RcVec3f orig; //< The world space origin of the navigation mesh's tile space. [(x, y, z)]
|
||||
public float tileWidth; //< The width of each tile. (Along the x-axis.)
|
||||
public float tileHeight; //< The height of each tile. (Along the z-axis.)
|
||||
public int maxTiles; //< The maximum number of tiles the navigation mesh can contain. This and maxPolys are used to calculate how many bits are needed to identify tiles and polygons uniquely.
|
||||
public int maxPolys; //< The maximum number of polygons each tile can contain. This and maxTiles are used to calculate how many bits are needed to identify tiles and polygons uniquely.
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public class DtNavMeshQueryMock : DtNavMeshQuery
|
||||
{
|
||||
private readonly DtStraightPath[] _straightPath;
|
||||
private readonly DtStatus _status;
|
||||
|
||||
public DtNavMeshQueryMock(DtStraightPath[] straightPath, DtStatus status)
|
||||
: base(null)
|
||||
{
|
||||
_straightPath = straightPath;
|
||||
_status = status;
|
||||
}
|
||||
|
||||
public override DtStatus FindStraightPath(RcVec3f startPos, RcVec3f endPos,
|
||||
List<long> path, int pathSize,
|
||||
Span<DtStraightPath> straightPath, out int straightPathCount, int maxStraightPath,
|
||||
int options)
|
||||
{
|
||||
straightPathCount = 0;
|
||||
for (int i = 0; i < _straightPath.Length && i < maxStraightPath; ++i)
|
||||
{
|
||||
straightPath[i] = _straightPath[i];
|
||||
straightPathCount += 1;
|
||||
}
|
||||
|
||||
return _status;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -17,6 +17,7 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
|
@ -48,6 +49,7 @@ namespace DotRecast.Detour
|
|||
private static bool Raycast(DtMeshTile tile, RcVec3f sp, RcVec3f sq, out float hitTime)
|
||||
{
|
||||
hitTime = 0.0f;
|
||||
Span<RcVec3f> tempVerts = stackalloc RcVec3f[3];
|
||||
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
||||
{
|
||||
DtPoly p = tile.data.polys[i];
|
||||
|
@ -58,7 +60,7 @@ namespace DotRecast.Detour
|
|||
|
||||
ref DtPolyDetail pd = ref tile.data.detailMeshes[i];
|
||||
|
||||
RcVec3f[] verts = new RcVec3f[3];
|
||||
Span<RcVec3f> verts = tempVerts;
|
||||
for (int j = 0; j < pd.triCount; ++j)
|
||||
{
|
||||
int t = (pd.triBase + j) * 4;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
|
@ -10,9 +11,11 @@ namespace DotRecast.Detour
|
|||
{
|
||||
}
|
||||
|
||||
public float[] Apply(float[] polyVerts, RcVec3f circleCenter, float radius)
|
||||
public Span<float> Apply(Span<float> polyVerts, RcVec3f circleCenter, float radius, Span<float> resultBuffer)
|
||||
{
|
||||
return polyVerts;
|
||||
var result = resultBuffer.Slice(0, polyVerts.Length);
|
||||
polyVerts.CopyTo(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public static class DtNodeFlags
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,8 +18,10 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DotRecast.Core.Buffers;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
|
@ -27,24 +29,68 @@ namespace DotRecast.Detour
|
|||
{
|
||||
private readonly Dictionary<long, List<DtNode>> m_map;
|
||||
|
||||
private int m_nodeCount;
|
||||
private readonly List<DtNode> m_nodes;
|
||||
private int m_usedNodesCount;
|
||||
private List<DtNode[]> m_buckets;
|
||||
private readonly int m_initialBufferCapacityBase;
|
||||
private readonly RcObjectPool<List<DtNode>> m_listPool;
|
||||
|
||||
public DtNodePool()
|
||||
public DtNodePool(int initialBufferCapacityBase = 6) // initial size 64
|
||||
{
|
||||
m_map = new Dictionary<long, List<DtNode>>();
|
||||
m_nodes = new List<DtNode>();
|
||||
m_listPool = new RcObjectPool<List<DtNode>>(() => new List<DtNode>());
|
||||
m_buckets = new List<DtNode[]>();
|
||||
m_initialBufferCapacityBase = initialBufferCapacityBase;
|
||||
}
|
||||
|
||||
private void AddNewBucket()
|
||||
{
|
||||
var bucketIndex = m_buckets.Count;
|
||||
var bucket = new DtNode[1 << (bucketIndex + m_initialBufferCapacityBase)];
|
||||
m_buckets.Add(bucket);
|
||||
FillBucket(bucketIndex);
|
||||
}
|
||||
|
||||
private void FillBucket(int bucketIndex)
|
||||
{
|
||||
var bucket = m_buckets[bucketIndex];
|
||||
var startIndex = GetBucketStartIndex(bucketIndex);
|
||||
for (int i = 0; i < bucket.Length; i++)
|
||||
{
|
||||
bucket[i] = new DtNode(startIndex + i);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetBucketStartIndex(int bucketIndex)
|
||||
{
|
||||
return ((1 << (bucketIndex + m_initialBufferCapacityBase)) - 1) ^ ((1 << m_initialBufferCapacityBase) - 1);
|
||||
}
|
||||
|
||||
private DtNode[] EnsureBucket(int bucketIndex)
|
||||
{
|
||||
if (m_buckets.Count == bucketIndex)
|
||||
AddNewBucket();
|
||||
else if (m_buckets.Count < bucketIndex)
|
||||
throw new Exception();
|
||||
return m_buckets[bucketIndex];
|
||||
}
|
||||
|
||||
private int GetBucketIndexByElementIndex(int elementIndex)
|
||||
{
|
||||
return DtUtils.Ilog2((elementIndex >> m_initialBufferCapacityBase) + 1);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var pair in m_map)
|
||||
m_listPool.Return(pair.Value);
|
||||
|
||||
m_map.Clear();
|
||||
m_nodeCount = 0;
|
||||
m_usedNodesCount = 0;
|
||||
}
|
||||
|
||||
public int GetNodeCount()
|
||||
{
|
||||
return m_nodeCount;
|
||||
return m_usedNodesCount;
|
||||
}
|
||||
|
||||
public int FindNodes(long id, out List<DtNode> nodes)
|
||||
|
@ -84,7 +130,8 @@ namespace DotRecast.Detour
|
|||
}
|
||||
else
|
||||
{
|
||||
nodes = new List<DtNode>();
|
||||
nodes = m_listPool.Get();
|
||||
nodes.Clear();
|
||||
m_map.Add(id, nodes);
|
||||
}
|
||||
|
||||
|
@ -93,15 +140,10 @@ namespace DotRecast.Detour
|
|||
|
||||
private DtNode Create(long id, int state, List<DtNode> nodes)
|
||||
{
|
||||
if (m_nodes.Count <= m_nodeCount)
|
||||
{
|
||||
var newNode = new DtNode(m_nodeCount);
|
||||
m_nodes.Add(newNode);
|
||||
}
|
||||
|
||||
int i = m_nodeCount;
|
||||
m_nodeCount++;
|
||||
var node = m_nodes[i];
|
||||
int i = m_usedNodesCount++;
|
||||
int bucketIndex = GetBucketIndexByElementIndex(i);
|
||||
int bucketStartIndex = GetBucketStartIndex(bucketIndex);
|
||||
var node = EnsureBucket(bucketIndex)[i - bucketStartIndex];
|
||||
node.pidx = 0;
|
||||
node.cost = 0;
|
||||
node.total = 0;
|
||||
|
@ -123,9 +165,16 @@ namespace DotRecast.Detour
|
|||
|
||||
public DtNode GetNodeAtIdx(int idx)
|
||||
{
|
||||
return idx != 0
|
||||
? m_nodes[idx - 1]
|
||||
: null;
|
||||
if (idx == 0)
|
||||
return null;
|
||||
|
||||
int bucketIndex = GetBucketIndexByElementIndex(idx - 1);
|
||||
if (m_buckets.Count <= bucketIndex)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
int bucketStartIndex = GetBucketStartIndex(bucketIndex);
|
||||
var node = EnsureBucket(bucketIndex)[idx - bucketStartIndex - 1];
|
||||
return node;
|
||||
}
|
||||
|
||||
public DtNode GetNode(long refs)
|
||||
|
@ -135,7 +184,7 @@ namespace DotRecast.Detour
|
|||
|
||||
public IEnumerable<DtNode> AsEnumerable()
|
||||
{
|
||||
return m_nodes.Take(m_nodeCount);
|
||||
return m_buckets.SelectMany(x => x);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,12 +18,14 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/// Defines an navigation mesh off-mesh connection within a dtMeshTile object.
|
||||
/// An off-mesh connection is a user defined traversable connection made up to two vertices.
|
||||
[Serializable]
|
||||
public class DtOffMeshConnection
|
||||
{
|
||||
/// The endpoints of the connection. [(ax, ay, az, bx, by, bz)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -20,26 +20,31 @@ freely, subject to the following restrictions:
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Buffers;
|
||||
using DotRecast.Core.Collections;
|
||||
using DotRecast.Core.Numerics;
|
||||
using CollectionExtensions = DotRecast.Core.Collections.CollectionExtensions;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
using static DtDetour;
|
||||
|
||||
public static class DtPathUtils
|
||||
{
|
||||
private const int MAX_STEER_POINTS = 3;
|
||||
|
||||
public static bool GetSteerTarget(DtNavMeshQuery navQuery, RcVec3f startPos, RcVec3f endPos,
|
||||
float minTargetDist,
|
||||
List<long> path,
|
||||
List<long> path, int pathSize,
|
||||
out RcVec3f steerPos, out int steerPosFlag, out long steerPosRef)
|
||||
{
|
||||
const int MAX_STEER_POINTS = 3;
|
||||
|
||||
steerPos = RcVec3f.Zero;
|
||||
steerPosFlag = 0;
|
||||
steerPosRef = 0;
|
||||
|
||||
// Find steer target.
|
||||
var straightPath = new List<DtStraightPath>(MAX_STEER_POINTS);
|
||||
var result = navQuery.FindStraightPath(startPos, endPos, path, ref straightPath, MAX_STEER_POINTS, 0);
|
||||
Span<DtStraightPath> straightPath = stackalloc DtStraightPath[MAX_STEER_POINTS];
|
||||
var result = navQuery.FindStraightPath(startPos, endPos, path, pathSize, straightPath, out var nsteerPath, MAX_STEER_POINTS, 0);
|
||||
if (result.Failed())
|
||||
{
|
||||
return false;
|
||||
|
@ -47,7 +52,7 @@ namespace DotRecast.Detour
|
|||
|
||||
// Find vertex far enough to steer to.
|
||||
int ns = 0;
|
||||
while (ns < straightPath.Count)
|
||||
while (ns < nsteerPath)
|
||||
{
|
||||
// Stop at Off-Mesh link or when point is further than slop away.
|
||||
if (((straightPath[ns].flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
||||
|
@ -57,7 +62,7 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
// Failed to find good point to steer to.
|
||||
if (ns >= straightPath.Count)
|
||||
if (ns >= nsteerPath)
|
||||
return false;
|
||||
|
||||
steerPos = straightPath[ns].pos;
|
||||
|
@ -88,29 +93,32 @@ namespace DotRecast.Detour
|
|||
// +-S-+-T-+
|
||||
// |:::| | <-- the step can end up in here, resulting U-turn path.
|
||||
// +---+---+
|
||||
public static List<long> FixupShortcuts(List<long> path, DtNavMeshQuery navQuery)
|
||||
public static int FixupShortcuts(ref List<long> path, int npath, DtNavMeshQuery navQuery)
|
||||
{
|
||||
if (path.Count < 3)
|
||||
if (npath < 3)
|
||||
{
|
||||
return path;
|
||||
return npath;
|
||||
}
|
||||
|
||||
// Get connected polygons
|
||||
List<long> neis = new List<long>();
|
||||
const int maxNeis = 16;
|
||||
Span<long> neis = stackalloc long[maxNeis];
|
||||
int nneis = 0;
|
||||
|
||||
var status = navQuery.GetAttachedNavMesh().GetTileAndPolyByRef(path[0], out var tile, out var poly);
|
||||
if (status.Failed())
|
||||
{
|
||||
return path;
|
||||
return npath;
|
||||
}
|
||||
|
||||
|
||||
for (int k = tile.polyLinks[poly.index]; k != DtNavMesh.DT_NULL_LINK; k = tile.links[k].next)
|
||||
for (int k = poly.firstLink; k != DT_NULL_LINK; k = tile.links[k].next)
|
||||
{
|
||||
DtLink link = tile.links[k];
|
||||
if (link.refs != 0)
|
||||
{
|
||||
neis.Add(link.refs);
|
||||
if (nneis < maxNeis)
|
||||
neis[nneis++] = link.refs;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,9 +126,9 @@ namespace DotRecast.Detour
|
|||
// in the path, short cut to that polygon directly.
|
||||
const int maxLookAhead = 6;
|
||||
int cut = 0;
|
||||
for (int i = Math.Min(maxLookAhead, path.Count) - 1; i > 1 && cut == 0; i--)
|
||||
for (int i = Math.Min(maxLookAhead, npath) - 1; i > 1 && cut == 0; i--)
|
||||
{
|
||||
for (int j = 0; j < neis.Count; j++)
|
||||
for (int j = 0; j < nneis; j++)
|
||||
{
|
||||
if (path[i] == neis[j])
|
||||
{
|
||||
|
@ -134,23 +142,25 @@ namespace DotRecast.Detour
|
|||
{
|
||||
List<long> shortcut = new List<long>();
|
||||
shortcut.Add(path[0]);
|
||||
shortcut.AddRange(path.GetRange(cut, path.Count - cut));
|
||||
return shortcut;
|
||||
shortcut.AddRange(path.GetRange(cut, npath - cut));
|
||||
|
||||
path = shortcut;
|
||||
return shortcut.Count;
|
||||
}
|
||||
|
||||
return path;
|
||||
return npath;
|
||||
}
|
||||
|
||||
public static List<long> MergeCorridorStartMoved(List<long> path, int npath, int maxPath, List<long> visited)
|
||||
public static int MergeCorridorStartMoved(List<long> path, int npath, int maxPath, Span<long> visited, int nvisited)
|
||||
{
|
||||
int furthestPath = -1;
|
||||
int furthestVisited = -1;
|
||||
|
||||
// Find furthest common polygon.
|
||||
for (int i = path.Count - 1; i >= 0; --i)
|
||||
for (int i = npath - 1; i >= 0; --i)
|
||||
{
|
||||
bool found = false;
|
||||
for (int j = visited.Count - 1; j >= 0; --j)
|
||||
for (int j = nvisited - 1; j >= 0; --j)
|
||||
{
|
||||
if (path[i] == visited[j])
|
||||
{
|
||||
|
@ -169,33 +179,36 @@ namespace DotRecast.Detour
|
|||
// If no intersection found just return current path.
|
||||
if (furthestPath == -1 || furthestVisited == -1)
|
||||
{
|
||||
return path;
|
||||
return npath;
|
||||
}
|
||||
|
||||
// Concatenate paths.
|
||||
|
||||
var endIndex = nvisited - 1;
|
||||
var length1 = endIndex - furthestVisited;
|
||||
var length2 = npath - furthestPath;
|
||||
using var result = RcRentedArray.Rent<long>(length1 + length2);
|
||||
// Adjust beginning of the buffer to include the visited.
|
||||
List<long> result = new List<long>();
|
||||
// Store visited
|
||||
for (int i = visited.Count - 1; i > furthestVisited; --i)
|
||||
{
|
||||
result.Add(visited[i]);
|
||||
for (int i = 0; i < length1; ++i)
|
||||
result[i] = visited[endIndex - i];
|
||||
|
||||
path.CopyTo(furthestPath, result.AsArray(), length1, length2);
|
||||
|
||||
path.Clear();
|
||||
CollectionExtensions.AddRange(path, result.AsSpan());
|
||||
return result.Length;
|
||||
}
|
||||
|
||||
result.AddRange(path.GetRange(furthestPath, path.Count - furthestPath));
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<long> MergeCorridorEndMoved(List<long> path, int npath, int maxPath, List<long> visited)
|
||||
public static int MergeCorridorEndMoved(List<long> path, int npath, int maxPath, Span<long> visited, int nvisited)
|
||||
{
|
||||
int furthestPath = -1;
|
||||
int furthestVisited = -1;
|
||||
|
||||
// Find furthest common polygon.
|
||||
for (int i = 0; i < path.Count; ++i)
|
||||
for (int i = 0; i < npath; ++i)
|
||||
{
|
||||
bool found = false;
|
||||
for (int j = visited.Count - 1; j >= 0; --j)
|
||||
for (int j = nvisited - 1; j >= 0; --j)
|
||||
{
|
||||
if (path[i] == visited[j])
|
||||
{
|
||||
|
@ -214,25 +227,31 @@ namespace DotRecast.Detour
|
|||
// If no intersection found just return current path.
|
||||
if (furthestPath == -1 || furthestVisited == -1)
|
||||
{
|
||||
return path;
|
||||
return npath;
|
||||
}
|
||||
|
||||
// Concatenate paths.
|
||||
List<long> result = path.GetRange(0, furthestPath);
|
||||
result.AddRange(visited.GetRange(furthestVisited, visited.Count - furthestVisited));
|
||||
return result;
|
||||
var length1 = furthestPath;
|
||||
var length2 = nvisited - furthestVisited;
|
||||
using var result = RcRentedArray.Rent<long>(length1 + length2);
|
||||
path.CopyTo(0, result.AsArray(), 0, length1);
|
||||
visited.Slice(furthestVisited, nvisited - furthestVisited).CopyTo(result.AsSpan().Slice(length1, length2));
|
||||
|
||||
path.Clear();
|
||||
CollectionExtensions.AddRange(path, result.AsSpan());
|
||||
return path.Count;
|
||||
}
|
||||
|
||||
public static List<long> MergeCorridorStartShortcut(List<long> path, int npath, int maxPath, List<long> visited)
|
||||
public static int MergeCorridorStartShortcut(List<long> path, int npath, int maxPath, List<long> visited, int nvisited)
|
||||
{
|
||||
int furthestPath = -1;
|
||||
int furthestVisited = -1;
|
||||
|
||||
// Find furthest common polygon.
|
||||
for (int i = path.Count - 1; i >= 0; --i)
|
||||
for (int i = npath - 1; i >= 0; --i)
|
||||
{
|
||||
bool found = false;
|
||||
for (int j = visited.Count - 1; j >= 0; --j)
|
||||
for (int j = nvisited - 1; j >= 0; --j)
|
||||
{
|
||||
if (path[i] == visited[j])
|
||||
{
|
||||
|
@ -251,15 +270,21 @@ namespace DotRecast.Detour
|
|||
// If no intersection found just return current path.
|
||||
if (furthestPath == -1 || furthestVisited <= 0)
|
||||
{
|
||||
return path;
|
||||
return npath;
|
||||
}
|
||||
|
||||
// Concatenate paths.
|
||||
|
||||
// Adjust beginning of the buffer to include the visited.
|
||||
List<long> result = visited.GetRange(0, furthestVisited);
|
||||
result.AddRange(path.GetRange(furthestPath, path.Count - furthestPath));
|
||||
return result;
|
||||
var length1 = furthestVisited;
|
||||
var length2 = npath - furthestPath;
|
||||
using var result = RcRentedArray.Rent<long>(length1 + length2);
|
||||
visited.CopyTo(0, result.AsArray(), 0, length1);
|
||||
path.CopyTo(furthestPath, result.AsArray(), length1, length2);
|
||||
|
||||
path.Clear();
|
||||
CollectionExtensions.AddRange(path, result.AsSpan());
|
||||
return path.Count;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -20,21 +20,26 @@ freely, subject to the following restrictions:
|
|||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/** Defines a polygon within a MeshTile object. */
|
||||
/// Defines a polygon within a dtMeshTile object.
|
||||
/// @ingroup detour
|
||||
public class DtPoly
|
||||
{
|
||||
public readonly int index;
|
||||
|
||||
/** The indices of the polygon's vertices. The actual vertices are located in MeshTile::verts. */
|
||||
/// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.)
|
||||
public int firstLink;
|
||||
|
||||
/// The indices of the polygon's vertices.
|
||||
/// The actual vertices are located in dtMeshTile::verts.
|
||||
public readonly int[] verts;
|
||||
|
||||
/** Packed data representing neighbor polygons references and flags for each edge. */
|
||||
/// Packed data representing neighbor polygons references and flags for each edge.
|
||||
public readonly int[] neis;
|
||||
|
||||
/** The user defined polygon flags. */
|
||||
/// The user defined polygon flags.
|
||||
public int flags;
|
||||
|
||||
/** The number of vertices in the polygon. */
|
||||
/// The number of vertices in the polygon.
|
||||
public int vertCount;
|
||||
|
||||
/// The bit packed area id and polygon type.
|
||||
|
@ -48,25 +53,25 @@ namespace DotRecast.Detour
|
|||
neis = new int[maxVertsPerPoly];
|
||||
}
|
||||
|
||||
/** Sets the user defined area id. [Limit: < {@link org.recast4j.detour.NavMesh#DT_MAX_AREAS}] */
|
||||
/// Sets the user defined area id. [Limit: < #DT_MAX_AREAS]
|
||||
public void SetArea(int a)
|
||||
{
|
||||
areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f);
|
||||
}
|
||||
|
||||
/** Sets the polygon type. (See: #dtPolyTypes.) */
|
||||
/// Sets the polygon type. (See: #dtPolyTypes.)
|
||||
public void SetPolyType(int t)
|
||||
{
|
||||
areaAndtype = (areaAndtype & 0x3f) | (t << 6);
|
||||
}
|
||||
|
||||
/** Gets the user defined area id. */
|
||||
/// Gets the user defined area id.
|
||||
public int GetArea()
|
||||
{
|
||||
return areaAndtype & 0x3f;
|
||||
}
|
||||
|
||||
/** Gets the polygon type. (See: #dtPolyTypes) */
|
||||
/// Gets the polygon type. (See: #dtPolyTypes)
|
||||
public int GetPolyType()
|
||||
{
|
||||
return areaAndtype >> 6;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -20,22 +20,15 @@ freely, subject to the following restrictions:
|
|||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/** Defines the location of detail sub-mesh data within a dtMeshTile. */
|
||||
/// Defines the location of detail sub-mesh data within a dtMeshTile.
|
||||
public readonly struct DtPolyDetail
|
||||
{
|
||||
/** The offset of the vertices in the MeshTile::detailVerts array. */
|
||||
public readonly int vertBase;
|
||||
public readonly int vertBase; //< The offset of the vertices in the dtMeshTile::detailVerts array.
|
||||
public readonly int triBase; //< The offset of the triangles in the dtMeshTile::detailTris array.
|
||||
public readonly byte vertCount; //< The number of vertices in the sub-mesh.
|
||||
public readonly byte triCount; //< The number of triangles in the sub-mesh.
|
||||
|
||||
/** The offset of the triangles in the MeshTile::detailTris array. */
|
||||
public readonly int triBase;
|
||||
|
||||
/** The number of vertices in the sub-mesh. */
|
||||
public readonly int vertCount;
|
||||
|
||||
/** The number of triangles in the sub-mesh. */
|
||||
public readonly int triCount;
|
||||
|
||||
public DtPolyDetail(int vertBase, int triBase, int vertCount, int triCount)
|
||||
public DtPolyDetail(int vertBase, int triBase, byte vertCount, byte triCount)
|
||||
{
|
||||
this.vertBase = vertBase;
|
||||
this.triBase = triBase;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/// Flags representing the type of a navigation mesh polygon.
|
||||
public static class DtPolyTypes
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -23,6 +23,8 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
using static DtDetour;
|
||||
|
||||
/**
|
||||
* <b>The Default Implementation</b>
|
||||
*
|
||||
|
@ -50,7 +52,7 @@ namespace DotRecast.Detour
|
|||
*/
|
||||
public class DtQueryDefaultFilter : IDtQueryFilter
|
||||
{
|
||||
private readonly float[] m_areaCost = new float[DtNavMesh.DT_MAX_AREAS]; //< Cost per area type. (Used by default implementation.)
|
||||
private readonly float[] m_areaCost = new float[DT_MAX_AREAS]; //< Cost per area type. (Used by default implementation.)
|
||||
private int m_includeFlags; //< Flags for polygons that can be visited. (Used by default implementation.)
|
||||
private int m_excludeFlags; //< Flags for polygons that should not be visited. (Used by default implementation.)
|
||||
|
||||
|
@ -58,7 +60,7 @@ namespace DotRecast.Detour
|
|||
{
|
||||
m_includeFlags = 0xffff;
|
||||
m_excludeFlags = 0;
|
||||
for (int i = 0; i < DtNavMesh.DT_MAX_AREAS; ++i)
|
||||
for (int i = 0; i < DT_MAX_AREAS; ++i)
|
||||
{
|
||||
m_areaCost[i] = 1.0f;
|
||||
}
|
||||
|
@ -68,12 +70,12 @@ namespace DotRecast.Detour
|
|||
{
|
||||
m_includeFlags = includeFlags;
|
||||
m_excludeFlags = excludeFlags;
|
||||
for (int i = 0; i < Math.Min(DtNavMesh.DT_MAX_AREAS, areaCost.Length); ++i)
|
||||
for (int i = 0; i < Math.Min(DT_MAX_AREAS, areaCost.Length); ++i)
|
||||
{
|
||||
m_areaCost[i] = areaCost[i];
|
||||
}
|
||||
|
||||
for (int i = areaCost.Length; i < DtNavMesh.DT_MAX_AREAS; ++i)
|
||||
for (int i = areaCost.Length; i < DT_MAX_AREAS; ++i)
|
||||
{
|
||||
m_areaCost[i] = 1.0f;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -38,9 +38,16 @@ namespace DotRecast.Detour
|
|||
public int hitEdgeIndex;
|
||||
|
||||
/// Pointer to an array of reference ids of the visited polygons. [opt]
|
||||
public List<long> path;
|
||||
public long[] path;
|
||||
|
||||
public int pathCount;
|
||||
|
||||
/// The cost of the path until hit.
|
||||
public float pathCost;
|
||||
|
||||
public void AddPathNode(long nodeRef)
|
||||
{
|
||||
path[pathCount++] = nodeRef;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/// Options for dtNavMeshQuery::raycast
|
||||
public static class DtRaycastOptions
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public readonly struct DtSegInterval
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -25,11 +25,16 @@ namespace DotRecast.Detour
|
|||
//TODO: (PP) Add comments
|
||||
public readonly struct DtStraightPath
|
||||
{
|
||||
/// The local path corridor corners for the agent. (Staight path.) [(x, y, z) * #ncorners]
|
||||
public readonly RcVec3f pos;
|
||||
public readonly int flags;
|
||||
|
||||
/// The local path corridor corner flags. (See: #dtStraightPathFlags) [(flags) * #ncorners]
|
||||
public readonly byte flags;
|
||||
|
||||
/// The reference id of the polygon being entered at the corner. [(polyRef) * #ncorners]
|
||||
public readonly long refs;
|
||||
|
||||
public DtStraightPath(RcVec3f pos, int flags, long refs)
|
||||
public DtStraightPath(RcVec3f pos, byte flags, long refs)
|
||||
{
|
||||
this.pos = pos;
|
||||
this.flags = flags;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/// Vertex flags returned by dtNavMeshQuery::findStraightPath.
|
||||
public static class DtStraightPathFlags
|
||||
{
|
||||
public const int DT_STRAIGHTPATH_START = 0x01; //< The vertex is the start position in the path.
|
||||
public const int DT_STRAIGHTPATH_END = 0x02; //< The vertex is the end position in the path.
|
||||
public const int DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04; //< The vertex is the start of an off-mesh connection.
|
||||
public const byte DT_STRAIGHTPATH_START = 0x01; //< The vertex is the start position in the path.
|
||||
public const byte DT_STRAIGHTPATH_END = 0x02; //< The vertex is the end position in the path.
|
||||
public const byte DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04; //< The vertex is the start of an off-mesh connection.
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Collections;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Detour
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/// Options for dtNavMeshQuery::findStraightPath.
|
||||
public static class DtStraightPathOptions
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using System;
|
||||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/**
|
||||
* Calculate the intersection between a polygon and a circle. A dodecagon is used as an approximation of the circle.
|
||||
*/
|
||||
// Calculate the intersection between a polygon and a circle. A dodecagon is used as an approximation of the circle.
|
||||
public class DtStrictDtPolygonByCircleConstraint : IDtPolygonByCircleConstraint
|
||||
{
|
||||
private const int CIRCLE_SEGMENTS = 12;
|
||||
private static readonly float[] UnitCircle = MakeUnitCircle();
|
||||
private static readonly float[] UnitCircle = CreateCircle();
|
||||
|
||||
public static readonly IDtPolygonByCircleConstraint Shared = new DtStrictDtPolygonByCircleConstraint();
|
||||
|
||||
|
@ -17,7 +15,7 @@ namespace DotRecast.Detour
|
|||
{
|
||||
}
|
||||
|
||||
private static float[] MakeUnitCircle()
|
||||
public static float[] CreateCircle()
|
||||
{
|
||||
var temp = new float[CIRCLE_SEGMENTS * 3];
|
||||
for (int i = 0; i < CIRCLE_SEGMENTS; i++)
|
||||
|
@ -31,13 +29,23 @@ namespace DotRecast.Detour
|
|||
return temp;
|
||||
}
|
||||
|
||||
public float[] Apply(float[] verts, RcVec3f center, float radius)
|
||||
public static void ScaleCircle(Span<float> src, RcVec3f center, float radius, Span<float> dst)
|
||||
{
|
||||
for (int i = 0; i < CIRCLE_SEGMENTS; i++)
|
||||
{
|
||||
dst[3 * i] = src[3 * i] * radius + center.X;
|
||||
dst[3 * i + 1] = center.Y;
|
||||
dst[3 * i + 2] = src[3 * i + 2] * radius + center.Z;
|
||||
}
|
||||
}
|
||||
|
||||
public Span<float> Apply(Span<float> verts, RcVec3f center, float radius, Span<float> resultBuffer)
|
||||
{
|
||||
float radiusSqr = radius * radius;
|
||||
int outsideVertex = -1;
|
||||
for (int pv = 0; pv < verts.Length; pv += 3)
|
||||
{
|
||||
if (RcVecUtils.Dist2DSqr(center, verts, pv) > radiusSqr)
|
||||
if (RcVec.Dist2DSqr(center, verts, pv) > radiusSqr)
|
||||
{
|
||||
outsideVertex = pv;
|
||||
break;
|
||||
|
@ -47,32 +55,30 @@ namespace DotRecast.Detour
|
|||
if (outsideVertex == -1)
|
||||
{
|
||||
// polygon inside circle
|
||||
return verts;
|
||||
var result = resultBuffer.Slice(0, verts.Length);
|
||||
verts.CopyTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
float[] qCircle = Circle(center, radius);
|
||||
float[] intersection = DtConvexConvexIntersections.Intersect(verts, qCircle);
|
||||
if (intersection == null && DtUtils.PointInPolygon(center, verts, verts.Length / 3))
|
||||
Span<float> qCircle = stackalloc float[UnitCircle.Length];
|
||||
ScaleCircle(UnitCircle, center, radius, qCircle);
|
||||
Span<float> intersection = DtConvexConvexIntersections.Intersect(verts, qCircle, resultBuffer);
|
||||
if (intersection.IsEmpty && DtUtils.PointInPolygon(center, verts, verts.Length / 3))
|
||||
{
|
||||
// circle inside polygon
|
||||
return qCircle;
|
||||
var result = resultBuffer.Slice(0, qCircle.Length);
|
||||
qCircle.CopyTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return intersection;
|
||||
}
|
||||
|
||||
|
||||
private float[] Circle(RcVec3f center, float radius)
|
||||
if(!intersection.IsEmpty)
|
||||
{
|
||||
float[] circle = new float[12 * 3];
|
||||
for (int i = 0; i < CIRCLE_SEGMENTS * 3; i += 3)
|
||||
{
|
||||
circle[i] = UnitCircle[i] * radius + center.X;
|
||||
circle[i + 1] = center.Y;
|
||||
circle[i + 2] = UnitCircle[i + 2] * radius + center.Z;
|
||||
var result = resultBuffer.Slice(0, intersection.Length);
|
||||
// No need to copy, data is already in buffer
|
||||
return result;
|
||||
}
|
||||
|
||||
return circle;
|
||||
return Span<float>.Empty;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,10 @@
|
|||
using System;
|
||||
using DotRecast.Core;
|
||||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
public static class DtUtils
|
||||
{
|
||||
private static readonly float EQUAL_THRESHOLD = RcMath.Sqr(1.0f / 16384.0f);
|
||||
|
||||
public static int NextPow2(int v)
|
||||
{
|
||||
v--;
|
||||
|
@ -39,24 +36,6 @@ namespace DotRecast.Detour
|
|||
return r;
|
||||
}
|
||||
|
||||
/// Performs a 'sloppy' colocation check of the specified points.
|
||||
/// @param[in] p0 A point. [(x, y, z)]
|
||||
/// @param[in] p1 A point. [(x, y, z)]
|
||||
/// @return True if the points are considered to be at the same location.
|
||||
///
|
||||
/// Basically, this function will return true if the specified points are
|
||||
/// close enough to eachother to be considered colocated.
|
||||
public static bool VEqual(RcVec3f p0, RcVec3f p1)
|
||||
{
|
||||
return VEqual(p0, p1, EQUAL_THRESHOLD);
|
||||
}
|
||||
|
||||
public static bool VEqual(RcVec3f p0, RcVec3f p1, float thresholdSqr)
|
||||
{
|
||||
float d = RcVec3f.DistanceSquared(p0, p1);
|
||||
return d < thresholdSqr;
|
||||
}
|
||||
|
||||
/// Determines if two axis-aligned bounding boxes overlap.
|
||||
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
||||
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
||||
|
@ -64,12 +43,12 @@ namespace DotRecast.Detour
|
|||
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||
/// @return True if the two AABB's overlap.
|
||||
/// @see dtOverlapBounds
|
||||
public static bool OverlapQuantBounds(int[] amin, int[] amax, int[] bmin, int[] bmax)
|
||||
public static bool OverlapQuantBounds(ref RcVec3i amin, ref RcVec3i amax, ref RcVec3i bmin, ref RcVec3i bmax)
|
||||
{
|
||||
bool overlap = true;
|
||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||
overlap = (amin.X > bmax.X || amax.X < bmin.X) ? false : overlap;
|
||||
overlap = (amin.Y > bmax.Y || amax.Y < bmin.Y) ? false : overlap;
|
||||
overlap = (amin.Z > bmax.Z || amax.Z < bmin.Z) ? false : overlap;
|
||||
return overlap;
|
||||
}
|
||||
|
||||
|
@ -97,7 +76,7 @@ namespace DotRecast.Detour
|
|||
/// @par
|
||||
///
|
||||
/// All vertices are projected onto the xz-plane, so the y-values are ignored.
|
||||
public static bool OverlapPolyPoly2D(float[] polya, int npolya, float[] polyb, int npolyb)
|
||||
public static bool OverlapPolyPoly2D(Span<float> polya, int npolya, Span<float> polyb, int npolyb)
|
||||
{
|
||||
const float eps = 1e-4f;
|
||||
for (int i = 0, j = npolya - 1; i < npolya; j = i++)
|
||||
|
@ -145,7 +124,7 @@ namespace DotRecast.Detour
|
|||
/// @param[in] b Vertex B. [(x, y, z)]
|
||||
/// @param[in] c Vertex C. [(x, y, z)]
|
||||
/// @return The signed xz-plane area of the triangle.
|
||||
public static float TriArea2D(float[] verts, int a, int b, int c)
|
||||
public static float TriArea2D(Span<float> verts, int a, int b, int c)
|
||||
{
|
||||
float abx = verts[b] - verts[a];
|
||||
float abz = verts[b + 2] - verts[a + 2];
|
||||
|
@ -165,7 +144,7 @@ namespace DotRecast.Detour
|
|||
|
||||
// Returns a random point in a convex polygon.
|
||||
// Adapted from Graphics Gems article.
|
||||
public static RcVec3f RandomPointInConvexPoly(float[] pts, int npts, float[] areas, float s, float t)
|
||||
public static void RandomPointInConvexPoly(Span<float> pts, int npts, Span<float> areas, float s, float t, out RcVec3f @out)
|
||||
{
|
||||
// Calc triangle araes
|
||||
float areasum = 0.0f;
|
||||
|
@ -202,7 +181,7 @@ namespace DotRecast.Detour
|
|||
int pb = (tri - 1) * 3;
|
||||
int pc = tri * 3;
|
||||
|
||||
return new RcVec3f()
|
||||
@out = new RcVec3f()
|
||||
{
|
||||
X = a * pts[pa] + b * pts[pb] + c * pts[pc],
|
||||
Y = a * pts[pa + 1] + b * pts[pb + 1] + c * pts[pc + 1],
|
||||
|
@ -246,13 +225,13 @@ namespace DotRecast.Detour
|
|||
return false;
|
||||
}
|
||||
|
||||
public static RcVec2f ProjectPoly(RcVec3f axis, float[] poly, int npoly)
|
||||
public static RcVec2f ProjectPoly(RcVec3f axis, Span<float> poly, int npoly)
|
||||
{
|
||||
float rmin, rmax;
|
||||
rmin = rmax = axis.Dot2D(poly, 0);
|
||||
rmin = rmax = axis.Dot2D(new RcVec3f(poly));
|
||||
for (int i = 1; i < npoly; ++i)
|
||||
{
|
||||
float d = axis.Dot2D(poly, i * 3);
|
||||
float d = axis.Dot2D(RcVec.Create(poly, i * 3));
|
||||
rmin = Math.Min(rmin, d);
|
||||
rmax = Math.Max(rmax, d);
|
||||
}
|
||||
|
@ -267,7 +246,7 @@ namespace DotRecast.Detour
|
|||
/// @par
|
||||
///
|
||||
/// All points are projected onto the xz-plane, so the y-values are ignored.
|
||||
public static bool PointInPolygon(RcVec3f pt, float[] verts, int nverts)
|
||||
public static bool PointInPolygon(RcVec3f pt, Span<float> verts, int nverts)
|
||||
{
|
||||
// TODO: Replace pnpoly with triArea2D tests?
|
||||
int i, j;
|
||||
|
@ -286,7 +265,7 @@ namespace DotRecast.Detour
|
|||
return c;
|
||||
}
|
||||
|
||||
public static bool DistancePtPolyEdgesSqr(RcVec3f pt, float[] verts, int nverts, float[] ed, float[] et)
|
||||
public static bool DistancePtPolyEdgesSqr(RcVec3f pt, Span<float> verts, int nverts, Span<float> ed, Span<float> et)
|
||||
{
|
||||
// TODO: Replace pnpoly with triArea2D tests?
|
||||
int i, j;
|
||||
|
@ -307,10 +286,10 @@ namespace DotRecast.Detour
|
|||
return c;
|
||||
}
|
||||
|
||||
public static float DistancePtSegSqr2D(RcVec3f pt, float[] verts, int p, int q, out float t)
|
||||
public static float DistancePtSegSqr2D(RcVec3f pt, Span<float> verts, int p, int q, out float t)
|
||||
{
|
||||
var vp = RcVecUtils.Create(verts, p);
|
||||
var vq = RcVecUtils.Create(verts, q);
|
||||
var vp = RcVec.Create(verts, p);
|
||||
var vq = RcVec.Create(verts, q);
|
||||
return DistancePtSegSqr2D(pt, vp, vq, out t);
|
||||
}
|
||||
|
||||
|
@ -342,7 +321,7 @@ namespace DotRecast.Detour
|
|||
}
|
||||
|
||||
public static bool IntersectSegmentPoly2D(RcVec3f p0, RcVec3f p1,
|
||||
RcVec3f[] verts, int nverts,
|
||||
Span<RcVec3f> verts, int nverts,
|
||||
out float tmin, out float tmax,
|
||||
out int segMin, out int segMax)
|
||||
{
|
||||
|
@ -362,8 +341,8 @@ namespace DotRecast.Detour
|
|||
RcVec3f vpi = verts[i];
|
||||
var edge = RcVec3f.Subtract(vpi, vpj);
|
||||
var diff = RcVec3f.Subtract(p0v, vpj);
|
||||
float n = RcVecUtils.Perp2D(edge, diff);
|
||||
float d = RcVecUtils.Perp2D(dir, edge);
|
||||
float n = RcVec.Perp2D(edge, diff);
|
||||
float d = RcVec.Perp2D(dir, edge);
|
||||
if (MathF.Abs(d) < EPS)
|
||||
{
|
||||
// S is nearly parallel to this edge
|
||||
|
@ -425,14 +404,14 @@ namespace DotRecast.Detour
|
|||
RcVec3f u = RcVec3f.Subtract(aq, ap);
|
||||
RcVec3f v = RcVec3f.Subtract(bq, bp);
|
||||
RcVec3f w = RcVec3f.Subtract(ap, bp);
|
||||
float d = RcVecUtils.PerpXZ(u, v);
|
||||
float d = RcVec.PerpXZ(u, v);
|
||||
if (MathF.Abs(d) < 1e-6f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
s = RcVecUtils.PerpXZ(v, w) / d;
|
||||
t = RcVecUtils.PerpXZ(u, w) / d;
|
||||
s = RcVec.PerpXZ(v, w) / d;
|
||||
t = RcVec.PerpXZ(u, w) / d;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
using System;
|
||||
|
||||
namespace DotRecast.Detour
|
||||
{
|
||||
/// Provides custom polygon query behavior.
|
||||
/// Used by dtNavMeshQuery::queryPolygons.
|
||||
/// @ingroup detour
|
||||
public interface IDtPolyQuery
|
||||
{
|
||||
void Process(DtMeshTile tile, DtPoly poly, long refs);
|
||||
/// Called for each batch of unique polygons touched by the search area in dtNavMeshQuery::queryPolygons.
|
||||
/// This can be called multiple times for a single query.
|
||||
void Process(DtMeshTile tile, Span<DtPoly> poly, Span<long> refs, int count);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -24,6 +24,6 @@ namespace DotRecast.Detour
|
|||
{
|
||||
public interface IDtPolygonByCircleConstraint
|
||||
{
|
||||
float[] Apply(float[] polyVerts, RcVec3f circleCenter, float radius);
|
||||
Span<float> Apply(Span<float> polyVerts, RcVec3f circleCenter, float radius, Span<float> resultBuffer);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -21,13 +21,17 @@ using DotRecast.Core;
|
|||
|
||||
namespace DotRecast.Detour.Io
|
||||
{
|
||||
using static DtDetour;
|
||||
|
||||
public class DtMeshDataReader
|
||||
{
|
||||
public const int DT_POLY_DETAIL_SIZE = 10;
|
||||
public const int LINK_SIZEOF = 16;
|
||||
public const int LINK_SIZEOF32BIT = 12;
|
||||
|
||||
public DtMeshData Read(BinaryReader stream, int maxVertPerPoly)
|
||||
{
|
||||
RcByteBuffer buf = IOUtils.ToByteBuffer(stream);
|
||||
RcByteBuffer buf = RcIO.ToByteBuffer(stream);
|
||||
return Read(buf, maxVertPerPoly, false);
|
||||
}
|
||||
|
||||
|
@ -38,7 +42,7 @@ namespace DotRecast.Detour.Io
|
|||
|
||||
public DtMeshData Read32Bit(BinaryReader stream, int maxVertPerPoly)
|
||||
{
|
||||
RcByteBuffer buf = IOUtils.ToByteBuffer(stream);
|
||||
RcByteBuffer buf = RcIO.ToByteBuffer(stream);
|
||||
return Read(buf, maxVertPerPoly, true);
|
||||
}
|
||||
|
||||
|
@ -53,10 +57,10 @@ namespace DotRecast.Detour.Io
|
|||
DtMeshHeader header = new DtMeshHeader();
|
||||
data.header = header;
|
||||
header.magic = buf.GetInt();
|
||||
if (header.magic != DtNavMesh.DT_NAVMESH_MAGIC)
|
||||
if (header.magic != DT_NAVMESH_MAGIC)
|
||||
{
|
||||
header.magic = IOUtils.SwapEndianness(header.magic);
|
||||
if (header.magic != DtNavMesh.DT_NAVMESH_MAGIC)
|
||||
header.magic = RcIO.SwapEndianness(header.magic);
|
||||
if (header.magic != DT_NAVMESH_MAGIC)
|
||||
{
|
||||
throw new IOException("Invalid magic");
|
||||
}
|
||||
|
@ -65,16 +69,16 @@ namespace DotRecast.Detour.Io
|
|||
}
|
||||
|
||||
header.version = buf.GetInt();
|
||||
if (header.version != DtNavMesh.DT_NAVMESH_VERSION)
|
||||
if (header.version != DT_NAVMESH_VERSION)
|
||||
{
|
||||
if (header.version < DtNavMesh.DT_NAVMESH_VERSION_RECAST4J_FIRST
|
||||
|| header.version > DtNavMesh.DT_NAVMESH_VERSION_RECAST4J_LAST)
|
||||
if (header.version < DT_NAVMESH_VERSION_RECAST4J_FIRST
|
||||
|| header.version > DT_NAVMESH_VERSION_RECAST4J_LAST)
|
||||
{
|
||||
throw new IOException("Invalid version " + header.version);
|
||||
}
|
||||
}
|
||||
|
||||
bool cCompatibility = header.version == DtNavMesh.DT_NAVMESH_VERSION;
|
||||
bool cCompatibility = header.version == DT_NAVMESH_VERSION;
|
||||
header.x = buf.GetInt();
|
||||
header.y = buf.GetInt();
|
||||
header.layer = buf.GetInt();
|
||||
|
@ -116,8 +120,6 @@ namespace DotRecast.Detour.Io
|
|||
return data;
|
||||
}
|
||||
|
||||
public const int LINK_SIZEOF = 16;
|
||||
public const int LINK_SIZEOF32BIT = 12;
|
||||
|
||||
public static int GetSizeofLink(bool is32Bit)
|
||||
{
|
||||
|
@ -141,7 +143,7 @@ namespace DotRecast.Detour.Io
|
|||
for (int i = 0; i < polys.Length; i++)
|
||||
{
|
||||
polys[i] = new DtPoly(i, maxVertPerPoly);
|
||||
if (header.version < DtNavMesh.DT_NAVMESH_VERSION_RECAST4J_NO_POLY_FIRSTLINK)
|
||||
if (header.version < DT_NAVMESH_VERSION_RECAST4J_NO_POLY_FIRSTLINK)
|
||||
{
|
||||
buf.GetInt(); // polys[i].firstLink
|
||||
}
|
||||
|
@ -171,8 +173,8 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
int vertBase = buf.GetInt();
|
||||
int triBase = buf.GetInt();
|
||||
int vertCount = buf.Get() & 0xFF;
|
||||
int triCount = buf.Get() & 0xFF;
|
||||
byte vertCount = (byte)(buf.Get() & 0xFF);
|
||||
byte triCount = (byte)(buf.Get() & 0xFF);
|
||||
polys[i] = new DtPolyDetail(vertBase, triBase, vertCount, triCount);
|
||||
if (cCompatibility)
|
||||
{
|
||||
|
@ -200,29 +202,25 @@ namespace DotRecast.Detour.Io
|
|||
for (int i = 0; i < nodes.Length; i++)
|
||||
{
|
||||
nodes[i] = new DtBVNode();
|
||||
if (header.version < DtNavMesh.DT_NAVMESH_VERSION_RECAST4J_32BIT_BVTREE)
|
||||
if (header.version < DT_NAVMESH_VERSION_RECAST4J_32BIT_BVTREE)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
nodes[i].bmin[j] = buf.GetShort() & 0xFFFF;
|
||||
}
|
||||
nodes[i].bmin.X = buf.GetShort() & 0xFFFF;
|
||||
nodes[i].bmin.Y = buf.GetShort() & 0xFFFF;
|
||||
nodes[i].bmin.Z = buf.GetShort() & 0xFFFF;
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
nodes[i].bmax[j] = buf.GetShort() & 0xFFFF;
|
||||
}
|
||||
nodes[i].bmax.X = buf.GetShort() & 0xFFFF;
|
||||
nodes[i].bmax.Y = buf.GetShort() & 0xFFFF;
|
||||
nodes[i].bmax.Z = buf.GetShort() & 0xFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
nodes[i].bmin[j] = buf.GetInt();
|
||||
}
|
||||
nodes[i].bmin.X = buf.GetInt();
|
||||
nodes[i].bmin.Y = buf.GetInt();
|
||||
nodes[i].bmin.Z = buf.GetInt();
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
nodes[i].bmax[j] = buf.GetInt();
|
||||
}
|
||||
nodes[i].bmax.X = buf.GetInt();
|
||||
nodes[i].bmax.Y = buf.GetInt();
|
||||
nodes[i].bmax.Z = buf.GetInt();
|
||||
}
|
||||
|
||||
nodes[i].i = buf.GetInt();
|
||||
|
|
|
@ -21,36 +21,38 @@ using DotRecast.Core;
|
|||
|
||||
namespace DotRecast.Detour.Io
|
||||
{
|
||||
public class DtMeshDataWriter : DtWriter
|
||||
using static DtDetour;
|
||||
|
||||
public class DtMeshDataWriter
|
||||
{
|
||||
public void Write(BinaryWriter stream, DtMeshData data, RcByteOrder order, bool cCompatibility)
|
||||
{
|
||||
DtMeshHeader header = data.header;
|
||||
Write(stream, header.magic, order);
|
||||
Write(stream, cCompatibility ? DtNavMesh.DT_NAVMESH_VERSION : DtNavMesh.DT_NAVMESH_VERSION_RECAST4J_LAST, order);
|
||||
Write(stream, header.x, order);
|
||||
Write(stream, header.y, order);
|
||||
Write(stream, header.layer, order);
|
||||
Write(stream, header.userId, order);
|
||||
Write(stream, header.polyCount, order);
|
||||
Write(stream, header.vertCount, order);
|
||||
Write(stream, header.maxLinkCount, order);
|
||||
Write(stream, header.detailMeshCount, order);
|
||||
Write(stream, header.detailVertCount, order);
|
||||
Write(stream, header.detailTriCount, order);
|
||||
Write(stream, header.bvNodeCount, order);
|
||||
Write(stream, header.offMeshConCount, order);
|
||||
Write(stream, header.offMeshBase, order);
|
||||
Write(stream, header.walkableHeight, order);
|
||||
Write(stream, header.walkableRadius, order);
|
||||
Write(stream, header.walkableClimb, order);
|
||||
Write(stream, header.bmin.X, order);
|
||||
Write(stream, header.bmin.Y, order);
|
||||
Write(stream, header.bmin.Z, order);
|
||||
Write(stream, header.bmax.X, order);
|
||||
Write(stream, header.bmax.Y, order);
|
||||
Write(stream, header.bmax.Z, order);
|
||||
Write(stream, header.bvQuantFactor, order);
|
||||
RcIO.Write(stream, header.magic, order);
|
||||
RcIO.Write(stream, cCompatibility ? DT_NAVMESH_VERSION : DT_NAVMESH_VERSION_RECAST4J_LAST, order);
|
||||
RcIO.Write(stream, header.x, order);
|
||||
RcIO.Write(stream, header.y, order);
|
||||
RcIO.Write(stream, header.layer, order);
|
||||
RcIO.Write(stream, header.userId, order);
|
||||
RcIO.Write(stream, header.polyCount, order);
|
||||
RcIO.Write(stream, header.vertCount, order);
|
||||
RcIO.Write(stream, header.maxLinkCount, order);
|
||||
RcIO.Write(stream, header.detailMeshCount, order);
|
||||
RcIO.Write(stream, header.detailVertCount, order);
|
||||
RcIO.Write(stream, header.detailTriCount, order);
|
||||
RcIO.Write(stream, header.bvNodeCount, order);
|
||||
RcIO.Write(stream, header.offMeshConCount, order);
|
||||
RcIO.Write(stream, header.offMeshBase, order);
|
||||
RcIO.Write(stream, header.walkableHeight, order);
|
||||
RcIO.Write(stream, header.walkableRadius, order);
|
||||
RcIO.Write(stream, header.walkableClimb, order);
|
||||
RcIO.Write(stream, header.bmin.X, order);
|
||||
RcIO.Write(stream, header.bmin.Y, order);
|
||||
RcIO.Write(stream, header.bmin.Z, order);
|
||||
RcIO.Write(stream, header.bmax.X, order);
|
||||
RcIO.Write(stream, header.bmax.Y, order);
|
||||
RcIO.Write(stream, header.bmax.Z, order);
|
||||
RcIO.Write(stream, header.bvQuantFactor, order);
|
||||
WriteVerts(stream, data.verts, header.vertCount, order);
|
||||
WritePolys(stream, data, order, cCompatibility);
|
||||
if (cCompatibility)
|
||||
|
@ -70,7 +72,7 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
for (int i = 0; i < count * 3; i++)
|
||||
{
|
||||
Write(stream, verts[i], order);
|
||||
RcIO.Write(stream, verts[i], order);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,22 +82,22 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
if (cCompatibility)
|
||||
{
|
||||
Write(stream, 0xFFFF, order);
|
||||
RcIO.Write(stream, 0xFFFF, order);
|
||||
}
|
||||
|
||||
for (int j = 0; j < data.polys[i].verts.Length; j++)
|
||||
{
|
||||
Write(stream, (short)data.polys[i].verts[j], order);
|
||||
RcIO.Write(stream, (short)data.polys[i].verts[j], order);
|
||||
}
|
||||
|
||||
for (int j = 0; j < data.polys[i].neis.Length; j++)
|
||||
{
|
||||
Write(stream, (short)data.polys[i].neis[j], order);
|
||||
RcIO.Write(stream, (short)data.polys[i].neis[j], order);
|
||||
}
|
||||
|
||||
Write(stream, (short)data.polys[i].flags, order);
|
||||
Write(stream, (byte)data.polys[i].vertCount);
|
||||
Write(stream, (byte)data.polys[i].areaAndtype);
|
||||
RcIO.Write(stream, (short)data.polys[i].flags, order);
|
||||
RcIO.Write(stream, (byte)data.polys[i].vertCount);
|
||||
RcIO.Write(stream, (byte)data.polys[i].areaAndtype);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,13 +105,13 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
for (int i = 0; i < data.header.detailMeshCount; i++)
|
||||
{
|
||||
Write(stream, data.detailMeshes[i].vertBase, order);
|
||||
Write(stream, data.detailMeshes[i].triBase, order);
|
||||
Write(stream, (byte)data.detailMeshes[i].vertCount);
|
||||
Write(stream, (byte)data.detailMeshes[i].triCount);
|
||||
RcIO.Write(stream, data.detailMeshes[i].vertBase, order);
|
||||
RcIO.Write(stream, data.detailMeshes[i].triBase, order);
|
||||
RcIO.Write(stream, (byte)data.detailMeshes[i].vertCount);
|
||||
RcIO.Write(stream, (byte)data.detailMeshes[i].triCount);
|
||||
if (cCompatibility)
|
||||
{
|
||||
Write(stream, (short)0, order);
|
||||
RcIO.Write(stream, (short)0, order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +120,7 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
for (int i = 0; i < data.header.detailTriCount * 4; i++)
|
||||
{
|
||||
Write(stream, (byte)data.detailTris[i]);
|
||||
RcIO.Write(stream, (byte)data.detailTris[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,30 +130,26 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
if (cCompatibility)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
Write(stream, (short)data.bvTree[i].bmin[j], order);
|
||||
}
|
||||
RcIO.Write(stream, (short)data.bvTree[i].bmin.X, order);
|
||||
RcIO.Write(stream, (short)data.bvTree[i].bmin.Y, order);
|
||||
RcIO.Write(stream, (short)data.bvTree[i].bmin.Z, order);
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
Write(stream, (short)data.bvTree[i].bmax[j], order);
|
||||
}
|
||||
RcIO.Write(stream, (short)data.bvTree[i].bmax.X, order);
|
||||
RcIO.Write(stream, (short)data.bvTree[i].bmax.Y, order);
|
||||
RcIO.Write(stream, (short)data.bvTree[i].bmax.Z, order);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
Write(stream, data.bvTree[i].bmin[j], order);
|
||||
RcIO.Write(stream, data.bvTree[i].bmin.X, order);
|
||||
RcIO.Write(stream, data.bvTree[i].bmin.Y, order);
|
||||
RcIO.Write(stream, data.bvTree[i].bmin.Z, order);
|
||||
|
||||
RcIO.Write(stream, data.bvTree[i].bmax.X, order);
|
||||
RcIO.Write(stream, data.bvTree[i].bmax.Y, order);
|
||||
RcIO.Write(stream, data.bvTree[i].bmax.Z, order);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
Write(stream, data.bvTree[i].bmax[j], order);
|
||||
}
|
||||
}
|
||||
|
||||
Write(stream, data.bvTree[i].i, order);
|
||||
RcIO.Write(stream, data.bvTree[i].i, order);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,16 +159,16 @@ namespace DotRecast.Detour.Io
|
|||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
Write(stream, data.offMeshCons[i].pos[j].X, order);
|
||||
Write(stream, data.offMeshCons[i].pos[j].Y, order);
|
||||
Write(stream, data.offMeshCons[i].pos[j].Z, order);
|
||||
RcIO.Write(stream, data.offMeshCons[i].pos[j].X, order);
|
||||
RcIO.Write(stream, data.offMeshCons[i].pos[j].Y, order);
|
||||
RcIO.Write(stream, data.offMeshCons[i].pos[j].Z, order);
|
||||
}
|
||||
|
||||
Write(stream, data.offMeshCons[i].rad, order);
|
||||
Write(stream, (short)data.offMeshCons[i].poly, order);
|
||||
Write(stream, (byte)data.offMeshCons[i].flags);
|
||||
Write(stream, (byte)data.offMeshCons[i].side);
|
||||
Write(stream, data.offMeshCons[i].userId, order);
|
||||
RcIO.Write(stream, data.offMeshCons[i].rad, order);
|
||||
RcIO.Write(stream, (short)data.offMeshCons[i].poly, order);
|
||||
RcIO.Write(stream, (byte)data.offMeshCons[i].flags);
|
||||
RcIO.Write(stream, (byte)data.offMeshCons[i].side);
|
||||
RcIO.Write(stream, data.offMeshCons[i].userId, order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ using DotRecast.Core;
|
|||
|
||||
namespace DotRecast.Detour.Io
|
||||
{
|
||||
using static DtDetour;
|
||||
|
||||
public class DtMeshSetReader
|
||||
{
|
||||
private readonly DtMeshDataReader meshReader = new DtMeshDataReader();
|
||||
|
@ -29,7 +31,7 @@ namespace DotRecast.Detour.Io
|
|||
|
||||
public DtNavMesh Read(BinaryReader @is, int maxVertPerPoly)
|
||||
{
|
||||
return Read(IOUtils.ToByteBuffer(@is), maxVertPerPoly, false);
|
||||
return Read(RcIO.ToByteBuffer(@is), maxVertPerPoly, false);
|
||||
}
|
||||
|
||||
public DtNavMesh Read(RcByteBuffer bb, int maxVertPerPoly)
|
||||
|
@ -39,7 +41,7 @@ namespace DotRecast.Detour.Io
|
|||
|
||||
public DtNavMesh Read32Bit(BinaryReader @is, int maxVertPerPoly)
|
||||
{
|
||||
return Read(IOUtils.ToByteBuffer(@is), maxVertPerPoly, true);
|
||||
return Read(RcIO.ToByteBuffer(@is), maxVertPerPoly, true);
|
||||
}
|
||||
|
||||
public DtNavMesh Read32Bit(RcByteBuffer bb, int maxVertPerPoly)
|
||||
|
@ -49,7 +51,7 @@ namespace DotRecast.Detour.Io
|
|||
|
||||
public DtNavMesh Read(BinaryReader @is)
|
||||
{
|
||||
return Read(IOUtils.ToByteBuffer(@is));
|
||||
return Read(RcIO.ToByteBuffer(@is));
|
||||
}
|
||||
|
||||
public DtNavMesh Read(RcByteBuffer bb)
|
||||
|
@ -66,7 +68,8 @@ namespace DotRecast.Detour.Io
|
|||
}
|
||||
|
||||
bool cCompatibility = header.version == NavMeshSetHeader.NAVMESHSET_VERSION;
|
||||
DtNavMesh mesh = new DtNavMesh(header.option, header.maxVertsPerPoly);
|
||||
DtNavMesh mesh = new DtNavMesh();
|
||||
mesh.Init(header.option, header.maxVertsPerPoly);
|
||||
ReadTiles(bb, is32Bit, ref header, cCompatibility, mesh);
|
||||
return mesh;
|
||||
}
|
||||
|
@ -77,7 +80,7 @@ namespace DotRecast.Detour.Io
|
|||
header.magic = bb.GetInt();
|
||||
if (header.magic != NavMeshSetHeader.NAVMESHSET_MAGIC)
|
||||
{
|
||||
header.magic = IOUtils.SwapEndianness(header.magic);
|
||||
header.magic = RcIO.SwapEndianness(header.magic);
|
||||
if (header.magic != NavMeshSetHeader.NAVMESHSET_MAGIC)
|
||||
{
|
||||
throw new IOException("Invalid magic " + header.magic);
|
||||
|
@ -131,7 +134,7 @@ namespace DotRecast.Detour.Io
|
|||
}
|
||||
|
||||
DtMeshData data = meshReader.Read(bb, mesh.GetMaxVertsPerPoly(), is32Bit);
|
||||
mesh.AddTile(data, i, tileHeader.tileRef);
|
||||
mesh.AddTile(data, i, tileHeader.tileRef, out _);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +150,7 @@ namespace DotRecast.Detour.Io
|
|||
int salt = ((refs >> (m_polyBits + m_tileBits)) & saltMask);
|
||||
int it = ((refs >> m_polyBits) & tileMask);
|
||||
int ip = refs & polyMask;
|
||||
return DtNavMesh.EncodePolyId(salt, it, ip);
|
||||
return EncodePolyId(salt, it, ip);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Detour.Io
|
||||
{
|
||||
public class DtMeshSetWriter : DtWriter
|
||||
public class DtMeshSetWriter
|
||||
{
|
||||
private readonly DtMeshDataWriter writer = new DtMeshDataWriter();
|
||||
private readonly DtNavMeshParamWriter paramWriter = new DtNavMeshParamWriter();
|
||||
|
@ -35,8 +35,8 @@ namespace DotRecast.Detour.Io
|
|||
|
||||
private void WriteHeader(BinaryWriter stream, DtNavMesh mesh, RcByteOrder order, bool cCompatibility)
|
||||
{
|
||||
Write(stream, NavMeshSetHeader.NAVMESHSET_MAGIC, order);
|
||||
Write(stream, cCompatibility ? NavMeshSetHeader.NAVMESHSET_VERSION : NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J, order);
|
||||
RcIO.Write(stream, NavMeshSetHeader.NAVMESHSET_MAGIC, order);
|
||||
RcIO.Write(stream, cCompatibility ? NavMeshSetHeader.NAVMESHSET_VERSION : NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J, order);
|
||||
int numTiles = 0;
|
||||
for (int i = 0; i < mesh.GetMaxTiles(); ++i)
|
||||
{
|
||||
|
@ -49,11 +49,11 @@ namespace DotRecast.Detour.Io
|
|||
numTiles++;
|
||||
}
|
||||
|
||||
Write(stream, numTiles, order);
|
||||
RcIO.Write(stream, numTiles, order);
|
||||
paramWriter.Write(stream, mesh.GetParams(), order);
|
||||
if (!cCompatibility)
|
||||
{
|
||||
Write(stream, mesh.GetMaxVertsPerPoly(), order);
|
||||
RcIO.Write(stream, mesh.GetMaxVertsPerPoly(), order);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,11 +77,11 @@ namespace DotRecast.Detour.Io
|
|||
|
||||
byte[] ba = msw.ToArray();
|
||||
tileHeader.dataSize = ba.Length;
|
||||
Write(stream, tileHeader.tileRef, order);
|
||||
Write(stream, tileHeader.dataSize, order);
|
||||
RcIO.Write(stream, tileHeader.tileRef, order);
|
||||
RcIO.Write(stream, tileHeader.dataSize, order);
|
||||
if (cCompatibility)
|
||||
{
|
||||
Write(stream, 0, order); // C struct padding
|
||||
RcIO.Write(stream, 0, order); // C struct padding
|
||||
}
|
||||
|
||||
stream.Write(ba);
|
||||
|
|
|
@ -4,17 +4,17 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Detour.Io
|
||||
{
|
||||
public class DtNavMeshParamWriter : DtWriter
|
||||
public class DtNavMeshParamWriter
|
||||
{
|
||||
public void Write(BinaryWriter stream, DtNavMeshParams option, RcByteOrder order)
|
||||
{
|
||||
Write(stream, option.orig.X, order);
|
||||
Write(stream, option.orig.Y, order);
|
||||
Write(stream, option.orig.Z, order);
|
||||
Write(stream, option.tileWidth, order);
|
||||
Write(stream, option.tileHeight, order);
|
||||
Write(stream, option.maxTiles, order);
|
||||
Write(stream, option.maxPolys, order);
|
||||
RcIO.Write(stream, option.orig.X, order);
|
||||
RcIO.Write(stream, option.orig.Y, order);
|
||||
RcIO.Write(stream, option.orig.Z, order);
|
||||
RcIO.Write(stream, option.tileWidth, order);
|
||||
RcIO.Write(stream, option.tileHeight, order);
|
||||
RcIO.Write(stream, option.maxTiles, order);
|
||||
RcIO.Write(stream, option.maxPolys, order);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
Recast4J Copyright (c) 2015 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 System.IO;
|
||||
using DotRecast.Core;
|
||||
|
||||
namespace DotRecast.Detour.Io
|
||||
{
|
||||
public abstract class DtWriter
|
||||
{
|
||||
protected void Write(BinaryWriter stream, float value, RcByteOrder order)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
int i = BitConverter.ToInt32(bytes, 0);
|
||||
Write(stream, i, order);
|
||||
}
|
||||
|
||||
protected void Write(BinaryWriter stream, short value, RcByteOrder order)
|
||||
{
|
||||
if (order == RcByteOrder.BIG_ENDIAN)
|
||||
{
|
||||
stream.Write((byte)((value >> 8) & 0xFF));
|
||||
stream.Write((byte)(value & 0xFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.Write((byte)(value & 0xFF));
|
||||
stream.Write((byte)((value >> 8) & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
protected void Write(BinaryWriter stream, long value, RcByteOrder order)
|
||||
{
|
||||
if (order == RcByteOrder.BIG_ENDIAN)
|
||||
{
|
||||
Write(stream, (int)((ulong)value >> 32), order);
|
||||
Write(stream, (int)(value & 0xFFFFFFFF), order);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write(stream, (int)(value & 0xFFFFFFFF), order);
|
||||
Write(stream, (int)((ulong)value >> 32), order);
|
||||
}
|
||||
}
|
||||
|
||||
protected void Write(BinaryWriter stream, int value, RcByteOrder order)
|
||||
{
|
||||
if (order == RcByteOrder.BIG_ENDIAN)
|
||||
{
|
||||
stream.Write((byte)((value >> 24) & 0xFF));
|
||||
stream.Write((byte)((value >> 16) & 0xFF));
|
||||
stream.Write((byte)((value >> 8) & 0xFF));
|
||||
stream.Write((byte)(value & 0xFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.Write((byte)(value & 0xFF));
|
||||
stream.Write((byte)((value >> 8) & 0xFF));
|
||||
stream.Write((byte)((value >> 16) & 0xFF));
|
||||
stream.Write((byte)((value >> 24) & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
protected void Write(BinaryWriter stream, bool @bool)
|
||||
{
|
||||
Write(stream, (byte)(@bool ? 1 : 0));
|
||||
}
|
||||
|
||||
protected void Write(BinaryWriter stream, byte value)
|
||||
{
|
||||
stream.Write(value);
|
||||
}
|
||||
|
||||
protected void Write(BinaryWriter stream, MemoryStream data)
|
||||
{
|
||||
data.Position = 0;
|
||||
byte[] buffer = new byte[data.Length];
|
||||
data.Read(buffer, 0, buffer.Length);
|
||||
stream.Write(buffer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
Recast4J Copyright (c) 2015 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 System.IO;
|
||||
using DotRecast.Core;
|
||||
|
||||
namespace DotRecast.Detour.Io
|
||||
{
|
||||
public static class IOUtils
|
||||
{
|
||||
public static RcByteBuffer ToByteBuffer(BinaryReader @is, bool direct)
|
||||
{
|
||||
byte[] data = ToByteArray(@is);
|
||||
if (direct)
|
||||
{
|
||||
Array.Reverse(data);
|
||||
}
|
||||
|
||||
return new RcByteBuffer(data);
|
||||
}
|
||||
|
||||
public static byte[] ToByteArray(BinaryReader inputStream)
|
||||
{
|
||||
using var msw = new MemoryStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int l;
|
||||
while ((l = inputStream.Read(buffer)) > 0)
|
||||
{
|
||||
msw.Write(buffer, 0, l);
|
||||
}
|
||||
|
||||
return msw.ToArray();
|
||||
}
|
||||
|
||||
|
||||
public static RcByteBuffer ToByteBuffer(BinaryReader inputStream)
|
||||
{
|
||||
var bytes = ToByteArray(inputStream);
|
||||
return new RcByteBuffer(bytes);
|
||||
}
|
||||
|
||||
public static int SwapEndianness(int i)
|
||||
{
|
||||
var s = (((uint)i >> 24) & 0xFF) | (((uint)i >> 8) & 0xFF00) | (((uint)i << 8) & 0xFF0000) | ((i << 24) & 0xFF000000);
|
||||
return (int)s;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -32,6 +32,7 @@ namespace DotRecast.Recast.Demo
|
|||
private DtNavMesh _navMesh;
|
||||
private DtNavMeshQuery _navMeshQuery;
|
||||
private readonly RcNavMeshBuildSettings _settings;
|
||||
private RcConfig _cfg;
|
||||
private IList<RcBuilderResult> _recastResults;
|
||||
private bool _changed;
|
||||
|
||||
|
@ -56,6 +57,11 @@ namespace DotRecast.Recast.Demo
|
|||
return _geom;
|
||||
}
|
||||
|
||||
public RcConfig GetRecastConfig()
|
||||
{
|
||||
return _cfg;
|
||||
}
|
||||
|
||||
public IList<RcBuilderResult> GetRecastResults()
|
||||
{
|
||||
return _recastResults;
|
||||
|
@ -86,9 +92,10 @@ namespace DotRecast.Recast.Demo
|
|||
_changed = changed;
|
||||
}
|
||||
|
||||
public void Update(DemoInputGeomProvider geom, IList<RcBuilderResult> recastResults, DtNavMesh navMesh)
|
||||
public void Update(DemoInputGeomProvider geom, RcConfig cfg, IList<RcBuilderResult> recastResults, DtNavMesh navMesh)
|
||||
{
|
||||
_geom = geom;
|
||||
_cfg = cfg;
|
||||
_recastResults = recastResults;
|
||||
_navMesh = navMesh;
|
||||
SetQuery(navMesh);
|
||||
|
|
|
@ -20,15 +20,15 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog" Version="3.1.1" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.0" />
|
||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0"/>
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.6"/>
|
||||
<PackageReference Include="Silk.NET" Version="2.20.0" />
|
||||
<PackageReference Include="Silk.NET.OpenGL.Extensions.ImGui" Version="2.20.0" />
|
||||
<PackageReference Include="Serilog" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
|
||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.8" />
|
||||
<PackageReference Include="Silk.NET" Version="2.22.0" />
|
||||
<PackageReference Include="Silk.NET.OpenGL.Extensions.ImGui" Version="2.22.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using DotRecast.Core;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Draw;
|
||||
|
@ -9,19 +9,19 @@ public class ArrayBuffer<T>
|
|||
private T[] _items;
|
||||
public int Count => _size;
|
||||
|
||||
public ArrayBuffer()
|
||||
public ArrayBuffer() : this(512) { }
|
||||
|
||||
public ArrayBuffer(int capacity)
|
||||
{
|
||||
if (capacity <= 0)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
_size = 0;
|
||||
_items = Array.Empty<T>();
|
||||
_items = new T[capacity];
|
||||
}
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
if (0 >= _items.Length)
|
||||
{
|
||||
_items = new T[256];
|
||||
}
|
||||
|
||||
if (_items.Length <= _size)
|
||||
{
|
||||
var temp = new T[(int)(_size * 1.5)];
|
||||
|
@ -37,8 +37,8 @@ public class ArrayBuffer<T>
|
|||
_size = 0;
|
||||
}
|
||||
|
||||
public T[] AsArray()
|
||||
public Span<T> AsArray()
|
||||
{
|
||||
return _items;
|
||||
return _items.AsSpan(0, _size);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -326,9 +326,9 @@ public class DebugDraw
|
|||
}
|
||||
}
|
||||
|
||||
private static readonly int NUM_ARC_PTS = 8;
|
||||
private static readonly float PAD = 0.05f;
|
||||
private static readonly float ARC_PTS_SCALE = (1.0f - PAD * 2) / NUM_ARC_PTS;
|
||||
private const int NUM_ARC_PTS = 8;
|
||||
private const float PAD = 0.05f;
|
||||
private const float ARC_PTS_SCALE = (1.0f - PAD * 2) / NUM_ARC_PTS;
|
||||
|
||||
public void AppendArc(float x0, float y0, float z0, float x1, float y1, float z1, float h, float as0, float as1, int col)
|
||||
{
|
||||
|
@ -694,7 +694,7 @@ public class DebugDraw
|
|||
plane[3] = pw;
|
||||
}
|
||||
|
||||
public bool FrustumTest(float[] bounds)
|
||||
public bool FrustumTest(Span<float> bounds)
|
||||
{
|
||||
foreach (float[] plane in frustumPlanes)
|
||||
{
|
||||
|
@ -748,6 +748,6 @@ public class DebugDraw
|
|||
|
||||
public bool FrustumTest(RcVec3f bmin, RcVec3f bmax)
|
||||
{
|
||||
return FrustumTest(new float[] { bmin.X, bmin.Y, bmin.Z, bmax.X, bmax.Y, bmax.Z });
|
||||
return FrustumTest(stackalloc float[] { bmin.X, bmin.Y, bmin.Z, bmax.X, bmax.Y, bmax.Z });
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -32,15 +32,18 @@ public class GLCheckerTexture
|
|||
_gl = gl;
|
||||
}
|
||||
|
||||
public void Release()
|
||||
public unsafe void Release()
|
||||
{
|
||||
if (m_texId != 0)
|
||||
{
|
||||
_gl.DeleteTextures(1, m_texId);
|
||||
fixed (uint* p = &m_texId)
|
||||
{
|
||||
_gl.DeleteTextures(1, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind()
|
||||
public unsafe void Bind()
|
||||
{
|
||||
if (m_texId == 0)
|
||||
{
|
||||
|
@ -50,7 +53,11 @@ public class GLCheckerTexture
|
|||
uint TSIZE = 64;
|
||||
int[] data = new int[TSIZE * TSIZE];
|
||||
|
||||
_gl.GenTextures(1, out m_texId);
|
||||
fixed (uint* p = &m_texId)
|
||||
{
|
||||
_gl.GenTextures(1, p);
|
||||
}
|
||||
|
||||
_gl.BindTexture(GLEnum.Texture2D, m_texId);
|
||||
|
||||
int level = 0;
|
||||
|
@ -70,8 +77,10 @@ public class GLCheckerTexture
|
|||
level++;
|
||||
}
|
||||
|
||||
_gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMinFilter, (uint)GLEnum.LinearMipmapNearest);
|
||||
_gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMagFilter, (uint)GLEnum.Linear);
|
||||
uint linearMipmapNearest = (uint)GLEnum.LinearMipmapNearest;
|
||||
uint linear = (uint)GLEnum.Linear;
|
||||
_gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMinFilter, &linearMipmapNearest);
|
||||
_gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMagFilter, &linear);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -68,8 +69,8 @@ public static class GLU
|
|||
public static int GlhUnProjectf(float winx, float winy, float winz, float[] modelview, float[] projection, int[] viewport, ref RcVec3f objectCoordinate)
|
||||
{
|
||||
// Transformation matrices
|
||||
float[] m = new float[16], A = new float[16];
|
||||
float[] @in = new float[4], @out = new float[4];
|
||||
Span<float> m = stackalloc float[16], A = stackalloc float[16];
|
||||
Span<float> @in = stackalloc float[4], @out = stackalloc float[4];
|
||||
// Calculation for inverting a matrix, compute projection x modelview
|
||||
// and store in A[16]
|
||||
MultiplyMatrices4by4OpenGL_FLOAT(A, projection, modelview);
|
||||
|
@ -92,7 +93,7 @@ public static class GLU
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void MultiplyMatrices4by4OpenGL_FLOAT(float[] result, float[] matrix1, float[] matrix2)
|
||||
static void MultiplyMatrices4by4OpenGL_FLOAT(Span<float> result, float[] matrix1, float[] matrix2)
|
||||
{
|
||||
result[0] = matrix1[0] * matrix2[0] + matrix1[4] * matrix2[1] + matrix1[8] * matrix2[2] + matrix1[12] * matrix2[3];
|
||||
result[4] = matrix1[0] * matrix2[4] + matrix1[4] * matrix2[5] + matrix1[8] * matrix2[6] + matrix1[12] * matrix2[7];
|
||||
|
@ -115,7 +116,7 @@ public static class GLU
|
|||
result[15] = matrix1[3] * matrix2[12] + matrix1[7] * matrix2[13] + matrix1[11] * matrix2[14] + matrix1[15] * matrix2[15];
|
||||
}
|
||||
|
||||
static void MultiplyMatrixByVector4by4OpenGL_FLOAT(float[] resultvector, float[] matrix, float[] pvector)
|
||||
static void MultiplyMatrixByVector4by4OpenGL_FLOAT(Span<float> resultvector, Span<float> matrix, Span<float> pvector)
|
||||
{
|
||||
resultvector[0] = matrix[0] * pvector[0] + matrix[4] * pvector[1] + matrix[8] * pvector[2] + matrix[12] * pvector[3];
|
||||
resultvector[1] = matrix[1] * pvector[0] + matrix[5] * pvector[1] + matrix[9] * pvector[2] + matrix[13] * pvector[3];
|
||||
|
@ -124,15 +125,13 @@ public static class GLU
|
|||
}
|
||||
|
||||
// This code comes directly from GLU except that it is for float
|
||||
static int GlhInvertMatrixf2(float[] m, float[] @out)
|
||||
static int GlhInvertMatrixf2(Span<float> m, Span<float> @out)
|
||||
{
|
||||
float[][] wtmp = RcArrays.Of<float>(4, 8);
|
||||
float m0, m1, m2, m3, s;
|
||||
float[] r0, r1, r2, r3;
|
||||
r0 = wtmp[0];
|
||||
r1 = wtmp[1];
|
||||
r2 = wtmp[2];
|
||||
r3 = wtmp[3];
|
||||
Span<float> r0 = stackalloc float[8];
|
||||
Span<float> r1 = stackalloc float[8];
|
||||
Span<float> r2 = stackalloc float[8];
|
||||
Span<float> r3 = stackalloc float[8];
|
||||
r0[0] = MAT(m, 0, 0);
|
||||
r0[1] = MAT(m, 0, 1);
|
||||
r0[2] = MAT(m, 0, 2);
|
||||
|
@ -160,27 +159,28 @@ public static class GLU
|
|||
/* choose pivot - or die */
|
||||
if (MathF.Abs(r3[0]) > MathF.Abs(r2[0]))
|
||||
{
|
||||
float[] r = r2;
|
||||
Span<float> r = r2;
|
||||
r2 = r3;
|
||||
r3 = r;
|
||||
}
|
||||
|
||||
if (MathF.Abs(r2[0]) > MathF.Abs(r1[0]))
|
||||
{
|
||||
float[] r = r2;
|
||||
Span<float> r = r2;
|
||||
r2 = r1;
|
||||
r1 = r;
|
||||
}
|
||||
|
||||
if (MathF.Abs(r1[0]) > MathF.Abs(r0[0]))
|
||||
{
|
||||
float[] r = r1;
|
||||
Span<float> r = r1;
|
||||
r1 = r0;
|
||||
r0 = r;
|
||||
}
|
||||
|
||||
if (0.0 == r0[0])
|
||||
return 0;
|
||||
|
||||
/* eliminate first variable */
|
||||
m1 = r1[0] / r0[0];
|
||||
m2 = r2[0] / r0[0];
|
||||
|
@ -232,14 +232,14 @@ public static class GLU
|
|||
/* choose pivot - or die */
|
||||
if (MathF.Abs(r3[1]) > MathF.Abs(r2[1]))
|
||||
{
|
||||
float[] r = r2;
|
||||
Span<float> r = r2;
|
||||
r2 = r3;
|
||||
r3 = r;
|
||||
}
|
||||
|
||||
if (MathF.Abs(r2[1]) > MathF.Abs(r1[1]))
|
||||
{
|
||||
float[] r = r2;
|
||||
Span<float> r = r2;
|
||||
r2 = r1;
|
||||
r1 = r;
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ public static class GLU
|
|||
/* choose pivot - or die */
|
||||
if (MathF.Abs(r3[2]) > MathF.Abs(r2[2]))
|
||||
{
|
||||
float[] r = r2;
|
||||
Span<float> r = r2;
|
||||
r2 = r3;
|
||||
r3 = r;
|
||||
}
|
||||
|
@ -358,12 +358,12 @@ public static class GLU
|
|||
return 1;
|
||||
}
|
||||
|
||||
static float MAT(float[] m, int r, int c)
|
||||
static float MAT(Span<float> m, int r, int c)
|
||||
{
|
||||
return m[(c) * 4 + (r)];
|
||||
}
|
||||
|
||||
static void MAT(float[] m, int r, int c, float v)
|
||||
static void MAT(Span<float> m, int r, int c, float v)
|
||||
{
|
||||
m[(c) * 4 + (r)] = v;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Draw;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Silk.NET.OpenGL;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Draw;
|
||||
|
||||
// TODO use a lot of Memory, 2GB+
|
||||
|
||||
public class ModernOpenGLDraw : IOpenGLDraw
|
||||
{
|
||||
private GL _gl;
|
||||
|
@ -19,8 +20,8 @@ public class ModernOpenGLDraw : IOpenGLDraw
|
|||
private float fogEnd;
|
||||
private bool fogEnabled;
|
||||
private int uniformViewMatrix;
|
||||
private readonly ArrayBuffer<OpenGLVertex> vertices = new();
|
||||
private readonly ArrayBuffer<int> elements = new();
|
||||
private readonly ArrayBuffer<OpenGLVertex> vertices = new(512);
|
||||
private readonly ArrayBuffer<int> elements = new(512);
|
||||
private GLCheckerTexture _texture;
|
||||
private readonly float[] _viewMatrix = new float[16];
|
||||
private readonly float[] _projectionMatrix = new float[16];
|
||||
|
@ -36,36 +37,42 @@ public class ModernOpenGLDraw : IOpenGLDraw
|
|||
|
||||
public unsafe void Init()
|
||||
{
|
||||
string SHADER_VERSION = "#version 400\n";
|
||||
string vertex_shader = SHADER_VERSION + "uniform mat4 ProjMtx;\n" //
|
||||
+ "uniform mat4 ViewMtx;\n" //
|
||||
+ "in vec3 Position;\n" //
|
||||
+ "in vec2 TexCoord;\n" //
|
||||
+ "in vec4 Color;\n" //
|
||||
+ "out vec2 Frag_UV;\n" //
|
||||
+ "out vec4 Frag_Color;\n" //
|
||||
+ "out float Frag_Depth;\n" //
|
||||
+ "void main() {\n" //
|
||||
+ " Frag_UV = TexCoord;\n" //
|
||||
+ " Frag_Color = Color;\n" //
|
||||
+ " vec4 VSPosition = ViewMtx * vec4(Position, 1);\n" //
|
||||
+ " Frag_Depth = -VSPosition.z;\n" //
|
||||
+ " gl_Position = ProjMtx * VSPosition;\n" //
|
||||
+ "}\n";
|
||||
string fragment_shader = SHADER_VERSION + "precision mediump float;\n" //
|
||||
+ "uniform sampler2D Texture;\n" //
|
||||
+ "uniform float UseTexture;\n" //
|
||||
+ "uniform float EnableFog;\n" //
|
||||
+ "uniform float FogStart;\n" //
|
||||
+ "uniform float FogEnd;\n" //
|
||||
+ "const vec4 FogColor = vec4(0.3f, 0.3f, 0.32f, 1.0f);\n" //
|
||||
+ "in vec2 Frag_UV;\n" //
|
||||
+ "in vec4 Frag_Color;\n" //
|
||||
+ "in float Frag_Depth;\n" //
|
||||
+ "out vec4 Out_Color;\n" //
|
||||
+ "void main(){\n" //
|
||||
+ " Out_Color = mix(FogColor, Frag_Color * mix(vec4(1), texture(Texture, Frag_UV.st), UseTexture), 1.0 - EnableFog * clamp( (Frag_Depth - FogStart) / (FogEnd - FogStart), 0.0, 1.0) );\n" //
|
||||
+ "}\n";
|
||||
const string SHADER_VERSION = "#version 400\n";
|
||||
const string vertex_shader = $@"
|
||||
{SHADER_VERSION}
|
||||
uniform mat4 ProjMtx;
|
||||
uniform mat4 ViewMtx;
|
||||
in vec3 Position;
|
||||
in vec2 TexCoord;
|
||||
in vec4 Color;
|
||||
out vec2 Frag_UV;
|
||||
out vec4 Frag_Color;
|
||||
out float Frag_Depth;
|
||||
void main() {{
|
||||
Frag_UV = TexCoord;
|
||||
Frag_Color = Color;
|
||||
vec4 VSPosition = ViewMtx * vec4(Position, 1);
|
||||
Frag_Depth = -VSPosition.z;
|
||||
gl_Position = ProjMtx * VSPosition;
|
||||
}}
|
||||
";
|
||||
const string fragment_shader = $@"
|
||||
{SHADER_VERSION}
|
||||
precision mediump float;
|
||||
uniform sampler2D Texture;
|
||||
uniform float UseTexture;
|
||||
uniform float EnableFog;
|
||||
uniform float FogStart;
|
||||
uniform float FogEnd;
|
||||
const vec4 FogColor = vec4(0.3f, 0.3f, 0.32f, 1.0f);
|
||||
in vec2 Frag_UV;
|
||||
in vec4 Frag_Color;
|
||||
in float Frag_Depth;
|
||||
out vec4 Out_Color;
|
||||
void main(){{
|
||||
Out_Color = mix(FogColor, Frag_Color * mix(vec4(1), texture(Texture, Frag_UV.st), UseTexture), 1.0 - EnableFog * clamp( (Frag_Depth - FogStart) / (FogEnd - FogStart), 0.0, 1.0) );
|
||||
}}
|
||||
";
|
||||
|
||||
program = _gl.CreateProgram();
|
||||
uint vert_shdr = _gl.CreateShader(GLEnum.VertexShader);
|
||||
|
@ -150,6 +157,10 @@ public class ModernOpenGLDraw : IOpenGLDraw
|
|||
_gl.BindVertexArray(0);
|
||||
_gl.BindBuffer(GLEnum.ArrayBuffer, 0);
|
||||
_gl.BindBuffer(GLEnum.ElementArrayBuffer, 0);
|
||||
|
||||
//int* range = stackalloc int[2];
|
||||
//_gl.GetInteger(GetPName.LineWidthRange, range);
|
||||
//Console.WriteLine($"\nLineWidthRange: {range[0]} {range[1]}");
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
@ -191,35 +202,18 @@ public class ModernOpenGLDraw : IOpenGLDraw
|
|||
// GlBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_BUFFER, GL_STREAM_DRAW);
|
||||
// GlBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_BUFFER, GL_STREAM_DRAW);
|
||||
|
||||
uint vboSize = (uint)vertices.Count * 24;
|
||||
uint eboSize = currentPrim == DebugDrawPrimitives.QUADS ? (uint)vertices.Count * 6 : (uint)vertices.Count * 4;
|
||||
|
||||
_gl.BufferData(GLEnum.ArrayBuffer, vboSize, null, GLEnum.StreamDraw);
|
||||
_gl.BufferData(GLEnum.ElementArrayBuffer, eboSize, null, GLEnum.StreamDraw);
|
||||
// load draw vertices & elements directly into vertex + element buffer
|
||||
|
||||
{
|
||||
byte* pVerts = (byte*)_gl.MapBuffer(GLEnum.ArrayBuffer, GLEnum.WriteOnly);
|
||||
byte* pElems = (byte*)_gl.MapBuffer(GLEnum.ElementArrayBuffer, GLEnum.WriteOnly);
|
||||
|
||||
//vertices.ForEach(v => v.Store(verts));
|
||||
fixed (void* v = vertices.AsArray())
|
||||
{
|
||||
System.Buffer.MemoryCopy(v, pVerts, vboSize, vboSize);
|
||||
}
|
||||
_gl.BufferData<OpenGLVertex>(GLEnum.ArrayBuffer, vertices.AsArray(), GLEnum.DynamicDraw);
|
||||
|
||||
if (currentPrim == DebugDrawPrimitives.QUADS)
|
||||
{
|
||||
using var unmanagedElems = new UnmanagedMemoryStream(pElems, eboSize, eboSize, FileAccess.Write);
|
||||
using var bw = new BinaryWriter(unmanagedElems);
|
||||
for (int i = 0; i < vertices.Count; i += 4)
|
||||
{
|
||||
bw.Write(i);
|
||||
bw.Write(i + 1);
|
||||
bw.Write(i + 2);
|
||||
bw.Write(i);
|
||||
bw.Write(i + 2);
|
||||
bw.Write(i + 3);
|
||||
elements.Add(i);
|
||||
elements.Add(i + 1);
|
||||
elements.Add(i + 2);
|
||||
elements.Add(i);
|
||||
elements.Add(i + 2);
|
||||
elements.Add(i + 3);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -228,16 +222,10 @@ public class ModernOpenGLDraw : IOpenGLDraw
|
|||
{
|
||||
elements.Add(i);
|
||||
}
|
||||
|
||||
fixed (void* e = elements.AsArray())
|
||||
{
|
||||
System.Buffer.MemoryCopy(e, pElems, eboSize, eboSize);
|
||||
}
|
||||
}
|
||||
|
||||
_gl.UnmapBuffer(GLEnum.ElementArrayBuffer);
|
||||
_gl.UnmapBuffer(GLEnum.ArrayBuffer);
|
||||
}
|
||||
_gl.BufferData<int>(GLEnum.ElementArrayBuffer, elements.AsArray(), GLEnum.DynamicDraw);
|
||||
|
||||
if (_texture != null)
|
||||
{
|
||||
_texture.Bind();
|
||||
|
@ -271,15 +259,22 @@ public class ModernOpenGLDraw : IOpenGLDraw
|
|||
_gl.BindBuffer(GLEnum.ArrayBuffer, 0);
|
||||
_gl.BindBuffer(GLEnum.ElementArrayBuffer, 0);
|
||||
vertices.Clear();
|
||||
elements.Clear();
|
||||
_gl.LineWidth(1.0f);
|
||||
_gl.PointSize(1.0f);
|
||||
}
|
||||
|
||||
|
||||
public void Vertex(float x, float y, float z, int color)
|
||||
{
|
||||
vertices.Add(new OpenGLVertex(x, y, z, color));
|
||||
}
|
||||
|
||||
public unsafe void Vertex(float* pos, int color)
|
||||
{
|
||||
vertices.Add(new OpenGLVertex(pos[0], pos[1], pos[2], color));
|
||||
}
|
||||
|
||||
public void Vertex(float[] pos, int color)
|
||||
{
|
||||
vertices.Add(new OpenGLVertex(pos, color));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -23,14 +23,14 @@ using DotRecast.Core.Numerics;
|
|||
using DotRecast.Detour;
|
||||
using DotRecast.Recast.Toolset.Builder;
|
||||
using DotRecast.Recast.Toolset.Geom;
|
||||
using static DotRecast.Recast.RcCommons;
|
||||
using static DotRecast.Recast.RcRecast;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Draw;
|
||||
|
||||
public class NavMeshRenderer
|
||||
{
|
||||
private readonly RecastDebugDraw _debugDraw;
|
||||
private readonly int _navMeshDrawFlags = RecastDebugDraw.DRAWNAVMESH_OFFMESHCONS | RecastDebugDraw.DRAWNAVMESH_CLOSEDLIST;
|
||||
private readonly int _navMeshDrawFlags = RecastDebugDraw.DU_DRAWNAVMESH_OFFMESHCONS | RecastDebugDraw.DU_DRAWNAVMESH_CLOSEDLIST;
|
||||
|
||||
public NavMeshRenderer(RecastDebugDraw debugDraw)
|
||||
{
|
||||
|
@ -123,80 +123,80 @@ public class NavMeshRenderer
|
|||
|
||||
foreach (RcBuilderResult rcBuilderResult in rcBuilderResults)
|
||||
{
|
||||
if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT)
|
||||
if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_COMPACT)
|
||||
{
|
||||
_debugDraw.DebugDrawCompactHeightfieldSolid(rcBuilderResult.GetCompactHeightfield());
|
||||
_debugDraw.DebugDrawCompactHeightfieldSolid(rcBuilderResult.CompactHeightfield);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT_DISTANCE)
|
||||
if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_COMPACT_DISTANCE)
|
||||
{
|
||||
_debugDraw.DebugDrawCompactHeightfieldDistance(rcBuilderResult.GetCompactHeightfield());
|
||||
_debugDraw.DebugDrawCompactHeightfieldDistance(rcBuilderResult.CompactHeightfield);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT_REGIONS)
|
||||
if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_COMPACT_REGIONS)
|
||||
{
|
||||
_debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.GetCompactHeightfield());
|
||||
_debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.CompactHeightfield);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.GetSolidHeightfield() != null && drawMode == DrawMode.DRAWMODE_VOXELS)
|
||||
if (rcBuilderResult.SolidHeightfiled != null && drawMode == DrawMode.DRAWMODE_VOXELS)
|
||||
{
|
||||
_debugDraw.Fog(true);
|
||||
_debugDraw.DebugDrawHeightfieldSolid(rcBuilderResult.GetSolidHeightfield());
|
||||
_debugDraw.DebugDrawHeightfieldSolid(rcBuilderResult.SolidHeightfiled);
|
||||
_debugDraw.Fog(false);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.GetSolidHeightfield() != null && drawMode == DrawMode.DRAWMODE_VOXELS_WALKABLE)
|
||||
if (rcBuilderResult.SolidHeightfiled != null && drawMode == DrawMode.DRAWMODE_VOXELS_WALKABLE)
|
||||
{
|
||||
_debugDraw.Fog(true);
|
||||
_debugDraw.DebugDrawHeightfieldWalkable(rcBuilderResult.GetSolidHeightfield());
|
||||
_debugDraw.DebugDrawHeightfieldWalkable(rcBuilderResult.SolidHeightfiled);
|
||||
_debugDraw.Fog(false);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_RAW_CONTOURS)
|
||||
if (rcBuilderResult.ContourSet != null && drawMode == DrawMode.DRAWMODE_RAW_CONTOURS)
|
||||
{
|
||||
_debugDraw.DepthMask(false);
|
||||
_debugDraw.DebugDrawRawContours(rcBuilderResult.GetContourSet(), 1f);
|
||||
_debugDraw.DebugDrawRawContours(rcBuilderResult.ContourSet, 1f);
|
||||
_debugDraw.DepthMask(true);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_BOTH_CONTOURS)
|
||||
if (rcBuilderResult.ContourSet != null && drawMode == DrawMode.DRAWMODE_BOTH_CONTOURS)
|
||||
{
|
||||
_debugDraw.DepthMask(false);
|
||||
_debugDraw.DebugDrawRawContours(rcBuilderResult.GetContourSet(), 0.5f);
|
||||
_debugDraw.DebugDrawContours(rcBuilderResult.GetContourSet());
|
||||
_debugDraw.DebugDrawRawContours(rcBuilderResult.ContourSet, 0.5f);
|
||||
_debugDraw.DebugDrawContours(rcBuilderResult.ContourSet);
|
||||
_debugDraw.DepthMask(true);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_CONTOURS)
|
||||
if (rcBuilderResult.ContourSet != null && drawMode == DrawMode.DRAWMODE_CONTOURS)
|
||||
{
|
||||
_debugDraw.DepthMask(false);
|
||||
_debugDraw.DebugDrawContours(rcBuilderResult.GetContourSet());
|
||||
_debugDraw.DebugDrawContours(rcBuilderResult.ContourSet);
|
||||
_debugDraw.DepthMask(true);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_REGION_CONNECTIONS)
|
||||
if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_REGION_CONNECTIONS)
|
||||
{
|
||||
_debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.GetCompactHeightfield());
|
||||
_debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.CompactHeightfield);
|
||||
_debugDraw.DepthMask(false);
|
||||
if (rcBuilderResult.GetContourSet() != null)
|
||||
if (rcBuilderResult.ContourSet != null)
|
||||
{
|
||||
_debugDraw.DebugDrawRegionConnections(rcBuilderResult.GetContourSet());
|
||||
_debugDraw.DebugDrawRegionConnections(rcBuilderResult.ContourSet);
|
||||
}
|
||||
|
||||
_debugDraw.DepthMask(true);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.GetMesh() != null && drawMode == DrawMode.DRAWMODE_POLYMESH)
|
||||
if (rcBuilderResult.Mesh != null && drawMode == DrawMode.DRAWMODE_POLYMESH)
|
||||
{
|
||||
_debugDraw.DepthMask(false);
|
||||
_debugDraw.DebugDrawPolyMesh(rcBuilderResult.GetMesh());
|
||||
_debugDraw.DebugDrawPolyMesh(rcBuilderResult.Mesh);
|
||||
_debugDraw.DepthMask(true);
|
||||
}
|
||||
|
||||
if (rcBuilderResult.GetMeshDetail() != null && drawMode == DrawMode.DRAWMODE_POLYMESH_DETAIL)
|
||||
if (rcBuilderResult.MeshDetail != null && drawMode == DrawMode.DRAWMODE_POLYMESH_DETAIL)
|
||||
{
|
||||
_debugDraw.DepthMask(false);
|
||||
_debugDraw.DebugDrawPolyMeshDetail(rcBuilderResult.GetMeshDetail());
|
||||
_debugDraw.DebugDrawPolyMeshDetail(rcBuilderResult.MeshDetail);
|
||||
_debugDraw.DepthMask(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -19,7 +19,6 @@ freely, subject to the following restrictions:
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Detour;
|
||||
using DotRecast.Recast.Toolset.Builder;
|
||||
|
@ -27,11 +26,13 @@ using Silk.NET.OpenGL;
|
|||
|
||||
namespace DotRecast.Recast.Demo.Draw;
|
||||
|
||||
using static DtDetour;
|
||||
|
||||
public class RecastDebugDraw : DebugDraw
|
||||
{
|
||||
public static readonly int DRAWNAVMESH_OFFMESHCONS = 0x01;
|
||||
public static readonly int DRAWNAVMESH_CLOSEDLIST = 0x02;
|
||||
public static readonly int DRAWNAVMESH_COLOR_TILES = 0x04;
|
||||
public const int DU_DRAWNAVMESH_OFFMESHCONS = 0x01;
|
||||
public const int DU_DRAWNAVMESH_CLOSEDLIST = 0x02;
|
||||
public const int DU_DRAWNAVMESH_COLOR_TILES = 0x04;
|
||||
|
||||
public RecastDebugDraw(GL gl) : base(gl)
|
||||
{
|
||||
|
@ -101,7 +102,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
|
||||
public void DebugDrawNavMeshWithClosedList(DtNavMesh mesh, DtNavMeshQuery query, int flags)
|
||||
{
|
||||
DtNavMeshQuery q = (flags & DRAWNAVMESH_CLOSEDLIST) != 0 ? query : null;
|
||||
DtNavMeshQuery q = (flags & DU_DRAWNAVMESH_CLOSEDLIST) != 0 ? query : null;
|
||||
for (int i = 0; i < mesh.GetMaxTiles(); ++i)
|
||||
{
|
||||
DtMeshTile tile = mesh.GetTile(i);
|
||||
|
@ -116,7 +117,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
{
|
||||
long @base = mesh.GetPolyRefBase(tile);
|
||||
|
||||
int tileNum = DtNavMesh.DecodePolyIdTile(@base);
|
||||
int tileNum = DecodePolyIdTile(@base);
|
||||
int tileColor = DuIntToCol(tileNum, 128);
|
||||
DepthMask(false);
|
||||
Begin(DebugDrawPrimitives.TRIS);
|
||||
|
@ -135,7 +136,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((flags & DRAWNAVMESH_COLOR_TILES) != 0)
|
||||
if ((flags & DU_DRAWNAVMESH_COLOR_TILES) != 0)
|
||||
{
|
||||
col = tileColor;
|
||||
}
|
||||
|
@ -163,7 +164,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
// Draw outer poly boundaries
|
||||
DrawPolyBoundaries(tile, DuRGBA(0, 48, 64, 220), 2.5f, false);
|
||||
|
||||
if ((flags & DRAWNAVMESH_OFFMESHCONS) != 0)
|
||||
if ((flags & DU_DRAWNAVMESH_OFFMESHCONS) != 0)
|
||||
{
|
||||
Begin(DebugDrawPrimitives.LINES, 2.0f);
|
||||
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
||||
|
@ -198,7 +199,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
// Check to see if start and end end-points have links.
|
||||
bool startSet = false;
|
||||
bool endSet = false;
|
||||
for (int k = tile.polyLinks[p.index]; k != DtNavMesh.DT_NULL_LINK; k = tile.links[k].next)
|
||||
for (int k = p.firstLink; k != DT_NULL_LINK; k = tile.links[k].next)
|
||||
{
|
||||
if (tile.links[k].edge == 0)
|
||||
{
|
||||
|
@ -299,6 +300,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
|
||||
Begin(DebugDrawPrimitives.LINES, linew);
|
||||
|
||||
Span<RcVec3f> tv = stackalloc RcVec3f[3];
|
||||
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
||||
{
|
||||
DtPoly p = tile.data.polys[i];
|
||||
|
@ -318,10 +320,10 @@ public class RecastDebugDraw : DebugDraw
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((p.neis[j] & DtNavMesh.DT_EXT_LINK) != 0)
|
||||
if ((p.neis[j] & DT_EXT_LINK) != 0)
|
||||
{
|
||||
bool con = false;
|
||||
for (int k = tile.polyLinks[p.index]; k != DtNavMesh.DT_NULL_LINK; k = tile.links[k].next)
|
||||
for (int k = p.firstLink; k != DT_NULL_LINK; k = tile.links[k].next)
|
||||
{
|
||||
if (tile.links[k].edge == j)
|
||||
{
|
||||
|
@ -370,14 +372,14 @@ public class RecastDebugDraw : DebugDraw
|
|||
for (int k = 0; k < pd.triCount; ++k)
|
||||
{
|
||||
int t = (pd.triBase + k) * 4;
|
||||
RcVec3f[] tv = new RcVec3f[3];
|
||||
for (int m = 0; m < 3; ++m)
|
||||
{
|
||||
int v = tile.data.detailTris[t + m];
|
||||
if (v < p.vertCount)
|
||||
{
|
||||
tv[m] = new RcVec3f(
|
||||
tile.data.verts[p.verts[v] * 3], tile.data.verts[p.verts[v] * 3 + 1],
|
||||
tile.data.verts[p.verts[v] * 3],
|
||||
tile.data.verts[p.verts[v] * 3 + 1],
|
||||
tile.data.verts[p.verts[v] * 3 + 2]
|
||||
);
|
||||
}
|
||||
|
@ -393,7 +395,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
|
||||
for (int m = 0, n = 2; m < 3; n = m++)
|
||||
{
|
||||
if ((DtNavMesh.GetDetailTriEdgeFlags(tile.data.detailTris[t + 3], n) & DtDetailTriEdgeFlags.DT_DETAIL_EDGE_BOUNDARY) == 0)
|
||||
if ((GetDetailTriEdgeFlags(tile.data.detailTris[t + 3], n) & DtDetailTriEdgeFlags.DT_DETAIL_EDGE_BOUNDARY) == 0)
|
||||
continue;
|
||||
|
||||
if (((tile.data.detailTris[t + 3] >> (n * 2)) & 0x3) == 0)
|
||||
|
@ -463,9 +465,13 @@ public class RecastDebugDraw : DebugDraw
|
|||
continue;
|
||||
}
|
||||
|
||||
AppendBoxWire(tile.data.header.bmin.X + n.bmin[0] * cs, tile.data.header.bmin.Y + n.bmin[1] * cs,
|
||||
tile.data.header.bmin.Z + n.bmin[2] * cs, tile.data.header.bmin.X + n.bmax[0] * cs,
|
||||
tile.data.header.bmin.Y + n.bmax[1] * cs, tile.data.header.bmin.Z + n.bmax[2] * cs,
|
||||
AppendBoxWire(
|
||||
tile.data.header.bmin.X + n.bmin.X * cs,
|
||||
tile.data.header.bmin.Y + n.bmin.Y * cs,
|
||||
tile.data.header.bmin.Z + n.bmin.Z * cs,
|
||||
tile.data.header.bmin.X + n.bmax.X * cs,
|
||||
tile.data.header.bmin.Y + n.bmax.Y * cs,
|
||||
tile.data.header.bmin.Z + n.bmax.Z * cs,
|
||||
DuRGBA(255, 255, 255, 128));
|
||||
}
|
||||
|
||||
|
@ -497,7 +503,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
{
|
||||
color = DuRGBA(0, 192, 255, 64);
|
||||
}
|
||||
else if (area == RcConstants.RC_NULL_AREA)
|
||||
else if (area == RcRecast.RC_NULL_AREA)
|
||||
{
|
||||
color = DuRGBA(0, 0, 0, 64);
|
||||
}
|
||||
|
@ -669,7 +675,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
int v3 = c.rverts[j * 4 + 3];
|
||||
float off = 0;
|
||||
int colv = color;
|
||||
if ((v3 & RcConstants.RC_BORDER_VERTEX) != 0)
|
||||
if ((v3 & RcRecast.RC_BORDER_VERTEX) != 0)
|
||||
{
|
||||
colv = DuRGBA(255, 255, 255, a);
|
||||
off = ch * 2;
|
||||
|
@ -716,7 +722,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
int vb0 = c.verts[j * 4];
|
||||
int vb1 = c.verts[j * 4 + 1];
|
||||
int vb2 = c.verts[j * 4 + 2];
|
||||
int col = (va3 & RcConstants.RC_AREA_BORDER) != 0 ? bcolor : color;
|
||||
int col = (va3 & RcRecast.RC_AREA_BORDER) != 0 ? bcolor : color;
|
||||
|
||||
float fx = orig.X + va0 * cs;
|
||||
float fy = orig.Y + (va1 + 1 + (i & 1)) * ch;
|
||||
|
@ -747,7 +753,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
int v3 = c.verts[j * 4 + 3];
|
||||
float off = 0;
|
||||
int colv = color;
|
||||
if ((v3 & RcConstants.RC_BORDER_VERTEX) != 0)
|
||||
if ((v3 & RcRecast.RC_BORDER_VERTEX) != 0)
|
||||
{
|
||||
colv = DuRGBA(255, 255, 255, a);
|
||||
off = ch * 2;
|
||||
|
@ -827,7 +833,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
{
|
||||
fcol[0] = DuRGBA(64, 128, 160, 255);
|
||||
}
|
||||
else if (s.area == RcConstants.RC_NULL_AREA)
|
||||
else if (s.area == RcRecast.RC_NULL_AREA)
|
||||
{
|
||||
fcol[0] = DuRGBA(64, 64, 64, 255);
|
||||
}
|
||||
|
@ -949,7 +955,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
{
|
||||
color = DuRGBA(0, 192, 255, 64);
|
||||
}
|
||||
else if (area == RcConstants.RC_NULL_AREA)
|
||||
else if (area == RcRecast.RC_NULL_AREA)
|
||||
{
|
||||
color = DuRGBA(0, 0, 0, 64);
|
||||
}
|
||||
|
@ -961,7 +967,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
int[] vi = new int[3];
|
||||
for (int j = 2; j < nvp; ++j)
|
||||
{
|
||||
if (mesh.polys[p + j] == RcConstants.RC_MESH_NULL_IDX)
|
||||
if (mesh.polys[p + j] == RcRecast.RC_MESH_NULL_IDX)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -992,7 +998,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
int p = i * nvp * 2;
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (mesh.polys[p + j] == RcConstants.RC_MESH_NULL_IDX)
|
||||
if (mesh.polys[p + j] == RcRecast.RC_MESH_NULL_IDX)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -1002,7 +1008,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
continue;
|
||||
}
|
||||
|
||||
int nj = (j + 1 >= nvp || mesh.polys[p + j + 1] == RcConstants.RC_MESH_NULL_IDX) ? 0 : j + 1;
|
||||
int nj = (j + 1 >= nvp || mesh.polys[p + j + 1] == RcRecast.RC_MESH_NULL_IDX) ? 0 : j + 1;
|
||||
int[] vi = { mesh.polys[p + j], mesh.polys[p + nj] };
|
||||
|
||||
for (int k = 0; k < 2; ++k)
|
||||
|
@ -1026,7 +1032,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
int p = i * nvp * 2;
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (mesh.polys[p + j] == RcConstants.RC_MESH_NULL_IDX)
|
||||
if (mesh.polys[p + j] == RcRecast.RC_MESH_NULL_IDX)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -1036,7 +1042,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
continue;
|
||||
}
|
||||
|
||||
int nj = (j + 1 >= nvp || mesh.polys[p + j + 1] == RcConstants.RC_MESH_NULL_IDX) ? 0 : j + 1;
|
||||
int nj = (j + 1 >= nvp || mesh.polys[p + j + 1] == RcRecast.RC_MESH_NULL_IDX) ? 0 : j + 1;
|
||||
int[] vi = { mesh.polys[p + j], mesh.polys[p + nj] };
|
||||
|
||||
int col = colb;
|
||||
|
@ -1327,7 +1333,7 @@ public class RecastDebugDraw : DebugDraw
|
|||
|
||||
for (int side = 0; side < 8; ++side)
|
||||
{
|
||||
int m = DtNavMesh.DT_EXT_LINK | (short)side;
|
||||
int m = DT_EXT_LINK | (short)side;
|
||||
|
||||
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using DotRecast.Core;
|
||||
using K4os.Compression.LZ4;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Demo;
|
||||
namespace DotRecast.Recast.Demo;
|
||||
|
||||
public static class KeyModState
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Demo.Messages;
|
||||
namespace DotRecast.Recast.Demo.Messages;
|
||||
|
||||
public class GeomLoadBeganEvent : IRecastDemoMessage
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Demo.Messages;
|
||||
namespace DotRecast.Recast.Demo.Messages;
|
||||
|
||||
public interface IRecastDemoChannel
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Demo.Messages;
|
||||
namespace DotRecast.Recast.Demo.Messages;
|
||||
|
||||
public class IRecastDemoMessage
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Demo.Messages;
|
||||
namespace DotRecast.Recast.Demo.Messages;
|
||||
|
||||
public class NavMeshBuildBeganEvent : IRecastDemoMessage
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Demo.Messages;
|
||||
namespace DotRecast.Recast.Demo.Messages;
|
||||
|
||||
public class NavMeshLoadBeganEvent : IRecastDemoMessage
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Demo.Messages;
|
||||
namespace DotRecast.Recast.Demo.Messages;
|
||||
|
||||
public class NavMeshSaveBeganEvent : IRecastDemoMessage
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Messages;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Recast.Demo.Logging.Sinks;
|
||||
using Serilog;
|
||||
using Serilog.Enrichers;
|
||||
|
||||
namespace DotRecast.Recast.Demo;
|
||||
|
||||
|
@ -10,6 +10,8 @@ public static class Program
|
|||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Thread.CurrentThread.Name ??= "main";
|
||||
|
||||
InitializeWorkingDirectory();
|
||||
InitializeLogger();
|
||||
StartDemo();
|
||||
|
@ -22,7 +24,6 @@ public static class Program
|
|||
.MinimumLevel.Verbose()
|
||||
.Enrich.WithThreadId()
|
||||
.Enrich.WithThreadName()
|
||||
.Enrich.WithProperty(ThreadNameEnricher.ThreadNamePropertyName, "main")
|
||||
.WriteTo.Async(c => c.LogMessageBroker(outputTemplate: format))
|
||||
.WriteTo.Async(c => c.Console(outputTemplate: format))
|
||||
.WriteTo.Async(c => c.File(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -25,6 +25,8 @@ using System.Globalization;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime;
|
||||
using System.Runtime.InteropServices;
|
||||
using DotRecast.Core;
|
||||
using Serilog;
|
||||
using Silk.NET.Input;
|
||||
|
@ -318,7 +320,7 @@ public class RecastDemo : IRecastDemoChannel
|
|||
|
||||
if (null != mesh)
|
||||
{
|
||||
_sample.Update(_sample.GetInputGeom(), ImmutableArray<RcBuilderResult>.Empty, mesh);
|
||||
_sample.Update(_sample.GetInputGeom(), _sample.GetRecastConfig(), ImmutableArray<RcBuilderResult>.Empty, mesh);
|
||||
_toolsetView.SetEnabled(true);
|
||||
}
|
||||
}
|
||||
|
@ -409,9 +411,17 @@ public class RecastDemo : IRecastDemoChannel
|
|||
|
||||
var workingDirectory = Directory.GetCurrentDirectory();
|
||||
Logger.Information($"Working directory - {workingDirectory}");
|
||||
Logger.Information($"ImGui.Net - version({ImGui.GetVersion()}) UI scale({scale}) fontSize({fontSize})");
|
||||
Logger.Information($"Dotnet - {Environment.Version.ToString()} culture({currentCulture.Name})");
|
||||
Logger.Information($"OS Version - {Environment.OSVersion} {bitness}");
|
||||
Logger.Information($"{RuntimeInformation.OSArchitecture} {RuntimeInformation.OSDescription}");
|
||||
Logger.Information($"{RuntimeInformation.ProcessArchitecture} {RuntimeInformation.FrameworkDescription}");
|
||||
Logger.Information($"Dotnet - {Environment.Version.ToString()} culture({currentCulture.Name})");
|
||||
Logger.Information($"Processor Count : {Environment.ProcessorCount}");
|
||||
|
||||
Logger.Information($"Server garbage collection : {(GCSettings.IsServerGC ? "Enabled" : "Disabled")}");
|
||||
Logger.Information($"Current latency mode for garbage collection: {GCSettings.LatencyMode}");
|
||||
Logger.Information("");
|
||||
|
||||
Logger.Information($"ImGui.Net - version({ImGui.GetVersion()}) UI scale({scale}) fontSize({fontSize})");
|
||||
Logger.Information($"{vendor} {rendererGl}");
|
||||
Logger.Information($"gl version({version}) lang version({glslString})");
|
||||
}
|
||||
|
@ -462,7 +472,7 @@ public class RecastDemo : IRecastDemoChannel
|
|||
var settings = _sample.GetSettings();
|
||||
RcVec3f bmin = _sample.GetInputGeom().GetMeshBoundsMin();
|
||||
RcVec3f bmax = _sample.GetInputGeom().GetMeshBoundsMax();
|
||||
RcCommons.CalcGridSize(bmin, bmax, settings.cellSize, out var gw, out var gh);
|
||||
RcRecast.CalcGridSize(bmin, bmax, settings.cellSize, out var gw, out var gh);
|
||||
settingsView.SetVoxels(gw, gh);
|
||||
settingsView.SetTiles(tileNavMeshBuilder.GetTiles(_sample.GetInputGeom(), settings.cellSize, settings.tileSize));
|
||||
settingsView.SetMaxTiles(tileNavMeshBuilder.GetMaxTiles(_sample.GetInputGeom(), settings.cellSize, settings.tileSize));
|
||||
|
@ -537,6 +547,7 @@ public class RecastDemo : IRecastDemoChannel
|
|||
bool hasBound = false;
|
||||
RcVec3f bminN = RcVec3f.Zero;
|
||||
RcVec3f bmaxN = RcVec3f.Zero;
|
||||
|
||||
if (_sample.GetInputGeom() != null)
|
||||
{
|
||||
bminN = _sample.GetInputGeom().GetMeshBoundsMin();
|
||||
|
@ -552,7 +563,7 @@ public class RecastDemo : IRecastDemoChannel
|
|||
{
|
||||
foreach (RcBuilderResult result in _sample.GetRecastResults())
|
||||
{
|
||||
if (result.GetSolidHeightfield() != null)
|
||||
if (result.CompactHeightfield != null)
|
||||
{
|
||||
if (!hasBound)
|
||||
{
|
||||
|
@ -561,15 +572,15 @@ public class RecastDemo : IRecastDemoChannel
|
|||
}
|
||||
|
||||
bminN = new RcVec3f(
|
||||
Math.Min(bminN.X, result.GetSolidHeightfield().bmin.X),
|
||||
Math.Min(bminN.Y, result.GetSolidHeightfield().bmin.Y),
|
||||
Math.Min(bminN.Z, result.GetSolidHeightfield().bmin.Z)
|
||||
Math.Min(bminN.X, result.CompactHeightfield.bmin.X),
|
||||
Math.Min(bminN.Y, result.CompactHeightfield.bmin.Y),
|
||||
Math.Min(bminN.Z, result.CompactHeightfield.bmin.Z)
|
||||
);
|
||||
|
||||
bmaxN = new RcVec3f(
|
||||
Math.Max(bmaxN.X, result.GetSolidHeightfield().bmax.X),
|
||||
Math.Max(bmaxN.Y, result.GetSolidHeightfield().bmax.Y),
|
||||
Math.Max(bmaxN.Z, result.GetSolidHeightfield().bmax.Z)
|
||||
Math.Max(bmaxN.X, result.CompactHeightfield.bmax.X),
|
||||
Math.Max(bmaxN.Y, result.CompactHeightfield.bmax.Y),
|
||||
Math.Max(bmaxN.Z, result.CompactHeightfield.bmax.Z)
|
||||
);
|
||||
|
||||
hasBound = true;
|
||||
|
@ -577,12 +588,15 @@ public class RecastDemo : IRecastDemoChannel
|
|||
}
|
||||
}
|
||||
|
||||
// Reset camera and fog to match the mesh bounds.
|
||||
if (hasBound)
|
||||
{
|
||||
RcVec3f bmin = bminN;
|
||||
RcVec3f bmax = bmaxN;
|
||||
|
||||
camr = (float)(Math.Sqrt(RcMath.Sqr(bmax.X - bmin.X) + RcMath.Sqr(bmax.Y - bmin.Y) + RcMath.Sqr(bmax.Z - bmin.Z)) / 2);
|
||||
camr = (float)(Math.Sqrt(RcMath.Sqr(bmax.X - bmin.X) +
|
||||
RcMath.Sqr(bmax.Y - bmin.Y) +
|
||||
RcMath.Sqr(bmax.Z - bmin.Z)) / 2);
|
||||
cameraPos.X = (bmax.X + bmin.X) / 2 + camr;
|
||||
cameraPos.Y = (bmax.Y + bmin.Y) / 2 + camr;
|
||||
cameraPos.Z = (bmax.Z + bmin.Z) / 2 + camr;
|
||||
|
@ -670,7 +684,7 @@ public class RecastDemo : IRecastDemoChannel
|
|||
{
|
||||
var geom = LoadInputMesh(args.FilePath);
|
||||
|
||||
_sample.Update(geom, ImmutableArray<RcBuilderResult>.Empty, null);
|
||||
_sample.Update(geom, null, ImmutableArray<RcBuilderResult>.Empty, null);
|
||||
}
|
||||
|
||||
private void OnNavMeshBuildBegan(NavMeshBuildBeganEvent args)
|
||||
|
@ -688,14 +702,15 @@ public class RecastDemo : IRecastDemoChannel
|
|||
|
||||
NavMeshBuildResult buildResult;
|
||||
|
||||
var geom = _sample.GetInputGeom();
|
||||
var settings = _sample.GetSettings();
|
||||
if (settings.tiled)
|
||||
{
|
||||
buildResult = tileNavMeshBuilder.Build(_sample.GetInputGeom(), settings);
|
||||
buildResult = tileNavMeshBuilder.Build(geom, settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
buildResult = soloNavMeshBuilder.Build(_sample.GetInputGeom(), settings);
|
||||
buildResult = soloNavMeshBuilder.Build(geom, settings);
|
||||
}
|
||||
|
||||
if (!buildResult.Success)
|
||||
|
@ -704,7 +719,7 @@ public class RecastDemo : IRecastDemoChannel
|
|||
return;
|
||||
}
|
||||
|
||||
_sample.Update(_sample.GetInputGeom(), buildResult.RecastBuilderResults, buildResult.NavMesh);
|
||||
_sample.Update(_sample.GetInputGeom(), buildResult.Cfg, buildResult.RecastBuilderResults, buildResult.NavMesh);
|
||||
_sample.SetChanged(false);
|
||||
settingsView.SetBuildTime((RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond);
|
||||
//settingsUI.SetBuildTelemetry(buildResult.Item1.Select(x => x.GetTelemetry()).ToList());
|
||||
|
@ -713,7 +728,7 @@ public class RecastDemo : IRecastDemoChannel
|
|||
Logger.Information($"build times");
|
||||
Logger.Information($"-----------------------------------------");
|
||||
var telemetries = buildResult.RecastBuilderResults
|
||||
.Select(x => x.GetTelemetry())
|
||||
.Select(x => x.Context)
|
||||
.SelectMany(x => x.ToList())
|
||||
.GroupBy(x => x.Key)
|
||||
.ToImmutableSortedDictionary(x => x.Key, x => x.Sum(y => y.Millis));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,12 +18,9 @@ freely, subject to the following restrictions:
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Detour;
|
||||
using DotRecast.Detour.Crowd;
|
||||
using DotRecast.Recast.Toolset.Builder;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
using DotRecast.Recast.Toolset;
|
||||
using DotRecast.Recast.Toolset.Tools;
|
||||
|
@ -98,6 +95,11 @@ public class CrowdAgentProfilingSampleTool : ISampleTool
|
|||
ImGui.SliderInt("Max Iterations", ref toolCfg.maxIterations, 0, 4000);
|
||||
ImGui.NewLine();
|
||||
|
||||
ImGui.Text("Debug Draw");
|
||||
ImGui.Separator();
|
||||
ImGui.Checkbox("Show Agents", ref toolCfg.showAgents);
|
||||
ImGui.NewLine();
|
||||
|
||||
if (ImGui.Button("Start Crowd Profiling"))
|
||||
{
|
||||
var settings = _sample.GetSettings();
|
||||
|
@ -118,11 +120,11 @@ public class CrowdAgentProfilingSampleTool : ISampleTool
|
|||
ImGui.Text($"{rtt.Key}: {rtt.Micros} us");
|
||||
}
|
||||
|
||||
ImGui.Text($"Sampling Time: {_tool.GetCrowdUpdateSamplingTime()} ms");
|
||||
ImGui.Text($"Current Update Time: {_tool.GetCrowdUpdateTime()} ms");
|
||||
ImGui.Text($"Avg Update Time: {_tool.GetCrowdUpdateAvgTime()} ms");
|
||||
ImGui.Text($"Max Update Time: {_tool.GetCrowdUpdateMaxTime()} ms");
|
||||
ImGui.Text($"Min Update Time: {_tool.GetCrowdUpdateMinTime()} ms");
|
||||
ImGui.Text($"Sampling Time: {_tool.GetCrowdUpdateSamplingTime():0.00} ms");
|
||||
ImGui.Text($"Current Update Time: {_tool.GetCrowdUpdateTime():0.00} ms");
|
||||
ImGui.Text($"Avg Update Time: {_tool.GetCrowdUpdateAvgTime():0.00} ms");
|
||||
ImGui.Text($"Max Update Time: {_tool.GetCrowdUpdateMaxTime():0.00} ms");
|
||||
ImGui.Text($"Min Update Time: {_tool.GetCrowdUpdateMinTime():0.00} ms");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +134,7 @@ public class CrowdAgentProfilingSampleTool : ISampleTool
|
|||
dd.DepthMask(false);
|
||||
|
||||
var crowd = _tool.GetCrowd();
|
||||
if (crowd != null)
|
||||
if (crowd != null && _tool.GetToolConfig().showAgents)
|
||||
{
|
||||
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -234,7 +234,7 @@ public class CrowdSampleTool : ISampleTool
|
|||
dd.Vertex(prev.X, prev.Y + 0.1f, prev.Z, DuRGBA(0, 0, 0, (int)(128 * preva)));
|
||||
dd.Vertex(trail.trail[v], trail.trail[v + 1] + 0.1f, trail.trail[v + 2], DuRGBA(0, 0, 0, (int)(128 * a)));
|
||||
preva = a;
|
||||
prev = RcVecUtils.Create(trail.trail, v);
|
||||
prev = RcVec.Create(trail.trail, v);
|
||||
}
|
||||
|
||||
dd.End();
|
||||
|
@ -251,10 +251,10 @@ public class CrowdSampleTool : ISampleTool
|
|||
|
||||
if (_showCorners)
|
||||
{
|
||||
if (0 < ag.corners.Count)
|
||||
if (0 < ag.ncorners)
|
||||
{
|
||||
dd.Begin(LINES, 2.0f);
|
||||
for (int j = 0; j < ag.corners.Count; ++j)
|
||||
for (int j = 0; j < ag.ncorners; ++j)
|
||||
{
|
||||
RcVec3f va = j == 0 ? pos : ag.corners[j - 1].pos;
|
||||
RcVec3f vb = ag.corners[j].pos;
|
||||
|
@ -262,10 +262,10 @@ public class CrowdSampleTool : ISampleTool
|
|||
dd.Vertex(vb.X, vb.Y + radius, vb.Z, DuRGBA(128, 0, 0, 192));
|
||||
}
|
||||
|
||||
if ((ag.corners[ag.corners.Count - 1].flags
|
||||
if ((ag.corners[ag.ncorners - 1].flags
|
||||
& DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
||||
{
|
||||
RcVec3f v = ag.corners[ag.corners.Count - 1].pos;
|
||||
RcVec3f v = ag.corners[ag.ncorners - 1].pos;
|
||||
dd.Vertex(v.X, v.Y, v.Z, DuRGBA(192, 0, 0, 192));
|
||||
dd.Vertex(v.X, v.Y + radius * 2, v.Z, DuRGBA(192, 0, 0, 192));
|
||||
}
|
||||
|
@ -325,7 +325,7 @@ public class CrowdSampleTool : ISampleTool
|
|||
2.0f);
|
||||
|
||||
dd.Begin(LINES, 2.0f);
|
||||
for (int j = 0; j < ag.neis.Count; ++j)
|
||||
for (int j = 0; j < ag.nneis; ++j)
|
||||
{
|
||||
DtCrowdAgent nei = ag.neis[j].agent;
|
||||
if (nei != null)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -25,6 +25,7 @@ using DotRecast.Core;
|
|||
using DotRecast.Core.Collections;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Detour.Dynamic;
|
||||
using DotRecast.Detour.Dynamic.Io;
|
||||
using DotRecast.Recast.Toolset;
|
||||
using DotRecast.Recast.Toolset.Tools;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
|
@ -91,7 +92,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
var bridgeGeom = DemoInputGeomProvider.LoadFile("bridge.obj");
|
||||
var houseGeom = DemoInputGeomProvider.LoadFile("house.obj");
|
||||
var convexGeom = DemoInputGeomProvider.LoadFile("convex.obj");
|
||||
_tool = new(Random.Shared, bridgeGeom, houseGeom, convexGeom);
|
||||
_tool = new(new RcRand(Random.Shared), bridgeGeom, houseGeom, convexGeom);
|
||||
executor = Task.Factory;
|
||||
}
|
||||
|
||||
|
@ -116,8 +117,17 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
|
||||
if (mode == RcDynamicUpdateToolMode.BUILD)
|
||||
{
|
||||
var loadVoxelPopupStrId = "Load Voxels Popup";
|
||||
const string loadVoxelPopupStrId = "Load Voxels Popup";
|
||||
|
||||
bool isLoadVoxelPopup = true;
|
||||
if (_sample.GetRecastResults() != null && _sample.GetRecastConfig() != null)
|
||||
{
|
||||
if (ImGui.Button("Import Voxels"))
|
||||
{
|
||||
Copy();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.Button("Load Voxels..."))
|
||||
{
|
||||
ImGui.OpenPopup(loadVoxelPopupStrId);
|
||||
|
@ -135,7 +145,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
var saveVoxelPopupStrId = "Save Voxels Popup";
|
||||
const string saveVoxelPopupStrId = "Save Voxels Popup";
|
||||
bool isSaveVoxelPopup = true;
|
||||
|
||||
var dynaMesh = _tool.GetDynamicNavMesh();
|
||||
|
@ -144,7 +154,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
ImGui.Checkbox("Compression", ref compression);
|
||||
if (ImGui.Button("Save Voxels..."))
|
||||
{
|
||||
ImGui.BeginPopup(saveVoxelPopupStrId);
|
||||
ImGui.OpenPopup(saveVoxelPopupStrId);
|
||||
}
|
||||
|
||||
if (ImGui.BeginPopupModal(saveVoxelPopupStrId, ref isSaveVoxelPopup, ImGuiWindowFlags.NoTitleBar))
|
||||
|
@ -152,9 +162,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
var picker = ImFilePicker.GetFilePicker(saveVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels");
|
||||
if (picker.Draw())
|
||||
{
|
||||
if (string.IsNullOrEmpty(picker.SelectedFile))
|
||||
Save(picker.SelectedFile);
|
||||
|
||||
ImFilePicker.RemoveFilePicker(saveVoxelPopupStrId);
|
||||
}
|
||||
|
||||
|
@ -406,12 +414,12 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
long t = RcFrequency.Ticks;
|
||||
try
|
||||
{
|
||||
bool updated = _tool.UpdateDynaMesh(executor);
|
||||
bool updated = _tool.Update(executor);
|
||||
if (updated)
|
||||
{
|
||||
buildTime = (RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond;
|
||||
var dynaMesh = _tool.GetDynamicNavMesh();
|
||||
_sample.Update(null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
|
||||
_sample.Update(null, null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
|
||||
_sample.SetChanged(false);
|
||||
}
|
||||
}
|
||||
|
@ -421,6 +429,15 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
}
|
||||
}
|
||||
|
||||
private void Copy()
|
||||
{
|
||||
if (_sample.GetRecastResults() != null && _sample.GetRecastConfig() != null)
|
||||
{
|
||||
var dynaMesh = _tool.Copy(_sample.GetRecastConfig(), _sample.GetRecastResults());
|
||||
UpdateFrom(dynaMesh.config);
|
||||
BuildDynaMesh();
|
||||
}
|
||||
}
|
||||
|
||||
private void Load(string filename)
|
||||
{
|
||||
|
@ -450,7 +467,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
long t = RcFrequency.Ticks;
|
||||
try
|
||||
{
|
||||
var _ = dynaMesh.Build(executor).Result;
|
||||
var _ = dynaMesh.Build(executor);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -458,7 +475,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
}
|
||||
|
||||
buildTime = (RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond;
|
||||
_sample.Update(null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
|
||||
_sample.Update(null, null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
|
||||
}
|
||||
|
||||
private void UpdateTo(DtDynamicNavMeshConfig config)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using DotRecast.Core.Collections;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
|
@ -36,16 +36,11 @@ public static class GizmoRenderer
|
|||
}
|
||||
}
|
||||
|
||||
public static int GetColorByNormal(float[] vertices, int v0, int v1, int v2)
|
||||
public static int GetColorByNormal(RcVec3f v0, RcVec3f v1, RcVec3f v2)
|
||||
{
|
||||
RcVec3f e0 = new RcVec3f();
|
||||
RcVec3f e1 = new RcVec3f();
|
||||
RcVec3f normal = new RcVec3f();
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
e0 = RcVecUtils.Subtract(vertices, v1, v0);
|
||||
e1 = RcVecUtils.Subtract(vertices, v2, v0);
|
||||
}
|
||||
RcVec3f e0 = v1 - v0;
|
||||
RcVec3f e1 = v2 - v0;
|
||||
|
||||
normal.X = e0.Y * e1.Z - e0.Z * e1.Y;
|
||||
normal.Y = e0.Z * e1.X - e0.X * e1.Z;
|
||||
|
@ -65,7 +60,7 @@ public static class GizmoRenderer
|
|||
var trX = new RcVec3f(box.halfEdges[0].X, box.halfEdges[1].X, box.halfEdges[2].X);
|
||||
var trY = new RcVec3f(box.halfEdges[0].Y, box.halfEdges[1].Y, box.halfEdges[2].Y);
|
||||
var trZ = new RcVec3f(box.halfEdges[0].Z, box.halfEdges[1].Z, box.halfEdges[2].Z);
|
||||
float[] vertices = new float[8 * 3];
|
||||
Span<float> vertices = stackalloc float[8 * 3];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
vertices[i * 3 + 0] = RcVec3f.Dot(RcBoxGizmo.VERTS[i], trX) + box.center.X;
|
||||
|
@ -160,13 +155,13 @@ public static class GizmoRenderer
|
|||
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);
|
||||
RcVec3f v0 = RcVec.Create(trimesh.vertices, 3 * trimesh.triangles[i]);
|
||||
RcVec3f v1 = RcVec.Create(trimesh.vertices, 3 * trimesh.triangles[i + 1]);
|
||||
RcVec3f v2 = RcVec.Create(trimesh.vertices, 3 * trimesh.triangles[i + 2]);
|
||||
int col = GetColorByNormal(v0, v1, v2);
|
||||
debugDraw.Vertex(v0.X, v0.Y, v0.Z, col);
|
||||
debugDraw.Vertex(v1.X, v1.Y, v1.Z, col);
|
||||
debugDraw.Vertex(v2.X, v2.Y, v2.Z, col);
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -16,6 +16,7 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System.Linq;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Detour.Extras.Jumplink;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
|
@ -96,13 +97,25 @@ public class JumpLinkBuilderSampleTool : ISampleTool
|
|||
|
||||
if (build || _cfg.buildOffMeshConnections)
|
||||
{
|
||||
if (0 < _sample.GetRecastResults().Count)
|
||||
do
|
||||
{
|
||||
if (0 >= _sample.GetRecastResults().Count)
|
||||
{
|
||||
Logger.Error("build navmesh");
|
||||
break;
|
||||
}
|
||||
|
||||
if (_sample.GetRecastResults().Any(x => null == x.SolidHeightfiled))
|
||||
{
|
||||
Logger.Error("Tick 'Keep Itermediate Results' option");
|
||||
break;
|
||||
}
|
||||
|
||||
var geom = _sample.GetInputGeom();
|
||||
var settings = _sample.GetSettings();
|
||||
|
||||
_tool.Build(geom, settings, _sample.GetRecastResults(), _cfg);
|
||||
}
|
||||
} while (false);
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
|
@ -404,7 +417,7 @@ public class JumpLinkBuilderSampleTool : ISampleTool
|
|||
}
|
||||
|
||||
|
||||
private void DrawTrajectory(RecastDebugDraw dd, JumpLink link, RcVec3f pa, RcVec3f pb, Trajectory tra, int cola)
|
||||
private void DrawTrajectory(RecastDebugDraw dd, JumpLink link, RcVec3f pa, RcVec3f pb, ITrajectory tra, int cola)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Detour.TileCache;
|
||||
using DotRecast.Detour.TileCache.Io.Compress;
|
||||
|
@ -32,7 +32,7 @@ public class ObstacleSampleTool : ISampleTool
|
|||
var buildResult = _tool.Build(geom, settings, RcByteOrder.LITTLE_ENDIAN, true);
|
||||
if (buildResult.Success)
|
||||
{
|
||||
_sample.Update(_sample.GetInputGeom(), buildResult.RecastBuilderResults, buildResult.NavMesh);
|
||||
_sample.Update(_sample.GetInputGeom(), buildResult.Cfg, buildResult.RecastBuilderResults, buildResult.NavMesh);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -57,7 +57,8 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
private bool m_hitResult;
|
||||
|
||||
private float m_distanceToWall;
|
||||
private List<DtStraightPath> m_straightPath;
|
||||
private DtStraightPath[] m_straightPath;
|
||||
private int m_straightPathCount;
|
||||
private List<long> m_polys;
|
||||
private List<long> m_parent;
|
||||
private float m_neighbourhoodRadius;
|
||||
|
@ -77,6 +78,8 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED,
|
||||
new float[] { 1f, 1f, 1f, 1f, 2f, 1.5f }
|
||||
);
|
||||
m_straightPath = new DtStraightPath[MAX_POLYS];
|
||||
m_straightPathCount = 0;
|
||||
}
|
||||
|
||||
public void Layout()
|
||||
|
@ -137,22 +140,22 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
ImGui.Text("Common");
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.Text("Include Flags");
|
||||
ImGui.Text("+ Include Flags");
|
||||
ImGui.Separator();
|
||||
ImGui.CheckboxFlags("Walk", ref _includeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_WALK);
|
||||
ImGui.CheckboxFlags("Swim", ref _includeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_SWIM);
|
||||
ImGui.CheckboxFlags("Door", ref _includeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_DOOR);
|
||||
ImGui.CheckboxFlags("Jump", ref _includeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP);
|
||||
ImGui.CheckboxFlags("+ Walk", ref _includeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_WALK);
|
||||
ImGui.CheckboxFlags("+ Swim", ref _includeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_SWIM);
|
||||
ImGui.CheckboxFlags("+ Door", ref _includeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_DOOR);
|
||||
ImGui.CheckboxFlags("+ Jump", ref _includeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP);
|
||||
ImGui.NewLine();
|
||||
|
||||
m_filter.SetIncludeFlags(_includeFlags);
|
||||
|
||||
ImGui.Text("Exclude Flags");
|
||||
ImGui.Text("- Exclude Flags");
|
||||
ImGui.Separator();
|
||||
ImGui.CheckboxFlags("Walk", ref _excludeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_WALK);
|
||||
ImGui.CheckboxFlags("Swim", ref _excludeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_SWIM);
|
||||
ImGui.CheckboxFlags("Door", ref _excludeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_DOOR);
|
||||
ImGui.CheckboxFlags("Jump", ref _excludeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP);
|
||||
ImGui.CheckboxFlags("- Walk", ref _excludeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_WALK);
|
||||
ImGui.CheckboxFlags("- Swim", ref _excludeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_SWIM);
|
||||
ImGui.CheckboxFlags("- Door", ref _excludeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_DOOR);
|
||||
ImGui.CheckboxFlags("- Jump", ref _excludeFlags, SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP);
|
||||
ImGui.NewLine();
|
||||
|
||||
m_filter.SetExcludeFlags(_excludeFlags);
|
||||
|
@ -284,7 +287,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
int spathCol = DuRGBA(64, 16, 0, 220);
|
||||
int offMeshCol = DuRGBA(128, 96, 0, 220);
|
||||
dd.Begin(LINES, 2.0f);
|
||||
for (int i = 0; i < m_straightPath.Count - 1; ++i)
|
||||
for (int i = 0; i < m_straightPathCount - 1; ++i)
|
||||
{
|
||||
DtStraightPath straightPathItem = m_straightPath[i];
|
||||
DtStraightPath straightPathItem2 = m_straightPath[i + 1];
|
||||
|
@ -304,7 +307,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
|
||||
dd.End();
|
||||
dd.Begin(POINTS, 6.0f);
|
||||
for (int i = 0; i < m_straightPath.Count; ++i)
|
||||
for (int i = 0; i < m_straightPathCount; ++i)
|
||||
{
|
||||
DtStraightPath straightPathItem = m_straightPath[i];
|
||||
int col;
|
||||
|
@ -349,7 +352,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
dd.DepthMask(false);
|
||||
int spathCol = m_hitResult ? DuRGBA(64, 16, 0, 220) : DuRGBA(240, 240, 240, 220);
|
||||
dd.Begin(LINES, 2.0f);
|
||||
for (int i = 0; i < m_straightPath.Count - 1; ++i)
|
||||
for (int i = 0; i < m_straightPathCount - 1; ++i)
|
||||
{
|
||||
DtStraightPath straightPathItem = m_straightPath[i];
|
||||
DtStraightPath straightPathItem2 = m_straightPath[i + 1];
|
||||
|
@ -359,7 +362,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
|
||||
dd.End();
|
||||
dd.Begin(POINTS, 4.0f);
|
||||
for (int i = 0; i < m_straightPath.Count; ++i)
|
||||
for (int i = 0; i < m_straightPathCount; ++i)
|
||||
{
|
||||
DtStraightPath straightPathItem = m_straightPath[i];
|
||||
dd.Vertex(straightPathItem.pos.X, straightPathItem.pos.Y + 0.4f, straightPathItem.pos.Z, spathCol);
|
||||
|
@ -469,8 +472,9 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
{
|
||||
if (m_polys != null)
|
||||
{
|
||||
var segmentVerts = new List<RcSegmentVert>();
|
||||
var segmentRefs = new List<long>();
|
||||
const int MAX_SEGS = DtDetour.DT_VERTS_PER_POLYGON * 4;
|
||||
Span<RcSegmentVert> segs = stackalloc RcSegmentVert[MAX_SEGS];
|
||||
Span<long> refs = stackalloc long[MAX_SEGS];
|
||||
|
||||
for (int i = 0; i < m_polys.Count; i++)
|
||||
{
|
||||
|
@ -488,18 +492,20 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
dd.DepthMask(true);
|
||||
if (_sample.GetNavMeshQuery() != null)
|
||||
{
|
||||
int nsegs = 0;
|
||||
var result = _sample
|
||||
.GetNavMeshQuery()
|
||||
.GetPolyWallSegments(m_polys[i], false, m_filter, ref segmentVerts, ref segmentRefs);
|
||||
.GetPolyWallSegments(m_polys[i], m_filter, segs, refs, ref nsegs, MAX_SEGS);
|
||||
|
||||
if (result.Succeeded())
|
||||
{
|
||||
dd.Begin(LINES, 2.0f);
|
||||
for (int j = 0; j < segmentVerts.Count; ++j)
|
||||
for (int j = 0; j < nsegs; ++j)
|
||||
{
|
||||
RcSegmentVert s = segmentVerts[j];
|
||||
ref RcSegmentVert s = ref segs[j];
|
||||
var v0 = s.vmin;
|
||||
var s3 = s.vmax;
|
||||
|
||||
// Skip too distant segments.
|
||||
var distSqr = DtUtils.DistancePtSegSqr2D(m_spos, v0, s3, out var tseg);
|
||||
if (distSqr > RcMath.Sqr(m_neighbourhoodRadius))
|
||||
|
@ -508,12 +514,13 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
}
|
||||
|
||||
RcVec3f delta = RcVec3f.Subtract(s3, s.vmin);
|
||||
RcVec3f p0 = RcVecUtils.Mad(s.vmin, delta, 0.5f);
|
||||
RcVec3f p0 = RcVec.Mad(s.vmin, delta, 0.5f);
|
||||
RcVec3f norm = new RcVec3f(delta.Z, 0, -delta.X);
|
||||
norm = RcVec3f.Normalize(norm);
|
||||
RcVec3f p1 = RcVecUtils.Mad(p0, norm, agentRadius * 0.5f);
|
||||
RcVec3f p1 = RcVec.Mad(p0, norm, agentRadius * 0.5f);
|
||||
|
||||
// Skip backfacing segments.
|
||||
if (segmentRefs[j] != 0)
|
||||
if (refs[j] != 0)
|
||||
{
|
||||
int col = DuRGBA(255, 255, 255, 32);
|
||||
dd.Vertex(s.vmin.X, s.vmin.Y + agentClimb, s.vmin.Z, col);
|
||||
|
@ -661,23 +668,23 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
if (_mode == RcTestNavmeshToolMode.PATHFIND_FOLLOW)
|
||||
{
|
||||
_tool.FindFollowPath(navMesh, navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _enableRaycast,
|
||||
ref m_polys, ref m_smoothPath);
|
||||
ref m_polys, m_polys?.Count ?? 0, ref m_smoothPath);
|
||||
}
|
||||
else if (_mode == RcTestNavmeshToolMode.PATHFIND_STRAIGHT)
|
||||
{
|
||||
_tool.FindStraightPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _enableRaycast,
|
||||
ref m_polys, ref m_straightPath, _straightPathOption);
|
||||
ref m_polys, m_straightPath, out m_straightPathCount, MAX_POLYS, _straightPathOption);
|
||||
}
|
||||
else if (_mode == RcTestNavmeshToolMode.PATHFIND_SLICED)
|
||||
{
|
||||
m_polys?.Clear();
|
||||
m_straightPath?.Clear();
|
||||
m_straightPathCount = 0;
|
||||
m_pathFindStatus = _tool.InitSlicedFindPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _enableRaycast);
|
||||
}
|
||||
else if (_mode == RcTestNavmeshToolMode.RAYCAST)
|
||||
{
|
||||
_tool.Raycast(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter,
|
||||
ref m_polys, ref m_straightPath, ref m_hitPos, ref m_hitNormal, ref m_hitResult);
|
||||
ref m_polys, m_straightPath, out m_straightPathCount, MAX_POLYS, ref m_hitPos, ref m_hitNormal, ref m_hitResult);
|
||||
}
|
||||
else if (_mode == RcTestNavmeshToolMode.DISTANCE_TO_WALL)
|
||||
{
|
||||
|
@ -712,7 +719,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
|
||||
if (m_pathFindStatus.InProgress())
|
||||
{
|
||||
m_pathFindStatus = _tool.UpdateSlicedFindPath(navQuery, 1, m_endRef, m_spos, m_epos, ref m_polys, ref m_straightPath);
|
||||
m_pathFindStatus = _tool.UpdateSlicedFindPath(navQuery, 1, m_endRef, m_spos, m_epos, ref m_polys, m_straightPath, out m_straightPathCount, MAX_POLYS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
using DotRecast.Recast.Toolset;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
|
@ -69,7 +69,7 @@ public class ImFilePicker
|
|||
ImGui.Text("Current Folder: " + CurrentFolder);
|
||||
bool result = false;
|
||||
|
||||
if (ImGui.BeginChildFrame(1, new Vector2(1024, 400)))
|
||||
if (ImGui.BeginChild(1, new Vector2(1024, 400)))
|
||||
{
|
||||
var di = new DirectoryInfo(CurrentFolder);
|
||||
if (di.Exists)
|
||||
|
@ -111,7 +111,7 @@ public class ImFilePicker
|
|||
}
|
||||
}
|
||||
|
||||
ImGui.EndChildFrame();
|
||||
ImGui.EndChild();
|
||||
|
||||
|
||||
if (ImGui.Button("Cancel"))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -80,7 +80,7 @@ public class RcLogView : IRcView
|
|||
}
|
||||
|
||||
|
||||
if (ImGui.BeginChild("scrolling", Vector2.Zero, false, ImGuiWindowFlags.HorizontalScrollbar))
|
||||
if (ImGui.BeginChild("scrolling", Vector2.Zero, ImGuiChildFlags.None, ImGuiWindowFlags.HorizontalScrollbar))
|
||||
{
|
||||
_isHovered = ImGui.IsWindowHovered(ImGuiHoveredFlags.RectOnly | ImGuiHoveredFlags.RootAndChildWindows);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Core;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace DotRecast.Recast.Demo.UI;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -166,6 +167,10 @@ public class RcSettingsView : IRcView
|
|||
ImGui.SliderFloat("Max Sample Error", ref settings.detailSampleMaxError, 0f, 16f, "%.1f");
|
||||
ImGui.NewLine();
|
||||
|
||||
ImGui.Checkbox("Keep Itermediate Results", ref settings.keepInterResults);
|
||||
ImGui.Checkbox("Build All Tiles", ref settings.buildAll);
|
||||
ImGui.NewLine();
|
||||
|
||||
ImGui.Text("Tiling");
|
||||
ImGui.Separator();
|
||||
ImGui.Checkbox("Enable", ref settings.tiled);
|
||||
|
@ -228,6 +233,12 @@ public class RcSettingsView : IRcView
|
|||
DrawMode.Values.ForEach(dm => { ImGui.RadioButton(dm.Text, ref drawMode, dm.Idx); });
|
||||
ImGui.NewLine();
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Text("Tick 'Keep Itermediate Results'");
|
||||
ImGui.Text("rebuild some tiles to see");
|
||||
ImGui.Text("more debug mode options.");
|
||||
ImGui.NewLine();
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Demo.UI.ViewModels;
|
||||
namespace DotRecast.Recast.Demo.UI.ViewModels;
|
||||
|
||||
public class LogMessageItem
|
||||
{
|
||||
|
|
|
@ -10,8 +10,8 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb,
|
||||
RcBuilderResult rcResult)
|
||||
{
|
||||
RcPolyMesh pmesh = rcResult.GetMesh();
|
||||
RcPolyMeshDetail dmesh = rcResult.GetMeshDetail();
|
||||
RcPolyMesh pmesh = rcResult.Mesh;
|
||||
RcPolyMeshDetail dmesh = rcResult.MeshDetail;
|
||||
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
|
||||
for (int i = 0; i < pmesh.npolys; ++i)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Detour;
|
||||
|
||||
|
@ -7,6 +7,7 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
public class NavMeshBuildResult
|
||||
{
|
||||
public readonly bool Success;
|
||||
public readonly RcConfig Cfg;
|
||||
public readonly IList<RcBuilderResult> RecastBuilderResults;
|
||||
public readonly DtNavMesh NavMesh;
|
||||
|
||||
|
@ -17,11 +18,22 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
NavMesh = null;
|
||||
}
|
||||
|
||||
public NavMeshBuildResult(IList<RcBuilderResult> recastBuilderResults, DtNavMesh navMesh)
|
||||
// for solo
|
||||
public NavMeshBuildResult(RcConfig cfg, IList<RcBuilderResult> recastBuilderResults, DtNavMesh navMesh)
|
||||
{
|
||||
Success = true;
|
||||
Cfg = cfg;
|
||||
RecastBuilderResults = recastBuilderResults;
|
||||
NavMesh = navMesh;
|
||||
}
|
||||
|
||||
// for tiles
|
||||
public NavMeshBuildResult(RcConfig cfg, IList<RcBuilderResult> recastBuilderResults)
|
||||
{
|
||||
Success = true;
|
||||
Cfg = cfg;
|
||||
RecastBuilderResults = recastBuilderResults;
|
||||
NavMesh = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -34,12 +34,12 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
public const int SAMPLE_POLYAREA_TYPE_JUMP_AUTO = 0x6;
|
||||
public const int SAMPLE_POLYAREA_TYPE_WALKABLE = 0x3f;
|
||||
|
||||
public static readonly int SAMPLE_POLYFLAGS_WALK = 0x01; // Ability to walk (ground, grass, road)
|
||||
public static readonly int SAMPLE_POLYFLAGS_SWIM = 0x02; // Ability to swim (water).
|
||||
public static readonly int SAMPLE_POLYFLAGS_DOOR = 0x04; // Ability to move through doors.
|
||||
public static readonly int SAMPLE_POLYFLAGS_JUMP = 0x08; // Ability to jump.
|
||||
public static readonly int SAMPLE_POLYFLAGS_DISABLED = 0x10; // Disabled polygon
|
||||
public static readonly int SAMPLE_POLYFLAGS_ALL = 0xffff; // All abilities.
|
||||
public const int SAMPLE_POLYFLAGS_WALK = 0x01; // Ability to walk (ground, grass, road)
|
||||
public const int SAMPLE_POLYFLAGS_SWIM = 0x02; // Ability to swim (water).
|
||||
public const int SAMPLE_POLYFLAGS_DOOR = 0x04; // Ability to move through doors.
|
||||
public const int SAMPLE_POLYFLAGS_JUMP = 0x08; // Ability to jump.
|
||||
public const int SAMPLE_POLYFLAGS_DISABLED = 0x10; // Disabled polygon
|
||||
public const int SAMPLE_POLYFLAGS_ALL = 0xffff; // All abilities.
|
||||
|
||||
public static readonly RcAreaModification SAMPLE_AREAMOD_WALKABLE = new RcAreaModification(SAMPLE_POLYAREA_TYPE_WALKABLE);
|
||||
public static readonly RcAreaModification SAMPLE_AREAMOD_GROUND = new RcAreaModification(SAMPLE_POLYAREA_TYPE_GROUND);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -34,7 +35,8 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
settings.edgeMaxLen, settings.edgeMaxError,
|
||||
settings.vertsPerPoly,
|
||||
settings.detailSampleDist, settings.detailSampleMaxError,
|
||||
settings.filterLowHangingObstacles, settings.filterLedgeSpans, settings.filterWalkableLowHeightSpans);
|
||||
settings.filterLowHangingObstacles, settings.filterLedgeSpans, settings.filterWalkableLowHeightSpans,
|
||||
settings.keepInterResults);
|
||||
}
|
||||
|
||||
public NavMeshBuildResult Build(DemoInputGeomProvider geom,
|
||||
|
@ -45,7 +47,8 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
float edgeMaxLen, float edgeMaxError,
|
||||
int vertsPerPoly,
|
||||
float detailSampleDist, float detailSampleMaxError,
|
||||
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans)
|
||||
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans,
|
||||
bool keepInterResults)
|
||||
{
|
||||
RcConfig cfg = new RcConfig(
|
||||
partitionType,
|
||||
|
@ -58,7 +61,7 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
|
||||
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
|
||||
|
||||
RcBuilderResult rcResult = BuildRecastResult(geom, cfg);
|
||||
RcBuilderResult rcResult = BuildRecastResult(geom, cfg, keepInterResults);
|
||||
var meshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, rcResult);
|
||||
if (null == meshData)
|
||||
{
|
||||
|
@ -66,19 +69,26 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
}
|
||||
|
||||
var navMesh = BuildNavMesh(meshData, vertsPerPoly);
|
||||
return new NavMeshBuildResult(RcImmutableArray.Create(rcResult), navMesh);
|
||||
return new NavMeshBuildResult(cfg, RcImmutableArray.Create(rcResult), navMesh);
|
||||
}
|
||||
|
||||
private DtNavMesh BuildNavMesh(DtMeshData meshData, int vertsPerPoly)
|
||||
{
|
||||
return new DtNavMesh(meshData, vertsPerPoly, 0);
|
||||
var mesh = new DtNavMesh();
|
||||
var status = mesh.Init(meshData, vertsPerPoly, 0);
|
||||
if (status.Failed())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private RcBuilderResult BuildRecastResult(DemoInputGeomProvider geom, RcConfig cfg)
|
||||
return mesh;
|
||||
}
|
||||
|
||||
private RcBuilderResult BuildRecastResult(DemoInputGeomProvider geom, RcConfig cfg, bool keepInterResults)
|
||||
{
|
||||
RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
|
||||
RcBuilder rcBuilder = new RcBuilder();
|
||||
return rcBuilder.Build(geom, bcfg);
|
||||
return rcBuilder.Build(geom, bcfg, keepInterResults);
|
||||
}
|
||||
|
||||
public DtMeshData BuildMeshData(DemoInputGeomProvider geom,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -41,7 +42,8 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
settings.minRegionSize, settings.mergedRegionSize,
|
||||
settings.edgeMaxLen, settings.edgeMaxError,
|
||||
settings.vertsPerPoly, settings.detailSampleDist, settings.detailSampleMaxError,
|
||||
settings.filterLowHangingObstacles, settings.filterLedgeSpans, settings.filterWalkableLowHeightSpans);
|
||||
settings.filterLowHangingObstacles, settings.filterLedgeSpans, settings.filterWalkableLowHeightSpans,
|
||||
settings.keepInterResults, settings.buildAll);
|
||||
}
|
||||
|
||||
public NavMeshBuildResult Build(IInputGeomProvider geom,
|
||||
|
@ -53,9 +55,10 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
float edgeMaxLen, float edgeMaxError,
|
||||
int vertsPerPoly,
|
||||
float detailSampleDist, float detailSampleMaxError,
|
||||
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans)
|
||||
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans,
|
||||
bool keepInterResults, bool buildAll)
|
||||
{
|
||||
List<RcBuilderResult> results = BuildRecastResult(
|
||||
NavMeshBuildResult result = BuildRecastResult(
|
||||
geom,
|
||||
tileSize,
|
||||
partitionType,
|
||||
|
@ -65,15 +68,16 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
edgeMaxLen, edgeMaxError,
|
||||
vertsPerPoly,
|
||||
detailSampleDist, detailSampleMaxError,
|
||||
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans
|
||||
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
|
||||
keepInterResults, buildAll
|
||||
);
|
||||
|
||||
var tileMeshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, results);
|
||||
var tileMeshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result.RecastBuilderResults);
|
||||
var tileNavMesh = BuildNavMesh(geom, tileMeshData, cellSize, tileSize, vertsPerPoly);
|
||||
return new NavMeshBuildResult(results, tileNavMesh);
|
||||
return new NavMeshBuildResult(result.Cfg, result.RecastBuilderResults, tileNavMesh);
|
||||
}
|
||||
|
||||
public List<RcBuilderResult> BuildRecastResult(IInputGeomProvider geom,
|
||||
public NavMeshBuildResult BuildRecastResult(IInputGeomProvider geom,
|
||||
int tileSize,
|
||||
RcPartition partitionType,
|
||||
float cellSize, float cellHeight,
|
||||
|
@ -82,7 +86,8 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
float edgeMaxLen, float edgeMaxError,
|
||||
int vertsPerPoly,
|
||||
float detailSampleDist, float detailSampleMaxError,
|
||||
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans)
|
||||
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans,
|
||||
bool keepInterResults, bool buildAll)
|
||||
|
||||
{
|
||||
RcConfig cfg = new RcConfig(true, tileSize, tileSize,
|
||||
|
@ -97,7 +102,8 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
|
||||
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
|
||||
RcBuilder rcBuilder = new RcBuilder();
|
||||
return rcBuilder.BuildTiles(geom, cfg, Task.Factory);
|
||||
var results = rcBuilder.BuildTiles(geom, cfg, keepInterResults, buildAll, Environment.ProcessorCount + 1, Task.Factory);
|
||||
return new NavMeshBuildResult(cfg, results);
|
||||
}
|
||||
|
||||
public DtNavMesh BuildNavMesh(IInputGeomProvider geom, List<DtMeshData> meshData, float cellSize, int tileSize, int vertsPerPoly)
|
||||
|
@ -111,8 +117,9 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
|
||||
navMeshParams.maxTiles = GetMaxTiles(geom, cellSize, tileSize);
|
||||
navMeshParams.maxPolys = GetMaxPolysPerTile(geom, cellSize, tileSize);
|
||||
DtNavMesh navMesh = new DtNavMesh(navMeshParams, vertsPerPoly);
|
||||
meshData.ForEach(md => navMesh.AddTile(md, 0, 0));
|
||||
DtNavMesh navMesh = new DtNavMesh();
|
||||
navMesh.Init(navMeshParams, vertsPerPoly);
|
||||
meshData.ForEach(md => navMesh.AddTile(md, 0, 0, out _));
|
||||
return navMesh;
|
||||
}
|
||||
|
||||
|
@ -123,10 +130,9 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
List<DtMeshData> meshData = new List<DtMeshData>();
|
||||
foreach (RcBuilderResult result in results)
|
||||
{
|
||||
int x = result.tileX;
|
||||
int z = result.tileZ;
|
||||
DtNavMeshCreateParams option = DemoNavMeshBuilder
|
||||
.GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result);
|
||||
int x = result.TileX;
|
||||
int z = result.TileZ;
|
||||
DtNavMeshCreateParams option = DemoNavMeshBuilder.GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result);
|
||||
|
||||
option.tileX = x;
|
||||
option.tileZ = z;
|
||||
|
@ -155,7 +161,7 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
|
||||
private int GetTileBits(IInputGeomProvider geom, float cellSize, int tileSize)
|
||||
{
|
||||
RcCommons.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh);
|
||||
RcRecast.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh);
|
||||
int tw = (gw + tileSize - 1) / tileSize;
|
||||
int th = (gh + tileSize - 1) / tileSize;
|
||||
int tileBits = Math.Min(DtUtils.Ilog2(DtUtils.NextPow2(tw * th)), 14);
|
||||
|
@ -164,7 +170,7 @@ namespace DotRecast.Recast.Toolset.Builder
|
|||
|
||||
public int[] GetTiles(DemoInputGeomProvider geom, float cellSize, int tileSize)
|
||||
{
|
||||
RcCommons.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh);
|
||||
RcRecast.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh);
|
||||
int tw = (gw + tileSize - 1) / tileSize;
|
||||
int th = (gh + tileSize - 1) / tileSize;
|
||||
return new int[] { tw, th };
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Detour;
|
||||
using DotRecast.Detour;
|
||||
using DotRecast.Detour.TileCache;
|
||||
using DotRecast.Recast.Geom;
|
||||
using DotRecast.Recast.Toolset.Builder;
|
||||
|
@ -46,13 +46,13 @@ namespace DotRecast.Recast.Toolset.Geom
|
|||
if (null != _geom)
|
||||
{
|
||||
var offMeshConnections = _geom.GetOffMeshConnections();
|
||||
option.offMeshConCount = offMeshConnections.Count;
|
||||
option.offMeshConVerts = new float[option.offMeshConCount * 6];
|
||||
option.offMeshConRad = new float[option.offMeshConCount];
|
||||
option.offMeshConDir = new int[option.offMeshConCount];
|
||||
option.offMeshConAreas = new int[option.offMeshConCount];
|
||||
option.offMeshConFlags = new int[option.offMeshConCount];
|
||||
option.offMeshConUserID = new int[option.offMeshConCount];
|
||||
option.offMeshConCount = offMeshConnections.Count;
|
||||
for (int i = 0; i < option.offMeshConCount; i++)
|
||||
{
|
||||
RcOffMeshConnection offMeshCon = offMeshConnections[i];
|
||||
|
@ -65,7 +65,7 @@ namespace DotRecast.Recast.Toolset.Geom
|
|||
option.offMeshConDir[i] = offMeshCon.bidir ? 1 : 0;
|
||||
option.offMeshConAreas[i] = offMeshCon.area;
|
||||
option.offMeshConFlags[i] = offMeshCon.flags;
|
||||
// option.offMeshConUserID[i] = offMeshCon.userId;
|
||||
option.offMeshConUserID[i] = offMeshCon.userId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -41,7 +41,7 @@ namespace DotRecast.Recast.Toolset.Geom
|
|||
|
||||
public static DemoInputGeomProvider LoadFile(string objFilePath)
|
||||
{
|
||||
byte[] chunk = RcResources.Load(objFilePath);
|
||||
byte[] chunk = RcIO.ReadFileIfFound(objFilePath);
|
||||
var context = RcObjImporter.LoadContext(chunk);
|
||||
return new DemoInputGeomProvider(context.vertexPositions, context.meshFaces);
|
||||
}
|
||||
|
@ -57,12 +57,12 @@ namespace DotRecast.Recast.Toolset.Geom
|
|||
this.faces = faces;
|
||||
normals = new float[faces.Length];
|
||||
CalculateNormals();
|
||||
bmin = RcVecUtils.Create(vertices);
|
||||
bmax = RcVecUtils.Create(vertices);
|
||||
bmin = new RcVec3f(vertices);
|
||||
bmax = new RcVec3f(vertices);
|
||||
for (int i = 1; i < vertices.Length / 3; i++)
|
||||
{
|
||||
bmin = RcVecUtils.Min(bmin, vertices, i * 3);
|
||||
bmax = RcVecUtils.Max(bmax, vertices, i * 3);
|
||||
bmin = RcVec3f.Min(bmin, RcVec.Create(vertices, i * 3));
|
||||
bmax = RcVec3f.Max(bmax, RcVec.Create(vertices, i * 3));
|
||||
}
|
||||
|
||||
_mesh = new RcTriMesh(vertices, faces);
|
||||
|
@ -87,11 +87,11 @@ namespace DotRecast.Recast.Toolset.Geom
|
|||
{
|
||||
for (int i = 0; i < faces.Length; i += 3)
|
||||
{
|
||||
int v0 = faces[i] * 3;
|
||||
int v1 = faces[i + 1] * 3;
|
||||
int v2 = faces[i + 2] * 3;
|
||||
var e0 = RcVecUtils.Subtract(vertices, v1, v0);
|
||||
var e1 = RcVecUtils.Subtract(vertices, v2, v0);
|
||||
RcVec3f v0 = RcVec.Create(vertices, faces[i] * 3);
|
||||
RcVec3f v1 = RcVec.Create(vertices, faces[i + 1] * 3);
|
||||
RcVec3f v2 = RcVec.Create(vertices, faces[i + 2] * 3);
|
||||
RcVec3f e0 = v1 - v0;
|
||||
RcVec3f e1 = v2 - v0;
|
||||
|
||||
normals[i] = e0.Y * e1.Z - e0.Z * e1.Y;
|
||||
normals[i + 1] = e0.Z * e1.X - e0.X * e1.Z;
|
||||
|
@ -150,7 +150,7 @@ namespace DotRecast.Recast.Toolset.Geom
|
|||
q.X = src.X + (dst.X - src.X) * btmax;
|
||||
q.Y = src.Z + (dst.Z - src.Z) * btmax;
|
||||
|
||||
List<RcChunkyTriMeshNode> chunks = _mesh.chunkyTriMesh.GetChunksOverlappingSegment(p, q);
|
||||
List<RcChunkyTriMeshNode> chunks = RcChunkyTriMeshs.GetChunksOverlappingSegment(_mesh.chunkyTriMesh, p, q);
|
||||
if (0 == chunks.Count)
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace DotRecast.Recast.Toolset.Gizmos
|
|||
0.5f * (start.Z + end.Z)
|
||||
};
|
||||
RcVec3f axis = new RcVec3f(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
||||
RcVec3f[] normals = new RcVec3f[3];
|
||||
Span<RcVec3f> normals = stackalloc RcVec3f[3];
|
||||
normals[1] = new RcVec3f(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
||||
normals[1] = RcVec3f.Normalize(normals[1]);
|
||||
normals[0] = GetSideVector(axis);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Toolset.Gizmos
|
||||
namespace DotRecast.Recast.Toolset.Gizmos
|
||||
{
|
||||
public class RcCompositeGizmo : IRcGizmoMeshFilter
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace DotRecast.Recast.Toolset.Gizmos
|
|||
0.5f * (start.Z + end.Z)
|
||||
);
|
||||
RcVec3f axis = new RcVec3f(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
||||
RcVec3f[] normals = new RcVec3f[3];
|
||||
Span<RcVec3f> normals = stackalloc RcVec3f[3];
|
||||
normals[1] = new RcVec3f(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
||||
normals[1] = RcVec3f.Normalize(normals[1]);
|
||||
normals[0] = GetSideVector(axis);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
using DotRecast.Recast.Toolset.Gizmos;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Gizmos
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Gizmos
|
||||
{
|
||||
|
|
|
@ -4,8 +4,8 @@ namespace DotRecast.Recast.Toolset.Gizmos
|
|||
{
|
||||
public static class RcGizmoHelper
|
||||
{
|
||||
private static readonly int SEGMENTS = 16;
|
||||
private static readonly int RINGS = 8;
|
||||
private const int SEGMENTS = 16;
|
||||
private const int RINGS = 8;
|
||||
|
||||
private static float[] sphericalVertices;
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
using static DotRecast.Recast.Toolset.Gizmos.RcGizmoHelper;
|
||||
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Gizmos
|
||||
{
|
||||
public class RcSphereGizmo : IRcGizmoMeshFilter
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Toolset.Gizmos
|
||||
namespace DotRecast.Recast.Toolset.Gizmos
|
||||
{
|
||||
public class RcTrimeshGizmo : IRcGizmoMeshFilter
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Toolset
|
||||
namespace DotRecast.Recast.Toolset
|
||||
{
|
||||
public interface IRcToolable
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Toolset
|
||||
namespace DotRecast.Recast.Toolset
|
||||
{
|
||||
public class RcNavMeshBuildSettings
|
||||
{
|
||||
|
@ -31,5 +31,8 @@
|
|||
|
||||
public bool tiled = false;
|
||||
public int tileSize = 32;
|
||||
|
||||
public bool keepInterResults = true; // full memory
|
||||
public bool buildAll = true;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
@ -26,12 +26,12 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
private readonly List<DtPolyPoint> _polyPoints;
|
||||
|
||||
private const int SamplingCount = 500;
|
||||
private long _samplingUpdateTime;
|
||||
private double _samplingUpdateTime;
|
||||
private readonly RcCyclicBuffer<long> _updateTimes;
|
||||
private long _curUpdateTime;
|
||||
private long _avgUpdateTime;
|
||||
private long _minUpdateTime;
|
||||
private long _maxUpdateTime;
|
||||
private double _curUpdateTime;
|
||||
private double _avgUpdateTime;
|
||||
private double _minUpdateTime;
|
||||
private double _maxUpdateTime;
|
||||
|
||||
public RcCrowdAgentProfilingTool()
|
||||
{
|
||||
|
@ -269,11 +269,11 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
_updateTimes.PushBack(currentTime);
|
||||
|
||||
// for benchmark
|
||||
_samplingUpdateTime = _updateTimes.Sum() / TimeSpan.TicksPerMillisecond;
|
||||
_curUpdateTime = currentTime / TimeSpan.TicksPerMillisecond;
|
||||
_avgUpdateTime = (long)(_updateTimes.Average() / TimeSpan.TicksPerMillisecond);
|
||||
_minUpdateTime = _updateTimes.Min() / TimeSpan.TicksPerMillisecond;
|
||||
_maxUpdateTime = _updateTimes.Max() / TimeSpan.TicksPerMillisecond;
|
||||
_samplingUpdateTime = _updateTimes.Sum() / (double)TimeSpan.TicksPerMillisecond;
|
||||
_curUpdateTime = currentTime / (double)TimeSpan.TicksPerMillisecond;
|
||||
_avgUpdateTime = (_updateTimes.Average() / (double)TimeSpan.TicksPerMillisecond);
|
||||
_minUpdateTime = _updateTimes.Min() / (double)TimeSpan.TicksPerMillisecond;
|
||||
_maxUpdateTime = _updateTimes.Max() / (double)TimeSpan.TicksPerMillisecond;
|
||||
}
|
||||
|
||||
private void MoveMob(DtNavMeshQuery navquery, IDtQueryFilter filter, DtCrowdAgent ag, RcCrowdAgentData crowAgentData)
|
||||
|
@ -374,27 +374,27 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
}
|
||||
}
|
||||
|
||||
public long GetCrowdUpdateSamplingTime()
|
||||
public double GetCrowdUpdateSamplingTime()
|
||||
{
|
||||
return _samplingUpdateTime;
|
||||
}
|
||||
|
||||
public long GetCrowdUpdateTime()
|
||||
public double GetCrowdUpdateTime()
|
||||
{
|
||||
return _curUpdateTime;
|
||||
}
|
||||
|
||||
public long GetCrowdUpdateAvgTime()
|
||||
public double GetCrowdUpdateAvgTime()
|
||||
{
|
||||
return _avgUpdateTime;
|
||||
}
|
||||
|
||||
public long GetCrowdUpdateMinTime()
|
||||
public double GetCrowdUpdateMinTime()
|
||||
{
|
||||
return _minUpdateTime;
|
||||
}
|
||||
|
||||
public long GetCrowdUpdateMaxTime()
|
||||
public double GetCrowdUpdateMaxTime()
|
||||
{
|
||||
return _maxUpdateTime;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Toolset.Tools
|
||||
namespace DotRecast.Recast.Toolset.Tools
|
||||
{
|
||||
public class RcCrowdAgentProfilingToolConfig
|
||||
{
|
||||
|
@ -12,5 +12,7 @@
|
|||
public float percentTravellers = 15f;
|
||||
public int pathQueueSize = 32;
|
||||
public int maxIterations = 300;
|
||||
|
||||
public bool showAgents = true;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Toolset.Tools
|
||||
namespace DotRecast.Recast.Toolset.Tools
|
||||
{
|
||||
public class RcCrowdAgentTrail
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Toolset.Tools
|
||||
namespace DotRecast.Recast.Toolset.Tools
|
||||
{
|
||||
public enum RcCrowdAgentType
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
@ -297,7 +297,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
RcVec3f vel = RcVec3f.Subtract(tgt, pos);
|
||||
vel.Y = 0.0f;
|
||||
vel = RcVec3f.Normalize(vel);
|
||||
return vel.Scale(speed);
|
||||
return vel * speed;
|
||||
}
|
||||
|
||||
public long GetCrowdUpdateTime()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Collections;
|
||||
using DotRecast.Core.Collections;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast.Toolset.Tools
|
||||
namespace DotRecast.Recast.Toolset.Tools
|
||||
{
|
||||
public enum RcDynamicColliderShape
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -18,12 +18,12 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
private DtDynamicNavMesh dynaMesh;
|
||||
private readonly Dictionary<long, RcGizmo> colliderGizmos;
|
||||
|
||||
private readonly Random random;
|
||||
private readonly IRcRand random;
|
||||
private readonly DemoInputGeomProvider bridgeGeom;
|
||||
private readonly DemoInputGeomProvider houseGeom;
|
||||
private readonly DemoInputGeomProvider convexGeom;
|
||||
|
||||
public RcDynamicUpdateTool(Random rand, DemoInputGeomProvider bridgeGeom, DemoInputGeomProvider houseGeom, DemoInputGeomProvider convexGeom)
|
||||
public RcDynamicUpdateTool(IRcRand rand, DemoInputGeomProvider bridgeGeom, DemoInputGeomProvider houseGeom, DemoInputGeomProvider convexGeom)
|
||||
{
|
||||
this.colliderGizmos = new Dictionary<long, RcGizmo>();
|
||||
this.random = rand;
|
||||
|
@ -141,6 +141,16 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
return colliderWithGizmo;
|
||||
}
|
||||
|
||||
public DtDynamicNavMesh Copy(RcConfig cfg, IList<RcBuilderResult> results)
|
||||
{
|
||||
var voxelFile = DtVoxelFile.From(cfg, results);
|
||||
dynaMesh = new DtDynamicNavMesh(voxelFile);
|
||||
dynaMesh.config.keepIntermediateResults = true;
|
||||
colliderGizmos.Clear();
|
||||
|
||||
return dynaMesh;
|
||||
}
|
||||
|
||||
public DtDynamicNavMesh Load(string filename, IRcCompressor compressor)
|
||||
{
|
||||
using var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
|
@ -159,7 +169,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
public void Save(string filename, bool compression, IRcCompressor compressor)
|
||||
{
|
||||
DtVoxelFile voxelFile = DtVoxelFile.From(dynaMesh);
|
||||
using var fs = new FileStream(filename, FileMode.CreateNew, FileAccess.Write);
|
||||
using var fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
|
||||
using var bw = new BinaryWriter(fs);
|
||||
DtVoxelFileWriter writer = new DtVoxelFileWriter(compressor);
|
||||
writer.Write(bw, voxelFile, compression);
|
||||
|
@ -339,20 +349,14 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
return resultvector;
|
||||
}
|
||||
|
||||
public bool UpdateDynaMesh(TaskFactory executor)
|
||||
public bool Update(TaskFactory executor)
|
||||
{
|
||||
if (dynaMesh == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool updated = dynaMesh.Update(executor).Result;
|
||||
if (updated)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return dynaMesh.Update(executor);
|
||||
}
|
||||
|
||||
public bool Raycast(RcVec3f spos, RcVec3f epos, out float hitPos, out RcVec3f raycastHitPos)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Collections;
|
||||
using DotRecast.Core.Collections;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Detour.Extras.Jumplink;
|
||||
using DotRecast.Recast.Geom;
|
||||
|
@ -116,7 +116,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
{
|
||||
RcVec3f p = link.startSamples[i].p;
|
||||
RcVec3f q = link.endSamples[i].p;
|
||||
if (i == 0 || RcVecUtils.Dist2D(prev, p) > agentRadius)
|
||||
if (i == 0 || RcVec.Dist2D(prev, p) > agentRadius)
|
||||
{
|
||||
geom.AddOffMeshConnection(p, q, agentRadius, false, area, flags);
|
||||
prev = p;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Collections;
|
||||
|
@ -42,7 +42,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
// Init cache
|
||||
var bmin = geom.GetMeshBoundsMin();
|
||||
var bmax = geom.GetMeshBoundsMax();
|
||||
RcCommons.CalcGridSize(bmin, bmax, setting.cellSize, out var gw, out var gh);
|
||||
RcRecast.CalcGridSize(bmin, bmax, setting.cellSize, out var gw, out var gh);
|
||||
int ts = setting.tileSize;
|
||||
int tw = (gw + ts - 1) / ts;
|
||||
int th = (gh + ts - 1) / ts;
|
||||
|
@ -78,7 +78,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
_tc.BuildNavMeshTile(refs);
|
||||
}
|
||||
|
||||
return new NavMeshBuildResult(RcImmutableArray<RcBuilderResult>.Empty, _tc.GetNavMesh());
|
||||
return new NavMeshBuildResult(cfg, RcImmutableArray<RcBuilderResult>.Empty, _tc.GetNavMesh());
|
||||
}
|
||||
|
||||
public void ClearAllTempObstacles()
|
||||
|
@ -141,7 +141,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
navMeshParams.maxTiles = 256; // ..
|
||||
navMeshParams.maxPolys = 16384;
|
||||
|
||||
var navMesh = new DtNavMesh(navMeshParams, 6);
|
||||
var navMesh = new DtNavMesh();
|
||||
navMesh.Init(navMeshParams, 6);
|
||||
var comp = _comp.Create(cCompatibility ? 0 : 1);
|
||||
var storageParams = new DtTileCacheStorageParams(order, cCompatibility);
|
||||
DtTileCache tc = new DtTileCache(option, storageParams, navMesh, comp, _proc);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast.Geom;
|
||||
using DotRecast.Recast.Toolset.Builder;
|
||||
|
@ -34,7 +34,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
RcOffMeshConnection nearestConnection = null;
|
||||
foreach (RcOffMeshConnection offMeshCon in geom.GetOffMeshConnections())
|
||||
{
|
||||
float d = Math.Min(RcVecUtils.DistanceSquared(p, offMeshCon.verts, 0), RcVecUtils.DistanceSquared(p, offMeshCon.verts, 3));
|
||||
float d = Math.Min(RcVec.DistanceSquared(p, offMeshCon.verts, 0), RcVec.DistanceSquared(p, offMeshCon.verts, 3));
|
||||
if (d < nearestDist && Math.Sqrt(d) < settings.agentRadius)
|
||||
{
|
||||
nearestDist = d;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
@ -11,7 +11,6 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
public const int MAX_POLYS = 256;
|
||||
public const int MAX_SMOOTH = 2048;
|
||||
|
||||
|
||||
public RcTestNavMeshTool()
|
||||
{
|
||||
}
|
||||
|
@ -22,7 +21,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
}
|
||||
|
||||
public DtStatus FindFollowPath(DtNavMesh navMesh, DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f startPt, RcVec3f endPt, IDtQueryFilter filter, bool enableRaycast,
|
||||
ref List<long> pathIterPolys, ref List<RcVec3f> smoothPath)
|
||||
ref List<long> pathIterPolys, int pathIterPolyCount, ref List<RcVec3f> smoothPath)
|
||||
{
|
||||
if (startRef == 0 || endRef == 0)
|
||||
{
|
||||
|
@ -36,6 +35,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
smoothPath ??= new List<RcVec3f>();
|
||||
|
||||
pathIterPolys.Clear();
|
||||
pathIterPolyCount = 0;
|
||||
|
||||
smoothPath.Clear();
|
||||
|
||||
var opt = new DtFindPathOption(enableRaycast ? DtFindPathOptions.DT_FINDPATH_ANY_ANGLE : 0, float.MaxValue);
|
||||
|
@ -43,24 +44,29 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
if (0 >= pathIterPolys.Count)
|
||||
return DtStatus.DT_FAILURE;
|
||||
|
||||
pathIterPolyCount = pathIterPolys.Count;
|
||||
|
||||
// Iterate over the path to find smooth path on the detail mesh surface.
|
||||
navQuery.ClosestPointOnPoly(startRef, startPt, out var iterPos, out var _);
|
||||
navQuery.ClosestPointOnPoly(pathIterPolys[pathIterPolys.Count - 1], endPt, out var targetPos, out var _);
|
||||
|
||||
float STEP_SIZE = 0.5f;
|
||||
float SLOP = 0.01f;
|
||||
const float STEP_SIZE = 0.5f;
|
||||
const float SLOP = 0.01f;
|
||||
|
||||
smoothPath.Clear();
|
||||
smoothPath.Add(iterPos);
|
||||
var visited = new List<long>();
|
||||
|
||||
Span<long> visited = stackalloc long[16];
|
||||
int nvisited = 0;
|
||||
|
||||
|
||||
// Move towards target a small advancement at a time until target reached or
|
||||
// when ran out of memory to store the path.
|
||||
while (0 < pathIterPolys.Count && smoothPath.Count < MAX_SMOOTH)
|
||||
while (0 < pathIterPolyCount && smoothPath.Count < MAX_SMOOTH)
|
||||
{
|
||||
// Find location to steer towards.
|
||||
if (!DtPathUtils.GetSteerTarget(navQuery, iterPos, targetPos, SLOP,
|
||||
pathIterPolys, out var steerPos, out var steerPosFlag, out var steerPosRef))
|
||||
pathIterPolys, pathIterPolyCount, out var steerPos, out var steerPosFlag, out var steerPosRef))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -85,15 +91,15 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
len = STEP_SIZE / len;
|
||||
}
|
||||
|
||||
RcVec3f moveTgt = RcVecUtils.Mad(iterPos, delta, len);
|
||||
RcVec3f moveTgt = RcVec.Mad(iterPos, delta, len);
|
||||
|
||||
// Move
|
||||
navQuery.MoveAlongSurface(pathIterPolys[0], iterPos, moveTgt, filter, out var result, ref visited);
|
||||
navQuery.MoveAlongSurface(pathIterPolys[0], iterPos, moveTgt, filter, out var result, visited, out nvisited, 16);
|
||||
|
||||
iterPos = result;
|
||||
|
||||
pathIterPolys = DtPathUtils.MergeCorridorStartMoved(pathIterPolys, pathIterPolys.Count, MAX_POLYS, visited);
|
||||
pathIterPolys = DtPathUtils.FixupShortcuts(pathIterPolys, navQuery);
|
||||
pathIterPolyCount = DtPathUtils.MergeCorridorStartMoved(pathIterPolys, pathIterPolyCount, MAX_POLYS, visited, nvisited);
|
||||
pathIterPolyCount = DtPathUtils.FixupShortcuts(ref pathIterPolys, pathIterPolyCount, navQuery);
|
||||
|
||||
var status = navQuery.GetPolyHeight(pathIterPolys[0], result, out var h);
|
||||
if (status.Succeeded())
|
||||
|
@ -123,7 +129,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
long prevRef = 0;
|
||||
long polyRef = pathIterPolys[0];
|
||||
int npos = 0;
|
||||
while (npos < pathIterPolys.Count && polyRef != steerPosRef)
|
||||
while (npos < pathIterPolyCount && polyRef != steerPosRef)
|
||||
{
|
||||
prevRef = polyRef;
|
||||
polyRef = pathIterPolys[npos];
|
||||
|
@ -131,6 +137,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
}
|
||||
|
||||
pathIterPolys = pathIterPolys.GetRange(npos, pathIterPolys.Count - npos);
|
||||
pathIterPolyCount -= npos;
|
||||
|
||||
// Handle the connection.
|
||||
var status2 = navMesh.GetOffMeshConnectionPolyEndPoints(prevRef, polyRef, ref startPos, ref endPos);
|
||||
|
@ -164,15 +171,15 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
}
|
||||
|
||||
public DtStatus FindStraightPath(DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f startPt, RcVec3f endPt, IDtQueryFilter filter, bool enableRaycast,
|
||||
ref List<long> polys, ref List<DtStraightPath> straightPath, int straightPathOptions)
|
||||
ref List<long> polys, Span<DtStraightPath> straightPath, out int straightPathCount, int maxStraightPath, int straightPathOptions)
|
||||
{
|
||||
straightPathCount = 0;
|
||||
if (startRef == 0 || endRef == 0)
|
||||
{
|
||||
return DtStatus.DT_FAILURE;
|
||||
}
|
||||
|
||||
polys ??= new List<long>();
|
||||
straightPath ??= new List<DtStraightPath>();
|
||||
|
||||
polys.Clear();
|
||||
straightPath.Clear();
|
||||
|
@ -194,7 +201,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
}
|
||||
}
|
||||
|
||||
navQuery.FindStraightPath(startPt, epos, polys, ref straightPath, MAX_POLYS, straightPathOptions);
|
||||
navQuery.FindStraightPath(startPt, epos, polys, polys.Count, straightPath, out straightPathCount, maxStraightPath, straightPathOptions);
|
||||
|
||||
return DtStatus.DT_SUCCESS;
|
||||
}
|
||||
|
@ -213,8 +220,9 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
}
|
||||
|
||||
public DtStatus UpdateSlicedFindPath(DtNavMeshQuery navQuery, int maxIter, long endRef, RcVec3f startPos, RcVec3f endPos,
|
||||
ref List<long> path, ref List<DtStraightPath> straightPath)
|
||||
ref List<long> path, Span<DtStraightPath> straightPath, out int straightPathCount, int maxStraightPath)
|
||||
{
|
||||
straightPathCount = 0;
|
||||
var status = navQuery.UpdateSlicedFindPath(maxIter, out _);
|
||||
|
||||
if (!status.Succeeded())
|
||||
|
@ -224,7 +232,6 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
|
||||
navQuery.FinalizeSlicedFindPath(ref path);
|
||||
|
||||
straightPath?.Clear();
|
||||
if (path != null)
|
||||
{
|
||||
// In case of partial path, make sure the end point is clamped to the last polygon.
|
||||
|
@ -238,8 +245,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
}
|
||||
}
|
||||
|
||||
straightPath = new List<DtStraightPath>(MAX_POLYS);
|
||||
navQuery.FindStraightPath(startPos, epos, path, ref straightPath, MAX_POLYS, DtStraightPathOptions.DT_STRAIGHTPATH_ALL_CROSSINGS);
|
||||
navQuery.FindStraightPath(startPos, epos, path, path.Count, straightPath, out straightPathCount, maxStraightPath, DtStraightPathOptions.DT_STRAIGHTPATH_ALL_CROSSINGS);
|
||||
}
|
||||
|
||||
return DtStatus.DT_SUCCESS;
|
||||
|
@ -247,13 +253,12 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
|
||||
|
||||
public DtStatus Raycast(DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter,
|
||||
ref List<long> polys, ref List<DtStraightPath> straightPath, ref RcVec3f hitPos, ref RcVec3f hitNormal, ref bool hitResult)
|
||||
ref List<long> polys, Span<DtStraightPath> straightPath, out int straightPathCount, int maxStraightPath, ref RcVec3f hitPos, ref RcVec3f hitNormal, ref bool hitResult)
|
||||
{
|
||||
straightPathCount = 0;
|
||||
if (startRef == 0 || endRef == 0)
|
||||
{
|
||||
polys?.Clear();
|
||||
straightPath?.Clear();
|
||||
|
||||
return DtStatus.DT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -267,7 +272,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
// results ...
|
||||
polys = path;
|
||||
|
||||
if (t > 1)
|
||||
if (t >= 1)
|
||||
{
|
||||
// No hit
|
||||
hitPos = endPos;
|
||||
|
@ -291,10 +296,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
}
|
||||
}
|
||||
|
||||
straightPath ??= new List<DtStraightPath>();
|
||||
straightPath.Clear();
|
||||
straightPath.Add(new DtStraightPath(startPos, 0, 0));
|
||||
straightPath.Add(new DtStraightPath(hitPos, 0, 0));
|
||||
straightPath[straightPathCount++] = new DtStraightPath(startPos, 0, 0);
|
||||
straightPath[straightPathCount++] = new DtStraightPath(hitPos, 0, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -377,7 +380,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
float nx = (epos.Z - spos.Z) * 0.25f;
|
||||
float nz = -(epos.X - spos.X) * 0.25f;
|
||||
|
||||
var tempQueryPoly = new RcVec3f[4];
|
||||
RcVec3f[] tempQueryPoly = new RcVec3f[4];
|
||||
tempQueryPoly[0].X = spos.X + nx * 1.2f;
|
||||
tempQueryPoly[0].Y = spos.Y + agentHeight / 2;
|
||||
tempQueryPoly[0].Z = spos.Z + nz * 1.2f;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Collections;
|
||||
using DotRecast.Core.Collections;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Linq;
|
||||
using System.Linq;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Collections;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
@ -23,7 +23,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
var bmin = geom.GetMeshBoundsMin();
|
||||
var bmax = geom.GetMeshBoundsMax();
|
||||
int gw = 0, gh = 0;
|
||||
RcCommons.CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh);
|
||||
RcRecast.CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh);
|
||||
|
||||
int ts = settings.tileSize;
|
||||
int tw = (gw + ts - 1) / ts;
|
||||
|
@ -47,7 +47,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
var bmin = geom.GetMeshBoundsMin();
|
||||
var bmax = geom.GetMeshBoundsMax();
|
||||
int gw = 0, gh = 0;
|
||||
RcCommons.CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh);
|
||||
RcRecast.CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh);
|
||||
|
||||
int ts = settings.tileSize;
|
||||
int tw = (gw + ts - 1) / ts;
|
||||
|
@ -68,8 +68,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
tileTriCount = 0; // ...
|
||||
tileMemUsage = 0; // ...
|
||||
|
||||
var availableTileCount = navMesh.GetAvailableTileCount();
|
||||
if (0 >= availableTileCount)
|
||||
var availableTile = navMesh.IsAvailableTileCount();
|
||||
if (!availableTile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
|||
|
||||
var beginTick = RcFrequency.Ticks;
|
||||
var rb = new RcBuilder();
|
||||
var result = rb.BuildTile(geom, cfg, bmin, bmax, tx, ty, new RcAtomicInteger(0), 1);
|
||||
var result = rb.BuildTile(geom, cfg, bmin, bmax, tx, ty, new RcAtomicInteger(0), 1, settings.keepInterResults);
|
||||
|
||||
var tb = new TileNavMeshBuilder();
|
||||
var meshData = tb.BuildMeshData(geom, settings.cellSize, settings.cellHeight, settings.agentHeight, settings.agentRadius, settings.agentMaxClimb, RcImmutableArray.Create(result)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
namespace DotRecast.Recast
|
||||
{
|
||||
public static class EdgeValues
|
||||
{
|
||||
public const int EV_UNDEF = -1;
|
||||
public const int EV_HULL = -2;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast.Geom
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Recast.Geom
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Recast.Geom
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,278 +18,14 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast.Geom
|
||||
{
|
||||
public class RcChunkyTriMesh
|
||||
{
|
||||
private List<RcChunkyTriMeshNode> nodes;
|
||||
private int ntris;
|
||||
private int maxTrisPerChunk;
|
||||
|
||||
private void CalcExtends(BoundsItem[] items, int imin, int imax, ref RcVec2f bmin, ref RcVec2f bmax)
|
||||
{
|
||||
bmin.X = items[imin].bmin.X;
|
||||
bmin.Y = items[imin].bmin.Y;
|
||||
|
||||
bmax.X = items[imin].bmax.X;
|
||||
bmax.Y = items[imin].bmax.Y;
|
||||
|
||||
for (int i = imin + 1; i < imax; ++i)
|
||||
{
|
||||
BoundsItem it = items[i];
|
||||
if (it.bmin.X < bmin.X)
|
||||
{
|
||||
bmin.X = it.bmin.X;
|
||||
}
|
||||
|
||||
if (it.bmin.Y < bmin.Y)
|
||||
{
|
||||
bmin.Y = it.bmin.Y;
|
||||
}
|
||||
|
||||
if (it.bmax.X > bmax.X)
|
||||
{
|
||||
bmax.X = it.bmax.X;
|
||||
}
|
||||
|
||||
if (it.bmax.Y > bmax.Y)
|
||||
{
|
||||
bmax.Y = it.bmax.Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int LongestAxis(float x, float y)
|
||||
{
|
||||
return y > x ? 1 : 0;
|
||||
}
|
||||
|
||||
private void Subdivide(BoundsItem[] items, int imin, int imax, int trisPerChunk, List<RcChunkyTriMeshNode> nodes, int[] inTris)
|
||||
{
|
||||
int inum = imax - imin;
|
||||
|
||||
RcChunkyTriMeshNode node = new RcChunkyTriMeshNode();
|
||||
nodes.Add(node);
|
||||
|
||||
if (inum <= trisPerChunk)
|
||||
{
|
||||
// Leaf
|
||||
CalcExtends(items, imin, imax, ref node.bmin, ref node.bmax);
|
||||
|
||||
// Copy triangles.
|
||||
node.i = nodes.Count;
|
||||
node.tris = new int[inum * 3];
|
||||
|
||||
int dst = 0;
|
||||
for (int i = imin; i < imax; ++i)
|
||||
{
|
||||
int src = items[i].i * 3;
|
||||
node.tris[dst++] = inTris[src];
|
||||
node.tris[dst++] = inTris[src + 1];
|
||||
node.tris[dst++] = inTris[src + 2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Split
|
||||
CalcExtends(items, imin, imax, ref node.bmin, ref node.bmax);
|
||||
|
||||
int axis = LongestAxis(node.bmax.X - node.bmin.X, node.bmax.Y - node.bmin.Y);
|
||||
|
||||
if (axis == 0)
|
||||
{
|
||||
Array.Sort(items, imin, imax - imin, BoundsItemXComparer.Shared);
|
||||
// Sort along x-axis
|
||||
}
|
||||
else if (axis == 1)
|
||||
{
|
||||
Array.Sort(items, imin, imax - imin, BoundsItemYComparer.Shared);
|
||||
// Sort along y-axis
|
||||
}
|
||||
|
||||
int isplit = imin + inum / 2;
|
||||
|
||||
// Left
|
||||
Subdivide(items, imin, isplit, trisPerChunk, nodes, inTris);
|
||||
// Right
|
||||
Subdivide(items, isplit, imax, trisPerChunk, nodes, inTris);
|
||||
|
||||
// Negative index means escape.
|
||||
node.i = -nodes.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public RcChunkyTriMesh(float[] verts, int[] tris, int ntris, int trisPerChunk)
|
||||
{
|
||||
int nchunks = (ntris + trisPerChunk - 1) / trisPerChunk;
|
||||
|
||||
nodes = new List<RcChunkyTriMeshNode>(nchunks);
|
||||
this.ntris = ntris;
|
||||
|
||||
// Build tree
|
||||
BoundsItem[] items = new BoundsItem[ntris];
|
||||
|
||||
for (int i = 0; i < ntris; i++)
|
||||
{
|
||||
int t = i * 3;
|
||||
BoundsItem it = items[i] = new BoundsItem();
|
||||
it.i = i;
|
||||
// Calc triangle XZ bounds.
|
||||
it.bmin.X = it.bmax.X = verts[tris[t] * 3 + 0];
|
||||
it.bmin.Y = it.bmax.Y = verts[tris[t] * 3 + 2];
|
||||
for (int j = 1; j < 3; ++j)
|
||||
{
|
||||
int v = tris[t + j] * 3;
|
||||
if (verts[v] < it.bmin.X)
|
||||
{
|
||||
it.bmin.X = verts[v];
|
||||
}
|
||||
|
||||
if (verts[v + 2] < it.bmin.Y)
|
||||
{
|
||||
it.bmin.Y = verts[v + 2];
|
||||
}
|
||||
|
||||
if (verts[v] > it.bmax.X)
|
||||
{
|
||||
it.bmax.X = verts[v];
|
||||
}
|
||||
|
||||
if (verts[v + 2] > it.bmax.Y)
|
||||
{
|
||||
it.bmax.Y = verts[v + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Subdivide(items, 0, ntris, trisPerChunk, nodes, tris);
|
||||
|
||||
// Calc max tris per node.
|
||||
maxTrisPerChunk = 0;
|
||||
foreach (RcChunkyTriMeshNode node in nodes)
|
||||
{
|
||||
bool isLeaf = node.i >= 0;
|
||||
if (!isLeaf)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node.tris.Length / 3 > maxTrisPerChunk)
|
||||
{
|
||||
maxTrisPerChunk = node.tris.Length / 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckOverlapRect(float[] amin, float[] amax, RcVec2f bmin, RcVec2f bmax)
|
||||
{
|
||||
bool overlap = true;
|
||||
overlap = (amin[0] > bmax.X || amax[0] < bmin.X) ? false : overlap;
|
||||
overlap = (amin[1] > bmax.Y || amax[1] < bmin.Y) ? false : overlap;
|
||||
return overlap;
|
||||
}
|
||||
|
||||
public List<RcChunkyTriMeshNode> GetChunksOverlappingRect(float[] bmin, float[] bmax)
|
||||
{
|
||||
// Traverse tree
|
||||
List<RcChunkyTriMeshNode> ids = new List<RcChunkyTriMeshNode>();
|
||||
int i = 0;
|
||||
while (i < nodes.Count)
|
||||
{
|
||||
RcChunkyTriMeshNode node = nodes[i];
|
||||
bool overlap = CheckOverlapRect(bmin, bmax, node.bmin, node.bmax);
|
||||
bool isLeafNode = node.i >= 0;
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
{
|
||||
ids.Add(node);
|
||||
}
|
||||
|
||||
if (overlap || isLeafNode)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = -node.i;
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
public List<RcChunkyTriMeshNode> GetChunksOverlappingSegment(RcVec2f p, RcVec2f q)
|
||||
{
|
||||
// Traverse tree
|
||||
List<RcChunkyTriMeshNode> ids = new List<RcChunkyTriMeshNode>();
|
||||
int i = 0;
|
||||
while (i < nodes.Count)
|
||||
{
|
||||
RcChunkyTriMeshNode node = nodes[i];
|
||||
bool overlap = CheckOverlapSegment(p, q, node.bmin, node.bmax);
|
||||
bool isLeafNode = node.i >= 0;
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
{
|
||||
ids.Add(node);
|
||||
}
|
||||
|
||||
if (overlap || isLeafNode)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = -node.i;
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
private bool CheckOverlapSegment(RcVec2f p, RcVec2f q, RcVec2f bmin, RcVec2f bmax)
|
||||
{
|
||||
const float EPSILON = 1e-6f;
|
||||
|
||||
float tmin = 0;
|
||||
float tmax = 1;
|
||||
var d = new RcVec2f();
|
||||
d.X = q.X - p.X;
|
||||
d.Y = q.Y - p.Y;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (MathF.Abs(d.Get(i)) < EPSILON)
|
||||
{
|
||||
// Ray is parallel to slab. No hit if origin not within slab
|
||||
if (p.Get(i) < bmin.Get(i) || p.Get(i) > bmax.Get(i))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compute intersection t value of ray with near and far plane of slab
|
||||
float ood = 1.0f / d.Get(i);
|
||||
float t1 = (bmin.Get(i) - p.Get(i)) * ood;
|
||||
float t2 = (bmax.Get(i) - p.Get(i)) * ood;
|
||||
if (t1 > t2)
|
||||
{
|
||||
(t1, t2) = (t2, t1);
|
||||
}
|
||||
|
||||
if (t1 > tmin)
|
||||
tmin = t1;
|
||||
if (t2 < tmax)
|
||||
tmax = t2;
|
||||
if (tmin > tmax)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public List<RcChunkyTriMeshNode> nodes;
|
||||
public int ntris;
|
||||
public int maxTrisPerChunk;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast.Geom
|
||||
{
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast.Geom
|
||||
{
|
||||
public static class RcChunkyTriMeshs
|
||||
{
|
||||
/// Creates partitioned triangle mesh (AABB tree),
|
||||
/// where each node contains at max trisPerChunk triangles.
|
||||
public static bool CreateChunkyTriMesh(float[] verts, int[] tris, int ntris, int trisPerChunk, RcChunkyTriMesh cm)
|
||||
{
|
||||
int nchunks = (ntris + trisPerChunk - 1) / trisPerChunk;
|
||||
|
||||
cm.nodes = new List<RcChunkyTriMeshNode>(nchunks);
|
||||
cm.ntris = ntris;
|
||||
|
||||
// Build tree
|
||||
BoundsItem[] items = new BoundsItem[ntris];
|
||||
for (int i = 0; i < ntris; ++i)
|
||||
{
|
||||
items[i] = new BoundsItem();
|
||||
}
|
||||
|
||||
for (int i = 0; i < ntris; i++)
|
||||
{
|
||||
int t = i * 3;
|
||||
BoundsItem it = items[i];
|
||||
it.i = i;
|
||||
// Calc triangle XZ bounds.
|
||||
it.bmin.X = it.bmax.X = verts[tris[t] * 3 + 0];
|
||||
it.bmin.Y = it.bmax.Y = verts[tris[t] * 3 + 2];
|
||||
for (int j = 1; j < 3; ++j)
|
||||
{
|
||||
int v = tris[t + j] * 3;
|
||||
if (verts[v] < it.bmin.X)
|
||||
{
|
||||
it.bmin.X = verts[v];
|
||||
}
|
||||
|
||||
if (verts[v + 2] < it.bmin.Y)
|
||||
{
|
||||
it.bmin.Y = verts[v + 2];
|
||||
}
|
||||
|
||||
if (verts[v] > it.bmax.X)
|
||||
{
|
||||
it.bmax.X = verts[v];
|
||||
}
|
||||
|
||||
if (verts[v + 2] > it.bmax.Y)
|
||||
{
|
||||
it.bmax.Y = verts[v + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Subdivide(items, 0, ntris, trisPerChunk, cm.nodes, tris);
|
||||
|
||||
items = null;
|
||||
|
||||
// Calc max tris per node.
|
||||
cm.maxTrisPerChunk = 0;
|
||||
foreach (RcChunkyTriMeshNode node in cm.nodes)
|
||||
{
|
||||
bool isLeaf = node.i >= 0;
|
||||
if (!isLeaf)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node.tris.Length / 3 > cm.maxTrisPerChunk)
|
||||
{
|
||||
cm.maxTrisPerChunk = node.tris.Length / 3;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns the chunk indices which overlap the input rectable.
|
||||
public static List<RcChunkyTriMeshNode> GetChunksOverlappingRect(RcChunkyTriMesh cm, RcVec2f bmin, RcVec2f bmax)
|
||||
{
|
||||
// Traverse tree
|
||||
List<RcChunkyTriMeshNode> ids = new List<RcChunkyTriMeshNode>();
|
||||
int i = 0;
|
||||
while (i < cm.nodes.Count)
|
||||
{
|
||||
RcChunkyTriMeshNode node = cm.nodes[i];
|
||||
bool overlap = CheckOverlapRect(bmin, bmax, node.bmin, node.bmax);
|
||||
bool isLeafNode = node.i >= 0;
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
{
|
||||
ids.Add(node);
|
||||
}
|
||||
|
||||
if (overlap || isLeafNode)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = -node.i;
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// Returns the chunk indices which overlap the input segment.
|
||||
public static List<RcChunkyTriMeshNode> GetChunksOverlappingSegment(RcChunkyTriMesh cm, RcVec2f p, RcVec2f q)
|
||||
{
|
||||
// Traverse tree
|
||||
List<RcChunkyTriMeshNode> ids = new List<RcChunkyTriMeshNode>();
|
||||
int i = 0;
|
||||
while (i < cm.nodes.Count)
|
||||
{
|
||||
RcChunkyTriMeshNode node = cm.nodes[i];
|
||||
bool overlap = CheckOverlapSegment(p, q, node.bmin, node.bmax);
|
||||
bool isLeafNode = node.i >= 0;
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
{
|
||||
ids.Add(node);
|
||||
}
|
||||
|
||||
if (overlap || isLeafNode)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = -node.i;
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
|
||||
private static void CalcExtends(BoundsItem[] items, int imin, int imax, ref RcVec2f bmin, ref RcVec2f bmax)
|
||||
{
|
||||
bmin.X = items[imin].bmin.X;
|
||||
bmin.Y = items[imin].bmin.Y;
|
||||
|
||||
bmax.X = items[imin].bmax.X;
|
||||
bmax.Y = items[imin].bmax.Y;
|
||||
|
||||
for (int i = imin + 1; i < imax; ++i)
|
||||
{
|
||||
BoundsItem it = items[i];
|
||||
if (it.bmin.X < bmin.X)
|
||||
{
|
||||
bmin.X = it.bmin.X;
|
||||
}
|
||||
|
||||
if (it.bmin.Y < bmin.Y)
|
||||
{
|
||||
bmin.Y = it.bmin.Y;
|
||||
}
|
||||
|
||||
if (it.bmax.X > bmax.X)
|
||||
{
|
||||
bmax.X = it.bmax.X;
|
||||
}
|
||||
|
||||
if (it.bmax.Y > bmax.Y)
|
||||
{
|
||||
bmax.Y = it.bmax.Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int LongestAxis(float x, float y)
|
||||
{
|
||||
return y > x ? 1 : 0;
|
||||
}
|
||||
|
||||
private static void Subdivide(BoundsItem[] items, int imin, int imax, int trisPerChunk, List<RcChunkyTriMeshNode> nodes, int[] inTris)
|
||||
{
|
||||
int inum = imax - imin;
|
||||
|
||||
RcChunkyTriMeshNode node = new RcChunkyTriMeshNode();
|
||||
nodes.Add(node);
|
||||
|
||||
if (inum <= trisPerChunk)
|
||||
{
|
||||
// Leaf
|
||||
CalcExtends(items, imin, imax, ref node.bmin, ref node.bmax);
|
||||
|
||||
// Copy triangles.
|
||||
node.i = nodes.Count;
|
||||
node.tris = new int[inum * 3];
|
||||
|
||||
int dst = 0;
|
||||
for (int i = imin; i < imax; ++i)
|
||||
{
|
||||
int src = items[i].i * 3;
|
||||
node.tris[dst++] = inTris[src];
|
||||
node.tris[dst++] = inTris[src + 1];
|
||||
node.tris[dst++] = inTris[src + 2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Split
|
||||
CalcExtends(items, imin, imax, ref node.bmin, ref node.bmax);
|
||||
|
||||
int axis = LongestAxis(node.bmax.X - node.bmin.X, node.bmax.Y - node.bmin.Y);
|
||||
|
||||
if (axis == 0)
|
||||
{
|
||||
Array.Sort(items, imin, imax - imin, BoundsItemXComparer.Shared);
|
||||
// Sort along x-axis
|
||||
}
|
||||
else if (axis == 1)
|
||||
{
|
||||
Array.Sort(items, imin, imax - imin, BoundsItemYComparer.Shared);
|
||||
// Sort along y-axis
|
||||
}
|
||||
|
||||
int isplit = imin + inum / 2;
|
||||
|
||||
// Left
|
||||
Subdivide(items, imin, isplit, trisPerChunk, nodes, inTris);
|
||||
// Right
|
||||
Subdivide(items, isplit, imax, trisPerChunk, nodes, inTris);
|
||||
|
||||
// Negative index means escape.
|
||||
node.i = -nodes.Count;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CheckOverlapRect(RcVec2f amin, RcVec2f amax, RcVec2f bmin, RcVec2f bmax)
|
||||
{
|
||||
bool overlap = true;
|
||||
overlap = (amin.X > bmax.X || amax.X < bmin.X) ? false : overlap;
|
||||
overlap = (amin.Y > bmax.Y || amax.Y < bmin.Y) ? false : overlap;
|
||||
return overlap;
|
||||
}
|
||||
|
||||
|
||||
private static bool CheckOverlapSegment(RcVec2f p, RcVec2f q, RcVec2f bmin, RcVec2f bmax)
|
||||
{
|
||||
const float EPSILON = 1e-6f;
|
||||
|
||||
float tmin = 0;
|
||||
float tmax = 1;
|
||||
var d = new RcVec2f();
|
||||
d.X = q.X - p.X;
|
||||
d.Y = q.Y - p.Y;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (MathF.Abs(d.Get(i)) < EPSILON)
|
||||
{
|
||||
// Ray is parallel to slab. No hit if origin not within slab
|
||||
if (p.Get(i) < bmin.Get(i) || p.Get(i) > bmax.Get(i))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compute intersection t value of ray with near and far plane of slab
|
||||
float ood = 1.0f / d.Get(i);
|
||||
float t1 = (bmin.Get(i) - p.Get(i)) * ood;
|
||||
float t2 = (bmax.Get(i) - p.Get(i)) * ood;
|
||||
if (t1 > t2)
|
||||
{
|
||||
(t1, t2) = (t2, t1);
|
||||
}
|
||||
|
||||
if (t1 > tmin)
|
||||
tmin = t1;
|
||||
if (t2 < tmax)
|
||||
tmax = t2;
|
||||
if (tmin > tmax)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -33,7 +33,7 @@ namespace DotRecast.Recast.Geom
|
|||
public readonly int flags;
|
||||
public readonly int userId;
|
||||
|
||||
public RcOffMeshConnection(RcVec3f start, RcVec3f end, float radius, bool bidir, int area, int flags)
|
||||
public RcOffMeshConnection(RcVec3f start, RcVec3f end, float radius, bool bidir, int area, int flags, int userId = 0)
|
||||
{
|
||||
verts = new float[6];
|
||||
verts[0] = start.X;
|
||||
|
@ -46,6 +46,7 @@ namespace DotRecast.Recast.Geom
|
|||
this.bidir = bidir;
|
||||
this.area = area;
|
||||
this.flags = flags;
|
||||
this.userId = userId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
|||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast.Geom
|
||||
{
|
||||
|
@ -32,7 +33,8 @@ namespace DotRecast.Recast.Geom
|
|||
{
|
||||
this.vertices = vertices;
|
||||
this.faces = faces;
|
||||
chunkyTriMesh = new RcChunkyTriMesh(vertices, faces, faces.Length / 3, 32);
|
||||
chunkyTriMesh = new RcChunkyTriMesh();
|
||||
RcChunkyTriMeshs.CreateChunkyTriMesh(vertices, faces, faces.Length / 3, 32, chunkyTriMesh);
|
||||
}
|
||||
|
||||
public int[] GetTris()
|
||||
|
@ -45,9 +47,9 @@ namespace DotRecast.Recast.Geom
|
|||
return vertices;
|
||||
}
|
||||
|
||||
public List<RcChunkyTriMeshNode> GetChunksOverlappingRect(float[] bmin, float[] bmax)
|
||||
public List<RcChunkyTriMeshNode> GetChunksOverlappingRect(RcVec2f bmin, RcVec2f bmax)
|
||||
{
|
||||
return chunkyTriMesh.GetChunksOverlappingRect(bmin, bmax);
|
||||
return RcChunkyTriMeshs.GetChunksOverlappingRect(chunkyTriMesh, bmin, bmax);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -39,7 +39,7 @@ namespace DotRecast.Recast.Geom
|
|||
|
||||
public static SimpleInputGeomProvider LoadFile(string objFilePath)
|
||||
{
|
||||
byte[] chunk = RcResources.Load(objFilePath);
|
||||
byte[] chunk = RcIO.ReadFileIfFound(objFilePath);
|
||||
var context = RcObjImporter.LoadContext(chunk);
|
||||
return new SimpleInputGeomProvider(context.vertexPositions, context.meshFaces);
|
||||
}
|
||||
|
@ -77,12 +77,12 @@ namespace DotRecast.Recast.Geom
|
|||
this.faces = faces;
|
||||
normals = new float[faces.Length];
|
||||
CalculateNormals();
|
||||
bmin = RcVecUtils.Create(vertices);
|
||||
bmax = RcVecUtils.Create(vertices);
|
||||
bmin = new RcVec3f(vertices);
|
||||
bmax = new RcVec3f(vertices);
|
||||
for (int i = 1; i < vertices.Length / 3; i++)
|
||||
{
|
||||
bmin = RcVecUtils.Min(bmin, vertices, i * 3);
|
||||
bmax = RcVecUtils.Max(bmax, vertices, i * 3);
|
||||
bmin = RcVec3f.Min(bmin, RcVec.Create(vertices, i * 3));
|
||||
bmax = RcVec3f.Max(bmax, RcVec.Create(vertices, i * 3));
|
||||
}
|
||||
|
||||
_mesh = new RcTriMesh(vertices, faces);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public interface IRcBuilderProgressListener
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -25,8 +25,7 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcConstants;
|
||||
using static RcCommons;
|
||||
using static RcRecast;
|
||||
|
||||
public static class RcAreas
|
||||
{
|
||||
|
@ -457,12 +456,12 @@ namespace DotRecast.Recast
|
|||
int zStride = xSize; // For readability
|
||||
|
||||
// Compute the bounding box of the polygon
|
||||
RcVec3f bmin = RcVecUtils.Create(verts);
|
||||
RcVec3f bmax = RcVecUtils.Create(verts);
|
||||
RcVec3f bmin = new RcVec3f(verts);
|
||||
RcVec3f bmax = new RcVec3f(verts);
|
||||
for (int i = 3; i < verts.Length; i += 3)
|
||||
{
|
||||
bmin = RcVecUtils.Min(bmin, verts, i);
|
||||
bmax = RcVecUtils.Max(bmax, verts, i);
|
||||
bmin = RcVec3f.Min(bmin, RcVec.Create(verts, i));
|
||||
bmax = RcVec3f.Max(bmax, RcVec.Create(verts, i));
|
||||
}
|
||||
|
||||
bmin.Y = minY;
|
||||
|
@ -753,19 +752,19 @@ namespace DotRecast.Recast
|
|||
int vertIndexB = vertIndex;
|
||||
int vertIndexC = (vertIndex + 1) % numVerts;
|
||||
|
||||
RcVec3f vertA = RcVecUtils.Create(verts, vertIndexA * 3);
|
||||
RcVec3f vertB = RcVecUtils.Create(verts, vertIndexB * 3);
|
||||
RcVec3f vertC = RcVecUtils.Create(verts, vertIndexC * 3);
|
||||
RcVec3f vertA = RcVec.Create(verts, vertIndexA * 3);
|
||||
RcVec3f vertB = RcVec.Create(verts, vertIndexB * 3);
|
||||
RcVec3f vertC = RcVec.Create(verts, vertIndexC * 3);
|
||||
|
||||
// From A to B on the x/z plane
|
||||
RcVec3f prevSegmentDir = RcVec3f.Subtract(vertB, vertA);
|
||||
prevSegmentDir.Y = 0; // Squash onto x/z plane
|
||||
prevSegmentDir = RcVecUtils.SafeNormalize(prevSegmentDir);
|
||||
prevSegmentDir = RcVec.SafeNormalize(prevSegmentDir);
|
||||
|
||||
// From B to C on the x/z plane
|
||||
RcVec3f currSegmentDir = RcVec3f.Subtract(vertC, vertB);
|
||||
currSegmentDir.Y = 0; // Squash onto x/z plane
|
||||
currSegmentDir = RcVecUtils.SafeNormalize(currSegmentDir);
|
||||
currSegmentDir = RcVec.SafeNormalize(currSegmentDir);
|
||||
|
||||
// The y component of the cross product of the two normalized segment directions.
|
||||
// The X and Z components of the cross product are both zero because the two
|
||||
|
@ -792,7 +791,7 @@ namespace DotRecast.Recast
|
|||
bool bevel = cornerMiterSqMag * MITER_LIMIT * MITER_LIMIT < 1.0f;
|
||||
|
||||
// Scale the corner miter so it's proportional to how much the corner should be offset compared to the edges.
|
||||
if (cornerMiterSqMag > RcVecUtils.EPSILON)
|
||||
if (cornerMiterSqMag > RcVec.EPSILON)
|
||||
{
|
||||
float scale = 1.0f / cornerMiterSqMag;
|
||||
cornerMiterX *= scale;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public static class RcAxis
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
/// Contour build flags.
|
||||
/// @see rcBuildContours
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -19,7 +19,9 @@ freely, subject to the following restrictions:
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DotRecast.Core;
|
||||
|
@ -28,7 +30,7 @@ using DotRecast.Recast.Geom;
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcCommons;
|
||||
using static RcRecast;
|
||||
using static RcAreas;
|
||||
|
||||
public class RcBuilder
|
||||
|
@ -45,132 +47,113 @@ namespace DotRecast.Recast
|
|||
_progressListener = progressListener;
|
||||
}
|
||||
|
||||
public List<RcBuilderResult> BuildTiles(IInputGeomProvider geom, RcConfig cfg, TaskFactory taskFactory)
|
||||
public List<RcBuilderResult> BuildTiles(IInputGeomProvider geom, RcConfig cfg, bool keepInterResults, bool buildAll,
|
||||
int threads = 0, TaskFactory taskFactory = null, CancellationToken cancellation = default)
|
||||
{
|
||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
||||
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
|
||||
List<RcBuilderResult> results = new List<RcBuilderResult>();
|
||||
if (null != taskFactory)
|
||||
|
||||
if (1 < threads)
|
||||
{
|
||||
BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, default);
|
||||
return BuildMultiThread(geom, cfg, bmin, bmax, tw, th, threads, taskFactory ?? Task.Factory, cancellation, keepInterResults, buildAll);
|
||||
}
|
||||
else
|
||||
|
||||
return BuildSingleThread(geom, cfg, bmin, bmax, tw, th, keepInterResults, buildAll);
|
||||
}
|
||||
|
||||
private List<RcBuilderResult> BuildSingleThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th,
|
||||
bool keepInterResults, bool buildAll)
|
||||
{
|
||||
BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
|
||||
var results = new List<RcBuilderResult>(th * tw);
|
||||
RcAtomicInteger counter = new RcAtomicInteger(0);
|
||||
|
||||
for (int y = 0; y < th; ++y)
|
||||
{
|
||||
for (int x = 0; x < tw; ++x)
|
||||
{
|
||||
var result = BuildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th, keepInterResults);
|
||||
results.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<RcBuilderResult> BuildMultiThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th,
|
||||
int threads, TaskFactory taskFactory, CancellationToken cancellation,
|
||||
bool keepInterResults, bool buildAll)
|
||||
{
|
||||
var results = new ConcurrentQueue<RcBuilderResult>();
|
||||
RcAtomicInteger progress = new RcAtomicInteger(0);
|
||||
|
||||
public Task BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, int threads, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
|
||||
{
|
||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
||||
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
|
||||
Task task;
|
||||
if (1 < threads)
|
||||
{
|
||||
task = BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
private Task BuildSingleThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax,
|
||||
int tw, int th, List<RcBuilderResult> results)
|
||||
{
|
||||
RcAtomicInteger counter = new RcAtomicInteger(0);
|
||||
for (int y = 0; y < th; ++y)
|
||||
{
|
||||
for (int x = 0; x < tw; ++x)
|
||||
{
|
||||
results.Add(BuildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th));
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task BuildMultiThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax,
|
||||
int tw, int th, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
|
||||
{
|
||||
RcAtomicInteger counter = new RcAtomicInteger(0);
|
||||
CountdownEvent latch = new CountdownEvent(tw * th);
|
||||
List<Task> tasks = new List<Task>();
|
||||
|
||||
List<Task> limits = new List<Task>(threads);
|
||||
for (int x = 0; x < tw; ++x)
|
||||
{
|
||||
for (int y = 0; y < th; ++y)
|
||||
{
|
||||
int tx = x;
|
||||
int ty = y;
|
||||
var task = taskFactory.StartNew(() =>
|
||||
var task = taskFactory.StartNew(state =>
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
if (cancellation.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
RcBuilderResult tile = BuildTile(geom, cfg, bmin, bmax, tx, ty, counter, tw * th);
|
||||
lock (results)
|
||||
{
|
||||
results.Add(tile);
|
||||
}
|
||||
RcBuilderResult result = BuildTile(geom, cfg, bmin, bmax, tx, ty, progress, tw * th, keepInterResults);
|
||||
results.Enqueue(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}, null, cancellation);
|
||||
|
||||
|
||||
latch.Signal();
|
||||
}, cancellationToken);
|
||||
|
||||
tasks.Add(task);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
limits.Add(task);
|
||||
if (threads <= limits.Count)
|
||||
{
|
||||
latch.Wait();
|
||||
Task.WaitAll(limits.ToArray());
|
||||
limits.Clear();
|
||||
}
|
||||
}
|
||||
catch (ThreadInterruptedException)
|
||||
{
|
||||
}
|
||||
|
||||
return Task.WhenAll(tasks.ToArray());
|
||||
if (0 < limits.Count)
|
||||
{
|
||||
Task.WaitAll(limits.ToArray());
|
||||
limits.Clear();
|
||||
}
|
||||
|
||||
public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx,
|
||||
int ty, RcAtomicInteger counter, int total)
|
||||
var list = results.ToList();
|
||||
return list;
|
||||
}
|
||||
|
||||
public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx, int ty, RcAtomicInteger progress, int total, bool keepInterResults)
|
||||
{
|
||||
RcBuilderResult result = Build(geom, new RcBuilderConfig(cfg, bmin, bmax, tx, ty));
|
||||
var bcfg = new RcBuilderConfig(cfg, bmin, bmax, tx, ty);
|
||||
RcBuilderResult result = Build(geom, bcfg, keepInterResults);
|
||||
if (_progressListener != null)
|
||||
{
|
||||
_progressListener.OnProgress(counter.IncrementAndGet(), total);
|
||||
_progressListener.OnProgress(progress.IncrementAndGet(), total);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig builderCfg)
|
||||
public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig bcfg, bool keepInterResults)
|
||||
{
|
||||
RcConfig cfg = builderCfg.cfg;
|
||||
RcConfig cfg = bcfg.cfg;
|
||||
RcContext ctx = new RcContext();
|
||||
//
|
||||
// Step 1. Rasterize input polygon soup.
|
||||
//
|
||||
RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, builderCfg);
|
||||
return Build(ctx, builderCfg.tileX, builderCfg.tileZ, geom, cfg, solid);
|
||||
RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, bcfg);
|
||||
return Build(ctx, bcfg.tileX, bcfg.tileZ, geom, cfg, solid, keepInterResults);
|
||||
}
|
||||
|
||||
public RcBuilderResult Build(RcContext ctx, int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid)
|
||||
public RcBuilderResult Build(RcContext ctx, int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid, bool keepInterResults)
|
||||
{
|
||||
FilterHeightfield(ctx, solid, cfg);
|
||||
RcCompactHeightfield chf = BuildCompactHeightfield(ctx, geom, cfg, solid);
|
||||
|
@ -241,7 +224,17 @@ namespace DotRecast.Recast
|
|||
RcPolyMeshDetail dmesh = cfg.BuildMeshDetail
|
||||
? RcMeshDetails.BuildPolyMeshDetail(ctx, pmesh, chf, cfg.DetailSampleDist, cfg.DetailSampleMaxError)
|
||||
: null;
|
||||
return new RcBuilderResult(tileX, tileZ, solid, chf, cset, pmesh, dmesh, ctx);
|
||||
|
||||
return new RcBuilderResult(
|
||||
tileX,
|
||||
tileZ,
|
||||
keepInterResults ? solid : null,
|
||||
keepInterResults ? chf : null,
|
||||
keepInterResults ? cset : null,
|
||||
pmesh,
|
||||
dmesh,
|
||||
ctx
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -92,7 +92,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
else
|
||||
{
|
||||
RcCommons.CalcGridSize(this.bmin, this.bmax, cfg.Cs, out width, out height);
|
||||
RcRecast.CalcGridSize(this.bmin, this.bmax, cfg.Cs, out width, out height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +1,29 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Core;
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public class RcBuilderResult
|
||||
{
|
||||
public readonly int tileX;
|
||||
public readonly int tileZ;
|
||||
public readonly int TileX;
|
||||
public readonly int TileZ;
|
||||
|
||||
private readonly RcCompactHeightfield chf;
|
||||
private readonly RcContourSet cs;
|
||||
private readonly RcPolyMesh pmesh;
|
||||
private readonly RcPolyMeshDetail dmesh;
|
||||
private readonly RcHeightfield solid;
|
||||
private readonly RcContext _context;
|
||||
public readonly RcHeightfield SolidHeightfiled;
|
||||
public readonly RcCompactHeightfield CompactHeightfield;
|
||||
public readonly RcContourSet ContourSet;
|
||||
public readonly RcPolyMesh Mesh;
|
||||
public readonly RcPolyMeshDetail MeshDetail;
|
||||
public readonly RcContext Context;
|
||||
|
||||
public RcBuilderResult(int tileX, int tileZ, RcHeightfield solid, RcCompactHeightfield chf, RcContourSet cs, RcPolyMesh pmesh, RcPolyMeshDetail dmesh, RcContext ctx)
|
||||
public RcBuilderResult(int tileX, int tileZ, RcHeightfield solidHeightfiled, RcCompactHeightfield compactHeightfield, RcContourSet contourSet, RcPolyMesh mesh, RcPolyMeshDetail meshDetail, RcContext ctx)
|
||||
{
|
||||
this.tileX = tileX;
|
||||
this.tileZ = tileZ;
|
||||
this.solid = solid;
|
||||
this.chf = chf;
|
||||
this.cs = cs;
|
||||
this.pmesh = pmesh;
|
||||
this.dmesh = dmesh;
|
||||
_context = ctx;
|
||||
}
|
||||
|
||||
public RcPolyMesh GetMesh()
|
||||
{
|
||||
return pmesh;
|
||||
}
|
||||
|
||||
public RcPolyMeshDetail GetMeshDetail()
|
||||
{
|
||||
return dmesh;
|
||||
}
|
||||
|
||||
public RcCompactHeightfield GetCompactHeightfield()
|
||||
{
|
||||
return chf;
|
||||
}
|
||||
|
||||
public RcContourSet GetContourSet()
|
||||
{
|
||||
return cs;
|
||||
}
|
||||
|
||||
public RcHeightfield GetSolidHeightfield()
|
||||
{
|
||||
return solid;
|
||||
}
|
||||
|
||||
public RcContext GetTelemetry()
|
||||
{
|
||||
return _context;
|
||||
TileX = tileX;
|
||||
TileZ = tileZ;
|
||||
SolidHeightfiled = solidHeightfiled;
|
||||
CompactHeightfield = compactHeightfield;
|
||||
ContourSet = contourSet;
|
||||
Mesh = mesh;
|
||||
MeshDetail = meshDetail;
|
||||
Context = ctx;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public class RcCompactSpanBuilder
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -20,17 +20,14 @@ freely, subject to the following restrictions:
|
|||
using System;
|
||||
using System.Linq;
|
||||
using DotRecast.Core;
|
||||
using static DotRecast.Recast.RcConstants;
|
||||
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcCommons;
|
||||
|
||||
using static RcRecast;
|
||||
|
||||
public static class RcCompacts
|
||||
{
|
||||
private const int MAX_HEIGHT = RcConstants.RC_SPAN_MAX_HEIGHT;
|
||||
private const int MAX_HEIGHT = RC_SPAN_MAX_HEIGHT;
|
||||
|
||||
/// @}
|
||||
/// @name Compact Heightfield Functions
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public static class RcConstants
|
||||
{
|
||||
/// Represents the null area.
|
||||
/// When a data element is given this value it is considered to no longer be
|
||||
/// assigned to a usable area. (E.g. It is un-walkable.)
|
||||
public const int RC_NULL_AREA = 0;
|
||||
|
||||
/// The default area id used to indicate a walkable polygon.
|
||||
/// This is also the maximum allowed area id, and the only non-null area id
|
||||
/// recognized by some steps in the build process.
|
||||
public const int RC_WALKABLE_AREA = 63;
|
||||
|
||||
/// The value returned by #rcGetCon if the specified direction is not connected
|
||||
/// to another span. (Has no neighbor.)
|
||||
public const int RC_NOT_CONNECTED = 0x3f;
|
||||
|
||||
/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax.
|
||||
public const int RC_SPAN_HEIGHT_BITS = 20;
|
||||
|
||||
/// Defines the maximum value for rcSpan::smin and rcSpan::smax.
|
||||
public const int RC_SPAN_MAX_HEIGHT = (1 << RC_SPAN_HEIGHT_BITS) - 1;
|
||||
|
||||
/// The number of spans allocated per span spool.
|
||||
/// @see rcSpanPool
|
||||
public const int RC_SPANS_PER_POOL = 2048;
|
||||
|
||||
/// Heighfield border flag.
|
||||
/// If a heightfield region ID has this bit set, then the region is a border
|
||||
/// region and its spans are considered unwalkable.
|
||||
/// (Used during the region and contour build process.)
|
||||
/// @see rcCompactSpan::reg
|
||||
public const int RC_BORDER_REG = 0x8000;
|
||||
|
||||
/// Polygon touches multiple regions.
|
||||
/// If a polygon has this region ID it was merged with or created
|
||||
/// from polygons of different regions during the polymesh
|
||||
/// build step that removes redundant border vertices.
|
||||
/// (Used during the polymesh and detail polymesh build processes)
|
||||
/// @see rcPolyMesh::regs
|
||||
public const int RC_MULTIPLE_REGS = 0;
|
||||
|
||||
// Border vertex flag.
|
||||
/// If a region ID has this bit set, then the associated element lies on
|
||||
/// a tile border. If a contour vertex's region ID has this bit set, the
|
||||
/// vertex will later be removed in order to match the segments and vertices
|
||||
/// at tile boundaries.
|
||||
/// (Used during the build process.)
|
||||
/// @see rcCompactSpan::reg, #rcContour::verts, #rcContour::rverts
|
||||
public const int RC_BORDER_VERTEX = 0x10000;
|
||||
|
||||
/// Area border flag.
|
||||
/// If a region ID has this bit set, then the associated element lies on
|
||||
/// the border of an area.
|
||||
/// (Used during the region and contour build process.)
|
||||
/// @see rcCompactSpan::reg, #rcContour::verts, #rcContour::rverts
|
||||
public const int RC_AREA_BORDER = 0x20000;
|
||||
|
||||
/// Applied to the region id field of contour vertices in order to extract the region id.
|
||||
/// The region id field of a vertex may have several flags applied to it. So the
|
||||
/// fields value can't be used directly.
|
||||
/// @see rcContour::verts, rcContour::rverts
|
||||
public const int RC_CONTOUR_REG_MASK = 0xffff;
|
||||
|
||||
/// A value which indicates an invalid index within a mesh.
|
||||
/// @note This does not necessarily indicate an error.
|
||||
/// @see rcPolyMesh::polys
|
||||
public const int RC_MESH_NULL_IDX = 0xffff;
|
||||
|
||||
public const int RC_LOG_WARNING = 1;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -20,25 +20,14 @@ freely, subject to the following restrictions:
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
/** Represents a simple, non-overlapping contour in field space. */
|
||||
/// Represents a simple, non-overlapping contour in field space.
|
||||
public class RcContour
|
||||
{
|
||||
/** Simplified contour vertex and connection data. [Size: 4 * #nverts] */
|
||||
public int[] verts;
|
||||
|
||||
/** The number of vertices in the simplified contour. */
|
||||
public int nverts;
|
||||
|
||||
/** Raw contour vertex and connection data. [Size: 4 * #nrverts] */
|
||||
public int[] rverts;
|
||||
|
||||
/** The number of vertices in the raw contour. */
|
||||
public int nrverts;
|
||||
|
||||
/** The region id of the contour. */
|
||||
public int area;
|
||||
|
||||
/** The area id of the contour. */
|
||||
public int reg;
|
||||
public int[] verts; //< Simplified contour vertex and connection data. [Size: 4 * #nverts]
|
||||
public int nverts; //< The number of vertices in the simplified contour.
|
||||
public int[] rverts; //< Raw contour vertex and connection data. [Size: 4 * #nrverts]
|
||||
public int nrverts; //< The number of vertices in the raw contour.
|
||||
public int reg; //< The region id of the contour.
|
||||
public int area; //< The area id of the contour.
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public class RcContourHole
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public class RcContourRegion
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -24,8 +24,8 @@ using DotRecast.Core;
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcConstants;
|
||||
using static RcCommons;
|
||||
|
||||
using static RcRecast;
|
||||
|
||||
public static class RcContours
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
// Struct to keep track of entries in the region table that have been changed.
|
||||
public readonly struct RcDirtyEntry
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -20,11 +20,11 @@ freely, subject to the following restrictions:
|
|||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using static DotRecast.Recast.RcConstants;
|
||||
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcRecast;
|
||||
|
||||
public static class RcFilledVolumeRasterization
|
||||
{
|
||||
private const float EPSILON = 0.00001f;
|
||||
|
@ -176,7 +176,7 @@ namespace DotRecast.Recast
|
|||
|
||||
private static void Plane(float[][] planes, int p, float[] v1, float[] v2, float[] vertices, int vert)
|
||||
{
|
||||
RcVecUtils.Cross(planes[p], v1, v2);
|
||||
RcVec.Cross(planes[p], v1, v2);
|
||||
planes[p][3] = planes[p][0] * vertices[vert] + planes[p][1] * vertices[vert + 1] + planes[p][2] * vertices[vert + 2];
|
||||
}
|
||||
|
||||
|
@ -296,8 +296,8 @@ namespace DotRecast.Recast
|
|||
|
||||
if (axis.Y * axis.Y > EPSILON)
|
||||
{
|
||||
RcVec3f[] rectangleOnStartPlane = new RcVec3f[4];
|
||||
RcVec3f[] rectangleOnEndPlane = new RcVec3f[4];
|
||||
Span<RcVec3f> rectangleOnStartPlane = stackalloc RcVec3f[4];
|
||||
Span<RcVec3f> rectangleOnEndPlane = stackalloc RcVec3f[4];
|
||||
float ds = RcVec3f.Dot(axis, start);
|
||||
float de = RcVec3f.Dot(axis, end);
|
||||
for (int i = 0; i < 4; i++)
|
||||
|
@ -326,7 +326,7 @@ namespace DotRecast.Recast
|
|||
return s;
|
||||
}
|
||||
|
||||
private static float[] CylinderCapIntersection(RcVec3f start, float radiusSqr, float[] s, int i, RcVec3f[] rectangleOnPlane)
|
||||
private static float[] CylinderCapIntersection(RcVec3f start, float radiusSqr, float[] s, int i, Span<RcVec3f> rectangleOnPlane)
|
||||
{
|
||||
int j = (i + 1) % 4;
|
||||
// Ray against sphere intersection
|
||||
|
@ -507,8 +507,8 @@ namespace DotRecast.Recast
|
|||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
int vi = i * 3;
|
||||
if (vertices[vi] >= rectangle[0] && vertices[vi] < rectangle[2] && vertices[vi + 2] >= rectangle[1]
|
||||
&& vertices[vi + 2] < rectangle[3])
|
||||
if (vertices[vi] >= rectangle[0] && vertices[vi] < rectangle[2] &&
|
||||
vertices[vi + 2] >= rectangle[1] && vertices[vi + 2] < rectangle[3])
|
||||
{
|
||||
yMin = Math.Min(yMin, vertices[vi + 1]);
|
||||
yMax = Math.Max(yMax, vertices[vi + 1]);
|
||||
|
@ -525,7 +525,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
if (MathF.Abs(planes[j][1]) > EPSILON)
|
||||
{
|
||||
float dotNormalPoint = RcVecUtils.Dot(planes[j], point);
|
||||
float dotNormalPoint = RcVec3f.Dot(new RcVec3f(planes[j]), point);
|
||||
float t = (planes[j][3] - dotNormalPoint) / planes[j][1];
|
||||
float y = point.Y + t;
|
||||
bool valid = true;
|
||||
|
@ -729,15 +729,15 @@ namespace DotRecast.Recast
|
|||
private static bool RayTriangleIntersection(RcVec3f point, int plane, float[][] planes, out float y)
|
||||
{
|
||||
y = 0.0f;
|
||||
float t = (planes[plane][3] - RcVecUtils.Dot(planes[plane], point)) / planes[plane][1];
|
||||
float[] s = { point.X, point.Y + t, point.Z };
|
||||
float u = RcVecUtils.Dot(s, planes[plane + 1]) - planes[plane + 1][3];
|
||||
float t = (planes[plane][3] - RcVec3f.Dot(new RcVec3f(planes[plane]), point)) / planes[plane][1];
|
||||
RcVec3f s = new RcVec3f(point.X, point.Y + t, point.Z);
|
||||
float u = RcVec3f.Dot(s, new RcVec3f(planes[plane + 1])) - planes[plane + 1][3];
|
||||
if (u < 0.0f || u > 1.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float v = RcVecUtils.Dot(s, planes[plane + 2]) - planes[plane + 2][3];
|
||||
float v = RcVec3f.Dot(s, new RcVec3f(planes[plane + 2])) - planes[plane + 2][3];
|
||||
if (v < 0.0f)
|
||||
{
|
||||
return false;
|
||||
|
@ -749,7 +749,7 @@ namespace DotRecast.Recast
|
|||
return false;
|
||||
}
|
||||
|
||||
y = s[1];
|
||||
y = s.Y;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -23,8 +23,8 @@ using DotRecast.Core;
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcConstants;
|
||||
using static RcCommons;
|
||||
|
||||
using static RcRecast;
|
||||
|
||||
public static class RcFilters
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public class RcHeightPatch
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -22,29 +22,21 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
/** Represents a heightfield layer within a layer set. */
|
||||
/// A dynamic heightfield representing obstructed space.
|
||||
/// @ingroup recast
|
||||
public class RcHeightfield
|
||||
{
|
||||
/** The width of the heightfield. (Along the x-axis in cell units.) */
|
||||
public readonly int width;
|
||||
public readonly int width; //< The width of the heightfield. (Along the x-axis in cell units.)
|
||||
public readonly int height; //< The height of the heightfield. (Along the z-axis in cell units.)
|
||||
public readonly RcVec3f bmin; //< The minimum bounds in world space. [(x, y, z)]
|
||||
public RcVec3f bmax; //< The maximum bounds in world space. [(x, y, z)]
|
||||
public readonly float cs; //< The size of each cell. (On the xz-plane.)
|
||||
public readonly float ch; //< The height of each cell. (The minimum increment along the y-axis.)
|
||||
public readonly RcSpan[] spans; //< Heightfield of spans (width*height).
|
||||
|
||||
/** The height of the heightfield. (Along the z-axis in cell units.) */
|
||||
public readonly int height;
|
||||
|
||||
/** The minimum bounds in world space. [(x, y, z)] */
|
||||
public readonly RcVec3f bmin;
|
||||
|
||||
/** The maximum bounds in world space. [(x, y, z)] */
|
||||
public RcVec3f bmax;
|
||||
|
||||
/** The size of each cell. (On the xz-plane.) */
|
||||
public readonly float cs;
|
||||
|
||||
/** The height of each cell. (The minimum increment along the y-axis.) */
|
||||
public readonly float ch;
|
||||
|
||||
/** Heightfield of spans (width*height). */
|
||||
public readonly RcSpan[] spans;
|
||||
// memory pool for rcSpan instances.
|
||||
public RcSpanPool pools; //< Linked list of span pools.
|
||||
public RcSpan freelist; //< The next free span.
|
||||
|
||||
/** Border size in cell units */
|
||||
public readonly int borderSize;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public class RcLayerRegion
|
||||
{
|
||||
public int id;
|
||||
public int layerId; // Layer ID
|
||||
public bool @base; // Flag indicating if the region is the base of merged regions.
|
||||
public readonly int index;
|
||||
public List<int> layers;
|
||||
public List<int> neis;
|
||||
public int ymin, ymax;
|
||||
public List<int> layers; // Layer count
|
||||
public List<int> neis; // Neighbour count
|
||||
public byte layerId; // Layer ID
|
||||
public bool @base; // Flag indicating if the region is the base of merged regions.
|
||||
|
||||
public RcLayerRegion(int i)
|
||||
{
|
||||
id = i;
|
||||
ymin = 0xFFFF;
|
||||
layerId = 0xff;
|
||||
index = i;
|
||||
layers = new List<int>();
|
||||
neis = new List<int>();
|
||||
ymin = 0xFFFF;
|
||||
layerId = 0xff;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public class RcLayerSweepSpan
|
||||
{
|
||||
public int ns; // number samples
|
||||
public int id; // region id
|
||||
public int nei; // neighbour id
|
||||
public byte id; // region id
|
||||
public byte nei; // neighbour id
|
||||
};
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -25,15 +25,10 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcConstants;
|
||||
using static RcCommons;
|
||||
using static RcRecast;
|
||||
|
||||
public static class RcLayers
|
||||
{
|
||||
const int RC_MAX_LAYERS = RcConstants.RC_NOT_CONNECTED;
|
||||
const int RC_MAX_NEIS = 16;
|
||||
|
||||
|
||||
private static void AddUnique(List<int> a, int v)
|
||||
{
|
||||
if (!a.Contains(v))
|
||||
|
@ -61,7 +56,6 @@ namespace DotRecast.Recast
|
|||
/// @name Layer, Contour, Polymesh, and Detail Mesh Functions
|
||||
/// @see rcHeightfieldLayer, rcContourSet, rcPolyMesh, rcPolyMeshDetail
|
||||
/// @{
|
||||
|
||||
/// Builds a layer set from the specified compact heightfield.
|
||||
/// @ingroup recast
|
||||
/// @param[in,out] ctx The build context to use during the operation.
|
||||
|
@ -80,10 +74,10 @@ namespace DotRecast.Recast
|
|||
int w = chf.width;
|
||||
int h = chf.height;
|
||||
|
||||
int[] srcReg = new int[chf.spanCount];
|
||||
Array.Fill(srcReg, 0xFF);
|
||||
Span<byte> srcReg = stackalloc byte[chf.spanCount];
|
||||
srcReg.Fill(0xFF);
|
||||
|
||||
int nsweeps = chf.width; // Math.Max(chf.width, chf.height);
|
||||
int nsweeps = chf.width;
|
||||
RcLayerSweepSpan[] sweeps = new RcLayerSweepSpan[nsweeps];
|
||||
for (int i = 0; i < sweeps.Length; i++)
|
||||
{
|
||||
|
@ -91,15 +85,15 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// Partition walkable area into monotone regions.
|
||||
int[] prevCount = new int[256];
|
||||
int regId = 0;
|
||||
Span<int> prevCount = stackalloc int[256];
|
||||
byte regId = 0;
|
||||
|
||||
// Sweep one line at a time.
|
||||
for (int y = borderSize; y < h - borderSize; ++y)
|
||||
{
|
||||
// Collect spans from this row.
|
||||
Array.Fill(prevCount, 0);
|
||||
int sweepId = 0;
|
||||
prevCount.Fill(0);
|
||||
byte sweepId = 0;
|
||||
|
||||
for (int x = borderSize; x < w - borderSize; ++x)
|
||||
{
|
||||
|
@ -111,7 +105,7 @@ namespace DotRecast.Recast
|
|||
if (chf.areas[i] == RC_NULL_AREA)
|
||||
continue;
|
||||
|
||||
int sid = 0xFF;
|
||||
byte sid = 0xFF;
|
||||
|
||||
// -x
|
||||
if (GetCon(ref s, 0) != RC_NOT_CONNECTED)
|
||||
|
@ -136,7 +130,7 @@ namespace DotRecast.Recast
|
|||
int ax = x + GetDirOffsetX(3);
|
||||
int ay = y + GetDirOffsetY(3);
|
||||
int ai = chf.cells[ax + ay * w].index + GetCon(ref s, 3);
|
||||
int nr = srcReg[ai];
|
||||
byte nr = srcReg[ai];
|
||||
if (nr != 0xff)
|
||||
{
|
||||
// Set neighbour when first valid neighbour is encoutered.
|
||||
|
@ -266,9 +260,11 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// Create 2D layers from regions.
|
||||
int layerId = 0;
|
||||
byte layerId = 0;
|
||||
|
||||
List<int> stack = new List<int>();
|
||||
const int MAX_STACK = 64;
|
||||
Span<byte> stack = stackalloc byte[MAX_STACK];
|
||||
int nstack = 0;
|
||||
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
{
|
||||
|
@ -281,14 +277,16 @@ namespace DotRecast.Recast
|
|||
root.layerId = layerId;
|
||||
root.@base = true;
|
||||
|
||||
stack.Add(i);
|
||||
nstack = 0;
|
||||
stack[nstack++] = ((byte)i);
|
||||
|
||||
while (stack.Count != 0)
|
||||
while (0 != nstack)
|
||||
{
|
||||
// Pop front
|
||||
int pop = stack[0]; // TODO : 여기에 stack 처럼 작동하게 했는데, 스택인지는 모르겠음
|
||||
stack.RemoveAt(0);
|
||||
RcLayerRegion reg = regs[pop];
|
||||
RcLayerRegion reg = regs[stack[0]];
|
||||
nstack--;
|
||||
for (int j = 0; j < nstack; ++j)
|
||||
stack[j] = stack[j + 1];
|
||||
|
||||
foreach (int nei in reg.neis)
|
||||
{
|
||||
|
@ -307,8 +305,10 @@ namespace DotRecast.Recast
|
|||
if ((ymax - ymin) >= 255)
|
||||
continue;
|
||||
|
||||
if (nstack < MAX_STACK)
|
||||
{
|
||||
// Deepen
|
||||
stack.Add(nei);
|
||||
stack[nstack++] = (byte)nei;
|
||||
|
||||
// Mark layer id
|
||||
regn.layerId = layerId;
|
||||
|
@ -322,6 +322,7 @@ namespace DotRecast.Recast
|
|||
root.ymax = Math.Max(root.ymax, regn.ymax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layerId++;
|
||||
}
|
||||
|
@ -335,7 +336,7 @@ namespace DotRecast.Recast
|
|||
if (!ri.@base)
|
||||
continue;
|
||||
|
||||
int newId = ri.layerId;
|
||||
byte newId = ri.layerId;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
@ -411,7 +412,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// Compact layerIds
|
||||
int[] remap = new int[256];
|
||||
Span<byte> remap = stackalloc byte[256];
|
||||
|
||||
// Find number of unique layers.
|
||||
layerId = 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public readonly struct RcLevelStackEntry
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -22,178 +22,57 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using static DotRecast.Recast.RcConstants;
|
||||
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcCommons;
|
||||
|
||||
using static RcRecast;
|
||||
using static RcVec;
|
||||
using static EdgeValues;
|
||||
|
||||
public static class RcMeshDetails
|
||||
{
|
||||
public const int MAX_VERTS = 127;
|
||||
public const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts).
|
||||
public const int MAX_VERTS_PER_EDGE = 32;
|
||||
|
||||
public const int RC_UNSET_HEIGHT = RcConstants.RC_SPAN_MAX_HEIGHT;
|
||||
public const int EV_UNDEF = -1;
|
||||
public const int EV_HULL = -2;
|
||||
public const int RC_UNSET_HEIGHT = RC_SPAN_MAX_HEIGHT;
|
||||
|
||||
|
||||
private static float Vdot2(float[] a, float[] b)
|
||||
{
|
||||
return a[0] * b[0] + a[2] * b[2];
|
||||
}
|
||||
|
||||
private static float Vdot2(RcVec3f a, RcVec3f b)
|
||||
{
|
||||
return a.X * b.X + a.Z * b.Z;
|
||||
}
|
||||
|
||||
|
||||
private static float VdistSq2(float[] verts, int p, int q)
|
||||
{
|
||||
float dx = verts[q + 0] - verts[p + 0];
|
||||
float dy = verts[q + 2] - verts[p + 2];
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
private static float Vdist2(float[] verts, int p, int q)
|
||||
{
|
||||
return MathF.Sqrt(VdistSq2(verts, p, q));
|
||||
}
|
||||
|
||||
private static float VdistSq2(float[] p, float[] q)
|
||||
{
|
||||
float dx = q[0] - p[0];
|
||||
float dy = q[2] - p[2];
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
private static float VdistSq2(float[] p, RcVec3f q)
|
||||
{
|
||||
float dx = q.X - p[0];
|
||||
float dy = q.Z - p[2];
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
|
||||
private static float VdistSq2(RcVec3f p, RcVec3f q)
|
||||
{
|
||||
float dx = q.X - p.X;
|
||||
float dy = q.Z - p.Z;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
|
||||
private static float Vdist2(float[] p, float[] q)
|
||||
{
|
||||
return MathF.Sqrt(VdistSq2(p, q));
|
||||
}
|
||||
|
||||
private static float Vdist2(RcVec3f p, RcVec3f q)
|
||||
{
|
||||
return MathF.Sqrt(VdistSq2(p, q));
|
||||
}
|
||||
|
||||
private static float Vdist2(float[] p, RcVec3f q)
|
||||
{
|
||||
return MathF.Sqrt(VdistSq2(p, q));
|
||||
}
|
||||
|
||||
|
||||
private static float VdistSq2(float[] p, float[] verts, int q)
|
||||
{
|
||||
float dx = verts[q + 0] - p[0];
|
||||
float dy = verts[q + 2] - p[2];
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
private static float VdistSq2(RcVec3f p, float[] verts, int q)
|
||||
{
|
||||
float dx = verts[q + 0] - p.X;
|
||||
float dy = verts[q + 2] - p.Z;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
|
||||
private static float Vdist2(float[] p, float[] verts, int q)
|
||||
{
|
||||
return MathF.Sqrt(VdistSq2(p, verts, q));
|
||||
}
|
||||
|
||||
private static float Vdist2(RcVec3f p, float[] verts, int q)
|
||||
{
|
||||
return MathF.Sqrt(VdistSq2(p, verts, q));
|
||||
}
|
||||
|
||||
|
||||
private static float Vcross2(float[] verts, int p1, int p2, int p3)
|
||||
{
|
||||
float u1 = verts[p2 + 0] - verts[p1 + 0];
|
||||
float v1 = verts[p2 + 2] - verts[p1 + 2];
|
||||
float u2 = verts[p3 + 0] - verts[p1 + 0];
|
||||
float v2 = verts[p3 + 2] - verts[p1 + 2];
|
||||
return u1 * v2 - v1 * u2;
|
||||
}
|
||||
|
||||
private static float Vcross2(float[] p1, float[] p2, float[] p3)
|
||||
{
|
||||
float u1 = p2[0] - p1[0];
|
||||
float v1 = p2[2] - p1[2];
|
||||
float u2 = p3[0] - p1[0];
|
||||
float v2 = p3[2] - p1[2];
|
||||
return u1 * v2 - v1 * u2;
|
||||
}
|
||||
|
||||
private static float Vcross2(RcVec3f p1, RcVec3f p2, RcVec3f p3)
|
||||
{
|
||||
float u1 = p2.X - p1.X;
|
||||
float v1 = p2.Z - p1.Z;
|
||||
float u2 = p3.X - p1.X;
|
||||
float v2 = p3.Z - p1.Z;
|
||||
return u1 * v2 - v1 * u2;
|
||||
}
|
||||
|
||||
|
||||
private static bool CircumCircle(float[] verts, int p1, int p2, int p3, ref RcVec3f c, RcAtomicFloat r)
|
||||
public static bool CircumCircle(RcVec3f p1, RcVec3f p2, RcVec3f p3, ref RcVec3f c, out float r)
|
||||
{
|
||||
const float EPS = 1e-6f;
|
||||
// Calculate the circle relative to p1, to avoid some precision issues.
|
||||
var v1 = new RcVec3f();
|
||||
var v2 = RcVecUtils.Subtract(verts, p2, p1);
|
||||
var v3 = RcVecUtils.Subtract(verts, p3, p1);
|
||||
var v2 = p2 - p1;
|
||||
var v3 = p3 - p1;
|
||||
|
||||
float cp = Vcross2(v1, v2, v3);
|
||||
float cp = Cross2(v1, v2, v3);
|
||||
if (MathF.Abs(cp) > EPS)
|
||||
{
|
||||
float v1Sq = Vdot2(v1, v1);
|
||||
float v2Sq = Vdot2(v2, v2);
|
||||
float v3Sq = Vdot2(v3, v3);
|
||||
float v1Sq = Dot2(v1, v1);
|
||||
float v2Sq = Dot2(v2, v2);
|
||||
float v3Sq = Dot2(v3, v3);
|
||||
c.X = (v1Sq * (v2.Z - v3.Z) + v2Sq * (v3.Z - v1.Z) + v3Sq * (v1.Z - v2.Z)) / (2 * cp);
|
||||
c.Y = 0;
|
||||
c.Z = (v1Sq * (v3.X - v2.X) + v2Sq * (v1.X - v3.X) + v3Sq * (v2.X - v1.X)) / (2 * cp);
|
||||
r.Exchange(Vdist2(c, v1));
|
||||
c = RcVecUtils.Add(c, verts, p1);
|
||||
r = Dist2(c, v1);
|
||||
c = c + p1;
|
||||
return true;
|
||||
}
|
||||
|
||||
c = RcVecUtils.Create(verts, p1);
|
||||
r.Exchange(0f);
|
||||
c = p1;
|
||||
r = 0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static float DistPtTri(RcVec3f p, float[] verts, int a, int b, int c)
|
||||
public static float DistPtTri(RcVec3f p, RcVec3f a, RcVec3f b, RcVec3f c)
|
||||
{
|
||||
var v0 = RcVecUtils.Subtract(verts, c, a);
|
||||
var v1 = RcVecUtils.Subtract(verts, b, a);
|
||||
var v2 = RcVecUtils.Subtract(p, verts, a);
|
||||
var v0 = c - a;
|
||||
var v1 = b - a;
|
||||
var v2 = p - a;
|
||||
|
||||
float dot00 = Vdot2(v0, v0);
|
||||
float dot01 = Vdot2(v0, v1);
|
||||
float dot02 = Vdot2(v0, v2);
|
||||
float dot11 = Vdot2(v1, v1);
|
||||
float dot12 = Vdot2(v1, v2);
|
||||
float dot00 = Dot2(v0, v0);
|
||||
float dot01 = Dot2(v0, v1);
|
||||
float dot02 = Dot2(v0, v2);
|
||||
float dot11 = Dot2(v1, v1);
|
||||
float dot12 = Dot2(v1, v2);
|
||||
|
||||
// Compute barycentric coordinates
|
||||
float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
|
||||
|
@ -204,14 +83,14 @@ namespace DotRecast.Recast
|
|||
const float EPS = 1e-4f;
|
||||
if (u >= -EPS && v >= -EPS && (u + v) <= 1 + EPS)
|
||||
{
|
||||
float y = verts[a + 1] + v0.Y * u + v1.Y * v;
|
||||
float y = a.Y + v0.Y * u + v1.Y * v;
|
||||
return MathF.Abs(y - p.Y);
|
||||
}
|
||||
|
||||
return float.MaxValue;
|
||||
}
|
||||
|
||||
private static float DistancePtSeg(float[] verts, int pt, int p, int q)
|
||||
public static float DistancePtSeg(float[] verts, int pt, int p, int q)
|
||||
{
|
||||
float pqx = verts[q + 0] - verts[p + 0];
|
||||
float pqy = verts[q + 1] - verts[p + 1];
|
||||
|
@ -242,7 +121,7 @@ namespace DotRecast.Recast
|
|||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
private static float DistancePtSeg2d(RcVec3f verts, float[] poly, int p, int q)
|
||||
public static float DistancePtSeg2d(RcVec3f verts, float[] poly, int p, int q)
|
||||
{
|
||||
float pqx = poly[q + 0] - poly[p + 0];
|
||||
float pqz = poly[q + 2] - poly[p + 2];
|
||||
|
@ -270,7 +149,7 @@ namespace DotRecast.Recast
|
|||
return dx * dx + dz * dz;
|
||||
}
|
||||
|
||||
private static float DistancePtSeg2d(float[] verts, int pt, float[] poly, int p, int q)
|
||||
public static float DistancePtSeg2d(float[] verts, int pt, float[] poly, int p, int q)
|
||||
{
|
||||
float pqx = poly[q + 0] - poly[p + 0];
|
||||
float pqz = poly[q + 2] - poly[p + 2];
|
||||
|
@ -298,15 +177,15 @@ namespace DotRecast.Recast
|
|||
return dx * dx + dz * dz;
|
||||
}
|
||||
|
||||
private static float DistToTriMesh(RcVec3f p, float[] verts, int nverts, List<int> tris, int ntris)
|
||||
public static float DistToTriMesh(RcVec3f p, float[] verts, int nverts, List<int> tris, int ntris)
|
||||
{
|
||||
float dmin = float.MaxValue;
|
||||
for (int i = 0; i < ntris; ++i)
|
||||
{
|
||||
int va = tris[i * 4 + 0] * 3;
|
||||
int vb = tris[i * 4 + 1] * 3;
|
||||
int vc = tris[i * 4 + 2] * 3;
|
||||
float d = DistPtTri(p, verts, va, vb, vc);
|
||||
RcVec3f va = RcVec.Create(verts, tris[i * 4 + 0] * 3);
|
||||
RcVec3f vb = RcVec.Create(verts, tris[i * 4 + 1] * 3);
|
||||
RcVec3f vc = RcVec.Create(verts, tris[i * 4 + 2] * 3);
|
||||
float d = DistPtTri(p, va, vb, vc);
|
||||
if (d < dmin)
|
||||
{
|
||||
dmin = d;
|
||||
|
@ -321,7 +200,7 @@ namespace DotRecast.Recast
|
|||
return dmin;
|
||||
}
|
||||
|
||||
private static float DistToPoly(int nvert, float[] verts, RcVec3f p)
|
||||
public static float DistToPoly(int nvert, float[] verts, RcVec3f p)
|
||||
{
|
||||
float dmin = float.MaxValue;
|
||||
int i, j;
|
||||
|
@ -342,7 +221,7 @@ namespace DotRecast.Recast
|
|||
return c ? -dmin : dmin;
|
||||
}
|
||||
|
||||
private static int GetHeight(float fx, float fy, float fz, float cs, float ics, float ch, int radius,
|
||||
public static int GetHeight(float fx, float fy, float fz, float cs, float ics, float ch, int radius,
|
||||
RcHeightPatch hp)
|
||||
{
|
||||
int ix = (int)MathF.Floor(fx * ics + 0.01f);
|
||||
|
@ -425,7 +304,7 @@ namespace DotRecast.Recast
|
|||
return h;
|
||||
}
|
||||
|
||||
private static int FindEdge(List<int> edges, int s, int t)
|
||||
public static int FindEdge(List<int> edges, int s, int t)
|
||||
{
|
||||
for (int i = 0; i < edges.Count / 4; i++)
|
||||
{
|
||||
|
@ -439,7 +318,7 @@ namespace DotRecast.Recast
|
|||
return EV_UNDEF;
|
||||
}
|
||||
|
||||
private static void AddEdge(RcContext ctx, List<int> edges, int maxEdges, int s, int t, int l, int r)
|
||||
public static void AddEdge(RcContext ctx, List<int> edges, int maxEdges, int s, int t, int l, int r)
|
||||
{
|
||||
if (edges.Count / 4 >= maxEdges)
|
||||
{
|
||||
|
@ -457,7 +336,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
private static void UpdateLeftFace(List<int> edges, int e, int s, int t, int f)
|
||||
public static void UpdateLeftFace(List<int> edges, int e, int s, int t, int f)
|
||||
{
|
||||
if (edges[e + 0] == s && edges[e + 1] == t && edges[e + 2] == EV_UNDEF)
|
||||
{
|
||||
|
@ -469,13 +348,13 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
private static bool OverlapSegSeg2d(float[] verts, int a, int b, int c, int d)
|
||||
public static bool OverlapSegSeg2d(float[] verts, int a, int b, int c, int d)
|
||||
{
|
||||
float a1 = Vcross2(verts, a, b, d);
|
||||
float a2 = Vcross2(verts, a, b, c);
|
||||
float a1 = Cross2(verts, a, b, d);
|
||||
float a2 = Cross2(verts, a, b, c);
|
||||
if (a1 * a2 < 0.0f)
|
||||
{
|
||||
float a3 = Vcross2(verts, c, d, a);
|
||||
float a3 = Cross2(verts, c, d, a);
|
||||
float a4 = a3 + a2 - a1;
|
||||
if (a3 * a4 < 0.0f)
|
||||
{
|
||||
|
@ -486,7 +365,7 @@ namespace DotRecast.Recast
|
|||
return false;
|
||||
}
|
||||
|
||||
private static bool OverlapEdges(float[] pts, List<int> edges, int s1, int t1)
|
||||
public static bool OverlapEdges(float[] pts, List<int> edges, int s1, int t1)
|
||||
{
|
||||
for (int i = 0; i < edges.Count / 4; ++i)
|
||||
{
|
||||
|
@ -507,7 +386,7 @@ namespace DotRecast.Recast
|
|||
return false;
|
||||
}
|
||||
|
||||
static int CompleteFacet(RcContext ctx, float[] pts, int npts, List<int> edges, int maxEdges, int nfaces, int e)
|
||||
public static int CompleteFacet(RcContext ctx, float[] pts, int npts, List<int> edges, int maxEdges, int nfaces, int e)
|
||||
{
|
||||
const float EPS = 1e-5f;
|
||||
|
||||
|
@ -534,7 +413,7 @@ namespace DotRecast.Recast
|
|||
// Find best point on left of edge.
|
||||
int pt = npts;
|
||||
RcVec3f c = new RcVec3f();
|
||||
RcAtomicFloat r = new RcAtomicFloat(-1f);
|
||||
float r = -1f;
|
||||
for (int u = 0; u < npts; ++u)
|
||||
{
|
||||
if (u == s || u == t)
|
||||
|
@ -542,28 +421,32 @@ namespace DotRecast.Recast
|
|||
continue;
|
||||
}
|
||||
|
||||
if (Vcross2(pts, s * 3, t * 3, u * 3) > EPS)
|
||||
RcVec3f vs = RcVec.Create(pts, s * 3);
|
||||
RcVec3f vt = RcVec.Create(pts, t * 3);
|
||||
RcVec3f vu = RcVec.Create(pts, u * 3);
|
||||
|
||||
if (Cross2(vs, vt, vu) > EPS)
|
||||
{
|
||||
if (r.Get() < 0)
|
||||
if (r < 0)
|
||||
{
|
||||
// The circle is not updated yet, do it now.
|
||||
pt = u;
|
||||
CircumCircle(pts, s * 3, t * 3, u * 3, ref c, r);
|
||||
CircumCircle(vs, vt, vu, ref c, out r);
|
||||
continue;
|
||||
}
|
||||
|
||||
float d = Vdist2(c, pts, u * 3);
|
||||
float d = Dist2(c, vu);
|
||||
float tol = 0.001f;
|
||||
if (d > r.Get() * (1 + tol))
|
||||
if (d > r * (1 + tol))
|
||||
{
|
||||
// Outside current circumcircle, skip.
|
||||
continue;
|
||||
}
|
||||
else if (d < r.Get() * (1 - tol))
|
||||
else if (d < r * (1 - tol))
|
||||
{
|
||||
// Inside safe circumcircle, update circle.
|
||||
pt = u;
|
||||
CircumCircle(pts, s * 3, t * 3, u * 3, ref c, r);
|
||||
CircumCircle(vs, vt, vu, ref c, out r);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -581,7 +464,7 @@ namespace DotRecast.Recast
|
|||
|
||||
// Edge is valid.
|
||||
pt = u;
|
||||
CircumCircle(pts, s * 3, t * 3, u * 3, ref c, r);
|
||||
CircumCircle(vs, vt, vu, ref c, out r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -624,7 +507,7 @@ namespace DotRecast.Recast
|
|||
return nfaces;
|
||||
}
|
||||
|
||||
private static void DelaunayHull(RcContext ctx, int npts, float[] pts, int nhull, int[] hull, List<int> tris)
|
||||
public static void DelaunayHull(RcContext ctx, int npts, float[] pts, int nhull, int[] hull, List<int> tris)
|
||||
{
|
||||
int nfaces = 0;
|
||||
int maxEdges = npts * 10;
|
||||
|
@ -720,7 +603,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// Calculate minimum extend of the polygon.
|
||||
private static float PolyMinExtent(float[] verts, int nverts)
|
||||
public static float PolyMinExtent(float[] verts, int nverts)
|
||||
{
|
||||
float minDist = float.MaxValue;
|
||||
for (int i = 0; i < nverts; i++)
|
||||
|
@ -746,7 +629,7 @@ namespace DotRecast.Recast
|
|||
return MathF.Sqrt(minDist);
|
||||
}
|
||||
|
||||
private static void TriangulateHull(int nverts, float[] verts, int nhull, int[] hull, int nin, List<int> tris)
|
||||
public static void TriangulateHull(int nverts, float[] verts, int nhull, int[] hull, int nin, List<int> tris)
|
||||
{
|
||||
int start = 0, left = 1, right = nhull - 1;
|
||||
|
||||
|
@ -766,7 +649,7 @@ namespace DotRecast.Recast
|
|||
int pv = hull[pi] * 3;
|
||||
int cv = hull[i] * 3;
|
||||
int nv = hull[ni] * 3;
|
||||
float d = Vdist2(verts, pv, cv) + Vdist2(verts, cv, nv) + Vdist2(verts, nv, pv);
|
||||
float d = Dist2(verts, pv, cv) + Dist2(verts, cv, nv) + Dist2(verts, nv, pv);
|
||||
if (d < dmin)
|
||||
{
|
||||
start = i;
|
||||
|
@ -796,8 +679,8 @@ namespace DotRecast.Recast
|
|||
int nvleft = hull[nleft] * 3;
|
||||
int cvright = hull[right] * 3;
|
||||
int nvright = hull[nright] * 3;
|
||||
float dleft = Vdist2(verts, cvleft, nvleft) + Vdist2(verts, nvleft, cvright);
|
||||
float dright = Vdist2(verts, cvright, nvright) + Vdist2(verts, cvleft, nvright);
|
||||
float dleft = Dist2(verts, cvleft, nvleft) + Dist2(verts, nvleft, cvright);
|
||||
float dright = Dist2(verts, cvright, nvright) + Dist2(verts, cvleft, nvright);
|
||||
|
||||
if (dleft < dright)
|
||||
{
|
||||
|
@ -818,33 +701,37 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
private static float GetJitterX(int i)
|
||||
public static float GetJitterX(int i)
|
||||
{
|
||||
return (((i * 0x8da6b343) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
|
||||
}
|
||||
|
||||
private static float GetJitterY(int i)
|
||||
public static float GetJitterY(int i)
|
||||
{
|
||||
return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
|
||||
}
|
||||
|
||||
static int BuildPolyDetail(RcContext ctx, float[] @in, int nin, float sampleDist, float sampleMaxError,
|
||||
int heightSearchRadius, RcCompactHeightfield chf, RcHeightPatch hp, float[] verts, List<int> tris)
|
||||
public static int BuildPolyDetail(RcContext ctx, float[] @in, int nin,
|
||||
float sampleDist, float sampleMaxError,
|
||||
int heightSearchRadius, RcCompactHeightfield chf,
|
||||
RcHeightPatch hp, float[] verts,
|
||||
ref List<int> tris, ref List<int> edges, ref List<int> samples)
|
||||
{
|
||||
List<int> samples = new List<int>(512);
|
||||
|
||||
int nverts = 0;
|
||||
const int MAX_VERTS = 127;
|
||||
const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts).
|
||||
const int MAX_VERTS_PER_EDGE = 32;
|
||||
float[] edge = new float[(MAX_VERTS_PER_EDGE + 1) * 3];
|
||||
int[] hull = new int[MAX_VERTS];
|
||||
int nhull = 0;
|
||||
|
||||
nverts = nin;
|
||||
int nverts = nin;
|
||||
|
||||
for (int i = 0; i < nin; ++i)
|
||||
{
|
||||
RcVecUtils.Copy(verts, i * 3, @in, i * 3);
|
||||
RcVec.Copy(verts, i * 3, @in, i * 3);
|
||||
}
|
||||
|
||||
edges.Clear();
|
||||
tris.Clear();
|
||||
|
||||
float cs = chf.cs;
|
||||
|
@ -957,7 +844,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
for (int k = nidx - 2; k > 0; --k)
|
||||
{
|
||||
RcVecUtils.Copy(verts, nverts * 3, edge, idx[k] * 3);
|
||||
RcVec.Copy(verts, nverts * 3, edge, idx[k] * 3);
|
||||
hull[nhull++] = nverts;
|
||||
nverts++;
|
||||
}
|
||||
|
@ -966,7 +853,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
for (int k = 1; k < nidx - 1; ++k)
|
||||
{
|
||||
RcVecUtils.Copy(verts, nverts * 3, edge, idx[k] * 3);
|
||||
RcVec.Copy(verts, nverts * 3, edge, idx[k] * 3);
|
||||
hull[nhull++] = nverts;
|
||||
nverts++;
|
||||
}
|
||||
|
@ -997,12 +884,12 @@ namespace DotRecast.Recast
|
|||
if (sampleDist > 0)
|
||||
{
|
||||
// Create sample locations in a grid.
|
||||
RcVec3f bmin = RcVecUtils.Create(@in);
|
||||
RcVec3f bmax = RcVecUtils.Create(@in);
|
||||
RcVec3f bmin = new RcVec3f(@in);
|
||||
RcVec3f bmax = new RcVec3f(@in);
|
||||
for (int i = 1; i < nin; ++i)
|
||||
{
|
||||
bmin = RcVecUtils.Min(bmin, @in, i * 3);
|
||||
bmax = RcVecUtils.Max(bmax, @in, i * 3);
|
||||
bmin = RcVec3f.Min(bmin, RcVec.Create(@in, i * 3));
|
||||
bmax = RcVec3f.Max(bmax, RcVec.Create(@in, i * 3));
|
||||
}
|
||||
|
||||
int x0 = (int)MathF.Floor(bmin.X / sampleDist);
|
||||
|
@ -1105,7 +992,7 @@ namespace DotRecast.Recast
|
|||
return nverts;
|
||||
}
|
||||
|
||||
static bool OnHull(int a, int b, int nhull, int[] hull)
|
||||
public static bool OnHull(int a, int b, int nhull, int[] hull)
|
||||
{
|
||||
// All internal sampled points come after the hull so we can early out for those.
|
||||
if (a >= nhull || b >= nhull)
|
||||
|
@ -1121,7 +1008,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
// Find edges that lie on hull and mark them as such.
|
||||
static void SetTriFlags(List<int> tris, int nhull, int[] hull)
|
||||
public static void SetTriFlags(List<int> tris, int nhull, int[] hull)
|
||||
{
|
||||
// Matches DT_DETAIL_EDGE_BOUNDARY
|
||||
const int DETAIL_EDGE_BOUNDARY = 0x1;
|
||||
|
@ -1140,7 +1027,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
|
||||
static void SeedArrayWithPolyCenter(RcContext ctx, RcCompactHeightfield chf, int[] meshpoly, int poly, int npoly,
|
||||
public static void SeedArrayWithPolyCenter(RcContext ctx, RcCompactHeightfield chf, int[] meshpoly, int poly, int npoly,
|
||||
int[] verts, int bs, RcHeightPatch hp, List<int> array)
|
||||
{
|
||||
// Note: Reads to the compact heightfield are offset by border size (bs)
|
||||
|
@ -1289,22 +1176,25 @@ namespace DotRecast.Recast
|
|||
hp.data[cx - hp.xmin + (cy - hp.ymin) * hp.width] = cs2.y;
|
||||
}
|
||||
|
||||
const int RETRACT_SIZE = 256;
|
||||
|
||||
static void Push3(List<int> queue, int v1, int v2, int v3)
|
||||
public static void Push3(List<int> queue, int v1, int v2, int v3)
|
||||
{
|
||||
queue.Add(v1);
|
||||
queue.Add(v2);
|
||||
queue.Add(v3);
|
||||
}
|
||||
|
||||
static void GetHeightData(RcContext ctx, RcCompactHeightfield chf, int[] meshpolys, int poly, int npoly, int[] verts,
|
||||
int bs, RcHeightPatch hp, int region)
|
||||
public static void GetHeightData(RcContext ctx, RcCompactHeightfield chf,
|
||||
int[] meshpolys, int poly, int npoly,
|
||||
int[] verts, int bs,
|
||||
ref RcHeightPatch hp, ref List<int> queue,
|
||||
int region)
|
||||
{
|
||||
// Note: Reads to the compact heightfield are offset by border size (bs)
|
||||
// since border size offset is already removed from the polymesh vertices.
|
||||
|
||||
List<int> queue = new List<int>(512);
|
||||
queue.Clear();
|
||||
// Set all heights to RC_UNSET_HEIGHT.
|
||||
Array.Fill(hp.data, RC_UNSET_HEIGHT, 0, (hp.width * hp.height) - (0));
|
||||
|
||||
bool empty = true;
|
||||
|
@ -1370,6 +1260,7 @@ namespace DotRecast.Recast
|
|||
SeedArrayWithPolyCenter(ctx, chf, meshpolys, poly, npoly, verts, bs, hp, queue);
|
||||
}
|
||||
|
||||
const int RETRACT_SIZE = 256;
|
||||
int head = 0;
|
||||
|
||||
// We assume the seed is centered in the polygon, so a BFS to collect
|
||||
|
@ -1441,7 +1332,10 @@ namespace DotRecast.Recast
|
|||
int borderSize = mesh.borderSize;
|
||||
int heightSearchRadius = (int)Math.Max(1, MathF.Ceiling(mesh.maxEdgeError));
|
||||
|
||||
List<int> edges = new List<int>(64);
|
||||
List<int> tris = new List<int>(512);
|
||||
List<int> arr = new List<int>(512);
|
||||
List<int> samples = new List<int>(512);
|
||||
float[] verts = new float[256 * 3];
|
||||
RcHeightPatch hp = new RcHeightPatch();
|
||||
int nPolyVerts = 0;
|
||||
|
@ -1526,18 +1420,20 @@ namespace DotRecast.Recast
|
|||
hp.ymin = bounds[i * 4 + 2];
|
||||
hp.width = bounds[i * 4 + 1] - bounds[i * 4 + 0];
|
||||
hp.height = bounds[i * 4 + 3] - bounds[i * 4 + 2];
|
||||
GetHeightData(ctx, chf, mesh.polys, p, npoly, mesh.verts, borderSize, hp, mesh.regs[i]);
|
||||
GetHeightData(ctx, chf, mesh.polys, p, npoly, mesh.verts, borderSize, ref hp, ref arr, mesh.regs[i]);
|
||||
|
||||
// Build detail mesh.
|
||||
int nverts = BuildPolyDetail(ctx, poly, npoly, sampleDist, sampleMaxError, heightSearchRadius, chf, hp,
|
||||
verts, tris);
|
||||
int nverts = BuildPolyDetail(ctx, poly, npoly,
|
||||
sampleDist, sampleMaxError,
|
||||
heightSearchRadius, chf, hp,
|
||||
verts, ref tris,
|
||||
ref edges, ref samples);
|
||||
|
||||
// Move detail verts to world space.
|
||||
for (int j = 0; j < nverts; ++j)
|
||||
{
|
||||
verts[j * 3 + 0] += orig.X;
|
||||
verts[j * 3 + 1] += orig.Y + chf.ch; // Is this offset necessary? See
|
||||
// https://groups.google.com/d/msg/recastnavigation/UQFN6BGCcV0/-1Ny4koOBpkJ
|
||||
verts[j * 3 + 2] += orig.Z;
|
||||
}
|
||||
|
||||
|
@ -1614,7 +1510,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
|
||||
/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail
|
||||
private static RcPolyMeshDetail MergePolyMeshDetails(RcContext ctx, RcPolyMeshDetail[] meshes, int nmeshes)
|
||||
public static RcPolyMeshDetail MergePolyMeshDetails(RcContext ctx, RcPolyMeshDetail[] meshes, int nmeshes)
|
||||
{
|
||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MERGE_POLYMESHDETAIL);
|
||||
|
||||
|
@ -1665,7 +1561,7 @@ namespace DotRecast.Recast
|
|||
|
||||
for (int k = 0; k < dm.nverts; ++k)
|
||||
{
|
||||
RcVecUtils.Copy(mesh.verts, mesh.nverts * 3, dm.verts, k * 3);
|
||||
RcVec.Copy(mesh.verts, mesh.nverts * 3, dm.verts, k * 3);
|
||||
mesh.nverts++;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -24,7 +24,7 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcConstants;
|
||||
using static RcRecast;
|
||||
|
||||
public static class RcMeshs
|
||||
{
|
||||
|
@ -715,8 +715,13 @@ namespace DotRecast.Recast
|
|||
int nv = CountPolyVerts(mesh.polys, p, nvp);
|
||||
bool hasRem = false;
|
||||
for (int j = 0; j < nv; ++j)
|
||||
{
|
||||
if (mesh.polys[p + j] == rem)
|
||||
{
|
||||
hasRem = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasRem)
|
||||
{
|
||||
// Collect edges which does not touch the removed vertex.
|
||||
|
@ -956,7 +961,7 @@ namespace DotRecast.Recast
|
|||
mesh.npolys++;
|
||||
if (mesh.npolys > maxTris)
|
||||
{
|
||||
throw new Exception("removeVertex: Too many polygons " + mesh.npolys + " (max:" + maxTris + ".");
|
||||
throw new Exception($"removeVertex: Too many polygons {mesh.npolys} max:({maxTris}).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1033,11 +1038,23 @@ namespace DotRecast.Recast
|
|||
// Triangulate contour
|
||||
for (int j = 0; j < cont.nverts; ++j)
|
||||
indices[j] = j;
|
||||
|
||||
int ntris = Triangulate(cont.nverts, cont.verts, indices, tris);
|
||||
if (ntris <= 0)
|
||||
{
|
||||
// Bad triangulation, should not happen.
|
||||
ctx.Warn("buildPolyMesh: Bad triangulation Contour " + i + ".");
|
||||
/*
|
||||
printf("\tconst float bmin[3] = {%ff,%ff,%ff};\n", cset.bmin[0], cset.bmin[1], cset.bmin[2]);
|
||||
printf("\tconst float cs = %ff;\n", cset.cs);
|
||||
printf("\tconst float ch = %ff;\n", cset.ch);
|
||||
printf("\tconst int verts[] = {\n");
|
||||
for (int k = 0; k < cont.nverts; ++k)
|
||||
{
|
||||
const int* v = &cont.verts[k*4];
|
||||
printf("\t\t%d,%d,%d,%d,\n", v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
printf("\t};\n\tconst int nverts = sizeof(verts)/(sizeof(int)*4);\n");*/
|
||||
ctx.Warn($"BuildPolyMesh: Bad triangulation Contour {i}.");
|
||||
ntris = -ntris;
|
||||
}
|
||||
|
||||
|
@ -1198,14 +1215,12 @@ namespace DotRecast.Recast
|
|||
|
||||
if (mesh.nverts > MAX_MESH_VERTS_POLY)
|
||||
{
|
||||
throw new Exception("rcBuildPolyMesh: The resulting mesh has too many vertices " + mesh.nverts
|
||||
+ " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted.");
|
||||
throw new Exception($"BuildPolyMesh: The resulting mesh has too many vertices {mesh.nverts} (max {MAX_MESH_VERTS_POLY}). Data can be corrupted.");
|
||||
}
|
||||
|
||||
if (mesh.npolys > MAX_MESH_VERTS_POLY)
|
||||
{
|
||||
throw new Exception("rcBuildPolyMesh: The resulting mesh has too many polygons " + mesh.npolys
|
||||
+ " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted.");
|
||||
throw new Exception($"BuildPolyMesh: The resulting mesh has too many polygons {mesh.npolys} (max {MAX_MESH_VERTS_POLY}). Data can be corrupted.");
|
||||
}
|
||||
|
||||
return mesh;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public enum RcPartition
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Linq;
|
||||
using System.Linq;
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
Recast4J Copyright (c) 2015 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -17,6 +17,7 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
@ -30,9 +31,9 @@ namespace DotRecast.Recast
|
|||
hitTime = 0.0f;
|
||||
foreach (RcBuilderResult result in results)
|
||||
{
|
||||
if (result.GetMeshDetail() != null)
|
||||
if (result.MeshDetail != null)
|
||||
{
|
||||
if (Raycast(result.GetMesh(), result.GetMeshDetail(), src, dst, out hitTime))
|
||||
if (Raycast(result.Mesh, result.MeshDetail, src, dst, out hitTime))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -45,6 +46,7 @@ namespace DotRecast.Recast
|
|||
private static bool Raycast(RcPolyMesh poly, RcPolyMeshDetail meshDetail, RcVec3f sp, RcVec3f sq, out float hitTime)
|
||||
{
|
||||
hitTime = 0;
|
||||
Span<RcVec3f> tempVs = stackalloc RcVec3f[3];
|
||||
if (meshDetail != null)
|
||||
{
|
||||
for (int i = 0; i < meshDetail.nmeshes; ++i)
|
||||
|
@ -57,7 +59,7 @@ namespace DotRecast.Recast
|
|||
int tris = btris * 4;
|
||||
for (int j = 0; j < ntris; ++j)
|
||||
{
|
||||
RcVec3f[] vs = new RcVec3f[3];
|
||||
Span<RcVec3f> vs = tempVs;
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
vs[k].X = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -21,10 +21,12 @@ freely, subject to the following restrictions:
|
|||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using static DotRecast.Recast.RcConstants;
|
||||
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcRecast;
|
||||
|
||||
public static class RcRasterizations
|
||||
{
|
||||
/// Check whether two bounding boxes overlap
|
||||
|
@ -42,6 +44,63 @@ namespace DotRecast.Recast
|
|||
aMin.Z <= bMax.Z && aMax.Z >= bMin.Z;
|
||||
}
|
||||
|
||||
/// Allocates a new span in the heightfield.
|
||||
/// Use a memory pool and free list to minimize actual allocations.
|
||||
///
|
||||
/// @param[in] heightfield The heightfield
|
||||
/// @returns A pointer to the allocated or re-used span memory.
|
||||
private static RcSpan AllocSpan(RcHeightfield heightfield)
|
||||
{
|
||||
// If necessary, allocate new page and update the freelist.
|
||||
if (heightfield.freelist == null || heightfield.freelist.next == null)
|
||||
{
|
||||
// Create new page.
|
||||
// Allocate memory for the new pool.
|
||||
RcSpanPool spanPool = new RcSpanPool();
|
||||
if (spanPool == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add the pool into the list of pools.
|
||||
spanPool.next = heightfield.pools;
|
||||
heightfield.pools = spanPool;
|
||||
|
||||
// Add new spans to the free list.
|
||||
RcSpan freeList = heightfield.freelist;
|
||||
int head = 0;
|
||||
int it = RC_SPANS_PER_POOL;
|
||||
do
|
||||
{
|
||||
--it;
|
||||
spanPool.items[it].next = freeList;
|
||||
freeList = spanPool.items[it];
|
||||
} while (it != head);
|
||||
|
||||
heightfield.freelist = spanPool.items[it];
|
||||
}
|
||||
|
||||
// Pop item from the front of the free list.
|
||||
RcSpan newSpan = heightfield.freelist;
|
||||
heightfield.freelist = heightfield.freelist.next;
|
||||
return newSpan;
|
||||
}
|
||||
|
||||
/// Releases the memory used by the span back to the heightfield, so it can be re-used for new spans.
|
||||
/// @param[in] heightfield The heightfield.
|
||||
/// @param[in] span A pointer to the span to free
|
||||
private static void FreeSpan(RcHeightfield heightfield, RcSpan span)
|
||||
{
|
||||
if (span == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the span to the front of the free list.
|
||||
span.next = heightfield.freelist;
|
||||
heightfield.freelist = span;
|
||||
}
|
||||
|
||||
|
||||
/// Adds a span to the heightfield. If the new span overlaps existing spans,
|
||||
/// it will merge the new span with the existing ones.
|
||||
|
@ -150,13 +209,13 @@ namespace DotRecast.Recast
|
|||
/// @param[out] outVerts2Count The number of resulting polygon 2 vertices
|
||||
/// @param[in] axisOffset THe offset along the specified axis
|
||||
/// @param[in] axis The separating axis
|
||||
private static void DividePoly(float[] inVerts, int inVertsOffset, int inVertsCount,
|
||||
private static void DividePoly(Span<float> inVerts, int inVertsOffset, int inVertsCount,
|
||||
int outVerts1, out int outVerts1Count,
|
||||
int outVerts2, out int outVerts2Count,
|
||||
float axisOffset, int axis)
|
||||
{
|
||||
// How far positive or negative away from the separating axis is each vertex.
|
||||
float[] inVertAxisDelta = new float[12];
|
||||
Span<float> inVertAxisDelta = stackalloc float[12];
|
||||
for (int inVert = 0; inVert < inVertsCount; ++inVert)
|
||||
{
|
||||
inVertAxisDelta[inVert] = axisOffset - inVerts[inVertsOffset + inVert * 3 + axis];
|
||||
|
@ -174,7 +233,7 @@ namespace DotRecast.Recast
|
|||
inVerts[outVerts1 + poly1Vert * 3 + 0] = inVerts[inVertsOffset + inVertB * 3 + 0] + (inVerts[inVertsOffset + inVertA * 3 + 0] - inVerts[inVertsOffset + inVertB * 3 + 0]) * s;
|
||||
inVerts[outVerts1 + poly1Vert * 3 + 1] = inVerts[inVertsOffset + inVertB * 3 + 1] + (inVerts[inVertsOffset + inVertA * 3 + 1] - inVerts[inVertsOffset + inVertB * 3 + 1]) * s;
|
||||
inVerts[outVerts1 + poly1Vert * 3 + 2] = inVerts[inVertsOffset + inVertB * 3 + 2] + (inVerts[inVertsOffset + inVertA * 3 + 2] - inVerts[inVertsOffset + inVertB * 3 + 2]) * s;
|
||||
RcVecUtils.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, outVerts1 + poly1Vert * 3);
|
||||
RcVec.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, outVerts1 + poly1Vert * 3);
|
||||
poly1Vert++;
|
||||
poly2Vert++;
|
||||
|
||||
|
@ -182,12 +241,12 @@ namespace DotRecast.Recast
|
|||
// since these were already added above
|
||||
if (inVertAxisDelta[inVertA] > 0)
|
||||
{
|
||||
RcVecUtils.Copy(inVerts, outVerts1 + poly1Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||
RcVec.Copy(inVerts, outVerts1 + poly1Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||
poly1Vert++;
|
||||
}
|
||||
else if (inVertAxisDelta[inVertA] < 0)
|
||||
{
|
||||
RcVecUtils.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||
RcVec.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||
poly2Vert++;
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +255,7 @@ namespace DotRecast.Recast
|
|||
// add the i'th point to the right polygon. Addition is done even for points on the dividing line
|
||||
if (inVertAxisDelta[inVertA] >= 0)
|
||||
{
|
||||
RcVecUtils.Copy(inVerts, outVerts1 + poly1Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||
RcVec.Copy(inVerts, outVerts1 + poly1Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||
poly1Vert++;
|
||||
if (inVertAxisDelta[inVertA] != 0)
|
||||
{
|
||||
|
@ -204,7 +263,7 @@ namespace DotRecast.Recast
|
|||
}
|
||||
}
|
||||
|
||||
RcVecUtils.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||
RcVec.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||
poly2Vert++;
|
||||
}
|
||||
}
|
||||
|
@ -236,13 +295,13 @@ namespace DotRecast.Recast
|
|||
int flagMergeThreshold)
|
||||
{
|
||||
// Calculate the bounding box of the triangle.
|
||||
RcVec3f triBBMin = RcVecUtils.Create(verts, v0 * 3);
|
||||
triBBMin = RcVecUtils.Min(triBBMin, verts, v1 * 3);
|
||||
triBBMin = RcVecUtils.Min(triBBMin, verts, v2 * 3);
|
||||
RcVec3f triBBMin = RcVec.Create(verts, v0 * 3);
|
||||
triBBMin = RcVec3f.Min(triBBMin, RcVec.Create(verts, v1 * 3));
|
||||
triBBMin = RcVec3f.Min(triBBMin, RcVec.Create(verts, v2 * 3));
|
||||
|
||||
RcVec3f triBBMax = RcVecUtils.Create(verts, v0 * 3);
|
||||
triBBMax = RcVecUtils.Max(triBBMax, verts, v1 * 3);
|
||||
triBBMax = RcVecUtils.Max(triBBMax, verts, v2 * 3);
|
||||
RcVec3f triBBMax = RcVec.Create(verts, v0 * 3);
|
||||
triBBMax = RcVec3f.Max(triBBMax, RcVec.Create(verts, v1 * 3));
|
||||
triBBMax = RcVec3f.Max(triBBMax, RcVec.Create(verts, v2 * 3));
|
||||
|
||||
// If the triangle does not touch the bounding box of the heightfield, skip the triangle.
|
||||
if (!OverlapBounds(triBBMin, triBBMax, heightfieldBBMin, heightfieldBBMax))
|
||||
|
@ -263,15 +322,15 @@ namespace DotRecast.Recast
|
|||
z1 = Math.Clamp(z1, 0, h - 1);
|
||||
|
||||
// Clip the triangle into all grid cells it touches.
|
||||
float[] buf = new float[7 * 3 * 4];
|
||||
Span<float> buf = stackalloc float[7 * 3 * 4];
|
||||
int @in = 0;
|
||||
int inRow = 7 * 3;
|
||||
int p1 = inRow + 7 * 3;
|
||||
int p2 = p1 + 7 * 3;
|
||||
|
||||
RcVecUtils.Copy(buf, 0, verts, v0 * 3);
|
||||
RcVecUtils.Copy(buf, 3, verts, v1 * 3);
|
||||
RcVecUtils.Copy(buf, 6, verts, v2 * 3);
|
||||
RcVec.Copy(buf, 0, verts, v0 * 3);
|
||||
RcVec.Copy(buf, 3, verts, v1 * 3);
|
||||
RcVec.Copy(buf, 6, verts, v2 * 3);
|
||||
int nvRow;
|
||||
int nvIn = 3;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -24,10 +24,81 @@ using DotRecast.Core.Numerics;
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcConstants;
|
||||
|
||||
public static class RcCommons
|
||||
public static class RcRecast
|
||||
{
|
||||
/// Represents the null area.
|
||||
/// When a data element is given this value it is considered to no longer be
|
||||
/// assigned to a usable area. (E.g. It is un-walkable.)
|
||||
public const int RC_NULL_AREA = 0;
|
||||
|
||||
/// The default area id used to indicate a walkable polygon.
|
||||
/// This is also the maximum allowed area id, and the only non-null area id
|
||||
/// recognized by some steps in the build process.
|
||||
public const int RC_WALKABLE_AREA = 63;
|
||||
|
||||
/// The value returned by #rcGetCon if the specified direction is not connected
|
||||
/// to another span. (Has no neighbor.)
|
||||
public const int RC_NOT_CONNECTED = 0x3f;
|
||||
|
||||
/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax.
|
||||
public const int RC_SPAN_HEIGHT_BITS = 20;
|
||||
|
||||
/// Defines the maximum value for rcSpan::smin and rcSpan::smax.
|
||||
public const int RC_SPAN_MAX_HEIGHT = (1 << RC_SPAN_HEIGHT_BITS) - 1;
|
||||
|
||||
/// The number of spans allocated per span spool.
|
||||
/// @see rcSpanPool
|
||||
public const int RC_SPANS_PER_POOL = 2048;
|
||||
|
||||
// Must be 255 or smaller (not 256) because layer IDs are stored as
|
||||
// a byte where 255 is a special value.
|
||||
public const int RC_MAX_LAYERS = RC_NOT_CONNECTED;
|
||||
public const int RC_MAX_NEIS = 16;
|
||||
|
||||
/// Heighfield border flag.
|
||||
/// If a heightfield region ID has this bit set, then the region is a border
|
||||
/// region and its spans are considered unwalkable.
|
||||
/// (Used during the region and contour build process.)
|
||||
/// @see rcCompactSpan::reg
|
||||
public const int RC_BORDER_REG = 0x8000;
|
||||
|
||||
/// Polygon touches multiple regions.
|
||||
/// If a polygon has this region ID it was merged with or created
|
||||
/// from polygons of different regions during the polymesh
|
||||
/// build step that removes redundant border vertices.
|
||||
/// (Used during the polymesh and detail polymesh build processes)
|
||||
/// @see rcPolyMesh::regs
|
||||
public const int RC_MULTIPLE_REGS = 0;
|
||||
|
||||
// Border vertex flag.
|
||||
/// If a region ID has this bit set, then the associated element lies on
|
||||
/// a tile border. If a contour vertex's region ID has this bit set, the
|
||||
/// vertex will later be removed in order to match the segments and vertices
|
||||
/// at tile boundaries.
|
||||
/// (Used during the build process.)
|
||||
/// @see rcCompactSpan::reg, #rcContour::verts, #rcContour::rverts
|
||||
public const int RC_BORDER_VERTEX = 0x10000;
|
||||
|
||||
/// Area border flag.
|
||||
/// If a region ID has this bit set, then the associated element lies on
|
||||
/// the border of an area.
|
||||
/// (Used during the region and contour build process.)
|
||||
/// @see rcCompactSpan::reg, #rcContour::verts, #rcContour::rverts
|
||||
public const int RC_AREA_BORDER = 0x20000;
|
||||
|
||||
/// Applied to the region id field of contour vertices in order to extract the region id.
|
||||
/// The region id field of a vertex may have several flags applied to it. So the
|
||||
/// fields value can't be used directly.
|
||||
/// @see rcContour::verts, rcContour::rverts
|
||||
public const int RC_CONTOUR_REG_MASK = 0xffff;
|
||||
|
||||
/// A value which indicates an invalid index within a mesh.
|
||||
/// @note This does not necessarily indicate an error.
|
||||
/// @see rcPolyMesh::polys
|
||||
public const int RC_MESH_NULL_IDX = 0xffff;
|
||||
|
||||
public const int RC_LOG_WARNING = 1;
|
||||
|
||||
private static readonly int[] DirOffsetX = { -1, 0, 1, 0, };
|
||||
private static readonly int[] DirOffsetY = { 0, 1, 0, -1 };
|
||||
private static readonly int[] DirForOffset = { 3, 0, -1, 2, 1 };
|
||||
|
@ -127,7 +198,10 @@ namespace DotRecast.Recast
|
|||
for (int i = 0; i < nt; ++i)
|
||||
{
|
||||
int tri = i * 3;
|
||||
CalcTriNormal(verts, tris[tri], tris[tri + 1], tris[tri + 2], ref norm);
|
||||
RcVec3f v0 = RcVec.Create(verts, tris[tri + 0] * 3);
|
||||
RcVec3f v1 = RcVec.Create(verts, tris[tri + 1] * 3);
|
||||
RcVec3f v2 = RcVec.Create(verts, tris[tri + 2] * 3);
|
||||
CalcTriNormal(v0, v1, v2, ref norm);
|
||||
// Check if the face is walkable.
|
||||
if (norm.Y > walkableThr)
|
||||
areas[i] = areaMod.Apply(areas[i]);
|
||||
|
@ -136,10 +210,10 @@ namespace DotRecast.Recast
|
|||
return areas;
|
||||
}
|
||||
|
||||
public static void CalcTriNormal(float[] verts, int v0, int v1, int v2, ref RcVec3f norm)
|
||||
public static void CalcTriNormal(RcVec3f v0, RcVec3f v1, RcVec3f v2, ref RcVec3f norm)
|
||||
{
|
||||
var e0 = RcVecUtils.Subtract(verts, v1 * 3, v0 * 3);
|
||||
var e1 = RcVecUtils.Subtract(verts, v2 * 3, v0 * 3);
|
||||
var e0 = v1 - v0;
|
||||
var e1 = v2 - v0;
|
||||
norm = RcVec3f.Cross(e0, e1);
|
||||
norm = RcVec3f.Normalize(norm);
|
||||
}
|
||||
|
@ -162,7 +236,10 @@ namespace DotRecast.Recast
|
|||
for (int i = 0; i < nt; ++i)
|
||||
{
|
||||
int tri = i * 3;
|
||||
CalcTriNormal(verts, tris[tri], tris[tri + 1], tris[tri + 2], ref norm);
|
||||
RcVec3f v0 = RcVec.Create(verts, tris[tri + 0] * 3);
|
||||
RcVec3f v1 = RcVec.Create(verts, tris[tri + 1] * 3);
|
||||
RcVec3f v2 = RcVec.Create(verts, tris[tri + 2] * 3);
|
||||
CalcTriNormal(v0, v1, v2, ref norm);
|
||||
// Check if the face is walkable.
|
||||
if (norm.Y <= walkableThr)
|
||||
areas[i] = RC_NULL_AREA;
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -25,8 +25,8 @@ using DotRecast.Core;
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
using static RcConstants;
|
||||
using static RcCommons;
|
||||
|
||||
using static RcRecast;
|
||||
|
||||
public static class RcRegions
|
||||
{
|
||||
|
@ -1665,8 +1665,8 @@ namespace DotRecast.Recast
|
|||
|
||||
ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_WATERSHED);
|
||||
|
||||
int LOG_NB_STACKS = 3;
|
||||
int NB_STACKS = 1 << LOG_NB_STACKS;
|
||||
const int LOG_NB_STACKS = 3;
|
||||
const int NB_STACKS = 1 << LOG_NB_STACKS;
|
||||
List<List<RcLevelStackEntry>> lvlStacks = new List<List<RcLevelStackEntry>>();
|
||||
for (int i = 0; i < NB_STACKS; ++i)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -20,19 +20,13 @@ freely, subject to the following restrictions:
|
|||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
/** Represents a span in a heightfield. */
|
||||
/// Represents a span in a heightfield.
|
||||
/// @see rcHeightfield
|
||||
public class RcSpan
|
||||
{
|
||||
/** The lower limit of the span. [Limit: < smax] */
|
||||
public int smin;
|
||||
|
||||
/** The upper limit of the span. [Limit: <= SPAN_MAX_HEIGHT] */
|
||||
public int smax;
|
||||
|
||||
/** The area id assigned to the span. */
|
||||
public int area;
|
||||
|
||||
/** The next span higher up in column. */
|
||||
public RcSpan next;
|
||||
public int smin; //< The lower limit of the span. [Limit: < #smax]
|
||||
public int smax; //< The upper limit of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT]
|
||||
public int area; //< The area id assigned to the span.
|
||||
public RcSpan next; //< The next span higher up in column.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
/// A memory pool used for quick allocation of spans within a heightfield.
|
||||
/// @see rcHeightfield
|
||||
public class RcSpanPool
|
||||
{
|
||||
public RcSpanPool next; //< The next span pool.
|
||||
public readonly RcSpan[] items; //< Array of spans in the pool.
|
||||
|
||||
public RcSpanPool()
|
||||
{
|
||||
items = new RcSpan[RcRecast.RC_SPANS_PER_POOL];
|
||||
for (int i = 0; i < items.Length; ++i)
|
||||
{
|
||||
items[i] = new RcSpan();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace DotRecast.Recast
|
||||
namespace DotRecast.Recast
|
||||
{
|
||||
public class RcSweepSpan
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
|||
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast.Geom;
|
||||
|
||||
namespace DotRecast.Recast
|
||||
|
@ -44,18 +45,18 @@ namespace DotRecast.Recast
|
|||
float[] verts = geom.GetVerts();
|
||||
if (cfg.UseTiles)
|
||||
{
|
||||
float[] tbmin = new float[2];
|
||||
float[] tbmax = new float[2];
|
||||
tbmin[0] = builderCfg.bmin.X;
|
||||
tbmin[1] = builderCfg.bmin.Z;
|
||||
tbmax[0] = builderCfg.bmax.X;
|
||||
tbmax[1] = builderCfg.bmax.Z;
|
||||
RcVec2f tbmin;
|
||||
RcVec2f tbmax;
|
||||
tbmin.X = builderCfg.bmin.X;
|
||||
tbmin.Y = builderCfg.bmin.Z;
|
||||
tbmax.X = builderCfg.bmax.X;
|
||||
tbmax.Y = builderCfg.bmax.Z;
|
||||
List<RcChunkyTriMeshNode> nodes = geom.GetChunksOverlappingRect(tbmin, tbmax);
|
||||
foreach (RcChunkyTriMeshNode node in nodes)
|
||||
{
|
||||
int[] tris = node.tris;
|
||||
int ntris = tris.Length / 3;
|
||||
int[] m_triareas = RcCommons.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
||||
int[] m_triareas = RcRecast.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
||||
RcRasterizations.RasterizeTriangles(ctx, verts, tris, m_triareas, ntris, solid, cfg.WalkableClimb);
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +64,7 @@ namespace DotRecast.Recast
|
|||
{
|
||||
int[] tris = geom.GetTris();
|
||||
int ntris = tris.Length / 3;
|
||||
int[] m_triareas = RcCommons.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
||||
int[] m_triareas = RcRecast.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
||||
RcRasterizations.RasterizeTriangles(ctx, verts, tris, m_triareas, ntris, solid, cfg.WalkableClimb);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "com.rnd.dotrecast",
|
||||
"displayName": "DotRecast",
|
||||
"version": "0.1.4-exp.1"
|
||||
"version": "0.4.1"
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Running;
|
||||
using DotRecast.Benchmark.Benchmarks;
|
||||
|
||||
namespace DotRecast.Benchmark;
|
||||
|
||||
public static class BenchmarkProgram
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
var runs = ImmutableArray.Create(
|
||||
BenchmarkConverter.TypeToBenchmarks(typeof(VectorBenchmarks)),
|
||||
BenchmarkConverter.TypeToBenchmarks(typeof(PriorityQueueBenchmarks)),
|
||||
BenchmarkConverter.TypeToBenchmarks(typeof(StackallocBenchmarks))
|
||||
);
|
||||
|
||||
var summary = BenchmarkRunner.Run(runs.ToArray());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,278 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using DotRecast.Core.Collections;
|
||||
|
||||
namespace DotRecast.Benchmark.Benchmarks;
|
||||
|
||||
/*
|
||||
|
||||
// * Summary *
|
||||
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3958/23H2/2023Update/SunValley3)
|
||||
AMD Ryzen 5 3600, 1 CPU, 12 logical and 6 physical cores
|
||||
.NET SDK 8.0.101
|
||||
[Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2
|
||||
DefaultJob : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2
|
||||
|
||||
| Method | Count | Mean | Error | StdDev |
|
||||
|------------------------------- |------ |--------------------:|-----------------:|-----------------:|
|
||||
| Enqueue_RcSortedQueue | 10 | 87.49 ns | 0.774 ns | 0.724 ns |
|
||||
| Enqueue_RcBinaryMinHeap | 10 | 185.23 ns | 1.730 ns | 1.533 ns |
|
||||
| Enqueue_PriorityQueue | 10 | 202.95 ns | 1.611 ns | 1.428 ns |
|
||||
| DequeueAll_RcSortedQueue | 10 | 460.97 ns | 2.169 ns | 2.029 ns |
|
||||
| DequeueAll_RcBinaryMinHeap | 10 | 573.17 ns | 2.542 ns | 2.378 ns |
|
||||
| DequeueAll_PriorityQueue | 10 | 500.68 ns | 2.364 ns | 2.212 ns |
|
||||
| EnqueueDequeue_RcSortedQueue | 10 | 525.43 ns | 1.842 ns | 1.632 ns |
|
||||
| EnqueueDequeue_RcBinaryMinHeap | 10 | 455.65 ns | 2.410 ns | 2.254 ns |
|
||||
| EnqueueDequeue_PriorityQueue | 10 | 381.82 ns | 6.036 ns | 5.646 ns |
|
||||
| Enqueue_RcSortedQueue | 100 | 730.57 ns | 5.229 ns | 4.635 ns |
|
||||
| Enqueue_RcBinaryMinHeap | 100 | 3,012.15 ns | 10.875 ns | 9.640 ns |
|
||||
| Enqueue_PriorityQueue | 100 | 2,306.80 ns | 26.694 ns | 23.663 ns |
|
||||
| DequeueAll_RcSortedQueue | 100 | 6,241.67 ns | 31.856 ns | 29.798 ns |
|
||||
| DequeueAll_RcBinaryMinHeap | 100 | 13,692.29 ns | 38.829 ns | 34.421 ns |
|
||||
| DequeueAll_PriorityQueue | 100 | 12,482.93 ns | 93.955 ns | 87.886 ns |
|
||||
| EnqueueDequeue_RcSortedQueue | 100 | 64,002.79 ns | 316.081 ns | 280.197 ns |
|
||||
| EnqueueDequeue_RcBinaryMinHeap | 100 | 8,655.79 ns | 23.703 ns | 22.172 ns |
|
||||
| EnqueueDequeue_PriorityQueue | 100 | 7,806.20 ns | 105.801 ns | 98.967 ns |
|
||||
| Enqueue_RcSortedQueue | 1000 | 7,566.23 ns | 149.010 ns | 218.418 ns |
|
||||
| Enqueue_RcBinaryMinHeap | 1000 | 36,277.43 ns | 96.710 ns | 90.462 ns |
|
||||
| Enqueue_PriorityQueue | 1000 | 28,564.19 ns | 186.866 ns | 174.795 ns |
|
||||
| DequeueAll_RcSortedQueue | 1000 | 108,574.26 ns | 745.459 ns | 697.303 ns |
|
||||
| DequeueAll_RcBinaryMinHeap | 1000 | 210,346.25 ns | 332.478 ns | 311.000 ns |
|
||||
| DequeueAll_PriorityQueue | 1000 | 189,536.32 ns | 1,180.045 ns | 1,046.079 ns |
|
||||
| EnqueueDequeue_RcSortedQueue | 1000 | 8,957,965.42 ns | 45,715.567 ns | 42,762.370 ns |
|
||||
| EnqueueDequeue_RcBinaryMinHeap | 1000 | 131,615.02 ns | 394.216 ns | 368.750 ns |
|
||||
| EnqueueDequeue_PriorityQueue | 1000 | 114,799.89 ns | 1,269.621 ns | 1,060.191 ns |
|
||||
| Enqueue_RcSortedQueue | 10000 | 77,143.76 ns | 996.372 ns | 932.007 ns |
|
||||
| Enqueue_RcBinaryMinHeap | 10000 | 417,620.57 ns | 853.343 ns | 756.466 ns |
|
||||
| Enqueue_PriorityQueue | 10000 | 278,791.68 ns | 1,566.093 ns | 1,464.924 ns |
|
||||
| DequeueAll_RcSortedQueue | 10000 | 1,435,539.99 ns | 9,329.910 ns | 8,727.204 ns |
|
||||
| DequeueAll_RcBinaryMinHeap | 10000 | 2,956,366.90 ns | 6,344.030 ns | 5,934.210 ns |
|
||||
| DequeueAll_PriorityQueue | 10000 | 2,642,186.54 ns | 9,482.374 ns | 8,869.819 ns |
|
||||
| EnqueueDequeue_RcSortedQueue | 10000 | 1,318,277,320.00 ns | 6,725,701.525 ns | 6,291,225.379 ns |
|
||||
| EnqueueDequeue_RcBinaryMinHeap | 10000 | 1,712,170.68 ns | 5,674.513 ns | 5,307.943 ns |
|
||||
| EnqueueDequeue_PriorityQueue | 10000 | 1,466,910.77 ns | 4,394.686 ns | 4,110.792 ns |
|
||||
|
||||
*/
|
||||
|
||||
public class PriorityQueueBenchmarks
|
||||
{
|
||||
[Params(10, 100, 1000, 10000)] public int Count;
|
||||
|
||||
private RcSortedQueue<Node> _sq;
|
||||
private RcBinaryMinHeap<Node> _bmHeap;
|
||||
private PriorityQueue<Node, Node> _pq;
|
||||
|
||||
private float[] _priority;
|
||||
|
||||
class Node
|
||||
{
|
||||
public int id;
|
||||
public float total;
|
||||
}
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
static int Comp(Node x, Node y)
|
||||
{
|
||||
var v = x.total.CompareTo(y.total);
|
||||
if (v != 0)
|
||||
return v;
|
||||
return x.id.CompareTo(y.id);
|
||||
}
|
||||
|
||||
_sq = new(Comp);
|
||||
_bmHeap = new(Count, Comp);
|
||||
_pq = new(Count, Comparer<Node>.Create(Comp));
|
||||
|
||||
_priority = new float[Count];
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
_priority[i] = (float)Random.Shared.NextDouble() * 100f;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Enqueue_RcSortedQueue()
|
||||
{
|
||||
_sq.Clear();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
_sq.Enqueue(new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Enqueue_RcBinaryMinHeap()
|
||||
{
|
||||
_bmHeap.Clear();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
_bmHeap.Push(new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Enqueue_PriorityQueue()
|
||||
{
|
||||
_pq.Clear();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
var node = new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
};
|
||||
_pq.Enqueue(node, node);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void DequeueAll_RcSortedQueue()
|
||||
{
|
||||
_sq.Clear();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
_sq.Enqueue(new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
});
|
||||
}
|
||||
|
||||
while (_sq.Count() > 0)
|
||||
{
|
||||
_sq.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void DequeueAll_RcBinaryMinHeap()
|
||||
{
|
||||
_bmHeap.Clear();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
_bmHeap.Push(new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
});
|
||||
}
|
||||
|
||||
while (_bmHeap.Count > 0)
|
||||
{
|
||||
_bmHeap.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void DequeueAll_PriorityQueue()
|
||||
{
|
||||
_pq.Clear();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
var node = new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
};
|
||||
_pq.Enqueue(node, node);
|
||||
}
|
||||
|
||||
while (_pq.Count > 0)
|
||||
{
|
||||
_pq.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Benchmark]
|
||||
public void EnqueueDequeue_RcSortedQueue()
|
||||
{
|
||||
_sq.Clear();
|
||||
int half = Count / 2;
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
_sq.Enqueue(new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = half; i < Count; i++)
|
||||
{
|
||||
_sq.Enqueue(new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
});
|
||||
|
||||
_sq.Dequeue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void EnqueueDequeue_RcBinaryMinHeap()
|
||||
{
|
||||
_bmHeap.Clear();
|
||||
int half = Count / 2;
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
_bmHeap.Push(new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = half; i < Count; i++)
|
||||
{
|
||||
_bmHeap.Push(new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
});
|
||||
|
||||
_bmHeap.Pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void EnqueueDequeue_PriorityQueue()
|
||||
{
|
||||
_pq.Clear();
|
||||
int half = Count / 2;
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
var node = new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
};
|
||||
_pq.Enqueue(node, node);
|
||||
}
|
||||
|
||||
for (int i = half; i < Count; i++)
|
||||
{
|
||||
var node = new Node
|
||||
{
|
||||
id = i,
|
||||
total = _priority[i],
|
||||
};
|
||||
_pq.Enqueue(node, node);
|
||||
_pq.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Engines;
|
||||
|
||||
namespace DotRecast.Benchmark.Benchmarks;
|
||||
|
||||
/*
|
||||
|
||||
| Method | TestArraySize | Mean | Error | StdDev | Median |
|
||||
|------------------------------- |-------------- |-------------:|-----------:|------------:|-------------:|
|
||||
| Stackalloc_Long | 16 | 3.016 ns | 0.0179 ns | 0.0149 ns | 3.017 ns |
|
||||
| Stackalloc_Long_SkipLocalsInit | 16 | 2.265 ns | 0.0197 ns | 0.0184 ns | 2.258 ns |
|
||||
| New_Long | 16 | 5.917 ns | 0.1964 ns | 0.5634 ns | 5.761 ns |
|
||||
| New_Long_SkipLocalsInit | 16 | 5.703 ns | 0.1371 ns | 0.3935 ns | 5.661 ns |
|
||||
| Stackalloc_Long | 256 | 39.418 ns | 0.2737 ns | 0.2285 ns | 39.410 ns |
|
||||
| Stackalloc_Long_SkipLocalsInit | 256 | 2.274 ns | 0.0147 ns | 0.0131 ns | 2.274 ns |
|
||||
| New_Long | 256 | 53.901 ns | 2.9999 ns | 8.4614 ns | 51.449 ns |
|
||||
| New_Long_SkipLocalsInit | 256 | 53.480 ns | 1.8716 ns | 5.4298 ns | 51.858 ns |
|
||||
| Stackalloc_Long | 1024 | 137.037 ns | 0.3652 ns | 0.3416 ns | 137.031 ns |
|
||||
| Stackalloc_Long_SkipLocalsInit | 1024 | 3.669 ns | 0.0254 ns | 0.0226 ns | 3.668 ns |
|
||||
| New_Long | 1024 | 197.324 ns | 9.2795 ns | 27.0687 ns | 186.588 ns |
|
||||
| New_Long_SkipLocalsInit | 1024 | 210.996 ns | 10.0255 ns | 27.9471 ns | 206.110 ns |
|
||||
| Stackalloc_Long | 8192 | 1,897.989 ns | 7.1814 ns | 5.9968 ns | 1,897.814 ns |
|
||||
| Stackalloc_Long_SkipLocalsInit | 8192 | 20.598 ns | 0.2645 ns | 0.2344 ns | 20.572 ns |
|
||||
| New_Long | 8192 | 1,324.061 ns | 39.8447 ns | 116.2288 ns | 1,298.794 ns |
|
||||
| New_Long_SkipLocalsInit | 8192 | 1,305.211 ns | 35.1855 ns | 102.0796 ns | 1,295.539 ns |
|
||||
*/
|
||||
|
||||
public class StackallocBenchmarks
|
||||
{
|
||||
private readonly Consumer _consumer = new();
|
||||
|
||||
[Params(1 << 4, 1 << 8, 1 << 10, 1 << 13)]
|
||||
public int HashTableSize;
|
||||
|
||||
[Benchmark]
|
||||
public void Stackalloc_Long()
|
||||
{
|
||||
Span<long> hashTable = stackalloc long[HashTableSize];
|
||||
|
||||
_consumer.Consume(hashTable[0]);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
[SkipLocalsInit]
|
||||
public void Stackalloc_Long_SkipLocalsInit()
|
||||
{
|
||||
Span<long> hashTable = stackalloc long[HashTableSize];
|
||||
|
||||
_consumer.Consume(hashTable[0]);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void New_Long()
|
||||
{
|
||||
Span<long> hashTable = new long[HashTableSize];
|
||||
|
||||
_consumer.Consume(hashTable[0]);
|
||||
}
|
||||
|
||||
|
||||
[Benchmark]
|
||||
[SkipLocalsInit]
|
||||
public void New_Long_SkipLocalsInit()
|
||||
{
|
||||
Span<long> hashTable = new long[HashTableSize];
|
||||
|
||||
_consumer.Consume(hashTable[0]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
namespace DotRecast.Benchmark.Benchmarks;
|
||||
|
||||
/*
|
||||
| Method | Mean | Error | StdDev |
|
||||
|------------------ |----------:|----------:|----------:|
|
||||
| Dot_Vector3 | 0.6395 ns | 0.0125 ns | 0.0104 ns |
|
||||
| Dot_RcVec3f | 0.2275 ns | 0.0281 ns | 0.0375 ns |
|
||||
| Cross_Vector3 | 1.1652 ns | 0.0102 ns | 0.0085 ns |
|
||||
| Cross_RcVec3f | 1.1687 ns | 0.0140 ns | 0.0124 ns |
|
||||
| Normalize_Vector3 | 1.7964 ns | 0.0173 ns | 0.0162 ns |
|
||||
| Normalize_RcVec3f | 1.2806 ns | 0.0088 ns | 0.0078 ns |
|
||||
*/
|
||||
|
||||
public class VectorBenchmarks
|
||||
{
|
||||
private readonly Consumer _consumer = new();
|
||||
|
||||
[Benchmark]
|
||||
public void Dot_Vector3()
|
||||
{
|
||||
var v1 = new System.Numerics.Vector3(1, 2, 3);
|
||||
var v2 = new System.Numerics.Vector3(1, 2, 3);
|
||||
var v = System.Numerics.Vector3.Dot(v1, v2);
|
||||
_consumer.Consume(v);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Dot_RcVec3f()
|
||||
{
|
||||
var v1 = new RcVec3f(1, 2, 3);
|
||||
var v2 = new RcVec3f(1, 2, 3);
|
||||
var v = RcVec3f.Dot(v1, v2);
|
||||
_consumer.Consume(v);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Cross_Vector3()
|
||||
{
|
||||
var v1 = new System.Numerics.Vector3(1, 2, 3);
|
||||
var v2 = new System.Numerics.Vector3(1, 2, 3);
|
||||
var v = System.Numerics.Vector3.Cross(v1, v2);
|
||||
_consumer.Consume(v);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Cross_RcVec3f()
|
||||
{
|
||||
var v1 = new RcVec3f(1, 2, 3);
|
||||
var v2 = new RcVec3f(1, 2, 3);
|
||||
var v = RcVec3f.Cross(v1, v2);
|
||||
_consumer.Consume(v);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Normalize_Vector3()
|
||||
{
|
||||
var v1 = new System.Numerics.Vector3(1, 2, 3);
|
||||
var v = System.Numerics.Vector3.Normalize(v1);
|
||||
_consumer.Consume(v);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Normalize_RcVec3f()
|
||||
{
|
||||
var v1 = new RcVec3f(1, 2, 3);
|
||||
var v = RcVec3f.Normalize(v1);
|
||||
_consumer.Consume(v);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\DotRecast.Core\DotRecast.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -7,15 +7,15 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="NUnit" Version="4.2.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using DotRecast.Core.Buffers;
|
||||
using DotRecast.Core.Collections;
|
||||
using NUnit.Framework;
|
||||
|
@ -84,18 +85,73 @@ public class RcArrayBenchmarkTests
|
|||
[Test]
|
||||
public void TestBenchmarkArrays()
|
||||
{
|
||||
var list = new List<(string title, long ticks)>();
|
||||
list.Add(Bench("new int[len]", RoundForArray));
|
||||
list.Add(Bench("ArrayPool<int>.Shared.Rent(len)", RoundForPureRentArray));
|
||||
list.Add(Bench("RcRentedArray.Rent<int>(len)", RoundForRcRentedArray));
|
||||
list.Add(Bench("new RcStackArray512<int>()", RoundForRcStackArray));
|
||||
list.Add(Bench("stackalloc int[len]", RoundForStackalloc));
|
||||
var results = new List<(string title, long ticks)>();
|
||||
results.Add(Bench("new int[len]", RoundForArray));
|
||||
results.Add(Bench("ArrayPool<int>.Shared.Rent(len)", RoundForPureRentArray));
|
||||
results.Add(Bench("RcRentedArray.Rent<int>(len)", RoundForRcRentedArray));
|
||||
results.Add(Bench("new RcStackArray512<int>()", RoundForRcStackArray));
|
||||
results.Add(Bench("stackalloc int[len]", RoundForStackalloc));
|
||||
|
||||
list.Sort((x, y) => x.ticks.CompareTo(y.ticks));
|
||||
results.Sort((x, y) => x.ticks.CompareTo(y.ticks));
|
||||
|
||||
foreach (var t in list)
|
||||
foreach (var t in results)
|
||||
{
|
||||
Console.WriteLine($"{t.title} {t.ticks / (double)TimeSpan.TicksPerMillisecond} ms");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSpanVsArray()
|
||||
{
|
||||
var r = new RcRand();
|
||||
var list = new List<(long[] src, long[] dest)>();
|
||||
for (int i = 0; i < 14; ++i)
|
||||
{
|
||||
var s = new long[(int)Math.Pow(2, i + 1)];
|
||||
var d = new long[(int)Math.Pow(2, i + 1)];
|
||||
for (int ii = 0; ii < s.Length; ++ii)
|
||||
{
|
||||
s[ii] = r.NextInt32();
|
||||
}
|
||||
|
||||
list.Add((s, d));
|
||||
}
|
||||
|
||||
var results = new List<(string title, long ticks)>();
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
var seq = i;
|
||||
|
||||
Array.Fill(list[seq].dest, 0);
|
||||
var resultLong = Bench($"long[{list[seq].src.Length}]", _ =>
|
||||
{
|
||||
var v = list[seq];
|
||||
RcArrays.Copy(v.src, 0, v.dest, 0, v.src.Length);
|
||||
});
|
||||
|
||||
|
||||
Array.Fill(list[seq].dest, 0);
|
||||
var resultSpan = Bench($"Span<long[], {list[seq].src.Length}>", _ =>
|
||||
{
|
||||
var v = list[seq];
|
||||
RcSpans.Copy<long>(v.src, 0, v.dest, 0, v.src.Length);
|
||||
});
|
||||
|
||||
|
||||
results.Add(resultLong);
|
||||
results.Add(resultSpan);
|
||||
}
|
||||
|
||||
|
||||
int newLine = 0;
|
||||
foreach (var t in results)
|
||||
{
|
||||
Console.WriteLine($"{t.title}: {t.ticks / (double)TimeSpan.TicksPerMillisecond} ms");
|
||||
newLine += 1;
|
||||
if (0 == (newLine % 2))
|
||||
{
|
||||
Console.WriteLine("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
using DotRecast.Core.Collections;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Core.Test;
|
||||
|
||||
public class RcBinaryMinHeapTest
|
||||
{
|
||||
private static readonly RcAtomicLong Gen = new();
|
||||
|
||||
private class Node
|
||||
{
|
||||
public readonly long Id;
|
||||
public long Value;
|
||||
|
||||
public Node(int value)
|
||||
{
|
||||
Id = Gen.IncrementAndGet();
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPush()
|
||||
{
|
||||
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||
|
||||
minHeap.Push(new Node(5));
|
||||
minHeap.Push(new Node(3));
|
||||
minHeap.Push(new Node(7));
|
||||
minHeap.Push(new Node(2));
|
||||
minHeap.Push(new Node(4));
|
||||
|
||||
// Push 후 힙의 속성을 검증
|
||||
AssertHeapProperty(minHeap.ToArray());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPop()
|
||||
{
|
||||
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||
|
||||
minHeap.Push(new Node(5));
|
||||
minHeap.Push(new Node(3));
|
||||
minHeap.Push(new Node(7));
|
||||
minHeap.Push(new Node(2));
|
||||
minHeap.Push(new Node(4));
|
||||
|
||||
// Pop을 통해 최소 값부터 순서대로 제거하면서 검증
|
||||
Assert.That(minHeap.Pop().Value, Is.EqualTo(2));
|
||||
Assert.That(minHeap.Pop().Value, Is.EqualTo(3));
|
||||
Assert.That(minHeap.Pop().Value, Is.EqualTo(4));
|
||||
Assert.That(minHeap.Pop().Value, Is.EqualTo(5));
|
||||
Assert.That(minHeap.Pop().Value, Is.EqualTo(7));
|
||||
|
||||
// 모든 요소를 Pop한 후에는 비어있어야 함
|
||||
Assert.That(minHeap.IsEmpty(), Is.True);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestTop()
|
||||
{
|
||||
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||
|
||||
minHeap.Push(new Node(5));
|
||||
minHeap.Push(new Node(3));
|
||||
minHeap.Push(new Node(7));
|
||||
|
||||
Assert.That(minHeap.Top().Value, Is.EqualTo(3));
|
||||
AssertHeapProperty(minHeap.ToArray());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestModify()
|
||||
{
|
||||
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||
|
||||
var node7 = new Node(7);
|
||||
minHeap.Push(new Node(5));
|
||||
minHeap.Push(new Node(3));
|
||||
minHeap.Push(node7);
|
||||
minHeap.Push(new Node(2));
|
||||
minHeap.Push(new Node(4));
|
||||
|
||||
node7.Value = 1;
|
||||
var result = minHeap.Modify(node7); // Modify value 7 to 1
|
||||
var result2 = minHeap.Modify(new Node(4));
|
||||
|
||||
Assert.That(result, Is.EqualTo(true));
|
||||
Assert.That(result2, Is.EqualTo(false));
|
||||
Assert.That(minHeap.Top().Value, Is.EqualTo(1));
|
||||
AssertHeapProperty(minHeap.ToArray());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCount()
|
||||
{
|
||||
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||
|
||||
minHeap.Push(new Node(5));
|
||||
minHeap.Push(new Node(3));
|
||||
minHeap.Push(new Node(7));
|
||||
|
||||
Assert.That(minHeap.Count, Is.EqualTo(3));
|
||||
|
||||
minHeap.Pop();
|
||||
|
||||
Assert.That(minHeap.Count, Is.EqualTo(2));
|
||||
|
||||
minHeap.Clear();
|
||||
|
||||
Assert.That(minHeap.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestIsEmpty()
|
||||
{
|
||||
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||
|
||||
Assert.That(minHeap.IsEmpty(), Is.True);
|
||||
|
||||
minHeap.Push(new Node(5));
|
||||
|
||||
Assert.That(minHeap.IsEmpty(), Is.False);
|
||||
|
||||
minHeap.Pop();
|
||||
|
||||
Assert.That(minHeap.IsEmpty(), Is.True);
|
||||
}
|
||||
|
||||
private void AssertHeapProperty(Node[] array)
|
||||
{
|
||||
for (int i = 0; i < array.Length / 2; i++)
|
||||
{
|
||||
int leftChildIndex = 2 * i + 1;
|
||||
int rightChildIndex = 2 * i + 2;
|
||||
|
||||
// 왼쪽 자식 노드가 있는지 확인하고 비교
|
||||
if (leftChildIndex < array.Length)
|
||||
Assert.That(array[i].Value, Is.LessThanOrEqualTo(array[leftChildIndex].Value));
|
||||
|
||||
// 오른쪽 자식 노드가 있는지 확인하고 비교
|
||||
if (rightChildIndex < array.Length)
|
||||
Assert.That(array[i].Value, Is.LessThanOrEqualTo(array[rightChildIndex].Value));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DotRecast.Core.Buffers;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Core.Test;
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Core.Test;
|
||||
|
||||
public class RcIoTests
|
||||
{
|
||||
[Test]
|
||||
public void Test()
|
||||
{
|
||||
const long tileRef = 281474976710656L;
|
||||
const int dataSize = 344;
|
||||
|
||||
byte[] actual;
|
||||
|
||||
{
|
||||
using MemoryStream ms = new MemoryStream();
|
||||
using BinaryWriter bw = new BinaryWriter(ms);
|
||||
|
||||
RcIO.Write(bw, tileRef, RcByteOrder.LITTLE_ENDIAN);
|
||||
RcIO.Write(bw, dataSize, RcByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
bw.Flush();
|
||||
actual= ms.ToArray();
|
||||
}
|
||||
|
||||
{
|
||||
using MemoryStream ms = new MemoryStream(actual);
|
||||
using BinaryReader br = new BinaryReader(ms);
|
||||
var byteBuffer = RcIO.ToByteBuffer(br);
|
||||
byteBuffer.Order(RcByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
Assert.That(byteBuffer.GetLong(), Is.EqualTo(tileRef));
|
||||
Assert.That(byteBuffer.GetInt(), Is.EqualTo(dataSize));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Core.Test;
|
||||
|
||||
public class RcMathTest
|
||||
{
|
||||
[Test]
|
||||
public void TestSqr()
|
||||
{
|
||||
Assert.That(RcMath.Sqr(0), Is.EqualTo(0));
|
||||
Assert.That(RcMath.Sqr(5), Is.EqualTo(25));
|
||||
Assert.That(RcMath.Sqr(-5), Is.EqualTo(25));
|
||||
Assert.That(RcMath.Sqr(float.PositiveInfinity), Is.EqualTo(float.PositiveInfinity));
|
||||
Assert.That(RcMath.Sqr(float.NegativeInfinity), Is.EqualTo(float.PositiveInfinity));
|
||||
Assert.That(RcMath.Sqr(float.NaN), Is.EqualTo(float.NaN));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLerp()
|
||||
{
|
||||
//
|
||||
Assert.That(RcMath.Lerp(-10, 10, 2f), Is.EqualTo(30));
|
||||
Assert.That(RcMath.Lerp(-10, 10, 1f), Is.EqualTo(10));
|
||||
Assert.That(RcMath.Lerp(-10, 10, 0.5f), Is.EqualTo(0));
|
||||
Assert.That(RcMath.Lerp(-10, 10, 0.25f), Is.EqualTo(-5));
|
||||
Assert.That(RcMath.Lerp(-10, 10, 0), Is.EqualTo(-10));
|
||||
Assert.That(RcMath.Lerp(-10, 10, -0.5f), Is.EqualTo(-20));
|
||||
Assert.That(RcMath.Lerp(-10, 10, -1f), Is.EqualTo(-30));
|
||||
|
||||
//
|
||||
Assert.That(RcMath.Lerp(10, 10, 0.5f), Is.EqualTo(10));
|
||||
Assert.That(RcMath.Lerp(10, 10, 0.8f), Is.EqualTo(10));
|
||||
|
||||
//
|
||||
Assert.That(RcMath.Lerp(10, -10, 0.75f), Is.EqualTo(-5));
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DotRecast.Core.Buffers;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
@ -56,4 +57,50 @@ public class RcRentedArrayTest
|
|||
Assert.Throws<NullReferenceException>(() => rentedArray[^1] = 0);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSame()
|
||||
{
|
||||
// not same
|
||||
{
|
||||
using var r1 = RcRentedArray.Rent<float>(1024);
|
||||
using var r2 = RcRentedArray.Rent<float>(1024);
|
||||
|
||||
Assert.That(r2.AsArray() != r1.AsArray(), Is.EqualTo(true));
|
||||
}
|
||||
|
||||
// same
|
||||
{
|
||||
// error case
|
||||
float[] r1Array;
|
||||
using (var r1 = RcRentedArray.Rent<float>(1024))
|
||||
{
|
||||
r1Array = r1.AsArray();
|
||||
for (int i = 0; i < r1.Length; ++i)
|
||||
{
|
||||
r1[i] = 123;
|
||||
}
|
||||
}
|
||||
|
||||
using var r2 = RcRentedArray.Rent<float>(1024);
|
||||
|
||||
Assert.That(r2.AsArray() == r1Array, Is.EqualTo(true));
|
||||
Assert.That(r2.AsArray().Sum(), Is.EqualTo(0));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDispose()
|
||||
{
|
||||
var r1 = RcRentedArray.Rent<float>(1024);
|
||||
for (int i = 0; i < r1.Length; ++i)
|
||||
{
|
||||
r1[i] = 123;
|
||||
}
|
||||
|
||||
Assert.That(r1.IsDisposed, Is.EqualTo(false));
|
||||
r1.Dispose();
|
||||
Assert.That(r1.IsDisposed, Is.EqualTo(true));
|
||||
Assert.That(r1.AsArray(), Is.Null);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Collections;
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Core.Test;
|
||||
|
||||
public class RcSpanTest
|
||||
{
|
||||
[Test]
|
||||
public void TestCopy()
|
||||
{
|
||||
// Test for copying all elements to the destination span.
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 1, 2, 3 };
|
||||
Span<long> dst = stackalloc long[] { 0, 0, 0 };
|
||||
|
||||
RcSpans.Copy(src, dst);
|
||||
Assert.That(src.ToArray(), Is.EqualTo(dst.ToArray()));
|
||||
}
|
||||
|
||||
// Test for successful copying when the destination Span has a larger size.
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 1, 2 };
|
||||
Span<long> dst = stackalloc long[] { 0, 0, 0, 0 };
|
||||
|
||||
RcSpans.Copy(src, dst);
|
||||
Assert.That(src.ToArray(), Is.EqualTo(dst.Slice(0, src.Length).ToArray()));
|
||||
}
|
||||
|
||||
// Test for an error when copying to a Span with a smaller size.
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 1, 2, 3, 4, 5 };
|
||||
Span<long> dst = stackalloc long[] { 0, 0, 0 };
|
||||
RcSpans.Copy(src, dst);
|
||||
});
|
||||
}
|
||||
|
||||
// Test for copying a specific range of elements from the source span to a specific range in the destination span.
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 1, 2, 3, 4, 5 };
|
||||
Span<long> dst = stackalloc long[] { 0, 0, 0 };
|
||||
|
||||
RcSpans.Copy(src, 2, dst, 0, 2);
|
||||
Assert.That(src.Slice(2, 2).ToArray(), Is.EqualTo(dst.Slice(0, 2).ToArray()));
|
||||
}
|
||||
|
||||
// Test for copying a specific range of elements from the source span to a specific range in the destination span.
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 5, 4, 3, 2, 1 };
|
||||
Span<long> dst = stackalloc long[] { 0, 0, 0 };
|
||||
|
||||
RcSpans.Copy(src, 2, dst, 0, 3);
|
||||
Assert.That(src.Slice(2, 3).ToArray(), Is.EqualTo(dst.ToArray()));
|
||||
}
|
||||
|
||||
// Test for src (index + length) over
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 5, 4, 3, 2, 1 };
|
||||
Span<long> dst = stackalloc long[] { 0, 0, 0 };
|
||||
|
||||
//
|
||||
RcSpans.Copy(src, 3, dst, 0, 3);
|
||||
});
|
||||
|
||||
// Test for src (index + length) over
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 5, 4, 3, 2, 1 };
|
||||
Span<long> dst = stackalloc long[] { 0, 0, 0 };
|
||||
|
||||
//
|
||||
RcSpans.Copy(src, 5, dst, 0, 1);
|
||||
});
|
||||
|
||||
|
||||
// Test for dst (idx + length) over
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 5, 4, 3, 2, 1 };
|
||||
Span<long> dst = stackalloc long[] { 0, 0, 0 };
|
||||
|
||||
//
|
||||
RcSpans.Copy(src, 0, dst, 1, 3);
|
||||
});
|
||||
|
||||
// Test for dst (idx + length) over
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 5, 4, 3, 2, 1 };
|
||||
Span<long> dst = stackalloc long[] { 0, 0, 0 };
|
||||
|
||||
//
|
||||
RcSpans.Copy(src, 0, dst, 0, 4);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMove()
|
||||
{
|
||||
// [3, 2, 1] -> [3, 1, 1]
|
||||
{
|
||||
var expected = new List<long>() { 3, 1, 1 };
|
||||
Span<long> src = stackalloc long[] { 3, 2, 1 };
|
||||
RcSpans.Move(src, 2, 1, 1);
|
||||
Assert.That(src.ToArray(), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
// [3, 2, 1] -> [2, 1, 1]
|
||||
{
|
||||
var expected = new List<long>() { 2, 1, 1 };
|
||||
Span<long> src = stackalloc long[] { 3, 2, 1 };
|
||||
RcSpans.Move(src, 1, 0, 2);
|
||||
Assert.That(src.ToArray(), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
// [3, 2, 1] -> [3, 2, 1]
|
||||
{
|
||||
var expected = new List<long>() { 3, 2, 1 };
|
||||
Span<long> src = stackalloc long[] { 3, 2, 1 };
|
||||
RcSpans.Move(src, 0, 0, 3);
|
||||
Assert.That(src.ToArray(), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
// length over
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 3, 2, 1 };
|
||||
RcSpans.Move(src, 0, 0, 4);
|
||||
});
|
||||
|
||||
// source index over
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 3, 2, 1 };
|
||||
RcSpans.Move(src, 3, 0, 1);
|
||||
});
|
||||
|
||||
// destination index over
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
Span<long> src = stackalloc long[] { 3, 2, 1 };
|
||||
RcSpans.Move(src, 0, 3, 1);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Collections;
|
||||
using NUnit.Framework;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using DotRecast.Core.Numerics;
|
||||
using NUnit.Framework;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -25,7 +25,6 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Detour.Crowd.Test;
|
||||
|
||||
|
||||
public class AbstractCrowdTest
|
||||
{
|
||||
protected readonly long[] startRefs =
|
||||
|
@ -63,8 +62,9 @@ public class AbstractCrowdTest
|
|||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
nmd = new RecastTestMeshBuilder().GetMeshData();
|
||||
navmesh = new DtNavMesh(nmd, 6, 0);
|
||||
nmd = TestMeshDataFactory.Create();
|
||||
navmesh = new DtNavMesh();
|
||||
navmesh.Init(nmd, 6, 0);
|
||||
query = new DtNavMeshQuery(navmesh);
|
||||
DtCrowdConfig config = new DtCrowdConfig(0.6f);
|
||||
crowd = new DtCrowd(config, navmesh);
|
||||
|
@ -153,7 +153,7 @@ public class AbstractCrowdTest
|
|||
RcVec3f vel = RcVec3f.Subtract(tgt, pos);
|
||||
vel.Y = 0.0f;
|
||||
vel = RcVec3f.Normalize(vel);
|
||||
vel = vel.Scale(speed);
|
||||
vel = vel * speed;
|
||||
return vel;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="NUnit" Version="4.2.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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 System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Detour.Crowd.Test;
|
||||
|
||||
public class DtPathCorridorTest
|
||||
{
|
||||
private readonly DtPathCorridor corridor = new DtPathCorridor();
|
||||
private readonly IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
corridor.Init(256);
|
||||
corridor.Reset(0, new RcVec3f(10, 20, 30));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldKeepOriginalPathInFindCornersWhenNothingCanBePruned()
|
||||
{
|
||||
var straightPath = new DtStraightPath[4];
|
||||
straightPath[0] = new DtStraightPath(new RcVec3f(11, 20, 30.00001f), 0, 0);
|
||||
straightPath[1] = new DtStraightPath(new RcVec3f(12, 20, 30.00002f), 0, 0);
|
||||
straightPath[2] = new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0);
|
||||
straightPath[3] = new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0);
|
||||
var query = new DtNavMeshQueryMock(straightPath, DtStatus.DT_SUCCESS);
|
||||
|
||||
Span<DtStraightPath> path = stackalloc DtStraightPath[8];
|
||||
var npath = corridor.FindCorners(path, 8, query, filter);
|
||||
Assert.That(npath, Is.EqualTo(4));
|
||||
Assert.That(path.Slice(0, npath).ToArray(), Is.EqualTo(straightPath));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void ShouldPrunePathInFindCorners()
|
||||
{
|
||||
DtStraightPath[] straightPath = new DtStraightPath[5];
|
||||
straightPath[0] = (new DtStraightPath(new RcVec3f(10, 20, 30.00001f), 0, 0)); // too close
|
||||
straightPath[1] = (new DtStraightPath(new RcVec3f(10, 20, 30.00002f), 0, 0)); // too close
|
||||
straightPath[2] = (new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
|
||||
straightPath[3] = (new DtStraightPath(new RcVec3f(12f, 22, 33f), DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
|
||||
straightPath[4] = (new DtStraightPath(new RcVec3f(11f, 21, 32f), DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
|
||||
|
||||
var query = new DtNavMeshQueryMock(straightPath, DtStatus.DT_SUCCESS);
|
||||
|
||||
Span<DtStraightPath> path = stackalloc DtStraightPath[8];
|
||||
int npath = corridor.FindCorners(path, 8, query, filter);
|
||||
Assert.That(npath, Is.EqualTo(2));
|
||||
Assert.That(path.Slice(0, npath).ToArray(), Is.EqualTo(new DtStraightPath[] { straightPath[2], straightPath[3] }));
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
|
||||
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.Numerics;
|
||||
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Detour.Crowd.Test;
|
||||
|
||||
|
||||
public class PathCorridorTest
|
||||
{
|
||||
private readonly DtPathCorridor corridor = new DtPathCorridor();
|
||||
private readonly IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
corridor.Init(256);
|
||||
corridor.Reset(0, new RcVec3f(10, 20, 30));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldKeepOriginalPathInFindCornersWhenNothingCanBePruned()
|
||||
{
|
||||
List<DtStraightPath> straightPath = new();
|
||||
straightPath.Add(new DtStraightPath(new RcVec3f(11, 20, 30.00001f), 0, 0));
|
||||
straightPath.Add(new DtStraightPath(new RcVec3f(12, 20, 30.00002f), 0, 0));
|
||||
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
|
||||
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
|
||||
var mockQuery = new Mock<DtNavMeshQuery>(It.IsAny<DtNavMesh>());
|
||||
mockQuery.Setup(q => q.FindStraightPath(
|
||||
It.IsAny<RcVec3f>(),
|
||||
It.IsAny<RcVec3f>(),
|
||||
It.IsAny<List<long>>(),
|
||||
ref It.Ref<List<DtStraightPath>>.IsAny,
|
||||
It.IsAny<int>(),
|
||||
It.IsAny<int>())
|
||||
)
|
||||
.Callback((RcVec3f startPos, RcVec3f endPos, List<long> path,
|
||||
ref List<DtStraightPath> refStraightPath, int maxStraightPath, int options) =>
|
||||
{
|
||||
refStraightPath = straightPath;
|
||||
})
|
||||
.Returns(() => DtStatus.DT_SUCCESS);
|
||||
|
||||
var path = new List<DtStraightPath>();
|
||||
corridor.FindCorners(ref path, int.MaxValue, mockQuery.Object, filter);
|
||||
Assert.That(path.Count, Is.EqualTo(4));
|
||||
Assert.That(path, Is.EqualTo(straightPath));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldPrunePathInFindCorners()
|
||||
{
|
||||
List<DtStraightPath> straightPath = new();
|
||||
straightPath.Add(new DtStraightPath(new RcVec3f(10, 20, 30.00001f), 0, 0)); // too close
|
||||
straightPath.Add(new DtStraightPath(new RcVec3f(10, 20, 30.00002f), 0, 0)); // too close
|
||||
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
|
||||
straightPath.Add(new DtStraightPath(new RcVec3f(12f, 22, 33f), DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
|
||||
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
|
||||
|
||||
var mockQuery = new Mock<DtNavMeshQuery>(It.IsAny<DtNavMesh>());
|
||||
mockQuery.Setup(q => q.FindStraightPath(
|
||||
It.IsAny<RcVec3f>(),
|
||||
It.IsAny<RcVec3f>(),
|
||||
It.IsAny<List<long>>(),
|
||||
ref It.Ref<List<DtStraightPath>>.IsAny,
|
||||
It.IsAny<int>(),
|
||||
It.IsAny<int>())
|
||||
).Callback((RcVec3f startPos, RcVec3f endPos, List<long> path,
|
||||
ref List<DtStraightPath> refStraightPath, int maxStraightPath, int options) =>
|
||||
{
|
||||
refStraightPath = straightPath;
|
||||
})
|
||||
.Returns(() => DtStatus.DT_SUCCESS);
|
||||
|
||||
var path = new List<DtStraightPath>();
|
||||
corridor.FindCorners(ref path, int.MaxValue, mockQuery.Object, filter);
|
||||
Assert.That(path.Count, Is.EqualTo(2));
|
||||
Assert.That(path, Is.EqualTo(new List<DtStraightPath> { straightPath[2], straightPath[3] }));
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -22,46 +23,42 @@ using DotRecast.Recast.Geom;
|
|||
|
||||
namespace DotRecast.Detour.Crowd.Test;
|
||||
|
||||
public class RecastTestMeshBuilder
|
||||
public class TestMeshDataFactory
|
||||
{
|
||||
private readonly DtMeshData meshData;
|
||||
public const float m_cellSize = 0.3f;
|
||||
public const float m_cellHeight = 0.2f;
|
||||
public const float m_agentHeight = 2.0f;
|
||||
public const float m_agentRadius = 0.6f;
|
||||
public const float m_agentMaxClimb = 0.9f;
|
||||
public const float m_agentMaxSlope = 45.0f;
|
||||
public const int m_regionMinSize = 8;
|
||||
public const int m_regionMergeSize = 20;
|
||||
public const float m_edgeMaxLen = 12.0f;
|
||||
public const float m_edgeMaxError = 1.3f;
|
||||
public const int m_vertsPerPoly = 6;
|
||||
public const float m_detailSampleDist = 6.0f;
|
||||
public const float m_detailSampleMaxError = 1.0f;
|
||||
private const float m_cellSize = 0.3f;
|
||||
private const float m_cellHeight = 0.2f;
|
||||
private const float m_agentHeight = 2.0f;
|
||||
private const float m_agentRadius = 0.6f;
|
||||
private const float m_agentMaxClimb = 0.9f;
|
||||
private const float m_agentMaxSlope = 45.0f;
|
||||
private const int m_regionMinSize = 8;
|
||||
private const int m_regionMergeSize = 20;
|
||||
private const float m_edgeMaxLen = 12.0f;
|
||||
private const float m_edgeMaxError = 1.3f;
|
||||
private const int m_vertsPerPoly = 6;
|
||||
private const float m_detailSampleDist = 6.0f;
|
||||
private const float m_detailSampleMaxError = 1.0f;
|
||||
|
||||
public RecastTestMeshBuilder()
|
||||
: this(SimpleInputGeomProvider.LoadFile("dungeon.obj"),
|
||||
RcPartition.WATERSHED,
|
||||
m_cellSize, m_cellHeight,
|
||||
m_agentMaxSlope, m_agentHeight, m_agentRadius, m_agentMaxClimb,
|
||||
m_regionMinSize, m_regionMergeSize,
|
||||
m_edgeMaxLen, m_edgeMaxError,
|
||||
m_vertsPerPoly,
|
||||
m_detailSampleDist, m_detailSampleMaxError)
|
||||
public static DtMeshData Create()
|
||||
{
|
||||
}
|
||||
IInputGeomProvider geom = SimpleInputGeomProvider.LoadFile("dungeon.obj");
|
||||
RcPartition partition = RcPartition.WATERSHED;
|
||||
float cellSize = m_cellSize;
|
||||
float cellHeight = m_cellHeight;
|
||||
float agentMaxSlope = m_agentMaxSlope;
|
||||
float agentHeight = m_agentHeight;
|
||||
float agentRadius = m_agentRadius;
|
||||
float agentMaxClimb = m_agentMaxClimb;
|
||||
int regionMinSize = m_regionMinSize;
|
||||
int regionMergeSize = m_regionMergeSize;
|
||||
float edgeMaxLen = m_edgeMaxLen;
|
||||
float edgeMaxError = m_edgeMaxError;
|
||||
int vertsPerPoly = m_vertsPerPoly;
|
||||
float detailSampleDist = m_detailSampleDist;
|
||||
float detailSampleMaxError = m_detailSampleMaxError;
|
||||
|
||||
public RecastTestMeshBuilder(IInputGeomProvider geom,
|
||||
RcPartition partitionType,
|
||||
float cellSize, float cellHeight,
|
||||
float agentMaxSlope, float agentHeight, float agentRadius, float agentMaxClimb,
|
||||
int regionMinSize, int regionMergeSize,
|
||||
float edgeMaxLen, float edgeMaxError,
|
||||
int vertsPerPoly,
|
||||
float detailSampleDist, float detailSampleMaxError)
|
||||
{
|
||||
RcConfig cfg = new RcConfig(
|
||||
partitionType,
|
||||
partition,
|
||||
cellSize, cellHeight,
|
||||
agentMaxSlope, agentHeight, agentRadius, agentMaxClimb,
|
||||
regionMinSize, regionMergeSize,
|
||||
|
@ -72,32 +69,32 @@ public class RecastTestMeshBuilder
|
|||
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
|
||||
RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
|
||||
RcBuilder rcBuilder = new RcBuilder();
|
||||
RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg);
|
||||
RcPolyMesh m_pmesh = rcResult.GetMesh();
|
||||
for (int i = 0; i < m_pmesh.npolys; ++i)
|
||||
RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg, false);
|
||||
RcPolyMesh pmesh = rcResult.Mesh;
|
||||
for (int i = 0; i < pmesh.npolys; ++i)
|
||||
{
|
||||
m_pmesh.flags[i] = 1;
|
||||
pmesh.flags[i] = 1;
|
||||
}
|
||||
|
||||
RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
|
||||
RcPolyMeshDetail dmesh = rcResult.MeshDetail;
|
||||
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
|
||||
option.verts = m_pmesh.verts;
|
||||
option.vertCount = m_pmesh.nverts;
|
||||
option.polys = m_pmesh.polys;
|
||||
option.polyAreas = m_pmesh.areas;
|
||||
option.polyFlags = m_pmesh.flags;
|
||||
option.polyCount = m_pmesh.npolys;
|
||||
option.nvp = m_pmesh.nvp;
|
||||
option.detailMeshes = m_dmesh.meshes;
|
||||
option.detailVerts = m_dmesh.verts;
|
||||
option.detailVertsCount = m_dmesh.nverts;
|
||||
option.detailTris = m_dmesh.tris;
|
||||
option.detailTriCount = m_dmesh.ntris;
|
||||
option.verts = pmesh.verts;
|
||||
option.vertCount = pmesh.nverts;
|
||||
option.polys = pmesh.polys;
|
||||
option.polyAreas = pmesh.areas;
|
||||
option.polyFlags = pmesh.flags;
|
||||
option.polyCount = pmesh.npolys;
|
||||
option.nvp = pmesh.nvp;
|
||||
option.detailMeshes = dmesh.meshes;
|
||||
option.detailVerts = dmesh.verts;
|
||||
option.detailVertsCount = dmesh.nverts;
|
||||
option.detailTris = dmesh.tris;
|
||||
option.detailTriCount = dmesh.ntris;
|
||||
option.walkableHeight = agentHeight;
|
||||
option.walkableRadius = agentRadius;
|
||||
option.walkableClimb = agentMaxClimb;
|
||||
option.bmin = m_pmesh.bmin;
|
||||
option.bmax = m_pmesh.bmax;
|
||||
option.bmin = pmesh.bmin;
|
||||
option.bmax = pmesh.bmax;
|
||||
option.cs = cellSize;
|
||||
option.ch = cellHeight;
|
||||
option.buildBvTree = true;
|
||||
|
@ -120,11 +117,8 @@ public class RecastTestMeshBuilder
|
|||
option.offMeshConUserID = new int[1];
|
||||
option.offMeshConUserID[0] = 0x4567;
|
||||
option.offMeshConCount = 1;
|
||||
meshData = DtNavMeshBuilder.CreateNavMeshData(option);
|
||||
}
|
||||
var meshData = DtNavMeshBuilder.CreateNavMeshData(option);
|
||||
|
||||
public DtMeshData GetMeshData()
|
||||
{
|
||||
return meshData;
|
||||
}
|
||||
}
|
|
@ -7,19 +7,19 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="NUnit" Version="4.2.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.6" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -6,11 +7,11 @@ using DotRecast.Core.Numerics;
|
|||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
using DotRecast.Detour.Dynamic.Io;
|
||||
using DotRecast.Detour.Dynamic.Test.Io;
|
||||
using DotRecast.Detour.Io;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Detour.Dynamic.Test;
|
||||
|
||||
|
||||
public class DynamicNavMeshTest
|
||||
{
|
||||
private static readonly RcVec3f START_POS = new RcVec3f(70.87453f, 0.0010070801f, 86.69021f);
|
||||
|
@ -22,7 +23,7 @@ public class DynamicNavMeshTest
|
|||
[Test]
|
||||
public void E2eTest()
|
||||
{
|
||||
byte[] bytes = RcResources.Load("test_tiles.voxels");
|
||||
byte[] bytes = RcIO.ReadFileIfFound("test_tiles.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
using var br = new BinaryReader(ms);
|
||||
|
||||
|
@ -32,9 +33,7 @@ public class DynamicNavMeshTest
|
|||
// create dynamic navmesh
|
||||
DtDynamicNavMesh mesh = new DtDynamicNavMesh(f);
|
||||
// build navmesh asynchronously using multiple threads
|
||||
Task<bool> future = mesh.Build(Task.Factory);
|
||||
// wait for build to complete
|
||||
bool _ = future.Result;
|
||||
mesh.Build(Task.Factory);
|
||||
|
||||
// create new query
|
||||
DtNavMeshQuery query = new DtNavMeshQuery(mesh.NavMesh());
|
||||
|
@ -54,9 +53,8 @@ public class DynamicNavMeshTest
|
|||
long colliderId = mesh.AddCollider(colldier);
|
||||
|
||||
// update navmesh asynchronously
|
||||
future = mesh.Update(Task.Factory);
|
||||
// wait for update to complete
|
||||
_ = future.Result;
|
||||
mesh.Update(Task.Factory);
|
||||
|
||||
// create new query
|
||||
query = new DtNavMeshQuery(mesh.NavMesh());
|
||||
|
||||
|
@ -70,9 +68,7 @@ public class DynamicNavMeshTest
|
|||
// remove obstacle
|
||||
mesh.RemoveCollider(colliderId);
|
||||
// update navmesh asynchronously
|
||||
future = mesh.Update(Task.Factory);
|
||||
// wait for update to complete
|
||||
_ = future.Result;
|
||||
mesh.Update(Task.Factory);
|
||||
// create new query
|
||||
query = new DtNavMeshQuery(mesh.NavMesh());
|
||||
|
||||
|
@ -84,4 +80,101 @@ public class DynamicNavMeshTest
|
|||
// path length should be back to the initial value
|
||||
Assert.That(path.Count, Is.EqualTo(16));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void ShouldSaveAndLoadDynamicNavMesh()
|
||||
{
|
||||
using var writerMs = new MemoryStream();
|
||||
using var bw = new BinaryWriter(writerMs);
|
||||
|
||||
|
||||
int maxVertsPerPoly = 6;
|
||||
// load voxels from file
|
||||
|
||||
{
|
||||
byte[] bytes = RcIO.ReadFileIfFound("test_tiles.voxels");
|
||||
using var readMs = new MemoryStream(bytes);
|
||||
using var br = new BinaryReader(readMs);
|
||||
|
||||
DtVoxelFileReader reader = new DtVoxelFileReader(DtVoxelTileLZ4ForTestCompressor.Shared);
|
||||
DtVoxelFile f = reader.Read(br);
|
||||
|
||||
// create dynamic navmesh
|
||||
DtDynamicNavMesh mesh = new DtDynamicNavMesh(f);
|
||||
|
||||
// build navmesh asynchronously using multiple threads
|
||||
mesh.Build(Task.Factory);
|
||||
|
||||
// Save the resulting nav mesh and re-use it
|
||||
new DtMeshSetWriter().Write(bw, mesh.NavMesh(), RcByteOrder.LITTLE_ENDIAN, true);
|
||||
maxVertsPerPoly = mesh.NavMesh().GetMaxVertsPerPoly();
|
||||
}
|
||||
|
||||
{
|
||||
byte[] bytes = RcIO.ReadFileIfFound("test_tiles.voxels");
|
||||
using var readMs = new MemoryStream(bytes);
|
||||
using var br = new BinaryReader(readMs);
|
||||
|
||||
// load voxels from file
|
||||
DtVoxelFileReader reader = new DtVoxelFileReader(DtVoxelTileLZ4ForTestCompressor.Shared);
|
||||
DtVoxelFile f = reader.Read(br);
|
||||
|
||||
// create dynamic navmesh
|
||||
DtDynamicNavMesh mesh = new DtDynamicNavMesh(f);
|
||||
// use the saved nav mesh instead of building from scratch
|
||||
DtNavMesh navMesh = new DtMeshSetReader().Read(new RcByteBuffer(writerMs.ToArray()), maxVertsPerPoly);
|
||||
mesh.NavMesh(navMesh);
|
||||
|
||||
DtNavMeshQuery query = new DtNavMeshQuery(mesh.NavMesh());
|
||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||
|
||||
// find path
|
||||
_ = query.FindNearestPoly(START_POS, EXTENT, filter, out var startNearestRef, out var startNearestPos, out var _);
|
||||
_ = query.FindNearestPoly(END_POS, EXTENT, filter, out var endNearestRef, out var endNearestPos, out var _);
|
||||
|
||||
List<long> path = new List<long>();
|
||||
query.FindPath(startNearestRef, endNearestRef, startNearestPos, endNearestPos, filter, ref path, DtFindPathOption.AnyAngle);
|
||||
|
||||
// check path length without any obstacles
|
||||
Assert.That(path.Count, Is.EqualTo(16));
|
||||
|
||||
// place obstacle
|
||||
DtCollider colldier = new DtSphereCollider(SPHERE_POS, 20, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND, 0.1f);
|
||||
long colliderId = mesh.AddCollider(colldier);
|
||||
|
||||
// update navmesh asynchronously
|
||||
mesh.Update(Task.Factory);
|
||||
|
||||
// create new query
|
||||
query = new DtNavMeshQuery(mesh.NavMesh());
|
||||
|
||||
// find path again
|
||||
_ = query.FindNearestPoly(START_POS, EXTENT, filter, out startNearestRef, out startNearestPos, out var _);
|
||||
_ = query.FindNearestPoly(END_POS, EXTENT, filter, out endNearestRef, out endNearestPos, out var _);
|
||||
|
||||
path = new List<long>();
|
||||
query.FindPath(startNearestRef, endNearestRef, startNearestPos, endNearestPos, filter, ref path, DtFindPathOption.AnyAngle);
|
||||
|
||||
// check path length with obstacles
|
||||
Assert.That(path.Count, Is.EqualTo(19));
|
||||
|
||||
// remove obstacle
|
||||
mesh.RemoveCollider(colliderId);
|
||||
// update navmesh asynchronously
|
||||
mesh.Update(Task.Factory);
|
||||
|
||||
// create new query
|
||||
query = new DtNavMeshQuery(mesh.NavMesh());
|
||||
// find path one more time
|
||||
_ = query.FindNearestPoly(START_POS, EXTENT, filter, out startNearestRef, out startNearestPos, out var _);
|
||||
_ = query.FindNearestPoly(END_POS, EXTENT, filter, out endNearestRef, out endNearestPos, out var _);
|
||||
|
||||
path = new List<long>();
|
||||
query.FindPath(startNearestRef, endNearestRef, startNearestPos, endNearestPos, filter, ref path, DtFindPathOption.AnyAngle);
|
||||
|
||||
// path length should be back to the initial value
|
||||
Assert.That(path.Count, Is.EqualTo(16));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -31,7 +31,7 @@ public class VoxelFileReaderTest
|
|||
[Test]
|
||||
public void ShouldReadSingleTileFile()
|
||||
{
|
||||
byte[] bytes = RcResources.Load("test.voxels");
|
||||
byte[] bytes = RcIO.ReadFileIfFound("test.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
using var br = new BinaryReader(ms);
|
||||
|
||||
|
@ -57,7 +57,7 @@ public class VoxelFileReaderTest
|
|||
[Test]
|
||||
public void ShouldReadMultiTileFile()
|
||||
{
|
||||
byte[] bytes = RcResources.Load("test_tiles.voxels");
|
||||
byte[] bytes = RcIO.ReadFileIfFound("test_tiles.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
using var br = new BinaryReader(ms);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -32,7 +32,7 @@ public class VoxelFileReaderWriterTest
|
|||
[TestCase(true)]
|
||||
public void ShouldReadSingleTileFile(bool compression)
|
||||
{
|
||||
byte[] bytes = RcResources.Load("test.voxels");
|
||||
byte[] bytes = RcIO.ReadFileIfFound("test.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
using var br = new BinaryReader(ms);
|
||||
|
||||
|
@ -60,7 +60,7 @@ public class VoxelFileReaderWriterTest
|
|||
[TestCase(true)]
|
||||
public void ShouldReadMultiTileFile(bool compression)
|
||||
{
|
||||
byte[] bytes = RcResources.Load("test_tiles.voxels");
|
||||
byte[] bytes = RcIO.ReadFileIfFound("test_tiles.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
using var br = new BinaryReader(ms);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -31,7 +31,6 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Detour.Dynamic.Test;
|
||||
|
||||
|
||||
public class VoxelQueryTest
|
||||
{
|
||||
private const int TILE_WIDTH = 100;
|
||||
|
@ -94,19 +93,19 @@ public class VoxelQueryTest
|
|||
|
||||
private DtDynamicNavMesh CreateDynaMesh()
|
||||
{
|
||||
var bytes = RcResources.Load("test_tiles.voxels");
|
||||
var bytes = RcIO.ReadFileIfFound("test_tiles.voxels");
|
||||
using var ms = new MemoryStream(bytes);
|
||||
using var br = new BinaryReader(ms);
|
||||
|
||||
// load voxels from file
|
||||
DtVoxelFileReader reader = new DtVoxelFileReader(DtVoxelTileLZ4ForTestCompressor.Shared);
|
||||
DtVoxelFile f = reader.Read(br);
|
||||
|
||||
// create dynamic navmesh
|
||||
var mesh = new DtDynamicNavMesh(f);
|
||||
|
||||
// build navmesh asynchronously using multiple threads
|
||||
Task<bool> future = mesh.Build(Task.Factory);
|
||||
// wait for build to complete
|
||||
var _ = future.Result;
|
||||
mesh.Build(Task.Factory);
|
||||
return mesh;
|
||||
}
|
||||
}
|
|
@ -7,15 +7,15 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="NUnit" Version="4.2.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -21,7 +22,6 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
||||
|
||||
public abstract class AbstractDetourTest
|
||||
{
|
||||
protected static readonly long[] startRefs =
|
||||
|
@ -64,6 +64,8 @@ public abstract class AbstractDetourTest
|
|||
|
||||
protected DtNavMesh CreateNavMesh()
|
||||
{
|
||||
return new DtNavMesh(new RecastTestMeshBuilder().GetMeshData(), 6, 0);
|
||||
var mesh = new DtNavMesh();
|
||||
mesh.Init(TestMeshDataFactory.Create(), 6, 0);
|
||||
return mesh;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -17,6 +17,7 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
@ -29,9 +30,10 @@ public class ConvexConvexIntersectionTest
|
|||
{
|
||||
float[] p = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||
float[] q = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||
float[] intersection = DtConvexConvexIntersections.Intersect(p, q);
|
||||
float[] buffer = new float[128];
|
||||
Span<float> intersection = DtConvexConvexIntersections.Intersect(p, q, buffer);
|
||||
Assert.That(intersection.Length, Is.EqualTo(5 * 3));
|
||||
Assert.That(intersection, Is.EqualTo(p));
|
||||
Assert.That(intersection.ToArray(), Is.EquivalentTo(p));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -39,8 +41,9 @@ public class ConvexConvexIntersectionTest
|
|||
{
|
||||
float[] p = { -5, 0, -5, -5, 0, 4, 1, 0, 4, 1, 0, -5 };
|
||||
float[] q = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||
float[] intersection = DtConvexConvexIntersections.Intersect(p, q);
|
||||
float[] buffer = new float[128];
|
||||
Span<float> intersection = DtConvexConvexIntersections.Intersect(p, q, buffer);
|
||||
Assert.That(intersection.Length, Is.EqualTo(5 * 3));
|
||||
Assert.That(intersection, Is.EqualTo(new[] { 1, 0, 3, 1, 0, -3.4f, -2, 0, -4, -4, 0, 0, -3, 0, 3 }));
|
||||
Assert.That(intersection.ToArray(), Is.EquivalentTo(new[] { 1, 0, 3, 1, 0, -3.4f, -2, 0, -4, -4, 0, 0, -3, 0, 3 }));
|
||||
}
|
||||
}
|
|
@ -7,15 +7,15 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="NUnit" Version="4.2.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Immutable;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Collections;
|
||||
using NUnit.Framework;
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using DotRecast.Core.Numerics;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
||||
public class FindCollectPolyTest : AbstractDetourTest
|
||||
{
|
||||
private static readonly long[][] POLY_REFS =
|
||||
{
|
||||
new long[]
|
||||
{
|
||||
281474976710697L,
|
||||
281474976710695L,
|
||||
281474976710696L,
|
||||
281474976710691L,
|
||||
},
|
||||
new long[]
|
||||
{
|
||||
281474976710769L,
|
||||
281474976710773L,
|
||||
},
|
||||
new long[]
|
||||
{
|
||||
281474976710676L,
|
||||
281474976710678L,
|
||||
281474976710679L,
|
||||
281474976710674L,
|
||||
281474976710677L,
|
||||
281474976710683L,
|
||||
281474976710680L,
|
||||
281474976710684L,
|
||||
},
|
||||
|
||||
new long[]
|
||||
{
|
||||
281474976710748L,
|
||||
281474976710753L,
|
||||
281474976710752L,
|
||||
281474976710750L,
|
||||
},
|
||||
|
||||
new long[]
|
||||
{
|
||||
281474976710736L,
|
||||
281474976710733L,
|
||||
281474976710735L,
|
||||
}
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestFindNearestPoly()
|
||||
{
|
||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||
RcVec3f extents = new RcVec3f(2, 4, 2);
|
||||
var polys = new long[32];
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
{
|
||||
Array.Fill(polys, 0);
|
||||
RcVec3f startPos = startPoss[i];
|
||||
var status = query.QueryPolygons(startPos, extents, filter, polys, out var polyCount, 32);
|
||||
Assert.That(status.Succeeded(), Is.True, $"index({i})");
|
||||
Assert.That(polyCount, Is.EqualTo(POLY_REFS[i].Length), $"index({i})");
|
||||
Assert.That(polys.AsSpan(0, polyCount).ToArray(), Is.EqualTo(POLY_REFS[i]), $"index({i})");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -21,10 +22,12 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
||||
|
||||
public class FindNearestPolyTest : AbstractDetourTest
|
||||
{
|
||||
private static readonly long[] POLY_REFS = { 281474976710696L, 281474976710773L, 281474976710680L, 281474976710753L, 281474976710733L };
|
||||
private static readonly long[] POLY_REFS =
|
||||
{
|
||||
281474976710696L, 281474976710773L, 281474976710680L, 281474976710753L, 281474976710733L
|
||||
};
|
||||
|
||||
private static readonly RcVec3f[] POLY_POS =
|
||||
{
|
||||
|
@ -44,11 +47,11 @@ public class FindNearestPolyTest : AbstractDetourTest
|
|||
{
|
||||
RcVec3f startPos = startPoss[i];
|
||||
var status = query.FindNearestPoly(startPos, extents, filter, out var nearestRef, out var nearestPt, out var _);
|
||||
Assert.That(status.Succeeded(), Is.True);
|
||||
Assert.That(nearestRef, Is.EqualTo(POLY_REFS[i]));
|
||||
Assert.That(nearestPt.X, Is.EqualTo(POLY_POS[i].X).Within(0.001f));
|
||||
Assert.That(nearestPt.Y, Is.EqualTo(POLY_POS[i].Y).Within(0.001f));
|
||||
Assert.That(nearestPt.Z, Is.EqualTo(POLY_POS[i].Z).Within(0.001f));
|
||||
Assert.That(status.Succeeded(), Is.True, $"index({i})");
|
||||
Assert.That(nearestRef, Is.EqualTo(POLY_REFS[i]), $"index({i})");
|
||||
Assert.That(nearestPt.X, Is.EqualTo(POLY_POS[i].X).Within(0.001f), $"index({i})");
|
||||
Assert.That(nearestPt.Y, Is.EqualTo(POLY_POS[i].Y).Within(0.001f), $"index({i})");
|
||||
Assert.That(nearestPt.Z, Is.EqualTo(POLY_POS[i].Z).Within(0.001f), $"index({i})");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -16,13 +17,13 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
||||
|
||||
public class FindPathTest : AbstractDetourTest
|
||||
{
|
||||
private static readonly DtStatus[] STATUSES =
|
||||
|
@ -184,6 +185,7 @@ public class FindPathTest : AbstractDetourTest
|
|||
{
|
||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||
var path = new List<long>();
|
||||
Span<DtStraightPath> straightPath = stackalloc DtStraightPath[256];
|
||||
for (int i = 0; i < STRAIGHT_PATHS.Length; i++)
|
||||
{
|
||||
// startRefs.Length; i++) {
|
||||
|
@ -192,9 +194,8 @@ public class FindPathTest : AbstractDetourTest
|
|||
var startPos = startPoss[i];
|
||||
var endPos = endPoss[i];
|
||||
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
|
||||
var straightPath = new List<DtStraightPath>();
|
||||
query.FindStraightPath(startPos, endPos, path, ref straightPath, int.MaxValue, 0);
|
||||
Assert.That(straightPath.Count, Is.EqualTo(STRAIGHT_PATHS[i].Length));
|
||||
query.FindStraightPath(startPos, endPos, path, path.Count, straightPath, out var nstraightPath, 256, 0);
|
||||
Assert.That(nstraightPath, Is.EqualTo(STRAIGHT_PATHS[i].Length));
|
||||
for (int j = 0; j < STRAIGHT_PATHS[i].Length; j++)
|
||||
{
|
||||
Assert.That(straightPath[j].refs, Is.EqualTo(STRAIGHT_PATHS[i][j].refs));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -16,13 +17,13 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
||||
|
||||
public class GetPolyWallSegmentsTest : AbstractDetourTest
|
||||
{
|
||||
private static readonly RcSegmentVert[][] VERTICES =
|
||||
|
@ -82,28 +83,30 @@ public class GetPolyWallSegmentsTest : AbstractDetourTest
|
|||
[Test]
|
||||
public void TestFindDistanceToWall()
|
||||
{
|
||||
var segmentVerts = new List<RcSegmentVert>();
|
||||
var segmentRefs = new List<long>();
|
||||
const int MAX_SEGS = DtDetour.DT_VERTS_PER_POLYGON * 4;
|
||||
Span<RcSegmentVert> segs = stackalloc RcSegmentVert[MAX_SEGS];
|
||||
Span<long> refs = stackalloc long[MAX_SEGS];
|
||||
int nsegs = 0;
|
||||
|
||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
{
|
||||
var result = query.GetPolyWallSegments(startRefs[i], true, filter, ref segmentVerts, ref segmentRefs);
|
||||
Assert.That(segmentVerts.Count, Is.EqualTo(VERTICES[i].Length));
|
||||
Assert.That(segmentRefs.Count, Is.EqualTo(REFS[i].Length));
|
||||
var result = query.GetPolyWallSegments(startRefs[i], filter, segs, refs, ref nsegs, MAX_SEGS);
|
||||
Assert.That(nsegs, Is.EqualTo(VERTICES[i].Length));
|
||||
Assert.That(nsegs, Is.EqualTo(REFS[i].Length));
|
||||
for (int v = 0; v < VERTICES[i].Length / 6; v++)
|
||||
{
|
||||
Assert.That(segmentVerts[v].vmin.X, Is.EqualTo(VERTICES[i][v].vmin.X).Within(0.001f));
|
||||
Assert.That(segmentVerts[v].vmin.Y, Is.EqualTo(VERTICES[i][v].vmin.Y).Within(0.001f));
|
||||
Assert.That(segmentVerts[v].vmin.Z, Is.EqualTo(VERTICES[i][v].vmin.Z).Within(0.001f));
|
||||
Assert.That(segmentVerts[v].vmax.X, Is.EqualTo(VERTICES[i][v].vmax.X).Within(0.001f));
|
||||
Assert.That(segmentVerts[v].vmax.Y, Is.EqualTo(VERTICES[i][v].vmax.Y).Within(0.001f));
|
||||
Assert.That(segmentVerts[v].vmax.Z, Is.EqualTo(VERTICES[i][v].vmax.Z).Within(0.001f));
|
||||
Assert.That(segs[v].vmin.X, Is.EqualTo(VERTICES[i][v].vmin.X).Within(0.001f));
|
||||
Assert.That(segs[v].vmin.Y, Is.EqualTo(VERTICES[i][v].vmin.Y).Within(0.001f));
|
||||
Assert.That(segs[v].vmin.Z, Is.EqualTo(VERTICES[i][v].vmin.Z).Within(0.001f));
|
||||
Assert.That(segs[v].vmax.X, Is.EqualTo(VERTICES[i][v].vmax.X).Within(0.001f));
|
||||
Assert.That(segs[v].vmax.Y, Is.EqualTo(VERTICES[i][v].vmax.Y).Within(0.001f));
|
||||
Assert.That(segs[v].vmax.Z, Is.EqualTo(VERTICES[i][v].vmax.Z).Within(0.001f));
|
||||
}
|
||||
|
||||
for (int v = 0; v < REFS[i].Length; v++)
|
||||
{
|
||||
Assert.That(segmentRefs[v], Is.EqualTo(REFS[i][v]));
|
||||
Assert.That(refs[v], Is.EqualTo(REFS[i][v]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -32,8 +33,7 @@ public class MeshDataReaderWriterTest
|
|||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
RecastTestMeshBuilder rcBuilder = new RecastTestMeshBuilder();
|
||||
meshData = rcBuilder.GetMeshData();
|
||||
meshData = TestMeshDataFactory.Create();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -117,11 +117,8 @@ public class MeshDataReaderWriterTest
|
|||
for (int i = 0; i < meshData.header.bvNodeCount; i++)
|
||||
{
|
||||
Assert.That(readData.bvTree[i].i, Is.EqualTo(meshData.bvTree[i].i));
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
Assert.That(readData.bvTree[i].bmin[j], Is.EqualTo(meshData.bvTree[i].bmin[j]));
|
||||
Assert.That(readData.bvTree[i].bmax[j], Is.EqualTo(meshData.bvTree[i].bmax[j]));
|
||||
}
|
||||
Assert.That(readData.bvTree[i].bmin, Is.EqualTo(meshData.bvTree[i].bmin));
|
||||
Assert.That(readData.bvTree[i].bmax, Is.EqualTo(meshData.bvTree[i].bmax));
|
||||
}
|
||||
|
||||
for (int i = 0; i < meshData.header.offMeshConCount; i++)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -24,7 +25,6 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Detour.Test.Io;
|
||||
|
||||
|
||||
public class MeshSetReaderTest
|
||||
{
|
||||
private readonly DtMeshSetReader reader = new DtMeshSetReader();
|
||||
|
@ -32,27 +32,35 @@ public class MeshSetReaderTest
|
|||
[Test]
|
||||
public void TestNavmesh()
|
||||
{
|
||||
byte[] @is = RcResources.Load("all_tiles_navmesh.bin");
|
||||
byte[] @is = RcIO.ReadFileIfFound("all_tiles_navmesh.bin");
|
||||
using var ms = new MemoryStream(@is);
|
||||
using var br = new BinaryReader(ms);
|
||||
DtNavMesh mesh = reader.Read(br, 6);
|
||||
Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<DtMeshTile> tiles = mesh.GetTilesAt(4, 7);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
const int MAX_NEIS = 32;
|
||||
DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS];
|
||||
int nneis = 0;
|
||||
|
||||
nneis = mesh.GetTilesAt(4, 7, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(7));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(22 * 3));
|
||||
tiles = mesh.GetTilesAt(1, 6);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(1, 6, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(7));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(26 * 3));
|
||||
tiles = mesh.GetTilesAt(6, 2);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(6, 2, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(4 * 3));
|
||||
tiles = mesh.GetTilesAt(7, 6);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(7, 6, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(8));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(24 * 3));
|
||||
}
|
||||
|
@ -60,7 +68,7 @@ public class MeshSetReaderTest
|
|||
[Test]
|
||||
public void TestDungeon()
|
||||
{
|
||||
byte[] @is = RcResources.Load("dungeon_all_tiles_navmesh.bin");
|
||||
byte[] @is = RcIO.ReadFileIfFound("dungeon_all_tiles_navmesh.bin");
|
||||
using var ms = new MemoryStream(@is);
|
||||
using var br = new BinaryReader(ms);
|
||||
|
||||
|
@ -68,20 +76,28 @@ public class MeshSetReaderTest
|
|||
Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<DtMeshTile> tiles = mesh.GetTilesAt(6, 9);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
const int MAX_NEIS = 32;
|
||||
DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS];
|
||||
int nneis = 0;
|
||||
|
||||
nneis = mesh.GetTilesAt(6, 9, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3));
|
||||
tiles = mesh.GetTilesAt(2, 9);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(2, 9, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3));
|
||||
tiles = mesh.GetTilesAt(4, 3);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(4, 3, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3));
|
||||
tiles = mesh.GetTilesAt(2, 8);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(2, 8, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3));
|
||||
}
|
||||
|
@ -89,7 +105,7 @@ public class MeshSetReaderTest
|
|||
[Test]
|
||||
public void TestDungeon32Bit()
|
||||
{
|
||||
byte[] @is = RcResources.Load("dungeon_all_tiles_navmesh_32bit.bin");
|
||||
byte[] @is = RcIO.ReadFileIfFound("dungeon_all_tiles_navmesh_32bit.bin");
|
||||
using var ms = new MemoryStream(@is);
|
||||
using var br = new BinaryReader(ms);
|
||||
|
||||
|
@ -97,20 +113,28 @@ public class MeshSetReaderTest
|
|||
Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<DtMeshTile> tiles = mesh.GetTilesAt(6, 9);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
const int MAX_NEIS = 32;
|
||||
DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS];
|
||||
int nneis = 0;
|
||||
|
||||
nneis = mesh.GetTilesAt(6, 9, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3));
|
||||
tiles = mesh.GetTilesAt(2, 9);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(2, 9, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3));
|
||||
tiles = mesh.GetTilesAt(4, 3);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(4, 3, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3));
|
||||
tiles = mesh.GetTilesAt(2, 8);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(2, 8, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -28,7 +29,6 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Detour.Test.Io;
|
||||
|
||||
|
||||
public class MeshSetReaderWriterTest
|
||||
{
|
||||
private readonly DtMeshSetWriter writer = new DtMeshSetWriter();
|
||||
|
@ -66,11 +66,12 @@ public class MeshSetReaderWriterTest
|
|||
header.option.maxTiles = m_maxTiles;
|
||||
header.option.maxPolys = m_maxPolysPerTile;
|
||||
header.numTiles = 0;
|
||||
DtNavMesh mesh = new DtNavMesh(header.option, 6);
|
||||
DtNavMesh mesh = new DtNavMesh();
|
||||
mesh.Init(header.option, 6);
|
||||
|
||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
||||
RcCommons.CalcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize, out var tw, out var th);
|
||||
RcRecast.CalcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize, out var tw, out var th);
|
||||
for (int y = 0; y < th; ++y)
|
||||
{
|
||||
for (int x = 0; x < tw; ++x)
|
||||
|
@ -92,7 +93,7 @@ public class MeshSetReaderWriterTest
|
|||
if (data != null)
|
||||
{
|
||||
mesh.RemoveTile(mesh.GetTileRefAt(x, y, 0));
|
||||
mesh.AddTile(data, 0, 0);
|
||||
mesh.AddTile(data, 0, 0, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,20 +108,28 @@ public class MeshSetReaderWriterTest
|
|||
Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128));
|
||||
Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000));
|
||||
Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f));
|
||||
List<DtMeshTile> tiles = mesh.GetTilesAt(6, 9);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
const int MAX_NEIS = 32;
|
||||
DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS];
|
||||
int nneis = 0;
|
||||
|
||||
nneis = mesh.GetTilesAt(6, 9, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3));
|
||||
tiles = mesh.GetTilesAt(2, 9);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(2, 9, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3));
|
||||
tiles = mesh.GetTilesAt(4, 3);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(4, 3, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3));
|
||||
tiles = mesh.GetTilesAt(2, 8);
|
||||
Assert.That(tiles.Count, Is.EqualTo(1));
|
||||
|
||||
nneis = mesh.GetTilesAt(2, 8, tiles, MAX_NEIS);
|
||||
Assert.That(nneis, Is.EqualTo(1));
|
||||
Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5));
|
||||
Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -16,13 +17,13 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
||||
|
||||
public class MoveAlongSurfaceTest : AbstractDetourTest
|
||||
{
|
||||
private static readonly long[][] VISITED =
|
||||
|
@ -69,20 +70,21 @@ public class MoveAlongSurfaceTest : AbstractDetourTest
|
|||
public void TestMoveAlongSurface()
|
||||
{
|
||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||
var visited = new List<long>();
|
||||
const int MAX_VISITED = 32;
|
||||
Span<long> visited = stackalloc long[MAX_VISITED];
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
{
|
||||
long startRef = startRefs[i];
|
||||
RcVec3f startPos = startPoss[i];
|
||||
RcVec3f endPos = endPoss[i];
|
||||
var status = query.MoveAlongSurface(startRef, startPos, endPos, filter, out var result, ref visited);
|
||||
var status = query.MoveAlongSurface(startRef, startPos, endPos, filter, out var result, visited, out var nvisited, MAX_VISITED);
|
||||
Assert.That(status.Succeeded(), Is.True);
|
||||
|
||||
Assert.That(result.X, Is.EqualTo(POSITION[i].X).Within(0.01f));
|
||||
Assert.That(result.Y, Is.EqualTo(POSITION[i].Y).Within(0.01f));
|
||||
Assert.That(result.Z, Is.EqualTo(POSITION[i].Z).Within(0.01f));
|
||||
|
||||
Assert.That(visited.Count, Is.EqualTo(VISITED[i].Length));
|
||||
Assert.That(nvisited, Is.EqualTo(VISITED[i].Length));
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
Assert.That(visited[j], Is.EqualTo(VISITED[i][j]));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -21,6 +22,7 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
||||
using static DtDetour;
|
||||
|
||||
public class NavMeshBuilderTest
|
||||
{
|
||||
|
@ -29,7 +31,7 @@ public class NavMeshBuilderTest
|
|||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
nmd = new RecastTestMeshBuilder().GetMeshData();
|
||||
nmd = TestMeshDataFactory.Create();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -52,12 +54,12 @@ public class NavMeshBuilderTest
|
|||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Assert.That(RcVecUtils.Create(nmd.verts, 223 * 3 + (i * 3)), Is.EqualTo(nmd.offMeshCons[0].pos[i]));
|
||||
Assert.That(RcVec.Create(nmd.verts, 223 * 3 + (i * 3)), Is.EqualTo(nmd.offMeshCons[0].pos[i]));
|
||||
}
|
||||
|
||||
Assert.That(nmd.offMeshCons[0].rad, Is.EqualTo(0.1f));
|
||||
Assert.That(nmd.offMeshCons[0].poly, Is.EqualTo(118));
|
||||
Assert.That(nmd.offMeshCons[0].flags, Is.EqualTo(DtNavMesh.DT_OFFMESH_CON_BIDIR));
|
||||
Assert.That(nmd.offMeshCons[0].flags, Is.EqualTo(DT_OFFMESH_CON_BIDIR));
|
||||
Assert.That(nmd.offMeshCons[0].side, Is.EqualTo(0xFF));
|
||||
Assert.That(nmd.offMeshCons[0].userId, Is.EqualTo(0x4567));
|
||||
Assert.That(nmd.polys[118].vertCount, Is.EqualTo(2));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -17,6 +17,7 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using DotRecast.Core.Numerics;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
@ -32,9 +33,12 @@ public class PolygonByCircleConstraintTest
|
|||
{
|
||||
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
|
||||
RcVec3f center = new RcVec3f(1, 0, 1);
|
||||
float[] constrained = _constraint.Apply(polygon, center, 6);
|
||||
var radius = 6;
|
||||
|
||||
Assert.That(constrained, Is.EqualTo(polygon));
|
||||
float[] buffer = new float[128];
|
||||
Span<float> constrained = _constraint.Apply(polygon, center, radius, buffer);
|
||||
|
||||
Assert.That(constrained.ToArray(), Is.EquivalentTo(polygon));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -43,10 +47,13 @@ public class PolygonByCircleConstraintTest
|
|||
int expectedSize = 21;
|
||||
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
|
||||
RcVec3f center = new RcVec3f(2, 0, 0);
|
||||
var radius = 3;
|
||||
|
||||
float[] buffer = new float[128];
|
||||
Span<float> constrained = _constraint.Apply(polygon, center, radius, buffer);
|
||||
|
||||
float[] constrained = _constraint.Apply(polygon, center, 3);
|
||||
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
||||
Assert.That(constrained, Is.SupersetOf(new[] { 2f, 0f, 2f, 2f, 0f, -2f }));
|
||||
Assert.That(constrained.ToArray(), Is.SupersetOf(new[] { 2f, 0f, 2f, 2f, 0f, -2f }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -55,7 +62,10 @@ public class PolygonByCircleConstraintTest
|
|||
int expectedSize = 12 * 3;
|
||||
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||
RcVec3f center = new RcVec3f(-1, 0, -1);
|
||||
float[] constrained = _constraint.Apply(polygon, center, 2);
|
||||
var radius = 2;
|
||||
|
||||
float[] buffer = new float[128];
|
||||
Span<float> constrained = _constraint.Apply(polygon, center, radius, buffer);
|
||||
|
||||
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
||||
|
||||
|
@ -73,10 +83,13 @@ public class PolygonByCircleConstraintTest
|
|||
int expectedSize = 9 * 3;
|
||||
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||
RcVec3f center = new RcVec3f(-2, 0, -1);
|
||||
float[] constrained = _constraint.Apply(polygon, center, 3);
|
||||
var radius = 3;
|
||||
|
||||
float[] buffer = new float[128];
|
||||
Span<float> constrained = _constraint.Apply(polygon, center, radius, buffer);
|
||||
|
||||
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
||||
Assert.That(constrained, Is.SupersetOf(new[] { -2f, 0f, -4f, -4f, 0f, 0f, -3.4641016f, 0.0f, 1.60769534f, -2.0f, 0.0f, 2.0f }));
|
||||
Assert.That(constrained.ToArray(), Is.SupersetOf(new[] { -2f, 0f, -4f, -4f, 0f, 0f, -3.4641016f, 0.0f, 1.60769534f, -2.0f, 0.0f, 2.0f }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -85,9 +98,12 @@ public class PolygonByCircleConstraintTest
|
|||
int expectedSize = 7 * 3;
|
||||
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||
RcVec3f center = new RcVec3f(4, 0, 0);
|
||||
float[] constrained = _constraint.Apply(polygon, center, 4);
|
||||
var radius = 4;
|
||||
|
||||
float[] buffer = new float[128];
|
||||
Span<float> constrained = _constraint.Apply(polygon, center, radius, buffer);
|
||||
|
||||
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
||||
Assert.That(constrained, Is.SupersetOf(new[] { 1.53589869f, 0f, 3f, 2f, 0f, 3f, 3f, 0f, -3f }));
|
||||
Assert.That(constrained.ToArray(), Is.SupersetOf(new[] { 1.53589869f, 0f, 3f, 2f, 0f, 3f, 3f, 0f, -3f }));
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2021 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -19,21 +20,22 @@ freely, subject to the following restrictions:
|
|||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Core.Numerics;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
||||
|
||||
public class RandomPointTest : AbstractDetourTest
|
||||
{
|
||||
[Test]
|
||||
[Repeat(10)]
|
||||
public void TestRandom()
|
||||
{
|
||||
RcRand f = new RcRand(1);
|
||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||
for (int i = 0; i < 1000; i++)
|
||||
|
||||
var begin = RcFrequency.Ticks;
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
var status = query.FindRandomPoint(filter, f, out var randomRef, out var randomPt);
|
||||
Assert.That(status.Succeeded(), Is.True);
|
||||
|
@ -55,6 +57,9 @@ public class RandomPointTest : AbstractDetourTest
|
|||
Assert.That(randomPt.Z >= bmin[1], Is.True);
|
||||
Assert.That(randomPt.Z <= bmax[1], Is.True);
|
||||
}
|
||||
|
||||
var ticks = RcFrequency.Ticks - begin;
|
||||
Console.WriteLine($"RandomPointTest::TestRandom() - {(double)ticks / TimeSpan.TicksPerMillisecond} ms");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -103,7 +108,7 @@ public class RandomPointTest : AbstractDetourTest
|
|||
var status = query.FindRandomPointWithinCircle(randomRef, randomPt, radius, filter, f, out var nextRandomRef, out var nextRandomPt);
|
||||
Assert.That(status.Failed(), Is.False);
|
||||
|
||||
float distance = RcVecUtils.Dist2D(randomPt, nextRandomPt);
|
||||
float distance = RcVec.Dist2D(randomPt, nextRandomPt);
|
||||
Assert.That(distance <= radius, Is.True);
|
||||
|
||||
randomRef = nextRandomRef;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -27,8 +28,8 @@ public class TestDetourBuilder : DetourBuilder
|
|||
float agentMaxClimb, int x, int y, bool applyRecastDemoFlags)
|
||||
{
|
||||
RcBuilder rcBuilder = new RcBuilder();
|
||||
RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig);
|
||||
RcPolyMesh pmesh = rcResult.GetMesh();
|
||||
RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig, false);
|
||||
RcPolyMesh pmesh = rcResult.Mesh;
|
||||
|
||||
if (applyRecastDemoFlags)
|
||||
{
|
||||
|
@ -58,7 +59,7 @@ public class TestDetourBuilder : DetourBuilder
|
|||
}
|
||||
}
|
||||
|
||||
RcPolyMeshDetail dmesh = rcResult.GetMeshDetail();
|
||||
RcPolyMeshDetail dmesh = rcResult.MeshDetail;
|
||||
DtNavMeshCreateParams option = GetNavMeshCreateParams(rcConfig.cfg, pmesh, dmesh, agentHeight, agentRadius,
|
||||
agentMaxClimb);
|
||||
return Build(option, x, y);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -16,15 +17,13 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast;
|
||||
using DotRecast.Recast.Geom;
|
||||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
||||
public class RecastTestMeshBuilder
|
||||
public static class TestMeshDataFactory
|
||||
{
|
||||
private readonly DtMeshData meshData;
|
||||
private const float m_cellSize = 0.3f;
|
||||
private const float m_cellHeight = 0.2f;
|
||||
private const float m_agentHeight = 2.0f;
|
||||
|
@ -39,27 +38,24 @@ public class RecastTestMeshBuilder
|
|||
private const float m_detailSampleDist = 6.0f;
|
||||
private const float m_detailSampleMaxError = 1.0f;
|
||||
|
||||
public RecastTestMeshBuilder()
|
||||
: this(SimpleInputGeomProvider.LoadFile("dungeon.obj"),
|
||||
RcPartition.WATERSHED,
|
||||
m_cellSize, m_cellHeight,
|
||||
m_agentMaxSlope, m_agentHeight, m_agentRadius, m_agentMaxClimb,
|
||||
m_regionMinSize, m_regionMergeSize,
|
||||
m_edgeMaxLen, m_edgeMaxError,
|
||||
m_vertsPerPoly,
|
||||
m_detailSampleDist, m_detailSampleMaxError)
|
||||
public static DtMeshData Create()
|
||||
{
|
||||
}
|
||||
IInputGeomProvider geom = SimpleInputGeomProvider.LoadFile("dungeon.obj");
|
||||
RcPartition partition = RcPartition.WATERSHED;
|
||||
float cellSize = m_cellSize;
|
||||
float cellHeight = m_cellHeight;
|
||||
float agentMaxSlope = m_agentMaxSlope;
|
||||
float agentHeight = m_agentHeight;
|
||||
float agentRadius = m_agentRadius;
|
||||
float agentMaxClimb = m_agentMaxClimb;
|
||||
int regionMinSize = m_regionMinSize;
|
||||
int regionMergeSize = m_regionMergeSize;
|
||||
float edgeMaxLen = m_edgeMaxLen;
|
||||
float edgeMaxError = m_edgeMaxError;
|
||||
int vertsPerPoly = m_vertsPerPoly;
|
||||
float detailSampleDist = m_detailSampleDist;
|
||||
float detailSampleMaxError = m_detailSampleMaxError;
|
||||
|
||||
public RecastTestMeshBuilder(IInputGeomProvider geom,
|
||||
RcPartition partition,
|
||||
float cellSize, float cellHeight,
|
||||
float agentMaxSlope, float agentHeight, float agentRadius, float agentMaxClimb,
|
||||
int regionMinSize, int regionMergeSize,
|
||||
float edgeMaxLen, float edgeMaxError,
|
||||
int vertsPerPoly,
|
||||
float detailSampleDist, float detailSampleMaxError)
|
||||
{
|
||||
RcConfig cfg = new RcConfig(
|
||||
partition,
|
||||
cellSize, cellHeight,
|
||||
|
@ -72,32 +68,32 @@ public class RecastTestMeshBuilder
|
|||
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
|
||||
RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
|
||||
RcBuilder rcBuilder = new RcBuilder();
|
||||
RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg);
|
||||
RcPolyMesh m_pmesh = rcResult.GetMesh();
|
||||
for (int i = 0; i < m_pmesh.npolys; ++i)
|
||||
RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg, false);
|
||||
RcPolyMesh pmesh = rcResult.Mesh;
|
||||
for (int i = 0; i < pmesh.npolys; ++i)
|
||||
{
|
||||
m_pmesh.flags[i] = 1;
|
||||
pmesh.flags[i] = 1;
|
||||
}
|
||||
|
||||
RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
|
||||
RcPolyMeshDetail dmesh = rcResult.MeshDetail;
|
||||
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
|
||||
option.verts = m_pmesh.verts;
|
||||
option.vertCount = m_pmesh.nverts;
|
||||
option.polys = m_pmesh.polys;
|
||||
option.polyAreas = m_pmesh.areas;
|
||||
option.polyFlags = m_pmesh.flags;
|
||||
option.polyCount = m_pmesh.npolys;
|
||||
option.nvp = m_pmesh.nvp;
|
||||
option.detailMeshes = m_dmesh.meshes;
|
||||
option.detailVerts = m_dmesh.verts;
|
||||
option.detailVertsCount = m_dmesh.nverts;
|
||||
option.detailTris = m_dmesh.tris;
|
||||
option.detailTriCount = m_dmesh.ntris;
|
||||
option.verts = pmesh.verts;
|
||||
option.vertCount = pmesh.nverts;
|
||||
option.polys = pmesh.polys;
|
||||
option.polyAreas = pmesh.areas;
|
||||
option.polyFlags = pmesh.flags;
|
||||
option.polyCount = pmesh.npolys;
|
||||
option.nvp = pmesh.nvp;
|
||||
option.detailMeshes = dmesh.meshes;
|
||||
option.detailVerts = dmesh.verts;
|
||||
option.detailVertsCount = dmesh.nverts;
|
||||
option.detailTris = dmesh.tris;
|
||||
option.detailTriCount = dmesh.ntris;
|
||||
option.walkableHeight = agentHeight;
|
||||
option.walkableRadius = agentRadius;
|
||||
option.walkableClimb = agentMaxClimb;
|
||||
option.bmin = m_pmesh.bmin;
|
||||
option.bmax = m_pmesh.bmax;
|
||||
option.bmin = pmesh.bmin;
|
||||
option.bmax = pmesh.bmax;
|
||||
option.cs = cellSize;
|
||||
option.ch = cellHeight;
|
||||
option.buildBvTree = true;
|
||||
|
@ -120,11 +116,8 @@ public class RecastTestMeshBuilder
|
|||
option.offMeshConUserID = new int[1];
|
||||
option.offMeshConUserID[0] = 0x4567;
|
||||
option.offMeshConCount = 1;
|
||||
meshData = DtNavMeshBuilder.CreateNavMeshData(option);
|
||||
}
|
||||
var meshData = DtNavMeshBuilder.CreateNavMeshData(option);
|
||||
|
||||
public DtMeshData GetMeshData()
|
||||
{
|
||||
return meshData;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -17,7 +18,6 @@ freely, subject to the following restrictions:
|
|||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Numerics;
|
||||
using DotRecast.Recast;
|
||||
using DotRecast.Recast.Geom;
|
||||
|
||||
|
@ -64,7 +64,8 @@ public class TestTiledNavMeshBuilder
|
|||
navMeshParams.tileHeight = tileSize * cellSize;
|
||||
navMeshParams.maxTiles = 128;
|
||||
navMeshParams.maxPolys = 32768;
|
||||
navMesh = new DtNavMesh(navMeshParams, 6);
|
||||
navMesh = new DtNavMesh();
|
||||
navMesh.Init(navMeshParams, 6);
|
||||
|
||||
// Build all tiles
|
||||
RcConfig cfg = new RcConfig(true, tileSize, tileSize, RcConfig.CalcBorder(agentRadius, cellSize),
|
||||
|
@ -78,13 +79,13 @@ public class TestTiledNavMeshBuilder
|
|||
true, true, true,
|
||||
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
|
||||
RcBuilder rcBuilder = new RcBuilder();
|
||||
List<RcBuilderResult> rcResult = rcBuilder.BuildTiles(geom, cfg, null);
|
||||
List<RcBuilderResult> rcResult = rcBuilder.BuildTiles(geom, cfg, false, true);
|
||||
|
||||
// Add tiles to nav mesh
|
||||
|
||||
foreach (RcBuilderResult result in rcResult)
|
||||
{
|
||||
RcPolyMesh pmesh = result.GetMesh();
|
||||
RcPolyMesh pmesh = result.Mesh;
|
||||
if (pmesh.npolys == 0)
|
||||
{
|
||||
continue;
|
||||
|
@ -103,7 +104,7 @@ public class TestTiledNavMeshBuilder
|
|||
option.polyFlags = pmesh.flags;
|
||||
option.polyCount = pmesh.npolys;
|
||||
option.nvp = pmesh.nvp;
|
||||
RcPolyMeshDetail dmesh = result.GetMeshDetail();
|
||||
RcPolyMeshDetail dmesh = result.MeshDetail;
|
||||
option.detailMeshes = dmesh.meshes;
|
||||
option.detailVerts = dmesh.verts;
|
||||
option.detailVertsCount = dmesh.nverts;
|
||||
|
@ -116,10 +117,10 @@ public class TestTiledNavMeshBuilder
|
|||
option.bmax = pmesh.bmax;
|
||||
option.cs = cellSize;
|
||||
option.ch = cellHeight;
|
||||
option.tileX = result.tileX;
|
||||
option.tileZ = result.tileZ;
|
||||
option.tileX = result.TileX;
|
||||
option.tileZ = result.TileZ;
|
||||
option.buildBvTree = true;
|
||||
navMesh.AddTile(DtNavMeshBuilder.CreateNavMeshData(option), 0, 0);
|
||||
navMesh.AddTile(Detour.DtNavMeshBuilder.CreateNavMeshData(option), 0, 0, out _);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -44,7 +44,7 @@ public class AbstractTileCacheTest
|
|||
public DtTileCache GetTileCache(IInputGeomProvider geom, RcByteOrder order, bool cCompatibility)
|
||||
{
|
||||
DtTileCacheParams option = new DtTileCacheParams();
|
||||
RcCommons.CalcTileCount(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), m_cellSize, m_tileSize, m_tileSize, out var tw, out var th);
|
||||
RcRecast.CalcTileCount(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), m_cellSize, m_tileSize, m_tileSize, out var tw, out var th);
|
||||
option.ch = m_cellHeight;
|
||||
option.cs = m_cellSize;
|
||||
option.orig = geom.GetMeshBoundsMin();
|
||||
|
@ -64,7 +64,8 @@ public class AbstractTileCacheTest
|
|||
navMeshParams.maxTiles = 256;
|
||||
navMeshParams.maxPolys = 16384;
|
||||
|
||||
var navMesh = new DtNavMesh(navMeshParams, 6);
|
||||
var navMesh = new DtNavMesh();
|
||||
navMesh.Init(navMeshParams, 6);
|
||||
var comp = DtTileCacheCompressorFactory.Shared.Create(cCompatibility ? 0 : 1);
|
||||
var storageParams = new DtTileCacheStorageParams(order, cCompatibility);
|
||||
var process = new TestTileCacheMeshProcess();
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="NUnit" Version="4.2.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.6" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -35,7 +35,7 @@ public class TileCacheReaderTest
|
|||
[Test]
|
||||
public void TestNavmesh()
|
||||
{
|
||||
using var ms = new MemoryStream(RcResources.Load("all_tiles_tilecache.bin"));
|
||||
using var ms = new MemoryStream(RcIO.ReadFileIfFound("all_tiles_tilecache.bin"));
|
||||
using var br = new BinaryReader(ms);
|
||||
DtTileCache tc = reader.Read(br, 6, null);
|
||||
Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
|
||||
|
@ -133,7 +133,7 @@ public class TileCacheReaderTest
|
|||
[Test]
|
||||
public void TestDungeon()
|
||||
{
|
||||
using var ms = new MemoryStream(RcResources.Load("dungeon_all_tiles_tilecache.bin"));
|
||||
using var ms = new MemoryStream(RcIO.ReadFileIfFound("dungeon_all_tiles_tilecache.bin"));
|
||||
using var br = new BinaryReader(ms);
|
||||
DtTileCache tc = reader.Read(br, 6, null);
|
||||
Assert.That(tc.GetNavMesh().GetMaxTiles(), Is.EqualTo(256));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -26,7 +26,6 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Detour.TileCache.Test;
|
||||
|
||||
|
||||
public class TempObstaclesTest : AbstractTileCacheTest
|
||||
{
|
||||
[Test]
|
||||
|
@ -43,21 +42,29 @@ public class TempObstaclesTest : AbstractTileCacheTest
|
|||
tc.BuildNavMeshTile(refs);
|
||||
}
|
||||
|
||||
List<DtMeshTile> tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
const int MAX_NEIS = 32;
|
||||
DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS];
|
||||
int nneis = 0;
|
||||
|
||||
nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS);
|
||||
DtMeshTile tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
||||
|
||||
long o = tc.AddObstacle(new RcVec3f(-1.815208f, 9.998184f, -20.307983f), 1f, 2f);
|
||||
bool upToDate = tc.Update();
|
||||
Assert.That(upToDate, Is.True);
|
||||
tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
|
||||
nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS);
|
||||
tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(22));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(11));
|
||||
|
||||
tc.RemoveObstacle(o);
|
||||
upToDate = tc.Update();
|
||||
Assert.That(upToDate, Is.True);
|
||||
tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
|
||||
nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS);
|
||||
tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
||||
|
@ -77,24 +84,32 @@ public class TempObstaclesTest : AbstractTileCacheTest
|
|||
tc.BuildNavMeshTile(refs);
|
||||
}
|
||||
|
||||
List<DtMeshTile> tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
const int MAX_NEIS = 32;
|
||||
DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS];
|
||||
int nneis = 0;
|
||||
|
||||
nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS);
|
||||
DtMeshTile tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
||||
|
||||
long o = tc.AddBoxObstacle(
|
||||
new RcVec3f(-2.315208f, 9.998184f, -20.807983f),
|
||||
new RcVec3f(-1.315208f, 11.998184f, -19.807983f)
|
||||
);
|
||||
bool upToDate = tc.Update();
|
||||
Assert.That(upToDate, Is.True);
|
||||
tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
|
||||
nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS);
|
||||
tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(22));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(11));
|
||||
|
||||
tc.RemoveObstacle(o);
|
||||
upToDate = tc.Update();
|
||||
Assert.That(upToDate, Is.True);
|
||||
tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||
|
||||
nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS);
|
||||
tile = tiles[0];
|
||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Recast.Geom;
|
||||
using DotRecast.Recast.Geom;
|
||||
|
||||
namespace DotRecast.Detour.TileCache.Test;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -73,7 +73,7 @@ public class TestTileLayerBuilder : DtTileCacheLayerBuilder
|
|||
|
||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
||||
RcCommons.CalcTileCount(bmin, bmax, CellSize, m_tileSize, m_tileSize, out tw, out th);
|
||||
RcRecast.CalcTileCount(bmin, bmax, CellSize, m_tileSize, m_tileSize, out tw, out th);
|
||||
}
|
||||
|
||||
public List<byte[]> Build(RcByteOrder order, bool cCompatibility, int threads)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -18,6 +18,7 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DotRecast.Core;
|
||||
|
@ -29,7 +30,6 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Detour.TileCache.Test;
|
||||
|
||||
|
||||
public class TileCacheFindPathTest : AbstractTileCacheTest
|
||||
{
|
||||
private readonly RcVec3f start = new RcVec3f(39.44734f, 9.998177f, -0.784811f);
|
||||
|
@ -39,7 +39,7 @@ public class TileCacheFindPathTest : AbstractTileCacheTest
|
|||
|
||||
public TileCacheFindPathTest()
|
||||
{
|
||||
using var msr = new MemoryStream(RcResources.Load("dungeon_all_tiles_tilecache.bin"));
|
||||
using var msr = new MemoryStream(RcIO.ReadFileIfFound("dungeon_all_tiles_tilecache.bin"));
|
||||
using var br = new BinaryReader(msr);
|
||||
DtTileCache tcC = new DtTileCacheReader(DtTileCacheCompressorFactory.Shared).Read(br, 6, new TestTileCacheMeshProcess());
|
||||
navmesh = tcC.GetNavMesh();
|
||||
|
@ -56,11 +56,11 @@ public class TileCacheFindPathTest : AbstractTileCacheTest
|
|||
|
||||
var path = new List<long>();
|
||||
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
|
||||
int maxStraightPath = 256;
|
||||
const int maxStraightPath = 256;
|
||||
int options = 0;
|
||||
|
||||
var pathStr = new List<DtStraightPath>();
|
||||
query.FindStraightPath(startPos, endPos, path, ref pathStr, maxStraightPath, options);
|
||||
Assert.That(pathStr.Count, Is.EqualTo(8));
|
||||
Span<DtStraightPath> pathStr = stackalloc DtStraightPath[maxStraightPath];
|
||||
query.FindStraightPath(startPos, endPos, path, path.Count, pathStr, out var npathStr, maxStraightPath, options);
|
||||
Assert.That(npathStr, Is.EqualTo(8));
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using DotRecast.Detour.TileCache.Io.Compress;
|
||||
using DotRecast.Detour.TileCache.Io.Compress;
|
||||
using DotRecast.Detour.TileCache.Test.Io;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="NUnit" Version="4.2.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -24,9 +25,6 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Recast.Test;
|
||||
|
||||
using static RcConstants;
|
||||
|
||||
|
||||
public class RecastLayersTest
|
||||
{
|
||||
private const float m_cellSize = 0.3f;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -25,10 +26,9 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Recast.Test;
|
||||
|
||||
using static RcConstants;
|
||||
using static RcRecast;
|
||||
using static RcAreas;
|
||||
|
||||
|
||||
public class RecastSoloMeshTest
|
||||
{
|
||||
private const float m_cellSize = 0.3f;
|
||||
|
@ -139,7 +139,7 @@ public class RecastSoloMeshTest
|
|||
// Find triangles which are walkable based on their slope and rasterize them.
|
||||
// If your input data is multiple meshes, you can transform them here, calculate
|
||||
// the are type for each of the meshes and rasterize them.
|
||||
int[] m_triareas = RcCommons.MarkWalkableTriangles(m_ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
||||
int[] m_triareas = RcRecast.MarkWalkableTriangles(m_ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
||||
RcRasterizations.RasterizeTriangles(m_ctx, verts, tris, m_triareas, ntris, m_solid, cfg.WalkableClimb);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -21,8 +22,7 @@ using DotRecast.Core;
|
|||
|
||||
namespace DotRecast.Recast.Test;
|
||||
|
||||
using static RcConstants;
|
||||
|
||||
using static RcRecast;
|
||||
|
||||
public class RecastTest
|
||||
{
|
||||
|
@ -39,18 +39,18 @@ public class RecastTest
|
|||
RcContext ctx = new RcContext();
|
||||
{
|
||||
int[] areas = { 42 };
|
||||
RcCommons.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas);
|
||||
RcRecast.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas);
|
||||
Assert.That(areas[0], Is.EqualTo(RC_NULL_AREA), "Sets area ID of unwalkable triangle to RC_NULL_AREA");
|
||||
}
|
||||
{
|
||||
int[] areas = { 42 };
|
||||
RcCommons.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas);
|
||||
RcRecast.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas);
|
||||
Assert.That(areas[0], Is.EqualTo(42), "Does not modify walkable triangle aread ID's");
|
||||
}
|
||||
{
|
||||
int[] areas = { 42 };
|
||||
walkableSlopeAngle = 0;
|
||||
RcCommons.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas);
|
||||
RcRecast.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas);
|
||||
Assert.That(areas[0], Is.EqualTo(RC_NULL_AREA), "Slopes equal to the max slope are considered unwalkable.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -27,7 +28,6 @@ using NUnit.Framework;
|
|||
|
||||
namespace DotRecast.Recast.Test;
|
||||
|
||||
|
||||
public class RecastTileMeshTest
|
||||
{
|
||||
private const float m_cellSize = 0.3f;
|
||||
|
@ -70,29 +70,29 @@ public class RecastTileMeshTest
|
|||
true, true, true,
|
||||
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
|
||||
RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 7, 8);
|
||||
RcBuilderResult rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5));
|
||||
RcBuilderResult rcResult = builder.Build(geom, bcfg, false);
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(1));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(5));
|
||||
bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 6, 9);
|
||||
rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7));
|
||||
rcResult = builder.Build(geom, bcfg, false);
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(7));
|
||||
bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 9);
|
||||
rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9));
|
||||
rcResult = builder.Build(geom, bcfg, false);
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(9));
|
||||
bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 4, 3);
|
||||
rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6));
|
||||
rcResult = builder.Build(geom, bcfg, false);
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(3));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(6));
|
||||
bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 8);
|
||||
rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17));
|
||||
rcResult = builder.Build(geom, bcfg, false);
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(5));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(17));
|
||||
bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 0, 8);
|
||||
rcResult = builder.Build(geom, bcfg);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15));
|
||||
rcResult = builder.Build(geom, bcfg, false);
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(6));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(15));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -138,28 +138,27 @@ public class RecastTileMeshTest
|
|||
private void Build(IInputGeomProvider geom, RcBuilder builder, RcConfig cfg, int threads, bool validate)
|
||||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
List<RcBuilderResult> tiles = new();
|
||||
var task = builder.BuildTilesAsync(geom, cfg, threads, tiles, Task.Factory, cts.Token);
|
||||
List<RcBuilderResult> tiles = builder.BuildTiles(geom, cfg, false, true, threads, Task.Factory, cts.Token);
|
||||
if (validate)
|
||||
{
|
||||
RcBuilderResult rcResult = GetTile(tiles, 7, 8);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5));
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(1));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(5));
|
||||
rcResult = GetTile(tiles, 6, 9);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7));
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(7));
|
||||
rcResult = GetTile(tiles, 2, 9);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9));
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(9));
|
||||
rcResult = GetTile(tiles, 4, 3);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6));
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(3));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(6));
|
||||
rcResult = GetTile(tiles, 2, 8);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17));
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(5));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(17));
|
||||
rcResult = GetTile(tiles, 0, 8);
|
||||
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6));
|
||||
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15));
|
||||
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(6));
|
||||
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(15));
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -175,6 +174,6 @@ public class RecastTileMeshTest
|
|||
|
||||
private RcBuilderResult GetTile(List<RcBuilderResult> tiles, int x, int z)
|
||||
{
|
||||
return tiles.FirstOrDefault(tile => tile.tileX == x && tile.tileZ == z);
|
||||
return tiles.FirstOrDefault(tile => tile.TileX == x && tile.TileZ == z);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
recast4j Copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
||||
DotRecast Copyright (c) 2023-2024 Choi Ikpil ikpil@naver.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
namespace DotRecast.Tool.PublishToUniRecast;
|
||||
|
||||
public class CsProj
|
||||
{
|
||||
public readonly string RootPath;
|
||||
public readonly string Name;
|
||||
public readonly string TargetPath;
|
||||
|
||||
public CsProj(string rootPath, string name, string targetPath)
|
||||
{
|
||||
RootPath = rootPath;
|
||||
Name = name;
|
||||
TargetPath = targetPath;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,169 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace DotRecast.Tool.PublishToUniRecast;
|
||||
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var source = SearchDirectory("DotRecast");
|
||||
var destination = SearchDirectory("UniRecast");
|
||||
|
||||
if (!Directory.Exists(source))
|
||||
{
|
||||
throw new Exception("not found source directory");
|
||||
}
|
||||
|
||||
if (!Directory.Exists(destination))
|
||||
{
|
||||
throw new Exception("not found destination directory");
|
||||
}
|
||||
|
||||
var ignorePaths = ImmutableArray.Create("bin", "obj");
|
||||
var projs = ImmutableArray.Create(
|
||||
// src
|
||||
new CsProj("src", "DotRecast.Core", "Runtime"),
|
||||
new CsProj("src", "DotRecast.Recast", "Runtime"),
|
||||
new CsProj("src", "DotRecast.Detour", "Runtime"),
|
||||
new CsProj("src", "DotRecast.Detour.Crowd", "Runtime"),
|
||||
new CsProj("src", "DotRecast.Detour.Dynamic", "Runtime"),
|
||||
new CsProj("src", "DotRecast.Detour.Extras", "Runtime"),
|
||||
new CsProj("src", "DotRecast.Detour.TileCache", "Runtime"),
|
||||
new CsProj("src", "DotRecast.Recast.Toolset", "Runtime")
|
||||
);
|
||||
|
||||
|
||||
foreach (var proj in projs)
|
||||
{
|
||||
var sourcePath = Path.Combine(source, proj.RootPath, $"{proj.Name}");
|
||||
var destPath = Path.Combine(destination, $"{proj.TargetPath}", $"{proj.Name}");
|
||||
|
||||
SyncFiles(sourcePath, destPath, ignorePaths, "*.cs");
|
||||
}
|
||||
|
||||
// // 몇몇 필요한 리소스 복사 하기
|
||||
// string destResourcePath = destDotRecast + "/resources";
|
||||
// if (!Directory.Exists(destResourcePath))
|
||||
// {
|
||||
// Directory.CreateDirectory(destResourcePath);
|
||||
// }
|
||||
|
||||
// string sourceResourcePath = Path.Combine(dotRecastPath, "resources/nav_test.obj");
|
||||
// File.Copy(sourceResourcePath, destResourcePath + "/nav_test.obj", true);
|
||||
}
|
||||
|
||||
public static string SearchPath(string searchPath, int depth, out bool isDir)
|
||||
{
|
||||
isDir = false;
|
||||
|
||||
for (int i = 0; i < depth; ++i)
|
||||
{
|
||||
var relativePath = string.Join("", Enumerable.Range(0, i).Select(x => "../"));
|
||||
var searchingPath = Path.Combine(relativePath, searchPath);
|
||||
var fullSearchingPath = Path.GetFullPath(searchingPath);
|
||||
|
||||
if (File.Exists(fullSearchingPath))
|
||||
{
|
||||
return fullSearchingPath;
|
||||
}
|
||||
|
||||
if (Directory.Exists(fullSearchingPath))
|
||||
{
|
||||
isDir = true;
|
||||
return fullSearchingPath;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// only directory
|
||||
public static string SearchDirectory(string dirname, int depth = 10)
|
||||
{
|
||||
var searchingPath = SearchPath(dirname, depth, out var isDir);
|
||||
if (isDir)
|
||||
{
|
||||
return searchingPath;
|
||||
}
|
||||
|
||||
var path = Path.GetDirectoryName(searchingPath) ?? string.Empty;
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string SearchFile(string filename, int depth = 10)
|
||||
{
|
||||
var searchingPath = SearchPath(filename, depth, out var isDir);
|
||||
if (!isDir)
|
||||
{
|
||||
return searchingPath;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private static void SyncFiles(string srcRootPath, string dstRootPath, IList<string> ignoreFolders, string searchPattern = "*")
|
||||
{
|
||||
// 끝에서부터 이그노어 폴더일 경우 패스
|
||||
var destLastFolderName = Path.GetFileName(dstRootPath);
|
||||
if (ignoreFolders.Any(x => x == destLastFolderName))
|
||||
return;
|
||||
|
||||
if (!Directory.Exists(dstRootPath))
|
||||
Directory.CreateDirectory(dstRootPath);
|
||||
|
||||
// 소스파일 추출
|
||||
var sourceFiles = Directory.GetFiles(srcRootPath, searchPattern).ToList();
|
||||
var sourceFolders = Directory.GetDirectories(srcRootPath)
|
||||
.Select(x => new DirectoryInfo(x))
|
||||
.ToList();
|
||||
|
||||
// 대상 파일 추출
|
||||
var destinationFiles = Directory.GetFiles(dstRootPath, searchPattern).ToList();
|
||||
var destinationFolders = Directory.GetDirectories(dstRootPath)
|
||||
.Select(x => new DirectoryInfo(x))
|
||||
.ToList();
|
||||
|
||||
// 대상에 파일이 있는데, 소스에 없을 경우, 대상 파일을 삭제 한다.
|
||||
foreach (var destinationFile in destinationFiles)
|
||||
{
|
||||
var destName = Path.GetFileName(destinationFile);
|
||||
var found = sourceFiles.Any(x => Path.GetFileName(x) == destName);
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
File.Delete(destinationFile);
|
||||
Console.WriteLine($"delete file - {destinationFile}");
|
||||
}
|
||||
|
||||
// 대상에 폴더가 있는데, 소스에 없을 경우, 대상 폴더를 삭제 한다.
|
||||
foreach (var destinationFolder in destinationFolders)
|
||||
{
|
||||
var found = sourceFolders.Any(sourceFolder => sourceFolder.Name == destinationFolder.Name);
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
Directory.Delete(destinationFolder.FullName, true);
|
||||
Console.WriteLine($"delete folder - {destinationFolder.FullName}");
|
||||
}
|
||||
|
||||
// 소스 파일을 복사 한다.
|
||||
foreach (var sourceFile in sourceFiles)
|
||||
{
|
||||
var name = Path.GetFileName(sourceFile);
|
||||
var dest = Path.Combine(dstRootPath, name);
|
||||
File.Copy(sourceFile, dest, true);
|
||||
Console.WriteLine($"copy - {sourceFile} => {dest}");
|
||||
}
|
||||
|
||||
// 대상 폴더를 복사 한다
|
||||
foreach (var sourceFolder in sourceFolders)
|
||||
{
|
||||
var dest = Path.Combine(dstRootPath, sourceFolder.Name);
|
||||
SyncFiles(sourceFolder.FullName, dest, ignoreFolders, searchPattern);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue