forked from bit/DotRecastNetSim
Compare commits
2 Commits
main
...
pr/change-
Author | SHA1 | Date |
---|---|---|
ikpil | fd3a0201f8 | |
ikpil | dd9a5e55fc |
|
@ -1,3 +0,0 @@
|
||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: ikpil
|
|
|
@ -28,7 +28,7 @@ jobs:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
dotnet-version: [ '6', '7', '8' ]
|
dotnet-version: [ '6.x', '7.x', '8.x' ]
|
||||||
os: [ windows-latest, ubuntu-latest, macos-latest ]
|
os: [ windows-latest, ubuntu-latest, macos-latest ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -39,13 +39,13 @@ jobs:
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v3
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: ${{ matrix.dotnet-version }}.x
|
dotnet-version: '8.x'
|
||||||
|
|
||||||
- name: Restore dependencies
|
- name: Restore dependencies
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: dotnet build -c Release --no-restore --framework net${{ matrix.dotnet-version }}.0
|
run: dotnet build -c Release --no-restore
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: dotnet test -c Release --no-build --verbosity normal --framework net${{ matrix.dotnet-version }}.0
|
run: dotnet test -c Release --no-build --verbosity normal
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
|
|
||||||
## 🔨 Build
|
|
||||||
- Building requires only .NET 8 SDK.
|
|
||||||
|
|
||||||
### 🔨 Building with Command Prompt
|
|
||||||
|
|
||||||
```shell
|
|
||||||
dotnet build -c Release
|
|
||||||
```
|
|
||||||
|
|
||||||
### 🔨 Building with an IDE
|
|
||||||
|
|
||||||
1. Open IDE: Launch your C# IDE (e.g., Visual Studio).
|
|
||||||
2. Open Solution: Go to the "File" menu and select "Open Solution."
|
|
||||||
3. Build: In the IDE menu, select "Build" > "Build Solution" or click the "Build" icon on the toolbar.
|
|
||||||
|
|
||||||
## ▶️ Run
|
|
||||||
- To verify the run for all modules, run [DotRecast.Recast.Demo](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj)
|
|
||||||
- on windows requirement : install to [Microsoft Visual C++ Redistributable Package](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist)
|
|
||||||
|
|
||||||
### ▶️ Running With Command Prompt
|
|
||||||
|
|
||||||
```shell
|
|
||||||
dotnet run --project src/DotRecast.Recast.Demo --framework net8.0 -c Release
|
|
||||||
```
|
|
||||||
|
|
||||||
### ▶️ Running With IDE (ex. Visual Studio 2022 or Rider ...)
|
|
||||||
|
|
||||||
1. Open your C# IDE (like Visual Studio).
|
|
||||||
2. Go to "File" in the menu.
|
|
||||||
3. Choose "Open Project" or "Open Solution."
|
|
||||||
4. Find and select [DotRecast.sln](DotRecast.sln), then click "Open."
|
|
||||||
5. Run to [DotRecast.Recast.Demo](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj)
|
|
||||||
|
|
||||||
## 🧪 Running Unit Test
|
|
||||||
|
|
||||||
- [DotRecast.Core.Test](https://github.com/ikpil/DotRecast/tree/main/test/DotRecast.Core.Test) : ...
|
|
||||||
- [DotRecast.Recast.Test](https://github.com/ikpil/DotRecast/tree/main/test/DotRecast.Recast.Test) : ...
|
|
||||||
- [DotRecast.Detour.Test](https://github.com/ikpil/DotRecast/tree/main/test/DotRecast.Detour.Test) : ...
|
|
||||||
- [DotRecast.Detour.TileCache.Test](https://github.com/ikpil/DotRecast/tree/main/test/DotRecast.Detour.TileCache.Test) : ...
|
|
||||||
- [DotRecast.Detour.Crowd.Test](https://github.com/ikpil/DotRecast/tree/main/test/DotRecast.Detour.Crowd.Test) : ...
|
|
||||||
- [DotRecast.Detour.Dynamic.Test](https://github.com/ikpil/DotRecast/tree/main/test/DotRecast.Detour.Dynamic.Test) : ...
|
|
||||||
- [DotRecast.Detour.Extras.Test](https://github.com/ikpil/DotRecast/tree/main/test/DotRecast.Detour.Extras.Test) : ...
|
|
||||||
|
|
||||||
### 🧪 Testing With Command Prompt
|
|
||||||
|
|
||||||
```shell
|
|
||||||
dotnet test --framework net8.0 -c Release
|
|
||||||
```
|
|
||||||
|
|
||||||
### 🧪 Testing With IDE
|
|
||||||
|
|
||||||
- Refer to the manual for your IDE.
|
|
||||||
|
|
||||||
## 🛠️ Integration
|
|
||||||
|
|
||||||
There are a few ways to integrate [DotRecast.Recast](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Recast) and [DotRecast.Detour](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour) into your project.
|
|
||||||
Source integration is the most popular and most flexible, and is what the project was designed for from the beginning.
|
|
||||||
|
|
||||||
### 🛠️ Source Integration
|
|
||||||
|
|
||||||
It is recommended to add the source directories
|
|
||||||
[DotRecast.Core](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Core),
|
|
||||||
[DotRecast.Recast](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Recast),
|
|
||||||
[DotRecast.Detour](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour),
|
|
||||||
[DotRecast.Detour.Crowd](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour.Crowd),
|
|
||||||
[DotRecast.Detour.TileCache](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour.TileCache)
|
|
||||||
and directly into your project depending on which parts of the project you need.
|
|
||||||
|
|
||||||
For example your level building tool could include
|
|
||||||
[DotRecast.Core](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Core),
|
|
||||||
[DotRecast.Recast](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Recast),
|
|
||||||
[DotRecast.Detour](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour)
|
|
||||||
and your game runtime could just include
|
|
||||||
[DotRecast.Detour](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour)
|
|
||||||
|
|
||||||
- [DotRecast.Core](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Core) : Core Utils
|
|
||||||
- [DotRecast.Recast](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Recast) : Core navmesh building system.
|
|
||||||
- [DotRecast.Detour](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour) : Runtime navmesh interface and query system.
|
|
||||||
- [DotRecast.Detour.TileCache](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour.TileCache) : Runtime movement, obstacle avoidance, and crowd simulation systems.
|
|
||||||
- [DotRecast.Detour.Crowd](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour.Crowd) : Runtime navmesh dynamic obstacle and re-baking system.
|
|
||||||
- [DotRecast.Detour.Dynamic](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour.Dynamic) : robust support for dynamic nav meshes combining pre-built voxels with dynamic objects which can be freely added and removed
|
|
||||||
- [DotRecast.Detour.Extras](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour.Extras) : simple tool to import navmeshes created with [A* Pathfinding Project](https://arongranberg.com/astar/)
|
|
||||||
|
|
||||||
|
|
||||||
### 🛠️ Installation through Nuget
|
|
||||||
|
|
||||||
- Nuget link : [DotRecast.Core](https://www.nuget.org/packages/DotRecast.Core)
|
|
||||||
- Nuget link : [DotRecast.Recast](https://www.nuget.org/packages/DotRecast.Recast)
|
|
||||||
- Nuget link : [DotRecast.Detour](https://www.nuget.org/packages/DotRecast.Detour)
|
|
||||||
- Nuget link : [DotRecast.Detour.TileCache](https://www.nuget.org/packages/DotRecast.Detour.TileCache)
|
|
||||||
- Nuget link : [DotRecast.Detour.Crowd](https://www.nuget.org/packages/DotRecast.Detour.Crowd)
|
|
||||||
- Nuget link : [DotRecast.Detour.Dynamic](https://www.nuget.org/packages/DotRecast.Detour.Dynamic)
|
|
||||||
- Nuget link : [DotRecast.Detour.Extras](https://www.nuget.org/packages/DotRecast.Detour.Extras)
|
|
||||||
- Nuget link : [DotRecast.Recast.Toolset](https://www.nuget.org/packages/DotRecast.Recast.Toolset)
|
|
||||||
- Nuget link : [DotRecast.Recast.Demo](https://www.nuget.org/packages/DotRecast.Recast.Demo)
|
|
||||||
|
|
82
CHANGELOG.md
82
CHANGELOG.md
|
@ -1,82 +0,0 @@
|
||||||
# Changelog
|
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
||||||
|
|
||||||
## [Unreleased] - yyyy-mm-dd
|
|
||||||
|
|
||||||
### 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)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Changed DtPathCorridor.Init(int maxPath) function to allow setting the maximum path [@ikpil](https://github.com/ikpil)
|
|
||||||
- Changed from List<T> to RcCyclicBuffer in DtCrowdTelemetry execution timing sampling [@wrenge](https://github.com/wrenge)
|
|
||||||
- RcCyclicBuffer<T> optimizations [@wrenge](https://github.com/wrenge)
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
|
|
||||||
### Special Thanks
|
|
||||||
- [@Doprez](https://github.com/Doprez)
|
|
||||||
- [@Arctium](https://github.com/Arctium)
|
|
||||||
|
|
||||||
|
|
||||||
## [2024.1.3] - 2024-02-13
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Added DtNodeQueue UnitTest [@ikpil](https://github.com/ikpil)
|
|
||||||
- Added RcSortedQueue UnitTest [@ikpil](https://github.com/ikpil)
|
|
||||||
- Added IComparable interface to RcAtomicLong [@ikpil](https://github.com/ikpil)
|
|
||||||
- Added Menu bar in Demo [@ikpil](https://github.com/ikpil)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Update Microsoft.NET.Test.Sdk 17.8.0 to 17.9.0
|
|
||||||
- Enhanced ToString method of DtNode to provide more detailed information.
|
|
||||||
- Reuse DtNode in DtNodePool
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
|
|
||||||
### Special Thanks
|
|
||||||
- [@Doprez](https://github.com/Doprez)
|
|
||||||
- [@Arctium](https://github.com/Arctium)
|
|
||||||
|
|
||||||
## [2024.1.2] - 2024-02-04
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Added DtNodePool tests [@ikpil](https://github.com/ikpil)
|
|
||||||
- Added WangHash() for DtNodePool [@ikpil](https://github.com/ikpil)
|
|
||||||
- Added avg, min, max, sampling updated times in CrowdAgentProfilingTool [@ikpil](https://github.com/ikpil)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Fixed SOH issue in DtNavMeshQuery.Raycast [@ikpil](https://github.com/ikpil)
|
|
||||||
- Fixed SOH issue in DtProximityGrid.QueryItems [@ikpil](https://github.com/ikpil)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Upgrade NUnit.Analyzers 4.0.1
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
|
|
||||||
### Special Thanks
|
|
||||||
- [@Doprez](https://github.com/Doprez)
|
|
||||||
- [@Arctium](https://github.com/Arctium)
|
|
||||||
|
|
||||||
## [2024.1.1] - 2024-01-05
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Fix typo ([#25](https://github.com/ikpil/DotRecast/pull/25)) [@c0nd3v](https://github.com/c0nd3v)
|
|
||||||
- Fix updated struct version ([#23](https://github.com/ikpil/DotRecast/pull/23)) [@c0nd3v](https://github.com/c0nd3v)
|
|
||||||
- Allow Radius 0 in Demo ([#22](https://github.com/ikpil/DotRecast/pull/22)) [@c0nd3v](https://github.com/c0nd3v)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- [Upstream] Cleanup filter code and improved documentation ([#30](https://github.com/ikpil/DotRecast/pull/30)) [@ikpil](https://github.com/ikpil)
|
|
||||||
- [Upstream] Make detail mesh edge detection more robust ([#26](https://github.com/ikpil/DotRecast/pull/26)) [@ikpil](https://github.com/ikpil)
|
|
||||||
- [Upstream] 248275e - Fix: typo error (#153) ([#21](https://github.com/ikpil/DotRecast/pull/21)) [@ikpil](https://github.com/ikpil)
|
|
||||||
- Code cleanup and small optimizations in RecastFilter.cpp ([#29](https://github.com/ikpil/DotRecast/pull/29)) [@ikpil](https://github.com/ikpil)
|
|
||||||
- Added UI scaling feature based on monitor resolution in Demo ([#28](https://github.com/ikpil/DotRecast/pull/28)) [@ikpil](https://github.com/ikpil)
|
|
||||||
|
|
123
README.md
123
README.md
|
@ -1,94 +1,81 @@
|
||||||
<h1 align="center">DotRecast</h1>
|
[![License: Zlib](https://img.shields.io/badge/License-Zlib-lightgrey.svg)](https://opensource.org/licenses/Zlib)
|
||||||
<p align="center">
|
[![.NET](https://github.com/ikpil/DotRecast/actions/workflows/dotnet.yml/badge.svg)](https://github.com/ikpil/DotRecast/actions/workflows/dotnet.yml)
|
||||||
<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>
|
[![CodeQL](https://github.com/ikpil/DotRecast/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/ikpil/DotRecast/actions/workflows/codeql.yml)
|
||||||
</p>
|
[![NuGet Version and Downloads count](https://buildstats.info/nuget/DotRecast.Core)](https://www.nuget.org/packages/DotRecast.Core)
|
||||||
<p align="center">
|
![Repo Size](https://img.shields.io/github/repo-size/ikpil/DotRecast.svg?colorB=lightgray)
|
||||||
<i>If you'd like to support the project, we'd appreciate starring(⭐) our repos on Github for more visibility.</i>
|
![Languages](https://img.shields.io/github/languages/top/ikpil/DotRecast)
|
||||||
</p>
|
[![Visitors](https://api.visitorbadge.io/api/daily?path=https%3A%2F%2Fgithub.com%2Fikpil%2FDotRecast&countColor=%23263759&style=flat-square)](https://visitorbadge.io/status?path=https%3A%2F%2Fgithub.com%2Fikpil%2FDotRecast)
|
||||||
|
|
||||||
---
|
# Screenshot
|
||||||
|
![screenshot](https://github.com/ikpil/DotRecast/assets/313821/8cf67832-1206-4b58-8c1f-7205210cbf22)
|
||||||
|
|
||||||
<p align="center">
|
# Introduction
|
||||||
<img alt="![GitHub License]" src="https://img.shields.io/github/license/ikpil/DotRecast?style=for-the-badge">
|
1. DotRecast is a port of C++'s [recastnavigation](https://github.com/recastnavigation/recastnavigation) and Java's [recast4j](https://github.com/ppiastucki/recast4j) to the C# language.
|
||||||
<img alt="Languages" src="https://img.shields.io/github/languages/top/ikpil/DotRecast?style=for-the-badge">
|
2. For game development, C# servers, C# project, and Unity3D are supported.
|
||||||
<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/ikpil/DotRecast?style=for-the-badge">
|
3. DotRecast consists of Recast and Detour, Crowd, Dynamic, Extras, TileCache, DemoTool, Demo
|
||||||
<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>
|
|
||||||
|
|
||||||
---
|
https://user-images.githubusercontent.com/313821/266782992-32a72a43-8f02-4214-8f1e-86b06952c8b7.mp4
|
||||||
|
|
||||||
[![demo](https://user-images.githubusercontent.com/313821/266750582-8cf67832-1206-4b58-8c1f-7205210cbf22.gif)](https://youtu.be/zIFIgziKLhQ)
|
## DotRecast.Recast
|
||||||
|
|
||||||
|
Recast is state of the art navigation mesh construction toolset for games.
|
||||||
|
|
||||||
|
Recast is...
|
||||||
|
* 🤖 **Automatic** - throw any level geometry at it and you will get a robust navmesh out
|
||||||
|
* 🏎️ **Fast** - swift turnaround times for level designers
|
||||||
|
* 🧘 **Flexible** - easily customize the navmesh generation and runtime navigation systems to suit your specific game's needs.
|
||||||
|
|
||||||
## 🚀 Features
|
Recast constructs a navmesh through a multi-step rasterization process:
|
||||||
|
|
||||||
- 🤖 Automatic - Recast can generate a navmesh from any level geometry you throw at it
|
1. First Recast voxelizes the input triangle mesh by rasterizing the triangles into a multi-layer heightfield.
|
||||||
- 🏎️ Fast - swift turnaround times for level designers
|
2. Voxels in areas where the character would not be able to move are removed by applying simple voxel data filters.
|
||||||
- 🧘 Flexible - detailed customization options and modular design let you tailor functionality to your specific needs
|
3. The walkable areas described by the voxel grid are then divided into sets of 2D polygonal regions.
|
||||||
- 🚫 Dependency-Free - building Recast & Detour only requires a .NET compiler
|
4. The navigation polygons are generated by triangulating and stitching together the generated 2d polygonal regions.
|
||||||
- 💪 Industry Standard - Recast powers AI navigation features in Unity, Unreal, Godot, O3DE and countless AAA and indie games and engines
|
|
||||||
|
|
||||||
Recast Navigation is divided into multiple modules, each contained in its own folder:
|
## DotRecast.Detour
|
||||||
|
|
||||||
- [DotRecast.Core](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Core) : Core utils
|
Recast is accompanied by Detour, a path-finding and spatial reasoning toolkit. You can use any navigation mesh with Detour, but of course the data generated with Recast fits perfectly.
|
||||||
- [DotRecast.Recast](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Recast) : Navmesh generation
|
|
||||||
- [DotRecast.Detour](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour) : Runtime loading of navmesh data, pathfinding, navmesh queries
|
|
||||||
- [DotRecast.Detour.TileCache](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour.TileCache) : Navmesh streaming. Useful for large levels and open-world games
|
|
||||||
- [DotRecast.Detour.Crowd](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour.Crowd) : Agent movement, collision avoidance, and crowd simulation
|
|
||||||
- [DotRecast.Detour.Dynamic](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour.Dynamic) : robust support for dynamic nav meshes combining pre-built voxels with dynamic objects which can be freely added and removed
|
|
||||||
- [DotRecast.Detour.Extras](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Detour.Extras) : simple tool to import navmeshes created with [A* Pathfinding Project](https://arongranberg.com/astar/)
|
|
||||||
- [DotRecast.Recast.Toolset](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Recast.Toolset) : all modules
|
|
||||||
- [DotRecast.Recast.Demo](https://github.com/ikpil/DotRecast/tree/main/src/DotRecast.Recast.Demo) : Standalone, comprehensive demo app showcasing all aspects of Recast & Detour's functionality
|
|
||||||
- [Tests](https://github.com/ikpil/DotRecast/tree/main/test) : Unit tests
|
|
||||||
|
|
||||||
## ⚡ Getting Started
|
Detour offers a simple static navmesh data representation which is suitable for many simple cases. It also provides a tiled navigation mesh representation, which allows you to stream of navigation data in and out as the player progresses through the world and regenerate sections of the navmesh data as the world changes.
|
||||||
|
|
||||||
- To build or integrate into your own project, please check out [BuildingAndIntegrating.md](https://github.com/ikpil/DotRecast/tree/main/BuildingAndIntegrating.md)
|
## DotRecast.Recast.Demo
|
||||||
- To create a NavMesh, please check out [RecastSoloMeshTest.cs](https://github.com/ikpil/DotRecast/tree/main/test/DotRecast.Recast.Test/RecastSoloMeshTest.cs)
|
|
||||||
- To test pathfinding, please check out [FindPathTest.cs](https://github.com/ikpil/DotRecast/tree/main/test/DotRecast.Detour.Test/FindPathTest.cs)
|
|
||||||
- To watch the demo play video, please check out [Demo Video](#-demo-video)
|
|
||||||
|
|
||||||
## ⚙ How it Works
|
You can find a comprehensive demo project in the `DotRecast.Recast.Demo` folder. It's a kitchen sink demo showcasing all the functionality of the library. If you are new to Recast & Detour, check out [SoloNavMeshBuilder.cs](/src/DotRecast.Recast.Demo/Builder/SoloNavMeshBuilder.cs) to get started with building navmeshes and [TestNavmeshTool.cs](/src/DotRecast.Recast.Demo/Tools/TestNavmeshTool.cs) to see how Detour can be used to find paths.
|
||||||
|
|
||||||
Recast constructs a navmesh through a multi-step mesh rasterization process.
|
### Building DotRecast.Recast.Demo
|
||||||
|
|
||||||
1. First Recast rasterizes the input triangle meshes into voxels.
|
1. `DotRecast.Recast.Demo` uses [dotnet 8](https://dotnet.microsoft.com/) to build platform specific projects. Download it and make sure it's available on your path, or specify the path to it.
|
||||||
2. Voxels in areas where agents would not be able to move are filtered and removed.
|
2. Open a command prompt, point it to a directory and clone DotRecast to it: `git clone https://github.com/ikpil/DotRecast.git`
|
||||||
3. The walkable areas described by the voxel grid are then divided into sets of polygonal regions.
|
3. Open `<DotRecastDir>\DotRecast.sln` with Visual Studio 2022 and build `DotRecast.Recast.Demo`
|
||||||
4. The navigation polygons are generated by re-triangulating the generated polygonal regions into a navmesh.
|
- Optionally, you can run using the `dotnet run` command with `DotRecast.Recast.Demo.csproj`
|
||||||
|
|
||||||
You can use Recast to build a single navmesh, or a tiled navmesh.
|
#### Windows
|
||||||
Single meshes are suitable for many simple, static cases and are easy to work with.
|
|
||||||
Tiled navmeshes are more complex to work with but better support larger, more dynamic environments. Tiled meshes enable advance Detour features like re-baking, heirarchical path-planning, and navmesh data-streaming.
|
|
||||||
|
|
||||||
## 📚 Documentation & Links
|
- need to install [microsoft visual c++ redistributable package](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist)
|
||||||
|
|
||||||
- DotRecast Links
|
#### Linux & macOS & Windows
|
||||||
- [DotRecast/issues](https://github.com/ikpil/DotRecast/issues)
|
|
||||||
|
|
||||||
- Official Links
|
- Navigate to the `DotRecast.Recast.Demo` folder and run `dotnet run`
|
||||||
- [recastnavigation/discussions](https://github.com/recastnavigation/recastnavigation/discussions)
|
|
||||||
- [recastnav.com](https://recastnav.com)
|
|
||||||
|
|
||||||
## 🅾 License
|
### Running Unit tests
|
||||||
|
|
||||||
DotRecast is licensed under ZLib license, see [LICENSE.txt](https://github.com/ikpil/DotRecast/tree/main/LICENSE.txt) for more information.
|
#### With VS2022
|
||||||
|
|
||||||
## 📹 Demo Video
|
- In Visual Studio 2022 go to the test menu and press `Run All Tests`
|
||||||
|
|
||||||
[![demo](https://img.youtube.com/vi/zIFIgziKLhQ/0.jpg)](https://youtu.be/zIFIgziKLhQ)
|
#### With CLI
|
||||||
|
|
||||||
[![demo](https://img.youtube.com/vi/CPvc19gNUEk/0.jpg)](https://youtu.be/CPvc19gNUEk)
|
- in the DotRecast folder open a command prompt and run `dotnet test`
|
||||||
|
|
||||||
[![demo](https://img.youtube.com/vi/pe5jpGUNPRg/0.jpg)](https://youtu.be/pe5jpGUNPRg)
|
## Integrating with your game or engine
|
||||||
|
|
||||||
|
It is recommended to add the source directories `DotRecast.Core`, `DotRecast.Detour.Crowd`, `DotRecast.Detour.Dynamic`, `DotRecast.Detour.TitleCache`, `DotRecast.Detour.Extras` and `DotRecast.Recast` into your own project depending on which parts of the project you need. For example your level building tool could include `DotRecast.Core`, `DotRecast.Recast`, and `DotRecast.Detour`, and your game runtime could just include `DotRecast.Detour`.
|
||||||
|
|
||||||
|
## Discuss
|
||||||
|
|
||||||
|
- Discuss Recast & Detour: http://groups.google.com/group/recastnavigation
|
||||||
|
- Development blog: http://digestingduck.blogspot.com/
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
DotRecast is licensed under ZLib license, see [LICENSE.txt](LICENSE.txt) for more information.
|
||||||
|
|
|
@ -1,274 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net.Security;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Buffers
|
|
||||||
{
|
|
||||||
// https://github.com/joaoportela/CircularBuffer-CSharp/blob/master/CircularBuffer/CircularBuffer.cs
|
|
||||||
public class RcCyclicBuffer<T> : IEnumerable<T>
|
|
||||||
{
|
|
||||||
public struct Enumerator : IEnumerator<T>
|
|
||||||
{
|
|
||||||
private readonly RcCyclicBuffer<T> _cb;
|
|
||||||
private int _index;
|
|
||||||
private readonly int _size;
|
|
||||||
|
|
||||||
internal Enumerator(RcCyclicBuffer<T> cb)
|
|
||||||
{
|
|
||||||
_cb = cb;
|
|
||||||
_size = _cb._size;
|
|
||||||
_index = default;
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
return ++_index < _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
_index = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Current => _cb[_index];
|
|
||||||
|
|
||||||
object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
// This could be used to unlock write access to collection
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly T[] _buffer;
|
|
||||||
|
|
||||||
private int _start;
|
|
||||||
private int _end;
|
|
||||||
private int _size;
|
|
||||||
|
|
||||||
public RcCyclicBuffer(int capacity)
|
|
||||||
: this(capacity, new T[] { })
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public RcCyclicBuffer(int capacity, T[] items)
|
|
||||||
{
|
|
||||||
if (capacity < 1)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("RcCyclicBuffer cannot have negative or zero capacity.", nameof(capacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(items));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items.Length > capacity)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Too many items to fit RcCyclicBuffer", nameof(items));
|
|
||||||
}
|
|
||||||
|
|
||||||
_buffer = new T[capacity];
|
|
||||||
|
|
||||||
Array.Copy(items, _buffer, items.Length);
|
|
||||||
_size = items.Length;
|
|
||||||
|
|
||||||
_start = 0;
|
|
||||||
_end = _size == capacity ? 0 : _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Capacity => _buffer.Length;
|
|
||||||
public bool IsFull => Size == Capacity;
|
|
||||||
public bool IsEmpty => Size == 0;
|
|
||||||
|
|
||||||
public int Size => _size;
|
|
||||||
|
|
||||||
public T Front()
|
|
||||||
{
|
|
||||||
ThrowIfEmpty();
|
|
||||||
return _buffer[_start];
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Back()
|
|
||||||
{
|
|
||||||
ThrowIfEmpty();
|
|
||||||
return _buffer[(_end != 0 ? _end : Capacity) - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (IsEmpty)
|
|
||||||
{
|
|
||||||
throw new IndexOutOfRangeException($"Cannot access index {index}. Buffer is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index >= _size)
|
|
||||||
{
|
|
||||||
throw new IndexOutOfRangeException($"Cannot access index {index}. Buffer size is {_size}");
|
|
||||||
}
|
|
||||||
|
|
||||||
int actualIndex = InternalIndex(index);
|
|
||||||
return _buffer[actualIndex];
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (IsEmpty)
|
|
||||||
{
|
|
||||||
throw new IndexOutOfRangeException($"Cannot access index {index}. Buffer is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index >= _size)
|
|
||||||
{
|
|
||||||
throw new IndexOutOfRangeException($"Cannot access index {index}. Buffer size is {_size}");
|
|
||||||
}
|
|
||||||
|
|
||||||
int actualIndex = InternalIndex(index);
|
|
||||||
_buffer[actualIndex] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PushBack(T item)
|
|
||||||
{
|
|
||||||
if (IsFull)
|
|
||||||
{
|
|
||||||
_buffer[_end] = item;
|
|
||||||
Increment(ref _end);
|
|
||||||
_start = _end;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_buffer[_end] = item;
|
|
||||||
Increment(ref _end);
|
|
||||||
++_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PushFront(T item)
|
|
||||||
{
|
|
||||||
if (IsFull)
|
|
||||||
{
|
|
||||||
Decrement(ref _start);
|
|
||||||
_end = _start;
|
|
||||||
_buffer[_start] = item;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Decrement(ref _start);
|
|
||||||
_buffer[_start] = item;
|
|
||||||
++_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PopBack()
|
|
||||||
{
|
|
||||||
ThrowIfEmpty("Cannot take elements from an empty buffer.");
|
|
||||||
Decrement(ref _end);
|
|
||||||
_buffer[_end] = default(T);
|
|
||||||
--_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PopFront()
|
|
||||||
{
|
|
||||||
ThrowIfEmpty("Cannot take elements from an empty buffer.");
|
|
||||||
_buffer[_start] = default(T);
|
|
||||||
Increment(ref _start);
|
|
||||||
--_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
// to clear we just reset everything.
|
|
||||||
_start = 0;
|
|
||||||
_end = 0;
|
|
||||||
_size = 0;
|
|
||||||
Array.Clear(_buffer, 0, _buffer.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] ToArray()
|
|
||||||
{
|
|
||||||
T[] newArray = new T[Size];
|
|
||||||
CopyTo(newArray);
|
|
||||||
return newArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(Span<T> destination)
|
|
||||||
{
|
|
||||||
var span1 = ArrayOne();
|
|
||||||
span1.CopyTo(destination);
|
|
||||||
ArrayTwo().CopyTo(destination[span1.Length..]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThrowIfEmpty(string message = "Cannot access an empty buffer.")
|
|
||||||
{
|
|
||||||
if (IsEmpty)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Increment(ref int index)
|
|
||||||
{
|
|
||||||
if (++index == Capacity)
|
|
||||||
{
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Decrement(ref int index)
|
|
||||||
{
|
|
||||||
if (index == 0)
|
|
||||||
{
|
|
||||||
index = Capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int InternalIndex(int index)
|
|
||||||
{
|
|
||||||
return _start + (index < (Capacity - _start)
|
|
||||||
? index
|
|
||||||
: index - Capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Span<T> ArrayOne()
|
|
||||||
{
|
|
||||||
if (IsEmpty)
|
|
||||||
{
|
|
||||||
return new Span<T>(Array.Empty<T>());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_start < _end)
|
|
||||||
{
|
|
||||||
return new Span<T>(_buffer, _start, _end - _start);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Span<T>(_buffer, _start, _buffer.Length - _start);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Span<T> ArrayTwo()
|
|
||||||
{
|
|
||||||
if (IsEmpty)
|
|
||||||
{
|
|
||||||
return new Span<T>(Array.Empty<T>());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_start < _end)
|
|
||||||
{
|
|
||||||
return new Span<T>(_buffer, _end, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Span<T>(_buffer, 0, _end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Enumerator GetEnumerator() => new Enumerator(this);
|
|
||||||
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,119 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Numerics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Buffers
|
|
||||||
{
|
|
||||||
public static class RcCyclicBuffers
|
|
||||||
{
|
|
||||||
public static long Sum(this ReadOnlySpan<long> source)
|
|
||||||
{
|
|
||||||
var buffer = source;
|
|
||||||
var result = 0L;
|
|
||||||
if (Vector.IsHardwareAccelerated)
|
|
||||||
{
|
|
||||||
var vectors = MemoryMarshal.Cast<long, Vector<long>>(buffer);
|
|
||||||
var vecSum = Vector<long>.Zero;
|
|
||||||
foreach (var vec in vectors)
|
|
||||||
vecSum += vec;
|
|
||||||
|
|
||||||
result = Vector.Dot(vecSum, Vector<long>.One);
|
|
||||||
var remainder = source.Length % Vector<long>.Count;
|
|
||||||
buffer = buffer[^remainder..];
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var val in buffer)
|
|
||||||
result += val;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Average(this ReadOnlySpan<long> source)
|
|
||||||
{
|
|
||||||
if (0 >= source.Length)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return source.Sum() / (double)source.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long Min(this ReadOnlySpan<long> source)
|
|
||||||
{
|
|
||||||
var buffer = source;
|
|
||||||
var result = long.MaxValue;
|
|
||||||
|
|
||||||
if (Vector.IsHardwareAccelerated)
|
|
||||||
{
|
|
||||||
var vectors = MemoryMarshal.Cast<long, Vector<long>>(buffer);
|
|
||||||
var vecMin = Vector<long>.One * result;
|
|
||||||
|
|
||||||
foreach (var vec in vectors)
|
|
||||||
vecMin = Vector.Min(vecMin, vec);
|
|
||||||
|
|
||||||
for (int i = 0; i < Vector<long>.Count; i++)
|
|
||||||
result = Math.Min(result, vecMin[i]);
|
|
||||||
|
|
||||||
var remainder = source.Length % Vector<long>.Count;
|
|
||||||
buffer = buffer[^remainder..];
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var val in buffer)
|
|
||||||
result = Math.Min(result, val);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long Max(this ReadOnlySpan<long> source)
|
|
||||||
{
|
|
||||||
var buffer = source;
|
|
||||||
var result = long.MinValue;
|
|
||||||
|
|
||||||
if (Vector.IsHardwareAccelerated)
|
|
||||||
{
|
|
||||||
var vectors = MemoryMarshal.Cast<long, Vector<long>>(buffer);
|
|
||||||
var vecMax = Vector<long>.One * result;
|
|
||||||
|
|
||||||
foreach (var vec in vectors)
|
|
||||||
vecMax = Vector.Max(vecMax, vec);
|
|
||||||
|
|
||||||
for (int i = 0; i < Vector<long>.Count; i++)
|
|
||||||
result = Math.Max(result, vecMax[i]);
|
|
||||||
|
|
||||||
var remainder = source.Length % Vector<long>.Count;
|
|
||||||
buffer = buffer[^remainder..];
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var val in buffer)
|
|
||||||
result = Math.Max(result, val);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long Sum(this RcCyclicBuffer<long> source)
|
|
||||||
{
|
|
||||||
return Sum(source.ArrayOne()) + Sum(source.ArrayTwo());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Average(this RcCyclicBuffer<long> source)
|
|
||||||
{
|
|
||||||
return Sum(source) / (double)source.Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long Min(this RcCyclicBuffer<long> source)
|
|
||||||
{
|
|
||||||
var firstHalf = source.ArrayOne();
|
|
||||||
var secondHalf = source.ArrayTwo();
|
|
||||||
var a = firstHalf.Length > 0 ? Min(firstHalf) : long.MaxValue;
|
|
||||||
var b = secondHalf.Length > 0 ? Min(secondHalf) : long.MaxValue;
|
|
||||||
return Math.Min(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long Max(this RcCyclicBuffer<long> source)
|
|
||||||
{
|
|
||||||
var firstHalf = source.ArrayOne();
|
|
||||||
var secondHalf = source.ArrayTwo();
|
|
||||||
var a = firstHalf.Length > 0 ? Max(firstHalf) : long.MinValue;
|
|
||||||
var b = secondHalf.Length > 0 ? Max(secondHalf) : long.MinValue;
|
|
||||||
return Math.Max(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Buffers
|
|
||||||
{
|
|
||||||
public static class RcRentedArray
|
|
||||||
{
|
|
||||||
public static RcRentedArray<T> Rent<T>(int minimumLength)
|
|
||||||
{
|
|
||||||
var array = ArrayPool<T>.Shared.Rent(minimumLength);
|
|
||||||
return new RcRentedArray<T>(ArrayPool<T>.Shared, array, minimumLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RcRentedArray<T> : IDisposable
|
|
||||||
{
|
|
||||||
private ArrayPool<T> _owner;
|
|
||||||
private T[] _array;
|
|
||||||
|
|
||||||
public int Length { get; }
|
|
||||||
public bool IsDisposed => null == _owner || null == _array;
|
|
||||||
|
|
||||||
internal RcRentedArray(ArrayPool<T> owner, T[] array, int length)
|
|
||||||
{
|
|
||||||
_owner = owner;
|
|
||||||
_array = array;
|
|
||||||
Length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref T this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
return ref _array[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] AsArray()
|
|
||||||
{
|
|
||||||
return _array;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (null != _owner && null != _array)
|
|
||||||
{
|
|
||||||
_owner.Return(_array, true);
|
|
||||||
_owner = null;
|
|
||||||
_array = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -27,12 +27,12 @@ namespace DotRecast.Core.Collections
|
||||||
{
|
{
|
||||||
private bool _dirty;
|
private bool _dirty;
|
||||||
private readonly List<T> _items;
|
private readonly List<T> _items;
|
||||||
private readonly Comparer<T> _comparer;
|
private readonly Comparison<T> _comparison;
|
||||||
|
|
||||||
public RcSortedQueue(Comparison<T> comp)
|
public RcSortedQueue(Comparison<T> comparison)
|
||||||
{
|
{
|
||||||
_items = new List<T>();
|
_items = new List<T>();
|
||||||
_comparer = Comparer<T>.Create((x, y) => comp.Invoke(x, y) * -1);
|
_comparison = (x, y) => comparison.Invoke(x, y) * -1; // reverse
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count()
|
public int Count()
|
||||||
|
@ -40,22 +40,16 @@ namespace DotRecast.Core.Collections
|
||||||
return _items.Count;
|
return _items.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsEmpty()
|
|
||||||
{
|
|
||||||
return 0 == _items.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
_items.Clear();
|
_items.Clear();
|
||||||
_dirty = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Balance()
|
private void Balance()
|
||||||
{
|
{
|
||||||
if (_dirty)
|
if (_dirty)
|
||||||
{
|
{
|
||||||
_items.Sort(_comparer); // reverse
|
_items.Sort(_comparison); // reverse
|
||||||
_dirty = false;
|
_dirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,39 +57,35 @@ namespace DotRecast.Core.Collections
|
||||||
public T Peek()
|
public T Peek()
|
||||||
{
|
{
|
||||||
Balance();
|
Balance();
|
||||||
return _items[^1];
|
return _items[_items.Count - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Dequeue()
|
public T Dequeue()
|
||||||
{
|
{
|
||||||
var node = Peek();
|
var node = Peek();
|
||||||
_items.RemoveAt(_items.Count - 1);
|
_items.Remove(node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Enqueue(T item)
|
public void Enqueue(T item)
|
||||||
{
|
{
|
||||||
if (null == item)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_items.Add(item);
|
_items.Add(item);
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Remove(T item)
|
public void Remove(T item)
|
||||||
{
|
{
|
||||||
if (null == item)
|
|
||||||
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.FindLastIndex(x => item.Equals(x));
|
||||||
if (0 > idx)
|
if (0 > idx)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
_items.RemoveAt(idx);
|
_items.RemoveAt(idx);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsEmpty()
|
||||||
|
{
|
||||||
|
return 0 == _items.Count;
|
||||||
|
}
|
||||||
|
|
||||||
public List<T> ToList()
|
public List<T> ToList()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,421 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Collections
|
|
||||||
{
|
|
||||||
public struct RcStackArray128<T>
|
|
||||||
{
|
|
||||||
public static RcStackArray128<T> Empty => new RcStackArray128<T>();
|
|
||||||
|
|
||||||
private const int Size = 128;
|
|
||||||
public int Length => Size;
|
|
||||||
|
|
||||||
public T V0;
|
|
||||||
public T V1;
|
|
||||||
public T V2;
|
|
||||||
public T V3;
|
|
||||||
public T V4;
|
|
||||||
public T V5;
|
|
||||||
public T V6;
|
|
||||||
public T V7;
|
|
||||||
public T V8;
|
|
||||||
public T V9;
|
|
||||||
public T V10;
|
|
||||||
public T V11;
|
|
||||||
public T V12;
|
|
||||||
public T V13;
|
|
||||||
public T V14;
|
|
||||||
public T V15;
|
|
||||||
public T V16;
|
|
||||||
public T V17;
|
|
||||||
public T V18;
|
|
||||||
public T V19;
|
|
||||||
public T V20;
|
|
||||||
public T V21;
|
|
||||||
public T V22;
|
|
||||||
public T V23;
|
|
||||||
public T V24;
|
|
||||||
public T V25;
|
|
||||||
public T V26;
|
|
||||||
public T V27;
|
|
||||||
public T V28;
|
|
||||||
public T V29;
|
|
||||||
public T V30;
|
|
||||||
public T V31;
|
|
||||||
public T V32;
|
|
||||||
public T V33;
|
|
||||||
public T V34;
|
|
||||||
public T V35;
|
|
||||||
public T V36;
|
|
||||||
public T V37;
|
|
||||||
public T V38;
|
|
||||||
public T V39;
|
|
||||||
public T V40;
|
|
||||||
public T V41;
|
|
||||||
public T V42;
|
|
||||||
public T V43;
|
|
||||||
public T V44;
|
|
||||||
public T V45;
|
|
||||||
public T V46;
|
|
||||||
public T V47;
|
|
||||||
public T V48;
|
|
||||||
public T V49;
|
|
||||||
public T V50;
|
|
||||||
public T V51;
|
|
||||||
public T V52;
|
|
||||||
public T V53;
|
|
||||||
public T V54;
|
|
||||||
public T V55;
|
|
||||||
public T V56;
|
|
||||||
public T V57;
|
|
||||||
public T V58;
|
|
||||||
public T V59;
|
|
||||||
public T V60;
|
|
||||||
public T V61;
|
|
||||||
public T V62;
|
|
||||||
public T V63;
|
|
||||||
public T V64;
|
|
||||||
public T V65;
|
|
||||||
public T V66;
|
|
||||||
public T V67;
|
|
||||||
public T V68;
|
|
||||||
public T V69;
|
|
||||||
public T V70;
|
|
||||||
public T V71;
|
|
||||||
public T V72;
|
|
||||||
public T V73;
|
|
||||||
public T V74;
|
|
||||||
public T V75;
|
|
||||||
public T V76;
|
|
||||||
public T V77;
|
|
||||||
public T V78;
|
|
||||||
public T V79;
|
|
||||||
public T V80;
|
|
||||||
public T V81;
|
|
||||||
public T V82;
|
|
||||||
public T V83;
|
|
||||||
public T V84;
|
|
||||||
public T V85;
|
|
||||||
public T V86;
|
|
||||||
public T V87;
|
|
||||||
public T V88;
|
|
||||||
public T V89;
|
|
||||||
public T V90;
|
|
||||||
public T V91;
|
|
||||||
public T V92;
|
|
||||||
public T V93;
|
|
||||||
public T V94;
|
|
||||||
public T V95;
|
|
||||||
public T V96;
|
|
||||||
public T V97;
|
|
||||||
public T V98;
|
|
||||||
public T V99;
|
|
||||||
public T V100;
|
|
||||||
public T V101;
|
|
||||||
public T V102;
|
|
||||||
public T V103;
|
|
||||||
public T V104;
|
|
||||||
public T V105;
|
|
||||||
public T V106;
|
|
||||||
public T V107;
|
|
||||||
public T V108;
|
|
||||||
public T V109;
|
|
||||||
public T V110;
|
|
||||||
public T V111;
|
|
||||||
public T V112;
|
|
||||||
public T V113;
|
|
||||||
public T V114;
|
|
||||||
public T V115;
|
|
||||||
public T V116;
|
|
||||||
public T V117;
|
|
||||||
public T V118;
|
|
||||||
public T V119;
|
|
||||||
public T V120;
|
|
||||||
public T V121;
|
|
||||||
public T V122;
|
|
||||||
public T V123;
|
|
||||||
public T V124;
|
|
||||||
public T V125;
|
|
||||||
public T V126;
|
|
||||||
public T V127;
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
return index switch
|
|
||||||
{
|
|
||||||
0 => V0,
|
|
||||||
1 => V1,
|
|
||||||
2 => V2,
|
|
||||||
3 => V3,
|
|
||||||
4 => V4,
|
|
||||||
5 => V5,
|
|
||||||
6 => V6,
|
|
||||||
7 => V7,
|
|
||||||
8 => V8,
|
|
||||||
9 => V9,
|
|
||||||
10 => V10,
|
|
||||||
11 => V11,
|
|
||||||
12 => V12,
|
|
||||||
13 => V13,
|
|
||||||
14 => V14,
|
|
||||||
15 => V15,
|
|
||||||
16 => V16,
|
|
||||||
17 => V17,
|
|
||||||
18 => V18,
|
|
||||||
19 => V19,
|
|
||||||
20 => V20,
|
|
||||||
21 => V21,
|
|
||||||
22 => V22,
|
|
||||||
23 => V23,
|
|
||||||
24 => V24,
|
|
||||||
25 => V25,
|
|
||||||
26 => V26,
|
|
||||||
27 => V27,
|
|
||||||
28 => V28,
|
|
||||||
29 => V29,
|
|
||||||
30 => V30,
|
|
||||||
31 => V31,
|
|
||||||
32 => V32,
|
|
||||||
33 => V33,
|
|
||||||
34 => V34,
|
|
||||||
35 => V35,
|
|
||||||
36 => V36,
|
|
||||||
37 => V37,
|
|
||||||
38 => V38,
|
|
||||||
39 => V39,
|
|
||||||
40 => V40,
|
|
||||||
41 => V41,
|
|
||||||
42 => V42,
|
|
||||||
43 => V43,
|
|
||||||
44 => V44,
|
|
||||||
45 => V45,
|
|
||||||
46 => V46,
|
|
||||||
47 => V47,
|
|
||||||
48 => V48,
|
|
||||||
49 => V49,
|
|
||||||
50 => V50,
|
|
||||||
51 => V51,
|
|
||||||
52 => V52,
|
|
||||||
53 => V53,
|
|
||||||
54 => V54,
|
|
||||||
55 => V55,
|
|
||||||
56 => V56,
|
|
||||||
57 => V57,
|
|
||||||
58 => V58,
|
|
||||||
59 => V59,
|
|
||||||
60 => V60,
|
|
||||||
61 => V61,
|
|
||||||
62 => V62,
|
|
||||||
63 => V63,
|
|
||||||
64 => V64,
|
|
||||||
65 => V65,
|
|
||||||
66 => V66,
|
|
||||||
67 => V67,
|
|
||||||
68 => V68,
|
|
||||||
69 => V69,
|
|
||||||
70 => V70,
|
|
||||||
71 => V71,
|
|
||||||
72 => V72,
|
|
||||||
73 => V73,
|
|
||||||
74 => V74,
|
|
||||||
75 => V75,
|
|
||||||
76 => V76,
|
|
||||||
77 => V77,
|
|
||||||
78 => V78,
|
|
||||||
79 => V79,
|
|
||||||
80 => V80,
|
|
||||||
81 => V81,
|
|
||||||
82 => V82,
|
|
||||||
83 => V83,
|
|
||||||
84 => V84,
|
|
||||||
85 => V85,
|
|
||||||
86 => V86,
|
|
||||||
87 => V87,
|
|
||||||
88 => V88,
|
|
||||||
89 => V89,
|
|
||||||
90 => V90,
|
|
||||||
91 => V91,
|
|
||||||
92 => V92,
|
|
||||||
93 => V93,
|
|
||||||
94 => V94,
|
|
||||||
95 => V95,
|
|
||||||
96 => V96,
|
|
||||||
97 => V97,
|
|
||||||
98 => V98,
|
|
||||||
99 => V99,
|
|
||||||
100 => V100,
|
|
||||||
101 => V101,
|
|
||||||
102 => V102,
|
|
||||||
103 => V103,
|
|
||||||
104 => V104,
|
|
||||||
105 => V105,
|
|
||||||
106 => V106,
|
|
||||||
107 => V107,
|
|
||||||
108 => V108,
|
|
||||||
109 => V109,
|
|
||||||
110 => V110,
|
|
||||||
111 => V111,
|
|
||||||
112 => V112,
|
|
||||||
113 => V113,
|
|
||||||
114 => V114,
|
|
||||||
115 => V115,
|
|
||||||
116 => V116,
|
|
||||||
117 => V117,
|
|
||||||
118 => V118,
|
|
||||||
119 => V119,
|
|
||||||
120 => V120,
|
|
||||||
121 => V121,
|
|
||||||
122 => V122,
|
|
||||||
123 => V123,
|
|
||||||
124 => V124,
|
|
||||||
125 => V125,
|
|
||||||
126 => V126,
|
|
||||||
127 => V127,
|
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(index), index, null)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0: V0 = value; break;
|
|
||||||
case 1: V1 = value; break;
|
|
||||||
case 2: V2 = value; break;
|
|
||||||
case 3: V3 = value; break;
|
|
||||||
case 4: V4 = value; break;
|
|
||||||
case 5: V5 = value; break;
|
|
||||||
case 6: V6 = value; break;
|
|
||||||
case 7: V7 = value; break;
|
|
||||||
case 8: V8 = value; break;
|
|
||||||
case 9: V9 = value; break;
|
|
||||||
case 10: V10 = value; break;
|
|
||||||
case 11: V11 = value; break;
|
|
||||||
case 12: V12 = value; break;
|
|
||||||
case 13: V13 = value; break;
|
|
||||||
case 14: V14 = value; break;
|
|
||||||
case 15: V15 = value; break;
|
|
||||||
case 16: V16 = value; break;
|
|
||||||
case 17: V17 = value; break;
|
|
||||||
case 18: V18 = value; break;
|
|
||||||
case 19: V19 = value; break;
|
|
||||||
case 20: V20 = value; break;
|
|
||||||
case 21: V21 = value; break;
|
|
||||||
case 22: V22 = value; break;
|
|
||||||
case 23: V23 = value; break;
|
|
||||||
case 24: V24 = value; break;
|
|
||||||
case 25: V25 = value; break;
|
|
||||||
case 26: V26 = value; break;
|
|
||||||
case 27: V27 = value; break;
|
|
||||||
case 28: V28 = value; break;
|
|
||||||
case 29: V29 = value; break;
|
|
||||||
case 30: V30 = value; break;
|
|
||||||
case 31: V31 = value; break;
|
|
||||||
case 32 : V32 = value; break;
|
|
||||||
case 33 : V33 = value; break;
|
|
||||||
case 34 : V34 = value; break;
|
|
||||||
case 35 : V35 = value; break;
|
|
||||||
case 36 : V36 = value; break;
|
|
||||||
case 37 : V37 = value; break;
|
|
||||||
case 38 : V38 = value; break;
|
|
||||||
case 39 : V39 = value; break;
|
|
||||||
case 40 : V40 = value; break;
|
|
||||||
case 41 : V41 = value; break;
|
|
||||||
case 42 : V42 = value; break;
|
|
||||||
case 43 : V43 = value; break;
|
|
||||||
case 44 : V44 = value; break;
|
|
||||||
case 45 : V45 = value; break;
|
|
||||||
case 46 : V46 = value; break;
|
|
||||||
case 47 : V47 = value; break;
|
|
||||||
case 48 : V48 = value; break;
|
|
||||||
case 49 : V49 = value; break;
|
|
||||||
case 50 : V50 = value; break;
|
|
||||||
case 51 : V51 = value; break;
|
|
||||||
case 52 : V52 = value; break;
|
|
||||||
case 53 : V53 = value; break;
|
|
||||||
case 54 : V54 = value; break;
|
|
||||||
case 55 : V55 = value; break;
|
|
||||||
case 56 : V56 = value; break;
|
|
||||||
case 57 : V57 = value; break;
|
|
||||||
case 58 : V58 = value; break;
|
|
||||||
case 59 : V59 = value; break;
|
|
||||||
case 60 : V60 = value; break;
|
|
||||||
case 61 : V61 = value; break;
|
|
||||||
case 62 : V62 = value; break;
|
|
||||||
case 63 : V63 = value; break;
|
|
||||||
case 64 : V64 = value; break;
|
|
||||||
case 65 : V65 = value; break;
|
|
||||||
case 66 : V66 = value; break;
|
|
||||||
case 67 : V67 = value; break;
|
|
||||||
case 68 : V68 = value; break;
|
|
||||||
case 69 : V69 = value; break;
|
|
||||||
case 70 : V70 = value; break;
|
|
||||||
case 71 : V71 = value; break;
|
|
||||||
case 72 : V72 = value; break;
|
|
||||||
case 73 : V73 = value; break;
|
|
||||||
case 74 : V74 = value; break;
|
|
||||||
case 75 : V75 = value; break;
|
|
||||||
case 76 : V76 = value; break;
|
|
||||||
case 77 : V77 = value; break;
|
|
||||||
case 78 : V78 = value; break;
|
|
||||||
case 79 : V79 = value; break;
|
|
||||||
case 80 : V80 = value; break;
|
|
||||||
case 81 : V81 = value; break;
|
|
||||||
case 82 : V82 = value; break;
|
|
||||||
case 83 : V83 = value; break;
|
|
||||||
case 84 : V84 = value; break;
|
|
||||||
case 85 : V85 = value; break;
|
|
||||||
case 86 : V86 = value; break;
|
|
||||||
case 87 : V87 = value; break;
|
|
||||||
case 88 : V88 = value; break;
|
|
||||||
case 89 : V89 = value; break;
|
|
||||||
case 90 : V90 = value; break;
|
|
||||||
case 91 : V91 = value; break;
|
|
||||||
case 92 : V92 = value; break;
|
|
||||||
case 93 : V93 = value; break;
|
|
||||||
case 94 : V94 = value; break;
|
|
||||||
case 95 : V95 = value; break;
|
|
||||||
case 96 : V96 = value; break;
|
|
||||||
case 97 : V97 = value; break;
|
|
||||||
case 98 : V98 = value; break;
|
|
||||||
case 99 : V99 = value; break;
|
|
||||||
case 100 : V100 = value; break;
|
|
||||||
case 101 : V101 = value; break;
|
|
||||||
case 102 : V102 = value; break;
|
|
||||||
case 103 : V103 = value; break;
|
|
||||||
case 104 : V104 = value; break;
|
|
||||||
case 105 : V105 = value; break;
|
|
||||||
case 106 : V106 = value; break;
|
|
||||||
case 107 : V107 = value; break;
|
|
||||||
case 108 : V108 = value; break;
|
|
||||||
case 109 : V109 = value; break;
|
|
||||||
case 110 : V110 = value; break;
|
|
||||||
case 111 : V111 = value; break;
|
|
||||||
case 112 : V112 = value; break;
|
|
||||||
case 113 : V113 = value; break;
|
|
||||||
case 114 : V114 = value; break;
|
|
||||||
case 115 : V115 = value; break;
|
|
||||||
case 116 : V116 = value; break;
|
|
||||||
case 117 : V117 = value; break;
|
|
||||||
case 118 : V118 = value; break;
|
|
||||||
case 119 : V119 = value; break;
|
|
||||||
case 120 : V120 = value; break;
|
|
||||||
case 121 : V121 = value; break;
|
|
||||||
case 122 : V122 = value; break;
|
|
||||||
case 123 : V123 = value; break;
|
|
||||||
case 124 : V124 = value; break;
|
|
||||||
case 125 : V125 = value; break;
|
|
||||||
case 126 : V126 = value; break;
|
|
||||||
case 127 : V127 = value; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Collections
|
|
||||||
{
|
|
||||||
public struct RcStackArray16<T>
|
|
||||||
{
|
|
||||||
public static RcStackArray16<T> Empty => new RcStackArray16<T>();
|
|
||||||
|
|
||||||
private const int Size = 16;
|
|
||||||
public int Length => Size;
|
|
||||||
|
|
||||||
public T V0;
|
|
||||||
public T V1;
|
|
||||||
public T V2;
|
|
||||||
public T V3;
|
|
||||||
public T V4;
|
|
||||||
public T V5;
|
|
||||||
public T V6;
|
|
||||||
public T V7;
|
|
||||||
public T V8;
|
|
||||||
public T V9;
|
|
||||||
public T V10;
|
|
||||||
public T V11;
|
|
||||||
public T V12;
|
|
||||||
public T V13;
|
|
||||||
public T V14;
|
|
||||||
public T V15;
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
return index switch
|
|
||||||
{
|
|
||||||
0 => V0,
|
|
||||||
1 => V1,
|
|
||||||
2 => V2,
|
|
||||||
3 => V3,
|
|
||||||
4 => V4,
|
|
||||||
5 => V5,
|
|
||||||
6 => V6,
|
|
||||||
7 => V7,
|
|
||||||
8 => V8,
|
|
||||||
9 => V9,
|
|
||||||
10 => V10,
|
|
||||||
11 => V11,
|
|
||||||
12 => V12,
|
|
||||||
13 => V13,
|
|
||||||
14 => V14,
|
|
||||||
15 => V15,
|
|
||||||
_ => throw new IndexOutOfRangeException($"{index}")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0: V0 = value; break;
|
|
||||||
case 1: V1 = value; break;
|
|
||||||
case 2: V2 = value; break;
|
|
||||||
case 3: V3 = value; break;
|
|
||||||
case 4: V4 = value; break;
|
|
||||||
case 5: V5 = value; break;
|
|
||||||
case 6: V6 = value; break;
|
|
||||||
case 7: V7 = value; break;
|
|
||||||
case 8: V8 = value; break;
|
|
||||||
case 9: V9 = value; break;
|
|
||||||
case 10: V10 = value; break;
|
|
||||||
case 11: V11 = value; break;
|
|
||||||
case 12: V12 = value; break;
|
|
||||||
case 13: V13 = value; break;
|
|
||||||
case 14: V14 = value; break;
|
|
||||||
case 15: V15 = value; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Collections
|
|
||||||
{
|
|
||||||
public struct RcStackArray2<T>
|
|
||||||
{
|
|
||||||
public static RcStackArray2<T> Empty => new RcStackArray2<T>();
|
|
||||||
|
|
||||||
private const int Size = 2;
|
|
||||||
public int Length => Size;
|
|
||||||
|
|
||||||
public T V0;
|
|
||||||
public T V1;
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
return index switch
|
|
||||||
{
|
|
||||||
0 => V0,
|
|
||||||
1 => V1,
|
|
||||||
_ => throw new IndexOutOfRangeException($"{index}")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0: V0 = value; break;
|
|
||||||
case 1: V1 = value; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,805 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Collections
|
|
||||||
{
|
|
||||||
public struct RcStackArray256<T>
|
|
||||||
{
|
|
||||||
public static RcStackArray256<T> Empty => new RcStackArray256<T>();
|
|
||||||
|
|
||||||
private const int Size = 256;
|
|
||||||
public int Length => Size;
|
|
||||||
|
|
||||||
public T V0;
|
|
||||||
public T V1;
|
|
||||||
public T V2;
|
|
||||||
public T V3;
|
|
||||||
public T V4;
|
|
||||||
public T V5;
|
|
||||||
public T V6;
|
|
||||||
public T V7;
|
|
||||||
public T V8;
|
|
||||||
public T V9;
|
|
||||||
public T V10;
|
|
||||||
public T V11;
|
|
||||||
public T V12;
|
|
||||||
public T V13;
|
|
||||||
public T V14;
|
|
||||||
public T V15;
|
|
||||||
public T V16;
|
|
||||||
public T V17;
|
|
||||||
public T V18;
|
|
||||||
public T V19;
|
|
||||||
public T V20;
|
|
||||||
public T V21;
|
|
||||||
public T V22;
|
|
||||||
public T V23;
|
|
||||||
public T V24;
|
|
||||||
public T V25;
|
|
||||||
public T V26;
|
|
||||||
public T V27;
|
|
||||||
public T V28;
|
|
||||||
public T V29;
|
|
||||||
public T V30;
|
|
||||||
public T V31;
|
|
||||||
public T V32;
|
|
||||||
public T V33;
|
|
||||||
public T V34;
|
|
||||||
public T V35;
|
|
||||||
public T V36;
|
|
||||||
public T V37;
|
|
||||||
public T V38;
|
|
||||||
public T V39;
|
|
||||||
public T V40;
|
|
||||||
public T V41;
|
|
||||||
public T V42;
|
|
||||||
public T V43;
|
|
||||||
public T V44;
|
|
||||||
public T V45;
|
|
||||||
public T V46;
|
|
||||||
public T V47;
|
|
||||||
public T V48;
|
|
||||||
public T V49;
|
|
||||||
public T V50;
|
|
||||||
public T V51;
|
|
||||||
public T V52;
|
|
||||||
public T V53;
|
|
||||||
public T V54;
|
|
||||||
public T V55;
|
|
||||||
public T V56;
|
|
||||||
public T V57;
|
|
||||||
public T V58;
|
|
||||||
public T V59;
|
|
||||||
public T V60;
|
|
||||||
public T V61;
|
|
||||||
public T V62;
|
|
||||||
public T V63;
|
|
||||||
public T V64;
|
|
||||||
public T V65;
|
|
||||||
public T V66;
|
|
||||||
public T V67;
|
|
||||||
public T V68;
|
|
||||||
public T V69;
|
|
||||||
public T V70;
|
|
||||||
public T V71;
|
|
||||||
public T V72;
|
|
||||||
public T V73;
|
|
||||||
public T V74;
|
|
||||||
public T V75;
|
|
||||||
public T V76;
|
|
||||||
public T V77;
|
|
||||||
public T V78;
|
|
||||||
public T V79;
|
|
||||||
public T V80;
|
|
||||||
public T V81;
|
|
||||||
public T V82;
|
|
||||||
public T V83;
|
|
||||||
public T V84;
|
|
||||||
public T V85;
|
|
||||||
public T V86;
|
|
||||||
public T V87;
|
|
||||||
public T V88;
|
|
||||||
public T V89;
|
|
||||||
public T V90;
|
|
||||||
public T V91;
|
|
||||||
public T V92;
|
|
||||||
public T V93;
|
|
||||||
public T V94;
|
|
||||||
public T V95;
|
|
||||||
public T V96;
|
|
||||||
public T V97;
|
|
||||||
public T V98;
|
|
||||||
public T V99;
|
|
||||||
public T V100;
|
|
||||||
public T V101;
|
|
||||||
public T V102;
|
|
||||||
public T V103;
|
|
||||||
public T V104;
|
|
||||||
public T V105;
|
|
||||||
public T V106;
|
|
||||||
public T V107;
|
|
||||||
public T V108;
|
|
||||||
public T V109;
|
|
||||||
public T V110;
|
|
||||||
public T V111;
|
|
||||||
public T V112;
|
|
||||||
public T V113;
|
|
||||||
public T V114;
|
|
||||||
public T V115;
|
|
||||||
public T V116;
|
|
||||||
public T V117;
|
|
||||||
public T V118;
|
|
||||||
public T V119;
|
|
||||||
public T V120;
|
|
||||||
public T V121;
|
|
||||||
public T V122;
|
|
||||||
public T V123;
|
|
||||||
public T V124;
|
|
||||||
public T V125;
|
|
||||||
public T V126;
|
|
||||||
public T V127;
|
|
||||||
public T V128;
|
|
||||||
public T V129;
|
|
||||||
public T V130;
|
|
||||||
public T V131;
|
|
||||||
public T V132;
|
|
||||||
public T V133;
|
|
||||||
public T V134;
|
|
||||||
public T V135;
|
|
||||||
public T V136;
|
|
||||||
public T V137;
|
|
||||||
public T V138;
|
|
||||||
public T V139;
|
|
||||||
public T V140;
|
|
||||||
public T V141;
|
|
||||||
public T V142;
|
|
||||||
public T V143;
|
|
||||||
public T V144;
|
|
||||||
public T V145;
|
|
||||||
public T V146;
|
|
||||||
public T V147;
|
|
||||||
public T V148;
|
|
||||||
public T V149;
|
|
||||||
public T V150;
|
|
||||||
public T V151;
|
|
||||||
public T V152;
|
|
||||||
public T V153;
|
|
||||||
public T V154;
|
|
||||||
public T V155;
|
|
||||||
public T V156;
|
|
||||||
public T V157;
|
|
||||||
public T V158;
|
|
||||||
public T V159;
|
|
||||||
public T V160;
|
|
||||||
public T V161;
|
|
||||||
public T V162;
|
|
||||||
public T V163;
|
|
||||||
public T V164;
|
|
||||||
public T V165;
|
|
||||||
public T V166;
|
|
||||||
public T V167;
|
|
||||||
public T V168;
|
|
||||||
public T V169;
|
|
||||||
public T V170;
|
|
||||||
public T V171;
|
|
||||||
public T V172;
|
|
||||||
public T V173;
|
|
||||||
public T V174;
|
|
||||||
public T V175;
|
|
||||||
public T V176;
|
|
||||||
public T V177;
|
|
||||||
public T V178;
|
|
||||||
public T V179;
|
|
||||||
public T V180;
|
|
||||||
public T V181;
|
|
||||||
public T V182;
|
|
||||||
public T V183;
|
|
||||||
public T V184;
|
|
||||||
public T V185;
|
|
||||||
public T V186;
|
|
||||||
public T V187;
|
|
||||||
public T V188;
|
|
||||||
public T V189;
|
|
||||||
public T V190;
|
|
||||||
public T V191;
|
|
||||||
public T V192;
|
|
||||||
public T V193;
|
|
||||||
public T V194;
|
|
||||||
public T V195;
|
|
||||||
public T V196;
|
|
||||||
public T V197;
|
|
||||||
public T V198;
|
|
||||||
public T V199;
|
|
||||||
public T V200;
|
|
||||||
public T V201;
|
|
||||||
public T V202;
|
|
||||||
public T V203;
|
|
||||||
public T V204;
|
|
||||||
public T V205;
|
|
||||||
public T V206;
|
|
||||||
public T V207;
|
|
||||||
public T V208;
|
|
||||||
public T V209;
|
|
||||||
public T V210;
|
|
||||||
public T V211;
|
|
||||||
public T V212;
|
|
||||||
public T V213;
|
|
||||||
public T V214;
|
|
||||||
public T V215;
|
|
||||||
public T V216;
|
|
||||||
public T V217;
|
|
||||||
public T V218;
|
|
||||||
public T V219;
|
|
||||||
public T V220;
|
|
||||||
public T V221;
|
|
||||||
public T V222;
|
|
||||||
public T V223;
|
|
||||||
public T V224;
|
|
||||||
public T V225;
|
|
||||||
public T V226;
|
|
||||||
public T V227;
|
|
||||||
public T V228;
|
|
||||||
public T V229;
|
|
||||||
public T V230;
|
|
||||||
public T V231;
|
|
||||||
public T V232;
|
|
||||||
public T V233;
|
|
||||||
public T V234;
|
|
||||||
public T V235;
|
|
||||||
public T V236;
|
|
||||||
public T V237;
|
|
||||||
public T V238;
|
|
||||||
public T V239;
|
|
||||||
public T V240;
|
|
||||||
public T V241;
|
|
||||||
public T V242;
|
|
||||||
public T V243;
|
|
||||||
public T V244;
|
|
||||||
public T V245;
|
|
||||||
public T V246;
|
|
||||||
public T V247;
|
|
||||||
public T V248;
|
|
||||||
public T V249;
|
|
||||||
public T V250;
|
|
||||||
public T V251;
|
|
||||||
public T V252;
|
|
||||||
public T V253;
|
|
||||||
public T V254;
|
|
||||||
public T V255;
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
return index switch
|
|
||||||
{
|
|
||||||
0 => V0,
|
|
||||||
1 => V1,
|
|
||||||
2 => V2,
|
|
||||||
3 => V3,
|
|
||||||
4 => V4,
|
|
||||||
5 => V5,
|
|
||||||
6 => V6,
|
|
||||||
7 => V7,
|
|
||||||
8 => V8,
|
|
||||||
9 => V9,
|
|
||||||
10 => V10,
|
|
||||||
11 => V11,
|
|
||||||
12 => V12,
|
|
||||||
13 => V13,
|
|
||||||
14 => V14,
|
|
||||||
15 => V15,
|
|
||||||
16 => V16,
|
|
||||||
17 => V17,
|
|
||||||
18 => V18,
|
|
||||||
19 => V19,
|
|
||||||
20 => V20,
|
|
||||||
21 => V21,
|
|
||||||
22 => V22,
|
|
||||||
23 => V23,
|
|
||||||
24 => V24,
|
|
||||||
25 => V25,
|
|
||||||
26 => V26,
|
|
||||||
27 => V27,
|
|
||||||
28 => V28,
|
|
||||||
29 => V29,
|
|
||||||
30 => V30,
|
|
||||||
31 => V31,
|
|
||||||
32 => V32,
|
|
||||||
33 => V33,
|
|
||||||
34 => V34,
|
|
||||||
35 => V35,
|
|
||||||
36 => V36,
|
|
||||||
37 => V37,
|
|
||||||
38 => V38,
|
|
||||||
39 => V39,
|
|
||||||
40 => V40,
|
|
||||||
41 => V41,
|
|
||||||
42 => V42,
|
|
||||||
43 => V43,
|
|
||||||
44 => V44,
|
|
||||||
45 => V45,
|
|
||||||
46 => V46,
|
|
||||||
47 => V47,
|
|
||||||
48 => V48,
|
|
||||||
49 => V49,
|
|
||||||
50 => V50,
|
|
||||||
51 => V51,
|
|
||||||
52 => V52,
|
|
||||||
53 => V53,
|
|
||||||
54 => V54,
|
|
||||||
55 => V55,
|
|
||||||
56 => V56,
|
|
||||||
57 => V57,
|
|
||||||
58 => V58,
|
|
||||||
59 => V59,
|
|
||||||
60 => V60,
|
|
||||||
61 => V61,
|
|
||||||
62 => V62,
|
|
||||||
63 => V63,
|
|
||||||
64 => V64,
|
|
||||||
65 => V65,
|
|
||||||
66 => V66,
|
|
||||||
67 => V67,
|
|
||||||
68 => V68,
|
|
||||||
69 => V69,
|
|
||||||
70 => V70,
|
|
||||||
71 => V71,
|
|
||||||
72 => V72,
|
|
||||||
73 => V73,
|
|
||||||
74 => V74,
|
|
||||||
75 => V75,
|
|
||||||
76 => V76,
|
|
||||||
77 => V77,
|
|
||||||
78 => V78,
|
|
||||||
79 => V79,
|
|
||||||
80 => V80,
|
|
||||||
81 => V81,
|
|
||||||
82 => V82,
|
|
||||||
83 => V83,
|
|
||||||
84 => V84,
|
|
||||||
85 => V85,
|
|
||||||
86 => V86,
|
|
||||||
87 => V87,
|
|
||||||
88 => V88,
|
|
||||||
89 => V89,
|
|
||||||
90 => V90,
|
|
||||||
91 => V91,
|
|
||||||
92 => V92,
|
|
||||||
93 => V93,
|
|
||||||
94 => V94,
|
|
||||||
95 => V95,
|
|
||||||
96 => V96,
|
|
||||||
97 => V97,
|
|
||||||
98 => V98,
|
|
||||||
99 => V99,
|
|
||||||
100 => V100,
|
|
||||||
101 => V101,
|
|
||||||
102 => V102,
|
|
||||||
103 => V103,
|
|
||||||
104 => V104,
|
|
||||||
105 => V105,
|
|
||||||
106 => V106,
|
|
||||||
107 => V107,
|
|
||||||
108 => V108,
|
|
||||||
109 => V109,
|
|
||||||
110 => V110,
|
|
||||||
111 => V111,
|
|
||||||
112 => V112,
|
|
||||||
113 => V113,
|
|
||||||
114 => V114,
|
|
||||||
115 => V115,
|
|
||||||
116 => V116,
|
|
||||||
117 => V117,
|
|
||||||
118 => V118,
|
|
||||||
119 => V119,
|
|
||||||
120 => V120,
|
|
||||||
121 => V121,
|
|
||||||
122 => V122,
|
|
||||||
123 => V123,
|
|
||||||
124 => V124,
|
|
||||||
125 => V125,
|
|
||||||
126 => V126,
|
|
||||||
127 => V127,
|
|
||||||
128 => V128,
|
|
||||||
129 => V129,
|
|
||||||
130 => V130,
|
|
||||||
131 => V131,
|
|
||||||
132 => V132,
|
|
||||||
133 => V133,
|
|
||||||
134 => V134,
|
|
||||||
135 => V135,
|
|
||||||
136 => V136,
|
|
||||||
137 => V137,
|
|
||||||
138 => V138,
|
|
||||||
139 => V139,
|
|
||||||
140 => V140,
|
|
||||||
141 => V141,
|
|
||||||
142 => V142,
|
|
||||||
143 => V143,
|
|
||||||
144 => V144,
|
|
||||||
145 => V145,
|
|
||||||
146 => V146,
|
|
||||||
147 => V147,
|
|
||||||
148 => V148,
|
|
||||||
149 => V149,
|
|
||||||
150 => V150,
|
|
||||||
151 => V151,
|
|
||||||
152 => V152,
|
|
||||||
153 => V153,
|
|
||||||
154 => V154,
|
|
||||||
155 => V155,
|
|
||||||
156 => V156,
|
|
||||||
157 => V157,
|
|
||||||
158 => V158,
|
|
||||||
159 => V159,
|
|
||||||
160 => V160,
|
|
||||||
161 => V161,
|
|
||||||
162 => V162,
|
|
||||||
163 => V163,
|
|
||||||
164 => V164,
|
|
||||||
165 => V165,
|
|
||||||
166 => V166,
|
|
||||||
167 => V167,
|
|
||||||
168 => V168,
|
|
||||||
169 => V169,
|
|
||||||
170 => V170,
|
|
||||||
171 => V171,
|
|
||||||
172 => V172,
|
|
||||||
173 => V173,
|
|
||||||
174 => V174,
|
|
||||||
175 => V175,
|
|
||||||
176 => V176,
|
|
||||||
177 => V177,
|
|
||||||
178 => V178,
|
|
||||||
179 => V179,
|
|
||||||
180 => V180,
|
|
||||||
181 => V181,
|
|
||||||
182 => V182,
|
|
||||||
183 => V183,
|
|
||||||
184 => V184,
|
|
||||||
185 => V185,
|
|
||||||
186 => V186,
|
|
||||||
187 => V187,
|
|
||||||
188 => V188,
|
|
||||||
189 => V189,
|
|
||||||
190 => V190,
|
|
||||||
191 => V191,
|
|
||||||
192 => V192,
|
|
||||||
193 => V193,
|
|
||||||
194 => V194,
|
|
||||||
195 => V195,
|
|
||||||
196 => V196,
|
|
||||||
197 => V197,
|
|
||||||
198 => V198,
|
|
||||||
199 => V199,
|
|
||||||
200 => V200,
|
|
||||||
201 => V201,
|
|
||||||
202 => V202,
|
|
||||||
203 => V203,
|
|
||||||
204 => V204,
|
|
||||||
205 => V205,
|
|
||||||
206 => V206,
|
|
||||||
207 => V207,
|
|
||||||
208 => V208,
|
|
||||||
209 => V209,
|
|
||||||
210 => V210,
|
|
||||||
211 => V211,
|
|
||||||
212 => V212,
|
|
||||||
213 => V213,
|
|
||||||
214 => V214,
|
|
||||||
215 => V215,
|
|
||||||
216 => V216,
|
|
||||||
217 => V217,
|
|
||||||
218 => V218,
|
|
||||||
219 => V219,
|
|
||||||
220 => V220,
|
|
||||||
221 => V221,
|
|
||||||
222 => V222,
|
|
||||||
223 => V223,
|
|
||||||
224 => V224,
|
|
||||||
225 => V225,
|
|
||||||
226 => V226,
|
|
||||||
227 => V227,
|
|
||||||
228 => V228,
|
|
||||||
229 => V229,
|
|
||||||
230 => V230,
|
|
||||||
231 => V231,
|
|
||||||
232 => V232,
|
|
||||||
233 => V233,
|
|
||||||
234 => V234,
|
|
||||||
235 => V235,
|
|
||||||
236 => V236,
|
|
||||||
237 => V237,
|
|
||||||
238 => V238,
|
|
||||||
239 => V239,
|
|
||||||
240 => V240,
|
|
||||||
241 => V241,
|
|
||||||
242 => V242,
|
|
||||||
243 => V243,
|
|
||||||
244 => V244,
|
|
||||||
245 => V245,
|
|
||||||
246 => V246,
|
|
||||||
247 => V247,
|
|
||||||
248 => V248,
|
|
||||||
249 => V249,
|
|
||||||
250 => V250,
|
|
||||||
251 => V251,
|
|
||||||
252 => V252,
|
|
||||||
253 => V253,
|
|
||||||
254 => V254,
|
|
||||||
255 => V255,
|
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(index), index, null)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0: V0 = value; break;
|
|
||||||
case 1: V1 = value; break;
|
|
||||||
case 2: V2 = value; break;
|
|
||||||
case 3: V3 = value; break;
|
|
||||||
case 4: V4 = value; break;
|
|
||||||
case 5: V5 = value; break;
|
|
||||||
case 6: V6 = value; break;
|
|
||||||
case 7: V7 = value; break;
|
|
||||||
case 8: V8 = value; break;
|
|
||||||
case 9: V9 = value; break;
|
|
||||||
case 10: V10 = value; break;
|
|
||||||
case 11: V11 = value; break;
|
|
||||||
case 12: V12 = value; break;
|
|
||||||
case 13: V13 = value; break;
|
|
||||||
case 14: V14 = value; break;
|
|
||||||
case 15: V15 = value; break;
|
|
||||||
case 16: V16 = value; break;
|
|
||||||
case 17: V17 = value; break;
|
|
||||||
case 18: V18 = value; break;
|
|
||||||
case 19: V19 = value; break;
|
|
||||||
case 20: V20 = value; break;
|
|
||||||
case 21: V21 = value; break;
|
|
||||||
case 22: V22 = value; break;
|
|
||||||
case 23: V23 = value; break;
|
|
||||||
case 24: V24 = value; break;
|
|
||||||
case 25: V25 = value; break;
|
|
||||||
case 26: V26 = value; break;
|
|
||||||
case 27: V27 = value; break;
|
|
||||||
case 28: V28 = value; break;
|
|
||||||
case 29: V29 = value; break;
|
|
||||||
case 30: V30 = value; break;
|
|
||||||
case 31: V31 = value; break;
|
|
||||||
case 32: V32 = value; break;
|
|
||||||
case 33: V33 = value; break;
|
|
||||||
case 34: V34 = value; break;
|
|
||||||
case 35: V35 = value; break;
|
|
||||||
case 36: V36 = value; break;
|
|
||||||
case 37: V37 = value; break;
|
|
||||||
case 38: V38 = value; break;
|
|
||||||
case 39: V39 = value; break;
|
|
||||||
case 40: V40 = value; break;
|
|
||||||
case 41: V41 = value; break;
|
|
||||||
case 42: V42 = value; break;
|
|
||||||
case 43: V43 = value; break;
|
|
||||||
case 44: V44 = value; break;
|
|
||||||
case 45: V45 = value; break;
|
|
||||||
case 46: V46 = value; break;
|
|
||||||
case 47: V47 = value; break;
|
|
||||||
case 48: V48 = value; break;
|
|
||||||
case 49: V49 = value; break;
|
|
||||||
case 50: V50 = value; break;
|
|
||||||
case 51: V51 = value; break;
|
|
||||||
case 52: V52 = value; break;
|
|
||||||
case 53: V53 = value; break;
|
|
||||||
case 54: V54 = value; break;
|
|
||||||
case 55: V55 = value; break;
|
|
||||||
case 56: V56 = value; break;
|
|
||||||
case 57: V57 = value; break;
|
|
||||||
case 58: V58 = value; break;
|
|
||||||
case 59: V59 = value; break;
|
|
||||||
case 60: V60 = value; break;
|
|
||||||
case 61: V61 = value; break;
|
|
||||||
case 62: V62 = value; break;
|
|
||||||
case 63: V63 = value; break;
|
|
||||||
case 64: V64 = value; break;
|
|
||||||
case 65: V65 = value; break;
|
|
||||||
case 66: V66 = value; break;
|
|
||||||
case 67: V67 = value; break;
|
|
||||||
case 68: V68 = value; break;
|
|
||||||
case 69: V69 = value; break;
|
|
||||||
case 70: V70 = value; break;
|
|
||||||
case 71: V71 = value; break;
|
|
||||||
case 72: V72 = value; break;
|
|
||||||
case 73: V73 = value; break;
|
|
||||||
case 74: V74 = value; break;
|
|
||||||
case 75: V75 = value; break;
|
|
||||||
case 76: V76 = value; break;
|
|
||||||
case 77: V77 = value; break;
|
|
||||||
case 78: V78 = value; break;
|
|
||||||
case 79: V79 = value; break;
|
|
||||||
case 80: V80 = value; break;
|
|
||||||
case 81: V81 = value; break;
|
|
||||||
case 82: V82 = value; break;
|
|
||||||
case 83: V83 = value; break;
|
|
||||||
case 84: V84 = value; break;
|
|
||||||
case 85: V85 = value; break;
|
|
||||||
case 86: V86 = value; break;
|
|
||||||
case 87: V87 = value; break;
|
|
||||||
case 88: V88 = value; break;
|
|
||||||
case 89: V89 = value; break;
|
|
||||||
case 90: V90 = value; break;
|
|
||||||
case 91: V91 = value; break;
|
|
||||||
case 92: V92 = value; break;
|
|
||||||
case 93: V93 = value; break;
|
|
||||||
case 94: V94 = value; break;
|
|
||||||
case 95: V95 = value; break;
|
|
||||||
case 96: V96 = value; break;
|
|
||||||
case 97: V97 = value; break;
|
|
||||||
case 98: V98 = value; break;
|
|
||||||
case 99: V99 = value; break;
|
|
||||||
case 100: V100 = value; break;
|
|
||||||
case 101: V101 = value; break;
|
|
||||||
case 102: V102 = value; break;
|
|
||||||
case 103: V103 = value; break;
|
|
||||||
case 104: V104 = value; break;
|
|
||||||
case 105: V105 = value; break;
|
|
||||||
case 106: V106 = value; break;
|
|
||||||
case 107: V107 = value; break;
|
|
||||||
case 108: V108 = value; break;
|
|
||||||
case 109: V109 = value; break;
|
|
||||||
case 110: V110 = value; break;
|
|
||||||
case 111: V111 = value; break;
|
|
||||||
case 112: V112 = value; break;
|
|
||||||
case 113: V113 = value; break;
|
|
||||||
case 114: V114 = value; break;
|
|
||||||
case 115: V115 = value; break;
|
|
||||||
case 116: V116 = value; break;
|
|
||||||
case 117: V117 = value; break;
|
|
||||||
case 118: V118 = value; break;
|
|
||||||
case 119: V119 = value; break;
|
|
||||||
case 120: V120 = value; break;
|
|
||||||
case 121: V121 = value; break;
|
|
||||||
case 122: V122 = value; break;
|
|
||||||
case 123: V123 = value; break;
|
|
||||||
case 124: V124 = value; break;
|
|
||||||
case 125: V125 = value; break;
|
|
||||||
case 126: V126 = value; break;
|
|
||||||
case 127: V127 = value; break;
|
|
||||||
case 128: V128 = value; break;
|
|
||||||
case 129: V129 = value; break;
|
|
||||||
case 130: V130 = value; break;
|
|
||||||
case 131: V131 = value; break;
|
|
||||||
case 132: V132 = value; break;
|
|
||||||
case 133: V133 = value; break;
|
|
||||||
case 134: V134 = value; break;
|
|
||||||
case 135: V135 = value; break;
|
|
||||||
case 136: V136 = value; break;
|
|
||||||
case 137: V137 = value; break;
|
|
||||||
case 138: V138 = value; break;
|
|
||||||
case 139: V139 = value; break;
|
|
||||||
case 140: V140 = value; break;
|
|
||||||
case 141: V141 = value; break;
|
|
||||||
case 142: V142 = value; break;
|
|
||||||
case 143: V143 = value; break;
|
|
||||||
case 144: V144 = value; break;
|
|
||||||
case 145: V145 = value; break;
|
|
||||||
case 146: V146 = value; break;
|
|
||||||
case 147: V147 = value; break;
|
|
||||||
case 148: V148 = value; break;
|
|
||||||
case 149: V149 = value; break;
|
|
||||||
case 150: V150 = value; break;
|
|
||||||
case 151: V151 = value; break;
|
|
||||||
case 152: V152 = value; break;
|
|
||||||
case 153: V153 = value; break;
|
|
||||||
case 154: V154 = value; break;
|
|
||||||
case 155: V155 = value; break;
|
|
||||||
case 156: V156 = value; break;
|
|
||||||
case 157: V157 = value; break;
|
|
||||||
case 158: V158 = value; break;
|
|
||||||
case 159: V159 = value; break;
|
|
||||||
case 160: V160 = value; break;
|
|
||||||
case 161: V161 = value; break;
|
|
||||||
case 162: V162 = value; break;
|
|
||||||
case 163: V163 = value; break;
|
|
||||||
case 164: V164 = value; break;
|
|
||||||
case 165: V165 = value; break;
|
|
||||||
case 166: V166 = value; break;
|
|
||||||
case 167: V167 = value; break;
|
|
||||||
case 168: V168 = value; break;
|
|
||||||
case 169: V169 = value; break;
|
|
||||||
case 170: V170 = value; break;
|
|
||||||
case 171: V171 = value; break;
|
|
||||||
case 172: V172 = value; break;
|
|
||||||
case 173: V173 = value; break;
|
|
||||||
case 174: V174 = value; break;
|
|
||||||
case 175: V175 = value; break;
|
|
||||||
case 176: V176 = value; break;
|
|
||||||
case 177: V177 = value; break;
|
|
||||||
case 178: V178 = value; break;
|
|
||||||
case 179: V179 = value; break;
|
|
||||||
case 180: V180 = value; break;
|
|
||||||
case 181: V181 = value; break;
|
|
||||||
case 182: V182 = value; break;
|
|
||||||
case 183: V183 = value; break;
|
|
||||||
case 184: V184 = value; break;
|
|
||||||
case 185: V185 = value; break;
|
|
||||||
case 186: V186 = value; break;
|
|
||||||
case 187: V187 = value; break;
|
|
||||||
case 188: V188 = value; break;
|
|
||||||
case 189: V189 = value; break;
|
|
||||||
case 190: V190 = value; break;
|
|
||||||
case 191: V191 = value; break;
|
|
||||||
case 192: V192 = value; break;
|
|
||||||
case 193: V193 = value; break;
|
|
||||||
case 194: V194 = value; break;
|
|
||||||
case 195: V195 = value; break;
|
|
||||||
case 196: V196 = value; break;
|
|
||||||
case 197: V197 = value; break;
|
|
||||||
case 198: V198 = value; break;
|
|
||||||
case 199: V199 = value; break;
|
|
||||||
case 200: V200 = value; break;
|
|
||||||
case 201: V201 = value; break;
|
|
||||||
case 202: V202 = value; break;
|
|
||||||
case 203: V203 = value; break;
|
|
||||||
case 204: V204 = value; break;
|
|
||||||
case 205: V205 = value; break;
|
|
||||||
case 206: V206 = value; break;
|
|
||||||
case 207: V207 = value; break;
|
|
||||||
case 208: V208 = value; break;
|
|
||||||
case 209: V209 = value; break;
|
|
||||||
case 210: V210 = value; break;
|
|
||||||
case 211: V211 = value; break;
|
|
||||||
case 212: V212 = value; break;
|
|
||||||
case 213: V213 = value; break;
|
|
||||||
case 214: V214 = value; break;
|
|
||||||
case 215: V215 = value; break;
|
|
||||||
case 216: V216 = value; break;
|
|
||||||
case 217: V217 = value; break;
|
|
||||||
case 218: V218 = value; break;
|
|
||||||
case 219: V219 = value; break;
|
|
||||||
case 220: V220 = value; break;
|
|
||||||
case 221: V221 = value; break;
|
|
||||||
case 222: V222 = value; break;
|
|
||||||
case 223: V223 = value; break;
|
|
||||||
case 224: V224 = value; break;
|
|
||||||
case 225: V225 = value; break;
|
|
||||||
case 226: V226 = value; break;
|
|
||||||
case 227: V227 = value; break;
|
|
||||||
case 228: V228 = value; break;
|
|
||||||
case 229: V229 = value; break;
|
|
||||||
case 230: V230 = value; break;
|
|
||||||
case 231: V231 = value; break;
|
|
||||||
case 232: V232 = value; break;
|
|
||||||
case 233: V233 = value; break;
|
|
||||||
case 234: V234 = value; break;
|
|
||||||
case 235: V235 = value; break;
|
|
||||||
case 236: V236 = value; break;
|
|
||||||
case 237: V237 = value; break;
|
|
||||||
case 238: V238 = value; break;
|
|
||||||
case 239: V239 = value; break;
|
|
||||||
case 240: V240 = value; break;
|
|
||||||
case 241: V241 = value; break;
|
|
||||||
case 242: V242 = value; break;
|
|
||||||
case 243: V243 = value; break;
|
|
||||||
case 244: V244 = value; break;
|
|
||||||
case 245: V245 = value; break;
|
|
||||||
case 246: V246 = value; break;
|
|
||||||
case 247: V247 = value; break;
|
|
||||||
case 248: V248 = value; break;
|
|
||||||
case 249: V249 = value; break;
|
|
||||||
case 250: V250 = value; break;
|
|
||||||
case 251: V251 = value; break;
|
|
||||||
case 252: V252 = value; break;
|
|
||||||
case 253: V253 = value; break;
|
|
||||||
case 254: V254 = value; break;
|
|
||||||
case 255: V255 = value; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Collections
|
|
||||||
{
|
|
||||||
public struct RcStackArray32<T>
|
|
||||||
{
|
|
||||||
public static RcStackArray32<T> Empty => new RcStackArray32<T>();
|
|
||||||
|
|
||||||
private const int Size = 32;
|
|
||||||
public int Length => Size;
|
|
||||||
|
|
||||||
public T V0;
|
|
||||||
public T V1;
|
|
||||||
public T V2;
|
|
||||||
public T V3;
|
|
||||||
public T V4;
|
|
||||||
public T V5;
|
|
||||||
public T V6;
|
|
||||||
public T V7;
|
|
||||||
public T V8;
|
|
||||||
public T V9;
|
|
||||||
public T V10;
|
|
||||||
public T V11;
|
|
||||||
public T V12;
|
|
||||||
public T V13;
|
|
||||||
public T V14;
|
|
||||||
public T V15;
|
|
||||||
public T V16;
|
|
||||||
public T V17;
|
|
||||||
public T V18;
|
|
||||||
public T V19;
|
|
||||||
public T V20;
|
|
||||||
public T V21;
|
|
||||||
public T V22;
|
|
||||||
public T V23;
|
|
||||||
public T V24;
|
|
||||||
public T V25;
|
|
||||||
public T V26;
|
|
||||||
public T V27;
|
|
||||||
public T V28;
|
|
||||||
public T V29;
|
|
||||||
public T V30;
|
|
||||||
public T V31;
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
return index switch
|
|
||||||
{
|
|
||||||
0 => V0,
|
|
||||||
1 => V1,
|
|
||||||
2 => V2,
|
|
||||||
3 => V3,
|
|
||||||
4 => V4,
|
|
||||||
5 => V5,
|
|
||||||
6 => V6,
|
|
||||||
7 => V7,
|
|
||||||
8 => V8,
|
|
||||||
9 => V9,
|
|
||||||
10 => V10,
|
|
||||||
11 => V11,
|
|
||||||
12 => V12,
|
|
||||||
13 => V13,
|
|
||||||
14 => V14,
|
|
||||||
15 => V15,
|
|
||||||
16 => V16,
|
|
||||||
17 => V17,
|
|
||||||
18 => V18,
|
|
||||||
19 => V19,
|
|
||||||
20 => V20,
|
|
||||||
21 => V21,
|
|
||||||
22 => V22,
|
|
||||||
23 => V23,
|
|
||||||
24 => V24,
|
|
||||||
25 => V25,
|
|
||||||
26 => V26,
|
|
||||||
27 => V27,
|
|
||||||
28 => V28,
|
|
||||||
29 => V29,
|
|
||||||
30 => V30,
|
|
||||||
31 => V31,
|
|
||||||
_ => throw new IndexOutOfRangeException($"{index}")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0: V0 = value; break;
|
|
||||||
case 1: V1 = value; break;
|
|
||||||
case 2: V2 = value; break;
|
|
||||||
case 3: V3 = value; break;
|
|
||||||
case 4: V4 = value; break;
|
|
||||||
case 5: V5 = value; break;
|
|
||||||
case 6: V6 = value; break;
|
|
||||||
case 7: V7 = value; break;
|
|
||||||
case 8: V8 = value; break;
|
|
||||||
case 9: V9 = value; break;
|
|
||||||
case 10: V10 = value; break;
|
|
||||||
case 11: V11 = value; break;
|
|
||||||
case 12: V12 = value; break;
|
|
||||||
case 13: V13 = value; break;
|
|
||||||
case 14: V14 = value; break;
|
|
||||||
case 15: V15 = value; break;
|
|
||||||
case 16: V16 = value; break;
|
|
||||||
case 17: V17 = value; break;
|
|
||||||
case 18: V18 = value; break;
|
|
||||||
case 19: V19 = value; break;
|
|
||||||
case 20: V20 = value; break;
|
|
||||||
case 21: V21 = value; break;
|
|
||||||
case 22: V22 = value; break;
|
|
||||||
case 23: V23 = value; break;
|
|
||||||
case 24: V24 = value; break;
|
|
||||||
case 25: V25 = value; break;
|
|
||||||
case 26: V26 = value; break;
|
|
||||||
case 27: V27 = value; break;
|
|
||||||
case 28: V28 = value; break;
|
|
||||||
case 29: V29 = value; break;
|
|
||||||
case 30: V30 = value; break;
|
|
||||||
case 31: V31 = value; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Collections
|
|
||||||
{
|
|
||||||
public struct RcStackArray4<T>
|
|
||||||
{
|
|
||||||
public static RcStackArray4<T> Empty => new RcStackArray4<T>();
|
|
||||||
|
|
||||||
private const int Size = 4;
|
|
||||||
public int Length => Size;
|
|
||||||
|
|
||||||
public T V0;
|
|
||||||
public T V1;
|
|
||||||
public T V2;
|
|
||||||
public T V3;
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
return index switch
|
|
||||||
{
|
|
||||||
0 => V0,
|
|
||||||
1 => V1,
|
|
||||||
2 => V2,
|
|
||||||
3 => V3,
|
|
||||||
_ => throw new IndexOutOfRangeException($"{index}")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0: V0 = value; break;
|
|
||||||
case 1: V1 = value; break;
|
|
||||||
case 2: V2 = value; break;
|
|
||||||
case 3: V3 = value; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,229 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Collections
|
|
||||||
{
|
|
||||||
public struct RcStackArray64<T>
|
|
||||||
{
|
|
||||||
public static RcStackArray64<T> Empty => new RcStackArray64<T>();
|
|
||||||
|
|
||||||
private const int Size = 64;
|
|
||||||
public int Length => Size;
|
|
||||||
|
|
||||||
public T V0;
|
|
||||||
public T V1;
|
|
||||||
public T V2;
|
|
||||||
public T V3;
|
|
||||||
public T V4;
|
|
||||||
public T V5;
|
|
||||||
public T V6;
|
|
||||||
public T V7;
|
|
||||||
public T V8;
|
|
||||||
public T V9;
|
|
||||||
public T V10;
|
|
||||||
public T V11;
|
|
||||||
public T V12;
|
|
||||||
public T V13;
|
|
||||||
public T V14;
|
|
||||||
public T V15;
|
|
||||||
public T V16;
|
|
||||||
public T V17;
|
|
||||||
public T V18;
|
|
||||||
public T V19;
|
|
||||||
public T V20;
|
|
||||||
public T V21;
|
|
||||||
public T V22;
|
|
||||||
public T V23;
|
|
||||||
public T V24;
|
|
||||||
public T V25;
|
|
||||||
public T V26;
|
|
||||||
public T V27;
|
|
||||||
public T V28;
|
|
||||||
public T V29;
|
|
||||||
public T V30;
|
|
||||||
public T V31;
|
|
||||||
public T V32;
|
|
||||||
public T V33;
|
|
||||||
public T V34;
|
|
||||||
public T V35;
|
|
||||||
public T V36;
|
|
||||||
public T V37;
|
|
||||||
public T V38;
|
|
||||||
public T V39;
|
|
||||||
public T V40;
|
|
||||||
public T V41;
|
|
||||||
public T V42;
|
|
||||||
public T V43;
|
|
||||||
public T V44;
|
|
||||||
public T V45;
|
|
||||||
public T V46;
|
|
||||||
public T V47;
|
|
||||||
public T V48;
|
|
||||||
public T V49;
|
|
||||||
public T V50;
|
|
||||||
public T V51;
|
|
||||||
public T V52;
|
|
||||||
public T V53;
|
|
||||||
public T V54;
|
|
||||||
public T V55;
|
|
||||||
public T V56;
|
|
||||||
public T V57;
|
|
||||||
public T V58;
|
|
||||||
public T V59;
|
|
||||||
public T V60;
|
|
||||||
public T V61;
|
|
||||||
public T V62;
|
|
||||||
public T V63;
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
return index switch
|
|
||||||
{
|
|
||||||
0 => V0,
|
|
||||||
1 => V1,
|
|
||||||
2 => V2,
|
|
||||||
3 => V3,
|
|
||||||
4 => V4,
|
|
||||||
5 => V5,
|
|
||||||
6 => V6,
|
|
||||||
7 => V7,
|
|
||||||
8 => V8,
|
|
||||||
9 => V9,
|
|
||||||
10 => V10,
|
|
||||||
11 => V11,
|
|
||||||
12 => V12,
|
|
||||||
13 => V13,
|
|
||||||
14 => V14,
|
|
||||||
15 => V15,
|
|
||||||
16 => V16,
|
|
||||||
17 => V17,
|
|
||||||
18 => V18,
|
|
||||||
19 => V19,
|
|
||||||
20 => V20,
|
|
||||||
21 => V21,
|
|
||||||
22 => V22,
|
|
||||||
23 => V23,
|
|
||||||
24 => V24,
|
|
||||||
25 => V25,
|
|
||||||
26 => V26,
|
|
||||||
27 => V27,
|
|
||||||
28 => V28,
|
|
||||||
29 => V29,
|
|
||||||
30 => V30,
|
|
||||||
31 => V31,
|
|
||||||
32 => V32,
|
|
||||||
33 => V33,
|
|
||||||
34 => V34,
|
|
||||||
35 => V35,
|
|
||||||
36 => V36,
|
|
||||||
37 => V37,
|
|
||||||
38 => V38,
|
|
||||||
39 => V39,
|
|
||||||
40 => V40,
|
|
||||||
41 => V41,
|
|
||||||
42 => V42,
|
|
||||||
43 => V43,
|
|
||||||
44 => V44,
|
|
||||||
45 => V45,
|
|
||||||
46 => V46,
|
|
||||||
47 => V47,
|
|
||||||
48 => V48,
|
|
||||||
49 => V49,
|
|
||||||
50 => V50,
|
|
||||||
51 => V51,
|
|
||||||
52 => V52,
|
|
||||||
53 => V53,
|
|
||||||
54 => V54,
|
|
||||||
55 => V55,
|
|
||||||
56 => V56,
|
|
||||||
57 => V57,
|
|
||||||
58 => V58,
|
|
||||||
59 => V59,
|
|
||||||
60 => V60,
|
|
||||||
61 => V61,
|
|
||||||
62 => V62,
|
|
||||||
63 => V63,
|
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(index), index, null)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0: V0 = value; break;
|
|
||||||
case 1: V1 = value; break;
|
|
||||||
case 2: V2 = value; break;
|
|
||||||
case 3: V3 = value; break;
|
|
||||||
case 4: V4 = value; break;
|
|
||||||
case 5: V5 = value; break;
|
|
||||||
case 6: V6 = value; break;
|
|
||||||
case 7: V7 = value; break;
|
|
||||||
case 8: V8 = value; break;
|
|
||||||
case 9: V9 = value; break;
|
|
||||||
case 10: V10 = value; break;
|
|
||||||
case 11: V11 = value; break;
|
|
||||||
case 12: V12 = value; break;
|
|
||||||
case 13: V13 = value; break;
|
|
||||||
case 14: V14 = value; break;
|
|
||||||
case 15: V15 = value; break;
|
|
||||||
case 16: V16 = value; break;
|
|
||||||
case 17: V17 = value; break;
|
|
||||||
case 18: V18 = value; break;
|
|
||||||
case 19: V19 = value; break;
|
|
||||||
case 20: V20 = value; break;
|
|
||||||
case 21: V21 = value; break;
|
|
||||||
case 22: V22 = value; break;
|
|
||||||
case 23: V23 = value; break;
|
|
||||||
case 24: V24 = value; break;
|
|
||||||
case 25: V25 = value; break;
|
|
||||||
case 26: V26 = value; break;
|
|
||||||
case 27: V27 = value; break;
|
|
||||||
case 28: V28 = value; break;
|
|
||||||
case 29: V29 = value; break;
|
|
||||||
case 30: V30 = value; break;
|
|
||||||
case 31: V31 = value; break;
|
|
||||||
case 32 : V32 = value; break;
|
|
||||||
case 33 : V33 = value; break;
|
|
||||||
case 34 : V34 = value; break;
|
|
||||||
case 35 : V35 = value; break;
|
|
||||||
case 36 : V36 = value; break;
|
|
||||||
case 37 : V37 = value; break;
|
|
||||||
case 38 : V38 = value; break;
|
|
||||||
case 39 : V39 = value; break;
|
|
||||||
case 40 : V40 = value; break;
|
|
||||||
case 41 : V41 = value; break;
|
|
||||||
case 42 : V42 = value; break;
|
|
||||||
case 43 : V43 = value; break;
|
|
||||||
case 44 : V44 = value; break;
|
|
||||||
case 45 : V45 = value; break;
|
|
||||||
case 46 : V46 = value; break;
|
|
||||||
case 47 : V47 = value; break;
|
|
||||||
case 48 : V48 = value; break;
|
|
||||||
case 49 : V49 = value; break;
|
|
||||||
case 50 : V50 = value; break;
|
|
||||||
case 51 : V51 = value; break;
|
|
||||||
case 52 : V52 = value; break;
|
|
||||||
case 53 : V53 = value; break;
|
|
||||||
case 54 : V54 = value; break;
|
|
||||||
case 55 : V55 = value; break;
|
|
||||||
case 56 : V56 = value; break;
|
|
||||||
case 57 : V57 = value; break;
|
|
||||||
case 58 : V58 = value; break;
|
|
||||||
case 59 : V59 = value; break;
|
|
||||||
case 60 : V60 = value; break;
|
|
||||||
case 61 : V61 = value; break;
|
|
||||||
case 62 : V62 = value; break;
|
|
||||||
case 63 : V63 = value; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Collections
|
|
||||||
{
|
|
||||||
public struct RcStackArray8<T>
|
|
||||||
{
|
|
||||||
public static RcStackArray8<T> Empty => new RcStackArray8<T>();
|
|
||||||
|
|
||||||
private const int Size = 8;
|
|
||||||
public int Length => Size;
|
|
||||||
|
|
||||||
public T V0;
|
|
||||||
public T V1;
|
|
||||||
public T V2;
|
|
||||||
public T V3;
|
|
||||||
public T V4;
|
|
||||||
public T V5;
|
|
||||||
public T V6;
|
|
||||||
public T V7;
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
return index switch
|
|
||||||
{
|
|
||||||
0 => V0,
|
|
||||||
1 => V1,
|
|
||||||
2 => V2,
|
|
||||||
3 => V3,
|
|
||||||
4 => V4,
|
|
||||||
5 => V5,
|
|
||||||
6 => V6,
|
|
||||||
7 => V7,
|
|
||||||
_ => throw new IndexOutOfRangeException($"{index}")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0: V0 = value; break;
|
|
||||||
case 1: V1 = value; break;
|
|
||||||
case 2: V2 = value; break;
|
|
||||||
case 3: V3 = value; break;
|
|
||||||
case 4: V4 = value; break;
|
|
||||||
case 5: V5 = value; break;
|
|
||||||
case 6: V6 = value; break;
|
|
||||||
case 7: V7 = value; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,12 +5,11 @@
|
||||||
<PackageId>DotRecast.Core</PackageId>
|
<PackageId>DotRecast.Core</PackageId>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Authors>ikpil</Authors>
|
<Authors>ikpil</Authors>
|
||||||
<Description>DotRecast - a port of Recast Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers</Description>
|
<Description>DotRecast - a port of Recast Detour, navigation mesh toolset for games, Unity3D, servers, C#</Description>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
||||||
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
||||||
<PackageReleaseNotes>https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md</PackageReleaseNotes>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -3,58 +3,58 @@ using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace DotRecast.Core.Numerics
|
namespace DotRecast.Core.Numerics
|
||||||
{
|
{
|
||||||
public struct RcVec2f
|
// public struct Vector2
|
||||||
{
|
// {
|
||||||
public float X;
|
// public float X;
|
||||||
public float Y;
|
// public float Y;
|
||||||
|
//
|
||||||
public static readonly RcVec2f Zero = new RcVec2f { X = 0, Y = 0 };
|
// public static Vector2 Zero { get; } = new Vector2 { X = 0, Y = 0 };
|
||||||
|
//
|
||||||
public RcVec2f(float x, float y)
|
// public Vector2(float x, float y)
|
||||||
{
|
// {
|
||||||
X = x;
|
// X = x;
|
||||||
Y = y;
|
// Y = y;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public override bool Equals(object obj)
|
// public override bool Equals(object obj)
|
||||||
{
|
// {
|
||||||
if (!(obj is RcVec2f))
|
// if (!(obj is Vector2))
|
||||||
return false;
|
// return false;
|
||||||
|
//
|
||||||
return Equals((RcVec2f)obj);
|
// return Equals((Vector2)obj);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(RcVec2f other)
|
// public bool Equals(Vector2 other)
|
||||||
{
|
// {
|
||||||
return X.Equals(other.X) &&
|
// return X.Equals(other.X) &&
|
||||||
Y.Equals(other.Y);
|
// Y.Equals(other.Y);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override int GetHashCode()
|
// public override int GetHashCode()
|
||||||
{
|
// {
|
||||||
int hash = X.GetHashCode();
|
// int hash = X.GetHashCode();
|
||||||
hash = RcHashCodes.CombineHashCodes(hash, Y.GetHashCode());
|
// hash = RcHashCodes.CombineHashCodes(hash, Y.GetHashCode());
|
||||||
return hash;
|
// return hash;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool operator ==(RcVec2f left, RcVec2f right)
|
// public static bool operator ==(Vector2 left, Vector2 right)
|
||||||
{
|
// {
|
||||||
return left.Equals(right);
|
// return left.Equals(right);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool operator !=(RcVec2f left, RcVec2f right)
|
// public static bool operator !=(Vector2 left, Vector2 right)
|
||||||
{
|
// {
|
||||||
return !left.Equals(right);
|
// return !left.Equals(right);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override string ToString()
|
// public override string ToString()
|
||||||
{
|
// {
|
||||||
return $"{X}, {Y}";
|
// return $"{X}, {Y}";
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
|
@ -21,240 +21,240 @@ using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace DotRecast.Core.Numerics
|
namespace DotRecast.Core.Numerics
|
||||||
{
|
{
|
||||||
public struct RcVec3f
|
// public struct Vector3
|
||||||
{
|
// {
|
||||||
public float X;
|
// public float X;
|
||||||
public float Y;
|
// public float Y;
|
||||||
public float Z;
|
// public float Z;
|
||||||
|
//
|
||||||
public static readonly RcVec3f Zero = new RcVec3f(0.0f, 0.0f, 0.0f);
|
// public static Vector3 Zero { get; } = new Vector3(0.0f, 0.0f, 0.0f);
|
||||||
public static readonly RcVec3f One = new RcVec3f(1.0f);
|
// public static Vector3 One { get; } = new Vector3(1.0f);
|
||||||
public static readonly RcVec3f UnitX = new RcVec3f(1.0f, 0.0f, 0.0f);
|
// public static Vector3 UnitX { get; } = new Vector3(1.0f, 0.0f, 0.0f);
|
||||||
public static readonly RcVec3f UnitY = new RcVec3f(0.0f, 1.0f, 0.0f);
|
// public static Vector3 UnitY { get; } = new Vector3(0.0f, 1.0f, 0.0f);
|
||||||
public static readonly RcVec3f UnitZ = new RcVec3f(0.0f, 0.0f, 1.0f);
|
// public static Vector3 UnitZ { get; } = new Vector3(0.0f, 0.0f, 1.0f);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public RcVec3f(float x, float y, float z)
|
// public Vector3(float x, float y, float z)
|
||||||
{
|
// {
|
||||||
X = x;
|
// X = x;
|
||||||
Y = y;
|
// Y = y;
|
||||||
Z = z;
|
// Z = z;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public RcVec3f(float f)
|
// public Vector3(float f)
|
||||||
{
|
// {
|
||||||
X = f;
|
// X = f;
|
||||||
Y = f;
|
// Y = f;
|
||||||
Z = f;
|
// Z = f;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly float Length()
|
// public readonly float Length()
|
||||||
{
|
// {
|
||||||
float lengthSquared = LengthSquared();
|
// float lengthSquared = LengthSquared();
|
||||||
return MathF.Sqrt(lengthSquared);
|
// return MathF.Sqrt(lengthSquared);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// Derives the square of the scalar length of the vector. (len * len)
|
// /// Derives the square of the scalar length of the vector. (len * len)
|
||||||
/// @param[in] v The vector. [(x, y, z)]
|
// /// @param[in] v The vector. [(x, y, z)]
|
||||||
/// @return The square of the scalar length of the vector.
|
// /// @return The square of the scalar length of the vector.
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly float LengthSquared()
|
// public readonly float LengthSquared()
|
||||||
{
|
// {
|
||||||
return Dot(this, this);
|
// return Dot(this, this);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Subtract(RcVec3f left, RcVec3f right)
|
// public static Vector3 Subtract(Vector3 left, Vector3 right)
|
||||||
{
|
// {
|
||||||
return left - right;
|
// return left - right;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Add(RcVec3f left, RcVec3f right)
|
// public static Vector3 Add(Vector3 left, Vector3 right)
|
||||||
{
|
// {
|
||||||
return left + right;
|
// return left + right;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
public override bool Equals(object obj)
|
// public override bool Equals(object obj)
|
||||||
{
|
// {
|
||||||
if (!(obj is RcVec3f))
|
// if (!(obj is Vector3))
|
||||||
return false;
|
// return false;
|
||||||
|
//
|
||||||
return Equals((RcVec3f)obj);
|
// return Equals((Vector3)obj);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(RcVec3f other)
|
// public bool Equals(Vector3 other)
|
||||||
{
|
// {
|
||||||
return X.Equals(other.X) &&
|
// return X.Equals(other.X) &&
|
||||||
Y.Equals(other.Y) &&
|
// Y.Equals(other.Y) &&
|
||||||
Z.Equals(other.Z);
|
// Z.Equals(other.Z);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override int GetHashCode()
|
// public override int GetHashCode()
|
||||||
{
|
// {
|
||||||
return HashCode.Combine(X, Y, Z);
|
// return HashCode.Combine(X, Y, Z);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Min(RcVec3f value1, RcVec3f value2)
|
// public static Vector3 Min(Vector3 value1, Vector3 value2)
|
||||||
{
|
// {
|
||||||
return new RcVec3f(
|
// return new Vector3(
|
||||||
(value1.X < value2.X) ? value1.X : value2.X,
|
// (value1.X < value2.X) ? value1.X : value2.X,
|
||||||
(value1.Y < value2.Y) ? value1.Y : value2.Y,
|
// (value1.Y < value2.Y) ? value1.Y : value2.Y,
|
||||||
(value1.Z < value2.Z) ? value1.Z : value2.Z
|
// (value1.Z < value2.Z) ? value1.Z : value2.Z
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Max(RcVec3f value1, RcVec3f value2)
|
// public static Vector3 Max(Vector3 value1, Vector3 value2)
|
||||||
{
|
// {
|
||||||
return new RcVec3f(
|
// return new Vector3(
|
||||||
(value1.X > value2.X) ? value1.X : value2.X,
|
// (value1.X > value2.X) ? value1.X : value2.X,
|
||||||
(value1.Y > value2.Y) ? value1.Y : value2.Y,
|
// (value1.Y > value2.Y) ? value1.Y : value2.Y,
|
||||||
(value1.Z > value2.Z) ? value1.Z : value2.Z
|
// (value1.Z > value2.Z) ? value1.Z : value2.Z
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public override string ToString()
|
// public override string ToString()
|
||||||
{
|
// {
|
||||||
return $"{X}, {Y}, {Z}";
|
// return $"{X}, {Y}, {Z}";
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool operator ==(RcVec3f left, RcVec3f right)
|
// public static bool operator ==(Vector3 left, Vector3 right)
|
||||||
{
|
// {
|
||||||
return left.Equals(right);
|
// return left.Equals(right);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool operator !=(RcVec3f left, RcVec3f right)
|
// public static bool operator !=(Vector3 left, Vector3 right)
|
||||||
{
|
// {
|
||||||
return !left.Equals(right);
|
// return !left.Equals(right);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f operator -(RcVec3f left, RcVec3f right)
|
// public static Vector3 operator -(Vector3 left, Vector3 right)
|
||||||
{
|
// {
|
||||||
return new RcVec3f(
|
// return new Vector3(
|
||||||
left.X - right.X,
|
// left.X - right.X,
|
||||||
left.Y - right.Y,
|
// left.Y - right.Y,
|
||||||
left.Z - right.Z
|
// left.Z - right.Z
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f operator +(RcVec3f left, RcVec3f right)
|
// public static Vector3 operator +(Vector3 left, Vector3 right)
|
||||||
{
|
// {
|
||||||
return new RcVec3f(
|
// return new Vector3(
|
||||||
left.X + right.X,
|
// left.X + right.X,
|
||||||
left.Y + right.Y,
|
// left.Y + right.Y,
|
||||||
left.Z + right.Z
|
// left.Z + right.Z
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f operator *(RcVec3f left, RcVec3f right)
|
// public static Vector3 operator *(Vector3 left, Vector3 right)
|
||||||
{
|
// {
|
||||||
return new RcVec3f(
|
// return new Vector3(
|
||||||
left.X * right.X,
|
// left.X * right.X,
|
||||||
left.Y * right.Y,
|
// left.Y * right.Y,
|
||||||
left.Z * right.Z
|
// left.Z * right.Z
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f operator *(RcVec3f left, float right)
|
// public static Vector3 operator *(Vector3 left, float right)
|
||||||
{
|
// {
|
||||||
return left * new RcVec3f(right);
|
// return left * new Vector3(right);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f operator *(float left, RcVec3f right)
|
// public static Vector3 operator *(float left, Vector3 right)
|
||||||
{
|
// {
|
||||||
return right * left;
|
// return right * left;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Lerp(RcVec3f value1, RcVec3f value2, float amount)
|
// public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount)
|
||||||
{
|
// {
|
||||||
return (value1 * (1f - amount)) + (value2 * amount);
|
// return (value1 * (1f - amount)) + (value2 * amount);
|
||||||
// return new RcVec3f(
|
// // return new Vector3(
|
||||||
// value1.X + (value2.X - value1.X) * amount,
|
// // value1.X + (value2.X - value1.X) * amount,
|
||||||
// value1.Y + (value2.Y - value1.Y) * amount,
|
// // value1.Y + (value2.Y - value1.Y) * amount,
|
||||||
// value1.Z + (value2.Z - value1.Z) * amount
|
// // value1.Z + (value2.Z - value1.Z) * amount
|
||||||
// );
|
// // );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// Returns the distance between two points.
|
// /// Returns the distance between two points.
|
||||||
/// @param[in] v1 A point. [(x, y, z)]
|
// /// @param[in] v1 A point. [(x, y, z)]
|
||||||
/// @param[in] v2 A point. [(x, y, z)]
|
// /// @param[in] v2 A point. [(x, y, z)]
|
||||||
/// @return The distance between the two points.
|
// /// @return The distance between the two points.
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Distance(RcVec3f value1, RcVec3f value2)
|
// public static float Distance(Vector3 value1, Vector3 value2)
|
||||||
{
|
// {
|
||||||
float distanceSquared = DistanceSquared(value1, value2);
|
// float distanceSquared = DistanceSquared(value1, value2);
|
||||||
return MathF.Sqrt(distanceSquared);
|
// return MathF.Sqrt(distanceSquared);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float DistanceSquared(RcVec3f value1, RcVec3f value2)
|
// public static float DistanceSquared(Vector3 value1, Vector3 value2)
|
||||||
{
|
// {
|
||||||
var difference = value1 - value2;
|
// var difference = value1 - value2;
|
||||||
return Dot(difference, difference);
|
// return Dot(difference, difference);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Dot(RcVec3f vector1, RcVec3f vector2)
|
// public static float Dot(Vector3 vector1, Vector3 vector2)
|
||||||
{
|
// {
|
||||||
return (vector1.X * vector2.X) +
|
// return (vector1.X * vector2.X) +
|
||||||
(vector1.Y * vector2.Y) +
|
// (vector1.Y * vector2.Y) +
|
||||||
(vector1.Z * vector2.Z);
|
// (vector1.Z * vector2.Z);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly void CopyTo(float[] array)
|
// public readonly void CopyTo(float[] array)
|
||||||
{
|
// {
|
||||||
CopyTo(array, 0);
|
// CopyTo(array, 0);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly void CopyTo(float[] array, int n)
|
// public readonly void CopyTo(float[] array, int n)
|
||||||
{
|
// {
|
||||||
array[n + 0] = X;
|
// array[n + 0] = X;
|
||||||
array[n + 1] = Y;
|
// array[n + 1] = Y;
|
||||||
array[n + 2] = Z;
|
// array[n + 2] = Z;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Cross(RcVec3f v1, RcVec3f v2)
|
// public static Vector3 Cross(Vector3 v1, Vector3 v2)
|
||||||
{
|
// {
|
||||||
return new RcVec3f(
|
// return new Vector3(
|
||||||
(v1.Y * v2.Z) - (v1.Z * v2.Y),
|
// (v1.Y * v2.Z) - (v1.Z * v2.Y),
|
||||||
(v1.Z * v2.X) - (v1.X * v2.Z),
|
// (v1.Z * v2.X) - (v1.X * v2.Z),
|
||||||
(v1.X * v2.Y) - (v1.Y * v2.X)
|
// (v1.X * v2.Y) - (v1.Y * v2.X)
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// Normalizes the vector.
|
// /// Normalizes the vector.
|
||||||
/// @param[in,out] v The vector to normalize. [(x, y, z)]
|
// /// @param[in,out] v The vector to normalize. [(x, y, z)]
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Normalize(RcVec3f v)
|
// public static Vector3 Normalize(Vector3 v)
|
||||||
{
|
// {
|
||||||
float d = 1.0f / MathF.Sqrt(RcMath.Sqr(v.X) + RcMath.Sqr(v.Y) + RcMath.Sqr(v.Z));
|
// float d = 1.0f / MathF.Sqrt(RcMath.Sqr(v.X) + RcMath.Sqr(v.Y) + RcMath.Sqr(v.Z));
|
||||||
|
//
|
||||||
return new RcVec3f(
|
// return new Vector3(
|
||||||
v.X *= d,
|
// v.X *= d,
|
||||||
v.Y *= d,
|
// v.Y *= d,
|
||||||
v.Z *= d
|
// v.Z *= d
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace DotRecast.Core.Numerics
|
namespace DotRecast.Core.Numerics
|
||||||
|
@ -8,19 +9,19 @@ namespace DotRecast.Core.Numerics
|
||||||
public const float EPSILON = 1e-6f;
|
public const float EPSILON = 1e-6f;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Create(float[] values)
|
public static Vector3 Create(float[] values)
|
||||||
{
|
{
|
||||||
return Create(values, 0);
|
return Create(values, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Create(float[] values, int n)
|
public static Vector3 Create(float[] values, int n)
|
||||||
{
|
{
|
||||||
return new RcVec3f(values[n + 0], values[n + 1], values[n + 2]);
|
return new Vector3(values[n + 0], values[n + 1], values[n + 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Get(this RcVec2f v, int i)
|
public static float Get(this Vector2 v, int i)
|
||||||
{
|
{
|
||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
|
@ -31,7 +32,7 @@ namespace DotRecast.Core.Numerics
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Get(this RcVec3f v, int i)
|
public static float Get(this Vector3 v, int i)
|
||||||
{
|
{
|
||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
|
@ -43,7 +44,7 @@ namespace DotRecast.Core.Numerics
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Scale(this RcVec3f v, float scale)
|
public static Vector3 Scale(this Vector3 v, float scale)
|
||||||
{
|
{
|
||||||
return v * scale;
|
return v * scale;
|
||||||
}
|
}
|
||||||
|
@ -56,23 +57,23 @@ namespace DotRecast.Core.Numerics
|
||||||
/// The vectors are projected onto the xz-plane, so the y-values are
|
/// The vectors are projected onto the xz-plane, so the y-values are
|
||||||
/// ignored.
|
/// ignored.
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Dot2D(this RcVec3f @this, RcVec3f v)
|
public static float Dot2D(this Vector3 @this, Vector3 v)
|
||||||
{
|
{
|
||||||
return @this.X * v.X +
|
return @this.X * v.X +
|
||||||
@this.Z * v.Z;
|
@this.Z * v.Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Dot2D(this RcVec3f @this, float[] v, int vi)
|
public static float Dot2D(this Vector3 @this, float[] v, int vi)
|
||||||
{
|
{
|
||||||
return @this.X * v[vi] +
|
return @this.X * v[vi] +
|
||||||
@this.Z * v[vi + 2];
|
@this.Z * v[vi + 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Add(RcVec3f a, float[] verts, int i)
|
public static Vector3 Add(Vector3 a, float[] verts, int i)
|
||||||
{
|
{
|
||||||
return new RcVec3f(
|
return new Vector3(
|
||||||
a.X + verts[i],
|
a.X + verts[i],
|
||||||
a.Y + verts[i + 1],
|
a.Y + verts[i + 1],
|
||||||
a.Z + verts[i + 2]
|
a.Z + verts[i + 2]
|
||||||
|
@ -81,9 +82,9 @@ namespace DotRecast.Core.Numerics
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Subtract(float[] verts, int i, int j)
|
public static Vector3 Subtract(float[] verts, int i, int j)
|
||||||
{
|
{
|
||||||
return new RcVec3f(
|
return new Vector3(
|
||||||
verts[i] - verts[j],
|
verts[i] - verts[j],
|
||||||
verts[i + 1] - verts[j + 1],
|
verts[i + 1] - verts[j + 1],
|
||||||
verts[i + 2] - verts[j + 2]
|
verts[i + 2] - verts[j + 2]
|
||||||
|
@ -92,9 +93,9 @@ namespace DotRecast.Core.Numerics
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Subtract(RcVec3f i, float[] verts, int j)
|
public static Vector3 Subtract(Vector3 i, float[] verts, int j)
|
||||||
{
|
{
|
||||||
return new RcVec3f(
|
return new Vector3(
|
||||||
i.X - verts[j],
|
i.X - verts[j],
|
||||||
i.Y - verts[j + 1],
|
i.Y - verts[j + 1],
|
||||||
i.Z - verts[j + 2]
|
i.Z - verts[j + 2]
|
||||||
|
@ -127,7 +128,7 @@ namespace DotRecast.Core.Numerics
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Dot(float[] v1, RcVec3f vector2)
|
public static float Dot(float[] v1, Vector3 vector2)
|
||||||
{
|
{
|
||||||
return v1[0] * vector2.X +
|
return v1[0] * vector2.X +
|
||||||
v1[1] * vector2.Y +
|
v1[1] * vector2.Y +
|
||||||
|
@ -139,7 +140,7 @@ namespace DotRecast.Core.Numerics
|
||||||
/// @param[in] v2 A point. [(x, y, z)]
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
/// @return The distance between the two points.
|
/// @return The distance between the two points.
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float DistanceSquared(RcVec3f v1, float[] v2, int i)
|
public static float DistanceSquared(Vector3 v1, float[] v2, int i)
|
||||||
{
|
{
|
||||||
float dx = v2[i] - v1.X;
|
float dx = v2[i] - v1.X;
|
||||||
float dy = v2[i + 1] - v1.Y;
|
float dy = v2[i + 1] - v1.Y;
|
||||||
|
@ -151,13 +152,13 @@ namespace DotRecast.Core.Numerics
|
||||||
/// If the magnitude is zero, the vector is unchanged.
|
/// If the magnitude is zero, the vector is unchanged.
|
||||||
/// @param[in,out] v The vector to normalize. [(x, y, z)]
|
/// @param[in,out] v The vector to normalize. [(x, y, z)]
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f SafeNormalize(RcVec3f v)
|
public static Vector3 SafeNormalize(Vector3 v)
|
||||||
{
|
{
|
||||||
float sqMag = RcMath.Sqr(v.X) + RcMath.Sqr(v.Y) + RcMath.Sqr(v.Z);
|
float sqMag = RcMath.Sqr(v.X) + RcMath.Sqr(v.Y) + RcMath.Sqr(v.Z);
|
||||||
if (sqMag > EPSILON)
|
if (sqMag > EPSILON)
|
||||||
{
|
{
|
||||||
float inverseMag = 1.0f / MathF.Sqrt(sqMag);
|
float inverseMag = 1.0f / MathF.Sqrt(sqMag);
|
||||||
return new RcVec3f(
|
return new Vector3(
|
||||||
v.X *= inverseMag,
|
v.X *= inverseMag,
|
||||||
v.Y *= inverseMag,
|
v.Y *= inverseMag,
|
||||||
v.Z *= inverseMag
|
v.Z *= inverseMag
|
||||||
|
@ -168,9 +169,9 @@ namespace DotRecast.Core.Numerics
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Min(RcVec3f v, float[] @in, int i)
|
public static Vector3 Min(Vector3 v, float[] @in, int i)
|
||||||
{
|
{
|
||||||
return new RcVec3f(
|
return new Vector3(
|
||||||
(v.X < @in[i + 0]) ? v.X : @in[i + 0],
|
(v.X < @in[i + 0]) ? v.X : @in[i + 0],
|
||||||
(v.Y < @in[i + 1]) ? v.Y : @in[i + 1],
|
(v.Y < @in[i + 1]) ? v.Y : @in[i + 1],
|
||||||
(v.Z < @in[i + 2]) ? v.Z : @in[i + 2]
|
(v.Z < @in[i + 2]) ? v.Z : @in[i + 2]
|
||||||
|
@ -178,9 +179,9 @@ namespace DotRecast.Core.Numerics
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Max(RcVec3f v, float[] @in, int i)
|
public static Vector3 Max(Vector3 v, float[] @in, int i)
|
||||||
{
|
{
|
||||||
return new RcVec3f(
|
return new Vector3(
|
||||||
(v.X > @in[i + 0]) ? v.X : @in[i + 0],
|
(v.X > @in[i + 0]) ? v.X : @in[i + 0],
|
||||||
(v.Y > @in[i + 1]) ? v.Y : @in[i + 1],
|
(v.Y > @in[i + 1]) ? v.Y : @in[i + 1],
|
||||||
(v.Z > @in[i + 2]) ? v.Z : @in[i + 2]
|
(v.Z > @in[i + 2]) ? v.Z : @in[i + 2]
|
||||||
|
@ -195,7 +196,7 @@ namespace DotRecast.Core.Numerics
|
||||||
/// The vectors are projected onto the xz-plane, so the y-values are
|
/// The vectors are projected onto the xz-plane, so the y-values are
|
||||||
/// ignored.
|
/// ignored.
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Dist2D(RcVec3f v1, RcVec3f v2)
|
public static float Dist2D(Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
float dx = v2.X - v1.X;
|
float dx = v2.X - v1.X;
|
||||||
float dz = v2.Z - v1.Z;
|
float dz = v2.Z - v1.Z;
|
||||||
|
@ -203,7 +204,7 @@ namespace DotRecast.Core.Numerics
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Dist2DSqr(RcVec3f v1, RcVec3f v2)
|
public static float Dist2DSqr(Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
float dx = v2.X - v1.X;
|
float dx = v2.X - v1.X;
|
||||||
float dz = v2.Z - v1.Z;
|
float dz = v2.Z - v1.Z;
|
||||||
|
@ -211,7 +212,7 @@ namespace DotRecast.Core.Numerics
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Dist2DSqr(RcVec3f p, float[] verts, int i)
|
public static float Dist2DSqr(Vector3 p, float[] verts, int i)
|
||||||
{
|
{
|
||||||
float dx = verts[i] - p.X;
|
float dx = verts[i] - p.X;
|
||||||
float dz = verts[i + 2] - p.Z;
|
float dz = verts[i + 2] - p.Z;
|
||||||
|
@ -226,7 +227,7 @@ namespace DotRecast.Core.Numerics
|
||||||
/// The vectors are projected onto the xz-plane, so the y-values are
|
/// The vectors are projected onto the xz-plane, so the y-values are
|
||||||
/// ignored.
|
/// ignored.
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float Perp2D(RcVec3f u, RcVec3f v)
|
public static float Perp2D(Vector3 u, Vector3 v)
|
||||||
{
|
{
|
||||||
return u.Z * v.X - u.X * v.Z;
|
return u.Z * v.X - u.X * v.Z;
|
||||||
}
|
}
|
||||||
|
@ -236,7 +237,7 @@ namespace DotRecast.Core.Numerics
|
||||||
/// @return True if all of the point's components are finite, i.e. not NaN
|
/// @return True if all of the point's components are finite, i.e. not NaN
|
||||||
/// or any of the infinities.
|
/// or any of the infinities.
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool IsFinite(this RcVec3f v)
|
public static bool IsFinite(this Vector3 v)
|
||||||
{
|
{
|
||||||
return float.IsFinite(v.X) && float.IsFinite(v.Y) && float.IsFinite(v.Z);
|
return float.IsFinite(v.X) && float.IsFinite(v.Y) && float.IsFinite(v.Z);
|
||||||
}
|
}
|
||||||
|
@ -244,13 +245,13 @@ namespace DotRecast.Core.Numerics
|
||||||
/// Checks that the specified vector's 2D components are finite.
|
/// Checks that the specified vector's 2D components are finite.
|
||||||
/// @param[in] v A point. [(x, y, z)]
|
/// @param[in] v A point. [(x, y, z)]
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool IsFinite2D(this RcVec3f v)
|
public static bool IsFinite2D(this Vector3 v)
|
||||||
{
|
{
|
||||||
return float.IsFinite(v.X) && float.IsFinite(v.Z);
|
return float.IsFinite(v.X) && float.IsFinite(v.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float PerpXZ(RcVec3f a, RcVec3f b)
|
public static float PerpXZ(Vector3 a, Vector3 b)
|
||||||
{
|
{
|
||||||
return (a.X * b.Z) - (a.Z * b.X);
|
return (a.X * b.Z) - (a.Z * b.X);
|
||||||
}
|
}
|
||||||
|
@ -262,9 +263,9 @@ namespace DotRecast.Core.Numerics
|
||||||
/// @param[in] v2 The destination vector.
|
/// @param[in] v2 The destination vector.
|
||||||
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
|
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Lerp(float[] verts, int v1, int v2, float t)
|
public static Vector3 Lerp(float[] verts, int v1, int v2, float t)
|
||||||
{
|
{
|
||||||
return new RcVec3f(
|
return new Vector3(
|
||||||
verts[v1 + 0] + (verts[v2 + 0] - verts[v1 + 0]) * t,
|
verts[v1 + 0] + (verts[v2 + 0] - verts[v1 + 0]) * t,
|
||||||
verts[v1 + 1] + (verts[v2 + 1] - verts[v1 + 1]) * t,
|
verts[v1 + 1] + (verts[v2 + 1] - verts[v1 + 1]) * t,
|
||||||
verts[v1 + 2] + (verts[v2 + 2] - verts[v1 + 2]) * t
|
verts[v1 + 2] + (verts[v2 + 2] - verts[v1 + 2]) * t
|
||||||
|
@ -277,9 +278,9 @@ namespace DotRecast.Core.Numerics
|
||||||
/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
|
/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
|
||||||
/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
|
/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static RcVec3f Mad(RcVec3f v1, RcVec3f v2, float s)
|
public static Vector3 Mad(Vector3 v1, Vector3 v2, float s)
|
||||||
{
|
{
|
||||||
return new RcVec3f()
|
return new Vector3()
|
||||||
{
|
{
|
||||||
X = v1.X + (v2.X * s),
|
X = v1.X + (v2.X * s),
|
||||||
Y = v1.Y + (v2.Y * s),
|
Y = v1.Y + (v2.Y * s),
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DotRecast.Core
|
||||||
|
{
|
||||||
|
public struct RcAnonymousDisposable : IDisposable
|
||||||
|
{
|
||||||
|
private Action _dispose;
|
||||||
|
|
||||||
|
public RcAnonymousDisposable(Action dispose)
|
||||||
|
{
|
||||||
|
_dispose = dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_dispose?.Invoke();
|
||||||
|
_dispose = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
using System;
|
using System.Threading;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace DotRecast.Core
|
namespace DotRecast.Core
|
||||||
{
|
{
|
||||||
public class RcAtomicLong : IComparable<RcAtomicLong>
|
public class RcAtomicLong
|
||||||
{
|
{
|
||||||
private long _location;
|
private long _location;
|
||||||
|
|
||||||
|
@ -16,11 +15,6 @@ namespace DotRecast.Core
|
||||||
_location = location;
|
_location = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CompareTo(RcAtomicLong other)
|
|
||||||
{
|
|
||||||
return Read().CompareTo(other.Read());
|
|
||||||
}
|
|
||||||
|
|
||||||
public long IncrementAndGet()
|
public long IncrementAndGet()
|
||||||
{
|
{
|
||||||
return Interlocked.Increment(ref _location);
|
return Interlocked.Increment(ref _location);
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Core
|
namespace DotRecast.Core
|
||||||
{
|
{
|
||||||
|
@ -27,7 +28,7 @@ namespace DotRecast.Core
|
||||||
// Calculates convex hull on xz-plane of points on 'pts',
|
// Calculates convex hull on xz-plane of points on 'pts',
|
||||||
// stores the indices of the resulting hull in 'out' and
|
// stores the indices of the resulting hull in 'out' and
|
||||||
// returns number of points on hull.
|
// returns number of points on hull.
|
||||||
public static List<int> Convexhull(List<RcVec3f> pts)
|
public static List<int> Convexhull(List<Vector3> pts)
|
||||||
{
|
{
|
||||||
int npts = pts.Count;
|
int npts = pts.Count;
|
||||||
List<int> @out = new List<int>();
|
List<int> @out = new List<int>();
|
||||||
|
@ -49,9 +50,9 @@ namespace DotRecast.Core
|
||||||
endpt = 0;
|
endpt = 0;
|
||||||
for (int j = 1; j < npts; ++j)
|
for (int j = 1; j < npts; ++j)
|
||||||
{
|
{
|
||||||
RcVec3f a = pts[hull];
|
Vector3 a = pts[hull];
|
||||||
RcVec3f b = pts[endpt];
|
Vector3 b = pts[endpt];
|
||||||
RcVec3f c = pts[j];
|
Vector3 c = pts[j];
|
||||||
if (hull == endpt || Left(a, b, c))
|
if (hull == endpt || Left(a, b, c))
|
||||||
{
|
{
|
||||||
endpt = j;
|
endpt = j;
|
||||||
|
@ -65,7 +66,7 @@ namespace DotRecast.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if 'a' is more lower-left than 'b'.
|
// Returns true if 'a' is more lower-left than 'b'.
|
||||||
private static bool Cmppt(RcVec3f a, RcVec3f b)
|
private static bool Cmppt(Vector3 a, Vector3 b)
|
||||||
{
|
{
|
||||||
if (a.X < b.X)
|
if (a.X < b.X)
|
||||||
{
|
{
|
||||||
|
@ -91,7 +92,7 @@ namespace DotRecast.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if 'c' is left of line 'a'-'b'.
|
// Returns true if 'c' is left of line 'a'-'b'.
|
||||||
private static bool Left(RcVec3f a, RcVec3f b, RcVec3f c)
|
private static bool Left(Vector3 a, Vector3 b, Vector3 c)
|
||||||
{
|
{
|
||||||
float u1 = b.X - a.X;
|
float u1 = b.X - a.X;
|
||||||
float v1 = b.Z - a.Z;
|
float v1 = b.Z - a.Z;
|
||||||
|
|
|
@ -1,26 +1,10 @@
|
||||||
using System.Runtime.CompilerServices;
|
namespace DotRecast.Core
|
||||||
|
|
||||||
namespace DotRecast.Core
|
|
||||||
{
|
{
|
||||||
public static class RcHashCodes
|
public static class RcHashCodes
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static int CombineHashCodes(int h1, int h2)
|
public static int CombineHashCodes(int h1, int h2)
|
||||||
{
|
{
|
||||||
return (((h1 << 5) + h1) ^ h2);
|
return (((h1 << 5) + h1) ^ h2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// From Thomas Wang, https://gist.github.com/badboy/6267743
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static uint WangHash(uint a)
|
|
||||||
{
|
|
||||||
a = (~a) + (a << 18); // a = (a << 18) - a - 1;
|
|
||||||
a = a ^ (a >> 31);
|
|
||||||
a = a * 21; // a = (a + (a << 2)) + (a << 4);
|
|
||||||
a = a ^ (a >> 11);
|
|
||||||
a = a + (a << 6);
|
|
||||||
a = a ^ (a >> 22);
|
|
||||||
return (uint)a;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,26 +20,27 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Core
|
namespace DotRecast.Core
|
||||||
{
|
{
|
||||||
public static class RcIntersections
|
public static class RcIntersections
|
||||||
{
|
{
|
||||||
public static bool IntersectSegmentTriangle(RcVec3f sp, RcVec3f sq, RcVec3f a, RcVec3f b, RcVec3f c, out float t)
|
public static bool IntersectSegmentTriangle(Vector3 sp, Vector3 sq, Vector3 a, Vector3 b, Vector3 c, out float t)
|
||||||
{
|
{
|
||||||
t = 0;
|
t = 0;
|
||||||
float v, w;
|
float v, w;
|
||||||
RcVec3f ab = RcVec3f.Subtract(b, a);
|
Vector3 ab = Vector3.Subtract(b, a);
|
||||||
RcVec3f ac = RcVec3f.Subtract(c, a);
|
Vector3 ac = Vector3.Subtract(c, a);
|
||||||
RcVec3f qp = RcVec3f.Subtract(sp, sq);
|
Vector3 qp = Vector3.Subtract(sp, sq);
|
||||||
|
|
||||||
// Compute triangle normal. Can be precalculated or cached if
|
// Compute triangle normal. Can be precalculated or cached if
|
||||||
// intersecting multiple segments against the same triangle
|
// intersecting multiple segments against the same triangle
|
||||||
RcVec3f norm = RcVec3f.Cross(ab, ac);
|
Vector3 norm = Vector3.Cross(ab, ac);
|
||||||
|
|
||||||
// Compute denominator d. If d <= 0, segment is parallel to or points
|
// Compute denominator d. If d <= 0, segment is parallel to or points
|
||||||
// away from triangle, so exit early
|
// away from triangle, so exit early
|
||||||
float d = RcVec3f.Dot(qp, norm);
|
float d = Vector3.Dot(qp, norm);
|
||||||
if (d <= 0.0f)
|
if (d <= 0.0f)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -48,8 +49,8 @@ namespace DotRecast.Core
|
||||||
// Compute intersection t value of pq with plane of triangle. A ray
|
// Compute intersection t value of pq with plane of triangle. A ray
|
||||||
// intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
|
// intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
|
||||||
// dividing by d until intersection has been found to pierce triangle
|
// dividing by d until intersection has been found to pierce triangle
|
||||||
RcVec3f ap = RcVec3f.Subtract(sp, a);
|
Vector3 ap = Vector3.Subtract(sp, a);
|
||||||
t = RcVec3f.Dot(ap, norm);
|
t = Vector3.Dot(ap, norm);
|
||||||
if (t < 0.0f)
|
if (t < 0.0f)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -61,14 +62,14 @@ namespace DotRecast.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute barycentric coordinate components and test if within bounds
|
// Compute barycentric coordinate components and test if within bounds
|
||||||
RcVec3f e = RcVec3f.Cross(qp, ap);
|
Vector3 e = Vector3.Cross(qp, ap);
|
||||||
v = RcVec3f.Dot(ac, e);
|
v = Vector3.Dot(ac, e);
|
||||||
if (v < 0.0f || v > d)
|
if (v < 0.0f || v > d)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
w = -RcVec3f.Dot(ab, e);
|
w = -Vector3.Dot(ab, e);
|
||||||
if (w < 0.0f || v + w > d)
|
if (w < 0.0f || v + w > d)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -80,11 +81,11 @@ namespace DotRecast.Core
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsectSegAABB(RcVec3f sp, RcVec3f sq, RcVec3f amin, RcVec3f amax, out float tmin, out float tmax)
|
public static bool IsectSegAABB(Vector3 sp, Vector3 sq, Vector3 amin, Vector3 amax, out float tmin, out float tmax)
|
||||||
{
|
{
|
||||||
const float EPS = 1e-6f;
|
const float EPS = 1e-6f;
|
||||||
|
|
||||||
RcVec3f d = new RcVec3f();
|
Vector3 d = new Vector3();
|
||||||
d.X = sq.X - sp.X;
|
d.X = sq.X - sp.X;
|
||||||
d.Y = sq.Y - sp.Y;
|
d.Y = sq.Y - sp.Y;
|
||||||
d.Z = sq.Z - sp.Z;
|
d.Z = sq.Z - sp.Z;
|
||||||
|
|
|
@ -21,6 +21,7 @@ using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Core
|
namespace DotRecast.Core
|
||||||
{
|
{
|
||||||
|
@ -71,7 +72,7 @@ namespace DotRecast.Core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RcVec3f ReadVector3f(string line)
|
private static Vector3 ReadVector3f(string line)
|
||||||
{
|
{
|
||||||
string[] v = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
string[] v = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||||
if (v.Length < 4)
|
if (v.Length < 4)
|
||||||
|
@ -80,7 +81,7 @@ namespace DotRecast.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix - https://github.com/ikpil/DotRecast/issues/7
|
// fix - https://github.com/ikpil/DotRecast/issues/7
|
||||||
return new RcVec3f(
|
return new Vector3(
|
||||||
float.Parse(v[1], CultureInfo.InvariantCulture),
|
float.Parse(v[1], CultureInfo.InvariantCulture),
|
||||||
float.Parse(v[2], CultureInfo.InvariantCulture),
|
float.Parse(v[2], CultureInfo.InvariantCulture),
|
||||||
float.Parse(v[3], CultureInfo.InvariantCulture)
|
float.Parse(v[3], CultureInfo.InvariantCulture)
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace DotRecast.Core
|
|
||||||
{
|
|
||||||
public static class RcProcess
|
|
||||||
{
|
|
||||||
public static void OpenUrl(string url)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// OS에 따라 다른 명령 실행
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
||||||
{
|
|
||||||
var psi = new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true };
|
|
||||||
Process.Start(psi);
|
|
||||||
}
|
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|
||||||
{
|
|
||||||
Process.Start("open", url);
|
|
||||||
}
|
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
||||||
{
|
|
||||||
Process.Start("xdg-open", url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error opening web browser: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,10 +20,5 @@ namespace DotRecast.Core
|
||||||
{
|
{
|
||||||
return (float)_r.NextDouble();
|
return (float)_r.NextDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int NextInt32()
|
|
||||||
{
|
|
||||||
return _r.Next();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace DotRecast.Core
|
|
||||||
{
|
|
||||||
public readonly struct RcScopedTimer : IDisposable
|
|
||||||
{
|
|
||||||
private readonly RcContext _context;
|
|
||||||
private readonly RcTimerLabel _label;
|
|
||||||
|
|
||||||
internal RcScopedTimer(RcContext context, RcTimerLabel label)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
_label = label;
|
|
||||||
|
|
||||||
_context.StartTimer(_label);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_context.StopTimer(_label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +1,12 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Core
|
namespace DotRecast.Core
|
||||||
{
|
{
|
||||||
public struct RcSegmentVert
|
public struct RcSegmentVert
|
||||||
{
|
{
|
||||||
public RcVec3f vmin;
|
public Vector3 vmin;
|
||||||
public RcVec3f vmax;
|
public Vector3 vmax;
|
||||||
|
|
||||||
public RcSegmentVert(float v0, float v1, float v2, float v3, float v4, float v5)
|
public RcSegmentVert(float v0, float v1, float v2, float v3, float v4, float v5)
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,33 +25,21 @@ using System.Threading;
|
||||||
|
|
||||||
namespace DotRecast.Core
|
namespace DotRecast.Core
|
||||||
{
|
{
|
||||||
/// Provides an interface for optional logging and performance tracking of the Recast
|
public class RcTelemetry
|
||||||
/// build process.
|
|
||||||
///
|
|
||||||
/// This class does not provide logging or timer functionality on its
|
|
||||||
/// own. Both must be provided by a concrete implementation
|
|
||||||
/// by overriding the protected member functions. Also, this class does not
|
|
||||||
/// provide an interface for extracting log messages. (Only adding them.)
|
|
||||||
/// So concrete implementations must provide one.
|
|
||||||
///
|
|
||||||
/// If no logging or timers are required, just pass an instance of this
|
|
||||||
/// class through the Recast build process.
|
|
||||||
///
|
|
||||||
/// @ingroup recast
|
|
||||||
public class RcContext
|
|
||||||
{
|
{
|
||||||
private readonly ThreadLocal<Dictionary<string, RcAtomicLong>> _timerStart;
|
private readonly ThreadLocal<Dictionary<string, RcAtomicLong>> _timerStart;
|
||||||
private readonly ConcurrentDictionary<string, RcAtomicLong> _timerAccum;
|
private readonly ConcurrentDictionary<string, RcAtomicLong> _timerAccum;
|
||||||
|
|
||||||
public RcContext()
|
public RcTelemetry()
|
||||||
{
|
{
|
||||||
_timerStart = new ThreadLocal<Dictionary<string, RcAtomicLong>>(() => new Dictionary<string, RcAtomicLong>());
|
_timerStart = new ThreadLocal<Dictionary<string, RcAtomicLong>>(() => new Dictionary<string, RcAtomicLong>());
|
||||||
_timerAccum = new ConcurrentDictionary<string, RcAtomicLong>();
|
_timerAccum = new ConcurrentDictionary<string, RcAtomicLong>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcScopedTimer ScopedTimer(RcTimerLabel label)
|
public IDisposable ScopedTimer(RcTimerLabel label)
|
||||||
{
|
{
|
||||||
return new RcScopedTimer(this, label);
|
StartTimer(label);
|
||||||
|
return new RcAnonymousDisposable(() => StopTimer(label));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartTimer(RcTimerLabel label)
|
public void StartTimer(RcTimerLabel label)
|
|
@ -1,42 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using DotRecast.Core.Collections;
|
|
||||||
|
|
||||||
namespace DotRecast.Core
|
|
||||||
{
|
|
||||||
public static class RcThrowHelper
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static void ThrowExceptionIfIndexOutOfRange(int index, int size)
|
|
||||||
{
|
|
||||||
if (0 > index || index >= size)
|
|
||||||
{
|
|
||||||
throw new IndexOutOfRangeException($"Index {index} is out of range - size({size})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static void StackOverflow()
|
|
||||||
{
|
|
||||||
var array_128_512_1 = RcStackArray128<RcStackArray512<float>>.Empty; // 128 * 512 = 65536
|
|
||||||
var array_128_512_2 = RcStackArray128<RcStackArray512<float>>.Empty; // 128 * 512 = 65536
|
|
||||||
|
|
||||||
var array_32_512_1 = RcStackArray32<RcStackArray512<float>>.Empty; // 32 * 512 = 16384
|
|
||||||
|
|
||||||
var array_16_512_1 = RcStackArray16<RcStackArray512<float>>.Empty; // 16 * 512 = 8192
|
|
||||||
|
|
||||||
var array_8_512_1 = RcStackArray8<RcStackArray512<float>>.Empty; // 8 * 512 = 4196
|
|
||||||
var array_4_256_1 = RcStackArray4<RcStackArray256<float>>.Empty; // 4 * 256 = 1024
|
|
||||||
var array_4_64_1 = RcStackArray4<RcStackArray64<float>>.Empty; // 4 * 64 = 256
|
|
||||||
|
|
||||||
//
|
|
||||||
var array_2_8_1 = RcStackArray2<RcStackArray8<float>>.Empty; // 2 * 8 = 16
|
|
||||||
var array_2_4_1 = RcStackArray2<RcStackArray2<float>>.Empty; // 2 * 2 = 4
|
|
||||||
|
|
||||||
float f1 = 0.0f; // 1
|
|
||||||
//float f2 = 0.0f; // my system stack overflow!
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,12 +5,11 @@
|
||||||
<PackageId>DotRecast.Detour.Crowd</PackageId>
|
<PackageId>DotRecast.Detour.Crowd</PackageId>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Authors>ikpil</Authors>
|
<Authors>ikpil</Authors>
|
||||||
<Description>DotRecast - a port of Recast Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers</Description>
|
<Description>DotRecast - a port of Recast Detour, navigation mesh toolset for games, Unity3D, servers, C#</Description>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
||||||
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
||||||
<PackageReleaseNotes>https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md</PackageReleaseNotes>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -20,155 +20,164 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Collections;
|
using DotRecast.Core.Collections;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// This section contains detailed documentation for members that don't have
|
|
||||||
// a source file. It reduces clutter in the main section of the header.
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Members in this module implement local steering and dynamic avoidance features.
|
||||||
@defgroup crowd Crowd
|
*
|
||||||
|
* The crowd is the big beast of the navigation features. It not only handles a lot of the path management for you, but
|
||||||
Members in this module implement local steering and dynamic avoidance features.
|
* also local steering and dynamic avoidance between members of the crowd. I.e. It can keep your agents from running
|
||||||
|
* into each other.
|
||||||
The crowd is the big beast of the navigation features. It not only handles a
|
*
|
||||||
lot of the path management for you, but also local steering and dynamic
|
* Main class: Crowd
|
||||||
avoidance between members of the crowd. I.e. It can keep your agents from
|
*
|
||||||
running into each other.
|
* The #dtNavMeshQuery and #dtPathCorridor classes provide perfectly good, easy to use path planning features. But in
|
||||||
|
* the end they only give you points that your navigation client should be moving toward. When it comes to deciding
|
||||||
Main class: #dtCrowd
|
* things like agent velocity and steering to avoid other agents, that is up to you to implement. Unless, of course, you
|
||||||
|
* decide to use Crowd.
|
||||||
The #dtNavMeshQuery and #dtPathCorridor classes provide perfectly good, easy
|
*
|
||||||
to use path planning features. But in the end they only give you points that
|
* Basically, you add an agent to the crowd, providing various configuration settings such as maximum speed and
|
||||||
your navigation client should be moving toward. When it comes to deciding things
|
* acceleration. You also provide a local target to move toward. The crowd manager then provides, with every update, the
|
||||||
like agent velocity and steering to avoid other agents, that is up to you to
|
* new agent position and velocity for the frame. The movement will be constrained to the navigation mesh, and steering
|
||||||
implement. Unless, of course, you decide to use #dtCrowd.
|
* will be applied to ensure agents managed by the crowd do not collide with each other.
|
||||||
|
*
|
||||||
Basically, you add an agent to the crowd, providing various configuration
|
* This is very powerful feature set. But it comes with limitations.
|
||||||
settings such as maximum speed and acceleration. You also provide a local
|
*
|
||||||
target to more toward. The crowd manager then provides, with every update, the
|
* The biggest limitation is that you must give control of the agent's position completely over to the crowd manager.
|
||||||
new agent position and velocity for the frame. The movement will be
|
* You can update things like maximum speed and acceleration. But in order for the crowd manager to do its thing, it
|
||||||
constrained to the navigation mesh, and steering will be applied to ensure
|
* can't allow you to constantly be giving it overrides to position and velocity. So you give up direct control of the
|
||||||
agents managed by the crowd do not collide with each other.
|
* agent's movement. It belongs to the crowd.
|
||||||
|
*
|
||||||
This is very powerful feature set. But it comes with limitations.
|
* The second biggest limitation revolves around the fact that the crowd manager deals with local planning. So the
|
||||||
|
* agent's target should never be more than 256 polygons away from its current position. If it is, you risk your agent
|
||||||
The biggest limitation is that you must give control of the agent's position
|
* failing to reach its target. So you may still need to do long distance planning and provide the crowd manager with
|
||||||
completely over to the crowd manager. You can update things like maximum speed
|
* intermediate targets.
|
||||||
and acceleration. But in order for the crowd manager to do its thing, it can't
|
*
|
||||||
allow you to constantly be giving it overrides to position and velocity. So
|
* Other significant limitations:
|
||||||
you give up direct control of the agent's movement. It belongs to the crowd.
|
*
|
||||||
|
* - All agents using the crowd manager will use the same #dtQueryFilter. - Crowd management is relatively expensive.
|
||||||
The second biggest limitation revolves around the fact that the crowd manager
|
* The maximum agents under crowd management at any one time is between 20 and 30. A good place to start is a maximum of
|
||||||
deals with local planning. So the agent's target should never be more than
|
* 25 agents for 0.5ms per frame.
|
||||||
256 polygons aways from its current position. If it is, you risk
|
*
|
||||||
your agent failing to reach its target. So you may still need to do long
|
* @note This is a summary list of members. Use the index or search feature to find minor members.
|
||||||
distance planning and provide the crowd manager with intermediate targets.
|
*
|
||||||
|
* @struct dtCrowdAgentParams
|
||||||
Other significant limitations:
|
* @see CrowdAgent, Crowd::AddAgent(), Crowd::UpdateAgentParameters()
|
||||||
|
*
|
||||||
- All agents using the crowd manager will use the same #dtQueryFilter.
|
* @var dtCrowdAgentParams::obstacleAvoidanceType
|
||||||
- Crowd management is relatively expensive. The maximum agents under crowd
|
* @par
|
||||||
management at any one time is between 20 and 30. A good place to start
|
*
|
||||||
is a maximum of 25 agents for 0.5ms per frame.
|
* #dtCrowd permits agents to use different avoidance configurations. This value is the index of the
|
||||||
|
* #dtObstacleAvoidanceParams within the crowd.
|
||||||
@note This is a summary list of members. Use the index or search
|
*
|
||||||
feature to find minor members.
|
* @see dtObstacleAvoidanceParams, dtCrowd::SetObstacleAvoidanceParams(), dtCrowd::GetObstacleAvoidanceParams()
|
||||||
|
*
|
||||||
@struct dtCrowdAgentParams
|
* @var dtCrowdAgentParams::collisionQueryRange
|
||||||
@see dtCrowdAgent, dtCrowd::addAgent(), dtCrowd::updateAgentParameters()
|
* @par
|
||||||
|
*
|
||||||
@var dtCrowdAgentParams::obstacleAvoidanceType
|
* Collision elements include other agents and navigation mesh boundaries.
|
||||||
@par
|
*
|
||||||
|
* This value is often based on the agent radius and/or maximum speed. E.g. radius * 8
|
||||||
#dtCrowd permits agents to use different avoidance configurations. This value
|
*
|
||||||
is the index of the #dtObstacleAvoidanceParams within the crowd.
|
* @var dtCrowdAgentParams::pathOptimizationRange
|
||||||
|
* @par
|
||||||
@see dtObstacleAvoidanceParams, dtCrowd::setObstacleAvoidanceParams(),
|
*
|
||||||
dtCrowd::getObstacleAvoidanceParams()
|
* Only applicable if #updateFlags includes the #DT_CROWD_OPTIMIZE_VIS flag.
|
||||||
|
*
|
||||||
@var dtCrowdAgentParams::collisionQueryRange
|
* This value is often based on the agent radius. E.g. radius * 30
|
||||||
@par
|
*
|
||||||
|
* @see dtPathCorridor::OptimizePathVisibility()
|
||||||
Collision elements include other agents and navigation mesh boundaries.
|
*
|
||||||
|
* @var dtCrowdAgentParams::separationWeight
|
||||||
This value is often based on the agent radius and/or maximum speed. E.g. radius * 8
|
* @par
|
||||||
|
*
|
||||||
@var dtCrowdAgentParams::pathOptimizationRange
|
* A higher value will result in agents trying to stay farther away from each other at the cost of more difficult
|
||||||
@par
|
* steering in tight spaces.
|
||||||
|
*
|
||||||
Only applicable if #updateFlags includes the #DT_CROWD_OPTIMIZE_VIS flag.
|
*/
|
||||||
|
/**
|
||||||
This value is often based on the agent radius. E.g. radius * 30
|
* This is the core class of the refs crowd module. See the refs crowd documentation for a summary of the crowd
|
||||||
|
* features. A common method for setting up the crowd is as follows: -# Allocate the crowd -# Set the avoidance
|
||||||
@see dtPathCorridor::optimizePathVisibility()
|
* configurations using #SetObstacleAvoidanceParams(). -# Add agents using #AddAgent() and make an initial movement
|
||||||
|
* request using #RequestMoveTarget(). A common process for managing the crowd is as follows: -# Call #Update() to allow
|
||||||
@var dtCrowdAgentParams::separationWeight
|
* the crowd to manage its agents. -# Retrieve agent information using #GetActiveAgents(). -# Make movement requests
|
||||||
@par
|
* using #RequestMoveTarget() when movement goal changes. -# Repeat every frame. Some agent configuration settings can
|
||||||
|
* be updated using #UpdateAgentParameters(). But the crowd owns the agent position. So it is not possible to update an
|
||||||
A higher value will result in agents trying to stay farther away from each other at
|
* active agent's position. If agent position must be fed back into the crowd, the agent must be removed and re-added.
|
||||||
the cost of more difficult steering in tight spaces.
|
* Notes: - Path related information is available for newly added agents only after an #Update() has been performed. -
|
||||||
*/
|
* Agent objects are kept in a pool and re-used. So it is important when using agent objects to check the value of
|
||||||
/// Provides local steering behaviors for a group of agents.
|
* #dtCrowdAgent::active to determine if the agent is actually in use or not. - This class is meant to provide 'local'
|
||||||
/// @ingroup crowd
|
* movement. There is a limit of 256 polygons in the path corridor. So it is not meant to provide automatic pathfinding
|
||||||
|
* services over long distances.
|
||||||
|
*
|
||||||
|
* @see DtAllocCrowd(), DtFreeCrowd(), Init(), dtCrowdAgent
|
||||||
|
*/
|
||||||
public class DtCrowd
|
public class DtCrowd
|
||||||
{
|
{
|
||||||
|
/// The maximum number of corners a crowd agent will look ahead in the path.
|
||||||
|
/// This value is used for sizing the crowd agent corner buffers.
|
||||||
|
/// Due to the behavior of the crowd manager, the actual number of useful
|
||||||
|
/// corners will be one less than this number.
|
||||||
|
/// @ingroup crowd
|
||||||
|
public const int DT_CROWDAGENT_MAX_CORNERS = 4;
|
||||||
|
|
||||||
|
/// The maximum number of crowd avoidance configurations supported by the
|
||||||
|
/// crowd manager.
|
||||||
|
/// @ingroup crowd
|
||||||
|
/// @see dtObstacleAvoidanceParams, dtCrowd::SetObstacleAvoidanceParams(), dtCrowd::GetObstacleAvoidanceParams(),
|
||||||
|
/// dtCrowdAgentParams::obstacleAvoidanceType
|
||||||
|
public const int DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS = 8;
|
||||||
|
|
||||||
|
/// The maximum number of query filter types supported by the crowd manager.
|
||||||
|
/// @ingroup crowd
|
||||||
|
/// @see dtQueryFilter, dtCrowd::GetFilter() dtCrowd::GetEditableFilter(),
|
||||||
|
/// dtCrowdAgentParams::queryFilterType
|
||||||
|
public const int DT_CROWD_MAX_QUERY_FILTER_TYPE = 16;
|
||||||
|
|
||||||
private readonly RcAtomicInteger _agentId = new RcAtomicInteger();
|
private readonly RcAtomicInteger _agentId = new RcAtomicInteger();
|
||||||
private readonly List<DtCrowdAgent> _agents;
|
private readonly List<DtCrowdAgent> _agents;
|
||||||
|
|
||||||
private readonly DtPathQueue _pathQ;
|
private readonly DtPathQueue _pathQ;
|
||||||
|
private readonly DtObstacleAvoidanceParams[] _obstacleQueryParams = new DtObstacleAvoidanceParams[DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS];
|
||||||
private readonly DtObstacleAvoidanceParams[] _obstacleQueryParams;
|
|
||||||
private readonly DtObstacleAvoidanceQuery _obstacleQuery;
|
private readonly DtObstacleAvoidanceQuery _obstacleQuery;
|
||||||
|
|
||||||
private DtProximityGrid _grid;
|
private DtProximityGrid _grid;
|
||||||
|
private readonly Vector3 _ext = new Vector3();
|
||||||
private int _maxPathResult;
|
private readonly IDtQueryFilter[] _filters = new IDtQueryFilter[DT_CROWD_MAX_QUERY_FILTER_TYPE];
|
||||||
private readonly RcVec3f _agentPlacementHalfExtents;
|
private DtNavMeshQuery _navQuery;
|
||||||
|
private DtNavMesh _navMesh;
|
||||||
private readonly IDtQueryFilter[] _filters;
|
|
||||||
|
|
||||||
private readonly DtCrowdConfig _config;
|
private readonly DtCrowdConfig _config;
|
||||||
|
private readonly DtCrowdTelemetry _telemetry = new DtCrowdTelemetry();
|
||||||
private int _velocitySampleCount;
|
private int _velocitySampleCount;
|
||||||
|
|
||||||
private DtNavMeshQuery _navQuery;
|
public DtCrowd(DtCrowdConfig config, DtNavMesh nav) :
|
||||||
|
this(config, nav, i => new DtQueryDefaultFilter())
|
||||||
private DtNavMesh _navMesh;
|
|
||||||
private readonly DtCrowdTelemetry _telemetry = new DtCrowdTelemetry();
|
|
||||||
|
|
||||||
public DtCrowd(DtCrowdConfig config, DtNavMesh nav) : this(config, nav, i => new DtQueryDefaultFilter())
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtCrowd(DtCrowdConfig config, DtNavMesh nav, Func<int, IDtQueryFilter> queryFilterFactory)
|
public DtCrowd(DtCrowdConfig config, DtNavMesh nav, Func<int, IDtQueryFilter> queryFilterFactory)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_agentPlacementHalfExtents = new RcVec3f(config.maxAgentRadius * 2.0f, config.maxAgentRadius * 1.5f, config.maxAgentRadius * 2.0f);
|
_ext = new Vector3(config.maxAgentRadius * 2.0f, config.maxAgentRadius * 1.5f, config.maxAgentRadius * 2.0f);
|
||||||
|
|
||||||
_obstacleQuery = new DtObstacleAvoidanceQuery(config.maxObstacleAvoidanceCircles, config.maxObstacleAvoidanceSegments);
|
_obstacleQuery = new DtObstacleAvoidanceQuery(config.maxObstacleAvoidanceCircles, config.maxObstacleAvoidanceSegments);
|
||||||
|
|
||||||
_filters = new IDtQueryFilter[DtCrowdConst.DT_CROWD_MAX_QUERY_FILTER_TYPE];
|
for (int i = 0; i < DT_CROWD_MAX_QUERY_FILTER_TYPE; i++)
|
||||||
for (int i = 0; i < DtCrowdConst.DT_CROWD_MAX_QUERY_FILTER_TYPE; i++)
|
|
||||||
{
|
{
|
||||||
_filters[i] = queryFilterFactory.Invoke(i);
|
_filters[i] = queryFilterFactory.Invoke(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init obstacle query option.
|
// Init obstacle query option.
|
||||||
_obstacleQueryParams = new DtObstacleAvoidanceParams[DtCrowdConst.DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS];
|
for (int i = 0; i < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS; ++i)
|
||||||
for (int i = 0; i < DtCrowdConst.DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS; ++i)
|
|
||||||
{
|
{
|
||||||
_obstacleQueryParams[i] = new DtObstacleAvoidanceParams();
|
_obstacleQueryParams[i] = new DtObstacleAvoidanceParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate temp buffer for merging paths.
|
// Allocate temp buffer for merging paths.
|
||||||
_maxPathResult = DtCrowdConst.MAX_PATH_RESULT;
|
|
||||||
_pathQ = new DtPathQueue(config);
|
_pathQ = new DtPathQueue(config);
|
||||||
_agents = new List<DtCrowdAgent>();
|
_agents = new List<DtCrowdAgent>();
|
||||||
|
|
||||||
|
@ -198,7 +207,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
/// @param[in] option The new configuration.
|
/// @param[in] option The new configuration.
|
||||||
public void SetObstacleAvoidanceParams(int idx, DtObstacleAvoidanceParams option)
|
public void SetObstacleAvoidanceParams(int idx, DtObstacleAvoidanceParams option)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx < DtCrowdConst.DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS)
|
if (idx >= 0 && idx < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS)
|
||||||
{
|
{
|
||||||
_obstacleQueryParams[idx] = new DtObstacleAvoidanceParams(option);
|
_obstacleQueryParams[idx] = new DtObstacleAvoidanceParams(option);
|
||||||
}
|
}
|
||||||
|
@ -210,7 +219,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
/// @return The requested configuration.
|
/// @return The requested configuration.
|
||||||
public DtObstacleAvoidanceParams GetObstacleAvoidanceParams(int idx)
|
public DtObstacleAvoidanceParams GetObstacleAvoidanceParams(int idx)
|
||||||
{
|
{
|
||||||
if (idx >= 0 && idx < DtCrowdConst.DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS)
|
if (idx >= 0 && idx < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS)
|
||||||
{
|
{
|
||||||
return _obstacleQueryParams[idx];
|
return _obstacleQueryParams[idx];
|
||||||
}
|
}
|
||||||
|
@ -226,24 +235,23 @@ namespace DotRecast.Detour.Crowd
|
||||||
agent.option = option;
|
agent.option = option;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @par
|
/**
|
||||||
///
|
* Adds a new agent to the crowd.
|
||||||
/// The agent's position will be constrained to the surface of the navigation mesh.
|
*
|
||||||
/// Adds a new agent to the crowd.
|
* @param pos
|
||||||
/// @param[in] pos The requested position of the agent. [(x, y, z)]
|
* The requested position of the agent. [(x, y, z)]
|
||||||
/// @param[in] params The configuration of the agent.
|
* @param params
|
||||||
/// @return The index of the agent in the agent pool. Or -1 if the agent could not be added.
|
* The configuration of the agent.
|
||||||
public DtCrowdAgent AddAgent(RcVec3f pos, DtCrowdAgentParams option)
|
* @return The newly created agent object
|
||||||
|
*/
|
||||||
|
public DtCrowdAgent AddAgent(Vector3 pos, DtCrowdAgentParams option)
|
||||||
{
|
{
|
||||||
int idx = _agentId.GetAndIncrement();
|
DtCrowdAgent ag = new DtCrowdAgent(_agentId.GetAndIncrement());
|
||||||
DtCrowdAgent ag = new DtCrowdAgent(idx);
|
|
||||||
ag.corridor.Init(_maxPathResult);
|
|
||||||
_agents.Add(ag);
|
_agents.Add(ag);
|
||||||
|
|
||||||
UpdateAgentParameters(ag, option);
|
UpdateAgentParameters(ag, option);
|
||||||
|
|
||||||
// Find nearest position on navmesh and place the agent there.
|
// Find nearest position on navmesh and place the agent there.
|
||||||
var status = _navQuery.FindNearestPoly(pos, _agentPlacementHalfExtents, _filters[ag.option.queryFilterType], out var refs, out var nearestPt, out var _);
|
var status = _navQuery.FindNearestPoly(pos, _ext, _filters[ag.option.queryFilterType], out var refs, out var nearestPt, out var _);
|
||||||
if (status.Failed())
|
if (status.Failed())
|
||||||
{
|
{
|
||||||
nearestPt = pos;
|
nearestPt = pos;
|
||||||
|
@ -257,9 +265,9 @@ namespace DotRecast.Detour.Crowd
|
||||||
ag.topologyOptTime = 0;
|
ag.topologyOptTime = 0;
|
||||||
ag.targetReplanTime = 0;
|
ag.targetReplanTime = 0;
|
||||||
|
|
||||||
ag.dvel = RcVec3f.Zero;
|
ag.dvel = Vector3.Zero;
|
||||||
ag.nvel = RcVec3f.Zero;
|
ag.nvel = Vector3.Zero;
|
||||||
ag.vel = RcVec3f.Zero;
|
ag.vel = Vector3.Zero;
|
||||||
ag.npos = nearestPt;
|
ag.npos = nearestPt;
|
||||||
|
|
||||||
ag.desiredSpeed = 0;
|
ag.desiredSpeed = 0;
|
||||||
|
@ -289,7 +297,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
_agents.Remove(agent);
|
_agents.Remove(agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool RequestMoveTargetReplan(DtCrowdAgent ag, long refs, RcVec3f pos)
|
private bool RequestMoveTargetReplan(DtCrowdAgent ag, long refs, Vector3 pos)
|
||||||
{
|
{
|
||||||
ag.SetTarget(refs, pos);
|
ag.SetTarget(refs, pos);
|
||||||
ag.targetReplan = true;
|
ag.targetReplan = true;
|
||||||
|
@ -307,7 +315,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
/// The position will be constrained to the surface of the navigation mesh.
|
/// The position will be constrained to the surface of the navigation mesh.
|
||||||
///
|
///
|
||||||
/// The request will be processed during the next #Update().
|
/// The request will be processed during the next #Update().
|
||||||
public bool RequestMoveTarget(DtCrowdAgent agent, long refs, RcVec3f pos)
|
public bool RequestMoveTarget(DtCrowdAgent agent, long refs, Vector3 pos)
|
||||||
{
|
{
|
||||||
if (refs == 0)
|
if (refs == 0)
|
||||||
{
|
{
|
||||||
|
@ -324,7 +332,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
/// @param[in] idx The agent index. [Limits: 0 <= value < #GetAgentCount()]
|
/// @param[in] idx The agent index. [Limits: 0 <= value < #GetAgentCount()]
|
||||||
/// @param[in] vel The movement velocity. [(x, y, z)]
|
/// @param[in] vel The movement velocity. [(x, y, z)]
|
||||||
/// @return True if the request was successfully submitted.
|
/// @return True if the request was successfully submitted.
|
||||||
public bool RequestMoveVelocity(DtCrowdAgent agent, RcVec3f vel)
|
public bool RequestMoveVelocity(DtCrowdAgent agent, Vector3 vel)
|
||||||
{
|
{
|
||||||
// Initialize request.
|
// Initialize request.
|
||||||
agent.targetRef = 0;
|
agent.targetRef = 0;
|
||||||
|
@ -343,8 +351,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
// Initialize request.
|
// Initialize request.
|
||||||
agent.targetRef = 0;
|
agent.targetRef = 0;
|
||||||
agent.targetPos = RcVec3f.Zero;
|
agent.targetPos = Vector3.Zero;
|
||||||
agent.dvel = RcVec3f.Zero;
|
agent.dvel = Vector3.Zero;
|
||||||
agent.targetPathQueryResult = null;
|
agent.targetPathQueryResult = null;
|
||||||
agent.targetReplan = false;
|
agent.targetReplan = false;
|
||||||
agent.targetState = DtMoveRequestState.DT_CROWDAGENT_TARGET_NONE;
|
agent.targetState = DtMoveRequestState.DT_CROWDAGENT_TARGET_NONE;
|
||||||
|
@ -361,14 +369,14 @@ namespace DotRecast.Detour.Crowd
|
||||||
return _agents;
|
return _agents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f GetQueryExtents()
|
public Vector3 GetQueryExtents()
|
||||||
{
|
{
|
||||||
return _agentPlacementHalfExtents;
|
return _ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDtQueryFilter GetFilter(int i)
|
public IDtQueryFilter GetFilter(int i)
|
||||||
{
|
{
|
||||||
return i >= 0 && i < DtCrowdConst.DT_CROWD_MAX_QUERY_FILTER_TYPE ? _filters[i] : null;
|
return i >= 0 && i < DT_CROWD_MAX_QUERY_FILTER_TYPE ? _filters[i] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtProximityGrid GetGrid()
|
public DtProximityGrid GetGrid()
|
||||||
|
@ -444,9 +452,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.CheckPathValidity);
|
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.CheckPathValidity);
|
||||||
|
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -457,14 +464,14 @@ namespace DotRecast.Detour.Crowd
|
||||||
bool replan = false;
|
bool replan = false;
|
||||||
|
|
||||||
// First check that the current location is valid.
|
// First check that the current location is valid.
|
||||||
RcVec3f agentPos = new RcVec3f();
|
Vector3 agentPos = new Vector3();
|
||||||
long agentRef = ag.corridor.GetFirstPoly();
|
long agentRef = ag.corridor.GetFirstPoly();
|
||||||
agentPos = ag.npos;
|
agentPos = ag.npos;
|
||||||
if (!_navQuery.IsValidPolyRef(agentRef, _filters[ag.option.queryFilterType]))
|
if (!_navQuery.IsValidPolyRef(agentRef, _filters[ag.option.queryFilterType]))
|
||||||
{
|
{
|
||||||
// Current location is not valid, try to reposition.
|
// Current location is not valid, try to reposition.
|
||||||
// TODO: this can snap agents, how to handle that?
|
// TODO: this can snap agents, how to handle that?
|
||||||
_navQuery.FindNearestPoly(ag.npos, _agentPlacementHalfExtents, _filters[ag.option.queryFilterType], out agentRef, out var nearestPt, out var _);
|
_navQuery.FindNearestPoly(ag.npos, _ext, _filters[ag.option.queryFilterType], out agentRef, out var nearestPt, out var _);
|
||||||
agentPos = nearestPt;
|
agentPos = nearestPt;
|
||||||
|
|
||||||
if (agentRef == 0)
|
if (agentRef == 0)
|
||||||
|
@ -504,7 +511,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
if (!_navQuery.IsValidPolyRef(ag.targetRef, _filters[ag.option.queryFilterType]))
|
if (!_navQuery.IsValidPolyRef(ag.targetRef, _filters[ag.option.queryFilterType]))
|
||||||
{
|
{
|
||||||
// Current target is not valid, try to reposition.
|
// Current target is not valid, try to reposition.
|
||||||
_navQuery.FindNearestPoly(ag.targetPos, _agentPlacementHalfExtents, _filters[ag.option.queryFilterType], out ag.targetRef, out var nearestPt, out var _);
|
_navQuery.FindNearestPoly(ag.targetPos, _ext, _filters[ag.option.queryFilterType], out ag.targetRef, out var nearestPt, out var _);
|
||||||
ag.targetPos = nearestPt;
|
ag.targetPos = nearestPt;
|
||||||
replan = true;
|
replan = true;
|
||||||
}
|
}
|
||||||
|
@ -528,7 +535,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
replan = true;
|
replan = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the end of the path is near and it is not the requested location, replan.
|
// If the end of the path is near and it is not the requested
|
||||||
|
// location, replan.
|
||||||
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VALID)
|
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VALID)
|
||||||
{
|
{
|
||||||
if (ag.targetReplanTime > _config.targetReplanDelay && ag.corridor.GetPathCount() < _config.checkLookAhead
|
if (ag.targetReplanTime > _config.targetReplanDelay && ag.corridor.GetPathCount() < _config.checkLookAhead
|
||||||
|
@ -557,9 +565,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
|
|
||||||
// Fire off new requests.
|
// Fire off new requests.
|
||||||
List<long> reqPath = new List<long>();
|
List<long> reqPath = new List<long>();
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state == DtCrowdAgentState.DT_CROWDAGENT_STATE_INVALID)
|
if (ag.state == DtCrowdAgentState.DT_CROWDAGENT_STATE_INVALID)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -597,7 +604,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
status = _navQuery.FinalizeSlicedFindPath(ref reqPath);
|
status = _navQuery.FinalizeSlicedFindPath(ref reqPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f reqPos = new RcVec3f();
|
Vector3 reqPos = new Vector3();
|
||||||
if (status.Succeeded() && reqPath.Count > 0)
|
if (status.Succeeded() && reqPath.Count > 0)
|
||||||
{
|
{
|
||||||
// In progress or succeed.
|
// In progress or succeed.
|
||||||
|
@ -671,9 +678,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process path results.
|
// Process path results.
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_NONE
|
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_NONE
|
||||||
|| ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
|
|| ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
|
||||||
{
|
{
|
||||||
|
@ -811,9 +817,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
|
|
||||||
RcSortedQueue<DtCrowdAgent> queue = new RcSortedQueue<DtCrowdAgent>((a1, a2) => a2.topologyOptTime.CompareTo(a1.topologyOptTime));
|
RcSortedQueue<DtCrowdAgent> queue = new RcSortedQueue<DtCrowdAgent>((a1, a2) => a2.topologyOptTime.CompareTo(a1.topologyOptTime));
|
||||||
|
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -851,10 +856,9 @@ namespace DotRecast.Detour.Crowd
|
||||||
|
|
||||||
_grid = new DtProximityGrid(_config.maxAgentRadius * 3);
|
_grid = new DtProximityGrid(_config.maxAgentRadius * 3);
|
||||||
|
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
Vector3 p = ag.npos;
|
||||||
RcVec3f p = ag.npos;
|
|
||||||
float r = ag.option.radius;
|
float r = ag.option.radius;
|
||||||
_grid.AddItem(ag, p.X - r, p.Z - r, p.X + r, p.Z + r);
|
_grid.AddItem(ag, p.X - r, p.Z - r, p.X + r, p.Z + r);
|
||||||
}
|
}
|
||||||
|
@ -864,9 +868,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.BuildNeighbours);
|
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.BuildNeighbours);
|
||||||
|
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -888,23 +891,21 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private int GetNeighbours(RcVec3f pos, float height, float range, DtCrowdAgent skip, ref List<DtCrowdNeighbour> result, DtProximityGrid grid)
|
private int GetNeighbours(Vector3 pos, float height, float range, DtCrowdAgent skip, ref List<DtCrowdNeighbour> result, DtProximityGrid grid)
|
||||||
{
|
{
|
||||||
result.Clear();
|
result.Clear();
|
||||||
|
|
||||||
int MAX_NEIS = 32;
|
var proxAgents = new HashSet<DtCrowdAgent>();
|
||||||
var ids = new DtCrowdAgent[MAX_NEIS];
|
int nids = grid.QueryItems(pos.X - range, pos.Z - range, pos.X + range, pos.Z + range, ref proxAgents);
|
||||||
int nids = grid.QueryItems(pos.X - range, pos.Z - range, pos.X + range, pos.Z + range, ids, ids.Length);
|
foreach (DtCrowdAgent ag in proxAgents)
|
||||||
for (int i = 0; i < nids; ++i)
|
|
||||||
{
|
{
|
||||||
var ag = ids[i];
|
|
||||||
if (ag == skip)
|
if (ag == skip)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for overlap.
|
// Check for overlap.
|
||||||
RcVec3f diff = RcVec3f.Subtract(pos, ag.npos);
|
Vector3 diff = Vector3.Subtract(pos, ag.npos);
|
||||||
if (MathF.Abs(diff.Y) >= (height + ag.option.height) / 2.0f)
|
if (MathF.Abs(diff.Y) >= (height + ag.option.height) / 2.0f)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -929,9 +930,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.FindCorners);
|
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.FindCorners);
|
||||||
|
|
||||||
DtCrowdAgent debugAgent = debug != null ? debug.agent : null;
|
DtCrowdAgent debugAgent = debug != null ? debug.agent : null;
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -944,13 +944,13 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find corners for steering
|
// Find corners for steering
|
||||||
ag.corridor.FindCorners(ref ag.corners, DtCrowdConst.DT_CROWDAGENT_MAX_CORNERS, _navQuery, _filters[ag.option.queryFilterType]);
|
ag.corridor.FindCorners(ref ag.corners, DT_CROWDAGENT_MAX_CORNERS, _navQuery, _filters[ag.option.queryFilterType]);
|
||||||
|
|
||||||
// Check to see if the corner after the next corner is directly visible,
|
// Check to see if the corner after the next corner is directly visible,
|
||||||
// and short cut to there.
|
// 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.corners.Count > 0)
|
||||||
{
|
{
|
||||||
RcVec3f target = ag.corners[Math.Min(1, ag.corners.Count - 1)].pos;
|
Vector3 target = ag.corners[Math.Min(1, ag.corners.Count - 1)].pos;
|
||||||
ag.corridor.OptimizePathVisibility(target, ag.option.pathOptimizationRange, _navQuery,
|
ag.corridor.OptimizePathVisibility(target, ag.option.pathOptimizationRange, _navQuery,
|
||||||
_filters[ag.option.queryFilterType]);
|
_filters[ag.option.queryFilterType]);
|
||||||
|
|
||||||
|
@ -966,8 +966,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
// Copy data for debug purposes.
|
// Copy data for debug purposes.
|
||||||
if (debugAgent == ag)
|
if (debugAgent == ag)
|
||||||
{
|
{
|
||||||
debug.optStart = RcVec3f.Zero;
|
debug.optStart = Vector3.Zero;
|
||||||
debug.optEnd = RcVec3f.Zero;
|
debug.optEnd = Vector3.Zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -977,9 +977,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.TriggerOffMeshConnections);
|
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.TriggerOffMeshConnections);
|
||||||
|
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -1026,9 +1025,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.CalculateSteering);
|
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.CalculateSteering);
|
||||||
|
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -1039,7 +1037,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f dvel = new RcVec3f();
|
Vector3 dvel = new Vector3();
|
||||||
|
|
||||||
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
|
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
|
||||||
{
|
{
|
||||||
|
@ -1074,13 +1072,13 @@ namespace DotRecast.Detour.Crowd
|
||||||
float separationWeight = ag.option.separationWeight;
|
float separationWeight = ag.option.separationWeight;
|
||||||
|
|
||||||
float w = 0;
|
float w = 0;
|
||||||
RcVec3f disp = new RcVec3f();
|
Vector3 disp = new Vector3();
|
||||||
|
|
||||||
for (int j = 0; j < ag.neis.Count; ++j)
|
for (int j = 0; j < ag.neis.Count; ++j)
|
||||||
{
|
{
|
||||||
DtCrowdAgent nei = ag.neis[j].agent;
|
DtCrowdAgent nei = ag.neis[j].agent;
|
||||||
|
|
||||||
RcVec3f diff = RcVec3f.Subtract(ag.npos, nei.npos);
|
Vector3 diff = Vector3.Subtract(ag.npos, nei.npos);
|
||||||
diff.Y = 0;
|
diff.Y = 0;
|
||||||
|
|
||||||
float distSqr = diff.LengthSquared();
|
float distSqr = diff.LengthSquared();
|
||||||
|
@ -1125,9 +1123,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.PlanVelocity);
|
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.PlanVelocity);
|
||||||
|
|
||||||
DtCrowdAgent debugAgent = debug != null ? debug.agent : null;
|
DtCrowdAgent debugAgent = debug != null ? debug.agent : null;
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -1147,9 +1144,9 @@ namespace DotRecast.Detour.Crowd
|
||||||
// Append neighbour segments as obstacles.
|
// Append neighbour segments as obstacles.
|
||||||
for (int j = 0; j < ag.boundary.GetSegmentCount(); ++j)
|
for (int j = 0; j < ag.boundary.GetSegmentCount(); ++j)
|
||||||
{
|
{
|
||||||
RcVec3f[] s = ag.boundary.GetSegment(j);
|
Vector3[] s = ag.boundary.GetSegment(j);
|
||||||
RcVec3f s3 = s[1];
|
Vector3 s3 = s[1];
|
||||||
//RcArrays.Copy(s, 3, s3, 0, 3);
|
//RcArray.Copy(s, 3, s3, 0, 3);
|
||||||
if (DtUtils.TriArea2D(ag.npos, s[0], s3) < 0.0f)
|
if (DtUtils.TriArea2D(ag.npos, s[0], s3) < 0.0f)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -1195,9 +1192,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.Integrate);
|
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.Integrate);
|
||||||
|
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -1213,16 +1209,15 @@ namespace DotRecast.Detour.Crowd
|
||||||
|
|
||||||
for (int iter = 0; iter < 4; ++iter)
|
for (int iter = 0; iter < 4; ++iter)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
long idx0 = ag.idx;
|
long idx0 = ag.idx;
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ag.disp = RcVec3f.Zero;
|
ag.disp = Vector3.Zero;
|
||||||
|
|
||||||
float w = 0;
|
float w = 0;
|
||||||
|
|
||||||
|
@ -1230,7 +1225,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
DtCrowdAgent nei = ag.neis[j].agent;
|
DtCrowdAgent nei = ag.neis[j].agent;
|
||||||
long idx1 = nei.idx;
|
long idx1 = nei.idx;
|
||||||
RcVec3f diff = RcVec3f.Subtract(ag.npos, nei.npos);
|
Vector3 diff = Vector3.Subtract(ag.npos, nei.npos);
|
||||||
diff.Y = 0;
|
diff.Y = 0;
|
||||||
|
|
||||||
float dist = diff.LengthSquared();
|
float dist = diff.LengthSquared();
|
||||||
|
@ -1246,11 +1241,11 @@ namespace DotRecast.Detour.Crowd
|
||||||
// Agents on top of each other, try to choose diverging separation directions.
|
// Agents on top of each other, try to choose diverging separation directions.
|
||||||
if (idx0 > idx1)
|
if (idx0 > idx1)
|
||||||
{
|
{
|
||||||
diff = new RcVec3f(-ag.dvel.Z, 0, ag.dvel.X);
|
diff = new Vector3(-ag.dvel.Z, 0, ag.dvel.X);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
diff = new RcVec3f(ag.dvel.Z, 0, -ag.dvel.X);
|
diff = new Vector3(ag.dvel.Z, 0, -ag.dvel.X);
|
||||||
}
|
}
|
||||||
|
|
||||||
pen = 0.01f;
|
pen = 0.01f;
|
||||||
|
@ -1272,15 +1267,14 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ag.npos = RcVec3f.Add(ag.npos, ag.disp);
|
ag.npos = Vector3.Add(ag.npos, ag.disp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1289,9 +1283,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.MoveAgents);
|
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.MoveAgents);
|
||||||
|
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
if (ag.state != DtCrowdAgentState.DT_CROWDAGENT_STATE_WALKING)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -1316,9 +1309,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.UpdateOffMeshConnections);
|
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.UpdateOffMeshConnections);
|
||||||
|
|
||||||
for (var i = 0; i < agents.Count; i++)
|
foreach (DtCrowdAgent ag in agents)
|
||||||
{
|
{
|
||||||
var ag = agents[i];
|
|
||||||
DtCrowdAgentAnimation anim = ag.animation;
|
DtCrowdAgentAnimation anim = ag.animation;
|
||||||
if (!anim.active)
|
if (!anim.active)
|
||||||
{
|
{
|
||||||
|
@ -1341,17 +1333,17 @@ namespace DotRecast.Detour.Crowd
|
||||||
if (anim.t < ta)
|
if (anim.t < ta)
|
||||||
{
|
{
|
||||||
float u = Tween(anim.t, 0.0f, ta);
|
float u = Tween(anim.t, 0.0f, ta);
|
||||||
ag.npos = RcVec3f.Lerp(anim.initPos, anim.startPos, u);
|
ag.npos = Vector3.Lerp(anim.initPos, anim.startPos, u);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float u = Tween(anim.t, ta, tb);
|
float u = Tween(anim.t, ta, tb);
|
||||||
ag.npos = RcVec3f.Lerp(anim.startPos, anim.endPos, u);
|
ag.npos = Vector3.Lerp(anim.startPos, anim.endPos, u);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update velocity.
|
// Update velocity.
|
||||||
ag.vel = RcVec3f.Zero;
|
ag.vel = Vector3.Zero;
|
||||||
ag.dvel = RcVec3f.Zero;
|
ag.dvel = Vector3.Zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
|
@ -33,7 +34,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
/// The type of mesh polygon the agent is traversing. (See: #CrowdAgentState)
|
/// The type of mesh polygon the agent is traversing. (See: #CrowdAgentState)
|
||||||
public DtCrowdAgentState state;
|
public DtCrowdAgentState state;
|
||||||
|
|
||||||
/// True if the agent has valid path (targetState == DT_CROWDAGENT_TARGET_VALID) and the path does not lead to the requested position, else false.
|
/// True if the agent has valid path (targetState == DT_CROWDAGENT_TARGET_VALID) and the path does not lead to the
|
||||||
|
/// requested position, else false.
|
||||||
public bool partial;
|
public bool partial;
|
||||||
|
|
||||||
/// The path corridor the agent is using.
|
/// The path corridor the agent is using.
|
||||||
|
@ -51,24 +53,51 @@ namespace DotRecast.Detour.Crowd
|
||||||
/// The desired speed.
|
/// The desired speed.
|
||||||
public float desiredSpeed;
|
public float desiredSpeed;
|
||||||
|
|
||||||
public RcVec3f npos = new RcVec3f(); // < The current agent position. [(x, y, z)]
|
public Vector3 npos = new Vector3();
|
||||||
public RcVec3f disp = new RcVec3f(); // < A temporary value used to accumulate agent displacement during iterative collision resolution. [(x, y, z)]
|
|
||||||
public RcVec3f dvel = new RcVec3f(); // < The desired velocity of the agent. Based on the current path, calculated from scratch each frame. [(x, y, z)]
|
|
||||||
public RcVec3f nvel = new RcVec3f(); // < The desired velocity adjusted by obstacle avoidance, calculated from scratch each frame. [(x, y, z)]
|
|
||||||
public RcVec3f vel = new RcVec3f(); // < The actual velocity of the agent. The change from nvel -> vel is constrained by max acceleration. [(x, y, z)]
|
|
||||||
|
|
||||||
|
/// < The current agent position. [(x, y, z)]
|
||||||
|
public Vector3 disp = new Vector3();
|
||||||
|
|
||||||
|
/// < A temporary value used to accumulate agent displacement during iterative
|
||||||
|
/// collision resolution. [(x, y, z)]
|
||||||
|
public Vector3 dvel = new Vector3();
|
||||||
|
|
||||||
|
/// < The desired velocity of the agent. Based on the current path, calculated
|
||||||
|
/// from
|
||||||
|
/// scratch each frame. [(x, y, z)]
|
||||||
|
public Vector3 nvel = new Vector3();
|
||||||
|
|
||||||
|
/// < The desired velocity adjusted by obstacle avoidance, calculated from scratch each
|
||||||
|
/// frame. [(x, y, z)]
|
||||||
|
public Vector3 vel = new Vector3();
|
||||||
|
|
||||||
|
/// < The actual velocity of the agent. The change from nvel -> vel is
|
||||||
|
/// constrained by max acceleration. [(x, y, z)]
|
||||||
/// The agent's configuration parameters.
|
/// The agent's configuration parameters.
|
||||||
public DtCrowdAgentParams option;
|
public DtCrowdAgentParams option;
|
||||||
|
|
||||||
/// The local path corridor corners for the agent.
|
/// The local path corridor corners for the agent.
|
||||||
public List<DtStraightPath> corners = new List<DtStraightPath>();
|
public List<DtStraightPath> corners = new List<DtStraightPath>();
|
||||||
|
|
||||||
public DtMoveRequestState targetState; // < State of the movement request.
|
public DtMoveRequestState targetState;
|
||||||
public long targetRef; // < Target polyref of the movement request.
|
|
||||||
public RcVec3f targetPos = new RcVec3f(); // < Target position of the movement request (or velocity in case of DT_CROWDAGENT_TARGET_VELOCITY).
|
/// < State of the movement request.
|
||||||
public DtPathQueryResult targetPathQueryResult; // < Path finder query
|
public long targetRef;
|
||||||
public bool targetReplan; // < Flag indicating that the current path is being replanned.
|
|
||||||
public float targetReplanTime; // <Time since the agent's target was replanned.
|
/// < Target polyref of the movement request.
|
||||||
|
public Vector3 targetPos = new Vector3();
|
||||||
|
|
||||||
|
/// < Target position of the movement request (or velocity in case of
|
||||||
|
/// DT_CROWDAGENT_TARGET_VELOCITY).
|
||||||
|
public DtPathQueryResult targetPathQueryResult;
|
||||||
|
|
||||||
|
/// < Path finder query
|
||||||
|
public bool targetReplan;
|
||||||
|
|
||||||
|
/// < Flag indicating that the current path is being replanned.
|
||||||
|
public float targetReplanTime;
|
||||||
|
|
||||||
|
/// <Time since the agent's target was replanned.
|
||||||
public float targetReplanWaitTime;
|
public float targetReplanWaitTime;
|
||||||
|
|
||||||
public DtCrowdAgentAnimation animation;
|
public DtCrowdAgentAnimation animation;
|
||||||
|
@ -85,17 +114,17 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
// Fake dynamic constraint.
|
// Fake dynamic constraint.
|
||||||
float maxDelta = option.maxAcceleration * dt;
|
float maxDelta = option.maxAcceleration * dt;
|
||||||
RcVec3f dv = RcVec3f.Subtract(nvel, vel);
|
Vector3 dv = Vector3.Subtract(nvel, vel);
|
||||||
float ds = dv.Length();
|
float ds = dv.Length();
|
||||||
if (ds > maxDelta)
|
if (ds > maxDelta)
|
||||||
dv = dv.Scale(maxDelta / ds);
|
dv = dv.Scale(maxDelta / ds);
|
||||||
vel = RcVec3f.Add(vel, dv);
|
vel = Vector3.Add(vel, dv);
|
||||||
|
|
||||||
// Integrate
|
// Integrate
|
||||||
if (vel.Length() > 0.0001f)
|
if (vel.Length() > 0.0001f)
|
||||||
npos = RcVecUtils.Mad(npos, vel, dt);
|
npos = RcVecUtils.Mad(npos, vel, dt);
|
||||||
else
|
else
|
||||||
vel = RcVec3f.Zero;
|
vel = Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OverOffmeshConnection(float radius)
|
public bool OverOffmeshConnection(float radius)
|
||||||
|
@ -129,9 +158,9 @@ namespace DotRecast.Detour.Crowd
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f CalcSmoothSteerDirection()
|
public Vector3 CalcSmoothSteerDirection()
|
||||||
{
|
{
|
||||||
RcVec3f dir = new RcVec3f();
|
Vector3 dir = new Vector3();
|
||||||
if (0 < corners.Count)
|
if (0 < corners.Count)
|
||||||
{
|
{
|
||||||
int ip0 = 0;
|
int ip0 = 0;
|
||||||
|
@ -139,8 +168,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
var p0 = corners[ip0].pos;
|
var p0 = corners[ip0].pos;
|
||||||
var p1 = corners[ip1].pos;
|
var p1 = corners[ip1].pos;
|
||||||
|
|
||||||
var dir0 = RcVec3f.Subtract(p0, npos);
|
var dir0 = Vector3.Subtract(p0, npos);
|
||||||
var dir1 = RcVec3f.Subtract(p1, npos);
|
var dir1 = Vector3.Subtract(p1, npos);
|
||||||
dir0.Y = 0;
|
dir0.Y = 0;
|
||||||
dir1.Y = 0;
|
dir1.Y = 0;
|
||||||
|
|
||||||
|
@ -152,26 +181,26 @@ namespace DotRecast.Detour.Crowd
|
||||||
dir.X = dir0.X - dir1.X * len0 * 0.5f;
|
dir.X = dir0.X - dir1.X * len0 * 0.5f;
|
||||||
dir.Y = 0;
|
dir.Y = 0;
|
||||||
dir.Z = dir0.Z - dir1.Z * len0 * 0.5f;
|
dir.Z = dir0.Z - dir1.Z * len0 * 0.5f;
|
||||||
dir = RcVec3f.Normalize(dir);
|
dir = Vector3.Normalize(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f CalcStraightSteerDirection()
|
public Vector3 CalcStraightSteerDirection()
|
||||||
{
|
{
|
||||||
RcVec3f dir = new RcVec3f();
|
Vector3 dir = new Vector3();
|
||||||
if (0 < corners.Count)
|
if (0 < corners.Count)
|
||||||
{
|
{
|
||||||
dir = RcVec3f.Subtract(corners[0].pos, npos);
|
dir = Vector3.Subtract(corners[0].pos, npos);
|
||||||
dir.Y = 0;
|
dir.Y = 0;
|
||||||
dir = RcVec3f.Normalize(dir);
|
dir = Vector3.Normalize(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTarget(long refs, RcVec3f pos)
|
public void SetTarget(long refs, Vector3 pos)
|
||||||
{
|
{
|
||||||
targetRef = refs;
|
targetRef = refs;
|
||||||
targetPos = pos;
|
targetPos = pos;
|
||||||
|
|
|
@ -19,15 +19,16 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
public class DtCrowdAgentAnimation
|
public class DtCrowdAgentAnimation
|
||||||
{
|
{
|
||||||
public bool active;
|
public bool active;
|
||||||
public RcVec3f initPos = new RcVec3f();
|
public Vector3 initPos = new Vector3();
|
||||||
public RcVec3f startPos = new RcVec3f();
|
public Vector3 startPos = new Vector3();
|
||||||
public RcVec3f endPos = new RcVec3f();
|
public Vector3 endPos = new Vector3();
|
||||||
public long polyRef;
|
public long polyRef;
|
||||||
public float t, tmax;
|
public float t, tmax;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,14 +19,15 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
public class DtCrowdAgentDebugInfo
|
public class DtCrowdAgentDebugInfo
|
||||||
{
|
{
|
||||||
public DtCrowdAgent agent;
|
public DtCrowdAgent agent;
|
||||||
public RcVec3f optStart = new RcVec3f();
|
public Vector3 optStart = new Vector3();
|
||||||
public RcVec3f optEnd = new RcVec3f();
|
public Vector3 optEnd = new Vector3();
|
||||||
public DtObstacleAvoidanceDebugData vod;
|
public DtObstacleAvoidanceDebugData vod;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,16 +23,52 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
public readonly float maxAgentRadius;
|
public readonly float maxAgentRadius;
|
||||||
|
|
||||||
public int pathQueueSize = 32; // Max number of path requests in the queue
|
/**
|
||||||
public int maxFindPathIterations = 100; // Max number of sliced path finding iterations executed per update (used to handle longer paths and replans)
|
* Max number of path requests in the queue
|
||||||
public int maxTargetFindPathIterations = 20; // Max number of sliced path finding iterations executed per agent to find the initial path to target
|
*/
|
||||||
public float topologyOptimizationTimeThreshold = 0.5f; // Min time between topology optimizations (in seconds)
|
public int pathQueueSize = 32;
|
||||||
public int checkLookAhead = 10; // The number of polygons from the beginning of the corridor to check to ensure path validity
|
|
||||||
public float targetReplanDelay = 1.0f; // Min time between target re-planning (in seconds)
|
/**
|
||||||
public int maxTopologyOptimizationIterations = 32; // Max number of sliced path finding iterations executed per topology optimization per agent
|
* Max number of sliced path finding iterations executed per update (used to handle longer paths and replans)
|
||||||
|
*/
|
||||||
|
public int maxFindPathIterations = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max number of sliced path finding iterations executed per agent to find the initial path to target
|
||||||
|
*/
|
||||||
|
public int maxTargetFindPathIterations = 20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Min time between topology optimizations (in seconds)
|
||||||
|
*/
|
||||||
|
public float topologyOptimizationTimeThreshold = 0.5f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of polygons from the beginning of the corridor to check to ensure path validity
|
||||||
|
*/
|
||||||
|
public int checkLookAhead = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Min time between target re-planning (in seconds)
|
||||||
|
*/
|
||||||
|
public float targetReplanDelay = 1.0f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max number of sliced path finding iterations executed per topology optimization per agent
|
||||||
|
*/
|
||||||
|
public int maxTopologyOptimizationIterations = 32;
|
||||||
|
|
||||||
public float collisionResolveFactor = 0.7f;
|
public float collisionResolveFactor = 0.7f;
|
||||||
public int maxObstacleAvoidanceCircles = 6; // Max number of neighbour agents to consider in obstacle avoidance processing
|
|
||||||
public int maxObstacleAvoidanceSegments = 8; // Max number of neighbour segments to consider in obstacle avoidance processing
|
/**
|
||||||
|
* Max number of neighbour agents to consider in obstacle avoidance processing
|
||||||
|
*/
|
||||||
|
public int maxObstacleAvoidanceCircles = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max number of neighbour segments to consider in obstacle avoidance processing
|
||||||
|
*/
|
||||||
|
public int maxObstacleAvoidanceSegments = 8;
|
||||||
|
|
||||||
public DtCrowdConfig(float maxAgentRadius)
|
public DtCrowdConfig(float maxAgentRadius)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
namespace DotRecast.Detour.Crowd
|
|
||||||
{
|
|
||||||
public static class DtCrowdConst
|
|
||||||
{
|
|
||||||
/// The maximum number of neighbors that a crowd agent can take into account
|
|
||||||
/// for steering decisions.
|
|
||||||
/// @ingroup crowd
|
|
||||||
public const int DT_CROWDAGENT_MAX_NEIGHBOURS = 6;
|
|
||||||
|
|
||||||
/// The maximum number of corners a crowd agent will look ahead in the path.
|
|
||||||
/// This value is used for sizing the crowd agent corner buffers.
|
|
||||||
/// Due to the behavior of the crowd manager, the actual number of useful
|
|
||||||
/// corners will be one less than this number.
|
|
||||||
/// @ingroup crowd
|
|
||||||
public const int DT_CROWDAGENT_MAX_CORNERS = 4;
|
|
||||||
|
|
||||||
/// The maximum number of crowd avoidance configurations supported by the
|
|
||||||
/// crowd manager.
|
|
||||||
/// @ingroup crowd
|
|
||||||
/// @see dtObstacleAvoidanceParams, dtCrowd::SetObstacleAvoidanceParams(), dtCrowd::GetObstacleAvoidanceParams(),
|
|
||||||
/// dtCrowdAgentParams::obstacleAvoidanceType
|
|
||||||
public const int DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS = 8;
|
|
||||||
|
|
||||||
/// The maximum number of query filter types supported by the crowd manager.
|
|
||||||
/// @ingroup crowd
|
|
||||||
/// @see dtQueryFilter, dtCrowd::GetFilter() dtCrowd::GetEditableFilter(),
|
|
||||||
/// dtCrowdAgentParams::queryFilterType
|
|
||||||
public const int DT_CROWD_MAX_QUERY_FILTER_TYPE = 16;
|
|
||||||
|
|
||||||
public const int MAX_ITERS_PER_UPDATE = 100;
|
|
||||||
public const int MAX_PATHQUEUE_NODES = 4096;
|
|
||||||
public const int MAX_COMMON_NODES = 512;
|
|
||||||
public const int MAX_PATH_RESULT = 256;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
|
||||||
{
|
|
||||||
internal readonly struct DtCrowdScopedTimer : IDisposable
|
|
||||||
{
|
|
||||||
private readonly DtCrowdTimerLabel _label;
|
|
||||||
private readonly DtCrowdTelemetry _telemetry;
|
|
||||||
|
|
||||||
internal DtCrowdScopedTimer(DtCrowdTelemetry telemetry, DtCrowdTimerLabel label)
|
|
||||||
{
|
|
||||||
_telemetry = telemetry;
|
|
||||||
_label = label;
|
|
||||||
|
|
||||||
_telemetry.Start(_label);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_telemetry.Stop(_label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,9 +19,12 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Buffers;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
|
@ -32,7 +35,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
private float _maxTimeToFindPath;
|
private float _maxTimeToFindPath;
|
||||||
|
|
||||||
private readonly Dictionary<DtCrowdTimerLabel, long> _executionTimings = new Dictionary<DtCrowdTimerLabel, long>();
|
private readonly Dictionary<DtCrowdTimerLabel, long> _executionTimings = new Dictionary<DtCrowdTimerLabel, long>();
|
||||||
private readonly Dictionary<DtCrowdTimerLabel, RcCyclicBuffer<long>> _executionTimingSamples = new Dictionary<DtCrowdTimerLabel, RcCyclicBuffer<long>>();
|
private readonly Dictionary<DtCrowdTimerLabel, List<long>> _executionTimingSamples = new Dictionary<DtCrowdTimerLabel, List<long>>();
|
||||||
|
|
||||||
public float MaxTimeToEnqueueRequest()
|
public float MaxTimeToEnqueueRequest()
|
||||||
{
|
{
|
||||||
|
@ -69,27 +72,33 @@ namespace DotRecast.Detour.Crowd
|
||||||
_maxTimeToFindPath = Math.Max(_maxTimeToFindPath, time);
|
_maxTimeToFindPath = Math.Max(_maxTimeToFindPath, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal DtCrowdScopedTimer ScopedTimer(DtCrowdTimerLabel label)
|
public IDisposable ScopedTimer(DtCrowdTimerLabel label)
|
||||||
{
|
{
|
||||||
return new DtCrowdScopedTimer(this, label);
|
Start(label);
|
||||||
|
return new RcAnonymousDisposable(() => Stop(label));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Start(DtCrowdTimerLabel name)
|
private void Start(DtCrowdTimerLabel name)
|
||||||
{
|
{
|
||||||
_executionTimings.Add(name, RcFrequency.Ticks);
|
_executionTimings.Add(name, RcFrequency.Ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Stop(DtCrowdTimerLabel name)
|
private void Stop(DtCrowdTimerLabel name)
|
||||||
{
|
{
|
||||||
long duration = RcFrequency.Ticks - _executionTimings[name];
|
long duration = RcFrequency.Ticks - _executionTimings[name];
|
||||||
if (!_executionTimingSamples.TryGetValue(name, out var cb))
|
if (!_executionTimingSamples.TryGetValue(name, out var s))
|
||||||
{
|
{
|
||||||
cb = new RcCyclicBuffer<long>(TIMING_SAMPLES);
|
s = new List<long>();
|
||||||
_executionTimingSamples.Add(name, cb);
|
_executionTimingSamples.Add(name, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
cb.PushBack(duration);
|
if (s.Count == TIMING_SAMPLES)
|
||||||
_executionTimings[name] = (long)cb.Average();
|
{
|
||||||
|
s.RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Add(duration);
|
||||||
|
_executionTimings[name] = (long)s.Average();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,15 +21,18 @@ freely, subject to the following restrictions:
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
public class DtLocalBoundary
|
public class DtLocalBoundary
|
||||||
{
|
{
|
||||||
public const int MAX_LOCAL_SEGS = 8;
|
public const int MAX_LOCAL_SEGS = 8;
|
||||||
|
|
||||||
private RcVec3f m_center = new RcVec3f();
|
private Vector3 m_center = new Vector3();
|
||||||
private List<DtSegment> m_segs = new List<DtSegment>();
|
private List<DtSegment> m_segs = new List<DtSegment>();
|
||||||
private List<long> m_polys = new List<long>();
|
private List<long> m_polys = new List<long>();
|
||||||
private List<long> m_parents = new List<long>();
|
private List<long> m_parents = new List<long>();
|
||||||
|
@ -88,7 +91,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(long startRef, RcVec3f pos, float collisionQueryRange, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
public void Update(long startRef, Vector3 pos, float collisionQueryRange, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||||
{
|
{
|
||||||
if (startRef == 0)
|
if (startRef == 0)
|
||||||
{
|
{
|
||||||
|
@ -152,12 +155,12 @@ namespace DotRecast.Detour.Crowd
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f GetCenter()
|
public Vector3 GetCenter()
|
||||||
{
|
{
|
||||||
return m_center;
|
return m_center;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f[] GetSegment(int j)
|
public Vector3[] GetSegment(int j)
|
||||||
{
|
{
|
||||||
return m_segs[j].s;
|
return m_segs[j].s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
|
@ -78,7 +79,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
NormalizeArray(m_tpen, m_nsamples);
|
NormalizeArray(m_tpen, m_nsamples);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSample(RcVec3f vel, float ssize, float pen, float vpen, float vcpen, float spen, float tpen)
|
public void AddSample(Vector3 vel, float ssize, float pen, float vpen, float vcpen, float spen, float tpen)
|
||||||
{
|
{
|
||||||
if (m_nsamples >= m_maxSamples)
|
if (m_nsamples >= m_maxSamples)
|
||||||
return;
|
return;
|
||||||
|
@ -99,9 +100,9 @@ namespace DotRecast.Detour.Crowd
|
||||||
return m_nsamples;
|
return m_nsamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f GetSampleVelocity(int i)
|
public Vector3 GetSampleVelocity(int i)
|
||||||
{
|
{
|
||||||
RcVec3f vel = new RcVec3f();
|
Vector3 vel = new Vector3();
|
||||||
vel.X = m_vel[i * 3];
|
vel.X = m_vel[i * 3];
|
||||||
vel.Y = m_vel[i * 3 + 1];
|
vel.Y = m_vel[i * 3 + 1];
|
||||||
vel.Z = m_vel[i * 3 + 2];
|
vel.Z = m_vel[i * 3 + 2];
|
||||||
|
|
|
@ -21,6 +21,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
|
@ -71,7 +72,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
m_nsegments = 0;
|
m_nsegments = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCircle(RcVec3f pos, float rad, RcVec3f vel, RcVec3f dvel)
|
public void AddCircle(Vector3 pos, float rad, Vector3 vel, Vector3 dvel)
|
||||||
{
|
{
|
||||||
if (m_ncircles >= m_maxCircles)
|
if (m_ncircles >= m_maxCircles)
|
||||||
return;
|
return;
|
||||||
|
@ -83,7 +84,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
cir.dvel = dvel;
|
cir.dvel = dvel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSegment(RcVec3f p, RcVec3f q)
|
public void AddSegment(Vector3 p, Vector3 q)
|
||||||
{
|
{
|
||||||
if (m_nsegments >= m_maxSegments)
|
if (m_nsegments >= m_maxSegments)
|
||||||
return;
|
return;
|
||||||
|
@ -113,7 +114,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
return m_segments[i];
|
return m_segments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Prepare(RcVec3f pos, RcVec3f dvel)
|
private void Prepare(Vector3 pos, Vector3 dvel)
|
||||||
{
|
{
|
||||||
// Prepare obstacles
|
// Prepare obstacles
|
||||||
for (int i = 0; i < m_ncircles; ++i)
|
for (int i = 0; i < m_ncircles; ++i)
|
||||||
|
@ -121,14 +122,14 @@ namespace DotRecast.Detour.Crowd
|
||||||
DtObstacleCircle cir = m_circles[i];
|
DtObstacleCircle cir = m_circles[i];
|
||||||
|
|
||||||
// Side
|
// Side
|
||||||
RcVec3f pa = pos;
|
Vector3 pa = pos;
|
||||||
RcVec3f pb = cir.p;
|
Vector3 pb = cir.p;
|
||||||
|
|
||||||
RcVec3f orig = new RcVec3f();
|
Vector3 orig = new Vector3();
|
||||||
RcVec3f dv = new RcVec3f();
|
Vector3 dv = new Vector3();
|
||||||
cir.dp = RcVec3f.Subtract(pb, pa);
|
cir.dp = Vector3.Subtract(pb, pa);
|
||||||
cir.dp = RcVec3f.Normalize(cir.dp);
|
cir.dp = Vector3.Normalize(cir.dp);
|
||||||
dv = RcVec3f.Subtract(cir.dvel, dvel);
|
dv = Vector3.Subtract(cir.dvel, dvel);
|
||||||
|
|
||||||
float a = DtUtils.TriArea2D(orig, cir.dp, dv);
|
float a = DtUtils.TriArea2D(orig, cir.dp, dv);
|
||||||
if (a < 0.01f)
|
if (a < 0.01f)
|
||||||
|
@ -154,14 +155,14 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SweepCircleCircle(RcVec3f c0, float r0, RcVec3f v, RcVec3f c1, float r1, out float tmin, out float tmax)
|
private bool SweepCircleCircle(Vector3 c0, float r0, Vector3 v, Vector3 c1, float r1, out float tmin, out float tmax)
|
||||||
{
|
{
|
||||||
const float EPS = 0.0001f;
|
const float EPS = 0.0001f;
|
||||||
|
|
||||||
tmin = 0;
|
tmin = 0;
|
||||||
tmax = 0;
|
tmax = 0;
|
||||||
|
|
||||||
RcVec3f s = RcVec3f.Subtract(c1, c0);
|
Vector3 s = Vector3.Subtract(c1, c0);
|
||||||
float r = r0 + r1;
|
float r = r0 + r1;
|
||||||
float c = s.Dot2D(s) - r * r;
|
float c = s.Dot2D(s) - r * r;
|
||||||
float a = v.Dot2D(v);
|
float a = v.Dot2D(v);
|
||||||
|
@ -183,10 +184,10 @@ namespace DotRecast.Detour.Crowd
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsectRaySeg(RcVec3f ap, RcVec3f u, RcVec3f bp, RcVec3f bq, ref float t)
|
private bool IsectRaySeg(Vector3 ap, Vector3 u, Vector3 bp, Vector3 bq, ref float t)
|
||||||
{
|
{
|
||||||
RcVec3f v = RcVec3f.Subtract(bq, bp);
|
Vector3 v = Vector3.Subtract(bq, bp);
|
||||||
RcVec3f w = RcVec3f.Subtract(ap, bp);
|
Vector3 w = Vector3.Subtract(ap, bp);
|
||||||
float d = RcVecUtils.Perp2D(u, v);
|
float d = RcVecUtils.Perp2D(u, v);
|
||||||
if (MathF.Abs(d) < 1e-6f)
|
if (MathF.Abs(d) < 1e-6f)
|
||||||
return false;
|
return false;
|
||||||
|
@ -213,7 +214,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
* @param minPenalty
|
* @param minPenalty
|
||||||
* threshold penalty for early out
|
* threshold penalty for early out
|
||||||
*/
|
*/
|
||||||
private float ProcessSample(RcVec3f vcand, float cs, RcVec3f pos, float rad, RcVec3f vel, RcVec3f dvel,
|
private float ProcessSample(Vector3 vcand, float cs, Vector3 pos, float rad, Vector3 vel, Vector3 dvel,
|
||||||
float minPenalty, DtObstacleAvoidanceDebugData debug)
|
float minPenalty, DtObstacleAvoidanceDebugData debug)
|
||||||
{
|
{
|
||||||
// penalty for straying away from the desired and current velocities
|
// penalty for straying away from the desired and current velocities
|
||||||
|
@ -237,9 +238,9 @@ namespace DotRecast.Detour.Crowd
|
||||||
DtObstacleCircle cir = m_circles[i];
|
DtObstacleCircle cir = m_circles[i];
|
||||||
|
|
||||||
// RVO
|
// RVO
|
||||||
RcVec3f vab = vcand.Scale(2);
|
Vector3 vab = vcand.Scale(2);
|
||||||
vab = RcVec3f.Subtract(vab, vel);
|
vab = Vector3.Subtract(vab, vel);
|
||||||
vab = RcVec3f.Subtract(vab, cir.vel);
|
vab = Vector3.Subtract(vab, cir.vel);
|
||||||
|
|
||||||
// Side
|
// Side
|
||||||
side += Math.Clamp(Math.Min(cir.dp.Dot2D(vab) * 0.5f + 0.5f, cir.np.Dot2D(vab) * 2), 0.0f, 1.0f);
|
side += Math.Clamp(Math.Min(cir.dp.Dot2D(vab) * 0.5f + 0.5f, cir.np.Dot2D(vab) * 2), 0.0f, 1.0f);
|
||||||
|
@ -275,8 +276,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
if (seg.touch)
|
if (seg.touch)
|
||||||
{
|
{
|
||||||
// Special case when the agent is very close to the segment.
|
// Special case when the agent is very close to the segment.
|
||||||
RcVec3f sdir = RcVec3f.Subtract(seg.q, seg.p);
|
Vector3 sdir = Vector3.Subtract(seg.q, seg.p);
|
||||||
RcVec3f snorm = new RcVec3f();
|
Vector3 snorm = new Vector3();
|
||||||
snorm.X = -sdir.Z;
|
snorm.X = -sdir.Z;
|
||||||
snorm.Z = sdir.X;
|
snorm.Z = sdir.X;
|
||||||
// If the velocity is pointing towards the segment, no collision.
|
// If the velocity is pointing towards the segment, no collision.
|
||||||
|
@ -318,7 +319,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
return penalty;
|
return penalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int SampleVelocityGrid(RcVec3f pos, float rad, float vmax, RcVec3f vel, RcVec3f dvel, out RcVec3f nvel,
|
public int SampleVelocityGrid(Vector3 pos, float rad, float vmax, Vector3 vel, Vector3 dvel, out Vector3 nvel,
|
||||||
DtObstacleAvoidanceParams option, DtObstacleAvoidanceDebugData debug)
|
DtObstacleAvoidanceParams option, DtObstacleAvoidanceDebugData debug)
|
||||||
{
|
{
|
||||||
Prepare(pos, dvel);
|
Prepare(pos, dvel);
|
||||||
|
@ -327,7 +328,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
m_vmax = vmax;
|
m_vmax = vmax;
|
||||||
m_invVmax = vmax > 0 ? 1.0f / vmax : float.MaxValue;
|
m_invVmax = vmax > 0 ? 1.0f / vmax : float.MaxValue;
|
||||||
|
|
||||||
nvel = RcVec3f.Zero;
|
nvel = Vector3.Zero;
|
||||||
|
|
||||||
if (debug != null)
|
if (debug != null)
|
||||||
debug.Reset();
|
debug.Reset();
|
||||||
|
@ -344,7 +345,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
for (int x = 0; x < m_params.gridSize; ++x)
|
for (int x = 0; x < m_params.gridSize; ++x)
|
||||||
{
|
{
|
||||||
RcVec3f vcand = new RcVec3f(cvx + x * cs - half, 0f, cvz + y * cs - half);
|
Vector3 vcand = new Vector3(cvx + x * cs - half, 0f, cvz + y * cs - half);
|
||||||
if (RcMath.Sqr(vcand.X) + RcMath.Sqr(vcand.Z) > RcMath.Sqr(vmax + cs / 2))
|
if (RcMath.Sqr(vcand.X) + RcMath.Sqr(vcand.Z) > RcMath.Sqr(vmax + cs / 2))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -373,9 +374,9 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
|
|
||||||
// vector normalization that ignores the y-component.
|
// vector normalization that ignores the y-component.
|
||||||
RcVec3f DtRotate2D(float[] v, float ang)
|
Vector3 DtRotate2D(float[] v, float ang)
|
||||||
{
|
{
|
||||||
RcVec3f dest = new RcVec3f();
|
Vector3 dest = new Vector3();
|
||||||
float c = MathF.Cos(ang);
|
float c = MathF.Cos(ang);
|
||||||
float s = MathF.Sin(ang);
|
float s = MathF.Sin(ang);
|
||||||
dest.X = v[0] * c - v[2] * s;
|
dest.X = v[0] * c - v[2] * s;
|
||||||
|
@ -386,7 +387,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
|
|
||||||
static readonly float DT_PI = 3.14159265f;
|
static readonly float DT_PI = 3.14159265f;
|
||||||
|
|
||||||
public int SampleVelocityAdaptive(RcVec3f pos, float rad, float vmax, RcVec3f vel, RcVec3f dvel, out RcVec3f nvel,
|
public int SampleVelocityAdaptive(Vector3 pos, float rad, float vmax, Vector3 vel, Vector3 dvel, out Vector3 nvel,
|
||||||
DtObstacleAvoidanceParams option,
|
DtObstacleAvoidanceParams option,
|
||||||
DtObstacleAvoidanceDebugData debug)
|
DtObstacleAvoidanceDebugData debug)
|
||||||
{
|
{
|
||||||
|
@ -396,7 +397,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
m_vmax = vmax;
|
m_vmax = vmax;
|
||||||
m_invVmax = vmax > 0 ? 1.0f / vmax : float.MaxValue;
|
m_invVmax = vmax > 0 ? 1.0f / vmax : float.MaxValue;
|
||||||
|
|
||||||
nvel = RcVec3f.Zero;
|
nvel = Vector3.Zero;
|
||||||
|
|
||||||
if (debug != null)
|
if (debug != null)
|
||||||
debug.Reset();
|
debug.Reset();
|
||||||
|
@ -421,7 +422,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
ddir[1] = dvel.Y;
|
ddir[1] = dvel.Y;
|
||||||
ddir[2] = dvel.Z;
|
ddir[2] = dvel.Z;
|
||||||
DtNormalize2D(ddir);
|
DtNormalize2D(ddir);
|
||||||
RcVec3f rotated = DtRotate2D(ddir, da * 0.5f); // rotated by da/2
|
Vector3 rotated = DtRotate2D(ddir, da * 0.5f); // rotated by da/2
|
||||||
ddir[3] = rotated.X;
|
ddir[3] = rotated.X;
|
||||||
ddir[4] = rotated.Y;
|
ddir[4] = rotated.Y;
|
||||||
ddir[5] = rotated.Z;
|
ddir[5] = rotated.Z;
|
||||||
|
@ -464,17 +465,17 @@ namespace DotRecast.Detour.Crowd
|
||||||
|
|
||||||
// Start sampling.
|
// Start sampling.
|
||||||
float cr = vmax * (1.0f - m_params.velBias);
|
float cr = vmax * (1.0f - m_params.velBias);
|
||||||
RcVec3f res = new RcVec3f(dvel.X * m_params.velBias, 0, dvel.Z * m_params.velBias);
|
Vector3 res = new Vector3(dvel.X * m_params.velBias, 0, dvel.Z * m_params.velBias);
|
||||||
int ns = 0;
|
int ns = 0;
|
||||||
for (int k = 0; k < depth; ++k)
|
for (int k = 0; k < depth; ++k)
|
||||||
{
|
{
|
||||||
float minPenalty = float.MaxValue;
|
float minPenalty = float.MaxValue;
|
||||||
RcVec3f bvel = new RcVec3f();
|
Vector3 bvel = new Vector3();
|
||||||
bvel = RcVec3f.Zero;
|
bvel = Vector3.Zero;
|
||||||
|
|
||||||
for (int i = 0; i < npat; ++i)
|
for (int i = 0; i < npat; ++i)
|
||||||
{
|
{
|
||||||
RcVec3f vcand = new RcVec3f(res.X + pat[i * 2 + 0] * cr, 0f, res.Z + pat[i * 2 + 1] * cr);
|
Vector3 vcand = new Vector3(res.X + pat[i * 2 + 0] * cr, 0f, res.Z + pat[i * 2 + 1] * cr);
|
||||||
if (RcMath.Sqr(vcand.X) + RcMath.Sqr(vcand.Z) > RcMath.Sqr(vmax + 0.001f))
|
if (RcMath.Sqr(vcand.X) + RcMath.Sqr(vcand.Z) > RcMath.Sqr(vmax + 0.001f))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
|
@ -6,21 +7,21 @@ namespace DotRecast.Detour.Crowd
|
||||||
public class DtObstacleCircle
|
public class DtObstacleCircle
|
||||||
{
|
{
|
||||||
/** Position of the obstacle */
|
/** Position of the obstacle */
|
||||||
public RcVec3f p = new RcVec3f();
|
public Vector3 p = new Vector3();
|
||||||
|
|
||||||
/** Velocity of the obstacle */
|
/** Velocity of the obstacle */
|
||||||
public RcVec3f vel = new RcVec3f();
|
public Vector3 vel = new Vector3();
|
||||||
|
|
||||||
/** Velocity of the obstacle */
|
/** Velocity of the obstacle */
|
||||||
public RcVec3f dvel = new RcVec3f();
|
public Vector3 dvel = new Vector3();
|
||||||
|
|
||||||
/** Radius of the obstacle */
|
/** Radius of the obstacle */
|
||||||
public float rad;
|
public float rad;
|
||||||
|
|
||||||
/** Use for side selection during sampling. */
|
/** Use for side selection during sampling. */
|
||||||
public RcVec3f dp = new RcVec3f();
|
public Vector3 dp = new Vector3();
|
||||||
|
|
||||||
/** Use for side selection during sampling. */
|
/** Use for side selection during sampling. */
|
||||||
public RcVec3f np = new RcVec3f();
|
public Vector3 np = new Vector3();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,15 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
public class DtObstacleSegment
|
public class DtObstacleSegment
|
||||||
{
|
{
|
||||||
/** End points of the obstacle segment */
|
/** End points of the obstacle segment */
|
||||||
public RcVec3f p = new RcVec3f();
|
public Vector3 p = new Vector3();
|
||||||
|
|
||||||
/** End points of the obstacle segment */
|
/** End points of the obstacle segment */
|
||||||
public RcVec3f q = new RcVec3f();
|
public Vector3 q = new Vector3();
|
||||||
|
|
||||||
public bool touch;
|
public bool touch;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,118 +22,100 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
/// Represents a dynamic polygon corridor used to plan agent movement.
|
/**
|
||||||
/// @ingroup crowd, detour
|
* Represents a dynamic polygon corridor used to plan agent movement.
|
||||||
|
*
|
||||||
|
* The corridor is loaded with a path, usually obtained from a #NavMeshQuery::FindPath() query. The corridor is then
|
||||||
|
* used to plan local movement, with the corridor automatically updating as needed to deal with inaccurate agent
|
||||||
|
* locomotion.
|
||||||
|
*
|
||||||
|
* Example of a common use case:
|
||||||
|
*
|
||||||
|
* -# Construct the corridor object and call -# Obtain a path from a #dtNavMeshQuery object. -# Use #Reset() to set the
|
||||||
|
* agent's current position. (At the beginning of the path.) -# Use #SetCorridor() to load the path and target. -# Use
|
||||||
|
* #FindCorners() to plan movement. (This handles dynamic path straightening.) -# Use #MovePosition() to feed agent
|
||||||
|
* movement back into the corridor. (The corridor will automatically adjust as needed.) -# If the target is moving, use
|
||||||
|
* #MoveTargetPosition() to update the end of the corridor. (The corridor will automatically adjust as needed.) -#
|
||||||
|
* Repeat the previous 3 steps to continue to move the agent.
|
||||||
|
*
|
||||||
|
* The corridor position and target are always constrained to the navigation mesh.
|
||||||
|
*
|
||||||
|
* One of the difficulties in maintaining a path is that floating point errors, locomotion inaccuracies, and/or local
|
||||||
|
* steering can result in the agent crossing the boundary of the path corridor, temporarily invalidating the path. This
|
||||||
|
* class uses local mesh queries to detect and update the corridor as needed to handle these types of issues.
|
||||||
|
*
|
||||||
|
* The fact that local mesh queries are used to move the position and target locations results in two beahviors that
|
||||||
|
* need to be considered:
|
||||||
|
*
|
||||||
|
* Every time a move function is used there is a chance that the path will become non-optimial. Basically, the further
|
||||||
|
* the target is moved from its original location, and the further the position is moved outside the original corridor,
|
||||||
|
* the more likely the path will become non-optimal. This issue can be addressed by periodically running the
|
||||||
|
* #OptimizePathTopology() and #OptimizePathVisibility() methods.
|
||||||
|
*
|
||||||
|
* All local mesh queries have distance limitations. (Review the #dtNavMeshQuery methods for details.) So the most
|
||||||
|
* accurate use case is to move the position and target in small increments. If a large increment is used, then the
|
||||||
|
* corridor may not be able to accurately find the new location. Because of this limiation, if a position is moved in a
|
||||||
|
* large increment, then compare the desired and resulting polygon references. If the two do not match, then path
|
||||||
|
* replanning may be needed. E.g. If you move the target, check #GetLastPoly() to see if it is the expected polygon.
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class DtPathCorridor
|
public class DtPathCorridor
|
||||||
{
|
{
|
||||||
private RcVec3f m_pos;
|
private Vector3 m_pos = new Vector3();
|
||||||
private RcVec3f m_target;
|
private Vector3 m_target = new Vector3();
|
||||||
|
|
||||||
private List<long> m_path;
|
private List<long> m_path;
|
||||||
private int m_maxPath;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@class dtPathCorridor
|
* Allocates the corridor's path buffer.
|
||||||
@par
|
*/
|
||||||
|
|
||||||
The corridor is loaded with a path, usually obtained from a #dtNavMeshQuery::findPath() query. The corridor
|
|
||||||
is then used to plan local movement, with the corridor automatically updating as needed to deal with inaccurate
|
|
||||||
agent locomotion.
|
|
||||||
|
|
||||||
Example of a common use case:
|
|
||||||
|
|
||||||
-# Construct the corridor object and call #init() to allocate its path buffer.
|
|
||||||
-# Obtain a path from a #dtNavMeshQuery object.
|
|
||||||
-# Use #reset() to set the agent's current position. (At the beginning of the path.)
|
|
||||||
-# Use #setCorridor() to load the path and target.
|
|
||||||
-# Use #findCorners() to plan movement. (This handles dynamic path straightening.)
|
|
||||||
-# Use #movePosition() to feed agent movement back into the corridor. (The corridor will automatically adjust as needed.)
|
|
||||||
-# If the target is moving, use #moveTargetPosition() to update the end of the corridor.
|
|
||||||
(The corridor will automatically adjust as needed.)
|
|
||||||
-# Repeat the previous 3 steps to continue to move the agent.
|
|
||||||
|
|
||||||
The corridor position and target are always constrained to the navigation mesh.
|
|
||||||
|
|
||||||
One of the difficulties in maintaining a path is that floating point errors, locomotion inaccuracies, and/or local
|
|
||||||
steering can result in the agent crossing the boundary of the path corridor, temporarily invalidating the path.
|
|
||||||
This class uses local mesh queries to detect and update the corridor as needed to handle these types of issues.
|
|
||||||
|
|
||||||
The fact that local mesh queries are used to move the position and target locations results in two beahviors that
|
|
||||||
need to be considered:
|
|
||||||
|
|
||||||
Every time a move function is used there is a chance that the path will become non-optimial. Basically, the further
|
|
||||||
the target is moved from its original location, and the further the position is moved outside the original corridor,
|
|
||||||
the more likely the path will become non-optimal. This issue can be addressed by periodically running the
|
|
||||||
#optimizePathTopology() and #optimizePathVisibility() methods.
|
|
||||||
|
|
||||||
All local mesh queries have distance limitations. (Review the #dtNavMeshQuery methods for details.) So the most accurate
|
|
||||||
use case is to move the position and target in small increments. If a large increment is used, then the corridor
|
|
||||||
may not be able to accurately find the new location. Because of this limiation, if a position is moved in a large
|
|
||||||
increment, then compare the desired and resulting polygon references. If the two do not match, then path replanning
|
|
||||||
may be needed. E.g. If you move the target, check #getLastPoly() to see if it is the expected polygon.
|
|
||||||
*/
|
|
||||||
public DtPathCorridor()
|
public DtPathCorridor()
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @par
|
|
||||||
///
|
|
||||||
/// @warning Cannot be called more than once.
|
|
||||||
/// Allocates the corridor's path buffer.
|
|
||||||
/// @param[in] maxPath The maximum path size the corridor can handle.
|
|
||||||
/// @return True if the initialization succeeded.
|
|
||||||
public bool Init(int maxPath)
|
|
||||||
{
|
{
|
||||||
m_path = new List<long>();
|
m_path = new List<long>();
|
||||||
m_maxPath = maxPath;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @par
|
|
||||||
///
|
|
||||||
/// Essentially, the corridor is set of one polygon in size with the target
|
|
||||||
/// equal to the position.
|
|
||||||
///
|
|
||||||
/// Resets the path corridor to the specified position.
|
|
||||||
/// @param[in] ref The polygon reference containing the position.
|
|
||||||
/// @param[in] pos The new position in the corridor. [(x, y, z)]
|
|
||||||
public void Reset(long refs, RcVec3f pos)
|
|
||||||
{
|
|
||||||
m_pos = pos;
|
|
||||||
m_target = pos;
|
|
||||||
m_path.Clear();
|
|
||||||
m_path.Add(refs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@par
|
* Resets the path corridor to the specified position.
|
||||||
|
*
|
||||||
|
* @param ref
|
||||||
|
* The polygon reference containing the position.
|
||||||
|
* @param pos
|
||||||
|
* The new position in the corridor. [(x, y, z)]
|
||||||
|
*/
|
||||||
|
public void Reset(long refs, Vector3 pos)
|
||||||
|
{
|
||||||
|
m_path.Clear();
|
||||||
|
m_path.Add(refs);
|
||||||
|
m_pos = pos;
|
||||||
|
m_target = pos;
|
||||||
|
}
|
||||||
|
|
||||||
This is the function used to plan local movement within the corridor. One or more corners can be
|
private static readonly float MIN_TARGET_DIST = RcMath.Sqr(0.01f);
|
||||||
detected in order to plan movement. It performs essentially the same function as #dtNavMeshQuery::findStraightPath.
|
|
||||||
|
|
||||||
Due to internal optimizations, the maximum number of corners returned will be (@p maxCorners - 1)
|
/**
|
||||||
For example: If the buffers are sized to hold 10 corners, the function will never return more than 9 corners.
|
* Finds the corners in the corridor from the position toward the target. (The straightened path.)
|
||||||
So if 10 corners are needed, the buffers should be sized for 11 corners.
|
*
|
||||||
|
* This is the function used to plan local movement within the corridor. One or more corners can be detected in
|
||||||
If the target is within range, it will be the last corner and have a polygon reference id of zero.
|
* order to plan movement. It performs essentially the same function as #dtNavMeshQuery::findStraightPath.
|
||||||
*/
|
*
|
||||||
/// Finds the corners in the corridor from the position toward the target. (The straightened path.)
|
* Due to internal optimizations, the maximum number of corners returned will be (@p maxCorners - 1) For example: If
|
||||||
/// @param[out] cornerVerts The corner vertices. [(x, y, z) * cornerCount] [Size: <= maxCorners]
|
* the buffers are sized to hold 10 corners, the function will never return more than 9 corners. So if 10 corners
|
||||||
/// @param[out] cornerFlags The flag for each corner. [(flag) * cornerCount] [Size: <= maxCorners]
|
* are needed, the buffers should be sized for 11 corners.
|
||||||
/// @param[out] cornerPolys The polygon reference for each corner. [(polyRef) * cornerCount]
|
*
|
||||||
/// [Size: <= @p maxCorners]
|
* If the target is within range, it will be the last corner and have a polygon reference id of zero.
|
||||||
/// @param[in] maxCorners The maximum number of corners the buffers can hold.
|
*
|
||||||
/// @param[in] navquery The query object used to build the corridor.
|
* @param filter
|
||||||
/// @param[in] filter The filter to apply to the operation.
|
*
|
||||||
/// @return The number of corners returned in the corner buffers. [0 <= value <= @p maxCorners]
|
* @param[in] navquery The query object used to build the corridor.
|
||||||
|
* @return Corners
|
||||||
|
*/
|
||||||
public int FindCorners(ref List<DtStraightPath> corners, int maxCorners, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
public int FindCorners(ref List<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);
|
var result = navquery.FindStraightPath(m_pos, m_target, m_path, ref corners, maxCorners, 0);
|
||||||
if (result.Succeeded())
|
if (result.Succeeded())
|
||||||
{
|
{
|
||||||
|
@ -142,7 +124,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
foreach (DtStraightPath spi in corners)
|
foreach (DtStraightPath spi in corners)
|
||||||
{
|
{
|
||||||
if ((spi.flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0
|
if ((spi.flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0
|
||||||
|| RcVecUtils.Dist2DSqr(spi.pos, m_pos) > RcMath.Sqr(MIN_TARGET_DIST))
|
|| RcVecUtils.Dist2DSqr(spi.pos, m_pos) > MIN_TARGET_DIST)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -169,29 +151,33 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@par
|
* Attempts to optimize the path if the specified point is visible from the current position.
|
||||||
|
*
|
||||||
Inaccurate locomotion or dynamic obstacle avoidance can force the argent position significantly outside the
|
* Inaccurate locomotion or dynamic obstacle avoidance can force the agent position significantly outside the
|
||||||
original corridor. Over time this can result in the formation of a non-optimal corridor. Non-optimal paths can
|
* original corridor. Over time this can result in the formation of a non-optimal corridor. Non-optimal paths can
|
||||||
also form near the corners of tiles.
|
* also form near the corners of tiles.
|
||||||
|
*
|
||||||
This function uses an efficient local visibility search to try to optimize the corridor
|
* This function uses an efficient local visibility search to try to optimize the corridor between the current
|
||||||
between the current position and @p next.
|
* position and @p next.
|
||||||
|
*
|
||||||
The corridor will change only if @p next is visible from the current position and moving directly toward the point
|
* The corridor will change only if @p next is visible from the current position and moving directly toward the
|
||||||
is better than following the existing path.
|
* point is better than following the existing path.
|
||||||
|
*
|
||||||
The more inaccurate the agent movement, the more beneficial this function becomes. Simply adjust the frequency
|
* The more inaccurate the agent movement, the more beneficial this function becomes. Simply adjust the frequency of
|
||||||
of the call to match the needs to the agent.
|
* the call to match the needs to the agent.
|
||||||
|
*
|
||||||
This function is not suitable for long distance searches.
|
* This function is not suitable for long distance searches.
|
||||||
*/
|
*
|
||||||
/// Attempts to optimize the path if the specified point is visible from the current position.
|
* @param next
|
||||||
/// @param[in] next The point to search toward. [(x, y, z])
|
* The point to search toward. [(x, y, z])
|
||||||
/// @param[in] pathOptimizationRange The maximum range to search. [Limit: > 0]
|
* @param pathOptimizationRange
|
||||||
/// @param[in] navquery The query object used to build the corridor.
|
* The maximum range to search. [Limit: > 0]
|
||||||
/// @param[in] filter The filter to apply to the operation.
|
* @param navquery
|
||||||
public void OptimizePathVisibility(RcVec3f next, float pathOptimizationRange, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
* The query object used to build the corridor.
|
||||||
|
* @param filter
|
||||||
|
* The filter to apply to the operation.
|
||||||
|
*/
|
||||||
|
public void OptimizePathVisibility(Vector3 next, float pathOptimizationRange, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||||
{
|
{
|
||||||
// Clamp the ray to max distance.
|
// Clamp the ray to max distance.
|
||||||
float dist = RcVecUtils.Dist2D(m_pos, next);
|
float dist = RcVecUtils.Dist2D(m_pos, next);
|
||||||
|
@ -202,37 +188,40 @@ namespace DotRecast.Detour.Crowd
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overshoot a little. This helps to optimize open fields in tiled meshes.
|
// Overshoot a little. This helps to optimize open fields in tiled
|
||||||
|
// meshes.
|
||||||
dist = Math.Min(dist + 0.01f, pathOptimizationRange);
|
dist = Math.Min(dist + 0.01f, pathOptimizationRange);
|
||||||
|
|
||||||
// Adjust ray length.
|
// Adjust ray length.
|
||||||
var delta = RcVec3f.Subtract(next, m_pos);
|
var delta = Vector3.Subtract(next, m_pos);
|
||||||
RcVec3f goal = RcVecUtils.Mad(m_pos, delta, pathOptimizationRange / dist);
|
Vector3 goal = RcVecUtils.Mad(m_pos, delta, pathOptimizationRange / dist);
|
||||||
|
|
||||||
var res = new List<long>();
|
var status = navquery.Raycast(m_path[0], m_pos, goal, filter, 0, 0, out var rayHit);
|
||||||
var status = navquery.Raycast(m_path[0], m_pos, goal, filter, out var t, out var norm, ref res);
|
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
if (res.Count > 1 && t > 0.99f)
|
if (rayHit.path.Count > 1 && rayHit.t > 0.99f)
|
||||||
{
|
{
|
||||||
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, m_path.Count, m_maxPath, res);
|
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, rayHit.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@par
|
* Attempts to optimize the path using a local area search. (Partial replanning.)
|
||||||
|
*
|
||||||
Inaccurate locomotion or dynamic obstacle avoidance can force the agent position significantly outside the
|
* Inaccurate locomotion or dynamic obstacle avoidance can force the agent position significantly outside the
|
||||||
original corridor. Over time this can result in the formation of a non-optimal corridor. This function will use a
|
* original corridor. Over time this can result in the formation of a non-optimal corridor. This function will use a
|
||||||
local area path search to try to re-optimize the corridor.
|
* local area path search to try to re-optimize the corridor.
|
||||||
|
*
|
||||||
The more inaccurate the agent movement, the more beneficial this function becomes. Simply adjust the frequency of
|
* The more inaccurate the agent movement, the more beneficial this function becomes. Simply adjust the frequency of
|
||||||
the call to match the needs to the agent.
|
* the call to match the needs to the agent.
|
||||||
*/
|
*
|
||||||
/// Attempts to optimize the path using a local area search. (Partial replanning.)
|
* @param navquery
|
||||||
/// @param[in] navquery The query object used to build the corridor.
|
* The query object used to build the corridor.
|
||||||
/// @param[in] filter The filter to apply to the operation.
|
* @param filter
|
||||||
|
* The filter to apply to the operation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
public bool OptimizePathTopology(DtNavMeshQuery navquery, IDtQueryFilter filter, int maxIterations)
|
public bool OptimizePathTopology(DtNavMeshQuery navquery, IDtQueryFilter filter, int maxIterations)
|
||||||
{
|
{
|
||||||
if (m_path.Count < 3)
|
if (m_path.Count < 3)
|
||||||
|
@ -241,20 +230,20 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
|
|
||||||
var res = new List<long>();
|
var res = new List<long>();
|
||||||
navquery.InitSlicedFindPath(m_path[0], m_path[^1], m_pos, m_target, filter, 0);
|
navquery.InitSlicedFindPath(m_path[0], m_path[m_path.Count - 1], m_pos, m_target, filter, 0);
|
||||||
navquery.UpdateSlicedFindPath(maxIterations, out var _);
|
navquery.UpdateSlicedFindPath(maxIterations, out var _);
|
||||||
var status = navquery.FinalizeSlicedFindPathPartial(m_path, ref res);
|
var status = navquery.FinalizeSlicedFindPathPartial(m_path, ref res);
|
||||||
|
|
||||||
if (status.Succeeded() && res.Count > 0)
|
if (status.Succeeded() && res.Count > 0)
|
||||||
{
|
{
|
||||||
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, m_path.Count, m_maxPath, res);
|
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MoveOverOffmeshConnection(long offMeshConRef, long[] refs, ref RcVec3f startPos, ref RcVec3f endPos, DtNavMeshQuery navquery)
|
public bool MoveOverOffmeshConnection(long offMeshConRef, long[] refs, ref Vector3 startPos, ref Vector3 endPos, DtNavMeshQuery navquery)
|
||||||
{
|
{
|
||||||
// Advance the path up to and over the off-mesh connection.
|
// Advance the path up to and over the off-mesh connection.
|
||||||
long prevRef = 0, polyRef = m_path[0];
|
long prevRef = 0, polyRef = m_path[0];
|
||||||
|
@ -289,34 +278,36 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@par
|
* Moves the position from the current location to the desired location, adjusting the corridor as needed to reflect
|
||||||
|
* the change.
|
||||||
Behavior:
|
*
|
||||||
|
* Behavior:
|
||||||
- The movement is constrained to the surface of the navigation mesh.
|
*
|
||||||
- The corridor is automatically adjusted (shorted or lengthened) in order to remain valid.
|
* - The movement is constrained to the surface of the navigation mesh. - The corridor is automatically adjusted
|
||||||
- The new position will be located in the adjusted corridor's first polygon.
|
* (shorted or lengthened) in order to remain valid. - The new position will be located in the adjusted corridor's
|
||||||
|
* first polygon.
|
||||||
The expected use case is that the desired position will be 'near' the current corridor. What is considered 'near'
|
*
|
||||||
depends on local polygon density, query search half extents, etc.
|
* The expected use case is that the desired position will be 'near' the current corridor. What is considered 'near'
|
||||||
|
* depends on local polygon density, query search extents, etc.
|
||||||
The resulting position will differ from the desired position if the desired position is not on the navigation mesh,
|
*
|
||||||
or it can't be reached using a local search.
|
* The resulting position will differ from the desired position if the desired position is not on the navigation
|
||||||
*/
|
* mesh, or it can't be reached using a local search.
|
||||||
/// Moves the position from the current location to the desired location, adjusting the corridor
|
*
|
||||||
/// as needed to reflect the change.
|
* @param npos
|
||||||
/// @param[in] npos The desired new position. [(x, y, z)]
|
* The desired new position. [(x, y, z)]
|
||||||
/// @param[in] navquery The query object used to build the corridor.
|
* @param navquery
|
||||||
/// @param[in] filter The filter to apply to the operation.
|
* The query object used to build the corridor.
|
||||||
/// @return Returns true if move succeeded.
|
* @param filter
|
||||||
public bool MovePosition(RcVec3f npos, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
* The filter to apply to the operation.
|
||||||
|
*/
|
||||||
|
public bool MovePosition(Vector3 npos, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||||
{
|
{
|
||||||
// Move along navmesh and update new position.
|
// Move along navmesh and update new position.
|
||||||
var visited = new List<long>();
|
var visited = new List<long>();
|
||||||
var status = navquery.MoveAlongSurface(m_path[0], m_pos, npos, filter, out var result, ref visited);
|
var status = navquery.MoveAlongSurface(m_path[0], m_pos, npos, filter, out var result, ref visited);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
m_path = DtPathUtils.MergeCorridorStartMoved(m_path, m_path.Count, m_maxPath, visited);
|
m_path = DtPathUtils.MergeCorridorStartMoved(m_path, visited);
|
||||||
|
|
||||||
// Adjust the position to stay on top of the navmesh.
|
// Adjust the position to stay on top of the navmesh.
|
||||||
m_pos = result;
|
m_pos = result;
|
||||||
|
@ -333,32 +324,30 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@par
|
* Moves the target from the curent location to the desired location, adjusting the corridor as needed to reflect
|
||||||
|
* the change. Behavior: - The movement is constrained to the surface of the navigation mesh. - The corridor is
|
||||||
Behavior:
|
* automatically adjusted (shorted or lengthened) in order to remain valid. - The new target will be located in the
|
||||||
|
* adjusted corridor's last polygon.
|
||||||
- The movement is constrained to the surface of the navigation mesh.
|
*
|
||||||
- The corridor is automatically adjusted (shorted or lengthened) in order to remain valid.
|
* The expected use case is that the desired target will be 'near' the current corridor. What is considered 'near'
|
||||||
- The new target will be located in the adjusted corridor's last polygon.
|
* depends on local polygon density, query search extents, etc. The resulting target will differ from the desired
|
||||||
|
* target if the desired target is not on the navigation mesh, or it can't be reached using a local search.
|
||||||
The expected use case is that the desired target will be 'near' the current corridor. What is considered 'near' depends on local polygon density, query search half extents, etc.
|
*
|
||||||
|
* @param npos
|
||||||
The resulting target will differ from the desired target if the desired target is not on the navigation mesh, or it can't be reached using a local search.
|
* The desired new target position. [(x, y, z)]
|
||||||
*/
|
* @param navquery
|
||||||
/// Moves the target from the curent location to the desired location, adjusting the corridor
|
* The query object used to build the corridor.
|
||||||
/// as needed to reflect the change.
|
* @param filter
|
||||||
/// @param[in] npos The desired new target position. [(x, y, z)]
|
* The filter to apply to the operation.
|
||||||
/// @param[in] navquery The query object used to build the corridor.
|
*/
|
||||||
/// @param[in] filter The filter to apply to the operation.
|
public bool MoveTargetPosition(Vector3 npos, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||||
/// @return Returns true if move succeeded.
|
|
||||||
public bool MoveTargetPosition(RcVec3f npos, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
|
||||||
{
|
{
|
||||||
// Move along navmesh and update new position.
|
// Move along navmesh and update new position.
|
||||||
var visited = new List<long>();
|
var visited = new List<long>();
|
||||||
var status = navquery.MoveAlongSurface(m_path[^1], m_target, npos, filter, out var result, ref visited);
|
var status = navquery.MoveAlongSurface(m_path[m_path.Count - 1], m_target, npos, filter, out var result, ref visited);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
m_path = DtPathUtils.MergeCorridorEndMoved(m_path, m_path.Count, m_maxPath, visited);
|
m_path = DtPathUtils.MergeCorridorEndMoved(m_path, visited);
|
||||||
// TODO: should we do that?
|
// TODO: should we do that?
|
||||||
// Adjust the position to stay on top of the navmesh.
|
// Adjust the position to stay on top of the navmesh.
|
||||||
/*
|
/*
|
||||||
|
@ -372,23 +361,23 @@ namespace DotRecast.Detour.Crowd
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @par
|
/**
|
||||||
///
|
* Loads a new path and target into the corridor. The current corridor position is expected to be within the first
|
||||||
/// The current corridor position is expected to be within the first polygon in the path. The target
|
* polygon in the path. The target is expected to be in the last polygon.
|
||||||
/// is expected to be in the last polygon.
|
*
|
||||||
///
|
* @warning The size of the path must not exceed the size of corridor's path buffer set during #Init().
|
||||||
/// @warning The size of the path must not exceed the size of corridor's path buffer set during #init().
|
* @param target
|
||||||
/// Loads a new path and target into the corridor.
|
* The target location within the last polygon of the path. [(x, y, z)]
|
||||||
/// @param[in] target The target location within the last polygon of the path. [(x, y, z)]
|
* @param path
|
||||||
/// @param[in] path The path corridor. [(polyRef) * @p npolys]
|
* The path corridor.
|
||||||
/// @param[in] npath The number of polygons in the path.
|
*/
|
||||||
public void SetCorridor(RcVec3f target, List<long> path)
|
public void SetCorridor(Vector3 target, List<long> path)
|
||||||
{
|
{
|
||||||
m_target = target;
|
m_target = target;
|
||||||
m_path = new List<long>(path);
|
m_path = new List<long>(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FixPathStart(long safeRef, RcVec3f safePos)
|
public void FixPathStart(long safeRef, Vector3 safePos)
|
||||||
{
|
{
|
||||||
m_pos = safePos;
|
m_pos = safePos;
|
||||||
if (m_path.Count < 3 && m_path.Count > 0)
|
if (m_path.Count < 3 && m_path.Count > 0)
|
||||||
|
@ -439,15 +428,19 @@ namespace DotRecast.Detour.Crowd
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @par
|
/**
|
||||||
///
|
* Checks the current corridor path to see if its polygon references remain valid. The path can be invalidated if
|
||||||
/// The path can be invalidated if there are structural changes to the underlying navigation mesh, or the state of
|
* there are structural changes to the underlying navigation mesh, or the state of a polygon within the path changes
|
||||||
/// a polygon within the path changes resulting in it being filtered out. (E.g. An exclusion or inclusion flag changes.)
|
* resulting in it being filtered out. (E.g. An exclusion or inclusion flag changes.)
|
||||||
/// Checks the current corridor path to see if its polygon references remain valid.
|
*
|
||||||
///
|
* @param maxLookAhead
|
||||||
/// @param[in] maxLookAhead The number of polygons from the beginning of the corridor to search.
|
* The number of polygons from the beginning of the corridor to search.
|
||||||
/// @param[in] navquery The query object used to build the corridor.
|
* @param navquery
|
||||||
/// @param[in] filter The filter to apply to the operation.
|
* The query object used to build the corridor.
|
||||||
|
* @param filter
|
||||||
|
* The filter to apply to the operation.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public bool IsValid(int maxLookAhead, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
public bool IsValid(int maxLookAhead, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||||
{
|
{
|
||||||
// Check that all polygons still pass query filter.
|
// Check that all polygons still pass query filter.
|
||||||
|
@ -463,43 +456,59 @@ namespace DotRecast.Detour.Crowd
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the current position within the corridor. (In the first polygon.)
|
/**
|
||||||
/// @return The current position within the corridor.
|
* Gets the current position within the corridor. (In the first polygon.)
|
||||||
public RcVec3f GetPos()
|
*
|
||||||
|
* @return The current position within the corridor.
|
||||||
|
*/
|
||||||
|
public Vector3 GetPos()
|
||||||
{
|
{
|
||||||
return m_pos;
|
return m_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the current target within the corridor. (In the last polygon.)
|
/**
|
||||||
/// @return The current target within the corridor.
|
* Gets the current target within the corridor. (In the last polygon.)
|
||||||
public RcVec3f GetTarget()
|
*
|
||||||
|
* @return The current target within the corridor.
|
||||||
|
*/
|
||||||
|
public Vector3 GetTarget()
|
||||||
{
|
{
|
||||||
return m_target;
|
return m_target;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The polygon reference id of the first polygon in the corridor, the polygon containing the position.
|
/**
|
||||||
/// @return The polygon reference id of the first polygon in the corridor. (Or zero if there is no path.)
|
* The polygon reference id of the first polygon in the corridor, the polygon containing the position.
|
||||||
|
*
|
||||||
|
* @return The polygon reference id of the first polygon in the corridor. (Or zero if there is no path.)
|
||||||
|
*/
|
||||||
public long GetFirstPoly()
|
public long GetFirstPoly()
|
||||||
{
|
{
|
||||||
return 0 == m_path.Count ? 0 : m_path[0];
|
return 0 == m_path.Count ? 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.)
|
* 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()
|
public long GetLastPoly()
|
||||||
{
|
{
|
||||||
return 0 == m_path.Count ? 0 : m_path[m_path.Count - 1];
|
return 0 == m_path.Count ? 0 : m_path[m_path.Count - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The corridor's path.
|
/**
|
||||||
/// @return The corridor's path. [(polyRef) * #getPathCount()]
|
* The corridor's path.
|
||||||
|
*/
|
||||||
public List<long> GetPath()
|
public List<long> GetPath()
|
||||||
{
|
{
|
||||||
return m_path;
|
return m_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of polygons in the current corridor path.
|
/**
|
||||||
/// @return The number of polygons in the current corridor path.
|
* The number of polygons in the current corridor path.
|
||||||
|
*
|
||||||
|
* @return The number of polygons in the current corridor path.
|
||||||
|
*/
|
||||||
public int GetPathCount()
|
public int GetPathCount()
|
||||||
{
|
{
|
||||||
return m_path.Count;
|
return m_path.Count;
|
||||||
|
|
|
@ -19,14 +19,15 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
public class DtPathQuery
|
public class DtPathQuery
|
||||||
{
|
{
|
||||||
/// Path find start and end location.
|
/// Path find start and end location.
|
||||||
public RcVec3f startPos = new RcVec3f();
|
public Vector3 startPos = new Vector3();
|
||||||
public RcVec3f endPos = new RcVec3f();
|
public Vector3 endPos = new Vector3();
|
||||||
public long startRef;
|
public long startRef;
|
||||||
public long endRef;
|
public long endRef;
|
||||||
|
|
||||||
|
|
|
@ -20,35 +20,35 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
public class DtPathQueue
|
public class DtPathQueue
|
||||||
{
|
{
|
||||||
private readonly DtCrowdConfig m_config;
|
private readonly DtCrowdConfig config;
|
||||||
private readonly LinkedList<DtPathQuery> m_queue;
|
private readonly LinkedList<DtPathQuery> queue = new LinkedList<DtPathQuery>();
|
||||||
|
|
||||||
public DtPathQueue(DtCrowdConfig config)
|
public DtPathQueue(DtCrowdConfig config)
|
||||||
{
|
{
|
||||||
m_config = config;
|
this.config = config;
|
||||||
m_queue = new LinkedList<DtPathQuery>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(DtNavMesh navMesh)
|
public void Update(DtNavMesh navMesh)
|
||||||
{
|
{
|
||||||
// Update path request until there is nothing to update
|
// Update path request until there is nothing to update or up to maxIters pathfinder iterations has been
|
||||||
// or upto maxIters pathfinder iterations has been consumed.
|
// consumed.
|
||||||
int iterCount = m_config.maxFindPathIterations;
|
int iterCount = config.maxFindPathIterations;
|
||||||
while (iterCount > 0)
|
while (iterCount > 0)
|
||||||
{
|
{
|
||||||
DtPathQuery q = m_queue.First?.Value;
|
DtPathQuery q = queue.First?.Value;
|
||||||
if (q == null)
|
if (q == null)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_queue.RemoveFirst();
|
queue.RemoveFirst();
|
||||||
|
|
||||||
// Handle query start.
|
// Handle query start.
|
||||||
if (q.result.status.IsEmpty())
|
if (q.result.status.IsEmpty())
|
||||||
|
@ -71,14 +71,14 @@ namespace DotRecast.Detour.Crowd
|
||||||
|
|
||||||
if (!(q.result.status.Failed() || q.result.status.Succeeded()))
|
if (!(q.result.status.Failed() || q.result.status.Succeeded()))
|
||||||
{
|
{
|
||||||
m_queue.AddFirst(q);
|
queue.AddFirst(q);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtPathQueryResult Request(long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter)
|
public DtPathQueryResult Request(long startRef, long endRef, Vector3 startPos, Vector3 endPos, IDtQueryFilter filter)
|
||||||
{
|
{
|
||||||
if (m_queue.Count >= m_config.pathQueueSize)
|
if (queue.Count >= config.pathQueueSize)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
q.endPos = endPos;
|
q.endPos = endPos;
|
||||||
q.endRef = endRef;
|
q.endRef = endRef;
|
||||||
q.filter = filter;
|
q.filter = filter;
|
||||||
m_queue.AddLast(q);
|
queue.AddLast(q);
|
||||||
return q.result;
|
return q.result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,51 +83,30 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int QueryItems(float minx, float miny, float maxx, float maxy, DtCrowdAgent[] ids, int maxIds)
|
// 해당 셀 사이즈의 크기로 x ~ y 영역을 찾아, 군집 에이전트를 가져오는 코드
|
||||||
|
public int QueryItems(float minx, float miny, float maxx, float maxy, ref HashSet<DtCrowdAgent> result)
|
||||||
{
|
{
|
||||||
int iminx = (int)MathF.Floor(minx * _invCellSize);
|
int iminx = (int)MathF.Floor(minx * _invCellSize);
|
||||||
int iminy = (int)MathF.Floor(miny * _invCellSize);
|
int iminy = (int)MathF.Floor(miny * _invCellSize);
|
||||||
int imaxx = (int)MathF.Floor(maxx * _invCellSize);
|
int imaxx = (int)MathF.Floor(maxx * _invCellSize);
|
||||||
int imaxy = (int)MathF.Floor(maxy * _invCellSize);
|
int imaxy = (int)MathF.Floor(maxy * _invCellSize);
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
for (int y = iminy; y <= imaxy; ++y)
|
for (int y = iminy; y <= imaxy; ++y)
|
||||||
{
|
{
|
||||||
for (int x = iminx; x <= imaxx; ++x)
|
for (int x = iminx; x <= imaxx; ++x)
|
||||||
{
|
{
|
||||||
long key = CombineKey(x, y);
|
long key = CombineKey(x, y);
|
||||||
bool hasPool = _items.TryGetValue(key, out var pool);
|
if (_items.TryGetValue(key, out var ids))
|
||||||
if (!hasPool)
|
|
||||||
{
|
{
|
||||||
continue;
|
for (int i = 0; i < ids.Count; ++i)
|
||||||
}
|
|
||||||
|
|
||||||
for (int idx = 0; idx < pool.Count; ++idx)
|
|
||||||
{
|
|
||||||
var item = pool[idx];
|
|
||||||
|
|
||||||
// Check if the id exists already.
|
|
||||||
int end = n;
|
|
||||||
int i = 0;
|
|
||||||
while (i != end && ids[i] != item)
|
|
||||||
{
|
{
|
||||||
++i;
|
result.Add(ids[i]);
|
||||||
}
|
|
||||||
|
|
||||||
// Item not found, add it.
|
|
||||||
if (i == n)
|
|
||||||
{
|
|
||||||
ids[n++] = item;
|
|
||||||
|
|
||||||
if (n >= maxIds)
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
return result.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<(long, int)> GetItemCounts()
|
public IEnumerable<(long, int)> GetItemCounts()
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
public class DtSegment
|
public class DtSegment
|
||||||
{
|
{
|
||||||
/** Segment start/end */
|
/** Segment start/end */
|
||||||
public RcVec3f[] s = new RcVec3f[2];
|
public Vector3[] s = new Vector3[2];
|
||||||
|
|
||||||
/** Distance for pruning. */
|
/** Distance for pruning. */
|
||||||
public float d;
|
public float d;
|
||||||
|
|
|
@ -20,23 +20,24 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Colliders
|
namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
{
|
{
|
||||||
public class DtBoxCollider : DtCollider
|
public class DtBoxCollider : DtCollider
|
||||||
{
|
{
|
||||||
private readonly RcVec3f center;
|
private readonly Vector3 center;
|
||||||
private readonly RcVec3f[] halfEdges;
|
private readonly Vector3[] halfEdges;
|
||||||
|
|
||||||
public DtBoxCollider(RcVec3f center, RcVec3f[] halfEdges, int area, float flagMergeThreshold) :
|
public DtBoxCollider(Vector3 center, Vector3[] halfEdges, int area, float flagMergeThreshold) :
|
||||||
base(area, flagMergeThreshold, Bounds(center, halfEdges))
|
base(area, flagMergeThreshold, Bounds(center, halfEdges))
|
||||||
{
|
{
|
||||||
this.center = center;
|
this.center = center;
|
||||||
this.halfEdges = halfEdges;
|
this.halfEdges = halfEdges;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] Bounds(RcVec3f center, RcVec3f[] halfEdges)
|
private static float[] Bounds(Vector3 center, Vector3[] halfEdges)
|
||||||
{
|
{
|
||||||
float[] bounds = new float[]
|
float[] bounds = new float[]
|
||||||
{
|
{
|
||||||
|
@ -62,26 +63,26 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
|
||||||
{
|
{
|
||||||
RcFilledVolumeRasterization.RasterizeBox(
|
RcFilledVolumeRasterization.RasterizeBox(
|
||||||
hf, center, halfEdges, area, (int)MathF.Floor(flagMergeThreshold / hf.ch), context);
|
hf, center, halfEdges, area, (int)MathF.Floor(flagMergeThreshold / hf.ch), telemetry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RcVec3f[] GetHalfEdges(RcVec3f up, RcVec3f forward, RcVec3f extent)
|
public static Vector3[] GetHalfEdges(Vector3 up, Vector3 forward, Vector3 extent)
|
||||||
{
|
{
|
||||||
RcVec3f[] halfEdges =
|
Vector3[] halfEdges =
|
||||||
{
|
{
|
||||||
RcVec3f.Zero,
|
Vector3.Zero,
|
||||||
new RcVec3f(up.X, up.Y, up.Z),
|
new Vector3(up.X, up.Y, up.Z),
|
||||||
RcVec3f.Zero
|
Vector3.Zero
|
||||||
};
|
};
|
||||||
|
|
||||||
halfEdges[1] = RcVec3f.Normalize(halfEdges[1]);
|
halfEdges[1] = Vector3.Normalize(halfEdges[1]);
|
||||||
halfEdges[0] = RcVec3f.Cross(up, forward);
|
halfEdges[0] = Vector3.Cross(up, forward);
|
||||||
halfEdges[0] = RcVec3f.Normalize(halfEdges[0]);
|
halfEdges[0] = Vector3.Normalize(halfEdges[0]);
|
||||||
halfEdges[2] = RcVec3f.Cross(halfEdges[0], up);
|
halfEdges[2] = Vector3.Cross(halfEdges[0], up);
|
||||||
halfEdges[2] = RcVec3f.Normalize(halfEdges[2]);
|
halfEdges[2] = Vector3.Normalize(halfEdges[2]);
|
||||||
halfEdges[0].X *= extent.X;
|
halfEdges[0].X *= extent.X;
|
||||||
halfEdges[0].Y *= extent.X;
|
halfEdges[0].Y *= extent.X;
|
||||||
halfEdges[0].Z *= extent.X;
|
halfEdges[0].Z *= extent.X;
|
||||||
|
|
|
@ -20,17 +20,18 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Colliders
|
namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
{
|
{
|
||||||
public class DtCapsuleCollider : DtCollider
|
public class DtCapsuleCollider : DtCollider
|
||||||
{
|
{
|
||||||
private readonly RcVec3f start;
|
private readonly Vector3 start;
|
||||||
private readonly RcVec3f end;
|
private readonly Vector3 end;
|
||||||
private readonly float radius;
|
private readonly float radius;
|
||||||
|
|
||||||
public DtCapsuleCollider(RcVec3f start, RcVec3f end, float radius, int area, float flagMergeThreshold)
|
public DtCapsuleCollider(Vector3 start, Vector3 end, float radius, int area, float flagMergeThreshold)
|
||||||
: base(area, flagMergeThreshold, Bounds(start, end, radius))
|
: base(area, flagMergeThreshold, Bounds(start, end, radius))
|
||||||
{
|
{
|
||||||
this.start = start;
|
this.start = start;
|
||||||
|
@ -38,12 +39,12 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
this.radius = radius;
|
this.radius = radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
|
||||||
{
|
{
|
||||||
RcFilledVolumeRasterization.RasterizeCapsule(hf, start, end, radius, area, (int)MathF.Floor(flagMergeThreshold / hf.ch), context);
|
RcFilledVolumeRasterization.RasterizeCapsule(hf, start, end, radius, area, (int)MathF.Floor(flagMergeThreshold / hf.ch), telemetry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] Bounds(RcVec3f start, RcVec3f end, float radius)
|
private static float[] Bounds(Vector3 start, Vector3 end, float radius)
|
||||||
{
|
{
|
||||||
return new float[]
|
return new float[]
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,6 +40,6 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
return _bounds;
|
return _bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void Rasterize(RcHeightfield hf, RcContext context);
|
public abstract void Rasterize(RcHeightfield hf, RcTelemetry telemetry);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -68,10 +68,10 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Rasterize(RcHeightfield hf, RcContext context)
|
public void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
|
||||||
{
|
{
|
||||||
foreach (var c in colliders)
|
foreach (var c in colliders)
|
||||||
c.Rasterize(hf, context);
|
c.Rasterize(hf, telemetry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -42,10 +42,10 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
this.triangles = triangles;
|
this.triangles = triangles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
|
||||||
{
|
{
|
||||||
RcFilledVolumeRasterization.RasterizeConvex(hf, vertices, triangles, area,
|
RcFilledVolumeRasterization.RasterizeConvex(hf, vertices, triangles, area,
|
||||||
(int)MathF.Floor(flagMergeThreshold / hf.ch), context);
|
(int)MathF.Floor(flagMergeThreshold / hf.ch), telemetry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,17 +20,18 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Colliders
|
namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
{
|
{
|
||||||
public class DtCylinderCollider : DtCollider
|
public class DtCylinderCollider : DtCollider
|
||||||
{
|
{
|
||||||
private readonly RcVec3f start;
|
private readonly Vector3 start;
|
||||||
private readonly RcVec3f end;
|
private readonly Vector3 end;
|
||||||
private readonly float radius;
|
private readonly float radius;
|
||||||
|
|
||||||
public DtCylinderCollider(RcVec3f start, RcVec3f end, float radius, int area, float flagMergeThreshold) :
|
public DtCylinderCollider(Vector3 start, Vector3 end, float radius, int area, float flagMergeThreshold) :
|
||||||
base(area, flagMergeThreshold, Bounds(start, end, radius))
|
base(area, flagMergeThreshold, Bounds(start, end, radius))
|
||||||
{
|
{
|
||||||
this.start = start;
|
this.start = start;
|
||||||
|
@ -38,13 +39,13 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
this.radius = radius;
|
this.radius = radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
|
||||||
{
|
{
|
||||||
RcFilledVolumeRasterization.RasterizeCylinder(hf, start, end, radius, area, (int)MathF.Floor(flagMergeThreshold / hf.ch),
|
RcFilledVolumeRasterization.RasterizeCylinder(hf, start, end, radius, area, (int)MathF.Floor(flagMergeThreshold / hf.ch),
|
||||||
context);
|
telemetry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] Bounds(RcVec3f start, RcVec3f end, float radius)
|
private static float[] Bounds(Vector3 start, Vector3 end, float radius)
|
||||||
{
|
{
|
||||||
return new float[]
|
return new float[]
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,29 +20,30 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Colliders
|
namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
{
|
{
|
||||||
public class DtSphereCollider : DtCollider
|
public class DtSphereCollider : DtCollider
|
||||||
{
|
{
|
||||||
private readonly RcVec3f center;
|
private readonly Vector3 center;
|
||||||
private readonly float radius;
|
private readonly float radius;
|
||||||
|
|
||||||
public DtSphereCollider(RcVec3f center, float radius, int area, float flagMergeThreshold)
|
public DtSphereCollider(Vector3 center, float radius, int area, float flagMergeThreshold)
|
||||||
: base(area, flagMergeThreshold, Bounds(center, radius))
|
: base(area, flagMergeThreshold, Bounds(center, radius))
|
||||||
{
|
{
|
||||||
this.center = center;
|
this.center = center;
|
||||||
this.radius = radius;
|
this.radius = radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
|
||||||
{
|
{
|
||||||
RcFilledVolumeRasterization.RasterizeSphere(hf, center, radius, area, (int)MathF.Floor(flagMergeThreshold / hf.ch),
|
RcFilledVolumeRasterization.RasterizeSphere(hf, center, radius, area, (int)MathF.Floor(flagMergeThreshold / hf.ch),
|
||||||
context);
|
telemetry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] Bounds(RcVec3f center, float radius)
|
private static float[] Bounds(Vector3 center, float radius)
|
||||||
{
|
{
|
||||||
return new float[]
|
return new float[]
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,12 +58,12 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Rasterize(RcHeightfield hf, RcContext context)
|
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < triangles.Length; i += 3)
|
for (int i = 0; i < triangles.Length; i += 3)
|
||||||
{
|
{
|
||||||
RcRasterizations.RasterizeTriangle(context, vertices, triangles[i], triangles[i + 1], triangles[i + 2], area,
|
RcRasterizations.RasterizeTriangle(hf, vertices, triangles[i], triangles[i + 1], triangles[i + 2], area,
|
||||||
hf, (int)MathF.Floor(flagMergeThreshold / hf.ch));
|
(int)MathF.Floor(flagMergeThreshold / hf.ch), telemetry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,6 @@ namespace DotRecast.Detour.Dynamic.Colliders
|
||||||
public interface IDtCollider
|
public interface IDtCollider
|
||||||
{
|
{
|
||||||
float[] Bounds();
|
float[] Bounds();
|
||||||
void Rasterize(RcHeightfield hf, RcContext context);
|
void Rasterize(RcHeightfield hf, RcTelemetry telemetry);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,12 +5,11 @@
|
||||||
<PackageId>DotRecast.Detour.Dynamic</PackageId>
|
<PackageId>DotRecast.Detour.Dynamic</PackageId>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Authors>ikpil</Authors>
|
<Authors>ikpil</Authors>
|
||||||
<Description>DotRecast - a port of Recast Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers</Description>
|
<Description>DotRecast - a port of Recast Detour, navigation mesh toolset for games, Unity3D, servers, C#</Description>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
||||||
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
||||||
<PackageReleaseNotes>https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md</PackageReleaseNotes>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace DotRecast.Detour.Dynamic
|
||||||
public readonly DtDynamicNavMeshConfig config;
|
public readonly DtDynamicNavMeshConfig config;
|
||||||
private readonly RcBuilder builder;
|
private readonly RcBuilder builder;
|
||||||
private readonly Dictionary<long, DtDynamicTile> _tiles = new Dictionary<long, DtDynamicTile>();
|
private readonly Dictionary<long, DtDynamicTile> _tiles = new Dictionary<long, DtDynamicTile>();
|
||||||
private readonly RcContext _context;
|
private readonly RcTelemetry telemetry;
|
||||||
private readonly DtNavMeshParams navMeshParams;
|
private readonly DtNavMeshParams navMeshParams;
|
||||||
private readonly BlockingCollection<IDtDaynmicTileJob> updateQueue = new BlockingCollection<IDtDaynmicTileJob>();
|
private readonly BlockingCollection<IDtDaynmicTileJob> updateQueue = new BlockingCollection<IDtDaynmicTileJob>();
|
||||||
private readonly RcAtomicLong currentColliderId = new RcAtomicLong(0);
|
private readonly RcAtomicLong currentColliderId = new RcAtomicLong(0);
|
||||||
|
@ -72,7 +72,7 @@ namespace DotRecast.Detour.Dynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
;
|
;
|
||||||
_context = new RcContext();
|
telemetry = new RcTelemetry();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtNavMesh NavMesh()
|
public DtNavMesh NavMesh()
|
||||||
|
@ -218,7 +218,7 @@ namespace DotRecast.Detour.Dynamic
|
||||||
{
|
{
|
||||||
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
|
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
|
||||||
option.walkableHeight = config.walkableHeight;
|
option.walkableHeight = config.walkableHeight;
|
||||||
dirty = dirty | tile.Build(builder, config, _context);
|
dirty = dirty | tile.Build(builder, config, telemetry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool UpdateNavMesh()
|
private bool UpdateNavMesh()
|
||||||
|
|
|
@ -44,12 +44,12 @@ namespace DotRecast.Detour.Dynamic
|
||||||
this.voxelTile = voxelTile;
|
this.voxelTile = voxelTile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Build(RcBuilder builder, DtDynamicNavMeshConfig config, RcContext context)
|
public bool Build(RcBuilder builder, DtDynamicNavMeshConfig config, RcTelemetry telemetry)
|
||||||
{
|
{
|
||||||
if (dirty)
|
if (dirty)
|
||||||
{
|
{
|
||||||
RcHeightfield heightfield = BuildHeightfield(config, context);
|
RcHeightfield heightfield = BuildHeightfield(config, telemetry);
|
||||||
RcBuilderResult r = BuildRecast(builder, config, voxelTile, heightfield, context);
|
RcBuilderResult r = BuildRecast(builder, config, voxelTile, heightfield, telemetry);
|
||||||
DtNavMeshCreateParams option = NavMeshCreateParams(voxelTile.tileX, voxelTile.tileZ, voxelTile.cellSize,
|
DtNavMeshCreateParams option = NavMeshCreateParams(voxelTile.tileX, voxelTile.tileZ, voxelTile.cellSize,
|
||||||
voxelTile.cellHeight, config, r);
|
voxelTile.cellHeight, config, r);
|
||||||
meshData = DtNavMeshBuilder.CreateNavMeshData(option);
|
meshData = DtNavMeshBuilder.CreateNavMeshData(option);
|
||||||
|
@ -59,7 +59,7 @@ namespace DotRecast.Detour.Dynamic
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RcHeightfield BuildHeightfield(DtDynamicNavMeshConfig config, RcContext context)
|
private RcHeightfield BuildHeightfield(DtDynamicNavMeshConfig config, RcTelemetry telemetry)
|
||||||
{
|
{
|
||||||
ICollection<long> rasterizedColliders = checkpoint != null
|
ICollection<long> rasterizedColliders = checkpoint != null
|
||||||
? checkpoint.colliders as ICollection<long>
|
? checkpoint.colliders as ICollection<long>
|
||||||
|
@ -74,7 +74,7 @@ namespace DotRecast.Detour.Dynamic
|
||||||
if (!rasterizedColliders.Contains(cid))
|
if (!rasterizedColliders.Contains(cid))
|
||||||
{
|
{
|
||||||
heightfield.bmax.Y = Math.Max(heightfield.bmax.Y, c.Bounds()[4] + heightfield.ch * 2);
|
heightfield.bmax.Y = Math.Max(heightfield.bmax.Y, c.Bounds()[4] + heightfield.ch * 2);
|
||||||
c.Rasterize(heightfield, context);
|
c.Rasterize(heightfield, telemetry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ namespace DotRecast.Detour.Dynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
private RcBuilderResult BuildRecast(RcBuilder builder, DtDynamicNavMeshConfig config, DtVoxelTile vt,
|
private RcBuilderResult BuildRecast(RcBuilder builder, DtDynamicNavMeshConfig config, DtVoxelTile vt,
|
||||||
RcHeightfield heightfield, RcContext context)
|
RcHeightfield heightfield, RcTelemetry telemetry)
|
||||||
{
|
{
|
||||||
RcConfig rcConfig = new RcConfig(
|
RcConfig rcConfig = new RcConfig(
|
||||||
config.useTiles, config.tileSizeX, config.tileSizeZ,
|
config.useTiles, config.tileSizeX, config.tileSizeZ,
|
||||||
|
@ -100,7 +100,7 @@ namespace DotRecast.Detour.Dynamic
|
||||||
Math.Min(DtDynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly),
|
Math.Min(DtDynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly),
|
||||||
config.detailSampleDistance, config.detailSampleMaxError,
|
config.detailSampleDistance, config.detailSampleMaxError,
|
||||||
true, true, true, default, true);
|
true, true, true, default, true);
|
||||||
RcBuilderResult r = builder.Build(context, vt.tileX, vt.tileZ, null, rcConfig, heightfield);
|
RcBuilderResult r = builder.Build(vt.tileX, vt.tileZ, null, rcConfig, heightfield, telemetry);
|
||||||
if (config.keepIntermediateResults)
|
if (config.keepIntermediateResults)
|
||||||
{
|
{
|
||||||
recastResult = r;
|
recastResult = r;
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic
|
namespace DotRecast.Detour.Dynamic
|
||||||
|
@ -30,12 +31,12 @@ namespace DotRecast.Detour.Dynamic
|
||||||
*/
|
*/
|
||||||
public class DtVoxelQuery
|
public class DtVoxelQuery
|
||||||
{
|
{
|
||||||
private readonly RcVec3f origin;
|
private readonly Vector3 origin;
|
||||||
private readonly float tileWidth;
|
private readonly float tileWidth;
|
||||||
private readonly float tileDepth;
|
private readonly float tileDepth;
|
||||||
private readonly Func<int, int, RcHeightfield> heightfieldProvider;
|
private readonly Func<int, int, RcHeightfield> heightfieldProvider;
|
||||||
|
|
||||||
public DtVoxelQuery(RcVec3f origin, float tileWidth, float tileDepth, Func<int, int, RcHeightfield> heightfieldProvider)
|
public DtVoxelQuery(Vector3 origin, float tileWidth, float tileDepth, Func<int, int, RcHeightfield> heightfieldProvider)
|
||||||
{
|
{
|
||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
this.tileWidth = tileWidth;
|
this.tileWidth = tileWidth;
|
||||||
|
@ -48,12 +49,12 @@ namespace DotRecast.Detour.Dynamic
|
||||||
*
|
*
|
||||||
* @return Optional with hit parameter (t) or empty if no hit found
|
* @return Optional with hit parameter (t) or empty if no hit found
|
||||||
*/
|
*/
|
||||||
public bool Raycast(RcVec3f start, RcVec3f end, out float hit)
|
public bool Raycast(Vector3 start, Vector3 end, out float hit)
|
||||||
{
|
{
|
||||||
return TraverseTiles(start, end, out hit);
|
return TraverseTiles(start, end, out hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TraverseTiles(RcVec3f start, RcVec3f end, out float hit)
|
private bool TraverseTiles(Vector3 start, Vector3 end, out float hit)
|
||||||
{
|
{
|
||||||
float relStartX = start.X - origin.X;
|
float relStartX = start.X - origin.X;
|
||||||
float relStartZ = start.Z - origin.Z;
|
float relStartZ = start.Z - origin.Z;
|
||||||
|
@ -108,7 +109,7 @@ namespace DotRecast.Detour.Dynamic
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TraversHeightfield(int x, int z, RcVec3f start, RcVec3f end, float tMin, float tMax, out float hit)
|
private bool TraversHeightfield(int x, int z, Vector3 start, Vector3 end, float tMin, float tMax, out float hit)
|
||||||
{
|
{
|
||||||
RcHeightfield hf = heightfieldProvider.Invoke(x, z);
|
RcHeightfield hf = heightfieldProvider.Invoke(x, z);
|
||||||
if (null != hf)
|
if (null != hf)
|
||||||
|
|
|
@ -21,6 +21,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Io
|
namespace DotRecast.Detour.Dynamic.Io
|
||||||
|
@ -54,7 +55,7 @@ namespace DotRecast.Detour.Dynamic.Io
|
||||||
public bool useTiles;
|
public bool useTiles;
|
||||||
public int tileSizeX;
|
public int tileSizeX;
|
||||||
public int tileSizeZ;
|
public int tileSizeZ;
|
||||||
public RcVec3f rotation = new RcVec3f();
|
public Vector3 rotation = new Vector3();
|
||||||
public float[] bounds = new float[6];
|
public float[] bounds = new float[6];
|
||||||
public readonly List<DtVoxelTile> tiles = new List<DtVoxelTile>();
|
public readonly List<DtVoxelTile> tiles = new List<DtVoxelTile>();
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Io;
|
using DotRecast.Detour.Io;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Io
|
namespace DotRecast.Detour.Dynamic.Io
|
||||||
|
@ -108,11 +109,11 @@ namespace DotRecast.Detour.Dynamic.Io
|
||||||
int width = buf.GetInt();
|
int width = buf.GetInt();
|
||||||
int depth = buf.GetInt();
|
int depth = buf.GetInt();
|
||||||
int borderSize = buf.GetInt();
|
int borderSize = buf.GetInt();
|
||||||
RcVec3f boundsMin = new RcVec3f();
|
Vector3 boundsMin = new Vector3();
|
||||||
boundsMin.X = buf.GetFloat();
|
boundsMin.X = buf.GetFloat();
|
||||||
boundsMin.Y = buf.GetFloat();
|
boundsMin.Y = buf.GetFloat();
|
||||||
boundsMin.Z = buf.GetFloat();
|
boundsMin.Z = buf.GetFloat();
|
||||||
RcVec3f boundsMax = new RcVec3f();
|
Vector3 boundsMax = new Vector3();
|
||||||
boundsMax.X = buf.GetFloat();
|
boundsMax.X = buf.GetFloat();
|
||||||
boundsMax.Y = buf.GetFloat();
|
boundsMax.Y = buf.GetFloat();
|
||||||
boundsMax.Z = buf.GetFloat();
|
boundsMax.Z = buf.GetFloat();
|
||||||
|
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Io;
|
using DotRecast.Detour.Io;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Io
|
namespace DotRecast.Detour.Dynamic.Io
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Io
|
namespace DotRecast.Detour.Dynamic.Io
|
||||||
|
@ -32,13 +33,13 @@ namespace DotRecast.Detour.Dynamic.Io
|
||||||
public readonly int borderSize;
|
public readonly int borderSize;
|
||||||
public int width;
|
public int width;
|
||||||
public int depth;
|
public int depth;
|
||||||
public readonly RcVec3f boundsMin;
|
public readonly Vector3 boundsMin;
|
||||||
public RcVec3f boundsMax;
|
public Vector3 boundsMax;
|
||||||
public float cellSize;
|
public float cellSize;
|
||||||
public float cellHeight;
|
public float cellHeight;
|
||||||
public readonly byte[] spanData;
|
public readonly byte[] spanData;
|
||||||
|
|
||||||
public DtVoxelTile(int tileX, int tileZ, int width, int depth, RcVec3f boundsMin, RcVec3f boundsMax, float cellSize,
|
public DtVoxelTile(int tileX, int tileZ, int width, int depth, Vector3 boundsMin, Vector3 boundsMax, float cellSize,
|
||||||
float cellHeight, int borderSize, RcByteBuffer buffer)
|
float cellHeight, int borderSize, RcByteBuffer buffer)
|
||||||
{
|
{
|
||||||
this.tileX = tileX;
|
this.tileX = tileX;
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras
|
namespace DotRecast.Detour.Extras
|
||||||
{
|
{
|
||||||
|
@ -40,8 +41,8 @@ namespace DotRecast.Detour.Extras
|
||||||
BVItem it = new BVItem();
|
BVItem it = new BVItem();
|
||||||
items[i] = it;
|
items[i] = it;
|
||||||
it.i = i;
|
it.i = i;
|
||||||
RcVec3f bmin = RcVecUtils.Create(data.verts, data.polys[i].verts[0] * 3);
|
Vector3 bmin = RcVecUtils.Create(data.verts, data.polys[i].verts[0] * 3);
|
||||||
RcVec3f bmax = RcVecUtils.Create(data.verts, data.polys[i].verts[0] * 3);
|
Vector3 bmax = RcVecUtils.Create(data.verts, data.polys[i].verts[0] * 3);
|
||||||
for (int j = 1; j < data.polys[i].vertCount; j++)
|
for (int j = 1; j < data.polys[i].vertCount; j++)
|
||||||
{
|
{
|
||||||
bmin = RcVecUtils.Min(bmin, data.verts, data.polys[i].verts[j] * 3);
|
bmin = RcVecUtils.Min(bmin, data.verts, data.polys[i].verts[j] * 3);
|
||||||
|
|
|
@ -5,12 +5,11 @@
|
||||||
<PackageId>DotRecast.Detour.Extras</PackageId>
|
<PackageId>DotRecast.Detour.Extras</PackageId>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Authors>ikpil</Authors>
|
<Authors>ikpil</Authors>
|
||||||
<Description>DotRecast - a port of Recast Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers</Description>
|
<Description>DotRecast - a port of Recast Detour, navigation mesh toolset for games, Unity3D, servers, C#</Description>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
||||||
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
||||||
<PackageReleaseNotes>https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md</PackageReleaseNotes>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Jumplink
|
namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
public abstract class AbstractGroundSampler : IGroundSampler
|
public abstract class AbstractGroundSampler : IGroundSampler
|
||||||
{
|
{
|
||||||
public delegate bool ComputeNavMeshHeight(RcVec3f pt, float cellSize, out float height);
|
public delegate bool ComputeNavMeshHeight(Vector3 pt, float cellSize, out float height);
|
||||||
|
|
||||||
protected void SampleGround(JumpLinkBuilderConfig acfg, EdgeSampler es, ComputeNavMeshHeight heightFunc)
|
protected void SampleGround(JumpLinkBuilderConfig acfg, EdgeSampler es, ComputeNavMeshHeight heightFunc)
|
||||||
{
|
{
|
||||||
|
@ -33,7 +34,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
|
|
||||||
GroundSample s = new GroundSample();
|
GroundSample s = new GroundSample();
|
||||||
seg.gsamples[i] = s;
|
seg.gsamples[i] = s;
|
||||||
RcVec3f pt = RcVec3f.Lerp(seg.p, seg.q, u);
|
Vector3 pt = Vector3.Lerp(seg.p, seg.q, u);
|
||||||
bool success = heightFunc.Invoke(pt, seg.height, out var height);
|
bool success = heightFunc.Invoke(pt, seg.height, out var height);
|
||||||
s.p.X = pt.X;
|
s.p.X = pt.X;
|
||||||
s.p.Y = height;
|
s.p.Y = height;
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Jumplink
|
namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
public class ClimbTrajectory : Trajectory
|
public class ClimbTrajectory : Trajectory
|
||||||
{
|
{
|
||||||
public override RcVec3f Apply(RcVec3f start, RcVec3f end, float u)
|
public override Vector3 Apply(Vector3 start, Vector3 end, float u)
|
||||||
{
|
{
|
||||||
return new RcVec3f()
|
return new Vector3()
|
||||||
{
|
{
|
||||||
X = Lerp(start.X, end.X, Math.Min(2f * u, 1f)),
|
X = Lerp(start.X, end.X, Math.Min(2f * u, 1f)),
|
||||||
Y = Lerp(start.Y, end.Y, Math.Max(0f, 2f * u - 1f)),
|
Y = Lerp(start.Y, end.Y, Math.Max(0f, 2f * u - 1f)),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
using static DotRecast.Recast.RcConstants;
|
using static DotRecast.Recast.RcConstants;
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
List<JumpEdge> edges = new List<JumpEdge>();
|
List<JumpEdge> edges = new List<JumpEdge>();
|
||||||
if (mesh != null)
|
if (mesh != null)
|
||||||
{
|
{
|
||||||
RcVec3f orig = mesh.bmin;
|
Vector3 orig = mesh.bmin;
|
||||||
float cs = mesh.cs;
|
float cs = mesh.cs;
|
||||||
float ch = mesh.ch;
|
float ch = mesh.ch;
|
||||||
for (int i = 0; i < mesh.npolys; i++)
|
for (int i = 0; i < mesh.npolys; i++)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Jumplink
|
namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
|
@ -9,20 +10,20 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
public readonly List<GroundSegment> end = new List<GroundSegment>();
|
public readonly List<GroundSegment> end = new List<GroundSegment>();
|
||||||
public readonly Trajectory trajectory;
|
public readonly Trajectory trajectory;
|
||||||
|
|
||||||
public readonly RcVec3f ax = new RcVec3f();
|
public readonly Vector3 ax = new Vector3();
|
||||||
public readonly RcVec3f ay = new RcVec3f();
|
public readonly Vector3 ay = new Vector3();
|
||||||
public readonly RcVec3f az = new RcVec3f();
|
public readonly Vector3 az = new Vector3();
|
||||||
|
|
||||||
public EdgeSampler(JumpEdge edge, Trajectory trajectory)
|
public EdgeSampler(JumpEdge edge, Trajectory trajectory)
|
||||||
{
|
{
|
||||||
this.trajectory = trajectory;
|
this.trajectory = trajectory;
|
||||||
ax = RcVec3f.Subtract(edge.sq, edge.sp);
|
ax = Vector3.Subtract(edge.sq, edge.sp);
|
||||||
ax = RcVec3f.Normalize(ax);
|
ax = Vector3.Normalize(ax);
|
||||||
|
|
||||||
az = new RcVec3f(ax.Z, 0, -ax.X);
|
az = new Vector3(ax.Z, 0, -ax.X);
|
||||||
az = RcVec3f.Normalize(az);
|
az = Vector3.Normalize(az);
|
||||||
|
|
||||||
ay = new RcVec3f(0, 1, 0);
|
ay = new Vector3(0, 1, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Jumplink
|
namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
|
@ -29,8 +30,8 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
EdgeSampler es = new EdgeSampler(edge, new JumpTrajectory(acfg.jumpHeight));
|
EdgeSampler es = new EdgeSampler(edge, new JumpTrajectory(acfg.jumpHeight));
|
||||||
es.start.height = acfg.agentClimb * 2;
|
es.start.height = acfg.agentClimb * 2;
|
||||||
RcVec3f offset = new RcVec3f();
|
Vector3 offset = new Vector3();
|
||||||
Trans2d(ref offset, es.az, es.ay, new RcVec2f { X = acfg.startDistance, Y = -acfg.agentClimb, });
|
Trans2d(ref offset, es.az, es.ay, new Vector2 { X = acfg.startDistance, Y = -acfg.agentClimb, });
|
||||||
Vadd(ref es.start.p, edge.sp, offset);
|
Vadd(ref es.start.p, edge.sp, offset);
|
||||||
Vadd(ref es.start.q, edge.sq, offset);
|
Vadd(ref es.start.q, edge.sq, offset);
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
float v = (float)j / (float)(nsamples - 1);
|
float v = (float)j / (float)(nsamples - 1);
|
||||||
float ox = 2 * acfg.agentRadius + dx * v;
|
float ox = 2 * acfg.agentRadius + dx * v;
|
||||||
Trans2d(ref offset, es.az, es.ay, new RcVec2f { X = ox, Y = acfg.minHeight });
|
Trans2d(ref offset, es.az, es.ay, new Vector2 { X = ox, Y = acfg.minHeight });
|
||||||
GroundSegment end = new GroundSegment();
|
GroundSegment end = new GroundSegment();
|
||||||
end.height = acfg.heightRange;
|
end.height = acfg.heightRange;
|
||||||
Vadd(ref end.p, edge.sp, offset);
|
Vadd(ref end.p, edge.sp, offset);
|
||||||
|
@ -57,12 +58,12 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
EdgeSampler es = new EdgeSampler(edge, new ClimbTrajectory());
|
EdgeSampler es = new EdgeSampler(edge, new ClimbTrajectory());
|
||||||
es.start.height = acfg.agentClimb * 2;
|
es.start.height = acfg.agentClimb * 2;
|
||||||
RcVec3f offset = new RcVec3f();
|
Vector3 offset = new Vector3();
|
||||||
Trans2d(ref offset, es.az, es.ay, new RcVec2f() { X = acfg.startDistance, Y = -acfg.agentClimb });
|
Trans2d(ref offset, es.az, es.ay, new Vector2() { X = acfg.startDistance, Y = -acfg.agentClimb });
|
||||||
Vadd(ref es.start.p, edge.sp, offset);
|
Vadd(ref es.start.p, edge.sp, offset);
|
||||||
Vadd(ref es.start.q, edge.sq, offset);
|
Vadd(ref es.start.q, edge.sq, offset);
|
||||||
|
|
||||||
Trans2d(ref offset, es.az, es.ay, new RcVec2f() { X = acfg.endDistance, Y = acfg.minHeight });
|
Trans2d(ref offset, es.az, es.ay, new Vector2() { X = acfg.endDistance, Y = acfg.minHeight });
|
||||||
GroundSegment end = new GroundSegment();
|
GroundSegment end = new GroundSegment();
|
||||||
end.height = acfg.heightRange;
|
end.height = acfg.heightRange;
|
||||||
Vadd(ref end.p, edge.sp, offset);
|
Vadd(ref end.p, edge.sp, offset);
|
||||||
|
@ -78,7 +79,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
dest[2] = v1[2] + v2[2];
|
dest[2] = v1[2] + v2[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Vadd(ref RcVec3f dest, RcVec3f v1, RcVec3f v2)
|
private void Vadd(ref Vector3 dest, Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
dest.X = v1.X + v2.X;
|
dest.X = v1.X + v2.X;
|
||||||
dest.Y = v1.Y + v2.Y;
|
dest.Y = v1.Y + v2.Y;
|
||||||
|
@ -93,7 +94,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
dst[2] = ax[2] * pt[0] + ay[2] * pt[1];
|
dst[2] = ax[2] * pt[0] + ay[2] * pt[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Trans2d(ref RcVec3f dst, RcVec3f ax, RcVec3f ay, RcVec2f pt)
|
private void Trans2d(ref Vector3 dst, Vector3 ax, Vector3 ay, Vector2 pt)
|
||||||
{
|
{
|
||||||
dst.X = ax.X * pt.X + ay.X * pt.Y;
|
dst.X = ax.X * pt.X + ay.X * pt.Y;
|
||||||
dst.Y = ax.Y * pt.X + ay.Y * pt.Y;
|
dst.Y = ax.Y * pt.X + ay.Y * pt.Y;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Jumplink
|
namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
public class GroundSample
|
public class GroundSample
|
||||||
{
|
{
|
||||||
public RcVec3f p = new RcVec3f();
|
public Vector3 p = new Vector3();
|
||||||
public bool validTrajectory;
|
public bool validTrajectory;
|
||||||
public bool validHeight;
|
public bool validHeight;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Jumplink
|
namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
public class GroundSegment
|
public class GroundSegment
|
||||||
{
|
{
|
||||||
public RcVec3f p = new RcVec3f();
|
public Vector3 p = new Vector3();
|
||||||
public RcVec3f q = new RcVec3f();
|
public Vector3 q = new Vector3();
|
||||||
public GroundSample[] gsamples;
|
public GroundSample[] gsamples;
|
||||||
public float height;
|
public float height;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Jumplink
|
namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
public class JumpEdge
|
public class JumpEdge
|
||||||
{
|
{
|
||||||
public RcVec3f sp = new RcVec3f();
|
public Vector3 sp = new Vector3();
|
||||||
public RcVec3f sq = new RcVec3f();
|
public Vector3 sq = new Vector3();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Jumplink
|
namespace DotRecast.Detour.Extras.Jumplink
|
||||||
|
@ -54,11 +55,11 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
List<JumpLink> links = new List<JumpLink>();
|
List<JumpLink> links = new List<JumpLink>();
|
||||||
foreach (JumpSegment js in jumpSegments)
|
foreach (JumpSegment js in jumpSegments)
|
||||||
{
|
{
|
||||||
RcVec3f sp = es.start.gsamples[js.startSample].p;
|
Vector3 sp = es.start.gsamples[js.startSample].p;
|
||||||
RcVec3f sq = es.start.gsamples[js.startSample + js.samples - 1].p;
|
Vector3 sq = es.start.gsamples[js.startSample + js.samples - 1].p;
|
||||||
GroundSegment end = es.end[js.groundSegment];
|
GroundSegment end = es.end[js.groundSegment];
|
||||||
RcVec3f ep = end.gsamples[js.startSample].p;
|
Vector3 ep = end.gsamples[js.startSample].p;
|
||||||
RcVec3f eq = end.gsamples[js.startSample + js.samples - 1].p;
|
Vector3 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(RcVecUtils.Dist2DSqr(sp, sq), RcVecUtils.Dist2DSqr(ep, eq));
|
||||||
if (d >= 4 * acfg.agentRadius * acfg.agentRadius)
|
if (d >= 4 * acfg.agentRadius * acfg.agentRadius)
|
||||||
{
|
{
|
||||||
|
@ -72,7 +73,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
for (int j = 0; j < link.nspine; ++j)
|
for (int j = 0; j < link.nspine; ++j)
|
||||||
{
|
{
|
||||||
float u = ((float)j) / (link.nspine - 1);
|
float u = ((float)j) / (link.nspine - 1);
|
||||||
RcVec3f p = es.trajectory.Apply(sp, ep, u);
|
Vector3 p = es.trajectory.Apply(sp, ep, u);
|
||||||
link.spine0[j * 3] = p.X;
|
link.spine0[j * 3] = p.X;
|
||||||
link.spine0[j * 3 + 1] = p.Y;
|
link.spine0[j * 3 + 1] = p.Y;
|
||||||
link.spine0[j * 3 + 2] = p.Z;
|
link.spine0[j * 3 + 2] = p.Z;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Jumplink
|
namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
|
@ -12,9 +13,9 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
this.jumpHeight = jumpHeight;
|
this.jumpHeight = jumpHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override RcVec3f Apply(RcVec3f start, RcVec3f end, float u)
|
public override Vector3 Apply(Vector3 start, Vector3 end, float u)
|
||||||
{
|
{
|
||||||
return new RcVec3f
|
return new Vector3
|
||||||
{
|
{
|
||||||
X = Lerp(start.X, end.X, u),
|
X = Lerp(start.X, end.X, u),
|
||||||
Y = InterpolateHeight(start.Y, end.Y, u),
|
Y = InterpolateHeight(start.Y, end.Y, u),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
public override void Sample(JumpLinkBuilderConfig acfg, RcBuilderResult result, EdgeSampler es)
|
public override void Sample(JumpLinkBuilderConfig acfg, RcBuilderResult result, EdgeSampler es)
|
||||||
{
|
{
|
||||||
DtNavMeshQuery navMeshQuery = CreateNavMesh(result, acfg.agentRadius, acfg.agentHeight, acfg.agentClimb);
|
DtNavMeshQuery navMeshQuery = CreateNavMesh(result, acfg.agentRadius, acfg.agentHeight, acfg.agentClimb);
|
||||||
SampleGround(acfg, es, (RcVec3f pt, float heightRange, out float height) => GetNavMeshHeight(navMeshQuery, pt, acfg.cellSize, heightRange, out height));
|
SampleGround(acfg, es, (Vector3 pt, float heightRange, out float height) => GetNavMeshHeight(navMeshQuery, pt, acfg.cellSize, heightRange, out height));
|
||||||
}
|
}
|
||||||
|
|
||||||
private DtNavMeshQuery CreateNavMesh(RcBuilderResult r, float agentRadius, float agentHeight, float agentClimb)
|
private DtNavMeshQuery CreateNavMesh(RcBuilderResult r, float agentRadius, float agentHeight, float agentClimb)
|
||||||
|
@ -40,11 +41,11 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool GetNavMeshHeight(DtNavMeshQuery navMeshQuery, RcVec3f pt, float cs, float heightRange, out float height)
|
private bool GetNavMeshHeight(DtNavMeshQuery navMeshQuery, Vector3 pt, float cs, float heightRange, out float height)
|
||||||
{
|
{
|
||||||
height = default;
|
height = default;
|
||||||
|
|
||||||
RcVec3f halfExtents = new RcVec3f { X = cs, Y = heightRange, Z = cs };
|
Vector3 halfExtents = new Vector3 { X = cs, Y = heightRange, Z = cs };
|
||||||
float maxHeight = pt.Y + heightRange;
|
float maxHeight = pt.Y + heightRange;
|
||||||
RcAtomicBoolean found = new RcAtomicBoolean();
|
RcAtomicBoolean found = new RcAtomicBoolean();
|
||||||
RcAtomicFloat minHeight = new RcAtomicFloat(pt.Y);
|
RcAtomicFloat minHeight = new RcAtomicFloat(pt.Y);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Jumplink
|
namespace DotRecast.Detour.Extras.Jumplink
|
||||||
{
|
{
|
||||||
|
@ -10,7 +11,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
return u * g + (1f - u) * f;
|
return u * g + (1f - u) * f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual RcVec3f Apply(RcVec3f start, RcVec3f end, float u)
|
public virtual Vector3 Apply(Vector3 start, Vector3 end, float u)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ 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, Vector3 pa, Vector3 pb, Trajectory tra)
|
||||||
{
|
{
|
||||||
float cs = Math.Min(acfg.cellSize, acfg.cellHeight);
|
float cs = Math.Min(acfg.cellSize, acfg.cellHeight);
|
||||||
float d = RcVecUtils.Dist2D(pa, pb) + MathF.Abs(pa.Y - pb.Y);
|
float d = RcVecUtils.Dist2D(pa, pb) + MathF.Abs(pa.Y - pb.Y);
|
||||||
|
@ -40,7 +41,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
for (int i = 0; i < nsamples; ++i)
|
for (int i = 0; i < nsamples; ++i)
|
||||||
{
|
{
|
||||||
float u = (float)i / (float)(nsamples - 1);
|
float u = (float)i / (float)(nsamples - 1);
|
||||||
RcVec3f p = tra.Apply(pa, pb, u);
|
Vector3 p = tra.Apply(pa, pb, u);
|
||||||
if (CheckHeightfieldCollision(solid, p.X, p.Y + acfg.groundTolerance, p.Y + acfg.agentHeight, p.Z))
|
if (CheckHeightfieldCollision(solid, p.X, p.Y + acfg.groundTolerance, p.Y + acfg.agentHeight, p.Z))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -56,7 +57,7 @@ namespace DotRecast.Detour.Extras.Jumplink
|
||||||
int h = solid.height;
|
int h = solid.height;
|
||||||
float cs = solid.cs;
|
float cs = solid.cs;
|
||||||
float ch = solid.ch;
|
float ch = solid.ch;
|
||||||
RcVec3f orig = solid.bmin;
|
Vector3 orig = solid.bmin;
|
||||||
int ix = (int)MathF.Floor((x - orig.X) / cs);
|
int ix = (int)MathF.Floor((x - orig.X) / cs);
|
||||||
int iz = (int)MathF.Floor((z - orig.Z) / cs);
|
int iz = (int)MathF.Floor((z - orig.Z) / cs);
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Unity.Astar
|
namespace DotRecast.Detour.Extras.Unity.Astar
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,6 +17,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Unity.Astar
|
namespace DotRecast.Detour.Extras.Unity.Astar
|
||||||
{
|
{
|
||||||
|
@ -25,10 +26,10 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
||||||
public readonly long linkID;
|
public readonly long linkID;
|
||||||
public readonly int startNode;
|
public readonly int startNode;
|
||||||
public readonly int endNode;
|
public readonly int endNode;
|
||||||
public readonly RcVec3f clamped1;
|
public readonly Vector3 clamped1;
|
||||||
public readonly RcVec3f clamped2;
|
public readonly Vector3 clamped2;
|
||||||
|
|
||||||
public NodeLink2(long linkID, int startNode, int endNode, RcVec3f clamped1, RcVec3f clamped2) : base()
|
public NodeLink2(long linkID, int startNode, int endNode, Vector3 clamped1, Vector3 clamped2) : base()
|
||||||
{
|
{
|
||||||
this.linkID = linkID;
|
this.linkID = linkID;
|
||||||
this.startNode = startNode;
|
this.startNode = startNode;
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Unity.Astar
|
namespace DotRecast.Detour.Extras.Unity.Astar
|
||||||
{
|
{
|
||||||
|
@ -36,11 +37,11 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
||||||
int endNode = indexToNode[buffer.GetInt()];
|
int endNode = indexToNode[buffer.GetInt()];
|
||||||
int connectedNode1 = buffer.GetInt();
|
int connectedNode1 = buffer.GetInt();
|
||||||
int connectedNode2 = buffer.GetInt();
|
int connectedNode2 = buffer.GetInt();
|
||||||
RcVec3f clamped1 = new RcVec3f();
|
Vector3 clamped1 = new Vector3();
|
||||||
clamped1.X = buffer.GetFloat();
|
clamped1.X = buffer.GetFloat();
|
||||||
clamped1.Y = buffer.GetFloat();
|
clamped1.Y = buffer.GetFloat();
|
||||||
clamped1.Z = buffer.GetFloat();
|
clamped1.Z = buffer.GetFloat();
|
||||||
RcVec3f clamped2 = new RcVec3f();
|
Vector3 clamped2 = new Vector3();
|
||||||
clamped2.X = buffer.GetFloat();
|
clamped2.X = buffer.GetFloat();
|
||||||
clamped2.Y = buffer.GetFloat();
|
clamped2.Y = buffer.GetFloat();
|
||||||
clamped2.Z = buffer.GetFloat();
|
clamped2.Z = buffer.GetFloat();
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Unity.Astar
|
namespace DotRecast.Detour.Extras.Unity.Astar
|
||||||
{
|
{
|
||||||
|
@ -48,7 +49,7 @@ namespace DotRecast.Detour.Extras.Unity.Astar
|
||||||
startTile.header.vertCount += 2;
|
startTile.header.vertCount += 2;
|
||||||
DtOffMeshConnection connection = new DtOffMeshConnection();
|
DtOffMeshConnection connection = new DtOffMeshConnection();
|
||||||
connection.poly = poly;
|
connection.poly = poly;
|
||||||
connection.pos = new RcVec3f[]
|
connection.pos = new Vector3[]
|
||||||
{
|
{
|
||||||
l.clamped1, l.clamped2
|
l.clamped1, l.clamped2
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,7 @@ using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Io;
|
using DotRecast.Detour.Io;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Unity.Astar
|
namespace DotRecast.Detour.Extras.Unity.Astar
|
||||||
|
|
|
@ -5,12 +5,11 @@
|
||||||
<PackageId>DotRecast.Detour.TileCache</PackageId>
|
<PackageId>DotRecast.Detour.TileCache</PackageId>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Authors>ikpil</Authors>
|
<Authors>ikpil</Authors>
|
||||||
<Description>DotRecast - a port of Recast Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers</Description>
|
<Description>DotRecast - a port of Recast Detour, navigation mesh toolset for games, Unity3D, servers, C#</Description>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
||||||
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
||||||
<PackageReleaseNotes>https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md</PackageReleaseNotes>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Detour.TileCache
|
||||||
{
|
{
|
||||||
public class RcLayerSweepSpan
|
public class DtLayerSweepSpan
|
||||||
{
|
{
|
||||||
public int ns; // number samples
|
public int ns; // number samples
|
||||||
public int id; // region id
|
public int id; // region id
|
|
@ -22,6 +22,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.TileCache.Io;
|
using DotRecast.Detour.TileCache.Io;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache
|
namespace DotRecast.Detour.TileCache
|
||||||
|
@ -346,7 +347,7 @@ namespace DotRecast.Detour.TileCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cylinder obstacle
|
// Cylinder obstacle
|
||||||
public long AddObstacle(RcVec3f pos, float radius, float height)
|
public long AddObstacle(Vector3 pos, float radius, float height)
|
||||||
{
|
{
|
||||||
DtTileCacheObstacle ob = AllocObstacle();
|
DtTileCacheObstacle ob = AllocObstacle();
|
||||||
ob.type = DtTileCacheObstacleType.CYLINDER;
|
ob.type = DtTileCacheObstacleType.CYLINDER;
|
||||||
|
@ -359,7 +360,7 @@ namespace DotRecast.Detour.TileCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aabb obstacle
|
// Aabb obstacle
|
||||||
public long AddBoxObstacle(RcVec3f bmin, RcVec3f bmax)
|
public long AddBoxObstacle(Vector3 bmin, Vector3 bmax)
|
||||||
{
|
{
|
||||||
DtTileCacheObstacle ob = AllocObstacle();
|
DtTileCacheObstacle ob = AllocObstacle();
|
||||||
ob.type = DtTileCacheObstacleType.BOX;
|
ob.type = DtTileCacheObstacleType.BOX;
|
||||||
|
@ -371,7 +372,7 @@ namespace DotRecast.Detour.TileCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// Box obstacle: can be rotated in Y
|
// Box obstacle: can be rotated in Y
|
||||||
public long AddBoxObstacle(RcVec3f center, RcVec3f extents, float yRadians)
|
public long AddBoxObstacle(Vector3 center, Vector3 extents, float yRadians)
|
||||||
{
|
{
|
||||||
DtTileCacheObstacle ob = AllocObstacle();
|
DtTileCacheObstacle ob = AllocObstacle();
|
||||||
ob.type = DtTileCacheObstacleType.ORIENTED_BOX;
|
ob.type = DtTileCacheObstacleType.ORIENTED_BOX;
|
||||||
|
@ -437,7 +438,7 @@ namespace DotRecast.Detour.TileCache
|
||||||
return m_obstacles[i];
|
return m_obstacles[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<long> QueryTiles(RcVec3f bmin, RcVec3f bmax)
|
private List<long> QueryTiles(Vector3 bmin, Vector3 bmax)
|
||||||
{
|
{
|
||||||
List<long> results = new List<long>();
|
List<long> results = new List<long>();
|
||||||
float tw = m_params.width * m_params.cs;
|
float tw = m_params.width * m_params.cs;
|
||||||
|
@ -454,8 +455,8 @@ namespace DotRecast.Detour.TileCache
|
||||||
foreach (long i in tiles)
|
foreach (long i in tiles)
|
||||||
{
|
{
|
||||||
DtCompressedTile tile = m_tiles[DecodeTileIdTile(i)];
|
DtCompressedTile tile = m_tiles[DecodeTileIdTile(i)];
|
||||||
RcVec3f tbmin = new RcVec3f();
|
Vector3 tbmin = new Vector3();
|
||||||
RcVec3f tbmax = new RcVec3f();
|
Vector3 tbmax = new Vector3();
|
||||||
CalcTightTileBounds(tile.header, ref tbmin, ref tbmax);
|
CalcTightTileBounds(tile.header, ref tbmin, ref tbmax);
|
||||||
if (DtUtils.OverlapBounds(bmin, bmax, tbmin, tbmax))
|
if (DtUtils.OverlapBounds(bmin, bmax, tbmin, tbmax))
|
||||||
{
|
{
|
||||||
|
@ -498,8 +499,8 @@ namespace DotRecast.Detour.TileCache
|
||||||
if (req.action == DtObstacleRequestAction.REQUEST_ADD)
|
if (req.action == DtObstacleRequestAction.REQUEST_ADD)
|
||||||
{
|
{
|
||||||
// Find touched tiles.
|
// Find touched tiles.
|
||||||
RcVec3f bmin = new RcVec3f();
|
Vector3 bmin = new Vector3();
|
||||||
RcVec3f bmax = new RcVec3f();
|
Vector3 bmax = new Vector3();
|
||||||
GetObstacleBounds(ob, ref bmin, ref bmax);
|
GetObstacleBounds(ob, ref bmin, ref bmax);
|
||||||
ob.touched = QueryTiles(bmin, bmax);
|
ob.touched = QueryTiles(bmin, bmax);
|
||||||
// Add tiles to update list.
|
// Add tiles to update list.
|
||||||
|
@ -680,7 +681,7 @@ namespace DotRecast.Detour.TileCache
|
||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalcTightTileBounds(DtTileCacheLayerHeader header, ref RcVec3f bmin, ref RcVec3f bmax)
|
void CalcTightTileBounds(DtTileCacheLayerHeader header, ref Vector3 bmin, ref Vector3 bmax)
|
||||||
{
|
{
|
||||||
float cs = m_params.cs;
|
float cs = m_params.cs;
|
||||||
bmin.X = header.bmin.X + header.minx * cs;
|
bmin.X = header.bmin.X + header.minx * cs;
|
||||||
|
@ -691,7 +692,7 @@ namespace DotRecast.Detour.TileCache
|
||||||
bmax.Z = header.bmin.Z + (header.maxy + 1) * cs;
|
bmax.Z = header.bmin.Z + (header.maxy + 1) * cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetObstacleBounds(DtTileCacheObstacle ob, ref RcVec3f bmin, ref RcVec3f bmax)
|
public void GetObstacleBounds(DtTileCacheObstacle ob, ref Vector3 bmin, ref Vector3 bmax)
|
||||||
{
|
{
|
||||||
if (ob.type == DtTileCacheObstacleType.CYLINDER)
|
if (ob.type == DtTileCacheObstacleType.CYLINDER)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,8 +23,9 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.TileCache.Io;
|
using DotRecast.Detour.TileCache.Io;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Detour.TileCache.Io.Compress;
|
||||||
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache
|
namespace DotRecast.Detour.TileCache
|
||||||
|
@ -46,10 +47,10 @@ namespace DotRecast.Detour.TileCache
|
||||||
|
|
||||||
Array.Fill(layer.regs, (short)0x00FF);
|
Array.Fill(layer.regs, (short)0x00FF);
|
||||||
int nsweeps = w;
|
int nsweeps = w;
|
||||||
RcLayerSweepSpan[] sweeps = new RcLayerSweepSpan[nsweeps];
|
DtLayerSweepSpan[] sweeps = new DtLayerSweepSpan[nsweeps];
|
||||||
for (int i = 0; i < sweeps.Length; i++)
|
for (int i = 0; i < sweeps.Length; i++)
|
||||||
{
|
{
|
||||||
sweeps[i] = new RcLayerSweepSpan();
|
sweeps[i] = new DtLayerSweepSpan();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partition walkable area into monotone regions.
|
// Partition walkable area into monotone regions.
|
||||||
|
@ -1801,10 +1802,10 @@ namespace DotRecast.Detour.TileCache
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MarkCylinderArea(DtTileCacheLayer layer, RcVec3f orig, float cs, float ch, RcVec3f pos, float radius, float height, int areaId)
|
public void MarkCylinderArea(DtTileCacheLayer layer, Vector3 orig, float cs, float ch, Vector3 pos, float radius, float height, int areaId)
|
||||||
{
|
{
|
||||||
RcVec3f bmin = new RcVec3f();
|
Vector3 bmin = new Vector3();
|
||||||
RcVec3f bmax = new RcVec3f();
|
Vector3 bmax = new Vector3();
|
||||||
bmin.X = pos.X - radius;
|
bmin.X = pos.X - radius;
|
||||||
bmin.Y = pos.Y;
|
bmin.Y = pos.Y;
|
||||||
bmin.Z = pos.Z - radius;
|
bmin.Z = pos.Z - radius;
|
||||||
|
@ -1862,7 +1863,7 @@ namespace DotRecast.Detour.TileCache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MarkBoxArea(DtTileCacheLayer layer, RcVec3f orig, float cs, float ch, RcVec3f bmin, RcVec3f bmax, int areaId)
|
public void MarkBoxArea(DtTileCacheLayer layer, Vector3 orig, float cs, float ch, Vector3 bmin, Vector3 bmax, int areaId)
|
||||||
{
|
{
|
||||||
int w = layer.header.width;
|
int w = layer.header.width;
|
||||||
int h = layer.header.height;
|
int h = layer.header.height;
|
||||||
|
@ -1990,7 +1991,7 @@ namespace DotRecast.Detour.TileCache
|
||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MarkBoxArea(DtTileCacheLayer layer, RcVec3f orig, float cs, float ch, RcVec3f center, RcVec3f extents,
|
public void MarkBoxArea(DtTileCacheLayer layer, Vector3 orig, float cs, float ch, Vector3 center, Vector3 extents,
|
||||||
float[] rotAux, int areaId)
|
float[] rotAux, int areaId)
|
||||||
{
|
{
|
||||||
int w = layer.header.width;
|
int w = layer.header.width;
|
||||||
|
|
|
@ -24,6 +24,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.TileCache.Io.Compress;
|
using DotRecast.Detour.TileCache.Io.Compress;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
|
@ -87,8 +88,8 @@ namespace DotRecast.Detour.TileCache
|
||||||
protected virtual RcHeightfieldLayerSet BuildHeightfieldLayerSet(IInputGeomProvider geom, RcConfig cfg, int tx, int ty)
|
protected virtual RcHeightfieldLayerSet BuildHeightfieldLayerSet(IInputGeomProvider geom, RcConfig cfg, int tx, int ty)
|
||||||
{
|
{
|
||||||
RcBuilder rcBuilder = new RcBuilder();
|
RcBuilder rcBuilder = new RcBuilder();
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
Vector3 bmin = geom.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
Vector3 bmax = geom.GetMeshBoundsMax();
|
||||||
RcBuilderConfig builderCfg = new RcBuilderConfig(cfg, bmin, bmax, tx, ty);
|
RcBuilderConfig builderCfg = new RcBuilderConfig(cfg, bmin, bmax, tx, ty);
|
||||||
RcHeightfieldLayerSet lset = rcBuilder.BuildLayers(geom, builderCfg);
|
RcHeightfieldLayerSet lset = rcBuilder.BuildLayers(geom, builderCfg);
|
||||||
return lset;
|
return lset;
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache
|
namespace DotRecast.Detour.TileCache
|
||||||
{
|
{
|
||||||
|
@ -31,8 +32,8 @@ namespace DotRecast.Detour.TileCache
|
||||||
public int version; // < Data version
|
public int version; // < Data version
|
||||||
public int tx, ty, tlayer;
|
public int tx, ty, tlayer;
|
||||||
|
|
||||||
public RcVec3f bmin = new RcVec3f();
|
public Vector3 bmin = new Vector3();
|
||||||
public RcVec3f bmax = new RcVec3f();
|
public Vector3 bmax = new Vector3();
|
||||||
public int hmin, hmax; // < Height min/max range
|
public int hmin, hmax; // < Height min/max range
|
||||||
public int width, height; // < Dimension of the layer.
|
public int width, height; // < Dimension of the layer.
|
||||||
public int minx, maxx, miny, maxy; // < Usable sub-region.
|
public int minx, maxx, miny, maxy; // < Usable sub-region.
|
||||||
|
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache
|
namespace DotRecast.Detour.TileCache
|
||||||
{
|
{
|
||||||
|
@ -27,12 +28,12 @@ namespace DotRecast.Detour.TileCache
|
||||||
{
|
{
|
||||||
public readonly int index;
|
public readonly int index;
|
||||||
public DtTileCacheObstacleType type;
|
public DtTileCacheObstacleType type;
|
||||||
public RcVec3f pos = new RcVec3f();
|
public Vector3 pos = new Vector3();
|
||||||
public RcVec3f bmin = new RcVec3f();
|
public Vector3 bmin = new Vector3();
|
||||||
public RcVec3f bmax = new RcVec3f();
|
public Vector3 bmax = new Vector3();
|
||||||
public float radius, height;
|
public float radius, height;
|
||||||
public RcVec3f center = new RcVec3f();
|
public Vector3 center = new Vector3();
|
||||||
public RcVec3f extents = new RcVec3f();
|
public Vector3 extents = new Vector3();
|
||||||
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 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 List<long> touched = new List<long>();
|
public List<long> touched = new List<long>();
|
||||||
|
|
|
@ -19,12 +19,13 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache
|
namespace DotRecast.Detour.TileCache
|
||||||
{
|
{
|
||||||
public struct DtTileCacheParams
|
public struct DtTileCacheParams
|
||||||
{
|
{
|
||||||
public RcVec3f orig;
|
public Vector3 orig;
|
||||||
public float cs, ch;
|
public float cs, ch;
|
||||||
public int width, height;
|
public int width, height;
|
||||||
public float walkableHeight;
|
public float walkableHeight;
|
||||||
|
|
|
@ -5,12 +5,11 @@
|
||||||
<PackageId>DotRecast.Detour</PackageId>
|
<PackageId>DotRecast.Detour</PackageId>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Authors>ikpil</Authors>
|
<Authors>ikpil</Authors>
|
||||||
<Description>DotRecast - a port of Recast Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers</Description>
|
<Description>DotRecast - a port of Recast Detour, navigation mesh toolset for games, Unity3D, servers, C#</Description>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
||||||
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
||||||
<PackageReleaseNotes>https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md</PackageReleaseNotes>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -37,10 +38,10 @@ namespace DotRecast.Detour
|
||||||
float[] inters = new float[Math.Max(m, n) * 3 * 3];
|
float[] inters = new float[Math.Max(m, n) * 3 * 3];
|
||||||
int ii = 0;
|
int ii = 0;
|
||||||
/* Initialize variables. */
|
/* Initialize variables. */
|
||||||
RcVec3f a = new RcVec3f();
|
Vector3 a = new Vector3();
|
||||||
RcVec3f b = new RcVec3f();
|
Vector3 b = new Vector3();
|
||||||
RcVec3f a1 = new RcVec3f();
|
Vector3 a1 = new Vector3();
|
||||||
RcVec3f b1 = new RcVec3f();
|
Vector3 b1 = new Vector3();
|
||||||
|
|
||||||
int aa = 0;
|
int aa = 0;
|
||||||
int ba = 0;
|
int ba = 0;
|
||||||
|
@ -49,8 +50,8 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
DtConvexConvexInFlag f = DtConvexConvexInFlag.Unknown;
|
DtConvexConvexInFlag f = DtConvexConvexInFlag.Unknown;
|
||||||
bool firstPoint = true;
|
bool firstPoint = true;
|
||||||
RcVec3f ip = new RcVec3f();
|
Vector3 ip = new Vector3();
|
||||||
RcVec3f iq = new RcVec3f();
|
Vector3 iq = new Vector3();
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -59,8 +60,8 @@ namespace DotRecast.Detour
|
||||||
a1 = RcVecUtils.Create(p, 3 * ((ai + n - 1) % n)); // prev a
|
a1 = RcVecUtils.Create(p, 3 * ((ai + n - 1) % n)); // prev a
|
||||||
b1 = RcVecUtils.Create(q, 3 * ((bi + m - 1) % m)); // prev b
|
b1 = RcVecUtils.Create(q, 3 * ((bi + m - 1) % m)); // prev b
|
||||||
|
|
||||||
RcVec3f A = RcVec3f.Subtract(a, a1);
|
Vector3 A = Vector3.Subtract(a, a1);
|
||||||
RcVec3f B = RcVec3f.Subtract(b, b1);
|
Vector3 B = Vector3.Subtract(b, b1);
|
||||||
|
|
||||||
float cross = B.X * A.Z - A.X * B.Z; // TriArea2D({0, 0}, A, B);
|
float cross = B.X * A.Z - A.X * B.Z; // TriArea2D({0, 0}, A, B);
|
||||||
float aHB = DtUtils.TriArea2D(b1, b, a);
|
float aHB = DtUtils.TriArea2D(b1, b, a);
|
||||||
|
@ -176,7 +177,7 @@ namespace DotRecast.Detour
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int AddVertex(float[] inters, int ii, RcVec3f p)
|
private static int AddVertex(float[] inters, int ii, Vector3 p)
|
||||||
{
|
{
|
||||||
if (ii > 0)
|
if (ii > 0)
|
||||||
{
|
{
|
||||||
|
@ -212,7 +213,7 @@ namespace DotRecast.Detour
|
||||||
return inflag;
|
return inflag;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DtConvexConvexIntersection SegSegInt(RcVec3f a, RcVec3f b, RcVec3f c, RcVec3f d, ref RcVec3f p, ref RcVec3f q)
|
private static DtConvexConvexIntersection SegSegInt(Vector3 a, Vector3 b, Vector3 c, Vector3 d, ref Vector3 p, ref Vector3 q)
|
||||||
{
|
{
|
||||||
if (DtUtils.IntersectSegSeg2D(a, b, c, d, out var s, out var t))
|
if (DtUtils.IntersectSegSeg2D(a, b, c, d, out var s, out var t))
|
||||||
{
|
{
|
||||||
|
@ -228,7 +229,7 @@ namespace DotRecast.Detour
|
||||||
return DtConvexConvexIntersection.None;
|
return DtConvexConvexIntersection.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DtConvexConvexIntersection ParallelInt(RcVec3f a, RcVec3f b, RcVec3f c, RcVec3f d, ref RcVec3f p, ref RcVec3f q)
|
private static DtConvexConvexIntersection ParallelInt(Vector3 a, Vector3 b, Vector3 c, Vector3 d, ref Vector3 p, ref Vector3 q)
|
||||||
{
|
{
|
||||||
if (Between(a, b, c) && Between(a, b, d))
|
if (Between(a, b, c) && Between(a, b, d))
|
||||||
{
|
{
|
||||||
|
@ -275,7 +276,7 @@ namespace DotRecast.Detour
|
||||||
return DtConvexConvexIntersection.None;
|
return DtConvexConvexIntersection.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool Between(RcVec3f a, RcVec3f b, RcVec3f c)
|
private static bool Between(Vector3 a, Vector3 b, Vector3 c)
|
||||||
{
|
{
|
||||||
if (MathF.Abs(a.X - b.X) > MathF.Abs(a.Z - b.Z))
|
if (MathF.Abs(a.X - b.X) > MathF.Abs(a.Z - b.Z))
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
|
@ -34,9 +35,9 @@ namespace DotRecast.Detour
|
||||||
this.scale = scale;
|
this.scale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetCost(RcVec3f neighbourPos, RcVec3f endPos)
|
public float GetCost(Vector3 neighbourPos, Vector3 endPos)
|
||||||
{
|
{
|
||||||
return RcVec3f.Distance(neighbourPos, endPos) * scale;
|
return Vector3.Distance(neighbourPos, endPos) * scale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,18 +1,19 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
public class DtFindNearestPolyQuery : IDtPolyQuery
|
public class DtFindNearestPolyQuery : IDtPolyQuery
|
||||||
{
|
{
|
||||||
private readonly DtNavMeshQuery _query;
|
private readonly DtNavMeshQuery _query;
|
||||||
private readonly RcVec3f _center;
|
private readonly Vector3 _center;
|
||||||
private long _nearestRef;
|
private long _nearestRef;
|
||||||
private RcVec3f _nearestPt;
|
private Vector3 _nearestPt;
|
||||||
private bool _overPoly;
|
private bool _overPoly;
|
||||||
private float _nearestDistanceSqr;
|
private float _nearestDistanceSqr;
|
||||||
|
|
||||||
public DtFindNearestPolyQuery(DtNavMeshQuery query, RcVec3f center)
|
public DtFindNearestPolyQuery(DtNavMeshQuery query, Vector3 center)
|
||||||
{
|
{
|
||||||
this._query = query;
|
this._query = query;
|
||||||
this._center = center;
|
this._center = center;
|
||||||
|
@ -28,7 +29,7 @@ namespace DotRecast.Detour
|
||||||
// If a point is directly over a polygon and closer than
|
// If a point is directly over a polygon and closer than
|
||||||
// climb height, favor that instead of straight line nearest point.
|
// climb height, favor that instead of straight line nearest point.
|
||||||
float d = 0;
|
float d = 0;
|
||||||
RcVec3f diff = RcVec3f.Subtract(_center, closestPtPoly);
|
Vector3 diff = Vector3.Subtract(_center, closestPtPoly);
|
||||||
if (posOverPoly)
|
if (posOverPoly)
|
||||||
{
|
{
|
||||||
d = MathF.Abs(diff.Y) - tile.data.header.walkableClimb;
|
d = MathF.Abs(diff.Y) - tile.data.header.walkableClimb;
|
||||||
|
@ -53,7 +54,7 @@ namespace DotRecast.Detour
|
||||||
return _nearestRef;
|
return _nearestRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f NearestPt()
|
public Vector3 NearestPt()
|
||||||
{
|
{
|
||||||
return _nearestPt;
|
return _nearestPt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -80,10 +81,10 @@ namespace DotRecast.Detour
|
||||||
public float walkableClimb;
|
public float walkableClimb;
|
||||||
|
|
||||||
/** The minimum bounds of the tile's AABB. [(x, y, z)] */
|
/** The minimum bounds of the tile's AABB. [(x, y, z)] */
|
||||||
public RcVec3f bmin = new RcVec3f();
|
public Vector3 bmin = new Vector3();
|
||||||
|
|
||||||
/** The maximum bounds of the tile's AABB. [(x, y, z)] */
|
/** The maximum bounds of the tile's AABB. [(x, y, z)] */
|
||||||
public RcVec3f bmax = new RcVec3f();
|
public Vector3 bmax = new Vector3();
|
||||||
|
|
||||||
/** The bounding volume quantization factor. */
|
/** The bounding volume quantization factor. */
|
||||||
public float bvQuantFactor;
|
public float bvQuantFactor;
|
||||||
|
|
|
@ -22,6 +22,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -69,7 +70,7 @@ namespace DotRecast.Detour
|
||||||
private readonly DtNavMeshParams m_params;
|
private readonly DtNavMeshParams m_params;
|
||||||
|
|
||||||
/// < Current initialization params. TODO: do not store this info twice.
|
/// < Current initialization params. TODO: do not store this info twice.
|
||||||
private readonly RcVec3f m_orig;
|
private readonly Vector3 m_orig;
|
||||||
|
|
||||||
/// < Origin of the tile (0,0)
|
/// < Origin of the tile (0,0)
|
||||||
// float m_orig[3]; ///< Origin of the tile (0,0)
|
// float m_orig[3]; ///< Origin of the tile (0,0)
|
||||||
|
@ -257,7 +258,7 @@ namespace DotRecast.Detour
|
||||||
* The world position for the query. [(x, y, z)]
|
* The world position for the query. [(x, y, z)]
|
||||||
* @return 2-element int array with (tx,ty) tile location
|
* @return 2-element int array with (tx,ty) tile location
|
||||||
*/
|
*/
|
||||||
public void CalcTileLoc(RcVec3f pos, out int tx, out int ty)
|
public void CalcTileLoc(Vector3 pos, out int tx, out int ty)
|
||||||
{
|
{
|
||||||
tx = (int)MathF.Floor((pos.X - m_orig.X) / m_tileWidth);
|
tx = (int)MathF.Floor((pos.X - m_orig.X) / m_tileWidth);
|
||||||
ty = (int)MathF.Floor((pos.Z - m_orig.Z) / m_tileHeight);
|
ty = (int)MathF.Floor((pos.Z - m_orig.Z) / m_tileHeight);
|
||||||
|
@ -284,7 +285,7 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_tiles[it].salt != salt || m_tiles[it].data == null || m_tiles[it].data.header == null)
|
if (m_tiles[it].salt != salt || m_tiles[it].data.header == null)
|
||||||
{
|
{
|
||||||
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
|
@ -348,7 +349,7 @@ namespace DotRecast.Detour
|
||||||
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed
|
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed
|
||||||
// for off-mesh connection finding.
|
// for off-mesh connection finding.
|
||||||
|
|
||||||
List<long> QueryPolygonsInTile(DtMeshTile tile, RcVec3f qmin, RcVec3f qmax)
|
List<long> QueryPolygonsInTile(DtMeshTile tile, Vector3 qmin, Vector3 qmax)
|
||||||
{
|
{
|
||||||
List<long> polys = new List<long>();
|
List<long> polys = new List<long>();
|
||||||
if (tile.data.bvTree != null)
|
if (tile.data.bvTree != null)
|
||||||
|
@ -404,8 +405,8 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RcVec3f bmin = new RcVec3f();
|
Vector3 bmin = new Vector3();
|
||||||
RcVec3f bmax = new RcVec3f();
|
Vector3 bmax = new Vector3();
|
||||||
long @base = GetPolyRefBase(tile);
|
long @base = GetPolyRefBase(tile);
|
||||||
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
||||||
{
|
{
|
||||||
|
@ -693,7 +694,6 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes external links at specified side.V
|
|
||||||
void UnconnectLinks(DtMeshTile tile, DtMeshTile target)
|
void UnconnectLinks(DtMeshTile tile, DtMeshTile target)
|
||||||
{
|
{
|
||||||
if (tile == null || target == null)
|
if (tile == null || target == null)
|
||||||
|
@ -736,7 +736,6 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds external polygon links for a tile.
|
|
||||||
void ConnectExtLinks(DtMeshTile tile, DtMeshTile target, int side)
|
void ConnectExtLinks(DtMeshTile tile, DtMeshTile target, int side)
|
||||||
{
|
{
|
||||||
if (tile == null)
|
if (tile == null)
|
||||||
|
@ -822,7 +821,6 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds external polygon links for a tile.
|
|
||||||
void ConnectExtOffMeshLinks(DtMeshTile tile, DtMeshTile target, int side)
|
void ConnectExtOffMeshLinks(DtMeshTile tile, DtMeshTile target, int side)
|
||||||
{
|
{
|
||||||
if (tile == null)
|
if (tile == null)
|
||||||
|
@ -850,7 +848,7 @@ namespace DotRecast.Detour
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ext = new RcVec3f()
|
var ext = new Vector3()
|
||||||
{
|
{
|
||||||
X = targetCon.rad,
|
X = targetCon.rad,
|
||||||
Y = target.data.header.walkableClimb,
|
Y = target.data.header.walkableClimb,
|
||||||
|
@ -858,7 +856,7 @@ namespace DotRecast.Detour
|
||||||
};
|
};
|
||||||
|
|
||||||
// Find polygon to connect to.
|
// Find polygon to connect to.
|
||||||
RcVec3f p = targetCon.pos[1];
|
Vector3 p = targetCon.pos[1];
|
||||||
var refs = FindNearestPolyInTile(tile, p, ext, out var nearestPt);
|
var refs = FindNearestPolyInTile(tile, p, ext, out var nearestPt);
|
||||||
if (refs == 0)
|
if (refs == 0)
|
||||||
{
|
{
|
||||||
|
@ -915,14 +913,14 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
cons.Clear();
|
cons.Clear();
|
||||||
|
|
||||||
RcVec2f amin = RcVec2f.Zero;
|
Vector2 amin = Vector2.Zero;
|
||||||
RcVec2f amax = RcVec2f.Zero;
|
Vector2 amax = Vector2.Zero;
|
||||||
CalcSlabEndPoints(verts, va, vb, ref amin, ref amax, side);
|
CalcSlabEndPoints(verts, va, vb, ref amin, ref amax, side);
|
||||||
float apos = GetSlabCoord(verts, va, side);
|
float apos = GetSlabCoord(verts, va, side);
|
||||||
|
|
||||||
// Remove links pointing to 'side' and compact the links array.
|
// Remove links pointing to 'side' and compact the links array.
|
||||||
RcVec2f bmin = RcVec2f.Zero;
|
Vector2 bmin = Vector2.Zero;
|
||||||
RcVec2f bmax = RcVec2f.Zero;
|
Vector2 bmax = Vector2.Zero;
|
||||||
int m = DT_EXT_LINK | side;
|
int m = DT_EXT_LINK | side;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
long @base = GetPolyRefBase(tile);
|
long @base = GetPolyRefBase(tile);
|
||||||
|
@ -983,7 +981,7 @@ namespace DotRecast.Detour
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CalcSlabEndPoints(float[] verts, int va, int vb, ref RcVec2f bmin, ref RcVec2f bmax, int side)
|
static void CalcSlabEndPoints(float[] verts, int va, int vb, ref Vector2 bmin, ref Vector2 bmax, int side)
|
||||||
{
|
{
|
||||||
if (side == 0 || side == 4)
|
if (side == 0 || side == 4)
|
||||||
{
|
{
|
||||||
|
@ -1021,7 +1019,7 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OverlapSlabs(RcVec2f amin, RcVec2f amax, RcVec2f bmin, RcVec2f bmax, float px, float py)
|
bool OverlapSlabs(Vector2 amin, Vector2 amax, Vector2 bmin, Vector2 bmax, float px, float py)
|
||||||
{
|
{
|
||||||
// Check for horizontal overlap.
|
// Check for horizontal overlap.
|
||||||
// The segment is shrunken a little so that slabs which touch
|
// The segment is shrunken a little so that slabs which touch
|
||||||
|
@ -1061,7 +1059,11 @@ namespace DotRecast.Detour
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds internal polygons links for a tile.
|
/**
|
||||||
|
* Builds internal polygons links for a tile.
|
||||||
|
*
|
||||||
|
* @param tile
|
||||||
|
*/
|
||||||
void BaseOffMeshLinks(DtMeshTile tile)
|
void BaseOffMeshLinks(DtMeshTile tile)
|
||||||
{
|
{
|
||||||
if (tile == null)
|
if (tile == null)
|
||||||
|
@ -1077,7 +1079,7 @@ namespace DotRecast.Detour
|
||||||
DtOffMeshConnection con = tile.data.offMeshCons[i];
|
DtOffMeshConnection con = tile.data.offMeshCons[i];
|
||||||
DtPoly poly = tile.data.polys[con.poly];
|
DtPoly poly = tile.data.polys[con.poly];
|
||||||
|
|
||||||
var ext = new RcVec3f()
|
var ext = new Vector3()
|
||||||
{
|
{
|
||||||
X = con.rad,
|
X = con.rad,
|
||||||
Y = tile.data.header.walkableClimb,
|
Y = tile.data.header.walkableClimb,
|
||||||
|
@ -1091,7 +1093,7 @@ namespace DotRecast.Detour
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f[] p = con.pos; // First vertex
|
Vector3[] p = con.pos; // First vertex
|
||||||
// findNearestPoly may return too optimistic results, further check
|
// findNearestPoly may return too optimistic results, further check
|
||||||
// to make sure.
|
// to make sure.
|
||||||
if (RcMath.Sqr(nearestPt.X - p[0].X) + RcMath.Sqr(nearestPt.Z - p[0].Z) > RcMath.Sqr(con.rad))
|
if (RcMath.Sqr(nearestPt.X - p[0].X) + RcMath.Sqr(nearestPt.Z - p[0].Z) > RcMath.Sqr(con.rad))
|
||||||
|
@ -1137,7 +1139,7 @@ namespace DotRecast.Detour
|
||||||
* @param pos
|
* @param pos
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
RcVec3f ClosestPointOnDetailEdges(DtMeshTile tile, DtPoly poly, RcVec3f pos, bool onlyBoundary)
|
Vector3 ClosestPointOnDetailEdges(DtMeshTile tile, DtPoly poly, Vector3 pos, bool onlyBoundary)
|
||||||
{
|
{
|
||||||
int ANY_BOUNDARY_EDGE = (DtDetailTriEdgeFlags.DT_DETAIL_EDGE_BOUNDARY << 0) |
|
int ANY_BOUNDARY_EDGE = (DtDetailTriEdgeFlags.DT_DETAIL_EDGE_BOUNDARY << 0) |
|
||||||
(DtDetailTriEdgeFlags.DT_DETAIL_EDGE_BOUNDARY << 2) |
|
(DtDetailTriEdgeFlags.DT_DETAIL_EDGE_BOUNDARY << 2) |
|
||||||
|
@ -1145,8 +1147,8 @@ namespace DotRecast.Detour
|
||||||
int ip = poly.index;
|
int ip = poly.index;
|
||||||
float dmin = float.MaxValue;
|
float dmin = float.MaxValue;
|
||||||
float tmin = 0;
|
float tmin = 0;
|
||||||
RcVec3f pmin = new RcVec3f();
|
Vector3 pmin = new Vector3();
|
||||||
RcVec3f pmax = new RcVec3f();
|
Vector3 pmax = new Vector3();
|
||||||
|
|
||||||
if (tile.data.detailMeshes != null)
|
if (tile.data.detailMeshes != null)
|
||||||
{
|
{
|
||||||
|
@ -1160,13 +1162,13 @@ namespace DotRecast.Detour
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f[] v = new RcVec3f[3];
|
Vector3[] v = new Vector3[3];
|
||||||
for (int j = 0; j < 3; ++j)
|
for (int j = 0; j < 3; ++j)
|
||||||
{
|
{
|
||||||
if (tris[ti + j] < poly.vertCount)
|
if (tris[ti + j] < poly.vertCount)
|
||||||
{
|
{
|
||||||
int index = poly.verts[tris[ti + j]] * 3;
|
int index = poly.verts[tris[ti + j]] * 3;
|
||||||
v[j] = new RcVec3f
|
v[j] = new Vector3
|
||||||
{
|
{
|
||||||
X = tile.data.verts[index],
|
X = tile.data.verts[index],
|
||||||
Y = tile.data.verts[index + 1],
|
Y = tile.data.verts[index + 1],
|
||||||
|
@ -1176,7 +1178,7 @@ namespace DotRecast.Detour
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int index = (pd.vertBase + (tris[ti + j] - poly.vertCount)) * 3;
|
int index = (pd.vertBase + (tris[ti + j] - poly.vertCount)) * 3;
|
||||||
v[j] = new RcVec3f
|
v[j] = new Vector3
|
||||||
{
|
{
|
||||||
X = tile.data.detailVerts[index],
|
X = tile.data.detailVerts[index],
|
||||||
Y = tile.data.detailVerts[index + 1],
|
Y = tile.data.detailVerts[index + 1],
|
||||||
|
@ -1208,7 +1210,7 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RcVec3f[] v = new RcVec3f[2];
|
Vector3[] v = new Vector3[2];
|
||||||
for (int j = 0; j < poly.vertCount; ++j)
|
for (int j = 0; j < poly.vertCount; ++j)
|
||||||
{
|
{
|
||||||
int k = (j + 1) % poly.vertCount;
|
int k = (j + 1) % poly.vertCount;
|
||||||
|
@ -1230,10 +1232,10 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return RcVec3f.Lerp(pmin, pmax, tmin);
|
return Vector3.Lerp(pmin, pmax, tmin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool GetPolyHeight(DtMeshTile tile, DtPoly poly, RcVec3f pos, out float height)
|
public bool GetPolyHeight(DtMeshTile tile, DtPoly poly, Vector3 pos, out float height)
|
||||||
{
|
{
|
||||||
height = 0;
|
height = 0;
|
||||||
|
|
||||||
|
@ -1265,13 +1267,13 @@ namespace DotRecast.Detour
|
||||||
for (int j = 0; j < pd.triCount; ++j)
|
for (int j = 0; j < pd.triCount; ++j)
|
||||||
{
|
{
|
||||||
int t = (pd.triBase + j) * 4;
|
int t = (pd.triBase + j) * 4;
|
||||||
RcVec3f[] v = new RcVec3f[3];
|
Vector3[] v = new Vector3[3];
|
||||||
for (int k = 0; k < 3; ++k)
|
for (int k = 0; k < 3; ++k)
|
||||||
{
|
{
|
||||||
if (tile.data.detailTris[t + k] < poly.vertCount)
|
if (tile.data.detailTris[t + k] < poly.vertCount)
|
||||||
{
|
{
|
||||||
int index = poly.verts[tile.data.detailTris[t + k]] * 3;
|
int index = poly.verts[tile.data.detailTris[t + k]] * 3;
|
||||||
v[k] = new RcVec3f
|
v[k] = new Vector3
|
||||||
{
|
{
|
||||||
X = tile.data.verts[index],
|
X = tile.data.verts[index],
|
||||||
Y = tile.data.verts[index + 1],
|
Y = tile.data.verts[index + 1],
|
||||||
|
@ -1281,7 +1283,7 @@ namespace DotRecast.Detour
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int index = (pd.vertBase + (tile.data.detailTris[t + k] - poly.vertCount)) * 3;
|
int index = (pd.vertBase + (tile.data.detailTris[t + k] - poly.vertCount)) * 3;
|
||||||
v[k] = new RcVec3f
|
v[k] = new Vector3
|
||||||
{
|
{
|
||||||
X = tile.data.detailVerts[index],
|
X = tile.data.detailVerts[index],
|
||||||
Y = tile.data.detailVerts[index + 1],
|
Y = tile.data.detailVerts[index + 1],
|
||||||
|
@ -1299,7 +1301,7 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RcVec3f[] v = new RcVec3f[3];
|
Vector3[] v = new Vector3[3];
|
||||||
v[0].X = tile.data.verts[poly.verts[0] * 3];
|
v[0].X = tile.data.verts[poly.verts[0] * 3];
|
||||||
v[0].Y = tile.data.verts[poly.verts[0] * 3 + 1];
|
v[0].Y = tile.data.verts[poly.verts[0] * 3 + 1];
|
||||||
v[0].Z = tile.data.verts[poly.verts[0] * 3 + 2];
|
v[0].Z = tile.data.verts[poly.verts[0] * 3 + 2];
|
||||||
|
@ -1329,7 +1331,7 @@ namespace DotRecast.Detour
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClosestPointOnPoly(long refs, RcVec3f pos, out RcVec3f closest, out bool posOverPoly)
|
public void ClosestPointOnPoly(long refs, Vector3 pos, out Vector3 closest, out bool posOverPoly)
|
||||||
{
|
{
|
||||||
GetTileAndPolyByRefUnsafe(refs, out var tile, out var poly);
|
GetTileAndPolyByRefUnsafe(refs, out var tile, out var poly);
|
||||||
closest = pos;
|
closest = pos;
|
||||||
|
@ -1347,11 +1349,11 @@ namespace DotRecast.Detour
|
||||||
if (poly.GetPolyType() == DtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION)
|
if (poly.GetPolyType() == DtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||||
{
|
{
|
||||||
int i = poly.verts[0] * 3;
|
int i = poly.verts[0] * 3;
|
||||||
var v0 = new RcVec3f { X = tile.data.verts[i], Y = tile.data.verts[i + 1], Z = tile.data.verts[i + 2] };
|
var v0 = new Vector3 { X = tile.data.verts[i], Y = tile.data.verts[i + 1], Z = tile.data.verts[i + 2] };
|
||||||
i = poly.verts[1] * 3;
|
i = poly.verts[1] * 3;
|
||||||
var v1 = new RcVec3f { X = tile.data.verts[i], Y = tile.data.verts[i + 1], Z = tile.data.verts[i + 2] };
|
var v1 = new Vector3 { X = tile.data.verts[i], Y = tile.data.verts[i + 1], Z = tile.data.verts[i + 2] };
|
||||||
DtUtils.DistancePtSegSqr2D(pos, v0, v1, out var t);
|
DtUtils.DistancePtSegSqr2D(pos, v0, v1, out var t);
|
||||||
closest = RcVec3f.Lerp(v0, v1, t);
|
closest = Vector3.Lerp(v0, v1, t);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1360,13 +1362,13 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find nearest polygon within a tile.
|
/// Find nearest polygon within a tile.
|
||||||
private long FindNearestPolyInTile(DtMeshTile tile, RcVec3f center, RcVec3f halfExtents, out RcVec3f nearestPt)
|
private long FindNearestPolyInTile(DtMeshTile tile, Vector3 center, Vector3 halfExtents, out Vector3 nearestPt)
|
||||||
{
|
{
|
||||||
nearestPt = RcVec3f.Zero;
|
nearestPt = Vector3.Zero;
|
||||||
|
|
||||||
bool overPoly = false;
|
bool overPoly = false;
|
||||||
RcVec3f bmin = RcVec3f.Subtract(center, halfExtents);
|
Vector3 bmin = Vector3.Subtract(center, halfExtents);
|
||||||
RcVec3f bmax = RcVec3f.Add(center, halfExtents);
|
Vector3 bmax = Vector3.Add(center, halfExtents);
|
||||||
|
|
||||||
// Get nearby polygons from proximity grid.
|
// Get nearby polygons from proximity grid.
|
||||||
List<long> polys = QueryPolygonsInTile(tile, bmin, bmax);
|
List<long> polys = QueryPolygonsInTile(tile, bmin, bmax);
|
||||||
|
@ -1382,7 +1384,7 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
// If a point is directly over a polygon and closer than
|
// If a point is directly over a polygon and closer than
|
||||||
// climb height, favor that instead of straight line nearest point.
|
// climb height, favor that instead of straight line nearest point.
|
||||||
RcVec3f diff = RcVec3f.Subtract(center, closestPtPoly);
|
Vector3 diff = Vector3.Subtract(center, closestPtPoly);
|
||||||
if (posOverPoly)
|
if (posOverPoly)
|
||||||
{
|
{
|
||||||
d = MathF.Abs(diff.Y) - tile.data.header.walkableClimb;
|
d = MathF.Abs(diff.Y) - tile.data.header.walkableClimb;
|
||||||
|
@ -1531,7 +1533,7 @@ namespace DotRecast.Detour
|
||||||
/// inside a normal polygon. So an off-mesh connection is "entered" from a
|
/// inside a normal polygon. So an off-mesh connection is "entered" from a
|
||||||
/// normal polygon at one of its endpoints. This is the polygon identified by
|
/// normal polygon at one of its endpoints. This is the polygon identified by
|
||||||
/// the prevRef parameter.
|
/// the prevRef parameter.
|
||||||
public DtStatus GetOffMeshConnectionPolyEndPoints(long prevRef, long polyRef, ref RcVec3f startPos, ref RcVec3f endPos)
|
public DtStatus GetOffMeshConnectionPolyEndPoints(long prevRef, long polyRef, ref Vector3 startPos, ref Vector3 endPos)
|
||||||
{
|
{
|
||||||
if (polyRef == 0)
|
if (polyRef == 0)
|
||||||
{
|
{
|
||||||
|
@ -1734,9 +1736,9 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_SUCCESS;
|
return DtStatus.DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f GetPolyCenter(long refs)
|
public Vector3 GetPolyCenter(long refs)
|
||||||
{
|
{
|
||||||
RcVec3f center = RcVec3f.Zero;
|
Vector3 center = Vector3.Zero;
|
||||||
|
|
||||||
var status = GetTileAndPolyByRef(refs, out var tile, out var poly);
|
var status = GetTileAndPolyByRef(refs, out var tile, out var poly);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
|
@ -1784,10 +1786,10 @@ namespace DotRecast.Detour
|
||||||
return tiles;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ComputeBounds(out RcVec3f bmin, out RcVec3f bmax)
|
public void ComputeBounds(out Vector3 bmin, out Vector3 bmax)
|
||||||
{
|
{
|
||||||
bmin = new RcVec3f(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
|
bmin = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
|
||||||
bmax = new RcVec3f(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
|
bmax = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
|
||||||
for (int t = 0; t < GetMaxTiles(); ++t)
|
for (int t = 0; t < GetMaxTiles(); ++t)
|
||||||
{
|
{
|
||||||
DtMeshTile tile = GetTile(t);
|
DtMeshTile tile = GetTile(t);
|
||||||
|
|
|
@ -21,6 +21,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -220,7 +221,7 @@ namespace DotRecast.Detour
|
||||||
const int XM = 1 << 2;
|
const int XM = 1 << 2;
|
||||||
const int ZM = 1 << 3;
|
const int ZM = 1 << 3;
|
||||||
|
|
||||||
public static int ClassifyOffMeshPoint(RcVec3f pt, RcVec3f bmin, RcVec3f bmax)
|
public static int ClassifyOffMeshPoint(Vector3 pt, Vector3 bmin, Vector3 bmax)
|
||||||
{
|
{
|
||||||
int outcode = 0;
|
int outcode = 0;
|
||||||
outcode |= (pt.X >= bmax.X) ? XP : 0;
|
outcode |= (pt.X >= bmax.X) ? XP : 0;
|
||||||
|
@ -307,8 +308,8 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
hmin -= option.walkableClimb;
|
hmin -= option.walkableClimb;
|
||||||
hmax += option.walkableClimb;
|
hmax += option.walkableClimb;
|
||||||
RcVec3f bmin = new RcVec3f();
|
Vector3 bmin = new Vector3();
|
||||||
RcVec3f bmax = new RcVec3f();
|
Vector3 bmax = new Vector3();
|
||||||
bmin = option.bmin;
|
bmin = option.bmin;
|
||||||
bmax = option.bmax;
|
bmax = option.bmax;
|
||||||
bmin.Y = hmin;
|
bmin.Y = hmin;
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -90,8 +91,8 @@ namespace DotRecast.Detour
|
||||||
public int tileX; // < The tile's x-grid location within the multi-tile destination mesh. (Along the x-axis.)
|
public int tileX; // < The tile's x-grid location within the multi-tile destination mesh. (Along the x-axis.)
|
||||||
public int tileZ; // < The tile's y-grid location within the multi-tile destination mesh. (Along the z-axis.)
|
public int tileZ; // < The tile's y-grid location within the multi-tile destination mesh. (Along the z-axis.)
|
||||||
public int tileLayer; // < The tile's layer within the layered destination mesh. [Limit: >= 0] (Along the y-axis.)
|
public int tileLayer; // < The tile's layer within the layered destination mesh. [Limit: >= 0] (Along the y-axis.)
|
||||||
public RcVec3f bmin; // < The minimum bounds of the tile. [(x, y, z)] [Unit: wu]
|
public Vector3 bmin; // < The minimum bounds of the tile. [(x, y, z)] [Unit: wu]
|
||||||
public RcVec3f bmax; // < The maximum bounds of the tile. [(x, y, z)] [Unit: wu]
|
public Vector3 bmax; // < The maximum bounds of the tile. [(x, y, z)] [Unit: wu]
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
/// @name General Configuration Attributes
|
/// @name General Configuration Attributes
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -31,7 +32,7 @@ namespace DotRecast.Detour
|
||||||
public struct DtNavMeshParams
|
public struct DtNavMeshParams
|
||||||
{
|
{
|
||||||
/** The world space origin of the navigation mesh's tile space. [(x, y, z)] */
|
/** The world space origin of the navigation mesh's tile space. [(x, y, z)] */
|
||||||
public RcVec3f orig;
|
public Vector3 orig;
|
||||||
|
|
||||||
/** The width of each tile. (Along the x-axis.) */
|
/** The width of each tile. (Along the x-axis.) */
|
||||||
public float tileWidth;
|
public float tileWidth;
|
||||||
|
|
|
@ -23,6 +23,7 @@ using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Collections;
|
using DotRecast.Core.Collections;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -31,17 +32,14 @@ namespace DotRecast.Detour
|
||||||
/// < Add a vertex at every polygon edge crossing.
|
/// < Add a vertex at every polygon edge crossing.
|
||||||
protected readonly DtNavMesh m_nav;
|
protected readonly DtNavMesh m_nav;
|
||||||
|
|
||||||
protected readonly DtNodePool m_tinyNodePool;
|
|
||||||
protected readonly DtNodePool m_nodePool;
|
protected readonly DtNodePool m_nodePool;
|
||||||
protected readonly DtNodeQueue m_openList;
|
protected readonly DtNodeQueue m_openList;
|
||||||
|
|
||||||
protected DtQueryData m_query;
|
protected DtQueryData m_query;
|
||||||
|
|
||||||
/// < Sliced query state.
|
/// < Sliced query state.
|
||||||
public DtNavMeshQuery(DtNavMesh nav)
|
public DtNavMeshQuery(DtNavMesh nav)
|
||||||
{
|
{
|
||||||
m_nav = nav;
|
m_nav = nav;
|
||||||
m_tinyNodePool = new DtNodePool();
|
|
||||||
m_nodePool = new DtNodePool();
|
m_nodePool = new DtNodePool();
|
||||||
m_openList = new DtNodeQueue();
|
m_openList = new DtNodeQueue();
|
||||||
}
|
}
|
||||||
|
@ -53,10 +51,10 @@ namespace DotRecast.Detour
|
||||||
/// @param[out] randomRef The reference id of the random location.
|
/// @param[out] randomRef The reference id of the random location.
|
||||||
/// @param[out] randomPt The random location.
|
/// @param[out] randomPt The random location.
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus FindRandomPoint(IDtQueryFilter filter, IRcRand frand, out long randomRef, out RcVec3f randomPt)
|
public DtStatus FindRandomPoint(IDtQueryFilter filter, IRcRand frand, out long randomRef, out Vector3 randomPt)
|
||||||
{
|
{
|
||||||
randomRef = 0;
|
randomRef = 0;
|
||||||
randomPt = RcVec3f.Zero;
|
randomPt = Vector3.Zero;
|
||||||
|
|
||||||
if (null == filter || null == frand)
|
if (null == filter || null == frand)
|
||||||
{
|
{
|
||||||
|
@ -157,19 +155,24 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_SUCCESS;
|
return DtStatus.DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns random location on navmesh within the reach of specified location.
|
/**
|
||||||
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
* Returns random location on navmesh within the reach of specified location. Polygons are chosen weighted by area.
|
||||||
/// The location is not exactly constrained by the circle, but it limits the visited polygons.
|
* The search runs in linear related to number of polygon. The location is not exactly constrained by the circle,
|
||||||
/// @param[in] startRef The reference id of the polygon where the search starts.
|
* but it limits the visited polygons.
|
||||||
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
*
|
||||||
/// @param[in] maxRadius The radius of the search circle. [Units: wu]
|
* @param startRef
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
* The reference id of the polygon where the search starts.
|
||||||
/// @param[in] frand Function returning a random number [0..1).
|
* @param centerPos
|
||||||
/// @param[out] randomRef The reference id of the random location.
|
* The center of the search circle. [(x, y, z)]
|
||||||
/// @param[out] randomPt The random location. [(x, y, z)]
|
* @param maxRadius
|
||||||
/// @returns The status flags for the query.
|
* @param filter
|
||||||
public DtStatus FindRandomPointAroundCircle(long startRef, RcVec3f centerPos, float maxRadius,
|
* The polygon filter to apply to the query.
|
||||||
IDtQueryFilter filter, IRcRand frand, out long randomRef, out RcVec3f randomPt)
|
* @param frand
|
||||||
|
* Function returning a random number [0..1).
|
||||||
|
* @return Random location
|
||||||
|
*/
|
||||||
|
public DtStatus FindRandomPointAroundCircle(long startRef, Vector3 centerPos, float maxRadius,
|
||||||
|
IDtQueryFilter filter, IRcRand frand, out long randomRef, out Vector3 randomPt)
|
||||||
{
|
{
|
||||||
return FindRandomPointAroundCircle(startRef, centerPos, maxRadius, filter, frand, DtNoOpDtPolygonByCircleConstraint.Shared, out randomRef, out randomPt);
|
return FindRandomPointAroundCircle(startRef, centerPos, maxRadius, filter, frand, DtNoOpDtPolygonByCircleConstraint.Shared, out randomRef, out randomPt);
|
||||||
}
|
}
|
||||||
|
@ -189,27 +192,15 @@ namespace DotRecast.Detour
|
||||||
* Function returning a random number [0..1).
|
* Function returning a random number [0..1).
|
||||||
* @return Random location
|
* @return Random location
|
||||||
*/
|
*/
|
||||||
public DtStatus FindRandomPointWithinCircle(long startRef, RcVec3f centerPos, float maxRadius,
|
public DtStatus FindRandomPointWithinCircle(long startRef, Vector3 centerPos, float maxRadius,
|
||||||
IDtQueryFilter filter, IRcRand frand, out long randomRef, out RcVec3f randomPt)
|
IDtQueryFilter filter, IRcRand frand, out long randomRef, out Vector3 randomPt)
|
||||||
{
|
{
|
||||||
return FindRandomPointAroundCircle(startRef, centerPos, maxRadius, filter, frand, DtStrictDtPolygonByCircleConstraint.Shared, out randomRef, out randomPt);
|
return FindRandomPointAroundCircle(startRef, centerPos, maxRadius, filter, frand, DtStrictDtPolygonByCircleConstraint.Shared, out randomRef, out randomPt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns random location on navmesh within the reach of specified location.
|
public DtStatus FindRandomPointAroundCircle(long startRef, Vector3 centerPos, float maxRadius,
|
||||||
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
|
||||||
/// The location is not exactly constrained by the circle, but it limits the visited polygons.
|
|
||||||
/// @param[in] startRef The reference id of the polygon where the search starts.
|
|
||||||
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
|
||||||
/// @param[in] maxRadius The radius of the search circle. [Units: wu]
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[in] frand Function returning a random number [0..1).
|
|
||||||
/// @param[in] constraint
|
|
||||||
/// @param[out] randomRef The reference id of the random location.
|
|
||||||
/// @param[out] randomPt The random location. [(x, y, z)]
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
public DtStatus FindRandomPointAroundCircle(long startRef, RcVec3f centerPos, float maxRadius,
|
|
||||||
IDtQueryFilter filter, IRcRand frand, IDtPolygonByCircleConstraint constraint,
|
IDtQueryFilter filter, IRcRand frand, IDtPolygonByCircleConstraint constraint,
|
||||||
out long randomRef, out RcVec3f randomPt)
|
out long randomRef, out Vector3 randomPt)
|
||||||
{
|
{
|
||||||
randomRef = startRef;
|
randomRef = startRef;
|
||||||
randomPt = centerPos;
|
randomPt = centerPos;
|
||||||
|
@ -349,10 +340,10 @@ namespace DotRecast.Detour
|
||||||
// Cost
|
// Cost
|
||||||
if (neighbourNode.flags == 0)
|
if (neighbourNode.flags == 0)
|
||||||
{
|
{
|
||||||
neighbourNode.pos = RcVec3f.Lerp(va, vb, 0.5f);
|
neighbourNode.pos = Vector3.Lerp(va, vb, 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
float total = bestNode.total + RcVec3f.Distance(bestNode.pos, neighbourNode.pos);
|
float total = bestNode.total + Vector3.Distance(bestNode.pos, neighbourNode.pos);
|
||||||
|
|
||||||
// The node is already in open list and the new result is worse, skip.
|
// The node is already in open list and the new result is worse, skip.
|
||||||
if ((neighbourNode.flags & DtNodeFlags.DT_NODE_OPEN) != 0 && total >= neighbourNode.total)
|
if ((neighbourNode.flags & DtNodeFlags.DT_NODE_OPEN) != 0 && total >= neighbourNode.total)
|
||||||
|
@ -387,7 +378,7 @@ namespace DotRecast.Detour
|
||||||
float t = frand.Next();
|
float t = frand.Next();
|
||||||
|
|
||||||
float[] areas = new float[randomPolyVerts.Length / 3];
|
float[] areas = new float[randomPolyVerts.Length / 3];
|
||||||
RcVec3f pt = DtUtils.RandomPointInConvexPoly(randomPolyVerts, randomPolyVerts.Length / 3, areas, s, t);
|
Vector3 pt = DtUtils.RandomPointInConvexPoly(randomPolyVerts, randomPolyVerts.Length / 3, areas, s, t);
|
||||||
ClosestPointOnPoly(randomPolyRef, pt, out var closest, out var _);
|
ClosestPointOnPoly(randomPolyRef, pt, out var closest, out var _);
|
||||||
|
|
||||||
randomRef = randomPolyRef;
|
randomRef = randomPolyRef;
|
||||||
|
@ -403,15 +394,15 @@ namespace DotRecast.Detour
|
||||||
///
|
///
|
||||||
/// @p pos does not have to be within the bounds of the polygon or navigation mesh.
|
/// @p pos does not have to be within the bounds of the polygon or navigation mesh.
|
||||||
///
|
///
|
||||||
/// See closestPointOnPolyBoundary() for a limited but faster option.
|
/// See ClosestPointOnPolyBoundary() for a limited but faster option.
|
||||||
///
|
///
|
||||||
/// Finds the closest point on the specified polygon.
|
/// Finds the closest point on the specified polygon.
|
||||||
/// @param[in] ref The reference id of the polygon.
|
/// @param[in] ref The reference id of the polygon.
|
||||||
/// @param[in] pos The position to check. [(x, y, z)]
|
/// @param[in] pos The position to check. [(x, y, z)]
|
||||||
/// @param[out] closest The closest point on the polygon. [(x, y, z)]
|
/// @param[out] closest
|
||||||
/// @param[out] posOverPoly True of the position is over the polygon.
|
/// @param[out] posOverPoly
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus ClosestPointOnPoly(long refs, RcVec3f pos, out RcVec3f closest, out bool posOverPoly)
|
public DtStatus ClosestPointOnPoly(long refs, Vector3 pos, out Vector3 closest, out bool posOverPoly)
|
||||||
{
|
{
|
||||||
closest = pos;
|
closest = pos;
|
||||||
posOverPoly = false;
|
posOverPoly = false;
|
||||||
|
@ -442,7 +433,7 @@ namespace DotRecast.Detour
|
||||||
/// @param[in] pos The position to check. [(x, y, z)]
|
/// @param[in] pos The position to check. [(x, y, z)]
|
||||||
/// @param[out] closest The closest point. [(x, y, z)]
|
/// @param[out] closest The closest point. [(x, y, z)]
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus ClosestPointOnPolyBoundary(long refs, RcVec3f pos, out RcVec3f closest)
|
public DtStatus ClosestPointOnPolyBoundary(long refs, Vector3 pos, out Vector3 closest)
|
||||||
{
|
{
|
||||||
closest = pos;
|
closest = pos;
|
||||||
var status = m_nav.GetTileAndPolyByRef(refs, out var tile, out var poly);
|
var status = m_nav.GetTileAndPolyByRef(refs, out var tile, out var poly);
|
||||||
|
@ -502,7 +493,7 @@ namespace DotRecast.Detour
|
||||||
/// @param[in] pos A position within the xz-bounds of the polygon. [(x, y, z)]
|
/// @param[in] pos A position within the xz-bounds of the polygon. [(x, y, z)]
|
||||||
/// @param[out] height The height at the surface of the polygon.
|
/// @param[out] height The height at the surface of the polygon.
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus GetPolyHeight(long refs, RcVec3f pos, out float height)
|
public DtStatus GetPolyHeight(long refs, Vector3 pos, out float height)
|
||||||
{
|
{
|
||||||
height = default;
|
height = default;
|
||||||
|
|
||||||
|
@ -523,9 +514,9 @@ namespace DotRecast.Detour
|
||||||
if (poly.GetPolyType() == DtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION)
|
if (poly.GetPolyType() == DtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||||
{
|
{
|
||||||
int i = poly.verts[0] * 3;
|
int i = poly.verts[0] * 3;
|
||||||
var v0 = new RcVec3f { X = tile.data.verts[i], Y = tile.data.verts[i + 1], Z = tile.data.verts[i + 2] };
|
var v0 = new Vector3 { X = tile.data.verts[i], Y = tile.data.verts[i + 1], Z = tile.data.verts[i + 2] };
|
||||||
i = poly.verts[1] * 3;
|
i = poly.verts[1] * 3;
|
||||||
var v1 = new RcVec3f { X = tile.data.verts[i], Y = tile.data.verts[i + 1], Z = tile.data.verts[i + 2] };
|
var v1 = new Vector3 { X = tile.data.verts[i], Y = tile.data.verts[i + 1], Z = tile.data.verts[i + 2] };
|
||||||
DtUtils.DistancePtSegSqr2D(pos, v0, v1, out var t);
|
DtUtils.DistancePtSegSqr2D(pos, v0, v1, out var t);
|
||||||
height = v0.Y + (v1.Y - v0.Y) * t;
|
height = v0.Y + (v1.Y - v0.Y) * t;
|
||||||
|
|
||||||
|
@ -551,8 +542,8 @@ namespace DotRecast.Detour
|
||||||
/// @param[out] nearestPt The nearest point on the polygon. Unchanged if no polygon is found. [opt] [(x, y, z)]
|
/// @param[out] nearestPt The nearest point on the polygon. Unchanged if no polygon is found. [opt] [(x, y, z)]
|
||||||
/// @param[out] isOverPoly Set to true if the point's X/Z coordinate lies inside the polygon, false otherwise. Unchanged if no polygon is found. [opt]
|
/// @param[out] isOverPoly Set to true if the point's X/Z coordinate lies inside the polygon, false otherwise. Unchanged if no polygon is found. [opt]
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus FindNearestPoly(RcVec3f center, RcVec3f halfExtents, IDtQueryFilter filter,
|
public DtStatus FindNearestPoly(Vector3 center, Vector3 halfExtents, IDtQueryFilter filter,
|
||||||
out long nearestRef, out RcVec3f nearestPt, out bool isOverPoly)
|
out long nearestRef, out Vector3 nearestPt, out bool isOverPoly)
|
||||||
{
|
{
|
||||||
nearestRef = 0;
|
nearestRef = 0;
|
||||||
nearestPt = center;
|
nearestPt = center;
|
||||||
|
@ -574,7 +565,7 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: (PP) duplicate?
|
// FIXME: (PP) duplicate?
|
||||||
protected void QueryPolygonsInTile(DtMeshTile tile, RcVec3f qmin, RcVec3f qmax, IDtQueryFilter filter, IDtPolyQuery query)
|
protected void QueryPolygonsInTile(DtMeshTile tile, Vector3 qmin, Vector3 qmax, IDtQueryFilter filter, IDtPolyQuery query)
|
||||||
{
|
{
|
||||||
if (tile.data.bvTree != null)
|
if (tile.data.bvTree != null)
|
||||||
{
|
{
|
||||||
|
@ -631,8 +622,8 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RcVec3f bmin = new RcVec3f();
|
Vector3 bmin = new Vector3();
|
||||||
RcVec3f bmax = new RcVec3f();
|
Vector3 bmax = new Vector3();
|
||||||
long @base = m_nav.GetPolyRefBase(tile);
|
long @base = m_nav.GetPolyRefBase(tile);
|
||||||
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
||||||
{
|
{
|
||||||
|
@ -681,7 +672,7 @@ namespace DotRecast.Detour
|
||||||
* The polygon filter to apply to the query.
|
* The polygon filter to apply to the query.
|
||||||
* @return The reference ids of the polygons that overlap the query box.
|
* @return The reference ids of the polygons that overlap the query box.
|
||||||
*/
|
*/
|
||||||
public DtStatus QueryPolygons(RcVec3f center, RcVec3f halfExtents, IDtQueryFilter filter, IDtPolyQuery query)
|
public DtStatus QueryPolygons(Vector3 center, Vector3 halfExtents, IDtQueryFilter filter, IDtPolyQuery query)
|
||||||
{
|
{
|
||||||
if (!center.IsFinite() || !halfExtents.IsFinite() || null == filter)
|
if (!center.IsFinite() || !halfExtents.IsFinite() || null == filter)
|
||||||
{
|
{
|
||||||
|
@ -689,8 +680,8 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find tiles the query touches.
|
// Find tiles the query touches.
|
||||||
RcVec3f bmin = RcVec3f.Subtract(center, halfExtents);
|
Vector3 bmin = Vector3.Subtract(center, halfExtents);
|
||||||
RcVec3f bmax = RcVec3f.Add(center, halfExtents);
|
Vector3 bmax = Vector3.Add(center, halfExtents);
|
||||||
foreach (var t in QueryTiles(center, halfExtents))
|
foreach (var t in QueryTiles(center, halfExtents))
|
||||||
{
|
{
|
||||||
QueryPolygonsInTile(t, bmin, bmax, filter, query);
|
QueryPolygonsInTile(t, bmin, bmax, filter, query);
|
||||||
|
@ -702,15 +693,15 @@ namespace DotRecast.Detour
|
||||||
/**
|
/**
|
||||||
* Finds tiles that overlap the search box.
|
* Finds tiles that overlap the search box.
|
||||||
*/
|
*/
|
||||||
public IList<DtMeshTile> QueryTiles(RcVec3f center, RcVec3f halfExtents)
|
public IList<DtMeshTile> QueryTiles(Vector3 center, Vector3 halfExtents)
|
||||||
{
|
{
|
||||||
if (!center.IsFinite() || !halfExtents.IsFinite())
|
if (!center.IsFinite() || !halfExtents.IsFinite())
|
||||||
{
|
{
|
||||||
return RcImmutableArray<DtMeshTile>.Empty;
|
return RcImmutableArray<DtMeshTile>.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f bmin = RcVec3f.Subtract(center, halfExtents);
|
Vector3 bmin = Vector3.Subtract(center, halfExtents);
|
||||||
RcVec3f bmax = RcVec3f.Add(center, halfExtents);
|
Vector3 bmax = Vector3.Add(center, halfExtents);
|
||||||
m_nav.CalcTileLoc(bmin, out var minx, out var miny);
|
m_nav.CalcTileLoc(bmin, out var minx, out var miny);
|
||||||
m_nav.CalcTileLoc(bmax, out var maxx, out var maxy);
|
m_nav.CalcTileLoc(bmax, out var maxx, out var maxy);
|
||||||
|
|
||||||
|
@ -726,30 +717,27 @@ namespace DotRecast.Detour
|
||||||
return tiles;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @par
|
/**
|
||||||
///
|
* Finds a path from the start polygon to the end polygon.
|
||||||
/// If the end polygon cannot be reached through the navigation graph,
|
*
|
||||||
/// the last polygon in the path will be the nearest the end polygon.
|
* If the end polygon cannot be reached through the navigation graph, the last polygon in the path will be the
|
||||||
///
|
* nearest the end polygon.
|
||||||
/// If the path array is to small to hold the full result, it will be filled as
|
*
|
||||||
/// far as possible from the start polygon toward the end polygon.
|
* The start and end positions are used to calculate traversal costs. (The y-values impact the result.)
|
||||||
///
|
*
|
||||||
/// The start and end positions are used to calculate traversal costs.
|
* @param startRef
|
||||||
/// (The y-values impact the result.)
|
* The reference id of the start polygon.
|
||||||
///
|
* @param endRef
|
||||||
/// @name Standard Pathfinding Functions
|
* The reference id of the end polygon.
|
||||||
/// @{
|
* @param startPos
|
||||||
/// Finds a path from the start polygon to the end polygon.
|
* A position within the start polygon. [(x, y, z)]
|
||||||
/// @param[in] startRef The reference id of the start polygon.
|
* @param endPos
|
||||||
/// @param[in] endRef The reference id of the end polygon.
|
* A position within the end polygon. [(x, y, z)]
|
||||||
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
* @param filter
|
||||||
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
* The polygon filter to apply to the query.
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
* @return Found path
|
||||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
*/
|
||||||
/// [(polyRef) * @p pathCount]
|
public DtStatus FindPath(long startRef, long endRef, Vector3 startPos, Vector3 endPos, IDtQueryFilter filter, ref List<long> path, DtFindPathOption fpo)
|
||||||
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
|
||||||
/// @param[in] maxPath The maximum number of polygons the @p path array can hold. [Limit: >= 1]
|
|
||||||
public DtStatus FindPath(long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter, ref List<long> path, DtFindPathOption fpo)
|
|
||||||
{
|
{
|
||||||
if (null == path)
|
if (null == path)
|
||||||
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
||||||
|
@ -799,8 +787,7 @@ namespace DotRecast.Detour
|
||||||
DtNode lastBestNode = startNode;
|
DtNode lastBestNode = startNode;
|
||||||
float lastBestNodeCost = startNode.total;
|
float lastBestNodeCost = startNode.total;
|
||||||
|
|
||||||
DtRaycastHit rayHit = new DtRaycastHit();
|
|
||||||
rayHit.path = new List<long>();
|
|
||||||
while (!m_openList.IsEmpty())
|
while (!m_openList.IsEmpty())
|
||||||
{
|
{
|
||||||
// Remove node from open list and put it in closed list.
|
// Remove node from open list and put it in closed list.
|
||||||
|
@ -845,7 +832,7 @@ namespace DotRecast.Detour
|
||||||
if ((options & DtFindPathOptions.DT_FINDPATH_ANY_ANGLE) != 0)
|
if ((options & DtFindPathOptions.DT_FINDPATH_ANY_ANGLE) != 0)
|
||||||
{
|
{
|
||||||
if ((parentRef != 0) &&
|
if ((parentRef != 0) &&
|
||||||
(raycastLimitSqr >= float.MaxValue || RcVec3f.DistanceSquared(parentNode.pos, bestNode.pos) < raycastLimitSqr))
|
(raycastLimitSqr >= float.MaxValue || Vector3.DistanceSquared(parentNode.pos, bestNode.pos) < raycastLimitSqr))
|
||||||
{
|
{
|
||||||
tryLOS = true;
|
tryLOS = true;
|
||||||
}
|
}
|
||||||
|
@ -900,13 +887,13 @@ namespace DotRecast.Detour
|
||||||
if (tryLOS)
|
if (tryLOS)
|
||||||
{
|
{
|
||||||
var rayStatus = Raycast(parentRef, parentNode.pos, neighbourPos, filter,
|
var rayStatus = Raycast(parentRef, parentNode.pos, neighbourPos, filter,
|
||||||
DtRaycastOptions.DT_RAYCAST_USE_COSTS, ref rayHit, grandpaRef);
|
DtRaycastOptions.DT_RAYCAST_USE_COSTS, grandpaRef, out var rayHit);
|
||||||
if (rayStatus.Succeeded())
|
if (rayStatus.Succeeded())
|
||||||
{
|
{
|
||||||
foundShortCut = rayHit.t >= 1.0f;
|
foundShortCut = rayHit.t >= 1.0f;
|
||||||
if (foundShortCut)
|
if (foundShortCut)
|
||||||
{
|
{
|
||||||
shortcut = new List<long>(rayHit.path);
|
shortcut = rayHit.path;
|
||||||
// shortcut found using raycast. Using shorter cost
|
// shortcut found using raycast. Using shorter cost
|
||||||
// instead
|
// instead
|
||||||
cost = parentNode.cost + rayHit.pathCost;
|
cost = parentNode.cost + rayHit.pathCost;
|
||||||
|
@ -1009,17 +996,17 @@ namespace DotRecast.Detour
|
||||||
* query options (see: #FindPathOptions)
|
* query options (see: #FindPathOptions)
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public DtStatus InitSlicedFindPath(long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter, int options)
|
public DtStatus InitSlicedFindPath(long startRef, long endRef, Vector3 startPos, Vector3 endPos, IDtQueryFilter filter, int options)
|
||||||
{
|
{
|
||||||
return InitSlicedFindPath(startRef, endRef, startPos, endPos, filter, options, DtDefaultQueryHeuristic.Default, -1.0f);
|
return InitSlicedFindPath(startRef, endRef, startPos, endPos, filter, options, DtDefaultQueryHeuristic.Default, -1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtStatus InitSlicedFindPath(long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter, int options, float raycastLimit)
|
public DtStatus InitSlicedFindPath(long startRef, long endRef, Vector3 startPos, Vector3 endPos, IDtQueryFilter filter, int options, float raycastLimit)
|
||||||
{
|
{
|
||||||
return InitSlicedFindPath(startRef, endRef, startPos, endPos, filter, options, DtDefaultQueryHeuristic.Default, raycastLimit);
|
return InitSlicedFindPath(startRef, endRef, startPos, endPos, filter, options, DtDefaultQueryHeuristic.Default, raycastLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtStatus InitSlicedFindPath(long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter, int options, IDtQueryHeuristic heuristic, float raycastLimit)
|
public DtStatus InitSlicedFindPath(long startRef, long endRef, Vector3 startPos, Vector3 endPos, IDtQueryFilter filter, int options, IDtQueryHeuristic heuristic, float raycastLimit)
|
||||||
{
|
{
|
||||||
// Init path state.
|
// Init path state.
|
||||||
m_query = new DtQueryData();
|
m_query = new DtQueryData();
|
||||||
|
@ -1096,9 +1083,6 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_FAILURE;
|
return DtStatus.DT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
var rayHit = new DtRaycastHit();
|
|
||||||
rayHit.path = new List<long>();
|
|
||||||
|
|
||||||
int iter = 0;
|
int iter = 0;
|
||||||
while (iter < maxIter && !m_openList.IsEmpty())
|
while (iter < maxIter && !m_openList.IsEmpty())
|
||||||
{
|
{
|
||||||
|
@ -1166,7 +1150,7 @@ namespace DotRecast.Detour
|
||||||
if ((m_query.options & DtFindPathOptions.DT_FINDPATH_ANY_ANGLE) != 0)
|
if ((m_query.options & DtFindPathOptions.DT_FINDPATH_ANY_ANGLE) != 0)
|
||||||
{
|
{
|
||||||
if ((parentRef != 0) &&
|
if ((parentRef != 0) &&
|
||||||
(m_query.raycastLimitSqr >= float.MaxValue || RcVec3f.DistanceSquared(parentNode.pos, bestNode.pos) < m_query.raycastLimitSqr))
|
(m_query.raycastLimitSqr >= float.MaxValue || Vector3.DistanceSquared(parentNode.pos, bestNode.pos) < m_query.raycastLimitSqr))
|
||||||
{
|
{
|
||||||
tryLOS = true;
|
tryLOS = true;
|
||||||
}
|
}
|
||||||
|
@ -1224,13 +1208,13 @@ namespace DotRecast.Detour
|
||||||
if (tryLOS)
|
if (tryLOS)
|
||||||
{
|
{
|
||||||
status = Raycast(parentRef, parentNode.pos, neighbourPos, m_query.filter,
|
status = Raycast(parentRef, parentNode.pos, neighbourPos, m_query.filter,
|
||||||
DtRaycastOptions.DT_RAYCAST_USE_COSTS, ref rayHit, grandpaRef);
|
DtRaycastOptions.DT_RAYCAST_USE_COSTS, grandpaRef, out var rayHit);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
foundShortCut = rayHit.t >= 1.0f;
|
foundShortCut = rayHit.t >= 1.0f;
|
||||||
if (foundShortCut)
|
if (foundShortCut)
|
||||||
{
|
{
|
||||||
shortcut = new List<long>(rayHit.path);
|
shortcut = rayHit.path;
|
||||||
// shortcut found using raycast. Using shorter cost
|
// shortcut found using raycast. Using shorter cost
|
||||||
// instead
|
// instead
|
||||||
cost = parentNode.cost + rayHit.pathCost;
|
cost = parentNode.cost + rayHit.pathCost;
|
||||||
|
@ -1422,7 +1406,7 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_SUCCESS | details;
|
return DtStatus.DT_SUCCESS | details;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DtStatus AppendVertex(RcVec3f pos, int flags, long refs, ref List<DtStraightPath> straightPath,
|
protected DtStatus AppendVertex(Vector3 pos, int flags, long refs, ref List<DtStraightPath> straightPath,
|
||||||
int maxStraightPath)
|
int maxStraightPath)
|
||||||
{
|
{
|
||||||
if (straightPath.Count > 0 && DtUtils.VEqual(straightPath[straightPath.Count - 1].pos, pos))
|
if (straightPath.Count > 0 && DtUtils.VEqual(straightPath[straightPath.Count - 1].pos, pos))
|
||||||
|
@ -1448,7 +1432,7 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_IN_PROGRESS;
|
return DtStatus.DT_IN_PROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DtStatus AppendPortals(int startIdx, int endIdx, RcVec3f endPos, List<long> path,
|
protected DtStatus AppendPortals(int startIdx, int endIdx, Vector3 endPos, List<long> path,
|
||||||
ref List<DtStraightPath> straightPath, int maxStraightPath, int options)
|
ref List<DtStraightPath> straightPath, int maxStraightPath, int options)
|
||||||
{
|
{
|
||||||
var startPos = straightPath[straightPath.Count - 1].pos;
|
var startPos = straightPath[straightPath.Count - 1].pos;
|
||||||
|
@ -1489,7 +1473,7 @@ namespace DotRecast.Detour
|
||||||
// Append intersection
|
// Append intersection
|
||||||
if (DtUtils.IntersectSegSeg2D(startPos, endPos, left, right, out var _, out var t))
|
if (DtUtils.IntersectSegSeg2D(startPos, endPos, left, right, out var _, out var t))
|
||||||
{
|
{
|
||||||
var pt = RcVec3f.Lerp(left, right, t);
|
var pt = Vector3.Lerp(left, right, t);
|
||||||
stat = AppendVertex(pt, 0, path[i + 1], ref straightPath, maxStraightPath);
|
stat = AppendVertex(pt, 0, path[i + 1], ref straightPath, maxStraightPath);
|
||||||
if (!stat.InProgress())
|
if (!stat.InProgress())
|
||||||
{
|
{
|
||||||
|
@ -1527,7 +1511,7 @@ namespace DotRecast.Detour
|
||||||
/// @param[in] maxStraightPath The maximum number of points the straight path arrays can hold. [Limit: > 0]
|
/// @param[in] maxStraightPath The maximum number of points the straight path arrays can hold. [Limit: > 0]
|
||||||
/// @param[in] options Query options. (see: #dtStraightPathOptions)
|
/// @param[in] options Query options. (see: #dtStraightPathOptions)
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public virtual DtStatus FindStraightPath(RcVec3f startPos, RcVec3f endPos, List<long> path,
|
public virtual DtStatus FindStraightPath(Vector3 startPos, Vector3 endPos, List<long> path,
|
||||||
ref List<DtStraightPath> straightPath,
|
ref List<DtStraightPath> straightPath,
|
||||||
int maxStraightPath, int options)
|
int maxStraightPath, int options)
|
||||||
{
|
{
|
||||||
|
@ -1561,9 +1545,9 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
if (path.Count > 1)
|
if (path.Count > 1)
|
||||||
{
|
{
|
||||||
RcVec3f portalApex = closestStartPos;
|
Vector3 portalApex = closestStartPos;
|
||||||
RcVec3f portalLeft = portalApex;
|
Vector3 portalLeft = portalApex;
|
||||||
RcVec3f portalRight = portalApex;
|
Vector3 portalRight = portalApex;
|
||||||
int apexIndex = 0;
|
int apexIndex = 0;
|
||||||
int leftIndex = 0;
|
int leftIndex = 0;
|
||||||
int rightIndex = 0;
|
int rightIndex = 0;
|
||||||
|
@ -1576,8 +1560,8 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
for (int i = 0; i < path.Count; ++i)
|
for (int i = 0; i < path.Count; ++i)
|
||||||
{
|
{
|
||||||
RcVec3f left;
|
Vector3 left;
|
||||||
RcVec3f right;
|
Vector3 right;
|
||||||
int toType;
|
int toType;
|
||||||
|
|
||||||
if (i + 1 < path.Count)
|
if (i + 1 < path.Count)
|
||||||
|
@ -1786,11 +1770,11 @@ namespace DotRecast.Detour
|
||||||
/// @param[out] visitedCount The number of polygons visited during the move.
|
/// @param[out] visitedCount The number of polygons visited during the move.
|
||||||
/// @param[in] maxVisitedSize The maximum number of polygons the @p visited array can hold.
|
/// @param[in] maxVisitedSize The maximum number of polygons the @p visited array can hold.
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus MoveAlongSurface(long startRef, RcVec3f startPos, RcVec3f endPos,
|
public DtStatus MoveAlongSurface(long startRef, Vector3 startPos, Vector3 endPos,
|
||||||
IDtQueryFilter filter,
|
IDtQueryFilter filter,
|
||||||
out RcVec3f resultPos, ref List<long> visited)
|
out Vector3 resultPos, ref List<long> visited)
|
||||||
{
|
{
|
||||||
resultPos = RcVec3f.Zero;
|
resultPos = Vector3.Zero;
|
||||||
|
|
||||||
if (null != visited)
|
if (null != visited)
|
||||||
visited.Clear();
|
visited.Clear();
|
||||||
|
@ -1802,9 +1786,9 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_tinyNodePool.Clear();
|
DtNodePool tinyNodePool = new DtNodePool();
|
||||||
|
|
||||||
DtNode startNode = m_tinyNodePool.GetNode(startRef);
|
DtNode startNode = tinyNodePool.GetNode(startRef);
|
||||||
startNode.pidx = 0;
|
startNode.pidx = 0;
|
||||||
startNode.cost = 0;
|
startNode.cost = 0;
|
||||||
startNode.total = 0;
|
startNode.total = 0;
|
||||||
|
@ -1813,14 +1797,14 @@ namespace DotRecast.Detour
|
||||||
LinkedList<DtNode> stack = new LinkedList<DtNode>();
|
LinkedList<DtNode> stack = new LinkedList<DtNode>();
|
||||||
stack.AddLast(startNode);
|
stack.AddLast(startNode);
|
||||||
|
|
||||||
RcVec3f bestPos = new RcVec3f();
|
Vector3 bestPos = new Vector3();
|
||||||
float bestDist = float.MaxValue;
|
float bestDist = float.MaxValue;
|
||||||
DtNode bestNode = null;
|
DtNode bestNode = null;
|
||||||
bestPos = startPos;
|
bestPos = startPos;
|
||||||
|
|
||||||
// Search constraints
|
// Search constraints
|
||||||
var searchPos = RcVec3f.Lerp(startPos, endPos, 0.5f);
|
var searchPos = Vector3.Lerp(startPos, endPos, 0.5f);
|
||||||
float searchRadSqr = RcMath.Sqr(RcVec3f.Distance(startPos, endPos) / 2.0f + 0.001f);
|
float searchRadSqr = RcMath.Sqr(Vector3.Distance(startPos, endPos) / 2.0f + 0.001f);
|
||||||
|
|
||||||
float[] verts = new float[m_nav.GetMaxVertsPerPoly() * 3];
|
float[] verts = new float[m_nav.GetMaxVertsPerPoly() * 3];
|
||||||
|
|
||||||
|
@ -1909,7 +1893,7 @@ namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
for (int k = 0; k < nneis; ++k)
|
for (int k = 0; k < nneis; ++k)
|
||||||
{
|
{
|
||||||
DtNode neighbourNode = m_tinyNodePool.GetNode(neis[k]);
|
DtNode neighbourNode = tinyNodePool.GetNode(neis[k]);
|
||||||
// Skip if already visited.
|
// Skip if already visited.
|
||||||
if ((neighbourNode.flags & DtNodeFlags.DT_NODE_CLOSED) != 0)
|
if ((neighbourNode.flags & DtNodeFlags.DT_NODE_CLOSED) != 0)
|
||||||
{
|
{
|
||||||
|
@ -1927,7 +1911,7 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark as the node as visited and push to queue.
|
// Mark as the node as visited and push to queue.
|
||||||
neighbourNode.pidx = m_tinyNodePool.GetNodeIdx(curNode);
|
neighbourNode.pidx = tinyNodePool.GetNodeIdx(curNode);
|
||||||
neighbourNode.flags |= DtNodeFlags.DT_NODE_CLOSED;
|
neighbourNode.flags |= DtNodeFlags.DT_NODE_CLOSED;
|
||||||
stack.AddLast(neighbourNode);
|
stack.AddLast(neighbourNode);
|
||||||
}
|
}
|
||||||
|
@ -1942,8 +1926,8 @@ namespace DotRecast.Detour
|
||||||
DtNode node = bestNode;
|
DtNode node = bestNode;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
DtNode next = m_tinyNodePool.GetNodeAtIdx(node.pidx);
|
DtNode next = tinyNodePool.GetNodeAtIdx(node.pidx);
|
||||||
node.pidx = m_tinyNodePool.GetNodeIdx(prev);
|
node.pidx = tinyNodePool.GetNodeIdx(prev);
|
||||||
prev = node;
|
prev = node;
|
||||||
node = next;
|
node = next;
|
||||||
} while (node != null);
|
} while (node != null);
|
||||||
|
@ -1953,7 +1937,7 @@ namespace DotRecast.Detour
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
visited.Add(node.id);
|
visited.Add(node.id);
|
||||||
node = m_tinyNodePool.GetNodeAtIdx(node.pidx);
|
node = tinyNodePool.GetNodeAtIdx(node.pidx);
|
||||||
} while (node != null);
|
} while (node != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1962,10 +1946,10 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_SUCCESS;
|
return DtStatus.DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DtStatus GetPortalPoints(long from, long to, out RcVec3f left, out RcVec3f right, out int fromType, out int toType)
|
protected DtStatus GetPortalPoints(long from, long to, out Vector3 left, out Vector3 right, out int fromType, out int toType)
|
||||||
{
|
{
|
||||||
left = RcVec3f.Zero;
|
left = Vector3.Zero;
|
||||||
right = RcVec3f.Zero;
|
right = Vector3.Zero;
|
||||||
fromType = 0;
|
fromType = 0;
|
||||||
toType = 0;
|
toType = 0;
|
||||||
|
|
||||||
|
@ -1991,10 +1975,10 @@ namespace DotRecast.Detour
|
||||||
// Returns portal points between two polygons.
|
// Returns portal points between two polygons.
|
||||||
protected DtStatus GetPortalPoints(long from, DtPoly fromPoly, DtMeshTile fromTile,
|
protected DtStatus GetPortalPoints(long from, DtPoly fromPoly, DtMeshTile fromTile,
|
||||||
long to, DtPoly toPoly, DtMeshTile toTile,
|
long to, DtPoly toPoly, DtMeshTile toTile,
|
||||||
out RcVec3f left, out RcVec3f right)
|
out Vector3 left, out Vector3 right)
|
||||||
{
|
{
|
||||||
left = RcVec3f.Zero;
|
left = Vector3.Zero;
|
||||||
right = RcVec3f.Zero;
|
right = Vector3.Zero;
|
||||||
|
|
||||||
// Find the link that points to the 'to' polygon.
|
// Find the link that points to the 'to' polygon.
|
||||||
DtLink link = null;
|
DtLink link = null;
|
||||||
|
@ -2088,7 +2072,7 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DtStatus GetEdgeMidPoint(long from, DtPoly fromPoly, DtMeshTile fromTile, long to,
|
protected DtStatus GetEdgeMidPoint(long from, DtPoly fromPoly, DtMeshTile fromTile, long to,
|
||||||
DtPoly toPoly, DtMeshTile toTile, ref RcVec3f mid)
|
DtPoly toPoly, DtMeshTile toTile, ref Vector3 mid)
|
||||||
{
|
{
|
||||||
var ppStatus = GetPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, out var left, out var right);
|
var ppStatus = GetPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, out var left, out var right);
|
||||||
if (ppStatus.Failed())
|
if (ppStatus.Failed())
|
||||||
|
@ -2103,9 +2087,9 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_SUCCESS;
|
return DtStatus.DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DtStatus GetEdgeIntersectionPoint(RcVec3f fromPos, long from, DtPoly fromPoly, DtMeshTile fromTile,
|
protected DtStatus GetEdgeIntersectionPoint(Vector3 fromPos, long from, DtPoly fromPoly, DtMeshTile fromTile,
|
||||||
RcVec3f toPos, long to, DtPoly toPoly, DtMeshTile toTile,
|
Vector3 toPos, long to, DtPoly toPoly, DtMeshTile toTile,
|
||||||
ref RcVec3f pt)
|
ref Vector3 pt)
|
||||||
{
|
{
|
||||||
var ppStatus = GetPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, out var left, out var right);
|
var ppStatus = GetPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, out var left, out var right);
|
||||||
if (ppStatus.Failed())
|
if (ppStatus.Failed())
|
||||||
|
@ -2119,63 +2103,10 @@ namespace DotRecast.Detour
|
||||||
t = Math.Clamp(t2, 0.1f, 0.9f);
|
t = Math.Clamp(t2, 0.1f, 0.9f);
|
||||||
}
|
}
|
||||||
|
|
||||||
pt = RcVec3f.Lerp(left, right, t);
|
pt = Vector3.Lerp(left, right, t);
|
||||||
return DtStatus.DT_SUCCESS;
|
return DtStatus.DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @par
|
|
||||||
///
|
|
||||||
/// This method is meant to be used for quick, short distance checks.
|
|
||||||
///
|
|
||||||
/// If the path array is too small to hold the result, it will be filled as
|
|
||||||
/// far as possible from the start postion toward the end position.
|
|
||||||
///
|
|
||||||
/// <b>Using the Hit Parameter (t)</b>
|
|
||||||
///
|
|
||||||
/// If the hit parameter is a very high value (FLT_MAX), then the ray has hit
|
|
||||||
/// the end position. In this case the path represents a valid corridor to the
|
|
||||||
/// end position and the value of @p hitNormal is undefined.
|
|
||||||
///
|
|
||||||
/// If the hit parameter is zero, then the start position is on the wall that
|
|
||||||
/// was hit and the value of @p hitNormal is undefined.
|
|
||||||
///
|
|
||||||
/// If 0 < t < 1.0 then the following applies:
|
|
||||||
///
|
|
||||||
/// @code
|
|
||||||
/// distanceToHitBorder = distanceToEndPosition * t
|
|
||||||
/// hitPoint = startPos + (endPos - startPos) * t
|
|
||||||
/// @endcode
|
|
||||||
///
|
|
||||||
/// <b>Use Case Restriction</b>
|
|
||||||
///
|
|
||||||
/// The raycast ignores the y-value of the end position. (2D check.) This
|
|
||||||
/// places significant limits on how it can be used. For example:
|
|
||||||
///
|
|
||||||
/// Consider a scene where there is a main floor with a second floor balcony
|
|
||||||
/// that hangs over the main floor. So the first floor mesh extends below the
|
|
||||||
/// balcony mesh. The start position is somewhere on the first floor. The end
|
|
||||||
/// position is on the balcony.
|
|
||||||
///
|
|
||||||
/// The raycast will search toward the end position along the first floor mesh.
|
|
||||||
/// If it reaches the end position's xz-coordinates it will indicate FLT_MAX
|
|
||||||
/// (no wall hit), meaning it reached the end position. This is one example of why
|
|
||||||
/// this method is meant for short distance checks.
|
|
||||||
///
|
|
||||||
public DtStatus Raycast(long startRef, RcVec3f startPos, RcVec3f endPos,
|
|
||||||
IDtQueryFilter filter,
|
|
||||||
out float t, out RcVec3f hitNormal, ref List<long> path)
|
|
||||||
{
|
|
||||||
DtRaycastHit hit = new DtRaycastHit();
|
|
||||||
hit.path = path;
|
|
||||||
|
|
||||||
DtStatus status = Raycast(startRef, startPos, endPos, filter, 0, ref hit, 0);
|
|
||||||
|
|
||||||
t = hit.t;
|
|
||||||
hitNormal = hit.hitNormal;
|
|
||||||
path = hit.path;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @par
|
/// @par
|
||||||
///
|
///
|
||||||
|
@ -2229,10 +2160,11 @@ namespace DotRecast.Detour
|
||||||
/// @param[out] pathCount The number of visited polygons. [opt]
|
/// @param[out] pathCount The number of visited polygons. [opt]
|
||||||
/// @param[in] maxPath The maximum number of polygons the @p path array can hold.
|
/// @param[in] maxPath The maximum number of polygons the @p path array can hold.
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus Raycast(long startRef, RcVec3f startPos, RcVec3f endPos,
|
public DtStatus Raycast(long startRef, Vector3 startPos, Vector3 endPos, IDtQueryFilter filter, int options,
|
||||||
IDtQueryFilter filter, int options,
|
long prevRef, out DtRaycastHit hit)
|
||||||
ref DtRaycastHit hit, long prevRef)
|
|
||||||
{
|
{
|
||||||
|
hit = null;
|
||||||
|
|
||||||
// Validate input
|
// Validate input
|
||||||
if (!m_nav.IsValidPolyRef(startRef) || !startPos.IsFinite() || !endPos.IsFinite()
|
if (!m_nav.IsValidPolyRef(startRef) || !startPos.IsFinite() || !endPos.IsFinite()
|
||||||
|| null == filter || (prevRef != 0 && !m_nav.IsValidPolyRef(prevRef)))
|
|| null == filter || (prevRef != 0 && !m_nav.IsValidPolyRef(prevRef)))
|
||||||
|
@ -2240,18 +2172,15 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
hit.t = 0;
|
hit = new DtRaycastHit();
|
||||||
hit.path.Clear();
|
|
||||||
hit.pathCost = 0;
|
|
||||||
|
|
||||||
RcVec3f[] verts = new RcVec3f[m_nav.GetMaxVertsPerPoly() + 1];
|
Vector3[] verts = new Vector3[m_nav.GetMaxVertsPerPoly() + 1];
|
||||||
|
|
||||||
RcVec3f curPos = RcVec3f.Zero;
|
Vector3 curPos = Vector3.Zero;
|
||||||
RcVec3f lastPos = RcVec3f.Zero;
|
Vector3 lastPos = Vector3.Zero;
|
||||||
|
|
||||||
curPos = startPos;
|
curPos = startPos;
|
||||||
RcVec3f dir = RcVec3f.Subtract(endPos, startPos);
|
var dir = Vector3.Subtract(endPos, startPos);
|
||||||
hit.hitNormal = RcVec3f.Zero;
|
|
||||||
|
|
||||||
DtMeshTile prevTile, tile, nextTile;
|
DtMeshTile prevTile, tile, nextTile;
|
||||||
DtPoly prevPoly, poly, nextPoly;
|
DtPoly prevPoly, poly, nextPoly;
|
||||||
|
@ -2415,8 +2344,8 @@ namespace DotRecast.Detour
|
||||||
curPos = RcVecUtils.Mad(startPos, dir, hit.t);
|
curPos = RcVecUtils.Mad(startPos, dir, hit.t);
|
||||||
var e1 = verts[segMax];
|
var e1 = verts[segMax];
|
||||||
var e2 = verts[(segMax + 1) % nv];
|
var e2 = verts[(segMax + 1) % nv];
|
||||||
var eDir = RcVec3f.Subtract(e2, e1);
|
var eDir = Vector3.Subtract(e2, e1);
|
||||||
var diff = RcVec3f.Subtract(curPos, e1);
|
var diff = Vector3.Subtract(curPos, e1);
|
||||||
float s = RcMath.Sqr(eDir.X) > RcMath.Sqr(eDir.Z) ? diff.X / eDir.X : diff.Z / eDir.Z;
|
float s = RcMath.Sqr(eDir.X) > RcMath.Sqr(eDir.Z) ? diff.X / eDir.X : diff.Z / eDir.Z;
|
||||||
curPos.Y = e1.Y + eDir.Y * s;
|
curPos.Y = e1.Y + eDir.Y * s;
|
||||||
|
|
||||||
|
@ -2435,7 +2364,7 @@ namespace DotRecast.Detour
|
||||||
// int vb = b * 3;
|
// int vb = b * 3;
|
||||||
float dx = verts[b].X - verts[a].X;
|
float dx = verts[b].X - verts[a].X;
|
||||||
float dz = verts[b].Z - verts[a].X;
|
float dz = verts[b].Z - verts[a].X;
|
||||||
hit.hitNormal = RcVec3f.Normalize(new RcVec3f(dz, 0, -dx));
|
hit.hitNormal = Vector3.Normalize(new Vector3(dz, 0, -dx));
|
||||||
return DtStatus.DT_SUCCESS;
|
return DtStatus.DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2495,7 +2424,7 @@ namespace DotRecast.Detour
|
||||||
/// @param[out] resultCount The number of polygons found. [opt]
|
/// @param[out] resultCount The number of polygons found. [opt]
|
||||||
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus FindPolysAroundCircle(long startRef, RcVec3f centerPos, float radius, IDtQueryFilter filter,
|
public DtStatus FindPolysAroundCircle(long startRef, Vector3 centerPos, float radius, IDtQueryFilter filter,
|
||||||
ref List<long> resultRef, ref List<long> resultParent, ref List<float> resultCost)
|
ref List<long> resultRef, ref List<long> resultParent, ref List<float> resultCost)
|
||||||
{
|
{
|
||||||
if (null != resultRef)
|
if (null != resultRef)
|
||||||
|
@ -2599,7 +2528,7 @@ namespace DotRecast.Detour
|
||||||
// Cost
|
// Cost
|
||||||
if (neighbourNode.flags == 0)
|
if (neighbourNode.flags == 0)
|
||||||
{
|
{
|
||||||
neighbourNode.pos = RcVec3f.Lerp(va, vb, 0.5f);
|
neighbourNode.pos = Vector3.Lerp(va, vb, 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
float cost = filter.GetCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile, parentPoly, bestRef,
|
float cost = filter.GetCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile, parentPoly, bestRef,
|
||||||
|
@ -2666,7 +2595,7 @@ namespace DotRecast.Detour
|
||||||
/// @param[out] resultCount The number of polygons found.
|
/// @param[out] resultCount The number of polygons found.
|
||||||
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus FindPolysAroundShape(long startRef, RcVec3f[] verts, IDtQueryFilter filter,
|
public DtStatus FindPolysAroundShape(long startRef, Vector3[] verts, IDtQueryFilter filter,
|
||||||
ref List<long> resultRef, ref List<long> resultParent, ref List<float> resultCost)
|
ref List<long> resultRef, ref List<long> resultParent, ref List<float> resultCost)
|
||||||
{
|
{
|
||||||
resultRef.Clear();
|
resultRef.Clear();
|
||||||
|
@ -2683,7 +2612,7 @@ namespace DotRecast.Detour
|
||||||
m_nodePool.Clear();
|
m_nodePool.Clear();
|
||||||
m_openList.Clear();
|
m_openList.Clear();
|
||||||
|
|
||||||
RcVec3f centerPos = RcVec3f.Zero;
|
Vector3 centerPos = Vector3.Zero;
|
||||||
for (int i = 0; i < nverts; ++i)
|
for (int i = 0; i < nverts; ++i)
|
||||||
{
|
{
|
||||||
centerPos += verts[i];
|
centerPos += verts[i];
|
||||||
|
@ -2781,7 +2710,7 @@ namespace DotRecast.Detour
|
||||||
// Cost
|
// Cost
|
||||||
if (neighbourNode.flags == 0)
|
if (neighbourNode.flags == 0)
|
||||||
{
|
{
|
||||||
neighbourNode.pos = RcVec3f.Lerp(va, vb, 0.5f);
|
neighbourNode.pos = Vector3.Lerp(va, vb, 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
float cost = filter.GetCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile, parentPoly, bestRef,
|
float cost = filter.GetCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile, parentPoly, bestRef,
|
||||||
|
@ -2844,7 +2773,7 @@ namespace DotRecast.Detour
|
||||||
/// @param[out] resultRef The reference ids of the polygons touched by the circle.
|
/// @param[out] resultRef The reference ids of the polygons touched by the circle.
|
||||||
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus FindLocalNeighbourhood(long startRef, RcVec3f centerPos, float radius,
|
public DtStatus FindLocalNeighbourhood(long startRef, Vector3 centerPos, float radius,
|
||||||
IDtQueryFilter filter,
|
IDtQueryFilter filter,
|
||||||
ref List<long> resultRef, ref List<long> resultParent)
|
ref List<long> resultRef, ref List<long> resultParent)
|
||||||
{
|
{
|
||||||
|
@ -2859,9 +2788,9 @@ namespace DotRecast.Detour
|
||||||
resultRef.Clear();
|
resultRef.Clear();
|
||||||
resultParent.Clear();
|
resultParent.Clear();
|
||||||
|
|
||||||
m_tinyNodePool.Clear();
|
DtNodePool tinyNodePool = new DtNodePool();
|
||||||
|
|
||||||
DtNode startNode = m_tinyNodePool.GetNode(startRef);
|
DtNode startNode = tinyNodePool.GetNode(startRef);
|
||||||
startNode.pidx = 0;
|
startNode.pidx = 0;
|
||||||
startNode.id = startRef;
|
startNode.id = startRef;
|
||||||
startNode.flags = DtNodeFlags.DT_NODE_CLOSED;
|
startNode.flags = DtNodeFlags.DT_NODE_CLOSED;
|
||||||
|
@ -2897,7 +2826,7 @@ namespace DotRecast.Detour
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DtNode neighbourNode = m_tinyNodePool.GetNode(neighbourRef);
|
DtNode neighbourNode = tinyNodePool.GetNode(neighbourRef);
|
||||||
// Skip visited.
|
// Skip visited.
|
||||||
if ((neighbourNode.flags & DtNodeFlags.DT_NODE_CLOSED) != 0)
|
if ((neighbourNode.flags & DtNodeFlags.DT_NODE_CLOSED) != 0)
|
||||||
{
|
{
|
||||||
|
@ -2937,7 +2866,7 @@ namespace DotRecast.Detour
|
||||||
// Mark node visited, this is done before the overlap test so that
|
// Mark node visited, this is done before the overlap test so that
|
||||||
// we will not visit the poly again if the test fails.
|
// we will not visit the poly again if the test fails.
|
||||||
neighbourNode.flags |= DtNodeFlags.DT_NODE_CLOSED;
|
neighbourNode.flags |= DtNodeFlags.DT_NODE_CLOSED;
|
||||||
neighbourNode.pidx = m_tinyNodePool.GetNodeIdx(curNode);
|
neighbourNode.pidx = tinyNodePool.GetNodeIdx(curNode);
|
||||||
|
|
||||||
// Check that the polygon does not collide with existing polygons.
|
// Check that the polygon does not collide with existing polygons.
|
||||||
|
|
||||||
|
@ -3172,13 +3101,13 @@ namespace DotRecast.Detour
|
||||||
/// @param[out] hitNormal The normalized ray formed from the wall point to the
|
/// @param[out] hitNormal The normalized ray formed from the wall point to the
|
||||||
/// source point. [(x, y, z)]
|
/// source point. [(x, y, z)]
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public virtual DtStatus FindDistanceToWall(long startRef, RcVec3f centerPos, float maxRadius,
|
public virtual DtStatus FindDistanceToWall(long startRef, Vector3 centerPos, float maxRadius,
|
||||||
IDtQueryFilter filter,
|
IDtQueryFilter filter,
|
||||||
out float hitDist, out RcVec3f hitPos, out RcVec3f hitNormal)
|
out float hitDist, out Vector3 hitPos, out Vector3 hitNormal)
|
||||||
{
|
{
|
||||||
hitDist = 0;
|
hitDist = 0;
|
||||||
hitPos = RcVec3f.Zero;
|
hitPos = Vector3.Zero;
|
||||||
hitNormal = RcVec3f.Zero;
|
hitNormal = Vector3.Zero;
|
||||||
|
|
||||||
// Validate input
|
// Validate input
|
||||||
if (!m_nav.IsValidPolyRef(startRef) || !centerPos.IsFinite() || maxRadius < 0
|
if (!m_nav.IsValidPolyRef(startRef) || !centerPos.IsFinite() || maxRadius < 0
|
||||||
|
@ -3202,8 +3131,8 @@ namespace DotRecast.Detour
|
||||||
float radiusSqr = RcMath.Sqr(maxRadius);
|
float radiusSqr = RcMath.Sqr(maxRadius);
|
||||||
|
|
||||||
var hasBestV = false;
|
var hasBestV = false;
|
||||||
var bestvj = RcVec3f.Zero;
|
var bestvj = Vector3.Zero;
|
||||||
var bestvi = RcVec3f.Zero;
|
var bestvi = Vector3.Zero;
|
||||||
|
|
||||||
var status = DtStatus.DT_SUCCESS;
|
var status = DtStatus.DT_SUCCESS;
|
||||||
while (!m_openList.IsEmpty())
|
while (!m_openList.IsEmpty())
|
||||||
|
@ -3342,7 +3271,7 @@ namespace DotRecast.Detour
|
||||||
ref neighbourNode.pos);
|
ref neighbourNode.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
float total = bestNode.total + RcVec3f.Distance(bestNode.pos, neighbourNode.pos);
|
float total = bestNode.total + Vector3.Distance(bestNode.pos, neighbourNode.pos);
|
||||||
|
|
||||||
// The node is already in open list and the new result is worse, skip.
|
// The node is already in open list and the new result is worse, skip.
|
||||||
if ((neighbourNode.flags & DtNodeFlags.DT_NODE_OPEN) != 0 && total >= neighbourNode.total)
|
if ((neighbourNode.flags & DtNodeFlags.DT_NODE_OPEN) != 0 && total >= neighbourNode.total)
|
||||||
|
@ -3370,8 +3299,8 @@ namespace DotRecast.Detour
|
||||||
// Calc hit normal.
|
// Calc hit normal.
|
||||||
if (hasBestV)
|
if (hasBestV)
|
||||||
{
|
{
|
||||||
var tangent = RcVec3f.Subtract(bestvi, bestvj);
|
var tangent = Vector3.Subtract(bestvi, bestvj);
|
||||||
hitNormal = RcVec3f.Normalize(new RcVec3f(tangent.Z, 0, -tangent.X));
|
hitNormal = Vector3.Normalize(new Vector3(tangent.Z, 0, -tangent.X));
|
||||||
}
|
}
|
||||||
|
|
||||||
hitDist = MathF.Sqrt(radiusSqr);
|
hitDist = MathF.Sqrt(radiusSqr);
|
||||||
|
@ -3406,18 +3335,15 @@ namespace DotRecast.Detour
|
||||||
return m_nav;
|
return m_nav;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a path from the explored nodes in the previous search.
|
/**
|
||||||
/// @param[in] endRef The reference id of the end polygon.
|
* Gets a path from the explored nodes in the previous search.
|
||||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
*
|
||||||
/// [(polyRef) * @p pathCount]
|
* @param endRef
|
||||||
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
* The reference id of the end polygon.
|
||||||
/// @param[in] maxPath The maximum number of polygons the @p path array can hold. [Limit: >= 0]
|
* @returns An ordered list of polygon references representing the path. (Start to end.)
|
||||||
/// @returns The status flags. Returns DT_FAILURE | DT_INVALID_PARAM if any parameter is wrong, or if
|
* @remarks The result of this function depends on the state of the query object. For that reason it should only be
|
||||||
/// @p endRef was not explored in the previous search. Returns DT_SUCCESS | DT_BUFFER_TOO_SMALL
|
* used immediately after one of the two Dijkstra searches, findPolysAroundCircle or findPolysAroundShape.
|
||||||
/// if @p path cannot contain the entire path. In this case it is filled to capacity with a partial path.
|
*/
|
||||||
/// Otherwise returns DT_SUCCESS.
|
|
||||||
/// @remarks The result of this function depends on the state of the query object. For that reason it should only
|
|
||||||
/// be used immediately after one of the two Dijkstra searches, findPolysAroundCircle or findPolysAroundShape.
|
|
||||||
public DtStatus GetPathFromDijkstraSearch(long endRef, ref List<long> path)
|
public DtStatus GetPathFromDijkstraSearch(long endRef, ref List<long> path)
|
||||||
{
|
{
|
||||||
if (!m_nav.IsValidPolyRef(endRef) || null == path)
|
if (!m_nav.IsValidPolyRef(endRef) || null == path)
|
||||||
|
@ -3427,13 +3353,17 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
path.Clear();
|
path.Clear();
|
||||||
|
|
||||||
if (m_nodePool.FindNodes(endRef, out var endNodes) != 1
|
List<DtNode> nodes = m_nodePool.FindNodes(endRef);
|
||||||
|| (endNodes[0].flags & DtNodeFlags.DT_NODE_CLOSED) == 0)
|
if (nodes.Count != 1)
|
||||||
{
|
{
|
||||||
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
DtNode endNode = endNodes[0];
|
DtNode endNode = nodes[0];
|
||||||
|
if ((endNode.flags & DtNodeFlags.DT_NODE_CLOSED) == 0)
|
||||||
|
{
|
||||||
|
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
return GetPathToNode(endNode, ref path);
|
return GetPathToNode(endNode, ref path);
|
||||||
}
|
}
|
||||||
|
@ -3467,11 +3397,10 @@ namespace DotRecast.Detour
|
||||||
return DtStatus.DT_SUCCESS;
|
return DtStatus.DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @par
|
/**
|
||||||
///
|
* The closed list is the list of polygons that were fully evaluated during the last navigation graph search. (A* or
|
||||||
/// The closed list is the list of polygons that were fully evaluated during
|
* Dijkstra)
|
||||||
/// the last navigation graph search. (A* or Dijkstra)
|
*/
|
||||||
///
|
|
||||||
public bool IsInClosedList(long refs)
|
public bool IsInClosedList(long refs)
|
||||||
{
|
{
|
||||||
if (m_nodePool == null)
|
if (m_nodePool == null)
|
||||||
|
@ -3479,10 +3408,9 @@ namespace DotRecast.Detour
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = m_nodePool.FindNodes(refs, out var nodes);
|
foreach (DtNode n in m_nodePool.FindNodes(refs))
|
||||||
for (int i = 0; i < n; ++i)
|
|
||||||
{
|
{
|
||||||
if ((nodes[i].flags & DtNodeFlags.DT_NODE_CLOSED) != 0)
|
if ((n.flags & DtNodeFlags.DT_NODE_CLOSED) != 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -27,7 +28,7 @@ namespace DotRecast.Detour
|
||||||
*/
|
*/
|
||||||
public static class DtNavMeshRaycast
|
public static class DtNavMeshRaycast
|
||||||
{
|
{
|
||||||
public static bool Raycast(DtNavMesh mesh, RcVec3f src, RcVec3f dst, out float hitTime)
|
public static bool Raycast(DtNavMesh mesh, Vector3 src, Vector3 dst, out float hitTime)
|
||||||
{
|
{
|
||||||
hitTime = 0.0f;
|
hitTime = 0.0f;
|
||||||
for (int t = 0; t < mesh.GetMaxTiles(); ++t)
|
for (int t = 0; t < mesh.GetMaxTiles(); ++t)
|
||||||
|
@ -45,7 +46,7 @@ namespace DotRecast.Detour
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool Raycast(DtMeshTile tile, RcVec3f sp, RcVec3f sq, out float hitTime)
|
private static bool Raycast(DtMeshTile tile, Vector3 sp, Vector3 sq, out float hitTime)
|
||||||
{
|
{
|
||||||
hitTime = 0.0f;
|
hitTime = 0.0f;
|
||||||
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
for (int i = 0; i < tile.data.header.polyCount; ++i)
|
||||||
|
@ -58,7 +59,7 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
ref DtPolyDetail pd = ref tile.data.detailMeshes[i];
|
ref DtPolyDetail pd = ref tile.data.detailMeshes[i];
|
||||||
|
|
||||||
RcVec3f[] verts = new RcVec3f[3];
|
Vector3[] verts = new Vector3[3];
|
||||||
for (int j = 0; j < pd.triCount; ++j)
|
for (int j = 0; j < pd.triCount; ++j)
|
||||||
{
|
{
|
||||||
int t = (pd.triBase + j) * 4;
|
int t = (pd.triBase + j) * 4;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -10,7 +11,7 @@ namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public float[] Apply(float[] polyVerts, RcVec3f circleCenter, float radius)
|
public float[] Apply(float[] polyVerts, Vector3 circleCenter, float radius)
|
||||||
{
|
{
|
||||||
return polyVerts;
|
return polyVerts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,39 +20,48 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
public class DtNode
|
public class DtNode
|
||||||
{
|
{
|
||||||
public readonly int ptr;
|
public readonly int index;
|
||||||
|
|
||||||
public RcVec3f pos; // Position of the node.
|
/** Position of the node. */
|
||||||
public float cost; // Cost from previous node to current node.
|
public Vector3 pos = new Vector3();
|
||||||
public float total; // Cost up to the node.
|
|
||||||
public int pidx; // Index to parent node.
|
|
||||||
public int state; // extra state information. A polyRef can have multiple nodes with different extra info. see DT_MAX_STATES_PER_NODE
|
|
||||||
public int flags; // Node flags. A combination of dtNodeFlags.
|
|
||||||
public long id; // Polygon ref the node corresponds to.
|
|
||||||
public List<long> shortcut; // Shortcut found by raycast.
|
|
||||||
|
|
||||||
public DtNode(int ptr)
|
/** Cost of reaching the given node. */
|
||||||
|
public float cost;
|
||||||
|
|
||||||
|
/** Total cost of reaching the goal via the given node including heuristics. */
|
||||||
|
public float total;
|
||||||
|
|
||||||
|
/** Index to parent node. */
|
||||||
|
public int pidx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extra state information. A polyRef can have multiple nodes with different extra info. see DT_MAX_STATES_PER_NODE
|
||||||
|
*/
|
||||||
|
public int state;
|
||||||
|
|
||||||
|
/** Node flags. A combination of dtNodeFlags. */
|
||||||
|
public int flags;
|
||||||
|
|
||||||
|
/** Polygon ref the node corresponds to. */
|
||||||
|
public long id;
|
||||||
|
|
||||||
|
/** Shortcut found by raycast. */
|
||||||
|
public List<long> shortcut;
|
||||||
|
|
||||||
|
public DtNode(int index)
|
||||||
{
|
{
|
||||||
this.ptr = ptr;
|
this.index = index;
|
||||||
}
|
|
||||||
|
|
||||||
public static int ComparisonNodeTotal(DtNode a, DtNode b)
|
|
||||||
{
|
|
||||||
int compare = a.total.CompareTo(b.total);
|
|
||||||
if (0 != compare)
|
|
||||||
return compare;
|
|
||||||
|
|
||||||
return a.ptr.CompareTo(b.ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"Node [ptr={ptr} id={id} cost={cost} total={total}]";
|
return "Node [id=" + id + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,48 +19,40 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
public class DtNodePool
|
public class DtNodePool
|
||||||
{
|
{
|
||||||
private readonly Dictionary<long, List<DtNode>> m_map;
|
private readonly Dictionary<long, List<DtNode>> m_map = new Dictionary<long, List<DtNode>>();
|
||||||
|
private readonly List<DtNode> m_nodes = new List<DtNode>();
|
||||||
private int m_nodeCount;
|
|
||||||
private readonly List<DtNode> m_nodes;
|
|
||||||
|
|
||||||
public DtNodePool()
|
public DtNodePool()
|
||||||
{
|
{
|
||||||
m_map = new Dictionary<long, List<DtNode>>();
|
|
||||||
m_nodes = new List<DtNode>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
|
m_nodes.Clear();
|
||||||
m_map.Clear();
|
m_map.Clear();
|
||||||
m_nodeCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetNodeCount()
|
public List<DtNode> FindNodes(long id)
|
||||||
{
|
{
|
||||||
return m_nodeCount;
|
var hasNode = m_map.TryGetValue(id, out var nodes);
|
||||||
}
|
;
|
||||||
|
if (nodes == null)
|
||||||
public int FindNodes(long id, out List<DtNode> nodes)
|
|
||||||
{
|
|
||||||
var hasNode = m_map.TryGetValue(id, out nodes);
|
|
||||||
if (hasNode)
|
|
||||||
{
|
{
|
||||||
return nodes.Count;
|
nodes = new List<DtNode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtNode FindNode(long id)
|
public DtNode FindNode(long id)
|
||||||
{
|
{
|
||||||
m_map.TryGetValue(id, out var nodes);
|
var hasNode = m_map.TryGetValue(id, out var nodes);
|
||||||
|
;
|
||||||
if (nodes != null && 0 != nodes.Count)
|
if (nodes != null && 0 != nodes.Count)
|
||||||
{
|
{
|
||||||
return nodes[0];
|
return nodes[0];
|
||||||
|
@ -71,7 +63,7 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
public DtNode GetNode(long id, int state)
|
public DtNode GetNode(long id, int state)
|
||||||
{
|
{
|
||||||
m_map.TryGetValue(id, out var nodes);
|
var hasNode = m_map.TryGetValue(id, out var nodes);
|
||||||
if (nodes != null)
|
if (nodes != null)
|
||||||
{
|
{
|
||||||
foreach (DtNode node in nodes)
|
foreach (DtNode node in nodes)
|
||||||
|
@ -93,22 +85,10 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
private DtNode Create(long id, int state, List<DtNode> nodes)
|
private DtNode Create(long id, int state, List<DtNode> nodes)
|
||||||
{
|
{
|
||||||
if (m_nodes.Count <= m_nodeCount)
|
DtNode node = new DtNode(m_nodes.Count + 1);
|
||||||
{
|
|
||||||
var newNode = new DtNode(m_nodeCount);
|
|
||||||
m_nodes.Add(newNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = m_nodeCount;
|
|
||||||
m_nodeCount++;
|
|
||||||
var node = m_nodes[i];
|
|
||||||
node.pidx = 0;
|
|
||||||
node.cost = 0;
|
|
||||||
node.total = 0;
|
|
||||||
node.id = id;
|
node.id = id;
|
||||||
node.state = state;
|
node.state = state;
|
||||||
node.flags = 0;
|
m_nodes.Add(node);
|
||||||
node.shortcut = null;
|
|
||||||
|
|
||||||
nodes.Add(node);
|
nodes.Add(node);
|
||||||
return node;
|
return node;
|
||||||
|
@ -116,16 +96,12 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
public int GetNodeIdx(DtNode node)
|
public int GetNodeIdx(DtNode node)
|
||||||
{
|
{
|
||||||
return node != null
|
return node != null ? node.index : 0;
|
||||||
? node.ptr + 1
|
|
||||||
: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtNode GetNodeAtIdx(int idx)
|
public DtNode GetNodeAtIdx(int idx)
|
||||||
{
|
{
|
||||||
return idx != 0
|
return idx != 0 ? m_nodes[idx - 1] : null;
|
||||||
? m_nodes[idx - 1]
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtNode GetNode(long refs)
|
public DtNode GetNode(long refs)
|
||||||
|
@ -133,9 +109,9 @@ namespace DotRecast.Detour
|
||||||
return GetNode(refs, 0);
|
return GetNode(refs, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<DtNode> AsEnumerable()
|
public Dictionary<long, List<DtNode>> GetNodeMap()
|
||||||
{
|
{
|
||||||
return m_nodes.Take(m_nodeCount);
|
return m_map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,12 +24,7 @@ namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
public class DtNodeQueue
|
public class DtNodeQueue
|
||||||
{
|
{
|
||||||
private readonly RcSortedQueue<DtNode> m_heap;
|
private readonly RcSortedQueue<DtNode> m_heap = new RcSortedQueue<DtNode>((n1, n2) => n1.total.CompareTo(n2.total));
|
||||||
|
|
||||||
public DtNodeQueue()
|
|
||||||
{
|
|
||||||
m_heap = new RcSortedQueue<DtNode>(DtNode.ComparisonNodeTotal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count()
|
public int Count()
|
||||||
{
|
{
|
||||||
|
@ -48,7 +43,9 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
public DtNode Pop()
|
public DtNode Pop()
|
||||||
{
|
{
|
||||||
return m_heap.Dequeue();
|
var node = Peek();
|
||||||
|
m_heap.Remove(node);
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Push(DtNode node)
|
public void Push(DtNode node)
|
||||||
|
@ -64,7 +61,7 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
public bool IsEmpty()
|
public bool IsEmpty()
|
||||||
{
|
{
|
||||||
return m_heap.IsEmpty();
|
return 0 == m_heap.Count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,7 @@ freely, subject to the following restrictions:
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
|
@ -27,7 +28,7 @@ namespace DotRecast.Detour
|
||||||
public class DtOffMeshConnection
|
public class DtOffMeshConnection
|
||||||
{
|
{
|
||||||
/// The endpoints of the connection. [(ax, ay, az, bx, by, bz)]
|
/// The endpoints of the connection. [(ax, ay, az, bx, by, bz)]
|
||||||
public RcVec3f[] pos = new RcVec3f[2];
|
public Vector3[] pos = new Vector3[2];
|
||||||
|
|
||||||
/// The radius of the endpoints. [Limit: >= 0]
|
/// The radius of the endpoints. [Limit: >= 0]
|
||||||
public float rad;
|
public float rad;
|
||||||
|
|
|
@ -21,6 +21,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -28,12 +29,12 @@ namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
private const int MAX_STEER_POINTS = 3;
|
private const int MAX_STEER_POINTS = 3;
|
||||||
|
|
||||||
public static bool GetSteerTarget(DtNavMeshQuery navQuery, RcVec3f startPos, RcVec3f endPos,
|
public static bool GetSteerTarget(DtNavMeshQuery navQuery, Vector3 startPos, Vector3 endPos,
|
||||||
float minTargetDist,
|
float minTargetDist,
|
||||||
List<long> path,
|
List<long> path,
|
||||||
out RcVec3f steerPos, out int steerPosFlag, out long steerPosRef)
|
out Vector3 steerPos, out int steerPosFlag, out long steerPosRef)
|
||||||
{
|
{
|
||||||
steerPos = RcVec3f.Zero;
|
steerPos = Vector3.Zero;
|
||||||
steerPosFlag = 0;
|
steerPosFlag = 0;
|
||||||
steerPosRef = 0;
|
steerPosRef = 0;
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ namespace DotRecast.Detour
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool InRange(RcVec3f v1, RcVec3f v2, float r, float h)
|
public static bool InRange(Vector3 v1, Vector3 v2, float r, float h)
|
||||||
{
|
{
|
||||||
float dx = v2.X - v1.X;
|
float dx = v2.X - v1.X;
|
||||||
float dy = v2.Y - v1.Y;
|
float dy = v2.Y - v1.Y;
|
||||||
|
@ -141,7 +142,7 @@ namespace DotRecast.Detour
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<long> MergeCorridorStartMoved(List<long> path, int npath, int maxPath, List<long> visited)
|
public static List<long> MergeCorridorStartMoved(List<long> path, List<long> visited)
|
||||||
{
|
{
|
||||||
int furthestPath = -1;
|
int furthestPath = -1;
|
||||||
int furthestVisited = -1;
|
int furthestVisited = -1;
|
||||||
|
@ -186,7 +187,7 @@ namespace DotRecast.Detour
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<long> MergeCorridorEndMoved(List<long> path, int npath, int maxPath, List<long> visited)
|
public static List<long> MergeCorridorEndMoved(List<long> path, List<long> visited)
|
||||||
{
|
{
|
||||||
int furthestPath = -1;
|
int furthestPath = -1;
|
||||||
int furthestVisited = -1;
|
int furthestVisited = -1;
|
||||||
|
@ -223,7 +224,7 @@ namespace DotRecast.Detour
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<long> MergeCorridorStartShortcut(List<long> path, int npath, int maxPath, List<long> visited)
|
public static List<long> MergeCorridorStartShortcut(List<long> path, List<long> visited)
|
||||||
{
|
{
|
||||||
int furthestPath = -1;
|
int furthestPath = -1;
|
||||||
int furthestVisited = -1;
|
int furthestVisited = -1;
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
public readonly struct DtPolyPoint
|
public readonly struct DtPolyPoint
|
||||||
{
|
{
|
||||||
public readonly long refs;
|
public readonly long refs;
|
||||||
public readonly RcVec3f pt;
|
public readonly Vector3 pt;
|
||||||
|
|
||||||
public DtPolyPoint(long polyRefs, RcVec3f polyPt)
|
public DtPolyPoint(long polyRefs, Vector3 polyPt)
|
||||||
{
|
{
|
||||||
refs = polyRefs;
|
refs = polyRefs;
|
||||||
pt = polyPt;
|
pt = polyPt;
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -29,8 +30,8 @@ namespace DotRecast.Detour
|
||||||
public float lastBestNodeCost;
|
public float lastBestNodeCost;
|
||||||
public long startRef;
|
public long startRef;
|
||||||
public long endRef;
|
public long endRef;
|
||||||
public RcVec3f startPos;
|
public Vector3 startPos;
|
||||||
public RcVec3f endPos;
|
public Vector3 endPos;
|
||||||
public IDtQueryFilter filter;
|
public IDtQueryFilter filter;
|
||||||
public int options;
|
public int options;
|
||||||
public float raycastLimitSqr;
|
public float raycastLimitSqr;
|
||||||
|
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -84,10 +85,10 @@ namespace DotRecast.Detour
|
||||||
return (poly.flags & m_includeFlags) != 0 && (poly.flags & m_excludeFlags) == 0;
|
return (poly.flags & m_includeFlags) != 0 && (poly.flags & m_excludeFlags) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetCost(RcVec3f pa, RcVec3f pb, long prevRef, DtMeshTile prevTile, DtPoly prevPoly, long curRef,
|
public float GetCost(Vector3 pa, Vector3 pb, long prevRef, DtMeshTile prevTile, DtPoly prevPoly, long curRef,
|
||||||
DtMeshTile curTile, DtPoly curPoly, long nextRef, DtMeshTile nextTile, DtPoly nextPoly)
|
DtMeshTile curTile, DtPoly curPoly, long nextRef, DtMeshTile nextTile, DtPoly nextPoly)
|
||||||
{
|
{
|
||||||
return RcVec3f.Distance(pa, pb) * m_areaCost[curPoly.GetArea()];
|
return Vector3.Distance(pa, pb) * m_areaCost[curPoly.GetArea()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetIncludeFlags()
|
public int GetIncludeFlags()
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -15,7 +16,7 @@ namespace DotRecast.Detour
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetCost(RcVec3f pa, RcVec3f pb, long prevRef, DtMeshTile prevTile, DtPoly prevPoly, long curRef,
|
public float GetCost(Vector3 pa, Vector3 pb, long prevRef, DtMeshTile prevTile, DtPoly prevPoly, long curRef,
|
||||||
DtMeshTile curTile, DtPoly curPoly, long nextRef, DtMeshTile nextTile, DtPoly nextPoly)
|
DtMeshTile curTile, DtPoly curPoly, long nextRef, DtMeshTile nextTile, DtPoly nextPoly)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -15,7 +16,7 @@ namespace DotRecast.Detour
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetCost(RcVec3f pa, RcVec3f pb, long prevRef, DtMeshTile prevTile, DtPoly prevPoly, long curRef,
|
public float GetCost(Vector3 pa, Vector3 pb, long prevRef, DtMeshTile prevTile, DtPoly prevPoly, long curRef,
|
||||||
DtMeshTile curTile, DtPoly curPoly, long nextRef, DtMeshTile nextTile, DtPoly nextPoly)
|
DtMeshTile curTile, DtPoly curPoly, long nextRef, DtMeshTile nextTile, DtPoly nextPoly)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -20,27 +20,28 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
/// Provides information about raycast hit
|
/**
|
||||||
/// filled by dtNavMeshQuery::raycast
|
* Provides information about raycast hit. Filled by NavMeshQuery::raycast
|
||||||
/// @ingroup detour
|
*/
|
||||||
public struct DtRaycastHit
|
public class DtRaycastHit
|
||||||
{
|
{
|
||||||
/// The hit parameter. (FLT_MAX if no wall hit.)
|
/** The hit parameter. (float.MaxValue if no wall hit.) */
|
||||||
public float t;
|
public float t;
|
||||||
|
|
||||||
/// hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
/** hitNormal The normal of the nearest wall hit. [(x, y, z)] */
|
||||||
public RcVec3f hitNormal;
|
public Vector3 hitNormal = new Vector3();
|
||||||
|
|
||||||
/// The index of the edge on the final polygon where the wall was hit.
|
/** Visited polygons. */
|
||||||
public int hitEdgeIndex;
|
public readonly List<long> path = new List<long>();
|
||||||
|
|
||||||
/// Pointer to an array of reference ids of the visited polygons. [opt]
|
/** The cost of the path until hit. */
|
||||||
public List<long> path;
|
|
||||||
|
|
||||||
/// The cost of the path until hit.
|
|
||||||
public float pathCost;
|
public float pathCost;
|
||||||
|
|
||||||
|
/** The index of the edge on the readonly polygon where the wall was hit. */
|
||||||
|
public int hitEdgeIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,17 +19,18 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
//TODO: (PP) Add comments
|
//TODO: (PP) Add comments
|
||||||
public readonly struct DtStraightPath
|
public readonly struct DtStraightPath
|
||||||
{
|
{
|
||||||
public readonly RcVec3f pos;
|
public readonly Vector3 pos;
|
||||||
public readonly int flags;
|
public readonly int flags;
|
||||||
public readonly long refs;
|
public readonly long refs;
|
||||||
|
|
||||||
public DtStraightPath(RcVec3f pos, int flags, long refs)
|
public DtStraightPath(Vector3 pos, int flags, long refs)
|
||||||
{
|
{
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
this.flags = flags;
|
this.flags = flags;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -31,7 +32,7 @@ namespace DotRecast.Detour
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float[] Apply(float[] verts, RcVec3f center, float radius)
|
public float[] Apply(float[] verts, Vector3 center, float radius)
|
||||||
{
|
{
|
||||||
float radiusSqr = radius * radius;
|
float radiusSqr = radius * radius;
|
||||||
int outsideVertex = -1;
|
int outsideVertex = -1;
|
||||||
|
@ -62,7 +63,7 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private float[] Circle(RcVec3f center, float radius)
|
private float[] Circle(Vector3 center, float radius)
|
||||||
{
|
{
|
||||||
float[] circle = new float[12 * 3];
|
float[] circle = new float[12 * 3];
|
||||||
for (int i = 0; i < CIRCLE_SEGMENTS * 3; i += 3)
|
for (int i = 0; i < CIRCLE_SEGMENTS * 3; i += 3)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -46,14 +47,14 @@ namespace DotRecast.Detour
|
||||||
///
|
///
|
||||||
/// Basically, this function will return true if the specified points are
|
/// Basically, this function will return true if the specified points are
|
||||||
/// close enough to eachother to be considered colocated.
|
/// close enough to eachother to be considered colocated.
|
||||||
public static bool VEqual(RcVec3f p0, RcVec3f p1)
|
public static bool VEqual(Vector3 p0, Vector3 p1)
|
||||||
{
|
{
|
||||||
return VEqual(p0, p1, EQUAL_THRESHOLD);
|
return VEqual(p0, p1, EQUAL_THRESHOLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool VEqual(RcVec3f p0, RcVec3f p1, float thresholdSqr)
|
public static bool VEqual(Vector3 p0, Vector3 p1, float thresholdSqr)
|
||||||
{
|
{
|
||||||
float d = RcVec3f.DistanceSquared(p0, p1);
|
float d = Vector3.DistanceSquared(p0, p1);
|
||||||
return d < thresholdSqr;
|
return d < thresholdSqr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ namespace DotRecast.Detour
|
||||||
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||||
/// @return True if the two AABB's overlap.
|
/// @return True if the two AABB's overlap.
|
||||||
/// @see dtOverlapQuantBounds
|
/// @see dtOverlapQuantBounds
|
||||||
public static bool OverlapBounds(RcVec3f amin, RcVec3f amax, RcVec3f bmin, RcVec3f bmax)
|
public static bool OverlapBounds(Vector3 amin, Vector3 amax, Vector3 bmin, Vector3 bmax)
|
||||||
{
|
{
|
||||||
bool overlap = true;
|
bool overlap = true;
|
||||||
overlap = (amin.X > bmax.X || amax.X < bmin.X) ? false : overlap;
|
overlap = (amin.X > bmax.X || amax.X < bmin.X) ? false : overlap;
|
||||||
|
@ -105,10 +106,10 @@ namespace DotRecast.Detour
|
||||||
int va = j * 3;
|
int va = j * 3;
|
||||||
int vb = i * 3;
|
int vb = i * 3;
|
||||||
|
|
||||||
RcVec3f n = new RcVec3f(polya[vb + 2] - polya[va + 2], 0, -(polya[vb + 0] - polya[va + 0]));
|
Vector3 n = new Vector3(polya[vb + 2] - polya[va + 2], 0, -(polya[vb + 0] - polya[va + 0]));
|
||||||
|
|
||||||
RcVec2f aminmax = ProjectPoly(n, polya, npolya);
|
Vector2 aminmax = ProjectPoly(n, polya, npolya);
|
||||||
RcVec2f bminmax = ProjectPoly(n, polyb, npolyb);
|
Vector2 bminmax = ProjectPoly(n, polyb, npolyb);
|
||||||
if (!OverlapRange(aminmax.X, aminmax.Y, bminmax.X, bminmax.Y, eps))
|
if (!OverlapRange(aminmax.X, aminmax.Y, bminmax.X, bminmax.Y, eps))
|
||||||
{
|
{
|
||||||
// Found separating axis
|
// Found separating axis
|
||||||
|
@ -121,10 +122,10 @@ namespace DotRecast.Detour
|
||||||
int va = j * 3;
|
int va = j * 3;
|
||||||
int vb = i * 3;
|
int vb = i * 3;
|
||||||
|
|
||||||
RcVec3f n = new RcVec3f(polyb[vb + 2] - polyb[va + 2], 0, -(polyb[vb + 0] - polyb[va + 0]));
|
Vector3 n = new Vector3(polyb[vb + 2] - polyb[va + 2], 0, -(polyb[vb + 0] - polyb[va + 0]));
|
||||||
|
|
||||||
RcVec2f aminmax = ProjectPoly(n, polya, npolya);
|
Vector2 aminmax = ProjectPoly(n, polya, npolya);
|
||||||
RcVec2f bminmax = ProjectPoly(n, polyb, npolyb);
|
Vector2 bminmax = ProjectPoly(n, polyb, npolyb);
|
||||||
if (!OverlapRange(aminmax.X, aminmax.Y, bminmax.X, bminmax.Y, eps))
|
if (!OverlapRange(aminmax.X, aminmax.Y, bminmax.X, bminmax.Y, eps))
|
||||||
{
|
{
|
||||||
// Found separating axis
|
// Found separating axis
|
||||||
|
@ -154,7 +155,7 @@ namespace DotRecast.Detour
|
||||||
return acx * abz - abx * acz;
|
return acx * abz - abx * acz;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float TriArea2D(RcVec3f a, RcVec3f b, RcVec3f c)
|
public static float TriArea2D(Vector3 a, Vector3 b, Vector3 c)
|
||||||
{
|
{
|
||||||
float abx = b.X - a.X;
|
float abx = b.X - a.X;
|
||||||
float abz = b.Z - a.Z;
|
float abz = b.Z - a.Z;
|
||||||
|
@ -165,7 +166,7 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
// Returns a random point in a convex polygon.
|
// Returns a random point in a convex polygon.
|
||||||
// Adapted from Graphics Gems article.
|
// Adapted from Graphics Gems article.
|
||||||
public static RcVec3f RandomPointInConvexPoly(float[] pts, int npts, float[] areas, float s, float t)
|
public static Vector3 RandomPointInConvexPoly(float[] pts, int npts, float[] areas, float s, float t)
|
||||||
{
|
{
|
||||||
// Calc triangle araes
|
// Calc triangle araes
|
||||||
float areasum = 0.0f;
|
float areasum = 0.0f;
|
||||||
|
@ -202,7 +203,7 @@ namespace DotRecast.Detour
|
||||||
int pb = (tri - 1) * 3;
|
int pb = (tri - 1) * 3;
|
||||||
int pc = tri * 3;
|
int pc = tri * 3;
|
||||||
|
|
||||||
return new RcVec3f()
|
return new Vector3()
|
||||||
{
|
{
|
||||||
X = a * pts[pa] + b * pts[pb] + c * pts[pc],
|
X = a * pts[pa] + b * pts[pb] + c * pts[pc],
|
||||||
Y = a * pts[pa + 1] + b * pts[pb + 1] + c * pts[pc + 1],
|
Y = a * pts[pa + 1] + b * pts[pb + 1] + c * pts[pc + 1],
|
||||||
|
@ -210,14 +211,14 @@ namespace DotRecast.Detour
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool ClosestHeightPointTriangle(RcVec3f p, RcVec3f a, RcVec3f b, RcVec3f c, out float h)
|
public static bool ClosestHeightPointTriangle(Vector3 p, Vector3 a, Vector3 b, Vector3 c, out float h)
|
||||||
{
|
{
|
||||||
const float EPS = 1e-6f;
|
const float EPS = 1e-6f;
|
||||||
|
|
||||||
h = 0;
|
h = 0;
|
||||||
RcVec3f v0 = RcVec3f.Subtract(c, a);
|
Vector3 v0 = Vector3.Subtract(c, a);
|
||||||
RcVec3f v1 = RcVec3f.Subtract(b, a);
|
Vector3 v1 = Vector3.Subtract(b, a);
|
||||||
RcVec3f v2 = RcVec3f.Subtract(p, a);
|
Vector3 v2 = Vector3.Subtract(p, a);
|
||||||
|
|
||||||
// Compute scaled barycentric coordinates
|
// Compute scaled barycentric coordinates
|
||||||
float denom = v0.X * v1.Z - v0.Z * v1.X;
|
float denom = v0.X * v1.Z - v0.Z * v1.X;
|
||||||
|
@ -246,7 +247,7 @@ namespace DotRecast.Detour
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RcVec2f ProjectPoly(RcVec3f axis, float[] poly, int npoly)
|
public static Vector2 ProjectPoly(Vector3 axis, float[] poly, int npoly)
|
||||||
{
|
{
|
||||||
float rmin, rmax;
|
float rmin, rmax;
|
||||||
rmin = rmax = axis.Dot2D(poly, 0);
|
rmin = rmax = axis.Dot2D(poly, 0);
|
||||||
|
@ -257,7 +258,7 @@ namespace DotRecast.Detour
|
||||||
rmax = Math.Max(rmax, d);
|
rmax = Math.Max(rmax, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RcVec2f
|
return new Vector2
|
||||||
{
|
{
|
||||||
X = rmin,
|
X = rmin,
|
||||||
Y = rmax,
|
Y = rmax,
|
||||||
|
@ -267,7 +268,7 @@ namespace DotRecast.Detour
|
||||||
/// @par
|
/// @par
|
||||||
///
|
///
|
||||||
/// All points are projected onto the xz-plane, so the y-values are ignored.
|
/// 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(Vector3 pt, float[] verts, int nverts)
|
||||||
{
|
{
|
||||||
// TODO: Replace pnpoly with triArea2D tests?
|
// TODO: Replace pnpoly with triArea2D tests?
|
||||||
int i, j;
|
int i, j;
|
||||||
|
@ -286,7 +287,7 @@ namespace DotRecast.Detour
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool DistancePtPolyEdgesSqr(RcVec3f pt, float[] verts, int nverts, float[] ed, float[] et)
|
public static bool DistancePtPolyEdgesSqr(Vector3 pt, float[] verts, int nverts, float[] ed, float[] et)
|
||||||
{
|
{
|
||||||
// TODO: Replace pnpoly with triArea2D tests?
|
// TODO: Replace pnpoly with triArea2D tests?
|
||||||
int i, j;
|
int i, j;
|
||||||
|
@ -307,14 +308,14 @@ namespace DotRecast.Detour
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float DistancePtSegSqr2D(RcVec3f pt, float[] verts, int p, int q, out float t)
|
public static float DistancePtSegSqr2D(Vector3 pt, float[] verts, int p, int q, out float t)
|
||||||
{
|
{
|
||||||
var vp = RcVecUtils.Create(verts, p);
|
var vp = RcVecUtils.Create(verts, p);
|
||||||
var vq = RcVecUtils.Create(verts, q);
|
var vq = RcVecUtils.Create(verts, q);
|
||||||
return DistancePtSegSqr2D(pt, vp, vq, out t);
|
return DistancePtSegSqr2D(pt, vp, vq, out t);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float DistancePtSegSqr2D(RcVec3f pt, RcVec3f p, RcVec3f q, out float t)
|
public static float DistancePtSegSqr2D(Vector3 pt, Vector3 p, Vector3 q, out float t)
|
||||||
{
|
{
|
||||||
float pqx = q.X - p.X;
|
float pqx = q.X - p.X;
|
||||||
float pqz = q.Z - p.Z;
|
float pqz = q.Z - p.Z;
|
||||||
|
@ -341,8 +342,8 @@ namespace DotRecast.Detour
|
||||||
return dx * dx + dz * dz;
|
return dx * dx + dz * dz;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IntersectSegmentPoly2D(RcVec3f p0, RcVec3f p1,
|
public static bool IntersectSegmentPoly2D(Vector3 p0, Vector3 p1,
|
||||||
RcVec3f[] verts, int nverts,
|
Vector3[] verts, int nverts,
|
||||||
out float tmin, out float tmax,
|
out float tmin, out float tmax,
|
||||||
out int segMin, out int segMax)
|
out int segMin, out int segMax)
|
||||||
{
|
{
|
||||||
|
@ -353,15 +354,15 @@ namespace DotRecast.Detour
|
||||||
segMin = -1;
|
segMin = -1;
|
||||||
segMax = -1;
|
segMax = -1;
|
||||||
|
|
||||||
var dir = RcVec3f.Subtract(p1, p0);
|
var dir = Vector3.Subtract(p1, p0);
|
||||||
|
|
||||||
var p0v = p0;
|
var p0v = p0;
|
||||||
for (int i = 0, j = nverts - 1; i < nverts; j = i++)
|
for (int i = 0, j = nverts - 1; i < nverts; j = i++)
|
||||||
{
|
{
|
||||||
RcVec3f vpj = verts[j];
|
Vector3 vpj = verts[j];
|
||||||
RcVec3f vpi = verts[i];
|
Vector3 vpi = verts[i];
|
||||||
var edge = RcVec3f.Subtract(vpi, vpj);
|
var edge = Vector3.Subtract(vpi, vpj);
|
||||||
var diff = RcVec3f.Subtract(p0v, vpj);
|
var diff = Vector3.Subtract(p0v, vpj);
|
||||||
float n = RcVecUtils.Perp2D(edge, diff);
|
float n = RcVecUtils.Perp2D(edge, diff);
|
||||||
float d = RcVecUtils.Perp2D(dir, edge);
|
float d = RcVecUtils.Perp2D(dir, edge);
|
||||||
if (MathF.Abs(d) < EPS)
|
if (MathF.Abs(d) < EPS)
|
||||||
|
@ -417,14 +418,14 @@ namespace DotRecast.Detour
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static bool IntersectSegSeg2D(RcVec3f ap, RcVec3f aq, RcVec3f bp, RcVec3f bq, out float s, out float t)
|
public static bool IntersectSegSeg2D(Vector3 ap, Vector3 aq, Vector3 bp, Vector3 bq, out float s, out float t)
|
||||||
{
|
{
|
||||||
s = 0;
|
s = 0;
|
||||||
t = 0;
|
t = 0;
|
||||||
|
|
||||||
RcVec3f u = RcVec3f.Subtract(aq, ap);
|
Vector3 u = Vector3.Subtract(aq, ap);
|
||||||
RcVec3f v = RcVec3f.Subtract(bq, bp);
|
Vector3 v = Vector3.Subtract(bq, bp);
|
||||||
RcVec3f w = RcVec3f.Subtract(ap, bp);
|
Vector3 w = Vector3.Subtract(ap, bp);
|
||||||
float d = RcVecUtils.PerpXZ(u, v);
|
float d = RcVecUtils.PerpXZ(u, v);
|
||||||
if (MathF.Abs(d) < 1e-6f)
|
if (MathF.Abs(d) < 1e-6f)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,11 +19,12 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
public interface IDtPolygonByCircleConstraint
|
public interface IDtPolygonByCircleConstraint
|
||||||
{
|
{
|
||||||
float[] Apply(float[] polyVerts, RcVec3f circleCenter, float radius);
|
float[] Apply(float[] polyVerts, Vector3 circleCenter, float radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
|
@ -26,7 +27,7 @@ namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
bool PassFilter(long refs, DtMeshTile tile, DtPoly poly);
|
bool PassFilter(long refs, DtMeshTile tile, DtPoly poly);
|
||||||
|
|
||||||
float GetCost(RcVec3f pa, RcVec3f pb, long prevRef, DtMeshTile prevTile, DtPoly prevPoly, long curRef, DtMeshTile curTile,
|
float GetCost(Vector3 pa, Vector3 pb, long prevRef, DtMeshTile prevTile, DtPoly prevPoly, long curRef, DtMeshTile curTile,
|
||||||
DtPoly curPoly, long nextRef, DtMeshTile nextTile, DtPoly nextPoly);
|
DtPoly curPoly, long nextRef, DtMeshTile nextTile, DtPoly nextPoly);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,11 +18,12 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour
|
namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
public interface IDtQueryHeuristic
|
public interface IDtQueryHeuristic
|
||||||
{
|
{
|
||||||
float GetCost(RcVec3f neighbourPos, RcVec3f endPos);
|
float GetCost(Vector3 neighbourPos, Vector3 endPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Io
|
namespace DotRecast.Detour.Io
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Io
|
namespace DotRecast.Detour.Io
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,12 +7,11 @@
|
||||||
<PackageId>DotRecast.Recast.Demo</PackageId>
|
<PackageId>DotRecast.Recast.Demo</PackageId>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Authors>ikpil</Authors>
|
<Authors>ikpil</Authors>
|
||||||
<Description>DotRecast - a port of Recast Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers</Description>
|
<Description>DotRecast - a port of Recast Detour, navigation mesh toolset for games, Unity3D, servers, C#</Description>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
||||||
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
||||||
<PackageReleaseNotes>https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md</PackageReleaseNotes>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -21,6 +21,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using Silk.NET.OpenGL;
|
using Silk.NET.OpenGL;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Demo.Draw;
|
namespace DotRecast.Recast.Demo.Draw;
|
||||||
|
@ -92,7 +93,7 @@ public class DebugDraw
|
||||||
GetOpenGlDraw().Vertex(pos, color);
|
GetOpenGlDraw().Vertex(pos, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Vertex(RcVec3f pos, int color)
|
public void Vertex(Vector3 pos, int color)
|
||||||
{
|
{
|
||||||
GetOpenGlDraw().Vertex(pos, color);
|
GetOpenGlDraw().Vertex(pos, color);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +103,7 @@ public class DebugDraw
|
||||||
GetOpenGlDraw().Vertex(x, y, z, color);
|
GetOpenGlDraw().Vertex(x, y, z, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Vertex(RcVec3f pos, int color, RcVec2f uv)
|
public void Vertex(Vector3 pos, int color, Vector2 uv)
|
||||||
{
|
{
|
||||||
GetOpenGlDraw().Vertex(pos, color, uv);
|
GetOpenGlDraw().Vertex(pos, color, uv);
|
||||||
}
|
}
|
||||||
|
@ -336,12 +337,12 @@ public class DebugDraw
|
||||||
float dy = y1 - y0;
|
float dy = y1 - y0;
|
||||||
float dz = z1 - z0;
|
float dz = z1 - z0;
|
||||||
float len = MathF.Sqrt(dx * dx + dy * dy + dz * dz);
|
float len = MathF.Sqrt(dx * dx + dy * dy + dz * dz);
|
||||||
RcVec3f prev = new RcVec3f();
|
Vector3 prev = new Vector3();
|
||||||
EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD, ref prev);
|
EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD, ref prev);
|
||||||
for (int i = 1; i <= NUM_ARC_PTS; ++i)
|
for (int i = 1; i <= NUM_ARC_PTS; ++i)
|
||||||
{
|
{
|
||||||
float u = PAD + i * ARC_PTS_SCALE;
|
float u = PAD + i * ARC_PTS_SCALE;
|
||||||
RcVec3f pt = new RcVec3f();
|
Vector3 pt = new Vector3();
|
||||||
EvalArc(x0, y0, z0, dx, dy, dz, len * h, u, ref pt);
|
EvalArc(x0, y0, z0, dx, dy, dz, len * h, u, ref pt);
|
||||||
Vertex(prev.X, prev.Y, prev.Z, col);
|
Vertex(prev.X, prev.Y, prev.Z, col);
|
||||||
Vertex(pt.X, pt.Y, pt.Z, col);
|
Vertex(pt.X, pt.Y, pt.Z, col);
|
||||||
|
@ -353,8 +354,8 @@ public class DebugDraw
|
||||||
// End arrows
|
// End arrows
|
||||||
if (as0 > 0.001f)
|
if (as0 > 0.001f)
|
||||||
{
|
{
|
||||||
RcVec3f p = new RcVec3f();
|
Vector3 p = new Vector3();
|
||||||
RcVec3f q = new RcVec3f();
|
Vector3 q = new Vector3();
|
||||||
EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD, ref p);
|
EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD, ref p);
|
||||||
EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD + 0.05f, ref q);
|
EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD + 0.05f, ref q);
|
||||||
AppendArrowHead(p, q, as0, col);
|
AppendArrowHead(p, q, as0, col);
|
||||||
|
@ -362,15 +363,15 @@ public class DebugDraw
|
||||||
|
|
||||||
if (as1 > 0.001f)
|
if (as1 > 0.001f)
|
||||||
{
|
{
|
||||||
RcVec3f p = new RcVec3f();
|
Vector3 p = new Vector3();
|
||||||
RcVec3f q = new RcVec3f();
|
Vector3 q = new Vector3();
|
||||||
EvalArc(x0, y0, z0, dx, dy, dz, len * h, 1 - PAD, ref p);
|
EvalArc(x0, y0, z0, dx, dy, dz, len * h, 1 - PAD, ref p);
|
||||||
EvalArc(x0, y0, z0, dx, dy, dz, len * h, 1 - (PAD + 0.05f), ref q);
|
EvalArc(x0, y0, z0, dx, dy, dz, len * h, 1 - (PAD + 0.05f), ref q);
|
||||||
AppendArrowHead(p, q, as1, col);
|
AppendArrowHead(p, q, as1, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EvalArc(float x0, float y0, float z0, float dx, float dy, float dz, float h, float u, ref RcVec3f res)
|
private void EvalArc(float x0, float y0, float z0, float dx, float dy, float dz, float h, float u, ref Vector3 res)
|
||||||
{
|
{
|
||||||
res.X = x0 + dx * u;
|
res.X = x0 + dx * u;
|
||||||
res.Y = y0 + dy * u + h * (1 - (u * 2 - 1) * (u * 2 - 1));
|
res.Y = y0 + dy * u + h * (1 - (u * 2 - 1) * (u * 2 - 1));
|
||||||
|
@ -461,15 +462,15 @@ public class DebugDraw
|
||||||
Vertex(x1, y1, z1, col);
|
Vertex(x1, y1, z1, col);
|
||||||
|
|
||||||
// End arrows
|
// End arrows
|
||||||
RcVec3f p = new RcVec3f(x0, y0, z0);
|
Vector3 p = new Vector3(x0, y0, z0);
|
||||||
RcVec3f q = new RcVec3f(x1, y1, z1);
|
Vector3 q = new Vector3(x1, y1, z1);
|
||||||
if (as0 > 0.001f)
|
if (as0 > 0.001f)
|
||||||
AppendArrowHead(p, q, as0, col);
|
AppendArrowHead(p, q, as0, col);
|
||||||
if (as1 > 0.001f)
|
if (as1 > 0.001f)
|
||||||
AppendArrowHead(q, p, as1, col);
|
AppendArrowHead(q, p, as1, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppendArrowHead(RcVec3f p, RcVec3f q, float s, int col)
|
void AppendArrowHead(Vector3 p, Vector3 q, float s, int col)
|
||||||
{
|
{
|
||||||
const float eps = 0.001f;
|
const float eps = 0.001f;
|
||||||
if (VdistSqr(p, q) < eps * eps)
|
if (VdistSqr(p, q) < eps * eps)
|
||||||
|
@ -477,9 +478,9 @@ public class DebugDraw
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f ax = new RcVec3f();
|
Vector3 ax = new Vector3();
|
||||||
RcVec3f ay = new RcVec3f(0, 1, 0);
|
Vector3 ay = new Vector3(0, 1, 0);
|
||||||
RcVec3f az = new RcVec3f();
|
Vector3 az = new Vector3();
|
||||||
Vsub(ref az, q, p);
|
Vsub(ref az, q, p);
|
||||||
Vnormalize(ref az);
|
Vnormalize(ref az);
|
||||||
Vcross(ref ax, ay, az);
|
Vcross(ref ax, ay, az);
|
||||||
|
@ -495,14 +496,14 @@ public class DebugDraw
|
||||||
Vertex(p.X + az.X * s - ax.X * s / 3, p.Y + az.Y * s - ax.Y * s / 3, p.Z + az.Z * s - ax.Z * s / 3, col);
|
Vertex(p.X + az.X * s - ax.X * s / 3, p.Y + az.Y * s - ax.Y * s / 3, p.Z + az.Z * s - ax.Z * s / 3, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Vcross(ref RcVec3f dest, RcVec3f v1, RcVec3f v2)
|
public void Vcross(ref Vector3 dest, Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
dest.X = v1.Y * v2.Z - v1.Z * v2.Y;
|
dest.X = v1.Y * v2.Z - v1.Z * v2.Y;
|
||||||
dest.Y = v1.Z * v2.X - v1.X * v2.Z;
|
dest.Y = v1.Z * v2.X - v1.X * v2.Z;
|
||||||
dest.Z = v1.X * v2.Y - v1.Y * v2.X;
|
dest.Z = v1.X * v2.Y - v1.Y * v2.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Vnormalize(ref RcVec3f v)
|
public void Vnormalize(ref Vector3 v)
|
||||||
{
|
{
|
||||||
float d = (float)(1.0f / Math.Sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z));
|
float d = (float)(1.0f / Math.Sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z));
|
||||||
v.X *= d;
|
v.X *= d;
|
||||||
|
@ -510,14 +511,14 @@ public class DebugDraw
|
||||||
v.Z *= d;
|
v.Z *= d;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Vsub(ref RcVec3f dest, RcVec3f v1, RcVec3f v2)
|
public void Vsub(ref Vector3 dest, Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
dest.X = v1.X - v2.X;
|
dest.X = v1.X - v2.X;
|
||||||
dest.Y = v1.Y - v2.Y;
|
dest.Y = v1.Y - v2.Y;
|
||||||
dest.Z = v1.Z - v2.Z;
|
dest.Z = v1.Z - v2.Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float VdistSqr(RcVec3f v1, RcVec3f v2)
|
public float VdistSqr(Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
float x = v1.X - v2.X;
|
float x = v1.X - v2.X;
|
||||||
float y = v1.Y - v2.Y;
|
float y = v1.Y - v2.Y;
|
||||||
|
@ -637,7 +638,7 @@ public class DebugDraw
|
||||||
return _projectionMatrix;
|
return _projectionMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcMatrix4x4f ViewMatrix(RcVec3f cameraPos, RcVec2f cameraEulers)
|
public RcMatrix4x4f ViewMatrix(Vector3 cameraPos, Vector2 cameraEulers)
|
||||||
{
|
{
|
||||||
var rx = RcMatrix4x4f.CreateFromRotate(cameraEulers.X, 1, 0, 0);
|
var rx = RcMatrix4x4f.CreateFromRotate(cameraEulers.X, 1, 0, 0);
|
||||||
var ry = RcMatrix4x4f.CreateFromRotate(cameraEulers.Y, 0, 1, 0);
|
var ry = RcMatrix4x4f.CreateFromRotate(cameraEulers.Y, 0, 1, 0);
|
||||||
|
@ -746,7 +747,7 @@ public class DebugDraw
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool FrustumTest(RcVec3f bmin, RcVec3f bmax)
|
public bool FrustumTest(Vector3 bmin, Vector3 bmax)
|
||||||
{
|
{
|
||||||
return FrustumTest(new float[] { bmin.X, bmin.Y, bmin.Z, bmax.X, bmax.Y, bmax.Z });
|
return FrustumTest(new float[] { bmin.X, bmin.Y, bmin.Z, bmax.X, bmax.Y, bmax.Z });
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Demo.Draw;
|
namespace DotRecast.Recast.Demo.Draw;
|
||||||
|
|
||||||
|
@ -65,7 +66,7 @@ public static class GLU
|
||||||
matrix.M44 = 0.0f;
|
matrix.M44 = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GlhUnProjectf(float winx, float winy, float winz, float[] modelview, float[] projection, int[] viewport, ref RcVec3f objectCoordinate)
|
public static int GlhUnProjectf(float winx, float winy, float winz, float[] modelview, float[] projection, int[] viewport, ref Vector3 objectCoordinate)
|
||||||
{
|
{
|
||||||
// Transformation matrices
|
// Transformation matrices
|
||||||
float[] m = new float[16], A = new float[16];
|
float[] m = new float[16], A = new float[16];
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Demo.Draw;
|
namespace DotRecast.Recast.Demo.Draw;
|
||||||
|
|
||||||
|
@ -15,9 +16,9 @@ public interface IOpenGLDraw
|
||||||
void Vertex(float x, float y, float z, int color);
|
void Vertex(float x, float y, float z, int color);
|
||||||
|
|
||||||
void Vertex(float[] pos, int color);
|
void Vertex(float[] pos, int color);
|
||||||
void Vertex(RcVec3f pos, int color);
|
void Vertex(Vector3 pos, int color);
|
||||||
|
|
||||||
void Vertex(RcVec3f pos, int color, RcVec2f uv);
|
void Vertex(Vector3 pos, int color, Vector2 uv);
|
||||||
|
|
||||||
void Vertex(float x, float y, float z, int color, float u, float v);
|
void Vertex(float x, float y, float z, int color, float u, float v);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Silk.NET.OpenGL;
|
using Silk.NET.OpenGL;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Demo.Draw;
|
namespace DotRecast.Recast.Demo.Draw;
|
||||||
|
|
||||||
|
@ -285,13 +286,13 @@ public class ModernOpenGLDraw : IOpenGLDraw
|
||||||
vertices.Add(new OpenGLVertex(pos, color));
|
vertices.Add(new OpenGLVertex(pos, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Vertex(RcVec3f pos, int color)
|
public void Vertex(Vector3 pos, int color)
|
||||||
{
|
{
|
||||||
vertices.Add(new OpenGLVertex(pos, color));
|
vertices.Add(new OpenGLVertex(pos, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Vertex(RcVec3f pos, int color, RcVec2f uv)
|
public void Vertex(Vector3 pos, int color, Vector2 uv)
|
||||||
{
|
{
|
||||||
vertices.Add(new OpenGLVertex(pos, uv, color));
|
vertices.Add(new OpenGLVertex(pos, uv, color));
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
using DotRecast.Recast.Toolset.Geom;
|
using DotRecast.Recast.Toolset.Geom;
|
||||||
|
@ -80,8 +81,8 @@ public class NavMeshRenderer
|
||||||
if (geom != null)
|
if (geom != null)
|
||||||
{
|
{
|
||||||
int gw = 0, gh = 0;
|
int gw = 0, gh = 0;
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
Vector3 bmin = geom.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
Vector3 bmax = geom.GetMeshBoundsMax();
|
||||||
CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh);
|
CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh);
|
||||||
int tw = (gw + settings.tileSize - 1) / settings.tileSize;
|
int tw = (gw + settings.tileSize - 1) / settings.tileSize;
|
||||||
int th = (gh + settings.tileSize - 1) / settings.tileSize;
|
int th = (gh + settings.tileSize - 1) / settings.tileSize;
|
||||||
|
@ -210,8 +211,8 @@ public class NavMeshRenderer
|
||||||
private void DrawGeomBounds(DemoInputGeomProvider geom)
|
private void DrawGeomBounds(DemoInputGeomProvider geom)
|
||||||
{
|
{
|
||||||
// Draw bounds
|
// Draw bounds
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
Vector3 bmin = geom.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
Vector3 bmax = geom.GetMeshBoundsMax();
|
||||||
_debugDraw.DebugDrawBoxWire(bmin.X, bmin.Y, bmin.Z, bmax.X, bmax.Y, bmax.Z,
|
_debugDraw.DebugDrawBoxWire(bmin.X, bmin.Y, bmin.Z, bmax.X, bmax.Y, bmax.Z,
|
||||||
DebugDraw.DuRGBA(255, 255, 255, 128), 1.0f);
|
DebugDraw.DuRGBA(255, 255, 255, 128), 1.0f);
|
||||||
_debugDraw.Begin(DebugDrawPrimitives.POINTS, 5.0f);
|
_debugDraw.Begin(DebugDrawPrimitives.POINTS, 5.0f);
|
||||||
|
@ -260,8 +261,8 @@ public class NavMeshRenderer
|
||||||
int col = DebugDraw.DuTransCol(DebugDraw.AreaToCol(vol.areaMod.GetMaskedValue()), 32);
|
int col = DebugDraw.DuTransCol(DebugDraw.AreaToCol(vol.areaMod.GetMaskedValue()), 32);
|
||||||
for (int j = 0, k = vol.verts.Length - 3; j < vol.verts.Length; k = j, j += 3)
|
for (int j = 0, k = vol.verts.Length - 3; j < vol.verts.Length; k = j, j += 3)
|
||||||
{
|
{
|
||||||
var va = new RcVec3f(vol.verts[k], vol.verts[k + 1], vol.verts[k + 2]);
|
var va = new Vector3(vol.verts[k], vol.verts[k + 1], vol.verts[k + 2]);
|
||||||
var vb = new RcVec3f(vol.verts[j], vol.verts[j + 1], vol.verts[j + 2]);
|
var vb = new Vector3(vol.verts[j], vol.verts[j + 1], vol.verts[j + 2]);
|
||||||
|
|
||||||
_debugDraw.Vertex(vol.verts[0], vol.hmax, vol.verts[2], col);
|
_debugDraw.Vertex(vol.verts[0], vol.hmax, vol.verts[2], col);
|
||||||
_debugDraw.Vertex(vb.X, vol.hmax, vb.Z, col);
|
_debugDraw.Vertex(vb.X, vol.hmax, vb.Z, col);
|
||||||
|
@ -285,8 +286,8 @@ public class NavMeshRenderer
|
||||||
int col = DebugDraw.DuTransCol(DebugDraw.AreaToCol(vol.areaMod.GetMaskedValue()), 220);
|
int col = DebugDraw.DuTransCol(DebugDraw.AreaToCol(vol.areaMod.GetMaskedValue()), 220);
|
||||||
for (int j = 0, k = vol.verts.Length - 3; j < vol.verts.Length; k = j, j += 3)
|
for (int j = 0, k = vol.verts.Length - 3; j < vol.verts.Length; k = j, j += 3)
|
||||||
{
|
{
|
||||||
var va = new RcVec3f(vol.verts[k], vol.verts[k + 1], vol.verts[k + 2]);
|
var va = new Vector3(vol.verts[k], vol.verts[k + 1], vol.verts[k + 2]);
|
||||||
var vb = new RcVec3f(vol.verts[j], vol.verts[j + 1], vol.verts[j + 2]);
|
var vb = new Vector3(vol.verts[j], vol.verts[j + 1], vol.verts[j + 2]);
|
||||||
_debugDraw.Vertex(va.X, vol.hmin, va.Z, DebugDraw.DuDarkenCol(col));
|
_debugDraw.Vertex(va.X, vol.hmin, va.Z, DebugDraw.DuDarkenCol(col));
|
||||||
_debugDraw.Vertex(vb.X, vol.hmin, vb.Z, DebugDraw.DuDarkenCol(col));
|
_debugDraw.Vertex(vb.X, vol.hmin, vb.Z, DebugDraw.DuDarkenCol(col));
|
||||||
_debugDraw.Vertex(va.X, vol.hmax, va.Z, col);
|
_debugDraw.Vertex(va.X, vol.hmax, va.Z, col);
|
||||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Demo.Draw;
|
namespace DotRecast.Recast.Demo.Draw;
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ public struct OpenGLVertex
|
||||||
[FieldOffset(20)]
|
[FieldOffset(20)]
|
||||||
private readonly int color;
|
private readonly int color;
|
||||||
|
|
||||||
public OpenGLVertex(RcVec3f pos, RcVec2f uv, int color) :
|
public OpenGLVertex(Vector3 pos, Vector2 uv, int color) :
|
||||||
this(pos.X, pos.Y, pos.Z, uv.X, uv.Y, color)
|
this(pos.X, pos.Y, pos.Z, uv.X, uv.Y, color)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -36,7 +37,7 @@ public struct OpenGLVertex
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpenGLVertex(RcVec3f pos, int color) :
|
public OpenGLVertex(Vector3 pos, int color) :
|
||||||
this(pos.X, pos.Y, pos.Z, 0f, 0f, color)
|
this(pos.X, pos.Y, pos.Z, 0f, 0f, color)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
using Silk.NET.OpenGL;
|
using Silk.NET.OpenGL;
|
||||||
|
@ -41,9 +42,9 @@ public class RecastDebugDraw : DebugDraw
|
||||||
{
|
{
|
||||||
float walkableThr = MathF.Cos(walkableSlopeAngle / 180.0f * MathF.PI);
|
float walkableThr = MathF.Cos(walkableSlopeAngle / 180.0f * MathF.PI);
|
||||||
|
|
||||||
RcVec2f uva = RcVec2f.Zero;
|
Vector2 uva = Vector2.Zero;
|
||||||
RcVec2f uvb = RcVec2f.Zero;
|
Vector2 uvb = Vector2.Zero;
|
||||||
RcVec2f uvc = RcVec2f.Zero;
|
Vector2 uvc = Vector2.Zero;
|
||||||
|
|
||||||
Texture(true);
|
Texture(true);
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ public class RecastDebugDraw : DebugDraw
|
||||||
Begin(DebugDrawPrimitives.TRIS);
|
Begin(DebugDrawPrimitives.TRIS);
|
||||||
for (int i = 0; i < tris.Length; i += 3)
|
for (int i = 0; i < tris.Length; i += 3)
|
||||||
{
|
{
|
||||||
RcVec3f norm = new RcVec3f(normals[i], normals[i + 1], normals[i + 2]);
|
Vector3 norm = new Vector3(normals[i], normals[i + 1], normals[i + 2]);
|
||||||
|
|
||||||
int color;
|
int color;
|
||||||
char a = (char)(220 * (2 + norm.X + norm.Y) / 4);
|
char a = (char)(220 * (2 + norm.X + norm.Y) / 4);
|
||||||
|
@ -64,9 +65,9 @@ public class RecastDebugDraw : DebugDraw
|
||||||
color = DuRGBA(a, a, a, 255);
|
color = DuRGBA(a, a, a, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f va = new RcVec3f(verts[tris[i] * 3], verts[tris[i] * 3 + 1], verts[tris[i] * 3 + 2]);
|
Vector3 va = new Vector3(verts[tris[i] * 3], verts[tris[i] * 3 + 1], verts[tris[i] * 3 + 2]);
|
||||||
RcVec3f vb = new RcVec3f(verts[tris[i + 1] * 3], verts[tris[i + 1] * 3 + 1], verts[tris[i + 1] * 3 + 2]);
|
Vector3 vb = new Vector3(verts[tris[i + 1] * 3], verts[tris[i + 1] * 3 + 1], verts[tris[i + 1] * 3 + 2]);
|
||||||
RcVec3f vc = new RcVec3f(verts[tris[i + 2] * 3], verts[tris[i + 2] * 3 + 1], verts[tris[i + 2] * 3 + 2]);
|
Vector3 vc = new Vector3(verts[tris[i + 2] * 3], verts[tris[i + 2] * 3 + 1], verts[tris[i + 2] * 3 + 2]);
|
||||||
|
|
||||||
int ax = 0, ay = 0;
|
int ax = 0, ay = 0;
|
||||||
if (MathF.Abs(norm.Y) > MathF.Abs(norm.Get(ax)))
|
if (MathF.Abs(norm.Y) > MathF.Abs(norm.Get(ax)))
|
||||||
|
@ -186,11 +187,11 @@ public class RecastDebugDraw : DebugDraw
|
||||||
}
|
}
|
||||||
|
|
||||||
DtOffMeshConnection con = tile.data.offMeshCons[i - tile.data.header.offMeshBase];
|
DtOffMeshConnection con = tile.data.offMeshCons[i - tile.data.header.offMeshBase];
|
||||||
RcVec3f va = new RcVec3f(
|
Vector3 va = new Vector3(
|
||||||
tile.data.verts[p.verts[0] * 3], tile.data.verts[p.verts[0] * 3 + 1],
|
tile.data.verts[p.verts[0] * 3], tile.data.verts[p.verts[0] * 3 + 1],
|
||||||
tile.data.verts[p.verts[0] * 3 + 2]
|
tile.data.verts[p.verts[0] * 3 + 2]
|
||||||
);
|
);
|
||||||
RcVec3f vb = new RcVec3f(
|
Vector3 vb = new Vector3(
|
||||||
tile.data.verts[p.verts[1] * 3], tile.data.verts[p.verts[1] * 3 + 1],
|
tile.data.verts[p.verts[1] * 3], tile.data.verts[p.verts[1] * 3 + 1],
|
||||||
tile.data.verts[p.verts[1] * 3 + 2]
|
tile.data.verts[p.verts[1] * 3 + 2]
|
||||||
);
|
);
|
||||||
|
@ -352,11 +353,11 @@ public class RecastDebugDraw : DebugDraw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var v0 = new RcVec3f(
|
var v0 = new Vector3(
|
||||||
tile.data.verts[p.verts[j] * 3], tile.data.verts[p.verts[j] * 3 + 1],
|
tile.data.verts[p.verts[j] * 3], tile.data.verts[p.verts[j] * 3 + 1],
|
||||||
tile.data.verts[p.verts[j] * 3 + 2]
|
tile.data.verts[p.verts[j] * 3 + 2]
|
||||||
);
|
);
|
||||||
var v1 = new RcVec3f(
|
var v1 = new Vector3(
|
||||||
tile.data.verts[p.verts[(j + 1) % nj] * 3],
|
tile.data.verts[p.verts[(j + 1) % nj] * 3],
|
||||||
tile.data.verts[p.verts[(j + 1) % nj] * 3 + 1],
|
tile.data.verts[p.verts[(j + 1) % nj] * 3 + 1],
|
||||||
tile.data.verts[p.verts[(j + 1) % nj] * 3 + 2]
|
tile.data.verts[p.verts[(j + 1) % nj] * 3 + 2]
|
||||||
|
@ -370,20 +371,20 @@ public class RecastDebugDraw : DebugDraw
|
||||||
for (int k = 0; k < pd.triCount; ++k)
|
for (int k = 0; k < pd.triCount; ++k)
|
||||||
{
|
{
|
||||||
int t = (pd.triBase + k) * 4;
|
int t = (pd.triBase + k) * 4;
|
||||||
RcVec3f[] tv = new RcVec3f[3];
|
Vector3[] tv = new Vector3[3];
|
||||||
for (int m = 0; m < 3; ++m)
|
for (int m = 0; m < 3; ++m)
|
||||||
{
|
{
|
||||||
int v = tile.data.detailTris[t + m];
|
int v = tile.data.detailTris[t + m];
|
||||||
if (v < p.vertCount)
|
if (v < p.vertCount)
|
||||||
{
|
{
|
||||||
tv[m] = new RcVec3f(
|
tv[m] = new Vector3(
|
||||||
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]
|
tile.data.verts[p.verts[v] * 3 + 2]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tv[m] = new RcVec3f(
|
tv[m] = new Vector3(
|
||||||
tile.data.detailVerts[(pd.vertBase + (v - p.vertCount)) * 3],
|
tile.data.detailVerts[(pd.vertBase + (v - p.vertCount)) * 3],
|
||||||
tile.data.detailVerts[(pd.vertBase + (v - p.vertCount)) * 3 + 1],
|
tile.data.detailVerts[(pd.vertBase + (v - p.vertCount)) * 3 + 1],
|
||||||
tile.data.detailVerts[(pd.vertBase + (v - p.vertCount)) * 3 + 2]
|
tile.data.detailVerts[(pd.vertBase + (v - p.vertCount)) * 3 + 2]
|
||||||
|
@ -420,7 +421,7 @@ public class RecastDebugDraw : DebugDraw
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
||||||
static float DistancePtLine2d(RcVec3f pt, RcVec3f p, RcVec3f q)
|
static float DistancePtLine2d(Vector3 pt, Vector3 p, Vector3 q)
|
||||||
{
|
{
|
||||||
float pqx = q.X - p.X;
|
float pqx = q.X - p.X;
|
||||||
float pqz = q.Z - p.Z;
|
float pqz = q.Z - p.Z;
|
||||||
|
@ -522,7 +523,7 @@ public class RecastDebugDraw : DebugDraw
|
||||||
{
|
{
|
||||||
float alpha = 1f;
|
float alpha = 1f;
|
||||||
|
|
||||||
RcVec3f orig = cset.bmin;
|
Vector3 orig = cset.bmin;
|
||||||
float cs = cset.cs;
|
float cs = cset.cs;
|
||||||
float ch = cset.ch;
|
float ch = cset.ch;
|
||||||
|
|
||||||
|
@ -533,7 +534,7 @@ public class RecastDebugDraw : DebugDraw
|
||||||
for (int i = 0; i < cset.conts.Count; ++i)
|
for (int i = 0; i < cset.conts.Count; ++i)
|
||||||
{
|
{
|
||||||
RcContour cont = cset.conts[i];
|
RcContour cont = cset.conts[i];
|
||||||
RcVec3f pos = GetContourCenter(cont, orig, cs, ch);
|
Vector3 pos = GetContourCenter(cont, orig, cs, ch);
|
||||||
for (int j = 0; j < cont.nverts; ++j)
|
for (int j = 0; j < cont.nverts; ++j)
|
||||||
{
|
{
|
||||||
int v = j * 4;
|
int v = j * 4;
|
||||||
|
@ -545,7 +546,7 @@ public class RecastDebugDraw : DebugDraw
|
||||||
RcContour cont2 = FindContourFromSet(cset, (short)cont.verts[v + 3]);
|
RcContour cont2 = FindContourFromSet(cset, (short)cont.verts[v + 3]);
|
||||||
if (cont2 != null)
|
if (cont2 != null)
|
||||||
{
|
{
|
||||||
RcVec3f pos2 = GetContourCenter(cont2, orig, cs, ch);
|
Vector3 pos2 = GetContourCenter(cont2, orig, cs, ch);
|
||||||
AppendArc(pos.X, pos.Y, pos.Z, pos2.X, pos2.Y, pos2.Z, 0.25f, 0.6f, 0.6f, color);
|
AppendArc(pos.X, pos.Y, pos.Z, pos2.X, pos2.Y, pos2.Z, 0.25f, 0.6f, 0.6f, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -561,16 +562,16 @@ public class RecastDebugDraw : DebugDraw
|
||||||
{
|
{
|
||||||
RcContour cont = cset.conts[i];
|
RcContour cont = cset.conts[i];
|
||||||
int col = DuDarkenCol(DuIntToCol(cont.reg, a));
|
int col = DuDarkenCol(DuIntToCol(cont.reg, a));
|
||||||
RcVec3f pos = GetContourCenter(cont, orig, cs, ch);
|
Vector3 pos = GetContourCenter(cont, orig, cs, ch);
|
||||||
Vertex(pos, col);
|
Vertex(pos, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
||||||
private RcVec3f GetContourCenter(RcContour cont, RcVec3f orig, float cs, float ch)
|
private Vector3 GetContourCenter(RcContour cont, Vector3 orig, float cs, float ch)
|
||||||
{
|
{
|
||||||
RcVec3f center = new RcVec3f();
|
Vector3 center = new Vector3();
|
||||||
center.X = 0;
|
center.X = 0;
|
||||||
center.Y = 0;
|
center.Y = 0;
|
||||||
center.Z = 0;
|
center.Z = 0;
|
||||||
|
@ -612,7 +613,7 @@ public class RecastDebugDraw : DebugDraw
|
||||||
|
|
||||||
public void DebugDrawRawContours(RcContourSet cset, float alpha)
|
public void DebugDrawRawContours(RcContourSet cset, float alpha)
|
||||||
{
|
{
|
||||||
RcVec3f orig = cset.bmin;
|
Vector3 orig = cset.bmin;
|
||||||
float cs = cset.cs;
|
float cs = cset.cs;
|
||||||
float ch = cset.ch;
|
float ch = cset.ch;
|
||||||
|
|
||||||
|
@ -688,7 +689,7 @@ public class RecastDebugDraw : DebugDraw
|
||||||
public void DebugDrawContours(RcContourSet cset)
|
public void DebugDrawContours(RcContourSet cset)
|
||||||
{
|
{
|
||||||
float alpha = 1f;
|
float alpha = 1f;
|
||||||
RcVec3f orig = cset.bmin;
|
Vector3 orig = cset.bmin;
|
||||||
float cs = cset.cs;
|
float cs = cset.cs;
|
||||||
float ch = cset.ch;
|
float ch = cset.ch;
|
||||||
|
|
||||||
|
@ -770,7 +771,7 @@ public class RecastDebugDraw : DebugDraw
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f orig = hf.bmin;
|
Vector3 orig = hf.bmin;
|
||||||
float cs = hf.cs;
|
float cs = hf.cs;
|
||||||
float ch = hf.ch;
|
float ch = hf.ch;
|
||||||
|
|
||||||
|
@ -802,7 +803,7 @@ public class RecastDebugDraw : DebugDraw
|
||||||
|
|
||||||
public void DebugDrawHeightfieldWalkable(RcHeightfield hf)
|
public void DebugDrawHeightfieldWalkable(RcHeightfield hf)
|
||||||
{
|
{
|
||||||
RcVec3f orig = hf.bmin;
|
Vector3 orig = hf.bmin;
|
||||||
float cs = hf.cs;
|
float cs = hf.cs;
|
||||||
float ch = hf.ch;
|
float ch = hf.ch;
|
||||||
|
|
||||||
|
@ -935,7 +936,7 @@ public class RecastDebugDraw : DebugDraw
|
||||||
int nvp = mesh.nvp;
|
int nvp = mesh.nvp;
|
||||||
float cs = mesh.cs;
|
float cs = mesh.cs;
|
||||||
float ch = mesh.ch;
|
float ch = mesh.ch;
|
||||||
RcVec3f orig = mesh.bmin;
|
Vector3 orig = mesh.bmin;
|
||||||
|
|
||||||
Begin(DebugDrawPrimitives.TRIS);
|
Begin(DebugDrawPrimitives.TRIS);
|
||||||
|
|
||||||
|
@ -1200,39 +1201,45 @@ public class RecastDebugDraw : DebugDraw
|
||||||
float off = 0.5f;
|
float off = 0.5f;
|
||||||
Begin(DebugDrawPrimitives.POINTS, 4.0f);
|
Begin(DebugDrawPrimitives.POINTS, 4.0f);
|
||||||
|
|
||||||
foreach (DtNode node in pool.AsEnumerable())
|
foreach (List<DtNode> nodes in pool.GetNodeMap().Values)
|
||||||
{
|
{
|
||||||
if (node == null)
|
foreach (DtNode node in nodes)
|
||||||
{
|
{
|
||||||
continue;
|
if (node == null)
|
||||||
}
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Vertex(node.pos.X, node.pos.Y + off, node.pos.Z, DuRGBA(255, 192, 0, 255));
|
Vertex(node.pos.X, node.pos.Y + off, node.pos.Z, DuRGBA(255, 192, 0, 255));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
End();
|
End();
|
||||||
|
|
||||||
Begin(DebugDrawPrimitives.LINES, 2.0f);
|
Begin(DebugDrawPrimitives.LINES, 2.0f);
|
||||||
foreach (DtNode node in pool.AsEnumerable())
|
foreach (List<DtNode> nodes in pool.GetNodeMap().Values)
|
||||||
{
|
{
|
||||||
if (node == null)
|
foreach (DtNode node in nodes)
|
||||||
{
|
{
|
||||||
continue;
|
if (node == null)
|
||||||
}
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (node.pidx == 0)
|
if (node.pidx == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DtNode parent = pool.GetNodeAtIdx(node.pidx);
|
DtNode parent = pool.GetNodeAtIdx(node.pidx);
|
||||||
if (parent == null)
|
if (parent == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vertex(node.pos.X, node.pos.Y + off, node.pos.Z, DuRGBA(255, 192, 0, 128));
|
Vertex(node.pos.X, node.pos.Y + off, node.pos.Z, DuRGBA(255, 192, 0, 128));
|
||||||
Vertex(parent.pos.X, parent.pos.Y + off, parent.pos.Z, DuRGBA(255, 192, 0, 128));
|
Vertex(parent.pos.X, parent.pos.Y + off, parent.pos.Z, DuRGBA(255, 192, 0, 128));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
End();
|
End();
|
||||||
|
@ -1342,11 +1349,11 @@ public class RecastDebugDraw : DebugDraw
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Create new links
|
// Create new links
|
||||||
var va = new RcVec3f(
|
var va = new Vector3(
|
||||||
tile.data.verts[poly.verts[j] * 3],
|
tile.data.verts[poly.verts[j] * 3],
|
||||||
tile.data.verts[poly.verts[j] * 3 + 1], tile.data.verts[poly.verts[j] * 3 + 2]
|
tile.data.verts[poly.verts[j] * 3 + 1], tile.data.verts[poly.verts[j] * 3 + 2]
|
||||||
);
|
);
|
||||||
var vb = new RcVec3f(
|
var vb = new Vector3(
|
||||||
tile.data.verts[poly.verts[(j + 1) % nv] * 3],
|
tile.data.verts[poly.verts[(j + 1) % nv] * 3],
|
||||||
tile.data.verts[poly.verts[(j + 1) % nv] * 3 + 1],
|
tile.data.verts[poly.verts[(j + 1) % nv] * 3 + 1],
|
||||||
tile.data.verts[poly.verts[(j + 1) % nv] * 3 + 2]
|
tile.data.verts[poly.verts[(j + 1) % nv] * 3 + 2]
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Demo.Messages;
|
namespace DotRecast.Recast.Demo.Messages;
|
||||||
|
|
||||||
public class RaycastEvent : IRecastDemoMessage
|
public class RaycastEvent : IRecastDemoMessage
|
||||||
{
|
{
|
||||||
public RcVec3f Start { get; init; }
|
public Vector3 Start { get; init; }
|
||||||
public RcVec3f End { get; init; }
|
public Vector3 End { get; init; }
|
||||||
}
|
}
|
|
@ -34,6 +34,7 @@ using Silk.NET.OpenGL.Extensions.ImGui;
|
||||||
using Silk.NET.Windowing;
|
using Silk.NET.Windowing;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
using DotRecast.Detour.Extras.Unity.Astar;
|
using DotRecast.Detour.Extras.Unity.Astar;
|
||||||
using DotRecast.Detour.Io;
|
using DotRecast.Detour.Io;
|
||||||
|
@ -43,6 +44,7 @@ using DotRecast.Recast.Demo.Messages;
|
||||||
using DotRecast.Recast.Toolset.Geom;
|
using DotRecast.Recast.Toolset.Geom;
|
||||||
using DotRecast.Recast.Demo.Tools;
|
using DotRecast.Recast.Demo.Tools;
|
||||||
using DotRecast.Recast.Demo.UI;
|
using DotRecast.Recast.Demo.UI;
|
||||||
|
using DotRecast.Recast.Toolset;
|
||||||
using MouseButton = Silk.NET.Input.MouseButton;
|
using MouseButton = Silk.NET.Input.MouseButton;
|
||||||
using Window = Silk.NET.Windowing.Window;
|
using Window = Silk.NET.Windowing.Window;
|
||||||
|
|
||||||
|
@ -79,7 +81,7 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
private bool processHitTestShift;
|
private bool processHitTestShift;
|
||||||
private int _modState;
|
private int _modState;
|
||||||
|
|
||||||
private RcVec2f mousePos = new RcVec2f();
|
private Vector2 mousePos = new Vector2();
|
||||||
|
|
||||||
private bool _mouseOverMenu;
|
private bool _mouseOverMenu;
|
||||||
private bool pan;
|
private bool pan;
|
||||||
|
@ -87,12 +89,12 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
private bool rotate;
|
private bool rotate;
|
||||||
private bool movedDuringRotate;
|
private bool movedDuringRotate;
|
||||||
private float scrollZoom;
|
private float scrollZoom;
|
||||||
private RcVec2f origMousePos = new RcVec2f();
|
private Vector2 origMousePos = new Vector2();
|
||||||
private RcVec2f origCameraEulers = new RcVec2f();
|
private Vector2 origCameraEulers = new Vector2();
|
||||||
private RcVec3f origCameraPos = new RcVec3f();
|
private Vector3 origCameraPos = new Vector3();
|
||||||
|
|
||||||
private RcVec2f cameraEulers = new RcVec2f(45, -45);
|
private Vector2 cameraEulers = new Vector2(45, -45);
|
||||||
private RcVec3f cameraPos = new RcVec3f(0, 0, 0);
|
private Vector3 cameraPos = new Vector3(0, 0, 0);
|
||||||
|
|
||||||
|
|
||||||
private float[] projectionMatrix = new float[16];
|
private float[] projectionMatrix = new float[16];
|
||||||
|
@ -108,10 +110,9 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
|
|
||||||
private int[] viewport;
|
private int[] viewport;
|
||||||
private bool markerPositionSet;
|
private bool markerPositionSet;
|
||||||
private RcVec3f markerPosition = new RcVec3f();
|
private Vector3 markerPosition = new Vector3();
|
||||||
|
|
||||||
private RcMenuView _menuView;
|
private RcToolsetView toolset;
|
||||||
private RcToolsetView _toolsetView;
|
|
||||||
private RcSettingsView settingsView;
|
private RcSettingsView settingsView;
|
||||||
private RcLogView logView;
|
private RcLogView logView;
|
||||||
|
|
||||||
|
@ -319,7 +320,7 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
if (null != mesh)
|
if (null != mesh)
|
||||||
{
|
{
|
||||||
_sample.Update(_sample.GetInputGeom(), ImmutableArray<RcBuilderResult>.Empty, mesh);
|
_sample.Update(_sample.GetInputGeom(), ImmutableArray<RcBuilderResult>.Empty, mesh);
|
||||||
_toolsetView.SetEnabled(true);
|
toolset.SetEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -380,11 +381,10 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
DemoInputGeomProvider geom = LoadInputMesh("nav_test.obj");
|
DemoInputGeomProvider geom = LoadInputMesh("nav_test.obj");
|
||||||
_sample = new DemoSample(geom, ImmutableArray<RcBuilderResult>.Empty, null);
|
_sample = new DemoSample(geom, ImmutableArray<RcBuilderResult>.Empty, null);
|
||||||
|
|
||||||
_menuView = new RcMenuView();
|
|
||||||
settingsView = new RcSettingsView(this);
|
settingsView = new RcSettingsView(this);
|
||||||
settingsView.SetSample(_sample);
|
settingsView.SetSample(_sample);
|
||||||
|
|
||||||
_toolsetView = new RcToolsetView(
|
toolset = new RcToolsetView(
|
||||||
new TestNavmeshSampleTool(),
|
new TestNavmeshSampleTool(),
|
||||||
new TileSampleTool(),
|
new TileSampleTool(),
|
||||||
new ObstacleSampleTool(),
|
new ObstacleSampleTool(),
|
||||||
|
@ -395,10 +395,10 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
new JumpLinkBuilderSampleTool(),
|
new JumpLinkBuilderSampleTool(),
|
||||||
new DynamicUpdateSampleTool()
|
new DynamicUpdateSampleTool()
|
||||||
);
|
);
|
||||||
_toolsetView.SetEnabled(true);
|
toolset.SetEnabled(true);
|
||||||
logView = new RcLogView();
|
logView = new RcLogView();
|
||||||
|
|
||||||
_canvas = new RcCanvas(window, _menuView, settingsView, _toolsetView, logView);
|
_canvas = new RcCanvas(window, settingsView, toolset, logView);
|
||||||
|
|
||||||
var vendor = _gl.GetStringS(GLEnum.Vendor);
|
var vendor = _gl.GetStringS(GLEnum.Vendor);
|
||||||
var version = _gl.GetStringS(GLEnum.Version);
|
var version = _gl.GetStringS(GLEnum.Version);
|
||||||
|
@ -460,8 +460,8 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
if (_sample.GetInputGeom() != null)
|
if (_sample.GetInputGeom() != null)
|
||||||
{
|
{
|
||||||
var settings = _sample.GetSettings();
|
var settings = _sample.GetSettings();
|
||||||
RcVec3f bmin = _sample.GetInputGeom().GetMeshBoundsMin();
|
Vector3 bmin = _sample.GetInputGeom().GetMeshBoundsMin();
|
||||||
RcVec3f bmax = _sample.GetInputGeom().GetMeshBoundsMax();
|
Vector3 bmax = _sample.GetInputGeom().GetMeshBoundsMax();
|
||||||
RcCommons.CalcGridSize(bmin, bmax, settings.cellSize, out var gw, out var gh);
|
RcCommons.CalcGridSize(bmin, bmax, settings.cellSize, out var gw, out var gh);
|
||||||
settingsView.SetVoxels(gw, gh);
|
settingsView.SetVoxels(gw, gh);
|
||||||
settingsView.SetTiles(tileNavMeshBuilder.GetTiles(_sample.GetInputGeom(), settings.cellSize, settings.tileSize));
|
settingsView.SetTiles(tileNavMeshBuilder.GetTiles(_sample.GetInputGeom(), settings.cellSize, settings.tileSize));
|
||||||
|
@ -505,7 +505,7 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
timeAcc -= DELTA_TIME;
|
timeAcc -= DELTA_TIME;
|
||||||
if (simIter < 5 && _sample != null)
|
if (simIter < 5 && _sample != null)
|
||||||
{
|
{
|
||||||
var tool = _toolsetView.GetTool();
|
var tool = toolset.GetTool();
|
||||||
if (null != tool)
|
if (null != tool)
|
||||||
{
|
{
|
||||||
tool.HandleUpdate(DELTA_TIME);
|
tool.HandleUpdate(DELTA_TIME);
|
||||||
|
@ -519,8 +519,8 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
{
|
{
|
||||||
processHitTest = false;
|
processHitTest = false;
|
||||||
|
|
||||||
RcVec3f rayStart = new RcVec3f();
|
Vector3 rayStart = new Vector3();
|
||||||
RcVec3f rayEnd = new RcVec3f();
|
Vector3 rayEnd = new Vector3();
|
||||||
|
|
||||||
GLU.GlhUnProjectf(mousePos.X, viewport[3] - 1 - mousePos.Y, 0.0f, modelviewMatrix, projectionMatrix, viewport, ref rayStart);
|
GLU.GlhUnProjectf(mousePos.X, viewport[3] - 1 - mousePos.Y, 0.0f, modelviewMatrix, projectionMatrix, viewport, ref rayStart);
|
||||||
GLU.GlhUnProjectf(mousePos.X, viewport[3] - 1 - mousePos.Y, 1.0f, modelviewMatrix, projectionMatrix, viewport, ref rayEnd);
|
GLU.GlhUnProjectf(mousePos.X, viewport[3] - 1 - mousePos.Y, 1.0f, modelviewMatrix, projectionMatrix, viewport, ref rayEnd);
|
||||||
|
@ -535,8 +535,8 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
if (_sample.IsChanged())
|
if (_sample.IsChanged())
|
||||||
{
|
{
|
||||||
bool hasBound = false;
|
bool hasBound = false;
|
||||||
RcVec3f bminN = RcVec3f.Zero;
|
Vector3 bminN = Vector3.Zero;
|
||||||
RcVec3f bmaxN = RcVec3f.Zero;
|
Vector3 bmaxN = Vector3.Zero;
|
||||||
if (_sample.GetInputGeom() != null)
|
if (_sample.GetInputGeom() != null)
|
||||||
{
|
{
|
||||||
bminN = _sample.GetInputGeom().GetMeshBoundsMin();
|
bminN = _sample.GetInputGeom().GetMeshBoundsMin();
|
||||||
|
@ -556,17 +556,17 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
{
|
{
|
||||||
if (!hasBound)
|
if (!hasBound)
|
||||||
{
|
{
|
||||||
bminN = new RcVec3f(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
|
bminN = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
|
||||||
bmaxN = new RcVec3f(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
|
bmaxN = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
bminN = new RcVec3f(
|
bminN = new Vector3(
|
||||||
Math.Min(bminN.X, result.GetSolidHeightfield().bmin.X),
|
Math.Min(bminN.X, result.GetSolidHeightfield().bmin.X),
|
||||||
Math.Min(bminN.Y, result.GetSolidHeightfield().bmin.Y),
|
Math.Min(bminN.Y, result.GetSolidHeightfield().bmin.Y),
|
||||||
Math.Min(bminN.Z, result.GetSolidHeightfield().bmin.Z)
|
Math.Min(bminN.Z, result.GetSolidHeightfield().bmin.Z)
|
||||||
);
|
);
|
||||||
|
|
||||||
bmaxN = new RcVec3f(
|
bmaxN = new Vector3(
|
||||||
Math.Max(bmaxN.X, result.GetSolidHeightfield().bmax.X),
|
Math.Max(bmaxN.X, result.GetSolidHeightfield().bmax.X),
|
||||||
Math.Max(bmaxN.Y, result.GetSolidHeightfield().bmax.Y),
|
Math.Max(bmaxN.Y, result.GetSolidHeightfield().bmax.Y),
|
||||||
Math.Max(bmaxN.Z, result.GetSolidHeightfield().bmax.Z)
|
Math.Max(bmaxN.Z, result.GetSolidHeightfield().bmax.Z)
|
||||||
|
@ -579,8 +579,8 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
|
|
||||||
if (hasBound)
|
if (hasBound)
|
||||||
{
|
{
|
||||||
RcVec3f bmin = bminN;
|
Vector3 bmin = bminN;
|
||||||
RcVec3f bmax = bmaxN;
|
Vector3 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.X = (bmax.X + bmin.X) / 2 + camr;
|
||||||
|
@ -592,7 +592,7 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
_sample.SetChanged(false);
|
_sample.SetChanged(false);
|
||||||
_toolsetView.SetSample(_sample);
|
toolset.SetSample(_sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_messages.TryDequeue(out var msg))
|
if (_messages.TryDequeue(out var msg))
|
||||||
|
@ -621,7 +621,7 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
dd.Fog(camr * 0.1f, camr * 1.25f);
|
dd.Fog(camr * 0.1f, camr * 1.25f);
|
||||||
renderer.Render(_sample, settingsView.GetDrawMode());
|
renderer.Render(_sample, settingsView.GetDrawMode());
|
||||||
|
|
||||||
ISampleTool sampleTool = _toolsetView.GetTool();
|
ISampleTool sampleTool = toolset.GetTool();
|
||||||
if (sampleTool != null)
|
if (sampleTool != null)
|
||||||
{
|
{
|
||||||
sampleTool.HandleRender(renderer);
|
sampleTool.HandleRender(renderer);
|
||||||
|
@ -708,7 +708,7 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
_sample.SetChanged(false);
|
_sample.SetChanged(false);
|
||||||
settingsView.SetBuildTime((RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond);
|
settingsView.SetBuildTime((RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond);
|
||||||
//settingsUI.SetBuildTelemetry(buildResult.Item1.Select(x => x.GetTelemetry()).ToList());
|
//settingsUI.SetBuildTelemetry(buildResult.Item1.Select(x => x.GetTelemetry()).ToList());
|
||||||
_toolsetView.SetSample(_sample);
|
toolset.SetSample(_sample);
|
||||||
|
|
||||||
Logger.Information($"build times");
|
Logger.Information($"build times");
|
||||||
Logger.Information($"-----------------------------------------");
|
Logger.Information($"-----------------------------------------");
|
||||||
|
@ -798,10 +798,10 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
hit = RcPolyMeshRaycast.Raycast(_sample.GetRecastResults(), rayStart, rayEnd, out hitTime);
|
hit = RcPolyMeshRaycast.Raycast(_sample.GetRecastResults(), rayStart, rayEnd, out hitTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f rayDir = new RcVec3f(rayEnd.X - rayStart.X, rayEnd.Y - rayStart.Y, rayEnd.Z - rayStart.Z);
|
Vector3 rayDir = new Vector3(rayEnd.X - rayStart.X, rayEnd.Y - rayStart.Y, rayEnd.Z - rayStart.Z);
|
||||||
rayDir = RcVec3f.Normalize(rayDir);
|
rayDir = Vector3.Normalize(rayDir);
|
||||||
|
|
||||||
ISampleTool raySampleTool = _toolsetView.GetTool();
|
ISampleTool raySampleTool = toolset.GetTool();
|
||||||
|
|
||||||
if (raySampleTool != null)
|
if (raySampleTool != null)
|
||||||
{
|
{
|
||||||
|
@ -821,7 +821,7 @@ public class RecastDemo : IRecastDemoChannel
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RcVec3f pos = new RcVec3f();
|
Vector3 pos = new Vector3();
|
||||||
pos.X = rayStart.X + (rayEnd.X - rayStart.X) * hitTime;
|
pos.X = rayStart.X + (rayEnd.X - rayStart.X) * hitTime;
|
||||||
pos.Y = rayStart.Y + (rayEnd.Y - rayStart.Y) * hitTime;
|
pos.Y = rayStart.Y + (rayEnd.Y - rayStart.Y) * hitTime;
|
||||||
pos.Z = rayStart.Z + (rayEnd.Z - rayStart.Z) * hitTime;
|
pos.Z = rayStart.Z + (rayEnd.Z - rayStart.Z) * hitTime;
|
||||||
|
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
using DotRecast.Recast.Demo.Draw;
|
using DotRecast.Recast.Demo.Draw;
|
||||||
using DotRecast.Recast.Toolset;
|
using DotRecast.Recast.Toolset;
|
||||||
|
@ -155,16 +156,20 @@ public class ConvexVolumeSampleTool : ISampleTool
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
|
public void HandleClick(Vector3 s, Vector3 p, bool shift)
|
||||||
{
|
{
|
||||||
var geom = _sample.GetInputGeom();
|
var geom = _sample.GetInputGeom();
|
||||||
if (shift)
|
if (shift)
|
||||||
{
|
{
|
||||||
_tool.TryRemove(geom, p, out var volume);
|
_tool.RemoveByPos(geom, p);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_tool.TryAdd(geom, p, _areaType, _boxDescent, _boxHeight, _polyOffset, out var volume);
|
if (_tool.PlottingShape(p, out var pts, out var hull))
|
||||||
|
{
|
||||||
|
var vol = RcConvexVolumeTool.CreateConvexVolume(pts, hull, _areaType, _boxDescent, _boxHeight, _polyOffset);
|
||||||
|
_tool.Add(geom, vol);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +179,7 @@ public class ConvexVolumeSampleTool : ISampleTool
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift)
|
public void HandleClickRay(Vector3 start, Vector3 direction, bool shift)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
using DotRecast.Detour.Crowd;
|
using DotRecast.Detour.Crowd;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
|
@ -118,11 +119,7 @@ public class CrowdAgentProfilingSampleTool : ISampleTool
|
||||||
ImGui.Text($"{rtt.Key}: {rtt.Micros} us");
|
ImGui.Text($"{rtt.Key}: {rtt.Micros} us");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.Text($"Sampling Time: {_tool.GetCrowdUpdateSamplingTime()} ms");
|
ImGui.Text($"Update Time: {_tool.GetCrowdUpdateTime()} 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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +134,7 @@ public class CrowdAgentProfilingSampleTool : ISampleTool
|
||||||
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
||||||
{
|
{
|
||||||
float radius = ag.option.radius;
|
float radius = ag.option.radius;
|
||||||
RcVec3f pos = ag.npos;
|
Vector3 pos = ag.npos;
|
||||||
dd.DebugDrawCircle(pos.X, pos.Y, pos.Z, radius, DuRGBA(0, 0, 0, 32), 2.0f);
|
dd.DebugDrawCircle(pos.X, pos.Y, pos.Z, radius, DuRGBA(0, 0, 0, 32), 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +144,7 @@ public class CrowdAgentProfilingSampleTool : ISampleTool
|
||||||
|
|
||||||
float height = ag.option.height;
|
float height = ag.option.height;
|
||||||
float radius = ag.option.radius;
|
float radius = ag.option.radius;
|
||||||
RcVec3f pos = ag.npos;
|
Vector3 pos = ag.npos;
|
||||||
|
|
||||||
int col = DuRGBA(220, 220, 220, 128);
|
int col = DuRGBA(220, 220, 220, 128);
|
||||||
if (crowAgentData.type == RcCrowdAgentType.TRAVELLER)
|
if (crowAgentData.type == RcCrowdAgentType.TRAVELLER)
|
||||||
|
@ -202,7 +199,7 @@ public class CrowdAgentProfilingSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
|
public void HandleClick(Vector3 s, Vector3 p, bool shift)
|
||||||
{
|
{
|
||||||
//throw new NotImplementedException();
|
//throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -213,7 +210,7 @@ public class CrowdAgentProfilingSampleTool : ISampleTool
|
||||||
_tool.Update(dt);
|
_tool.Update(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift)
|
public void HandleClickRay(Vector3 start, Vector3 direction, bool shift)
|
||||||
{
|
{
|
||||||
//throw new NotImplementedException();
|
//throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
using DotRecast.Detour.Crowd;
|
using DotRecast.Detour.Crowd;
|
||||||
|
|
||||||
|
@ -188,7 +189,7 @@ public class CrowdSampleTool : ISampleTool
|
||||||
float gridy = -float.MaxValue;
|
float gridy = -float.MaxValue;
|
||||||
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
||||||
{
|
{
|
||||||
RcVec3f pos = ag.corridor.GetPos();
|
Vector3 pos = ag.corridor.GetPos();
|
||||||
gridy = Math.Max(gridy, pos.Y);
|
gridy = Math.Max(gridy, pos.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,10 +221,10 @@ public class CrowdSampleTool : ISampleTool
|
||||||
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
||||||
{
|
{
|
||||||
RcCrowdAgentTrail trail = agentTrails[ag.idx];
|
RcCrowdAgentTrail trail = agentTrails[ag.idx];
|
||||||
RcVec3f pos = ag.npos;
|
Vector3 pos = ag.npos;
|
||||||
|
|
||||||
dd.Begin(LINES, 3.0f);
|
dd.Begin(LINES, 3.0f);
|
||||||
RcVec3f prev = new RcVec3f();
|
Vector3 prev = new Vector3();
|
||||||
float preva = 1;
|
float preva = 1;
|
||||||
prev = pos;
|
prev = pos;
|
||||||
for (int j = 0; j < RcCrowdAgentTrail.AGENT_MAX_TRAIL - 1; ++j)
|
for (int j = 0; j < RcCrowdAgentTrail.AGENT_MAX_TRAIL - 1; ++j)
|
||||||
|
@ -247,7 +248,7 @@ public class CrowdSampleTool : ISampleTool
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float radius = ag.option.radius;
|
float radius = ag.option.radius;
|
||||||
RcVec3f pos = ag.npos;
|
Vector3 pos = ag.npos;
|
||||||
|
|
||||||
if (_showCorners)
|
if (_showCorners)
|
||||||
{
|
{
|
||||||
|
@ -256,8 +257,8 @@ public class CrowdSampleTool : ISampleTool
|
||||||
dd.Begin(LINES, 2.0f);
|
dd.Begin(LINES, 2.0f);
|
||||||
for (int j = 0; j < ag.corners.Count; ++j)
|
for (int j = 0; j < ag.corners.Count; ++j)
|
||||||
{
|
{
|
||||||
RcVec3f va = j == 0 ? pos : ag.corners[j - 1].pos;
|
Vector3 va = j == 0 ? pos : ag.corners[j - 1].pos;
|
||||||
RcVec3f vb = ag.corners[j].pos;
|
Vector3 vb = ag.corners[j].pos;
|
||||||
dd.Vertex(va.X, va.Y + radius, va.Z, DuRGBA(128, 0, 0, 192));
|
dd.Vertex(va.X, va.Y + radius, va.Z, DuRGBA(128, 0, 0, 192));
|
||||||
dd.Vertex(vb.X, vb.Y + radius, vb.Z, DuRGBA(128, 0, 0, 192));
|
dd.Vertex(vb.X, vb.Y + radius, vb.Z, DuRGBA(128, 0, 0, 192));
|
||||||
}
|
}
|
||||||
|
@ -265,7 +266,7 @@ public class CrowdSampleTool : ISampleTool
|
||||||
if ((ag.corners[ag.corners.Count - 1].flags
|
if ((ag.corners[ag.corners.Count - 1].flags
|
||||||
& DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
& DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
||||||
{
|
{
|
||||||
RcVec3f v = ag.corners[ag.corners.Count - 1].pos;
|
Vector3 v = ag.corners[ag.corners.Count - 1].pos;
|
||||||
dd.Vertex(v.X, v.Y, v.Z, DuRGBA(192, 0, 0, 192));
|
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));
|
dd.Vertex(v.X, v.Y + radius * 2, v.Z, DuRGBA(192, 0, 0, 192));
|
||||||
}
|
}
|
||||||
|
@ -299,7 +300,7 @@ public class CrowdSampleTool : ISampleTool
|
||||||
|
|
||||||
if (_showCollisionSegments)
|
if (_showCollisionSegments)
|
||||||
{
|
{
|
||||||
RcVec3f center = ag.boundary.GetCenter();
|
Vector3 center = ag.boundary.GetCenter();
|
||||||
dd.DebugDrawCross(center.X, center.Y + radius, center.Z, 0.2f, DuRGBA(192, 0, 128, 255), 2.0f);
|
dd.DebugDrawCross(center.X, center.Y + radius, center.Z, 0.2f, DuRGBA(192, 0, 128, 255), 2.0f);
|
||||||
dd.DebugDrawCircle(center.X, center.Y + radius, center.Z, ag.option.collisionQueryRange, DuRGBA(192, 0, 128, 128), 2.0f);
|
dd.DebugDrawCircle(center.X, center.Y + radius, center.Z, ag.option.collisionQueryRange, DuRGBA(192, 0, 128, 128), 2.0f);
|
||||||
|
|
||||||
|
@ -307,9 +308,9 @@ public class CrowdSampleTool : ISampleTool
|
||||||
for (int j = 0; j < ag.boundary.GetSegmentCount(); ++j)
|
for (int j = 0; j < ag.boundary.GetSegmentCount(); ++j)
|
||||||
{
|
{
|
||||||
int col = DuRGBA(192, 0, 128, 192);
|
int col = DuRGBA(192, 0, 128, 192);
|
||||||
RcVec3f[] s = ag.boundary.GetSegment(j);
|
Vector3[] s = ag.boundary.GetSegment(j);
|
||||||
RcVec3f s0 = s[0];
|
Vector3 s0 = s[0];
|
||||||
RcVec3f s3 = s[1];
|
Vector3 s3 = s[1];
|
||||||
if (DtUtils.TriArea2D(pos, s0, s3) < 0.0f)
|
if (DtUtils.TriArea2D(pos, s0, s3) < 0.0f)
|
||||||
col = DuDarkenCol(col);
|
col = DuDarkenCol(col);
|
||||||
|
|
||||||
|
@ -352,7 +353,7 @@ public class CrowdSampleTool : ISampleTool
|
||||||
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
||||||
{
|
{
|
||||||
float radius = ag.option.radius;
|
float radius = ag.option.radius;
|
||||||
RcVec3f pos = ag.npos;
|
Vector3 pos = ag.npos;
|
||||||
|
|
||||||
int col = DuRGBA(0, 0, 0, 32);
|
int col = DuRGBA(0, 0, 0, 32);
|
||||||
if (agentDebug.agent == ag)
|
if (agentDebug.agent == ag)
|
||||||
|
@ -365,7 +366,7 @@ public class CrowdSampleTool : ISampleTool
|
||||||
{
|
{
|
||||||
float height = ag.option.height;
|
float height = ag.option.height;
|
||||||
float radius = ag.option.radius;
|
float radius = ag.option.radius;
|
||||||
RcVec3f pos = ag.npos;
|
Vector3 pos = ag.npos;
|
||||||
|
|
||||||
int col = DuRGBA(220, 220, 220, 128);
|
int col = DuRGBA(220, 220, 220, 128);
|
||||||
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|
||||||
|
@ -401,7 +402,7 @@ public class CrowdSampleTool : ISampleTool
|
||||||
dd.Begin(QUADS);
|
dd.Begin(QUADS);
|
||||||
for (int j = 0; j < vod.GetSampleCount(); ++j)
|
for (int j = 0; j < vod.GetSampleCount(); ++j)
|
||||||
{
|
{
|
||||||
RcVec3f p = vod.GetSampleVelocity(j);
|
Vector3 p = vod.GetSampleVelocity(j);
|
||||||
float sr = vod.GetSampleSize(j);
|
float sr = vod.GetSampleSize(j);
|
||||||
float pen = vod.GetSamplePenalty(j);
|
float pen = vod.GetSamplePenalty(j);
|
||||||
float pen2 = vod.GetSamplePreferredSidePenalty(j);
|
float pen2 = vod.GetSamplePreferredSidePenalty(j);
|
||||||
|
@ -422,9 +423,9 @@ public class CrowdSampleTool : ISampleTool
|
||||||
{
|
{
|
||||||
float radius = ag.option.radius;
|
float radius = ag.option.radius;
|
||||||
float height = ag.option.height;
|
float height = ag.option.height;
|
||||||
RcVec3f pos = ag.npos;
|
Vector3 pos = ag.npos;
|
||||||
RcVec3f vel = ag.vel;
|
Vector3 vel = ag.vel;
|
||||||
RcVec3f dvel = ag.dvel;
|
Vector3 dvel = ag.dvel;
|
||||||
|
|
||||||
int col = DuRGBA(220, 220, 220, 192);
|
int col = DuRGBA(220, 220, 220, 192);
|
||||||
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|
||||||
|
@ -472,7 +473,7 @@ public class CrowdSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
|
public void HandleClick(Vector3 s, Vector3 p, bool shift)
|
||||||
{
|
{
|
||||||
var crowd = _tool.GetCrowd();
|
var crowd = _tool.GetCrowd();
|
||||||
if (crowd == null)
|
if (crowd == null)
|
||||||
|
@ -515,7 +516,7 @@ public class CrowdSampleTool : ISampleTool
|
||||||
if (nav != null && navquery != null)
|
if (nav != null && navquery != null)
|
||||||
{
|
{
|
||||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||||
RcVec3f halfExtents = crowd.GetQueryExtents();
|
Vector3 halfExtents = crowd.GetQueryExtents();
|
||||||
navquery.FindNearestPoly(p, halfExtents, filter, out var refs, out var nearestPt, out var _);
|
navquery.FindNearestPoly(p, halfExtents, filter, out var refs, out var nearestPt, out var _);
|
||||||
if (refs != 0)
|
if (refs != 0)
|
||||||
{
|
{
|
||||||
|
@ -536,7 +537,7 @@ public class CrowdSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift)
|
public void HandleClickRay(Vector3 start, Vector3 direction, bool shift)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,6 +24,7 @@ using System.Threading.Tasks;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Collections;
|
using DotRecast.Core.Collections;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Dynamic;
|
using DotRecast.Detour.Dynamic;
|
||||||
using DotRecast.Recast.Toolset;
|
using DotRecast.Recast.Toolset;
|
||||||
using DotRecast.Recast.Toolset.Tools;
|
using DotRecast.Recast.Toolset.Tools;
|
||||||
|
@ -81,10 +82,10 @@ public class DynamicUpdateSampleTool : ISampleTool
|
||||||
|
|
||||||
private bool sposSet;
|
private bool sposSet;
|
||||||
private bool eposSet;
|
private bool eposSet;
|
||||||
private RcVec3f spos;
|
private Vector3 spos;
|
||||||
private RcVec3f epos;
|
private Vector3 epos;
|
||||||
private bool raycastHit;
|
private bool raycastHit;
|
||||||
private RcVec3f raycastHitPos;
|
private Vector3 raycastHitPos;
|
||||||
|
|
||||||
public DynamicUpdateSampleTool()
|
public DynamicUpdateSampleTool()
|
||||||
{
|
{
|
||||||
|
@ -303,7 +304,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
|
|
||||||
dd.DepthMask(false);
|
dd.DepthMask(false);
|
||||||
if (raycastHitPos != RcVec3f.Zero)
|
if (raycastHitPos != Vector3.Zero)
|
||||||
{
|
{
|
||||||
int spathCol = raycastHit ? DuRGBA(128, 32, 16, 220) : DuRGBA(64, 128, 240, 220);
|
int spathCol = raycastHit ? DuRGBA(128, 32, 16, 220) : DuRGBA(64, 128, 240, 220);
|
||||||
dd.Begin(LINES, 2.0f);
|
dd.Begin(LINES, 2.0f);
|
||||||
|
@ -316,7 +317,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawAgent(RecastDebugDraw dd, RcVec3f pos, int col)
|
private void DrawAgent(RecastDebugDraw dd, Vector3 pos, int col)
|
||||||
{
|
{
|
||||||
var settings = _sample.GetSettings();
|
var settings = _sample.GetSettings();
|
||||||
float r = settings.agentRadius;
|
float r = settings.agentRadius;
|
||||||
|
@ -354,7 +355,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
|
public void HandleClick(Vector3 s, Vector3 p, bool shift)
|
||||||
{
|
{
|
||||||
if (mode == RcDynamicUpdateToolMode.COLLIDERS)
|
if (mode == RcDynamicUpdateToolMode.COLLIDERS)
|
||||||
{
|
{
|
||||||
|
@ -390,7 +391,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void HandleClickRay(RcVec3f start, RcVec3f dir, bool shift)
|
public void HandleClickRay(Vector3 start, Vector3 dir, bool shift)
|
||||||
{
|
{
|
||||||
if (mode == RcDynamicUpdateToolMode.COLLIDERS)
|
if (mode == RcDynamicUpdateToolMode.COLLIDERS)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Collections;
|
using DotRecast.Core.Collections;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Demo.Draw;
|
using DotRecast.Recast.Demo.Draw;
|
||||||
using DotRecast.Recast.Toolset.Gizmos;
|
using DotRecast.Recast.Toolset.Gizmos;
|
||||||
|
|
||||||
|
@ -38,9 +39,9 @@ public static class GizmoRenderer
|
||||||
|
|
||||||
public static int GetColorByNormal(float[] vertices, int v0, int v1, int v2)
|
public static int GetColorByNormal(float[] vertices, int v0, int v1, int v2)
|
||||||
{
|
{
|
||||||
RcVec3f e0 = new RcVec3f();
|
Vector3 e0 = new Vector3();
|
||||||
RcVec3f e1 = new RcVec3f();
|
Vector3 e1 = new Vector3();
|
||||||
RcVec3f normal = new RcVec3f();
|
Vector3 normal = new Vector3();
|
||||||
for (int j = 0; j < 3; ++j)
|
for (int j = 0; j < 3; ++j)
|
||||||
{
|
{
|
||||||
e0 = RcVecUtils.Subtract(vertices, v1, v0);
|
e0 = RcVecUtils.Subtract(vertices, v1, v0);
|
||||||
|
@ -50,7 +51,7 @@ public static class GizmoRenderer
|
||||||
normal.X = e0.Y * e1.Z - e0.Z * e1.Y;
|
normal.X = e0.Y * e1.Z - e0.Z * e1.Y;
|
||||||
normal.Y = e0.Z * e1.X - e0.X * e1.Z;
|
normal.Y = e0.Z * e1.X - e0.X * e1.Z;
|
||||||
normal.Z = e0.X * e1.Y - e0.Y * e1.X;
|
normal.Z = e0.X * e1.Y - e0.Y * e1.X;
|
||||||
normal = RcVec3f.Normalize(normal);
|
normal = Vector3.Normalize(normal);
|
||||||
float c = Math.Clamp(0.57735026f * (normal.X + normal.Y + normal.Z), -1, 1);
|
float c = Math.Clamp(0.57735026f * (normal.X + normal.Y + normal.Z), -1, 1);
|
||||||
int col = DebugDraw.DuLerpCol(
|
int col = DebugDraw.DuLerpCol(
|
||||||
DebugDraw.DuRGBA(32, 32, 0, 160),
|
DebugDraw.DuRGBA(32, 32, 0, 160),
|
||||||
|
@ -62,15 +63,15 @@ public static class GizmoRenderer
|
||||||
|
|
||||||
public static void RenderBox(RecastDebugDraw debugDraw, RcBoxGizmo box)
|
public static void RenderBox(RecastDebugDraw debugDraw, RcBoxGizmo box)
|
||||||
{
|
{
|
||||||
var trX = new RcVec3f(box.halfEdges[0].X, box.halfEdges[1].X, box.halfEdges[2].X);
|
var trX = new Vector3(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 trY = new Vector3(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);
|
var trZ = new Vector3(box.halfEdges[0].Z, box.halfEdges[1].Z, box.halfEdges[2].Z);
|
||||||
float[] vertices = new float[8 * 3];
|
float[] vertices = new float[8 * 3];
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
vertices[i * 3 + 0] = RcVec3f.Dot(RcBoxGizmo.VERTS[i], trX) + box.center.X;
|
vertices[i * 3 + 0] = Vector3.Dot(RcBoxGizmo.VERTS[i], trX) + box.center.X;
|
||||||
vertices[i * 3 + 1] = RcVec3f.Dot(RcBoxGizmo.VERTS[i], trY) + box.center.Y;
|
vertices[i * 3 + 1] = Vector3.Dot(RcBoxGizmo.VERTS[i], trY) + box.center.Y;
|
||||||
vertices[i * 3 + 2] = RcVec3f.Dot(RcBoxGizmo.VERTS[i], trZ) + box.center.Z;
|
vertices[i * 3 + 2] = Vector3.Dot(RcBoxGizmo.VERTS[i], trZ) + box.center.Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Demo.Draw;
|
using DotRecast.Recast.Demo.Draw;
|
||||||
using DotRecast.Recast.Toolset;
|
using DotRecast.Recast.Toolset;
|
||||||
|
|
||||||
|
@ -31,8 +32,8 @@ public interface ISampleTool
|
||||||
|
|
||||||
IRcToolable GetTool();
|
IRcToolable GetTool();
|
||||||
void Layout();
|
void Layout();
|
||||||
void HandleClick(RcVec3f s, RcVec3f p, bool shift);
|
void HandleClick(Vector3 s, Vector3 p, bool shift);
|
||||||
void HandleRender(NavMeshRenderer renderer);
|
void HandleRender(NavMeshRenderer renderer);
|
||||||
void HandleUpdate(float dt);
|
void HandleUpdate(float dt);
|
||||||
void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift);
|
void HandleClickRay(Vector3 start, Vector3 direction, bool shift);
|
||||||
}
|
}
|
|
@ -17,6 +17,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Extras.Jumplink;
|
using DotRecast.Detour.Extras.Jumplink;
|
||||||
using DotRecast.Recast.Demo.Draw;
|
using DotRecast.Recast.Demo.Draw;
|
||||||
using DotRecast.Recast.Toolset;
|
using DotRecast.Recast.Toolset;
|
||||||
|
@ -302,7 +303,7 @@ public class JumpLinkBuilderSampleTool : ISampleTool
|
||||||
{
|
{
|
||||||
GroundSample s = link.start.gsamples[i];
|
GroundSample s = link.start.gsamples[i];
|
||||||
float u = i / (float)(link.start.gsamples.Length - 1);
|
float u = i / (float)(link.start.gsamples.Length - 1);
|
||||||
RcVec3f spt = RcVec3f.Lerp(link.start.p, link.start.q, u);
|
Vector3 spt = Vector3.Lerp(link.start.p, link.start.q, u);
|
||||||
int col = DuRGBA(48, 16, 16, 255); // DuRGBA(255,(s->flags & 4)?255:0,0,255);
|
int col = DuRGBA(48, 16, 16, 255); // DuRGBA(255,(s->flags & 4)?255:0,0,255);
|
||||||
float off = 0.1f;
|
float off = 0.1f;
|
||||||
if (!s.validHeight)
|
if (!s.validHeight)
|
||||||
|
@ -322,7 +323,7 @@ public class JumpLinkBuilderSampleTool : ISampleTool
|
||||||
{
|
{
|
||||||
GroundSample s = link.start.gsamples[i];
|
GroundSample s = link.start.gsamples[i];
|
||||||
float u = i / (float)(link.start.gsamples.Length - 1);
|
float u = i / (float)(link.start.gsamples.Length - 1);
|
||||||
RcVec3f spt = RcVec3f.Lerp(link.start.p, link.start.q, u);
|
Vector3 spt = Vector3.Lerp(link.start.p, link.start.q, u);
|
||||||
int col = DuRGBA(255, 255, 255, 255);
|
int col = DuRGBA(255, 255, 255, 255);
|
||||||
float off = 0;
|
float off = 0;
|
||||||
if (s.validHeight)
|
if (s.validHeight)
|
||||||
|
@ -342,7 +343,7 @@ public class JumpLinkBuilderSampleTool : ISampleTool
|
||||||
{
|
{
|
||||||
GroundSample s = end.gsamples[i];
|
GroundSample s = end.gsamples[i];
|
||||||
float u = i / (float)(end.gsamples.Length - 1);
|
float u = i / (float)(end.gsamples.Length - 1);
|
||||||
RcVec3f spt = RcVec3f.Lerp(end.p, end.q, u);
|
Vector3 spt = Vector3.Lerp(end.p, end.q, u);
|
||||||
int col = DuRGBA(48, 16, 16, 255); // DuRGBA(255,(s->flags & 4)?255:0,0,255);
|
int col = DuRGBA(48, 16, 16, 255); // DuRGBA(255,(s->flags & 4)?255:0,0,255);
|
||||||
float off = 0.1f;
|
float off = 0.1f;
|
||||||
if (!s.validHeight)
|
if (!s.validHeight)
|
||||||
|
@ -361,7 +362,7 @@ public class JumpLinkBuilderSampleTool : ISampleTool
|
||||||
{
|
{
|
||||||
GroundSample s = end.gsamples[i];
|
GroundSample s = end.gsamples[i];
|
||||||
float u = i / (float)(end.gsamples.Length - 1);
|
float u = i / (float)(end.gsamples.Length - 1);
|
||||||
RcVec3f spt = RcVec3f.Lerp(end.p, end.q, u);
|
Vector3 spt = Vector3.Lerp(end.p, end.q, u);
|
||||||
int col = DuRGBA(255, 255, 255, 255);
|
int col = DuRGBA(255, 255, 255, 255);
|
||||||
float off = 0;
|
float off = 0;
|
||||||
if (s.validHeight)
|
if (s.validHeight)
|
||||||
|
@ -399,12 +400,12 @@ public class JumpLinkBuilderSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
|
public void HandleClick(Vector3 s, Vector3 p, bool shift)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void DrawTrajectory(RecastDebugDraw dd, JumpLink link, RcVec3f pa, RcVec3f pb, Trajectory tra, int cola)
|
private void DrawTrajectory(RecastDebugDraw dd, JumpLink link, Vector3 pa, Vector3 pb, Trajectory tra, int cola)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,7 +414,7 @@ public class JumpLinkBuilderSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift)
|
public void HandleClickRay(Vector3 start, Vector3 direction, bool shift)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.TileCache;
|
using DotRecast.Detour.TileCache;
|
||||||
using DotRecast.Detour.TileCache.Io.Compress;
|
using DotRecast.Detour.TileCache.Io.Compress;
|
||||||
using DotRecast.Recast.Demo.Draw;
|
using DotRecast.Recast.Demo.Draw;
|
||||||
|
@ -66,8 +67,8 @@ public class ObstacleSampleTool : ISampleTool
|
||||||
if (ob.state == DtObstacleState.DT_OBSTACLE_EMPTY)
|
if (ob.state == DtObstacleState.DT_OBSTACLE_EMPTY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
RcVec3f bmin = RcVec3f.Zero;
|
Vector3 bmin = Vector3.Zero;
|
||||||
RcVec3f bmax = RcVec3f.Zero;
|
Vector3 bmax = Vector3.Zero;
|
||||||
tc.GetObstacleBounds(ob, ref bmin, ref bmax);
|
tc.GetObstacleBounds(ob, ref bmin, ref bmax);
|
||||||
|
|
||||||
int col = 0;
|
int col = 0;
|
||||||
|
@ -98,7 +99,7 @@ public class ObstacleSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
|
public void HandleClick(Vector3 s, Vector3 p, bool shift)
|
||||||
{
|
{
|
||||||
if (shift)
|
if (shift)
|
||||||
{
|
{
|
||||||
|
@ -118,7 +119,7 @@ public class ObstacleSampleTool : ISampleTool
|
||||||
tc.Update();
|
tc.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift)
|
public void HandleClickRay(Vector3 start, Vector3 direction, bool shift)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Demo.Draw;
|
using DotRecast.Recast.Demo.Draw;
|
||||||
using DotRecast.Recast.Toolset;
|
using DotRecast.Recast.Toolset;
|
||||||
using DotRecast.Recast.Toolset.Geom;
|
using DotRecast.Recast.Toolset.Geom;
|
||||||
|
@ -40,7 +41,7 @@ public class OffMeshConnectionSampleTool : ISampleTool
|
||||||
|
|
||||||
private int _bidir;
|
private int _bidir;
|
||||||
private bool _hasStartPt;
|
private bool _hasStartPt;
|
||||||
private RcVec3f _startPt;
|
private Vector3 _startPt;
|
||||||
|
|
||||||
public OffMeshConnectionSampleTool()
|
public OffMeshConnectionSampleTool()
|
||||||
{
|
{
|
||||||
|
@ -88,7 +89,7 @@ public class OffMeshConnectionSampleTool : ISampleTool
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
|
public void HandleClick(Vector3 s, Vector3 p, bool shift)
|
||||||
{
|
{
|
||||||
DemoInputGeomProvider geom = _sample.GetInputGeom();
|
DemoInputGeomProvider geom = _sample.GetInputGeom();
|
||||||
if (geom == null)
|
if (geom == null)
|
||||||
|
@ -124,7 +125,7 @@ public class OffMeshConnectionSampleTool : ISampleTool
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift)
|
public void HandleClickRay(Vector3 start, Vector3 direction, bool shift)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
using DotRecast.Recast.Demo.Draw;
|
using DotRecast.Recast.Demo.Draw;
|
||||||
|
@ -42,18 +43,18 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
//
|
//
|
||||||
private bool m_sposSet;
|
private bool m_sposSet;
|
||||||
private long m_startRef;
|
private long m_startRef;
|
||||||
private RcVec3f m_spos;
|
private Vector3 m_spos;
|
||||||
|
|
||||||
private bool m_eposSet;
|
private bool m_eposSet;
|
||||||
private long m_endRef;
|
private long m_endRef;
|
||||||
private RcVec3f m_epos;
|
private Vector3 m_epos;
|
||||||
|
|
||||||
private readonly DtQueryDefaultFilter m_filter;
|
private readonly DtQueryDefaultFilter m_filter;
|
||||||
private readonly RcVec3f m_polyPickExt = new RcVec3f(2, 4, 2);
|
private readonly Vector3 m_polyPickExt = new Vector3(2, 4, 2);
|
||||||
|
|
||||||
// for hit
|
// for hit
|
||||||
private RcVec3f m_hitPos;
|
private Vector3 m_hitPos;
|
||||||
private RcVec3f m_hitNormal;
|
private Vector3 m_hitNormal;
|
||||||
private bool m_hitResult;
|
private bool m_hitResult;
|
||||||
|
|
||||||
private float m_distanceToWall;
|
private float m_distanceToWall;
|
||||||
|
@ -61,12 +62,12 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
private List<long> m_polys;
|
private List<long> m_polys;
|
||||||
private List<long> m_parent;
|
private List<long> m_parent;
|
||||||
private float m_neighbourhoodRadius;
|
private float m_neighbourhoodRadius;
|
||||||
private RcVec3f[] m_queryPoly = new RcVec3f[4];
|
private Vector3[] m_queryPoly = new Vector3[4];
|
||||||
private List<RcVec3f> m_smoothPath;
|
private List<Vector3> m_smoothPath;
|
||||||
private DtStatus m_pathFindStatus = DtStatus.DT_FAILURE;
|
private DtStatus m_pathFindStatus = DtStatus.DT_FAILURE;
|
||||||
|
|
||||||
// for mode RANDOM_POINTS_IN_CIRCLE
|
// for mode RANDOM_POINTS_IN_CIRCLE
|
||||||
private List<RcVec3f> _randomPoints = new();
|
private List<Vector3> _randomPoints = new();
|
||||||
|
|
||||||
public TestNavmeshSampleTool()
|
public TestNavmeshSampleTool()
|
||||||
{
|
{
|
||||||
|
@ -383,12 +384,12 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
{
|
{
|
||||||
dd.DebugDrawNavMeshPoly(m_navMesh, m_startRef, startCol);
|
dd.DebugDrawNavMeshPoly(m_navMesh, m_startRef, startCol);
|
||||||
dd.DepthMask(false);
|
dd.DepthMask(false);
|
||||||
if (m_spos != RcVec3f.Zero)
|
if (m_spos != Vector3.Zero)
|
||||||
{
|
{
|
||||||
dd.DebugDrawCircle(m_spos.X, m_spos.Y + agentHeight / 2, m_spos.Z, m_distanceToWall, DuRGBA(64, 16, 0, 220), 2.0f);
|
dd.DebugDrawCircle(m_spos.X, m_spos.Y + agentHeight / 2, m_spos.Z, m_distanceToWall, DuRGBA(64, 16, 0, 220), 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_hitPos != RcVec3f.Zero)
|
if (m_hitPos != Vector3.Zero)
|
||||||
{
|
{
|
||||||
dd.Begin(LINES, 3.0f);
|
dd.Begin(LINES, 3.0f);
|
||||||
dd.Vertex(m_hitPos.X, m_hitPos.Y + 0.02f, m_hitPos.Z, DuRGBA(0, 0, 0, 192));
|
dd.Vertex(m_hitPos.X, m_hitPos.Y + 0.02f, m_hitPos.Z, DuRGBA(0, 0, 0, 192));
|
||||||
|
@ -409,8 +410,8 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
if (m_parent[i] != 0)
|
if (m_parent[i] != 0)
|
||||||
{
|
{
|
||||||
dd.DepthMask(false);
|
dd.DepthMask(false);
|
||||||
RcVec3f p0 = m_navMesh.GetPolyCenter(m_parent[i]);
|
Vector3 p0 = m_navMesh.GetPolyCenter(m_parent[i]);
|
||||||
RcVec3f p1 = m_navMesh.GetPolyCenter(m_polys[i]);
|
Vector3 p1 = m_navMesh.GetPolyCenter(m_polys[i]);
|
||||||
dd.DebugDrawArc(p0.X, p0.Y, p0.Z, p1.X, p1.Y, p1.Z, 0.25f, 0.0f, 0.4f, DuRGBA(0, 0, 0, 128), 2.0f);
|
dd.DebugDrawArc(p0.X, p0.Y, p0.Z, p1.X, p1.Y, p1.Z, 0.25f, 0.0f, 0.4f, DuRGBA(0, 0, 0, 128), 2.0f);
|
||||||
dd.DepthMask(true);
|
dd.DepthMask(true);
|
||||||
}
|
}
|
||||||
|
@ -440,8 +441,8 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
if (m_parent[i] != 0)
|
if (m_parent[i] != 0)
|
||||||
{
|
{
|
||||||
dd.DepthMask(false);
|
dd.DepthMask(false);
|
||||||
RcVec3f p0 = m_navMesh.GetPolyCenter(m_parent[i]);
|
Vector3 p0 = m_navMesh.GetPolyCenter(m_parent[i]);
|
||||||
RcVec3f p1 = m_navMesh.GetPolyCenter(m_polys[i]);
|
Vector3 p1 = m_navMesh.GetPolyCenter(m_polys[i]);
|
||||||
dd.DebugDrawArc(p0.X, p0.Y, p0.Z, p1.X, p1.Y, p1.Z, 0.25f, 0.0f, 0.4f, DuRGBA(0, 0, 0, 128), 2.0f);
|
dd.DebugDrawArc(p0.X, p0.Y, p0.Z, p1.X, p1.Y, p1.Z, 0.25f, 0.0f, 0.4f, DuRGBA(0, 0, 0, 128), 2.0f);
|
||||||
dd.DepthMask(true);
|
dd.DepthMask(true);
|
||||||
}
|
}
|
||||||
|
@ -479,8 +480,8 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
if (m_parent[i] != 0)
|
if (m_parent[i] != 0)
|
||||||
{
|
{
|
||||||
dd.DepthMask(false);
|
dd.DepthMask(false);
|
||||||
RcVec3f p0 = m_navMesh.GetPolyCenter(m_parent[i]);
|
Vector3 p0 = m_navMesh.GetPolyCenter(m_parent[i]);
|
||||||
RcVec3f p1 = m_navMesh.GetPolyCenter(m_polys[i]);
|
Vector3 p1 = m_navMesh.GetPolyCenter(m_polys[i]);
|
||||||
dd.DebugDrawArc(p0.X, p0.Y, p0.Z, p1.X, p1.Y, p1.Z, 0.25f, 0.0f, 0.4f, DuRGBA(0, 0, 0, 128), 2.0f);
|
dd.DebugDrawArc(p0.X, p0.Y, p0.Z, p1.X, p1.Y, p1.Z, 0.25f, 0.0f, 0.4f, DuRGBA(0, 0, 0, 128), 2.0f);
|
||||||
dd.DepthMask(true);
|
dd.DepthMask(true);
|
||||||
}
|
}
|
||||||
|
@ -507,11 +508,11 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f delta = RcVec3f.Subtract(s3, s.vmin);
|
Vector3 delta = Vector3.Subtract(s3, s.vmin);
|
||||||
RcVec3f p0 = RcVecUtils.Mad(s.vmin, delta, 0.5f);
|
Vector3 p0 = RcVecUtils.Mad(s.vmin, delta, 0.5f);
|
||||||
RcVec3f norm = new RcVec3f(delta.Z, 0, -delta.X);
|
Vector3 norm = new Vector3(delta.Z, 0, -delta.X);
|
||||||
norm = RcVec3f.Normalize(norm);
|
norm = Vector3.Normalize(norm);
|
||||||
RcVec3f p1 = RcVecUtils.Mad(p0, norm, agentRadius * 0.5f);
|
Vector3 p1 = RcVecUtils.Mad(p0, norm, agentRadius * 0.5f);
|
||||||
// Skip backfacing segments.
|
// Skip backfacing segments.
|
||||||
if (segmentRefs[j] != 0)
|
if (segmentRefs[j] != 0)
|
||||||
{
|
{
|
||||||
|
@ -555,7 +556,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
dd.DepthMask(false);
|
dd.DepthMask(false);
|
||||||
dd.Begin(POINTS, 4.0f);
|
dd.Begin(POINTS, 4.0f);
|
||||||
int col = DuRGBA(64, 16, 0, 220);
|
int col = DuRGBA(64, 16, 0, 220);
|
||||||
foreach (RcVec3f point in _randomPoints)
|
foreach (Vector3 point in _randomPoints)
|
||||||
{
|
{
|
||||||
dd.Vertex(point.X, point.Y + 0.1f, point.Z, col);
|
dd.Vertex(point.X, point.Y + 0.1f, point.Z, col);
|
||||||
}
|
}
|
||||||
|
@ -575,7 +576,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawAgent(RecastDebugDraw dd, RcVec3f pos, int col)
|
private void DrawAgent(RecastDebugDraw dd, Vector3 pos, int col)
|
||||||
{
|
{
|
||||||
var settings = _sample.GetSettings();
|
var settings = _sample.GetSettings();
|
||||||
float r = settings.agentRadius;
|
float r = settings.agentRadius;
|
||||||
|
@ -613,7 +614,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
|
public void HandleClick(Vector3 s, Vector3 p, bool shift)
|
||||||
{
|
{
|
||||||
if (shift)
|
if (shift)
|
||||||
{
|
{
|
||||||
|
@ -717,7 +718,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift)
|
public void HandleClickRay(Vector3 start, Vector3 direction, bool shift)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Demo.Draw;
|
using DotRecast.Recast.Demo.Draw;
|
||||||
using DotRecast.Recast.Toolset;
|
using DotRecast.Recast.Toolset;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
|
@ -18,7 +19,7 @@ public class TileSampleTool : ISampleTool
|
||||||
private readonly RcTileTool _tool;
|
private readonly RcTileTool _tool;
|
||||||
|
|
||||||
private bool _hitPosSet;
|
private bool _hitPosSet;
|
||||||
private RcVec3f _hitPos;
|
private Vector3 _hitPos;
|
||||||
|
|
||||||
public TileSampleTool()
|
public TileSampleTool()
|
||||||
{
|
{
|
||||||
|
@ -62,8 +63,8 @@ public class TileSampleTool : ISampleTool
|
||||||
int tx = (int)((_hitPos.X - bmin.X) / ts);
|
int tx = (int)((_hitPos.X - bmin.X) / ts);
|
||||||
int ty = (int)((_hitPos.Z - bmin.Z) / ts);
|
int ty = (int)((_hitPos.Z - bmin.Z) / ts);
|
||||||
|
|
||||||
RcVec3f lastBuiltTileBmin = RcVec3f.Zero;
|
Vector3 lastBuiltTileBmin = Vector3.Zero;
|
||||||
RcVec3f lastBuiltTileBmax = RcVec3f.Zero;
|
Vector3 lastBuiltTileBmax = Vector3.Zero;
|
||||||
|
|
||||||
lastBuiltTileBmin.X = bmin.X + tx * ts;
|
lastBuiltTileBmin.X = bmin.X + tx * ts;
|
||||||
lastBuiltTileBmin.Y = bmin.Y;
|
lastBuiltTileBmin.Y = bmin.Y;
|
||||||
|
@ -98,7 +99,7 @@ public class TileSampleTool : ISampleTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
|
public void HandleClick(Vector3 s, Vector3 p, bool shift)
|
||||||
{
|
{
|
||||||
_hitPosSet = true;
|
_hitPosSet = true;
|
||||||
_hitPos = p;
|
_hitPos = p;
|
||||||
|
@ -130,7 +131,7 @@ public class TileSampleTool : ISampleTool
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift)
|
public void HandleClickRay(Vector3 start, Vector3 direction, bool shift)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,59 +0,0 @@
|
||||||
using DotRecast.Core;
|
|
||||||
using ImGuiNET;
|
|
||||||
|
|
||||||
namespace DotRecast.Recast.Demo.UI;
|
|
||||||
|
|
||||||
public class RcMenuView : IRcView
|
|
||||||
{
|
|
||||||
private RcCanvas _canvas;
|
|
||||||
|
|
||||||
public void Bind(RcCanvas canvas)
|
|
||||||
{
|
|
||||||
_canvas = canvas;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsHovered()
|
|
||||||
{
|
|
||||||
//throw new System.NotImplementedException();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(double dt)
|
|
||||||
{
|
|
||||||
//throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Draw(double dt)
|
|
||||||
{
|
|
||||||
if (ImGui.BeginMainMenuBar())
|
|
||||||
{
|
|
||||||
if (ImGui.BeginMenu("Help"))
|
|
||||||
{
|
|
||||||
if (ImGui.MenuItem("Repository"))
|
|
||||||
{
|
|
||||||
RcProcess.OpenUrl("https://github.com/ikpil/DotRecast");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.MenuItem("Nuget"))
|
|
||||||
{
|
|
||||||
RcProcess.OpenUrl("https://www.nuget.org/packages/DotRecast.Core/");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.Separator();
|
|
||||||
if (ImGui.MenuItem("Issue Tracker"))
|
|
||||||
{
|
|
||||||
RcProcess.OpenUrl("https://github.com/ikpil/DotRecast/issues");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.MenuItem("Release Notes"))
|
|
||||||
{
|
|
||||||
RcProcess.OpenUrl("https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndMainMenuBar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,12 +5,11 @@
|
||||||
<PackageId>DotRecast.Recast.Toolset</PackageId>
|
<PackageId>DotRecast.Recast.Toolset</PackageId>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Authors>ikpil</Authors>
|
<Authors>ikpil</Authors>
|
||||||
<Description>DotRecast - a port of Recast Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers</Description>
|
<Description>DotRecast - a port of Recast Detour, navigation mesh toolset for games, Unity3D, servers, C#</Description>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
||||||
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
||||||
<PackageReleaseNotes>https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md</PackageReleaseNotes>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -23,6 +23,7 @@ using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Collections;
|
using DotRecast.Core.Collections;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Toolset.Geom
|
namespace DotRecast.Recast.Toolset.Geom
|
||||||
|
@ -32,8 +33,8 @@ namespace DotRecast.Recast.Toolset.Geom
|
||||||
public readonly float[] vertices;
|
public readonly float[] vertices;
|
||||||
public readonly int[] faces;
|
public readonly int[] faces;
|
||||||
public readonly float[] normals;
|
public readonly float[] normals;
|
||||||
private readonly RcVec3f bmin;
|
private readonly Vector3 bmin;
|
||||||
private readonly RcVec3f bmax;
|
private readonly Vector3 bmax;
|
||||||
|
|
||||||
private readonly List<RcConvexVolume> _convexVolumes = new List<RcConvexVolume>();
|
private readonly List<RcConvexVolume> _convexVolumes = new List<RcConvexVolume>();
|
||||||
private readonly List<RcOffMeshConnection> _offMeshConnections = new List<RcOffMeshConnection>();
|
private readonly List<RcOffMeshConnection> _offMeshConnections = new List<RcOffMeshConnection>();
|
||||||
|
@ -73,12 +74,12 @@ namespace DotRecast.Recast.Toolset.Geom
|
||||||
return _mesh;
|
return _mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f GetMeshBoundsMin()
|
public Vector3 GetMeshBoundsMin()
|
||||||
{
|
{
|
||||||
return bmin;
|
return bmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f GetMeshBoundsMax()
|
public Vector3 GetMeshBoundsMax()
|
||||||
{
|
{
|
||||||
return bmax;
|
return bmax;
|
||||||
}
|
}
|
||||||
|
@ -122,7 +123,7 @@ namespace DotRecast.Recast.Toolset.Geom
|
||||||
return _offMeshConnections;
|
return _offMeshConnections;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddOffMeshConnection(RcVec3f start, RcVec3f end, float radius, bool bidir, int area, int flags)
|
public void AddOffMeshConnection(Vector3 start, Vector3 end, float radius, bool bidir, int area, int flags)
|
||||||
{
|
{
|
||||||
_offMeshConnections.Add(new RcOffMeshConnection(start, end, radius, bidir, area, flags));
|
_offMeshConnections.Add(new RcOffMeshConnection(start, end, radius, bidir, area, flags));
|
||||||
}
|
}
|
||||||
|
@ -133,7 +134,7 @@ namespace DotRecast.Recast.Toolset.Geom
|
||||||
_offMeshConnections.RemoveAll(filter); // TODO : 확인 필요
|
_offMeshConnections.RemoveAll(filter); // TODO : 확인 필요
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RaycastMesh(RcVec3f src, RcVec3f dst, out float tmin)
|
public bool RaycastMesh(Vector3 src, Vector3 dst, out float tmin)
|
||||||
{
|
{
|
||||||
tmin = 1.0f;
|
tmin = 1.0f;
|
||||||
|
|
||||||
|
@ -143,8 +144,8 @@ namespace DotRecast.Recast.Toolset.Geom
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var p = new RcVec2f();
|
var p = new Vector2();
|
||||||
var q = new RcVec2f();
|
var q = new Vector2();
|
||||||
p.X = src.X + (dst.X - src.X) * btmin;
|
p.X = src.X + (dst.X - src.X) * btmin;
|
||||||
p.Y = src.Z + (dst.Z - src.Z) * btmin;
|
p.Y = src.Z + (dst.Z - src.Z) * btmin;
|
||||||
q.X = src.X + (dst.X - src.X) * btmax;
|
q.X = src.X + (dst.X - src.X) * btmax;
|
||||||
|
@ -163,17 +164,17 @@ namespace DotRecast.Recast.Toolset.Geom
|
||||||
int[] tris = chunk.tris;
|
int[] tris = chunk.tris;
|
||||||
for (int j = 0; j < chunk.tris.Length; j += 3)
|
for (int j = 0; j < chunk.tris.Length; j += 3)
|
||||||
{
|
{
|
||||||
RcVec3f v1 = new RcVec3f(
|
Vector3 v1 = new Vector3(
|
||||||
vertices[tris[j] * 3],
|
vertices[tris[j] * 3],
|
||||||
vertices[tris[j] * 3 + 1],
|
vertices[tris[j] * 3 + 1],
|
||||||
vertices[tris[j] * 3 + 2]
|
vertices[tris[j] * 3 + 2]
|
||||||
);
|
);
|
||||||
RcVec3f v2 = new RcVec3f(
|
Vector3 v2 = new Vector3(
|
||||||
vertices[tris[j + 1] * 3],
|
vertices[tris[j + 1] * 3],
|
||||||
vertices[tris[j + 1] * 3 + 1],
|
vertices[tris[j + 1] * 3 + 1],
|
||||||
vertices[tris[j + 1] * 3 + 2]
|
vertices[tris[j + 1] * 3 + 2]
|
||||||
);
|
);
|
||||||
RcVec3f v3 = new RcVec3f(
|
Vector3 v3 = new Vector3(
|
||||||
vertices[tris[j + 2] * 3],
|
vertices[tris[j + 2] * 3],
|
||||||
vertices[tris[j + 2] * 3 + 1],
|
vertices[tris[j + 2] * 3 + 1],
|
||||||
vertices[tris[j + 2] * 3 + 2]
|
vertices[tris[j + 2] * 3 + 2]
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Dynamic.Colliders;
|
using DotRecast.Detour.Dynamic.Colliders;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Toolset.Gizmos
|
namespace DotRecast.Recast.Toolset.Gizmos
|
||||||
|
@ -11,28 +12,28 @@ namespace DotRecast.Recast.Toolset.Gizmos
|
||||||
2, 6, 7, 2, 7, 3, 4, 0, 3, 4, 3, 7
|
2, 6, 7, 2, 7, 3, 4, 0, 3, 4, 3, 7
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly RcVec3f[] VERTS =
|
public static readonly Vector3[] VERTS =
|
||||||
{
|
{
|
||||||
new RcVec3f(-1f, -1f, -1f),
|
new Vector3(-1f, -1f, -1f),
|
||||||
new RcVec3f(1f, -1f, -1f),
|
new Vector3(1f, -1f, -1f),
|
||||||
new RcVec3f(1f, -1f, 1f),
|
new Vector3(1f, -1f, 1f),
|
||||||
new RcVec3f(-1f, -1f, 1f),
|
new Vector3(-1f, -1f, 1f),
|
||||||
new RcVec3f(-1f, 1f, -1f),
|
new Vector3(-1f, 1f, -1f),
|
||||||
new RcVec3f(1f, 1f, -1f),
|
new Vector3(1f, 1f, -1f),
|
||||||
new RcVec3f(1f, 1f, 1f),
|
new Vector3(1f, 1f, 1f),
|
||||||
new RcVec3f(-1f, 1f, 1f),
|
new Vector3(-1f, 1f, 1f),
|
||||||
};
|
};
|
||||||
|
|
||||||
public readonly float[] vertices = new float[8 * 3];
|
public readonly float[] vertices = new float[8 * 3];
|
||||||
public readonly RcVec3f center;
|
public readonly Vector3 center;
|
||||||
public readonly RcVec3f[] halfEdges;
|
public readonly Vector3[] halfEdges;
|
||||||
|
|
||||||
public RcBoxGizmo(RcVec3f center, RcVec3f extent, RcVec3f forward, RcVec3f up) :
|
public RcBoxGizmo(Vector3 center, Vector3 extent, Vector3 forward, Vector3 up) :
|
||||||
this(center, DtBoxCollider.GetHalfEdges(up, forward, extent))
|
this(center, DtBoxCollider.GetHalfEdges(up, forward, extent))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcBoxGizmo(RcVec3f center, RcVec3f[] halfEdges)
|
public RcBoxGizmo(Vector3 center, Vector3[] halfEdges)
|
||||||
{
|
{
|
||||||
this.center = center;
|
this.center = center;
|
||||||
this.halfEdges = halfEdges;
|
this.halfEdges = halfEdges;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using static DotRecast.Recast.Toolset.Gizmos.RcGizmoHelper;
|
using static DotRecast.Recast.Toolset.Gizmos.RcGizmoHelper;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Toolset.Gizmos
|
namespace DotRecast.Recast.Toolset.Gizmos
|
||||||
|
@ -11,30 +12,30 @@ namespace DotRecast.Recast.Toolset.Gizmos
|
||||||
public readonly float[] center;
|
public readonly float[] center;
|
||||||
public readonly float[] gradient;
|
public readonly float[] gradient;
|
||||||
|
|
||||||
public RcCapsuleGizmo(RcVec3f start, RcVec3f end, float radius)
|
public RcCapsuleGizmo(Vector3 start, Vector3 end, float radius)
|
||||||
{
|
{
|
||||||
center = new float[]
|
center = new float[]
|
||||||
{
|
{
|
||||||
0.5f * (start.X + end.X), 0.5f * (start.Y + end.Y),
|
0.5f * (start.X + end.X), 0.5f * (start.Y + end.Y),
|
||||||
0.5f * (start.Z + end.Z)
|
0.5f * (start.Z + end.Z)
|
||||||
};
|
};
|
||||||
RcVec3f axis = new RcVec3f(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
Vector3 axis = new Vector3(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
||||||
RcVec3f[] normals = new RcVec3f[3];
|
Vector3[] normals = new Vector3[3];
|
||||||
normals[1] = new RcVec3f(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
normals[1] = new Vector3(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
||||||
normals[1] = RcVec3f.Normalize(normals[1]);
|
normals[1] = Vector3.Normalize(normals[1]);
|
||||||
normals[0] = GetSideVector(axis);
|
normals[0] = GetSideVector(axis);
|
||||||
normals[2] = RcVec3f.Zero;
|
normals[2] = Vector3.Zero;
|
||||||
normals[2] = RcVec3f.Cross(normals[0], normals[1]);
|
normals[2] = Vector3.Cross(normals[0], normals[1]);
|
||||||
normals[2] = RcVec3f.Normalize(normals[2]);
|
normals[2] = Vector3.Normalize(normals[2]);
|
||||||
triangles = GenerateSphericalTriangles();
|
triangles = GenerateSphericalTriangles();
|
||||||
var trX = new RcVec3f(normals[0].X, normals[1].X, normals[2].X);
|
var trX = new Vector3(normals[0].X, normals[1].X, normals[2].X);
|
||||||
var trY = new RcVec3f(normals[0].Y, normals[1].Y, normals[2].Y);
|
var trY = new Vector3(normals[0].Y, normals[1].Y, normals[2].Y);
|
||||||
var trZ = new RcVec3f(normals[0].Z, normals[1].Z, normals[2].Z);
|
var trZ = new Vector3(normals[0].Z, normals[1].Z, normals[2].Z);
|
||||||
float[] spVertices = GenerateSphericalVertices();
|
float[] spVertices = GenerateSphericalVertices();
|
||||||
float halfLength = 0.5f * axis.Length();
|
float halfLength = 0.5f * axis.Length();
|
||||||
vertices = new float[spVertices.Length];
|
vertices = new float[spVertices.Length];
|
||||||
gradient = new float[spVertices.Length / 3];
|
gradient = new float[spVertices.Length / 3];
|
||||||
RcVec3f v = new RcVec3f();
|
Vector3 v = new Vector3();
|
||||||
for (int i = 0; i < spVertices.Length; i += 3)
|
for (int i = 0; i < spVertices.Length; i += 3)
|
||||||
{
|
{
|
||||||
float offset = (i >= spVertices.Length / 2) ? -halfLength : halfLength;
|
float offset = (i >= spVertices.Length / 2) ? -halfLength : halfLength;
|
||||||
|
@ -47,22 +48,22 @@ namespace DotRecast.Recast.Toolset.Gizmos
|
||||||
v.X = vertices[i] - center[0];
|
v.X = vertices[i] - center[0];
|
||||||
v.Y = vertices[i + 1] - center[1];
|
v.Y = vertices[i + 1] - center[1];
|
||||||
v.Z = vertices[i + 2] - center[2];
|
v.Z = vertices[i + 2] - center[2];
|
||||||
v = RcVec3f.Normalize(v);
|
v = Vector3.Normalize(v);
|
||||||
gradient[i / 3] = Math.Clamp(0.57735026f * (v.X + v.Y + v.Z), -1, 1);
|
gradient[i / 3] = Math.Clamp(0.57735026f * (v.X + v.Y + v.Z), -1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RcVec3f GetSideVector(RcVec3f axis)
|
private Vector3 GetSideVector(Vector3 axis)
|
||||||
{
|
{
|
||||||
var side = new RcVec3f(1, 0, 0);
|
var side = new Vector3(1, 0, 0);
|
||||||
if (axis.X > 0.8)
|
if (axis.X > 0.8)
|
||||||
{
|
{
|
||||||
side = new RcVec3f(0, 0, 1);
|
side = new Vector3(0, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var forward = RcVec3f.Cross(side, axis);
|
var forward = Vector3.Cross(side, axis);
|
||||||
side = RcVec3f.Cross(axis, forward);
|
side = Vector3.Cross(axis, forward);
|
||||||
side = RcVec3f.Normalize(side);
|
side = Vector3.Normalize(side);
|
||||||
return side;
|
return side;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using static DotRecast.Recast.Toolset.Gizmos.RcGizmoHelper;
|
using static DotRecast.Recast.Toolset.Gizmos.RcGizmoHelper;
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,31 +10,31 @@ namespace DotRecast.Recast.Toolset.Gizmos
|
||||||
{
|
{
|
||||||
public readonly float[] vertices;
|
public readonly float[] vertices;
|
||||||
public readonly int[] triangles;
|
public readonly int[] triangles;
|
||||||
public readonly RcVec3f center;
|
public readonly Vector3 center;
|
||||||
public readonly float[] gradient;
|
public readonly float[] gradient;
|
||||||
|
|
||||||
public RcCylinderGizmo(RcVec3f start, RcVec3f end, float radius)
|
public RcCylinderGizmo(Vector3 start, Vector3 end, float radius)
|
||||||
{
|
{
|
||||||
center = new RcVec3f(
|
center = new Vector3(
|
||||||
0.5f * (start.X + end.X), 0.5f * (start.Y + end.Y),
|
0.5f * (start.X + end.X), 0.5f * (start.Y + end.Y),
|
||||||
0.5f * (start.Z + end.Z)
|
0.5f * (start.Z + end.Z)
|
||||||
);
|
);
|
||||||
RcVec3f axis = new RcVec3f(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
Vector3 axis = new Vector3(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
||||||
RcVec3f[] normals = new RcVec3f[3];
|
Vector3[] normals = new Vector3[3];
|
||||||
normals[1] = new RcVec3f(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
normals[1] = new Vector3(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
||||||
normals[1] = RcVec3f.Normalize(normals[1]);
|
normals[1] = Vector3.Normalize(normals[1]);
|
||||||
normals[0] = GetSideVector(axis);
|
normals[0] = GetSideVector(axis);
|
||||||
normals[2] = RcVec3f.Zero;
|
normals[2] = Vector3.Zero;
|
||||||
normals[2] = RcVec3f.Cross(normals[0], normals[1]);
|
normals[2] = Vector3.Cross(normals[0], normals[1]);
|
||||||
normals[2] = RcVec3f.Normalize(normals[2]);
|
normals[2] = Vector3.Normalize(normals[2]);
|
||||||
triangles = GenerateCylindricalTriangles();
|
triangles = GenerateCylindricalTriangles();
|
||||||
RcVec3f trX = new RcVec3f(normals[0].X, normals[1].X, normals[2].X);
|
Vector3 trX = new Vector3(normals[0].X, normals[1].X, normals[2].X);
|
||||||
RcVec3f trY = new RcVec3f(normals[0].Y, normals[1].Y, normals[2].Y);
|
Vector3 trY = new Vector3(normals[0].Y, normals[1].Y, normals[2].Y);
|
||||||
RcVec3f trZ = new RcVec3f(normals[0].Z, normals[1].Z, normals[2].Z);
|
Vector3 trZ = new Vector3(normals[0].Z, normals[1].Z, normals[2].Z);
|
||||||
vertices = GenerateCylindricalVertices();
|
vertices = GenerateCylindricalVertices();
|
||||||
float halfLength = 0.5f * axis.Length();
|
float halfLength = 0.5f * axis.Length();
|
||||||
gradient = new float[vertices.Length / 3];
|
gradient = new float[vertices.Length / 3];
|
||||||
RcVec3f v = new RcVec3f();
|
Vector3 v = new Vector3();
|
||||||
for (int i = 0; i < vertices.Length; i += 3)
|
for (int i = 0; i < vertices.Length; i += 3)
|
||||||
{
|
{
|
||||||
float offset = (i >= vertices.Length / 2) ? -halfLength : halfLength;
|
float offset = (i >= vertices.Length / 2) ? -halfLength : halfLength;
|
||||||
|
@ -52,23 +53,23 @@ namespace DotRecast.Recast.Toolset.Gizmos
|
||||||
v.X = vertices[i] - center.X;
|
v.X = vertices[i] - center.X;
|
||||||
v.Y = vertices[i + 1] - center.Y;
|
v.Y = vertices[i + 1] - center.Y;
|
||||||
v.Z = vertices[i + 2] - center.Z;
|
v.Z = vertices[i + 2] - center.Z;
|
||||||
v = RcVec3f.Normalize(v);
|
v = Vector3.Normalize(v);
|
||||||
gradient[i / 3] = Math.Clamp(0.57735026f * (v.X + v.Y + v.Z), -1, 1);
|
gradient[i / 3] = Math.Clamp(0.57735026f * (v.X + v.Y + v.Z), -1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RcVec3f GetSideVector(RcVec3f axis)
|
private Vector3 GetSideVector(Vector3 axis)
|
||||||
{
|
{
|
||||||
RcVec3f side = new RcVec3f(1, 0, 0);
|
Vector3 side = new Vector3(1, 0, 0);
|
||||||
if (axis.X > 0.8)
|
if (axis.X > 0.8)
|
||||||
{
|
{
|
||||||
side = new RcVec3f(0, 0, 1);
|
side = new Vector3(0, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var forward = RcVec3f.Cross(side, axis);
|
var forward = Vector3.Cross(side, axis);
|
||||||
side = RcVec3f.Cross(axis, forward);
|
side = Vector3.Cross(axis, forward);
|
||||||
side = RcVec3f.Normalize(side);
|
side = Vector3.Normalize(side);
|
||||||
return side;
|
return side;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,26 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Toolset.Gizmos
|
namespace DotRecast.Recast.Toolset.Gizmos
|
||||||
{
|
{
|
||||||
public static class RcGizmoFactory
|
public static class RcGizmoFactory
|
||||||
{
|
{
|
||||||
public static RcBoxGizmo Box(RcVec3f center, RcVec3f[] halfEdges)
|
public static RcBoxGizmo Box(Vector3 center, Vector3[] halfEdges)
|
||||||
{
|
{
|
||||||
return new RcBoxGizmo(center, halfEdges);
|
return new RcBoxGizmo(center, halfEdges);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RcSphereGizmo Sphere(RcVec3f center, float radius)
|
public static RcSphereGizmo Sphere(Vector3 center, float radius)
|
||||||
{
|
{
|
||||||
return new RcSphereGizmo(center, radius);
|
return new RcSphereGizmo(center, radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RcCapsuleGizmo Capsule(RcVec3f start, RcVec3f end, float radius)
|
public static RcCapsuleGizmo Capsule(Vector3 start, Vector3 end, float radius)
|
||||||
{
|
{
|
||||||
return new RcCapsuleGizmo(start, end, radius);
|
return new RcCapsuleGizmo(start, end, radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RcCylinderGizmo Cylinder(RcVec3f start, RcVec3f end, float radius)
|
public static RcCylinderGizmo Cylinder(Vector3 start, Vector3 end, float radius)
|
||||||
{
|
{
|
||||||
return new RcCylinderGizmo(start, end, radius);
|
return new RcCylinderGizmo(start, end, radius);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using static DotRecast.Recast.Toolset.Gizmos.RcGizmoHelper;
|
using static DotRecast.Recast.Toolset.Gizmos.RcGizmoHelper;
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,9 +10,9 @@ namespace DotRecast.Recast.Toolset.Gizmos
|
||||||
public readonly float[] vertices;
|
public readonly float[] vertices;
|
||||||
public readonly int[] triangles;
|
public readonly int[] triangles;
|
||||||
public readonly float radius;
|
public readonly float radius;
|
||||||
public readonly RcVec3f center;
|
public readonly Vector3 center;
|
||||||
|
|
||||||
public RcSphereGizmo(RcVec3f center, float radius)
|
public RcSphereGizmo(Vector3 center, float radius)
|
||||||
{
|
{
|
||||||
this.center = center;
|
this.center = center;
|
||||||
this.radius = radius;
|
this.radius = radius;
|
||||||
|
|
|
@ -2,18 +2,19 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Toolset.Tools
|
namespace DotRecast.Recast.Toolset.Tools
|
||||||
{
|
{
|
||||||
public class RcConvexVolumeTool : IRcToolable
|
public class RcConvexVolumeTool : IRcToolable
|
||||||
{
|
{
|
||||||
private readonly List<RcVec3f> _pts;
|
private readonly List<Vector3> _pts;
|
||||||
private readonly List<int> _hull;
|
private readonly List<int> _hull;
|
||||||
|
|
||||||
public RcConvexVolumeTool()
|
public RcConvexVolumeTool()
|
||||||
{
|
{
|
||||||
_pts = new List<RcVec3f>();
|
_pts = new List<Vector3>();
|
||||||
_hull = new List<int>();
|
_hull = new List<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return "Convex Volumes";
|
return "Convex Volumes";
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RcVec3f> GetShapePoint()
|
public List<Vector3> GetShapePoint()
|
||||||
{
|
{
|
||||||
return _pts;
|
return _pts;
|
||||||
}
|
}
|
||||||
|
@ -38,16 +39,16 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
_hull.Clear();
|
_hull.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool PlottingShape(RcVec3f p, out List<RcVec3f> pts, out List<int> hull)
|
public bool PlottingShape(Vector3 p, out List<Vector3> pts, out List<int> hull)
|
||||||
{
|
{
|
||||||
pts = null;
|
pts = null;
|
||||||
hull = null;
|
hull = null;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
// If clicked on that last pt, create the shape.
|
// If clicked on that last pt, create the shape.
|
||||||
if (_pts.Count > 0 && RcVec3f.DistanceSquared(p, _pts[_pts.Count - 1]) < 0.2f * 0.2f)
|
if (_pts.Count > 0 && Vector3.DistanceSquared(p, _pts[_pts.Count - 1]) < 0.2f * 0.2f)
|
||||||
{
|
{
|
||||||
pts = new List<RcVec3f>(_pts);
|
pts = new List<Vector3>(_pts);
|
||||||
hull = new List<int>(_hull);
|
hull = new List<int>(_hull);
|
||||||
|
|
||||||
_pts.Clear();
|
_pts.Clear();
|
||||||
|
@ -74,7 +75,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool TryRemove(IInputGeomProvider geom, RcVec3f pos, out RcConvexVolume volume)
|
public RcConvexVolume RemoveByPos(IInputGeomProvider geom, Vector3 pos)
|
||||||
{
|
{
|
||||||
// Delete
|
// Delete
|
||||||
int nearestIndex = -1;
|
int nearestIndex = -1;
|
||||||
|
@ -90,57 +91,26 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
|
|
||||||
// If end point close enough, delete it.
|
// If end point close enough, delete it.
|
||||||
if (nearestIndex == -1)
|
if (nearestIndex == -1)
|
||||||
{
|
return null;
|
||||||
volume = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var removal = geom.ConvexVolumes()[nearestIndex];
|
var removal = geom.ConvexVolumes()[nearestIndex];
|
||||||
geom.ConvexVolumes().RemoveAt(nearestIndex);
|
geom.ConvexVolumes().RemoveAt(nearestIndex);
|
||||||
volume = removal;
|
return removal;
|
||||||
return null != volume;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAdd(IInputGeomProvider geom, RcVec3f p, RcAreaModification areaType, float boxDescent, float boxHeight, float polyOffset, out RcConvexVolume volume)
|
public void Add(IInputGeomProvider geom, RcConvexVolume volume)
|
||||||
{
|
{
|
||||||
// Create
|
geom.AddConvexVolume(volume);
|
||||||
|
|
||||||
// If clicked on that last pt, create the shape.
|
|
||||||
if (_pts.Count > 0 && RcVec3f.DistanceSquared(p, _pts[^1]) < 0.2f * 0.2f)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
if (_hull.Count > 2)
|
|
||||||
{
|
|
||||||
volume = CreateConvexVolume(_pts, _hull, areaType, boxDescent, boxHeight, polyOffset);
|
|
||||||
geom.AddConvexVolume(volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
_pts.Clear();
|
|
||||||
_hull.Clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Add new point
|
|
||||||
_pts.Add(p);
|
|
||||||
|
|
||||||
// Update hull.
|
|
||||||
if (_pts.Count > 1)
|
|
||||||
{
|
|
||||||
_hull.Clear();
|
|
||||||
_hull.AddRange(RcConvexUtils.Convexhull(_pts));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_hull.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
volume = null;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RcConvexVolume CreateConvexVolume(List<RcVec3f> pts, List<int> hull, RcAreaModification areaType, float boxDescent, float boxHeight, float polyOffset)
|
public static RcConvexVolume CreateConvexVolume(List<Vector3> pts, List<int> hull, RcAreaModification areaType, float boxDescent, float boxHeight, float polyOffset)
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
if (hull.Count <= 2)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Create shape.
|
// Create shape.
|
||||||
float[] verts = new float[hull.Count * 3];
|
float[] verts = new float[hull.Count * 3];
|
||||||
for (int i = 0; i < hull.Count; ++i)
|
for (int i = 0; i < hull.Count; ++i)
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Toolset.Tools
|
namespace DotRecast.Recast.Toolset.Tools
|
||||||
{
|
{
|
||||||
public class RcCrowdAgentData
|
public class RcCrowdAgentData
|
||||||
{
|
{
|
||||||
public readonly RcCrowdAgentType type;
|
public readonly RcCrowdAgentType type;
|
||||||
public readonly RcVec3f home = new RcVec3f();
|
public readonly Vector3 home = new Vector3();
|
||||||
|
|
||||||
public RcCrowdAgentData(RcCrowdAgentType type, RcVec3f home)
|
public RcCrowdAgentData(RcCrowdAgentType type, Vector3 home)
|
||||||
{
|
{
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.home = home;
|
this.home = home;
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Numerics;
|
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Buffers;
|
|
||||||
using DotRecast.Core.Collections;
|
using DotRecast.Core.Collections;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
using DotRecast.Detour.Crowd;
|
using DotRecast.Detour.Crowd;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
|
@ -17,28 +15,20 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
private RcCrowdAgentProfilingToolConfig _cfg;
|
private RcCrowdAgentProfilingToolConfig _cfg;
|
||||||
|
|
||||||
private DtCrowdConfig _crowdCfg;
|
private DtCrowdConfig _crowdCfg;
|
||||||
private DtCrowd _crowd;
|
private DtCrowd crowd;
|
||||||
private readonly DtCrowdAgentConfig _agCfg;
|
private readonly DtCrowdAgentConfig _agCfg;
|
||||||
|
|
||||||
private DtNavMesh _navMesh;
|
private DtNavMesh navMesh;
|
||||||
|
|
||||||
private IRcRand _rand;
|
private RcRand rnd;
|
||||||
private readonly List<DtPolyPoint> _polyPoints;
|
private readonly List<DtPolyPoint> _polyPoints;
|
||||||
|
private long crowdUpdateTime;
|
||||||
private const int SamplingCount = 500;
|
|
||||||
private long _samplingUpdateTime;
|
|
||||||
private readonly RcCyclicBuffer<long> _updateTimes;
|
|
||||||
private long _curUpdateTime;
|
|
||||||
private long _avgUpdateTime;
|
|
||||||
private long _minUpdateTime;
|
|
||||||
private long _maxUpdateTime;
|
|
||||||
|
|
||||||
public RcCrowdAgentProfilingTool()
|
public RcCrowdAgentProfilingTool()
|
||||||
{
|
{
|
||||||
_cfg = new RcCrowdAgentProfilingToolConfig();
|
_cfg = new RcCrowdAgentProfilingToolConfig();
|
||||||
_agCfg = new DtCrowdAgentConfig();
|
_agCfg = new DtCrowdAgentConfig();
|
||||||
_polyPoints = new List<DtPolyPoint>();
|
_polyPoints = new List<DtPolyPoint>();
|
||||||
_updateTimes = new RcCyclicBuffer<long>(SamplingCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetName()
|
public string GetName()
|
||||||
|
@ -58,12 +48,12 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
|
|
||||||
public DtCrowd GetCrowd()
|
public DtCrowd GetCrowd()
|
||||||
{
|
{
|
||||||
return _crowd;
|
return crowd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Setup(float maxAgentRadius, DtNavMesh nav)
|
public void Setup(float maxAgentRadius, DtNavMesh nav)
|
||||||
{
|
{
|
||||||
_navMesh = nav;
|
navMesh = nav;
|
||||||
if (nav != null)
|
if (nav != null)
|
||||||
{
|
{
|
||||||
_crowdCfg = new DtCrowdConfig(maxAgentRadius);
|
_crowdCfg = new DtCrowdConfig(maxAgentRadius);
|
||||||
|
@ -85,20 +75,20 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return ap;
|
return ap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DtStatus GetMobPosition(DtNavMeshQuery navquery, IDtQueryFilter filter, out RcVec3f randomPt)
|
private DtStatus GetMobPosition(DtNavMeshQuery navquery, IDtQueryFilter filter, out Vector3 randomPt)
|
||||||
{
|
{
|
||||||
return navquery.FindRandomPoint(filter, _rand, out var randomRef, out randomPt);
|
return navquery.FindRandomPoint(filter, rnd, out var randomRef, out randomPt);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DtStatus GetVillagerPosition(DtNavMeshQuery navquery, IDtQueryFilter filter, out RcVec3f randomPt)
|
private DtStatus GetVillagerPosition(DtNavMeshQuery navquery, IDtQueryFilter filter, out Vector3 randomPt)
|
||||||
{
|
{
|
||||||
randomPt = RcVec3f.Zero;
|
randomPt = Vector3.Zero;
|
||||||
|
|
||||||
if (0 >= _polyPoints.Count)
|
if (0 >= _polyPoints.Count)
|
||||||
return DtStatus.DT_FAILURE;
|
return DtStatus.DT_FAILURE;
|
||||||
|
|
||||||
int zone = (int)(_rand.Next() * _polyPoints.Count);
|
int zone = (int)(rnd.Next() * _polyPoints.Count);
|
||||||
return navquery.FindRandomPointWithinCircle(_polyPoints[zone].refs, _polyPoints[zone].pt, _cfg.zoneRadius, filter, _rand,
|
return navquery.FindRandomPointWithinCircle(_polyPoints[zone].refs, _polyPoints[zone].pt, _cfg.zoneRadius, filter, rnd,
|
||||||
out var randomRef, out randomPt);
|
out var randomRef, out randomPt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,19 +96,19 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
{
|
{
|
||||||
_polyPoints.Clear();
|
_polyPoints.Clear();
|
||||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||||
DtNavMeshQuery navquery = new DtNavMeshQuery(_navMesh);
|
DtNavMeshQuery navquery = new DtNavMeshQuery(navMesh);
|
||||||
for (int i = 0; i < _cfg.numberOfZones; i++)
|
for (int i = 0; i < _cfg.numberOfZones; i++)
|
||||||
{
|
{
|
||||||
float zoneSeparation = _cfg.zoneRadius * _cfg.zoneRadius * 16;
|
float zoneSeparation = _cfg.zoneRadius * _cfg.zoneRadius * 16;
|
||||||
for (int k = 0; k < 100; k++)
|
for (int k = 0; k < 100; k++)
|
||||||
{
|
{
|
||||||
var status = navquery.FindRandomPoint(filter, _rand, out var randomRef, out var randomPt);
|
var status = navquery.FindRandomPoint(filter, rnd, out var randomRef, out var randomPt);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
foreach (var zone in _polyPoints)
|
foreach (var zone in _polyPoints)
|
||||||
{
|
{
|
||||||
if (RcVec3f.DistanceSquared(zone.pt, randomPt) < zoneSeparation)
|
if (Vector3.DistanceSquared(zone.pt, randomPt) < zoneSeparation)
|
||||||
{
|
{
|
||||||
valid = false;
|
valid = false;
|
||||||
break;
|
break;
|
||||||
|
@ -137,65 +127,57 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
|
|
||||||
private void CreateCrowd()
|
private void CreateCrowd()
|
||||||
{
|
{
|
||||||
_crowd = new DtCrowd(_crowdCfg, _navMesh, __ => new DtQueryDefaultFilter(
|
crowd = new DtCrowd(_crowdCfg, navMesh, __ => new DtQueryDefaultFilter(
|
||||||
SampleAreaModifications.SAMPLE_POLYFLAGS_ALL,
|
SampleAreaModifications.SAMPLE_POLYFLAGS_ALL,
|
||||||
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED,
|
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED,
|
||||||
new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f })
|
new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f })
|
||||||
);
|
);
|
||||||
|
|
||||||
DtObstacleAvoidanceParams option = new DtObstacleAvoidanceParams(_crowd.GetObstacleAvoidanceParams(0));
|
DtObstacleAvoidanceParams option = new DtObstacleAvoidanceParams(crowd.GetObstacleAvoidanceParams(0));
|
||||||
// Low (11)
|
// Low (11)
|
||||||
option.velBias = 0.5f;
|
option.velBias = 0.5f;
|
||||||
option.adaptiveDivs = 5;
|
option.adaptiveDivs = 5;
|
||||||
option.adaptiveRings = 2;
|
option.adaptiveRings = 2;
|
||||||
option.adaptiveDepth = 1;
|
option.adaptiveDepth = 1;
|
||||||
_crowd.SetObstacleAvoidanceParams(0, option);
|
crowd.SetObstacleAvoidanceParams(0, option);
|
||||||
// Medium (22)
|
// Medium (22)
|
||||||
option.velBias = 0.5f;
|
option.velBias = 0.5f;
|
||||||
option.adaptiveDivs = 5;
|
option.adaptiveDivs = 5;
|
||||||
option.adaptiveRings = 2;
|
option.adaptiveRings = 2;
|
||||||
option.adaptiveDepth = 2;
|
option.adaptiveDepth = 2;
|
||||||
_crowd.SetObstacleAvoidanceParams(1, option);
|
crowd.SetObstacleAvoidanceParams(1, option);
|
||||||
// Good (45)
|
// Good (45)
|
||||||
option.velBias = 0.5f;
|
option.velBias = 0.5f;
|
||||||
option.adaptiveDivs = 7;
|
option.adaptiveDivs = 7;
|
||||||
option.adaptiveRings = 2;
|
option.adaptiveRings = 2;
|
||||||
option.adaptiveDepth = 3;
|
option.adaptiveDepth = 3;
|
||||||
_crowd.SetObstacleAvoidanceParams(2, option);
|
crowd.SetObstacleAvoidanceParams(2, option);
|
||||||
// High (66)
|
// High (66)
|
||||||
option.velBias = 0.5f;
|
option.velBias = 0.5f;
|
||||||
option.adaptiveDivs = 7;
|
option.adaptiveDivs = 7;
|
||||||
option.adaptiveRings = 3;
|
option.adaptiveRings = 3;
|
||||||
option.adaptiveDepth = 3;
|
option.adaptiveDepth = 3;
|
||||||
_crowd.SetObstacleAvoidanceParams(3, option);
|
crowd.SetObstacleAvoidanceParams(3, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartProfiling(float agentRadius, float agentHeight, float agentMaxAcceleration, float agentMaxSpeed)
|
public void StartProfiling(float agentRadius, float agentHeight, float agentMaxAcceleration, float agentMaxSpeed)
|
||||||
{
|
{
|
||||||
if (null == _navMesh)
|
if (null == navMesh)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// for benchmark
|
rnd = new RcRand(_cfg.randomSeed);
|
||||||
_updateTimes.Clear();
|
|
||||||
_samplingUpdateTime = 0;
|
|
||||||
_curUpdateTime = 0;
|
|
||||||
_avgUpdateTime = 0;
|
|
||||||
_minUpdateTime = 0;
|
|
||||||
_maxUpdateTime = 0;
|
|
||||||
|
|
||||||
_rand = new RcRand(_cfg.randomSeed);
|
|
||||||
CreateCrowd();
|
CreateCrowd();
|
||||||
CreateZones();
|
CreateZones();
|
||||||
DtNavMeshQuery navquery = new DtNavMeshQuery(_navMesh);
|
DtNavMeshQuery navquery = new DtNavMeshQuery(navMesh);
|
||||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||||
for (int i = 0; i < _cfg.agents; i++)
|
for (int i = 0; i < _cfg.agents; i++)
|
||||||
{
|
{
|
||||||
float tr = _rand.Next();
|
float tr = rnd.Next();
|
||||||
RcCrowdAgentType type = RcCrowdAgentType.MOB;
|
RcCrowdAgentType type = RcCrowdAgentType.MOB;
|
||||||
float mobsPcnt = _cfg.percentMobs / 100f;
|
float mobsPcnt = _cfg.percentMobs / 100f;
|
||||||
if (tr > mobsPcnt)
|
if (tr > mobsPcnt)
|
||||||
{
|
{
|
||||||
tr = _rand.Next();
|
tr = rnd.Next();
|
||||||
float travellerPcnt = _cfg.percentTravellers / 100f;
|
float travellerPcnt = _cfg.percentTravellers / 100f;
|
||||||
if (tr > travellerPcnt)
|
if (tr > travellerPcnt)
|
||||||
{
|
{
|
||||||
|
@ -208,7 +190,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
|
|
||||||
var status = DtStatus.DT_FAILURE;
|
var status = DtStatus.DT_FAILURE;
|
||||||
var randomPt = RcVec3f.Zero;
|
var randomPt = Vector3.Zero;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case RcCrowdAgentType.MOB:
|
case RcCrowdAgentType.MOB:
|
||||||
|
@ -232,19 +214,19 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
public void Update(float dt)
|
public void Update(float dt)
|
||||||
{
|
{
|
||||||
long startTime = RcFrequency.Ticks;
|
long startTime = RcFrequency.Ticks;
|
||||||
if (_crowd != null)
|
if (crowd != null)
|
||||||
{
|
{
|
||||||
_crowd.Config().pathQueueSize = _cfg.pathQueueSize;
|
crowd.Config().pathQueueSize = _cfg.pathQueueSize;
|
||||||
_crowd.Config().maxFindPathIterations = _cfg.maxIterations;
|
crowd.Config().maxFindPathIterations = _cfg.maxIterations;
|
||||||
_crowd.Update(dt, null);
|
crowd.Update(dt, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
long endTime = RcFrequency.Ticks;
|
long endTime = RcFrequency.Ticks;
|
||||||
if (_crowd != null)
|
if (crowd != null)
|
||||||
{
|
{
|
||||||
DtNavMeshQuery navquery = new DtNavMeshQuery(_navMesh);
|
DtNavMeshQuery navquery = new DtNavMeshQuery(navMesh);
|
||||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||||
foreach (DtCrowdAgent ag in _crowd.GetActiveAgents())
|
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
||||||
{
|
{
|
||||||
if (NeedsNewTarget(ag))
|
if (NeedsNewTarget(ag))
|
||||||
{
|
{
|
||||||
|
@ -265,28 +247,20 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentTime = endTime - startTime;
|
crowdUpdateTime = (endTime - startTime) / TimeSpan.TicksPerMillisecond;
|
||||||
_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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MoveMob(DtNavMeshQuery navquery, IDtQueryFilter filter, DtCrowdAgent ag, RcCrowdAgentData crowAgentData)
|
private void MoveMob(DtNavMeshQuery navquery, IDtQueryFilter filter, DtCrowdAgent ag, RcCrowdAgentData crowAgentData)
|
||||||
{
|
{
|
||||||
// Move somewhere
|
// Move somewhere
|
||||||
var status = navquery.FindNearestPoly(ag.npos, _crowd.GetQueryExtents(), filter, out var nearestRef, out var nearestPt, out var _);
|
var status = navquery.FindNearestPoly(ag.npos, crowd.GetQueryExtents(), filter, out var nearestRef, out var nearestPt, out var _);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
status = navquery.FindRandomPointAroundCircle(nearestRef, crowAgentData.home, _cfg.zoneRadius * 2f, filter, _rand,
|
status = navquery.FindRandomPointAroundCircle(nearestRef, crowAgentData.home, _cfg.zoneRadius * 2f, filter, rnd,
|
||||||
out var randomRef, out var randomPt);
|
out var randomRef, out var randomPt);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
_crowd.RequestMoveTarget(ag, randomRef, randomPt);
|
crowd.RequestMoveTarget(ag, randomRef, randomPt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,14 +268,14 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
private void MoveVillager(DtNavMeshQuery navquery, IDtQueryFilter filter, DtCrowdAgent ag, RcCrowdAgentData crowAgentData)
|
private void MoveVillager(DtNavMeshQuery navquery, IDtQueryFilter filter, DtCrowdAgent ag, RcCrowdAgentData crowAgentData)
|
||||||
{
|
{
|
||||||
// Move somewhere close
|
// Move somewhere close
|
||||||
var status = navquery.FindNearestPoly(ag.npos, _crowd.GetQueryExtents(), filter, out var nearestRef, out var nearestPt, out var _);
|
var status = navquery.FindNearestPoly(ag.npos, crowd.GetQueryExtents(), filter, out var nearestRef, out var nearestPt, out var _);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
status = navquery.FindRandomPointAroundCircle(nearestRef, crowAgentData.home, _cfg.zoneRadius * 0.2f, filter, _rand,
|
status = navquery.FindRandomPointAroundCircle(nearestRef, crowAgentData.home, _cfg.zoneRadius * 0.2f, filter, rnd,
|
||||||
out var randomRef, out var randomPt);
|
out var randomRef, out var randomPt);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
_crowd.RequestMoveTarget(ag, randomRef, randomPt);
|
crowd.RequestMoveTarget(ag, randomRef, randomPt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,7 +286,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
List<DtPolyPoint> potentialTargets = new List<DtPolyPoint>();
|
List<DtPolyPoint> potentialTargets = new List<DtPolyPoint>();
|
||||||
foreach (var zone in _polyPoints)
|
foreach (var zone in _polyPoints)
|
||||||
{
|
{
|
||||||
if (RcVec3f.DistanceSquared(zone.pt, ag.npos) > _cfg.zoneRadius * _cfg.zoneRadius)
|
if (Vector3.DistanceSquared(zone.pt, ag.npos) > _cfg.zoneRadius * _cfg.zoneRadius)
|
||||||
{
|
{
|
||||||
potentialTargets.Add(zone);
|
potentialTargets.Add(zone);
|
||||||
}
|
}
|
||||||
|
@ -321,7 +295,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
if (0 < potentialTargets.Count)
|
if (0 < potentialTargets.Count)
|
||||||
{
|
{
|
||||||
potentialTargets.Shuffle();
|
potentialTargets.Shuffle();
|
||||||
_crowd.RequestMoveTarget(ag, potentialTargets[0].refs, potentialTargets[0].pt);
|
crowd.RequestMoveTarget(ag, potentialTargets[0].refs, potentialTargets[0].pt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,18 +318,18 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DtCrowdAgent AddAgent(RcVec3f p, RcCrowdAgentType type, float agentRadius, float agentHeight, float agentMaxAcceleration, float agentMaxSpeed)
|
private DtCrowdAgent AddAgent(Vector3 p, RcCrowdAgentType type, float agentRadius, float agentHeight, float agentMaxAcceleration, float agentMaxSpeed)
|
||||||
{
|
{
|
||||||
DtCrowdAgentParams ap = GetAgentParams(agentRadius, agentHeight, agentMaxAcceleration, agentMaxSpeed);
|
DtCrowdAgentParams ap = GetAgentParams(agentRadius, agentHeight, agentMaxAcceleration, agentMaxSpeed);
|
||||||
ap.userData = new RcCrowdAgentData(type, p);
|
ap.userData = new RcCrowdAgentData(type, p);
|
||||||
return _crowd.AddAgent(p, ap);
|
return crowd.AddAgent(p, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateAgentParams()
|
public void UpdateAgentParams()
|
||||||
{
|
{
|
||||||
if (_crowd != null)
|
if (crowd != null)
|
||||||
{
|
{
|
||||||
foreach (DtCrowdAgent ag in _crowd.GetActiveAgents())
|
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
||||||
{
|
{
|
||||||
DtCrowdAgentParams option = new DtCrowdAgentParams();
|
DtCrowdAgentParams option = new DtCrowdAgentParams();
|
||||||
option.radius = ag.option.radius;
|
option.radius = ag.option.radius;
|
||||||
|
@ -369,34 +343,14 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
option.updateFlags = _agCfg.GetUpdateFlags();
|
option.updateFlags = _agCfg.GetUpdateFlags();
|
||||||
option.obstacleAvoidanceType = _agCfg.obstacleAvoidanceType;
|
option.obstacleAvoidanceType = _agCfg.obstacleAvoidanceType;
|
||||||
option.separationWeight = _agCfg.separationWeight;
|
option.separationWeight = _agCfg.separationWeight;
|
||||||
_crowd.UpdateAgentParameters(ag, option);
|
crowd.UpdateAgentParameters(ag, option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long GetCrowdUpdateSamplingTime()
|
|
||||||
{
|
|
||||||
return _samplingUpdateTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long GetCrowdUpdateTime()
|
public long GetCrowdUpdateTime()
|
||||||
{
|
{
|
||||||
return _curUpdateTime;
|
return crowdUpdateTime;
|
||||||
}
|
|
||||||
|
|
||||||
public long GetCrowdUpdateAvgTime()
|
|
||||||
{
|
|
||||||
return _avgUpdateTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long GetCrowdUpdateMinTime()
|
|
||||||
{
|
|
||||||
return _minUpdateTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long GetCrowdUpdateMaxTime()
|
|
||||||
{
|
|
||||||
return _maxUpdateTime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
using DotRecast.Detour.Crowd;
|
using DotRecast.Detour.Crowd;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
|
@ -16,7 +17,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
private long crowdUpdateTime;
|
private long crowdUpdateTime;
|
||||||
private readonly Dictionary<long, RcCrowdAgentTrail> _trails;
|
private readonly Dictionary<long, RcCrowdAgentTrail> _trails;
|
||||||
private long _moveTargetRef;
|
private long _moveTargetRef;
|
||||||
private RcVec3f _moveTargetPos;
|
private Vector3 _moveTargetPos;
|
||||||
|
|
||||||
public RcCrowdTool()
|
public RcCrowdTool()
|
||||||
{
|
{
|
||||||
|
@ -52,7 +53,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return _moveTargetRef;
|
return _moveTargetRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f GetMoveTargetPos()
|
public Vector3 GetMoveTargetPos()
|
||||||
{
|
{
|
||||||
return _moveTargetPos;
|
return _moveTargetPos;
|
||||||
}
|
}
|
||||||
|
@ -170,7 +171,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddAgent(RcVec3f p, float agentRadius, float agentHeight, float agentMaxAcceleration, float agentMaxSpeed)
|
public void AddAgent(Vector3 p, float agentRadius, float agentHeight, float agentMaxAcceleration, float agentMaxSpeed)
|
||||||
{
|
{
|
||||||
DtCrowdAgentParams ap = CreateAgentParams(agentRadius, agentHeight, agentMaxAcceleration, agentMaxSpeed);
|
DtCrowdAgentParams ap = CreateAgentParams(agentRadius, agentHeight, agentMaxAcceleration, agentMaxSpeed);
|
||||||
DtCrowdAgent ag = crowd.AddAgent(p, ap);
|
DtCrowdAgent ag = crowd.AddAgent(p, ap);
|
||||||
|
@ -212,15 +213,15 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return ap;
|
return ap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtCrowdAgent HitTestAgents(RcVec3f s, RcVec3f p)
|
public DtCrowdAgent HitTestAgents(Vector3 s, Vector3 p)
|
||||||
{
|
{
|
||||||
DtCrowdAgent isel = null;
|
DtCrowdAgent isel = null;
|
||||||
float tsel = float.MaxValue;
|
float tsel = float.MaxValue;
|
||||||
|
|
||||||
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
||||||
{
|
{
|
||||||
RcVec3f bmin = new RcVec3f();
|
Vector3 bmin = new Vector3();
|
||||||
RcVec3f bmax = new RcVec3f();
|
Vector3 bmax = new Vector3();
|
||||||
GetAgentBounds(ag, ref bmin, ref bmax);
|
GetAgentBounds(ag, ref bmin, ref bmax);
|
||||||
if (RcIntersections.IsectSegAABB(s, p, bmin, bmax, out var tmin, out var tmax))
|
if (RcIntersections.IsectSegAABB(s, p, bmin, bmax, out var tmin, out var tmax))
|
||||||
{
|
{
|
||||||
|
@ -235,9 +236,9 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return isel;
|
return isel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetAgentBounds(DtCrowdAgent ag, ref RcVec3f bmin, ref RcVec3f bmax)
|
private void GetAgentBounds(DtCrowdAgent ag, ref Vector3 bmin, ref Vector3 bmax)
|
||||||
{
|
{
|
||||||
RcVec3f p = ag.npos;
|
Vector3 p = ag.npos;
|
||||||
float r = ag.option.radius;
|
float r = ag.option.radius;
|
||||||
float h = ag.option.height;
|
float h = ag.option.height;
|
||||||
bmin.X = p.X - r;
|
bmin.X = p.X - r;
|
||||||
|
@ -248,7 +249,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
bmax.Z = p.Z + r;
|
bmax.Z = p.Z + r;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMoveTarget(RcVec3f p, bool adjust)
|
public void SetMoveTarget(Vector3 p, bool adjust)
|
||||||
{
|
{
|
||||||
if (crowd == null)
|
if (crowd == null)
|
||||||
return;
|
return;
|
||||||
|
@ -256,21 +257,21 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
// Find nearest point on navmesh and set move request to that location.
|
// Find nearest point on navmesh and set move request to that location.
|
||||||
DtNavMeshQuery navquery = crowd.GetNavMeshQuery();
|
DtNavMeshQuery navquery = crowd.GetNavMeshQuery();
|
||||||
IDtQueryFilter filter = crowd.GetFilter(0);
|
IDtQueryFilter filter = crowd.GetFilter(0);
|
||||||
RcVec3f halfExtents = crowd.GetQueryExtents();
|
Vector3 halfExtents = crowd.GetQueryExtents();
|
||||||
|
|
||||||
if (adjust)
|
if (adjust)
|
||||||
{
|
{
|
||||||
// Request velocity
|
// Request velocity
|
||||||
if (_agentDebug.agent != null)
|
if (_agentDebug.agent != null)
|
||||||
{
|
{
|
||||||
RcVec3f vel = CalcVel(_agentDebug.agent.npos, p, _agentDebug.agent.option.maxSpeed);
|
Vector3 vel = CalcVel(_agentDebug.agent.npos, p, _agentDebug.agent.option.maxSpeed);
|
||||||
crowd.RequestMoveVelocity(_agentDebug.agent, vel);
|
crowd.RequestMoveVelocity(_agentDebug.agent, vel);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
||||||
{
|
{
|
||||||
RcVec3f vel = CalcVel(ag.npos, p, ag.option.maxSpeed);
|
Vector3 vel = CalcVel(ag.npos, p, ag.option.maxSpeed);
|
||||||
crowd.RequestMoveVelocity(ag, vel);
|
crowd.RequestMoveVelocity(ag, vel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,11 +293,11 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RcVec3f CalcVel(RcVec3f pos, RcVec3f tgt, float speed)
|
private Vector3 CalcVel(Vector3 pos, Vector3 tgt, float speed)
|
||||||
{
|
{
|
||||||
RcVec3f vel = RcVec3f.Subtract(tgt, pos);
|
Vector3 vel = Vector3.Subtract(tgt, pos);
|
||||||
vel.Y = 0.0f;
|
vel.Y = 0.0f;
|
||||||
vel = RcVec3f.Normalize(vel);
|
vel = Vector3.Normalize(vel);
|
||||||
return vel.Scale(speed);
|
return vel.Scale(speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Dynamic;
|
using DotRecast.Detour.Dynamic;
|
||||||
using DotRecast.Detour.Dynamic.Colliders;
|
using DotRecast.Detour.Dynamic.Colliders;
|
||||||
using DotRecast.Detour.Dynamic.Io;
|
using DotRecast.Detour.Dynamic.Io;
|
||||||
|
@ -47,7 +48,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return dynaMesh;
|
return dynaMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveShape(RcVec3f start, RcVec3f dir)
|
public void RemoveShape(Vector3 start, Vector3 dir)
|
||||||
{
|
{
|
||||||
foreach (var e in colliderGizmos)
|
foreach (var e in colliderGizmos)
|
||||||
{
|
{
|
||||||
|
@ -60,7 +61,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Hit(RcVec3f point, RcVec3f dir, float[] bounds)
|
private bool Hit(Vector3 point, Vector3 dir, float[] bounds)
|
||||||
{
|
{
|
||||||
float cx = 0.5f * (bounds[0] + bounds[3]);
|
float cx = 0.5f * (bounds[0] + bounds[3]);
|
||||||
float cy = 0.5f * (bounds[1] + bounds[4]);
|
float cy = 0.5f * (bounds[1] + bounds[4]);
|
||||||
|
@ -89,7 +90,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public RcGizmo AddShape(RcDynamicColliderShape colliderShape, RcVec3f p)
|
public RcGizmo AddShape(RcDynamicColliderShape colliderShape, Vector3 p)
|
||||||
{
|
{
|
||||||
if (dynaMesh == null)
|
if (dynaMesh == null)
|
||||||
{
|
{
|
||||||
|
@ -166,7 +167,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public RcGizmo SphereCollider(RcVec3f p, float walkableClimb)
|
public RcGizmo SphereCollider(Vector3 p, float walkableClimb)
|
||||||
{
|
{
|
||||||
float radius = 1 + (float)random.NextDouble() * 10;
|
float radius = 1 + (float)random.NextDouble() * 10;
|
||||||
var collider = new DtSphereCollider(p, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, walkableClimb);
|
var collider = new DtSphereCollider(p, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, walkableClimb);
|
||||||
|
@ -175,86 +176,86 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return new RcGizmo(collider, gizmo);
|
return new RcGizmo(collider, gizmo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcGizmo CapsuleCollider(RcVec3f p, float walkableClimb)
|
public RcGizmo CapsuleCollider(Vector3 p, float walkableClimb)
|
||||||
{
|
{
|
||||||
float radius = 0.4f + (float)random.NextDouble() * 4f;
|
float radius = 0.4f + (float)random.NextDouble() * 4f;
|
||||||
RcVec3f a = new RcVec3f(
|
Vector3 a = new Vector3(
|
||||||
(1f - 2 * (float)random.NextDouble()),
|
(1f - 2 * (float)random.NextDouble()),
|
||||||
0.01f + (float)random.NextDouble(),
|
0.01f + (float)random.NextDouble(),
|
||||||
(1f - 2 * (float)random.NextDouble())
|
(1f - 2 * (float)random.NextDouble())
|
||||||
);
|
);
|
||||||
a = RcVec3f.Normalize(a);
|
a = Vector3.Normalize(a);
|
||||||
|
|
||||||
float len = 1f + (float)random.NextDouble() * 20f;
|
float len = 1f + (float)random.NextDouble() * 20f;
|
||||||
a.X *= len;
|
a.X *= len;
|
||||||
a.Y *= len;
|
a.Y *= len;
|
||||||
a.Z *= len;
|
a.Z *= len;
|
||||||
RcVec3f start = new RcVec3f(p.X, p.Y, p.Z);
|
Vector3 start = new Vector3(p.X, p.Y, p.Z);
|
||||||
RcVec3f end = new RcVec3f(p.X + a.X, p.Y + a.Y, p.Z + a.Z);
|
Vector3 end = new Vector3(p.X + a.X, p.Y + a.Y, p.Z + a.Z);
|
||||||
var collider = new DtCapsuleCollider(start, end, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, walkableClimb);
|
var collider = new DtCapsuleCollider(start, end, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, walkableClimb);
|
||||||
var gizmo = RcGizmoFactory.Capsule(start, end, radius);
|
var gizmo = RcGizmoFactory.Capsule(start, end, radius);
|
||||||
return new RcGizmo(collider, gizmo);
|
return new RcGizmo(collider, gizmo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcGizmo BoxCollider(RcVec3f p, float walkableClimb)
|
public RcGizmo BoxCollider(Vector3 p, float walkableClimb)
|
||||||
{
|
{
|
||||||
RcVec3f extent = new RcVec3f(
|
Vector3 extent = new Vector3(
|
||||||
0.5f + (float)random.NextDouble() * 6f,
|
0.5f + (float)random.NextDouble() * 6f,
|
||||||
0.5f + (float)random.NextDouble() * 6f,
|
0.5f + (float)random.NextDouble() * 6f,
|
||||||
0.5f + (float)random.NextDouble() * 6f
|
0.5f + (float)random.NextDouble() * 6f
|
||||||
);
|
);
|
||||||
RcVec3f forward = new RcVec3f((1f - 2 * (float)random.NextDouble()), 0, (1f - 2 * (float)random.NextDouble()));
|
Vector3 forward = new Vector3((1f - 2 * (float)random.NextDouble()), 0, (1f - 2 * (float)random.NextDouble()));
|
||||||
RcVec3f up = new RcVec3f((1f - 2 * (float)random.NextDouble()), 0.01f + (float)random.NextDouble(), (1f - 2 * (float)random.NextDouble()));
|
Vector3 up = new Vector3((1f - 2 * (float)random.NextDouble()), 0.01f + (float)random.NextDouble(), (1f - 2 * (float)random.NextDouble()));
|
||||||
RcVec3f[] halfEdges = Detour.Dynamic.Colliders.DtBoxCollider.GetHalfEdges(up, forward, extent);
|
Vector3[] halfEdges = Detour.Dynamic.Colliders.DtBoxCollider.GetHalfEdges(up, forward, extent);
|
||||||
var collider = new DtBoxCollider(p, halfEdges, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, walkableClimb);
|
var collider = new DtBoxCollider(p, halfEdges, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, walkableClimb);
|
||||||
var gizmo = RcGizmoFactory.Box(p, halfEdges);
|
var gizmo = RcGizmoFactory.Box(p, halfEdges);
|
||||||
return new RcGizmo(collider, gizmo);
|
return new RcGizmo(collider, gizmo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcGizmo CylinderCollider(RcVec3f p, float walkableClimb)
|
public RcGizmo CylinderCollider(Vector3 p, float walkableClimb)
|
||||||
{
|
{
|
||||||
float radius = 0.7f + (float)random.NextDouble() * 4f;
|
float radius = 0.7f + (float)random.NextDouble() * 4f;
|
||||||
RcVec3f a = new RcVec3f(1f - 2 * (float)random.NextDouble(), 0.01f + (float)random.NextDouble(), 1f - 2 * (float)random.NextDouble());
|
Vector3 a = new Vector3(1f - 2 * (float)random.NextDouble(), 0.01f + (float)random.NextDouble(), 1f - 2 * (float)random.NextDouble());
|
||||||
a = RcVec3f.Normalize(a);
|
a = Vector3.Normalize(a);
|
||||||
float len = 2f + (float)random.NextDouble() * 20f;
|
float len = 2f + (float)random.NextDouble() * 20f;
|
||||||
a.X *= len;
|
a.X *= len;
|
||||||
a.Y *= len;
|
a.Y *= len;
|
||||||
a.Z *= len;
|
a.Z *= len;
|
||||||
RcVec3f start = new RcVec3f(p.X, p.Y, p.Z);
|
Vector3 start = new Vector3(p.X, p.Y, p.Z);
|
||||||
RcVec3f end = new RcVec3f(p.X + a.X, p.Y + a.Y, p.Z + a.Z);
|
Vector3 end = new Vector3(p.X + a.X, p.Y + a.Y, p.Z + a.Z);
|
||||||
var collider = new DtCylinderCollider(start, end, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, walkableClimb);
|
var collider = new DtCylinderCollider(start, end, radius, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER, walkableClimb);
|
||||||
var gizmo = RcGizmoFactory.Cylinder(start, end, radius);
|
var gizmo = RcGizmoFactory.Cylinder(start, end, radius);
|
||||||
|
|
||||||
return new RcGizmo(collider, gizmo);
|
return new RcGizmo(collider, gizmo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcGizmo CompositeCollider(RcVec3f p, float walkableClimb)
|
public RcGizmo CompositeCollider(Vector3 p, float walkableClimb)
|
||||||
{
|
{
|
||||||
RcVec3f baseExtent = new RcVec3f(5, 3, 8);
|
Vector3 baseExtent = new Vector3(5, 3, 8);
|
||||||
RcVec3f baseCenter = new RcVec3f(p.X, p.Y + 3, p.Z);
|
Vector3 baseCenter = new Vector3(p.X, p.Y + 3, p.Z);
|
||||||
RcVec3f baseUp = new RcVec3f(0, 1, 0);
|
Vector3 baseUp = new Vector3(0, 1, 0);
|
||||||
RcVec3f forward = new RcVec3f((1f - 2 * (float)random.NextDouble()), 0, (1f - 2 * (float)random.NextDouble()));
|
Vector3 forward = new Vector3((1f - 2 * (float)random.NextDouble()), 0, (1f - 2 * (float)random.NextDouble()));
|
||||||
forward = RcVec3f.Normalize(forward);
|
forward = Vector3.Normalize(forward);
|
||||||
|
|
||||||
RcVec3f side = RcVec3f.Cross(forward, baseUp);
|
Vector3 side = Vector3.Cross(forward, baseUp);
|
||||||
DtBoxCollider @base = new DtBoxCollider(baseCenter, Detour.Dynamic.Colliders.DtBoxCollider.GetHalfEdges(baseUp, forward, baseExtent),
|
DtBoxCollider @base = new DtBoxCollider(baseCenter, Detour.Dynamic.Colliders.DtBoxCollider.GetHalfEdges(baseUp, forward, baseExtent),
|
||||||
SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, walkableClimb);
|
SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, walkableClimb);
|
||||||
var roofUp = RcVec3f.Zero;
|
var roofUp = Vector3.Zero;
|
||||||
RcVec3f roofExtent = new RcVec3f(4.5f, 4.5f, 8f);
|
Vector3 roofExtent = new Vector3(4.5f, 4.5f, 8f);
|
||||||
var rx = RcMatrix4x4f.CreateFromRotate(45, forward.X, forward.Y, forward.Z);
|
var rx = RcMatrix4x4f.CreateFromRotate(45, forward.X, forward.Y, forward.Z);
|
||||||
roofUp = MulMatrixVector(ref roofUp, rx, baseUp);
|
roofUp = MulMatrixVector(ref roofUp, rx, baseUp);
|
||||||
RcVec3f roofCenter = new RcVec3f(p.X, p.Y + 6, p.Z);
|
Vector3 roofCenter = new Vector3(p.X, p.Y + 6, p.Z);
|
||||||
DtBoxCollider roof = new DtBoxCollider(roofCenter, Detour.Dynamic.Colliders.DtBoxCollider.GetHalfEdges(roofUp, forward, roofExtent),
|
DtBoxCollider roof = new DtBoxCollider(roofCenter, Detour.Dynamic.Colliders.DtBoxCollider.GetHalfEdges(roofUp, forward, roofExtent),
|
||||||
SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, walkableClimb);
|
SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, walkableClimb);
|
||||||
RcVec3f trunkStart = new RcVec3f(
|
Vector3 trunkStart = new Vector3(
|
||||||
baseCenter.X - forward.X * 15 + side.X * 6,
|
baseCenter.X - forward.X * 15 + side.X * 6,
|
||||||
p.Y,
|
p.Y,
|
||||||
baseCenter.Z - forward.Z * 15 + side.Z * 6
|
baseCenter.Z - forward.Z * 15 + side.Z * 6
|
||||||
);
|
);
|
||||||
RcVec3f trunkEnd = new RcVec3f(trunkStart.X, trunkStart.Y + 10, trunkStart.Z);
|
Vector3 trunkEnd = new Vector3(trunkStart.X, trunkStart.Y + 10, trunkStart.Z);
|
||||||
DtCapsuleCollider trunk = new DtCapsuleCollider(trunkStart, trunkEnd, 0.5f, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD,
|
DtCapsuleCollider trunk = new DtCapsuleCollider(trunkStart, trunkEnd, 0.5f, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD,
|
||||||
walkableClimb);
|
walkableClimb);
|
||||||
RcVec3f crownCenter = new RcVec3f(
|
Vector3 crownCenter = new Vector3(
|
||||||
baseCenter.X - forward.X * 15 + side.X * 6, p.Y + 10,
|
baseCenter.X - forward.X * 15 + side.X * 6, p.Y + 10,
|
||||||
baseCenter.Z - forward.Z * 15 + side.Z * 6
|
baseCenter.Z - forward.Z * 15 + side.Z * 6
|
||||||
);
|
);
|
||||||
|
@ -269,17 +270,17 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return new RcGizmo(collider, gizmo);
|
return new RcGizmo(collider, gizmo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcGizmo TrimeshBridge(RcVec3f p, float walkableClimb)
|
public RcGizmo TrimeshBridge(Vector3 p, float walkableClimb)
|
||||||
{
|
{
|
||||||
return TrimeshCollider(p, bridgeGeom, walkableClimb);
|
return TrimeshCollider(p, bridgeGeom, walkableClimb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcGizmo TrimeshHouse(RcVec3f p, float walkableClimb)
|
public RcGizmo TrimeshHouse(Vector3 p, float walkableClimb)
|
||||||
{
|
{
|
||||||
return TrimeshCollider(p, houseGeom, walkableClimb);
|
return TrimeshCollider(p, houseGeom, walkableClimb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcGizmo ConvexTrimesh(RcVec3f p, float walkableClimb)
|
public RcGizmo ConvexTrimesh(Vector3 p, float walkableClimb)
|
||||||
{
|
{
|
||||||
float[] verts = TransformVertices(p, convexGeom, 360);
|
float[] verts = TransformVertices(p, convexGeom, 360);
|
||||||
var collider = new DtConvexTrimeshCollider(verts, convexGeom.faces,
|
var collider = new DtConvexTrimeshCollider(verts, convexGeom.faces,
|
||||||
|
@ -288,7 +289,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return new RcGizmo(collider, gizmo);
|
return new RcGizmo(collider, gizmo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RcGizmo TrimeshCollider(RcVec3f p, DemoInputGeomProvider geom, float walkableClimb)
|
private RcGizmo TrimeshCollider(Vector3 p, DemoInputGeomProvider geom, float walkableClimb)
|
||||||
{
|
{
|
||||||
float[] verts = TransformVertices(p, geom, 0);
|
float[] verts = TransformVertices(p, geom, 0);
|
||||||
var collider = new DtTrimeshCollider(verts, geom.faces, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD,
|
var collider = new DtTrimeshCollider(verts, geom.faces, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD,
|
||||||
|
@ -298,14 +299,14 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return new RcGizmo(collider, gizmo);
|
return new RcGizmo(collider, gizmo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float[] TransformVertices(RcVec3f p, DemoInputGeomProvider geom, float ax)
|
private float[] TransformVertices(Vector3 p, DemoInputGeomProvider geom, float ax)
|
||||||
{
|
{
|
||||||
var rx = RcMatrix4x4f.CreateFromRotate((float)random.NextDouble() * ax, 1, 0, 0);
|
var rx = RcMatrix4x4f.CreateFromRotate((float)random.NextDouble() * ax, 1, 0, 0);
|
||||||
var ry = RcMatrix4x4f.CreateFromRotate((float)random.NextDouble() * 360, 0, 1, 0);
|
var ry = RcMatrix4x4f.CreateFromRotate((float)random.NextDouble() * 360, 0, 1, 0);
|
||||||
var m = RcMatrix4x4f.Mul(ref rx, ref ry);
|
var m = RcMatrix4x4f.Mul(ref rx, ref ry);
|
||||||
float[] verts = new float[geom.vertices.Length];
|
float[] verts = new float[geom.vertices.Length];
|
||||||
RcVec3f v = new RcVec3f();
|
Vector3 v = new Vector3();
|
||||||
RcVec3f vr = new RcVec3f();
|
Vector3 vr = new Vector3();
|
||||||
for (int i = 0; i < geom.vertices.Length; i += 3)
|
for (int i = 0; i < geom.vertices.Length; i += 3)
|
||||||
{
|
{
|
||||||
v.X = geom.vertices[i];
|
v.X = geom.vertices[i];
|
||||||
|
@ -331,7 +332,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return resultvector;
|
return resultvector;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RcVec3f MulMatrixVector(ref RcVec3f resultvector, RcMatrix4x4f matrix, RcVec3f pvector)
|
private static Vector3 MulMatrixVector(ref Vector3 resultvector, RcMatrix4x4f matrix, Vector3 pvector)
|
||||||
{
|
{
|
||||||
resultvector.X = matrix.M11 * pvector.X + matrix.M21 * pvector.Y + matrix.M31 * pvector.Z;
|
resultvector.X = matrix.M11 * pvector.X + matrix.M21 * pvector.Y + matrix.M31 * pvector.Z;
|
||||||
resultvector.Y = matrix.M12 * pvector.X + matrix.M22 * pvector.Y + matrix.M32 * pvector.Z;
|
resultvector.Y = matrix.M12 * pvector.X + matrix.M22 * pvector.Y + matrix.M32 * pvector.Z;
|
||||||
|
@ -355,14 +356,14 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Raycast(RcVec3f spos, RcVec3f epos, out float hitPos, out RcVec3f raycastHitPos)
|
public bool Raycast(Vector3 spos, Vector3 epos, out float hitPos, out Vector3 raycastHitPos)
|
||||||
{
|
{
|
||||||
RcVec3f sp = new RcVec3f(spos.X, spos.Y + 1.3f, spos.Z);
|
Vector3 sp = new Vector3(spos.X, spos.Y + 1.3f, spos.Z);
|
||||||
RcVec3f ep = new RcVec3f(epos.X, epos.Y + 1.3f, epos.Z);
|
Vector3 ep = new Vector3(epos.X, epos.Y + 1.3f, epos.Z);
|
||||||
|
|
||||||
bool hasHit = dynaMesh.VoxelQuery().Raycast(sp, ep, out hitPos);
|
bool hasHit = dynaMesh.VoxelQuery().Raycast(sp, ep, out hitPos);
|
||||||
raycastHitPos = hasHit
|
raycastHitPos = hasHit
|
||||||
? new RcVec3f(sp.X + hitPos * (ep.X - sp.X), sp.Y + hitPos * (ep.Y - sp.Y), sp.Z + hitPos * (ep.Z - sp.Z))
|
? new Vector3(sp.X + hitPos * (ep.X - sp.X), sp.Y + hitPos * (ep.Y - sp.Y), sp.Z + hitPos * (ep.Z - sp.Z))
|
||||||
: ep;
|
: ep;
|
||||||
|
|
||||||
return hasHit;
|
return hasHit;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Extras.Jumplink;
|
using DotRecast.Detour.Extras.Jumplink;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
|
@ -111,11 +112,11 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
{
|
{
|
||||||
int area = SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP_AUTO;
|
int area = SampleAreaModifications.SAMPLE_POLYAREA_TYPE_JUMP_AUTO;
|
||||||
int flags = SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP;
|
int flags = SampleAreaModifications.SAMPLE_POLYFLAGS_JUMP;
|
||||||
RcVec3f prev = new RcVec3f();
|
Vector3 prev = new Vector3();
|
||||||
for (int i = 0; i < link.startSamples.Length; i++)
|
for (int i = 0; i < link.startSamples.Length; i++)
|
||||||
{
|
{
|
||||||
RcVec3f p = link.startSamples[i].p;
|
Vector3 p = link.startSamples[i].p;
|
||||||
RcVec3f q = link.endSamples[i].p;
|
Vector3 q = link.endSamples[i].p;
|
||||||
if (i == 0 || RcVecUtils.Dist2D(prev, p) > agentRadius)
|
if (i == 0 || RcVecUtils.Dist2D(prev, p) > agentRadius)
|
||||||
{
|
{
|
||||||
geom.AddOffMeshConnection(p, q, agentRadius, false, area, flags);
|
geom.AddOffMeshConnection(p, q, agentRadius, false, area, flags);
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Collections;
|
using DotRecast.Core.Collections;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
using DotRecast.Detour.TileCache;
|
using DotRecast.Detour.TileCache;
|
||||||
using DotRecast.Detour.TileCache.Io.Compress;
|
using DotRecast.Detour.TileCache.Io.Compress;
|
||||||
|
@ -96,7 +97,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveTempObstacle(RcVec3f sp, RcVec3f sq)
|
public void RemoveTempObstacle(Vector3 sp, Vector3 sq)
|
||||||
{
|
{
|
||||||
if (null == _tc)
|
if (null == _tc)
|
||||||
return;
|
return;
|
||||||
|
@ -105,7 +106,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
_tc.RemoveObstacle(refs);
|
_tc.RemoveObstacle(refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long AddTempObstacle(RcVec3f p)
|
public long AddTempObstacle(Vector3 p)
|
||||||
{
|
{
|
||||||
if (null == _tc)
|
if (null == _tc)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -148,7 +149,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return tc;
|
return tc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long HitTestObstacle(RcVec3f sp, RcVec3f sq)
|
public long HitTestObstacle(Vector3 sp, Vector3 sq)
|
||||||
{
|
{
|
||||||
float tmin = float.MaxValue;
|
float tmin = float.MaxValue;
|
||||||
DtTileCacheObstacle obmin = null;
|
DtTileCacheObstacle obmin = null;
|
||||||
|
@ -159,8 +160,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
if (ob.state == DtObstacleState.DT_OBSTACLE_EMPTY)
|
if (ob.state == DtObstacleState.DT_OBSTACLE_EMPTY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
RcVec3f bmin = RcVec3f.Zero;
|
Vector3 bmin = Vector3.Zero;
|
||||||
RcVec3f bmax = RcVec3f.Zero;
|
Vector3 bmax = Vector3.Zero;
|
||||||
_tc.GetObstacleBounds(ob, ref bmin, ref bmax);
|
_tc.GetObstacleBounds(ob, ref bmin, ref bmax);
|
||||||
|
|
||||||
if (RcIntersections.IsectSegAABB(sp, sq, bmin, bmax, out var t0, out var t1))
|
if (RcIntersections.IsectSegAABB(sp, sq, bmin, bmax, out var t0, out var t1))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return "Off-Mesh Links";
|
return "Off-Mesh Links";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(IInputGeomProvider geom, RcNavMeshBuildSettings settings, RcVec3f start, RcVec3f end, bool bidir)
|
public void Add(IInputGeomProvider geom, RcNavMeshBuildSettings settings, Vector3 start, Vector3 end, bool bidir)
|
||||||
{
|
{
|
||||||
if (null == geom)
|
if (null == geom)
|
||||||
return;
|
return;
|
||||||
|
@ -26,7 +27,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
geom.AddOffMeshConnection(start, end, settings.agentRadius, bidir, area, flags);
|
geom.AddOffMeshConnection(start, end, settings.agentRadius, bidir, area, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(IInputGeomProvider geom, RcNavMeshBuildSettings settings, RcVec3f p)
|
public void Remove(IInputGeomProvider geom, RcNavMeshBuildSettings settings, Vector3 p)
|
||||||
{
|
{
|
||||||
// Delete
|
// Delete
|
||||||
// Find nearest link end-point
|
// Find nearest link end-point
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Toolset.Tools
|
namespace DotRecast.Recast.Toolset.Tools
|
||||||
|
@ -21,31 +22,31 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return "Test Navmesh";
|
return "Test Navmesh";
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtStatus FindFollowPath(DtNavMesh navMesh, DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f startPt, RcVec3f endPt, IDtQueryFilter filter, bool enableRaycast,
|
public DtStatus FindFollowPath(DtNavMesh navMesh, DtNavMeshQuery navQuery, long startRef, long endRef, Vector3 startPt, Vector3 endPt, IDtQueryFilter filter, bool enableRaycast,
|
||||||
ref List<long> pathIterPolys, ref List<RcVec3f> smoothPath)
|
ref List<long> polys, ref List<Vector3> smoothPath)
|
||||||
{
|
{
|
||||||
if (startRef == 0 || endRef == 0)
|
if (startRef == 0 || endRef == 0)
|
||||||
{
|
{
|
||||||
pathIterPolys?.Clear();
|
polys?.Clear();
|
||||||
smoothPath?.Clear();
|
smoothPath?.Clear();
|
||||||
|
|
||||||
return DtStatus.DT_FAILURE;
|
return DtStatus.DT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pathIterPolys ??= new List<long>();
|
polys ??= new List<long>();
|
||||||
smoothPath ??= new List<RcVec3f>();
|
smoothPath ??= new List<Vector3>();
|
||||||
|
|
||||||
pathIterPolys.Clear();
|
polys.Clear();
|
||||||
smoothPath.Clear();
|
smoothPath.Clear();
|
||||||
|
|
||||||
var opt = new DtFindPathOption(enableRaycast ? DtFindPathOptions.DT_FINDPATH_ANY_ANGLE : 0, float.MaxValue);
|
var opt = new DtFindPathOption(enableRaycast ? DtFindPathOptions.DT_FINDPATH_ANY_ANGLE : 0, float.MaxValue);
|
||||||
navQuery.FindPath(startRef, endRef, startPt, endPt, filter, ref pathIterPolys, opt);
|
navQuery.FindPath(startRef, endRef, startPt, endPt, filter, ref polys, opt);
|
||||||
if (0 >= pathIterPolys.Count)
|
if (0 >= polys.Count)
|
||||||
return DtStatus.DT_FAILURE;
|
return DtStatus.DT_FAILURE;
|
||||||
|
|
||||||
// Iterate over the path to find smooth path on the detail mesh surface.
|
// Iterate over the path to find smooth path on the detail mesh surface.
|
||||||
navQuery.ClosestPointOnPoly(startRef, startPt, out var iterPos, out var _);
|
navQuery.ClosestPointOnPoly(startRef, startPt, out var iterPos, out var _);
|
||||||
navQuery.ClosestPointOnPoly(pathIterPolys[pathIterPolys.Count - 1], endPt, out var targetPos, out var _);
|
navQuery.ClosestPointOnPoly(polys[polys.Count - 1], endPt, out var targetPos, out var _);
|
||||||
|
|
||||||
float STEP_SIZE = 0.5f;
|
float STEP_SIZE = 0.5f;
|
||||||
float SLOP = 0.01f;
|
float SLOP = 0.01f;
|
||||||
|
@ -56,11 +57,11 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
|
|
||||||
// Move towards target a small advancement at a time until target reached or
|
// Move towards target a small advancement at a time until target reached or
|
||||||
// when ran out of memory to store the path.
|
// when ran out of memory to store the path.
|
||||||
while (0 < pathIterPolys.Count && smoothPath.Count < MAX_SMOOTH)
|
while (0 < polys.Count && smoothPath.Count < MAX_SMOOTH)
|
||||||
{
|
{
|
||||||
// Find location to steer towards.
|
// Find location to steer towards.
|
||||||
if (!DtPathUtils.GetSteerTarget(navQuery, iterPos, targetPos, SLOP,
|
if (!DtPathUtils.GetSteerTarget(navQuery, iterPos, targetPos, SLOP,
|
||||||
pathIterPolys, out var steerPos, out var steerPosFlag, out var steerPosRef))
|
polys, out var steerPos, out var steerPosFlag, out var steerPosRef))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -73,8 +74,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
// Find movement delta.
|
// Find movement delta.
|
||||||
RcVec3f delta = RcVec3f.Subtract(steerPos, iterPos);
|
Vector3 delta = Vector3.Subtract(steerPos, iterPos);
|
||||||
float len = MathF.Sqrt(RcVec3f.Dot(delta, delta));
|
float len = MathF.Sqrt(Vector3.Dot(delta, delta));
|
||||||
// If the steer target is end of path or off-mesh link, do not move past the location.
|
// If the steer target is end of path or off-mesh link, do not move past the location.
|
||||||
if ((endOfPath || offMeshConnection) && len < STEP_SIZE)
|
if ((endOfPath || offMeshConnection) && len < STEP_SIZE)
|
||||||
{
|
{
|
||||||
|
@ -85,17 +86,17 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
len = STEP_SIZE / len;
|
len = STEP_SIZE / len;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f moveTgt = RcVecUtils.Mad(iterPos, delta, len);
|
Vector3 moveTgt = RcVecUtils.Mad(iterPos, delta, len);
|
||||||
|
|
||||||
// Move
|
// Move
|
||||||
navQuery.MoveAlongSurface(pathIterPolys[0], iterPos, moveTgt, filter, out var result, ref visited);
|
navQuery.MoveAlongSurface(polys[0], iterPos, moveTgt, filter, out var result, ref visited);
|
||||||
|
|
||||||
iterPos = result;
|
iterPos = result;
|
||||||
|
|
||||||
pathIterPolys = DtPathUtils.MergeCorridorStartMoved(pathIterPolys, pathIterPolys.Count, MAX_POLYS, visited);
|
polys = DtPathUtils.MergeCorridorStartMoved(polys, visited);
|
||||||
pathIterPolys = DtPathUtils.FixupShortcuts(pathIterPolys, navQuery);
|
polys = DtPathUtils.FixupShortcuts(polys, navQuery);
|
||||||
|
|
||||||
var status = navQuery.GetPolyHeight(pathIterPolys[0], result, out var h);
|
var status = navQuery.GetPolyHeight(polys[0], result, out var h);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
iterPos.Y = h;
|
iterPos.Y = h;
|
||||||
|
@ -116,21 +117,21 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
else if (offMeshConnection && DtPathUtils.InRange(iterPos, steerPos, SLOP, 1.0f))
|
else if (offMeshConnection && DtPathUtils.InRange(iterPos, steerPos, SLOP, 1.0f))
|
||||||
{
|
{
|
||||||
// Reached off-mesh connection.
|
// Reached off-mesh connection.
|
||||||
RcVec3f startPos = RcVec3f.Zero;
|
Vector3 startPos = Vector3.Zero;
|
||||||
RcVec3f endPos = RcVec3f.Zero;
|
Vector3 endPos = Vector3.Zero;
|
||||||
|
|
||||||
// Advance the path up to and over the off-mesh connection.
|
// Advance the path up to and over the off-mesh connection.
|
||||||
long prevRef = 0;
|
long prevRef = 0;
|
||||||
long polyRef = pathIterPolys[0];
|
long polyRef = polys[0];
|
||||||
int npos = 0;
|
int npos = 0;
|
||||||
while (npos < pathIterPolys.Count && polyRef != steerPosRef)
|
while (npos < polys.Count && polyRef != steerPosRef)
|
||||||
{
|
{
|
||||||
prevRef = polyRef;
|
prevRef = polyRef;
|
||||||
polyRef = pathIterPolys[npos];
|
polyRef = polys[npos];
|
||||||
npos++;
|
npos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
pathIterPolys = pathIterPolys.GetRange(npos, pathIterPolys.Count - npos);
|
polys = polys.GetRange(npos, polys.Count - npos);
|
||||||
|
|
||||||
// Handle the connection.
|
// Handle the connection.
|
||||||
var status2 = navMesh.GetOffMeshConnectionPolyEndPoints(prevRef, polyRef, ref startPos, ref endPos);
|
var status2 = navMesh.GetOffMeshConnectionPolyEndPoints(prevRef, polyRef, ref startPos, ref endPos);
|
||||||
|
@ -148,7 +149,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
|
|
||||||
// Move position at the other side of the off-mesh link.
|
// Move position at the other side of the off-mesh link.
|
||||||
iterPos = endPos;
|
iterPos = endPos;
|
||||||
navQuery.GetPolyHeight(pathIterPolys[0], iterPos, out var eh);
|
navQuery.GetPolyHeight(polys[0], iterPos, out var eh);
|
||||||
iterPos.Y = eh;
|
iterPos.Y = eh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +164,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return DtStatus.DT_SUCCESS;
|
return DtStatus.DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtStatus FindStraightPath(DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f startPt, RcVec3f endPt, IDtQueryFilter filter, bool enableRaycast,
|
public DtStatus FindStraightPath(DtNavMeshQuery navQuery, long startRef, long endRef, Vector3 startPt, Vector3 endPt, IDtQueryFilter filter, bool enableRaycast,
|
||||||
ref List<long> polys, ref List<DtStraightPath> straightPath, int straightPathOptions)
|
ref List<long> polys, ref List<DtStraightPath> straightPath, int straightPathOptions)
|
||||||
{
|
{
|
||||||
if (startRef == 0 || endRef == 0)
|
if (startRef == 0 || endRef == 0)
|
||||||
|
@ -184,7 +185,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return DtStatus.DT_FAILURE;
|
return DtStatus.DT_FAILURE;
|
||||||
|
|
||||||
// In case of partial path, make sure the end point is clamped to the last polygon.
|
// In case of partial path, make sure the end point is clamped to the last polygon.
|
||||||
var epos = new RcVec3f(endPt.X, endPt.Y, endPt.Z);
|
var epos = new Vector3(endPt.X, endPt.Y, endPt.Z);
|
||||||
if (polys[polys.Count - 1] != endRef)
|
if (polys[polys.Count - 1] != endRef)
|
||||||
{
|
{
|
||||||
var result = navQuery.ClosestPointOnPoly(polys[polys.Count - 1], endPt, out var closest, out var _);
|
var result = navQuery.ClosestPointOnPoly(polys[polys.Count - 1], endPt, out var closest, out var _);
|
||||||
|
@ -199,7 +200,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return DtStatus.DT_SUCCESS;
|
return DtStatus.DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtStatus InitSlicedFindPath(DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter, bool enableRaycast)
|
public DtStatus InitSlicedFindPath(DtNavMeshQuery navQuery, long startRef, long endRef, Vector3 startPos, Vector3 endPos, IDtQueryFilter filter, bool enableRaycast)
|
||||||
{
|
{
|
||||||
if (startRef == 0 || endRef == 0)
|
if (startRef == 0 || endRef == 0)
|
||||||
{
|
{
|
||||||
|
@ -212,7 +213,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtStatus UpdateSlicedFindPath(DtNavMeshQuery navQuery, int maxIter, long endRef, RcVec3f startPos, RcVec3f endPos,
|
public DtStatus UpdateSlicedFindPath(DtNavMeshQuery navQuery, int maxIter, long endRef, Vector3 startPos, Vector3 endPos,
|
||||||
ref List<long> path, ref List<DtStraightPath> straightPath)
|
ref List<long> path, ref List<DtStraightPath> straightPath)
|
||||||
{
|
{
|
||||||
var status = navQuery.UpdateSlicedFindPath(maxIter, out _);
|
var status = navQuery.UpdateSlicedFindPath(maxIter, out _);
|
||||||
|
@ -228,7 +229,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
if (path != null)
|
if (path != null)
|
||||||
{
|
{
|
||||||
// In case of partial path, make sure the end point is clamped to the last polygon.
|
// In case of partial path, make sure the end point is clamped to the last polygon.
|
||||||
RcVec3f epos = endPos;
|
Vector3 epos = endPos;
|
||||||
if (path[path.Count - 1] != endRef)
|
if (path[path.Count - 1] != endRef)
|
||||||
{
|
{
|
||||||
var result = navQuery.ClosestPointOnPoly(path[path.Count - 1], endPos, out var closest, out var _);
|
var result = navQuery.ClosestPointOnPoly(path[path.Count - 1], endPos, out var closest, out var _);
|
||||||
|
@ -246,8 +247,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public DtStatus Raycast(DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter,
|
public DtStatus Raycast(DtNavMeshQuery navQuery, long startRef, long endRef, Vector3 startPos, Vector3 endPos, IDtQueryFilter filter,
|
||||||
ref List<long> polys, ref List<DtStraightPath> straightPath, ref RcVec3f hitPos, ref RcVec3f hitNormal, ref bool hitResult)
|
ref List<long> polys, ref List<DtStraightPath> straightPath, ref Vector3 hitPos, ref Vector3 hitNormal, ref bool hitResult)
|
||||||
{
|
{
|
||||||
if (startRef == 0 || endRef == 0)
|
if (startRef == 0 || endRef == 0)
|
||||||
{
|
{
|
||||||
|
@ -257,17 +258,16 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return DtStatus.DT_FAILURE;
|
return DtStatus.DT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
var path = new List<long>();
|
var status = navQuery.Raycast(startRef, startPos, endPos, filter, 0, 0, out var rayHit);
|
||||||
var status = navQuery.Raycast(startRef, startPos, endPos, filter, out var t, out var hitNormal2, ref path);
|
|
||||||
if (!status.Succeeded())
|
if (!status.Succeeded())
|
||||||
{
|
{
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// results ...
|
// results ...
|
||||||
polys = path;
|
polys = rayHit.path;
|
||||||
|
|
||||||
if (t > 1)
|
if (rayHit.t > 1)
|
||||||
{
|
{
|
||||||
// No hit
|
// No hit
|
||||||
hitPos = endPos;
|
hitPos = endPos;
|
||||||
|
@ -276,15 +276,15 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Hit
|
// Hit
|
||||||
hitPos = RcVec3f.Lerp(startPos, endPos, t);
|
hitPos = Vector3.Lerp(startPos, endPos, rayHit.t);
|
||||||
hitNormal = hitNormal2;
|
hitNormal = rayHit.hitNormal;
|
||||||
hitResult = true;
|
hitResult = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust height.
|
// Adjust height.
|
||||||
if (path.Count > 0)
|
if (rayHit.path.Count > 0)
|
||||||
{
|
{
|
||||||
var result = navQuery.GetPolyHeight(path[path.Count - 1], hitPos, out var h);
|
var result = navQuery.GetPolyHeight(rayHit.path[rayHit.path.Count - 1], hitPos, out var h);
|
||||||
if (result.Succeeded())
|
if (result.Succeeded())
|
||||||
{
|
{
|
||||||
hitPos.Y = h;
|
hitPos.Y = h;
|
||||||
|
@ -299,8 +299,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtStatus FindDistanceToWall(DtNavMeshQuery navQuery, long startRef, RcVec3f spos, float maxRadius, IDtQueryFilter filter,
|
public DtStatus FindDistanceToWall(DtNavMeshQuery navQuery, long startRef, Vector3 spos, float maxRadius, IDtQueryFilter filter,
|
||||||
ref float hitDist, ref RcVec3f hitPos, ref RcVec3f hitNormal)
|
ref float hitDist, ref Vector3 hitPos, ref Vector3 hitNormal)
|
||||||
{
|
{
|
||||||
if (0 == startRef)
|
if (0 == startRef)
|
||||||
{
|
{
|
||||||
|
@ -321,7 +321,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public DtStatus FindPolysAroundCircle(DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f spos, RcVec3f epos, IDtQueryFilter filter, ref List<long> resultRef, ref List<long> resultParent)
|
public DtStatus FindPolysAroundCircle(DtNavMeshQuery navQuery, long startRef, long endRef, Vector3 spos, Vector3 epos, IDtQueryFilter filter, ref List<long> resultRef, ref List<long> resultParent)
|
||||||
{
|
{
|
||||||
if (startRef == 0 || endRef == 0)
|
if (startRef == 0 || endRef == 0)
|
||||||
{
|
{
|
||||||
|
@ -345,7 +345,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtStatus FindLocalNeighbourhood(DtNavMeshQuery navQuery, long startRef, RcVec3f spos, float radius, IDtQueryFilter filter,
|
public DtStatus FindLocalNeighbourhood(DtNavMeshQuery navQuery, long startRef, Vector3 spos, float radius, IDtQueryFilter filter,
|
||||||
ref List<long> resultRef, ref List<long> resultParent)
|
ref List<long> resultRef, ref List<long> resultParent)
|
||||||
{
|
{
|
||||||
if (startRef == 0)
|
if (startRef == 0)
|
||||||
|
@ -366,8 +366,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public DtStatus FindPolysAroundShape(DtNavMeshQuery navQuery, float agentHeight, long startRef, long endRef, RcVec3f spos, RcVec3f epos, IDtQueryFilter filter,
|
public DtStatus FindPolysAroundShape(DtNavMeshQuery navQuery, float agentHeight, long startRef, long endRef, Vector3 spos, Vector3 epos, IDtQueryFilter filter,
|
||||||
ref List<long> resultRefs, ref List<long> resultParents, ref RcVec3f[] queryPoly)
|
ref List<long> resultRefs, ref List<long> resultParents, ref Vector3[] queryPoly)
|
||||||
{
|
{
|
||||||
if (startRef == 0 || endRef == 0)
|
if (startRef == 0 || endRef == 0)
|
||||||
{
|
{
|
||||||
|
@ -377,7 +377,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
float nx = (epos.Z - spos.Z) * 0.25f;
|
float nx = (epos.Z - spos.Z) * 0.25f;
|
||||||
float nz = -(epos.X - spos.X) * 0.25f;
|
float nz = -(epos.X - spos.X) * 0.25f;
|
||||||
|
|
||||||
var tempQueryPoly = new RcVec3f[4];
|
var tempQueryPoly = new Vector3[4];
|
||||||
tempQueryPoly[0].X = spos.X + nx * 1.2f;
|
tempQueryPoly[0].X = spos.X + nx * 1.2f;
|
||||||
tempQueryPoly[0].Y = spos.Y + agentHeight / 2;
|
tempQueryPoly[0].Y = spos.Y + agentHeight / 2;
|
||||||
tempQueryPoly[0].Z = spos.Z + nz * 1.2f;
|
tempQueryPoly[0].Z = spos.Z + nz * 1.2f;
|
||||||
|
@ -408,8 +408,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtStatus FindRandomPointAroundCircle(DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f spos, RcVec3f epos, IDtQueryFilter filter, bool constrainByCircle, int count,
|
public DtStatus FindRandomPointAroundCircle(DtNavMeshQuery navQuery, long startRef, long endRef, Vector3 spos, Vector3 epos, IDtQueryFilter filter, bool constrainByCircle, int count,
|
||||||
ref List<RcVec3f> points)
|
ref List<Vector3> points)
|
||||||
{
|
{
|
||||||
if (startRef == 0 || endRef == 0)
|
if (startRef == 0 || endRef == 0)
|
||||||
{
|
{
|
||||||
|
@ -427,7 +427,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
var frand = new RcRand();
|
var frand = new RcRand();
|
||||||
int prevCnt = points.Count;
|
int prevCnt = points.Count;
|
||||||
|
|
||||||
points = new List<RcVec3f>();
|
points = new List<Vector3>();
|
||||||
while (0 < count && points.Count < prevCnt + count)
|
while (0 < count && points.Count < prevCnt + count)
|
||||||
{
|
{
|
||||||
var status = navQuery.FindRandomPointAroundCircle(startRef, spos, dist, filter, frand, constraint,
|
var status = navQuery.FindRandomPointAroundCircle(startRef, spos, dist, filter, frand, constraint,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Collections;
|
using DotRecast.Core.Collections;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour;
|
using DotRecast.Detour;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
using DotRecast.Recast.Toolset.Builder;
|
using DotRecast.Recast.Toolset.Builder;
|
||||||
|
@ -74,8 +75,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
Vector3 bmin = geom.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
Vector3 bmax = geom.GetMeshBoundsMax();
|
||||||
|
|
||||||
RcConfig cfg = new RcConfig(
|
RcConfig cfg = new RcConfig(
|
||||||
true, settings.tileSize, settings.tileSize,
|
true, settings.tileSize, settings.tileSize,
|
||||||
|
@ -112,7 +113,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool BuildTile(IInputGeomProvider geom, RcNavMeshBuildSettings settings, DtNavMesh navMesh, RcVec3f pos, out long tileBuildTicks, out int tileTriCount, out int tileMemUsage)
|
public bool BuildTile(IInputGeomProvider geom, RcNavMeshBuildSettings settings, DtNavMesh navMesh, Vector3 pos, out long tileBuildTicks, out int tileTriCount, out int tileMemUsage)
|
||||||
{
|
{
|
||||||
tileBuildTicks = 0;
|
tileBuildTicks = 0;
|
||||||
tileTriCount = 0;
|
tileTriCount = 0;
|
||||||
|
@ -123,8 +124,8 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
|
|
||||||
float ts = settings.tileSize * settings.cellSize;
|
float ts = settings.tileSize * settings.cellSize;
|
||||||
|
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
Vector3 bmin = geom.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
Vector3 bmax = geom.GetMeshBoundsMax();
|
||||||
|
|
||||||
int tx = (int)((pos.X - bmin.X) / ts);
|
int tx = (int)((pos.X - bmin.X) / ts);
|
||||||
int ty = (int)((pos.Z - bmin.Z) / ts);
|
int ty = (int)((pos.Z - bmin.Z) / ts);
|
||||||
|
@ -132,7 +133,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
return BuildTile(geom, settings, navMesh, tx, ty, out tileBuildTicks, out tileTriCount, out tileMemUsage);
|
return BuildTile(geom, settings, navMesh, tx, ty, out tileBuildTicks, out tileTriCount, out tileMemUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RemoveTile(IInputGeomProvider geom, RcNavMeshBuildSettings settings, DtNavMesh navMesh, RcVec3f pos)
|
public bool RemoveTile(IInputGeomProvider geom, RcNavMeshBuildSettings settings, DtNavMesh navMesh, Vector3 pos)
|
||||||
{
|
{
|
||||||
if (null == settings || null == geom || navMesh == null)
|
if (null == settings || null == geom || navMesh == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -5,12 +5,11 @@
|
||||||
<PackageId>DotRecast.Recast</PackageId>
|
<PackageId>DotRecast.Recast</PackageId>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Authors>ikpil</Authors>
|
<Authors>ikpil</Authors>
|
||||||
<Description>DotRecast - a port of Recast Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers</Description>
|
<Description>DotRecast - a port of Recast Detour, navigation mesh toolset for games, Unity3D, servers, C#</Description>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/ikpil/DotRecast</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
<RepositoryUrl>https://github.com/ikpil/DotRecast</RepositoryUrl>
|
||||||
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
<PackageTags>game gamedev ai csharp server unity navigation game-development unity3d pathfinding pathfinder recast detour navmesh crowd-simulation recastnavigation</PackageTags>
|
||||||
<PackageReleaseNotes>https://github.com/ikpil/DotRecast/blob/main/CHANGELOG.md</PackageReleaseNotes>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Geom
|
namespace DotRecast.Recast.Geom
|
||||||
{
|
{
|
||||||
public class BoundsItem
|
public class BoundsItem
|
||||||
{
|
{
|
||||||
public RcVec2f bmin;
|
public Vector2 bmin;
|
||||||
public RcVec2f bmax;
|
public Vector2 bmax;
|
||||||
public int i;
|
public int i;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,15 +21,16 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Geom
|
namespace DotRecast.Recast.Geom
|
||||||
{
|
{
|
||||||
public interface IInputGeomProvider
|
public interface IInputGeomProvider
|
||||||
{
|
{
|
||||||
RcTriMesh GetMesh();
|
RcTriMesh GetMesh();
|
||||||
RcVec3f GetMeshBoundsMin();
|
Vector3 GetMeshBoundsMin();
|
||||||
|
|
||||||
RcVec3f GetMeshBoundsMax();
|
Vector3 GetMeshBoundsMax();
|
||||||
|
|
||||||
IEnumerable<RcTriMesh> Meshes();
|
IEnumerable<RcTriMesh> Meshes();
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ namespace DotRecast.Recast.Geom
|
||||||
|
|
||||||
// off mesh connections
|
// off mesh connections
|
||||||
public List<RcOffMeshConnection> GetOffMeshConnections();
|
public List<RcOffMeshConnection> GetOffMeshConnections();
|
||||||
public void AddOffMeshConnection(RcVec3f start, RcVec3f end, float radius, bool bidir, int area, int flags);
|
public void AddOffMeshConnection(Vector3 start, Vector3 end, float radius, bool bidir, int area, int flags);
|
||||||
public void RemoveOffMeshConnections(Predicate<RcOffMeshConnection> filter);
|
public void RemoveOffMeshConnections(Predicate<RcOffMeshConnection> filter);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Geom
|
namespace DotRecast.Recast.Geom
|
||||||
{
|
{
|
||||||
|
@ -30,7 +31,7 @@ namespace DotRecast.Recast.Geom
|
||||||
private int ntris;
|
private int ntris;
|
||||||
private int maxTrisPerChunk;
|
private int maxTrisPerChunk;
|
||||||
|
|
||||||
private void CalcExtends(BoundsItem[] items, int imin, int imax, ref RcVec2f bmin, ref RcVec2f bmax)
|
private void CalcExtends(BoundsItem[] items, int imin, int imax, ref Vector2 bmin, ref Vector2 bmax)
|
||||||
{
|
{
|
||||||
bmin.X = items[imin].bmin.X;
|
bmin.X = items[imin].bmin.X;
|
||||||
bmin.Y = items[imin].bmin.Y;
|
bmin.Y = items[imin].bmin.Y;
|
||||||
|
@ -185,7 +186,7 @@ namespace DotRecast.Recast.Geom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckOverlapRect(float[] amin, float[] amax, RcVec2f bmin, RcVec2f bmax)
|
private bool CheckOverlapRect(float[] amin, float[] amax, Vector2 bmin, Vector2 bmax)
|
||||||
{
|
{
|
||||||
bool overlap = true;
|
bool overlap = true;
|
||||||
overlap = (amin[0] > bmax.X || amax[0] < bmin.X) ? false : overlap;
|
overlap = (amin[0] > bmax.X || amax[0] < bmin.X) ? false : overlap;
|
||||||
|
@ -222,7 +223,7 @@ namespace DotRecast.Recast.Geom
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RcChunkyTriMeshNode> GetChunksOverlappingSegment(RcVec2f p, RcVec2f q)
|
public List<RcChunkyTriMeshNode> GetChunksOverlappingSegment(Vector2 p, Vector2 q)
|
||||||
{
|
{
|
||||||
// Traverse tree
|
// Traverse tree
|
||||||
List<RcChunkyTriMeshNode> ids = new List<RcChunkyTriMeshNode>();
|
List<RcChunkyTriMeshNode> ids = new List<RcChunkyTriMeshNode>();
|
||||||
|
@ -251,13 +252,13 @@ namespace DotRecast.Recast.Geom
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckOverlapSegment(RcVec2f p, RcVec2f q, RcVec2f bmin, RcVec2f bmax)
|
private bool CheckOverlapSegment(Vector2 p, Vector2 q, Vector2 bmin, Vector2 bmax)
|
||||||
{
|
{
|
||||||
const float EPSILON = 1e-6f;
|
const float EPSILON = 1e-6f;
|
||||||
|
|
||||||
float tmin = 0;
|
float tmin = 0;
|
||||||
float tmax = 1;
|
float tmax = 1;
|
||||||
var d = new RcVec2f();
|
var d = new Vector2();
|
||||||
d.X = q.X - p.X;
|
d.X = q.X - p.X;
|
||||||
d.Y = q.Y - p.Y;
|
d.Y = q.Y - p.Y;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Geom
|
namespace DotRecast.Recast.Geom
|
||||||
{
|
{
|
||||||
public class RcChunkyTriMeshNode
|
public class RcChunkyTriMeshNode
|
||||||
{
|
{
|
||||||
public RcVec2f bmin;
|
public Vector2 bmin;
|
||||||
public RcVec2f bmax;
|
public Vector2 bmax;
|
||||||
public int i;
|
public int i;
|
||||||
public int[] tris;
|
public int[] tris;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Geom
|
namespace DotRecast.Recast.Geom
|
||||||
{
|
{
|
||||||
|
@ -33,7 +34,7 @@ namespace DotRecast.Recast.Geom
|
||||||
public readonly int flags;
|
public readonly int flags;
|
||||||
public readonly int userId;
|
public readonly int userId;
|
||||||
|
|
||||||
public RcOffMeshConnection(RcVec3f start, RcVec3f end, float radius, bool bidir, int area, int flags)
|
public RcOffMeshConnection(Vector3 start, Vector3 end, float radius, bool bidir, int area, int flags)
|
||||||
{
|
{
|
||||||
verts = new float[6];
|
verts = new float[6];
|
||||||
verts[0] = start.X;
|
verts[0] = start.X;
|
||||||
|
|
|
@ -23,6 +23,7 @@ using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Collections;
|
using DotRecast.Core.Collections;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Geom
|
namespace DotRecast.Recast.Geom
|
||||||
{
|
{
|
||||||
|
@ -31,8 +32,8 @@ namespace DotRecast.Recast.Geom
|
||||||
public readonly float[] vertices;
|
public readonly float[] vertices;
|
||||||
public readonly int[] faces;
|
public readonly int[] faces;
|
||||||
public readonly float[] normals;
|
public readonly float[] normals;
|
||||||
private RcVec3f bmin;
|
private Vector3 bmin;
|
||||||
private RcVec3f bmax;
|
private Vector3 bmax;
|
||||||
|
|
||||||
private readonly List<RcConvexVolume> volumes = new List<RcConvexVolume>();
|
private readonly List<RcConvexVolume> volumes = new List<RcConvexVolume>();
|
||||||
private readonly RcTriMesh _mesh;
|
private readonly RcTriMesh _mesh;
|
||||||
|
@ -93,12 +94,12 @@ namespace DotRecast.Recast.Geom
|
||||||
return _mesh;
|
return _mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f GetMeshBoundsMin()
|
public Vector3 GetMeshBoundsMin()
|
||||||
{
|
{
|
||||||
return bmin;
|
return bmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcVec3f GetMeshBoundsMax()
|
public Vector3 GetMeshBoundsMax()
|
||||||
{
|
{
|
||||||
return bmax;
|
return bmax;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +133,7 @@ namespace DotRecast.Recast.Geom
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddOffMeshConnection(RcVec3f start, RcVec3f end, float radius, bool bidir, int area, int flags)
|
public void AddOffMeshConnection(Vector3 start, Vector3 end, float radius, bool bidir, int area, int flags)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -150,8 +151,8 @@ namespace DotRecast.Recast.Geom
|
||||||
int v1 = faces[i + 1] * 3;
|
int v1 = faces[i + 1] * 3;
|
||||||
int v2 = faces[i + 2] * 3;
|
int v2 = faces[i + 2] * 3;
|
||||||
|
|
||||||
var e0 = new RcVec3f();
|
var e0 = new Vector3();
|
||||||
var e1 = new RcVec3f();
|
var e1 = new Vector3();
|
||||||
e0.X = vertices[v1 + 0] - vertices[v0 + 0];
|
e0.X = vertices[v1 + 0] - vertices[v0 + 0];
|
||||||
e0.Y = vertices[v1 + 1] - vertices[v0 + 1];
|
e0.Y = vertices[v1 + 1] - vertices[v0 + 1];
|
||||||
e0.Z = vertices[v1 + 2] - vertices[v0 + 2];
|
e0.Z = vertices[v1 + 2] - vertices[v0 + 2];
|
||||||
|
|
|
@ -22,6 +22,7 @@ using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Collections;
|
using DotRecast.Core.Collections;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
|
@ -44,7 +45,7 @@ namespace DotRecast.Recast
|
||||||
/// @param[in] erosionRadius The radius of erosion. [Limits: 0 < value < 255] [Units: vx]
|
/// @param[in] erosionRadius The radius of erosion. [Limits: 0 < value < 255] [Units: vx]
|
||||||
/// @param[in,out] compactHeightfield The populated compact heightfield to erode.
|
/// @param[in,out] compactHeightfield The populated compact heightfield to erode.
|
||||||
/// @returns True if the operation completed successfully.
|
/// @returns True if the operation completed successfully.
|
||||||
public static void ErodeWalkableArea(RcContext context, int erosionRadius, RcCompactHeightfield compactHeightfield)
|
public static void ErodeWalkableArea(RcTelemetry context, int erosionRadius, RcCompactHeightfield compactHeightfield)
|
||||||
{
|
{
|
||||||
int xSize = compactHeightfield.width;
|
int xSize = compactHeightfield.width;
|
||||||
int zSize = compactHeightfield.height;
|
int zSize = compactHeightfield.height;
|
||||||
|
@ -261,7 +262,7 @@ namespace DotRecast.Recast
|
||||||
/// @param[in,out] context The build context to use during the operation.
|
/// @param[in,out] context The build context to use during the operation.
|
||||||
/// @param[in,out] compactHeightfield A populated compact heightfield.
|
/// @param[in,out] compactHeightfield A populated compact heightfield.
|
||||||
/// @returns True if the operation completed successfully.
|
/// @returns True if the operation completed successfully.
|
||||||
public static bool MedianFilterWalkableArea(RcContext context, RcCompactHeightfield compactHeightfield)
|
public static bool MedianFilterWalkableArea(RcTelemetry context, RcCompactHeightfield compactHeightfield)
|
||||||
{
|
{
|
||||||
int xSize = compactHeightfield.width;
|
int xSize = compactHeightfield.width;
|
||||||
int zSize = compactHeightfield.height;
|
int zSize = compactHeightfield.height;
|
||||||
|
@ -344,7 +345,7 @@ namespace DotRecast.Recast
|
||||||
/// @param[in] boxMaxBounds The maximum extents of the bounding box. [(x, y, z)] [Units: wu]
|
/// @param[in] boxMaxBounds The maximum extents of the bounding box. [(x, y, z)] [Units: wu]
|
||||||
/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
|
/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
|
||||||
/// @param[in,out] compactHeightfield A populated compact heightfield.
|
/// @param[in,out] compactHeightfield A populated compact heightfield.
|
||||||
public static void MarkBoxArea(RcContext context, float[] boxMinBounds, float[] boxMaxBounds, RcAreaModification areaId, RcCompactHeightfield compactHeightfield)
|
public static void MarkBoxArea(RcTelemetry context, float[] boxMinBounds, float[] boxMaxBounds, RcAreaModification areaId, RcCompactHeightfield compactHeightfield)
|
||||||
{
|
{
|
||||||
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_MARK_BOX_AREA);
|
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_MARK_BOX_AREA);
|
||||||
|
|
||||||
|
@ -446,7 +447,7 @@ namespace DotRecast.Recast
|
||||||
/// @param[in] maxY The height of the top of the polygon. [Units: wu]
|
/// @param[in] maxY The height of the top of the polygon. [Units: wu]
|
||||||
/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
|
/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
|
||||||
/// @param[in,out] compactHeightfield A populated compact heightfield.
|
/// @param[in,out] compactHeightfield A populated compact heightfield.
|
||||||
public static void MarkConvexPolyArea(RcContext context, float[] verts,
|
public static void MarkConvexPolyArea(RcTelemetry context, float[] verts,
|
||||||
float minY, float maxY, RcAreaModification areaId,
|
float minY, float maxY, RcAreaModification areaId,
|
||||||
RcCompactHeightfield compactHeightfield)
|
RcCompactHeightfield compactHeightfield)
|
||||||
{
|
{
|
||||||
|
@ -457,8 +458,8 @@ namespace DotRecast.Recast
|
||||||
int zStride = xSize; // For readability
|
int zStride = xSize; // For readability
|
||||||
|
|
||||||
// Compute the bounding box of the polygon
|
// Compute the bounding box of the polygon
|
||||||
RcVec3f bmin = RcVecUtils.Create(verts);
|
Vector3 bmin = RcVecUtils.Create(verts);
|
||||||
RcVec3f bmax = RcVecUtils.Create(verts);
|
Vector3 bmax = RcVecUtils.Create(verts);
|
||||||
for (int i = 3; i < verts.Length; i += 3)
|
for (int i = 3; i < verts.Length; i += 3)
|
||||||
{
|
{
|
||||||
bmin = RcVecUtils.Min(bmin, verts, i);
|
bmin = RcVecUtils.Min(bmin, verts, i);
|
||||||
|
@ -539,7 +540,7 @@ namespace DotRecast.Recast
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f point = new RcVec3f(
|
Vector3 point = new Vector3(
|
||||||
compactHeightfield.bmin.X + (x + 0.5f) * compactHeightfield.cs,
|
compactHeightfield.bmin.X + (x + 0.5f) * compactHeightfield.cs,
|
||||||
0,
|
0,
|
||||||
compactHeightfield.bmin.Z + (z + 0.5f) * compactHeightfield.cs
|
compactHeightfield.bmin.Z + (z + 0.5f) * compactHeightfield.cs
|
||||||
|
@ -567,7 +568,7 @@ namespace DotRecast.Recast
|
||||||
/// @param[in] height The height of the cylinder. [Units: wu] [Limit: > 0]
|
/// @param[in] height The height of the cylinder. [Units: wu] [Limit: > 0]
|
||||||
/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
|
/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
|
||||||
/// @param[in,out] compactHeightfield A populated compact heightfield.
|
/// @param[in,out] compactHeightfield A populated compact heightfield.
|
||||||
public static void MarkCylinderArea(RcContext context, float[] position, float radius, float height,
|
public static void MarkCylinderArea(RcTelemetry context, float[] position, float radius, float height,
|
||||||
RcAreaModification areaId, RcCompactHeightfield compactHeightfield)
|
RcAreaModification areaId, RcCompactHeightfield compactHeightfield)
|
||||||
{
|
{
|
||||||
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_MARK_CYLINDER_AREA);
|
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_MARK_CYLINDER_AREA);
|
||||||
|
@ -577,13 +578,13 @@ namespace DotRecast.Recast
|
||||||
int zStride = xSize; // For readability
|
int zStride = xSize; // For readability
|
||||||
|
|
||||||
// Compute the bounding box of the cylinder
|
// Compute the bounding box of the cylinder
|
||||||
RcVec3f cylinderBBMin = new RcVec3f(
|
Vector3 cylinderBBMin = new Vector3(
|
||||||
position[0] - radius,
|
position[0] - radius,
|
||||||
position[1],
|
position[1],
|
||||||
position[2] - radius
|
position[2] - radius
|
||||||
);
|
);
|
||||||
|
|
||||||
RcVec3f cylinderBBMax = new RcVec3f(
|
Vector3 cylinderBBMax = new Vector3(
|
||||||
position[0] + radius,
|
position[0] + radius,
|
||||||
position[1] + height,
|
position[1] + height,
|
||||||
position[2] + radius
|
position[2] + radius
|
||||||
|
@ -679,7 +680,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public static bool PointInPoly(float[] verts, RcVec3f p)
|
// public static bool PointInPoly(float[] verts, Vector3 p)
|
||||||
// {
|
// {
|
||||||
// bool c = false;
|
// bool c = false;
|
||||||
// int i, j;
|
// int i, j;
|
||||||
|
@ -703,13 +704,13 @@ namespace DotRecast.Recast
|
||||||
/// @param[in] verts The polygon vertices
|
/// @param[in] verts The polygon vertices
|
||||||
/// @param[in] point The point to check
|
/// @param[in] point The point to check
|
||||||
/// @returns true if the point lies within the polygon, false otherwise.
|
/// @returns true if the point lies within the polygon, false otherwise.
|
||||||
public static bool PointInPoly(float[] verts, RcVec3f point)
|
public static bool PointInPoly(float[] verts, Vector3 point)
|
||||||
{
|
{
|
||||||
bool inPoly = false;
|
bool inPoly = false;
|
||||||
for (int i = 0, j = verts.Length / 3 - 1; i < verts.Length / 3; j = i++)
|
for (int i = 0, j = verts.Length / 3 - 1; i < verts.Length / 3; j = i++)
|
||||||
{
|
{
|
||||||
RcVec3f vi = new RcVec3f(verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]);
|
Vector3 vi = new Vector3(verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]);
|
||||||
RcVec3f vj = new RcVec3f(verts[j * 3], verts[j * 3 + 1], verts[j * 3 + 2]);
|
Vector3 vj = new Vector3(verts[j * 3], verts[j * 3 + 1], verts[j * 3 + 2]);
|
||||||
if (vi.Z > point.Z == vj.Z > point.Z)
|
if (vi.Z > point.Z == vj.Z > point.Z)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -753,17 +754,17 @@ namespace DotRecast.Recast
|
||||||
int vertIndexB = vertIndex;
|
int vertIndexB = vertIndex;
|
||||||
int vertIndexC = (vertIndex + 1) % numVerts;
|
int vertIndexC = (vertIndex + 1) % numVerts;
|
||||||
|
|
||||||
RcVec3f vertA = RcVecUtils.Create(verts, vertIndexA * 3);
|
Vector3 vertA = RcVecUtils.Create(verts, vertIndexA * 3);
|
||||||
RcVec3f vertB = RcVecUtils.Create(verts, vertIndexB * 3);
|
Vector3 vertB = RcVecUtils.Create(verts, vertIndexB * 3);
|
||||||
RcVec3f vertC = RcVecUtils.Create(verts, vertIndexC * 3);
|
Vector3 vertC = RcVecUtils.Create(verts, vertIndexC * 3);
|
||||||
|
|
||||||
// From A to B on the x/z plane
|
// From A to B on the x/z plane
|
||||||
RcVec3f prevSegmentDir = RcVec3f.Subtract(vertB, vertA);
|
Vector3 prevSegmentDir = Vector3.Subtract(vertB, vertA);
|
||||||
prevSegmentDir.Y = 0; // Squash onto x/z plane
|
prevSegmentDir.Y = 0; // Squash onto x/z plane
|
||||||
prevSegmentDir = RcVecUtils.SafeNormalize(prevSegmentDir);
|
prevSegmentDir = RcVecUtils.SafeNormalize(prevSegmentDir);
|
||||||
|
|
||||||
// From B to C on the x/z plane
|
// From B to C on the x/z plane
|
||||||
RcVec3f currSegmentDir = RcVec3f.Subtract(vertC, vertB);
|
Vector3 currSegmentDir = Vector3.Subtract(vertC, vertB);
|
||||||
currSegmentDir.Y = 0; // Squash onto x/z plane
|
currSegmentDir.Y = 0; // Squash onto x/z plane
|
||||||
currSegmentDir = RcVecUtils.SafeNormalize(currSegmentDir);
|
currSegmentDir = RcVecUtils.SafeNormalize(currSegmentDir);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace DotRecast.Recast
|
|
||||||
{
|
|
||||||
public static class RcAxis
|
|
||||||
{
|
|
||||||
public const int RC_AXIS_X = 0;
|
|
||||||
public const int RC_AXIS_Y = 1;
|
|
||||||
public const int RC_AXIS_Z = 2;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -24,6 +24,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
|
@ -47,8 +48,8 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
public List<RcBuilderResult> BuildTiles(IInputGeomProvider geom, RcConfig cfg, TaskFactory taskFactory)
|
public List<RcBuilderResult> BuildTiles(IInputGeomProvider geom, RcConfig cfg, TaskFactory taskFactory)
|
||||||
{
|
{
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
Vector3 bmin = geom.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
Vector3 bmax = geom.GetMeshBoundsMax();
|
||||||
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
|
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
|
||||||
List<RcBuilderResult> results = new List<RcBuilderResult>();
|
List<RcBuilderResult> results = new List<RcBuilderResult>();
|
||||||
if (null != taskFactory)
|
if (null != taskFactory)
|
||||||
|
@ -66,8 +67,8 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
public Task BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, int threads, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
|
public Task BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, int threads, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
Vector3 bmin = geom.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
Vector3 bmax = geom.GetMeshBoundsMax();
|
||||||
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
|
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
|
||||||
Task task;
|
Task task;
|
||||||
if (1 < threads)
|
if (1 < threads)
|
||||||
|
@ -82,7 +83,7 @@ namespace DotRecast.Recast
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task BuildSingleThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax,
|
private Task BuildSingleThreadAsync(IInputGeomProvider geom, RcConfig cfg, Vector3 bmin, Vector3 bmax,
|
||||||
int tw, int th, List<RcBuilderResult> results)
|
int tw, int th, List<RcBuilderResult> results)
|
||||||
{
|
{
|
||||||
RcAtomicInteger counter = new RcAtomicInteger(0);
|
RcAtomicInteger counter = new RcAtomicInteger(0);
|
||||||
|
@ -97,7 +98,7 @@ namespace DotRecast.Recast
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task BuildMultiThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax,
|
private Task BuildMultiThreadAsync(IInputGeomProvider geom, RcConfig cfg, Vector3 bmin, Vector3 bmax,
|
||||||
int tw, int th, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
|
int tw, int th, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
RcAtomicInteger counter = new RcAtomicInteger(0);
|
RcAtomicInteger counter = new RcAtomicInteger(0);
|
||||||
|
@ -147,7 +148,7 @@ namespace DotRecast.Recast
|
||||||
return Task.WhenAll(tasks.ToArray());
|
return Task.WhenAll(tasks.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx,
|
public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, Vector3 bmin, Vector3 bmax, int tx,
|
||||||
int ty, RcAtomicInteger counter, int total)
|
int ty, RcAtomicInteger counter, int total)
|
||||||
{
|
{
|
||||||
RcBuilderResult result = Build(geom, new RcBuilderConfig(cfg, bmin, bmax, tx, ty));
|
RcBuilderResult result = Build(geom, new RcBuilderConfig(cfg, bmin, bmax, tx, ty));
|
||||||
|
@ -162,50 +163,62 @@ namespace DotRecast.Recast
|
||||||
public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig builderCfg)
|
public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig builderCfg)
|
||||||
{
|
{
|
||||||
RcConfig cfg = builderCfg.cfg;
|
RcConfig cfg = builderCfg.cfg;
|
||||||
RcContext ctx = new RcContext();
|
RcTelemetry ctx = new RcTelemetry();
|
||||||
//
|
//
|
||||||
// Step 1. Rasterize input polygon soup.
|
// Step 1. Rasterize input polygon soup.
|
||||||
//
|
//
|
||||||
RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, builderCfg);
|
RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(geom, builderCfg, ctx);
|
||||||
return Build(ctx, builderCfg.tileX, builderCfg.tileZ, geom, cfg, solid);
|
return Build(builderCfg.tileX, builderCfg.tileZ, geom, cfg, solid, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcBuilderResult Build(RcContext ctx, int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid)
|
public RcBuilderResult Build(int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
FilterHeightfield(ctx, solid, cfg);
|
FilterHeightfield(solid, cfg, ctx);
|
||||||
RcCompactHeightfield chf = BuildCompactHeightfield(ctx, geom, cfg, solid);
|
RcCompactHeightfield chf = BuildCompactHeightfield(geom, cfg, ctx, solid);
|
||||||
|
|
||||||
// Partition the heightfield so that we can use simple algorithm later to triangulate the walkable areas.
|
// Partition the heightfield so that we can use simple algorithm later
|
||||||
|
// to triangulate the walkable areas.
|
||||||
// There are 3 partitioning methods, each with some pros and cons:
|
// There are 3 partitioning methods, each with some pros and cons:
|
||||||
// 1) Watershed partitioning
|
// 1) Watershed partitioning
|
||||||
// - the classic Recast partitioning
|
// - the classic Recast partitioning
|
||||||
// - creates the nicest tessellation
|
// - creates the nicest tessellation
|
||||||
// - usually slowest
|
// - usually slowest
|
||||||
// - partitions the heightfield into nice regions without holes or overlaps
|
// - partitions the heightfield into nice regions without holes or
|
||||||
// - the are some corner cases where this method creates produces holes and overlaps
|
// overlaps
|
||||||
// - holes may appear when a small obstacles is close to large open area (triangulation can handle this)
|
// - the are some corner cases where this method creates produces holes
|
||||||
// - overlaps may occur if you have narrow spiral corridors (i.e stairs), this make triangulation to fail
|
// and overlaps
|
||||||
// * generally the best choice if you precompute the navmesh, use this if you have large open areas
|
// - holes may appear when a small obstacles is close to large open area
|
||||||
// 2) Monotone partitioning
|
// (triangulation can handle this)
|
||||||
// - fastest
|
// - overlaps may occur if you have narrow spiral corridors (i.e
|
||||||
// - partitions the heightfield into regions without holes and overlaps (guaranteed)
|
// stairs), this make triangulation to fail
|
||||||
// - creates long thin polygons, which sometimes causes paths with detours
|
// * generally the best choice if you precompute the navmesh, use this
|
||||||
// * use this if you want fast navmesh generation
|
// if you have large open areas
|
||||||
|
// 2) Monotone partioning
|
||||||
|
// - fastest
|
||||||
|
// - partitions the heightfield into regions without holes and overlaps
|
||||||
|
// (guaranteed)
|
||||||
|
// - creates long thin polygons, which sometimes causes paths with
|
||||||
|
// detours
|
||||||
|
// * use this if you want fast navmesh generation
|
||||||
// 3) Layer partitoining
|
// 3) Layer partitoining
|
||||||
// - quite fast
|
// - quite fast
|
||||||
// - partitions the heighfield into non-overlapping regions
|
// - partitions the heighfield into non-overlapping regions
|
||||||
// - relies on the triangulation code to cope with holes (thus slower than monotone partitioning)
|
// - relies on the triangulation code to cope with holes (thus slower
|
||||||
// - produces better triangles than monotone partitioning
|
// than monotone partitioning)
|
||||||
// - does not have the corner cases of watershed partitioning
|
// - produces better triangles than monotone partitioning
|
||||||
// - can be slow and create a bit ugly tessellation (still better than monotone)
|
// - does not have the corner cases of watershed partitioning
|
||||||
// if you have large open areas with small obstacles (not a problem if you use tiles)
|
// - can be slow and create a bit ugly tessellation (still better than
|
||||||
// * good choice to use for tiled navmesh with medium and small sized tiles
|
// monotone)
|
||||||
|
// if you have large open areas with small obstacles (not a problem if
|
||||||
|
// you use tiles)
|
||||||
|
// * good choice to use for tiled navmesh with medium and small sized
|
||||||
|
// tiles
|
||||||
|
|
||||||
if (cfg.Partition == RcPartitionType.WATERSHED.Value)
|
if (cfg.Partition == RcPartitionType.WATERSHED.Value)
|
||||||
{
|
{
|
||||||
// Prepare for region partitioning, by calculating distance field along the walkable surface.
|
// Prepare for region partitioning, by calculating distance field
|
||||||
|
// along the walkable surface.
|
||||||
RcRegions.BuildDistanceField(ctx, chf);
|
RcRegions.BuildDistanceField(ctx, chf);
|
||||||
|
|
||||||
// Partition the walkable surface into simple regions without holes.
|
// Partition the walkable surface into simple regions without holes.
|
||||||
RcRegions.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea);
|
RcRegions.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea);
|
||||||
}
|
}
|
||||||
|
@ -247,7 +260,7 @@ namespace DotRecast.Recast
|
||||||
/*
|
/*
|
||||||
* Step 2. Filter walkable surfaces.
|
* Step 2. Filter walkable surfaces.
|
||||||
*/
|
*/
|
||||||
private void FilterHeightfield(RcContext ctx, RcHeightfield solid, RcConfig cfg)
|
private void FilterHeightfield(RcHeightfield solid, RcConfig cfg, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
// Once all geometry is rasterized, we do initial pass of filtering to
|
// Once all geometry is rasterized, we do initial pass of filtering to
|
||||||
// remove unwanted overhangs caused by the conservative rasterization
|
// remove unwanted overhangs caused by the conservative rasterization
|
||||||
|
@ -271,7 +284,7 @@ namespace DotRecast.Recast
|
||||||
/*
|
/*
|
||||||
* Step 3. Partition walkable surface to simple regions.
|
* Step 3. Partition walkable surface to simple regions.
|
||||||
*/
|
*/
|
||||||
private RcCompactHeightfield BuildCompactHeightfield(RcContext ctx, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid)
|
private RcCompactHeightfield BuildCompactHeightfield(IInputGeomProvider geom, RcConfig cfg, RcTelemetry ctx, RcHeightfield solid)
|
||||||
{
|
{
|
||||||
// Compact the heightfield so that it is faster to handle from now on.
|
// Compact the heightfield so that it is faster to handle from now on.
|
||||||
// This will result more cache coherent data as well as the neighbours
|
// This will result more cache coherent data as well as the neighbours
|
||||||
|
@ -294,13 +307,11 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
public RcHeightfieldLayerSet BuildLayers(IInputGeomProvider geom, RcBuilderConfig builderCfg)
|
public RcHeightfieldLayerSet BuildLayers(IInputGeomProvider geom, RcBuilderConfig builderCfg)
|
||||||
{
|
{
|
||||||
RcContext ctx = new RcContext();
|
RcTelemetry ctx = new RcTelemetry();
|
||||||
RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, builderCfg);
|
RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(geom, builderCfg, ctx);
|
||||||
FilterHeightfield(ctx, solid, builderCfg.cfg);
|
FilterHeightfield(solid, builderCfg.cfg, ctx);
|
||||||
RcCompactHeightfield chf = BuildCompactHeightfield(ctx, geom, builderCfg.cfg, solid);
|
RcCompactHeightfield chf = BuildCompactHeightfield(geom, builderCfg.cfg, ctx, solid);
|
||||||
|
return RcLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.WalkableHeight);
|
||||||
RcLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.BorderSize, builderCfg.cfg.WalkableHeight, out var lset);
|
|
||||||
return lset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
|
@ -36,16 +37,16 @@ namespace DotRecast.Recast
|
||||||
public readonly int height;
|
public readonly int height;
|
||||||
|
|
||||||
/** The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu] **/
|
/** The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu] **/
|
||||||
public readonly RcVec3f bmin = new RcVec3f();
|
public readonly Vector3 bmin = new Vector3();
|
||||||
|
|
||||||
/** The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] **/
|
/** The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] **/
|
||||||
public readonly RcVec3f bmax = new RcVec3f();
|
public readonly Vector3 bmax = new Vector3();
|
||||||
|
|
||||||
public RcBuilderConfig(RcConfig cfg, RcVec3f bmin, RcVec3f bmax) : this(cfg, bmin, bmax, 0, 0)
|
public RcBuilderConfig(RcConfig cfg, Vector3 bmin, Vector3 bmax) : this(cfg, bmin, bmax, 0, 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcBuilderConfig(RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tileX, int tileZ)
|
public RcBuilderConfig(RcConfig cfg, Vector3 bmin, Vector3 bmax, int tileX, int tileZ)
|
||||||
{
|
{
|
||||||
this.tileX = tileX;
|
this.tileX = tileX;
|
||||||
this.tileZ = tileZ;
|
this.tileZ = tileZ;
|
||||||
|
|
|
@ -12,9 +12,9 @@ namespace DotRecast.Recast
|
||||||
private readonly RcPolyMesh pmesh;
|
private readonly RcPolyMesh pmesh;
|
||||||
private readonly RcPolyMeshDetail dmesh;
|
private readonly RcPolyMeshDetail dmesh;
|
||||||
private readonly RcHeightfield solid;
|
private readonly RcHeightfield solid;
|
||||||
private readonly RcContext _context;
|
private readonly RcTelemetry telemetry;
|
||||||
|
|
||||||
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 solid, RcCompactHeightfield chf, RcContourSet cs, RcPolyMesh pmesh, RcPolyMeshDetail dmesh, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
this.tileX = tileX;
|
this.tileX = tileX;
|
||||||
this.tileZ = tileZ;
|
this.tileZ = tileZ;
|
||||||
|
@ -23,7 +23,7 @@ namespace DotRecast.Recast
|
||||||
this.cs = cs;
|
this.cs = cs;
|
||||||
this.pmesh = pmesh;
|
this.pmesh = pmesh;
|
||||||
this.dmesh = dmesh;
|
this.dmesh = dmesh;
|
||||||
_context = ctx;
|
telemetry = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcPolyMesh GetMesh()
|
public RcPolyMesh GetMesh()
|
||||||
|
@ -51,9 +51,9 @@ namespace DotRecast.Recast
|
||||||
return solid;
|
return solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcContext GetTelemetry()
|
public RcTelemetry GetTelemetry()
|
||||||
{
|
{
|
||||||
return _context;
|
return telemetry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
|
@ -98,14 +99,14 @@ namespace DotRecast.Recast
|
||||||
// Calculate bounding box.
|
// Calculate bounding box.
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CalcGridSize(RcVec3f bmin, RcVec3f bmax, float cs, out int sizeX, out int sizeZ)
|
public static void CalcGridSize(Vector3 bmin, Vector3 bmax, float cs, out int sizeX, out int sizeZ)
|
||||||
{
|
{
|
||||||
sizeX = (int)((bmax.X - bmin.X) / cs + 0.5f);
|
sizeX = (int)((bmax.X - bmin.X) / cs + 0.5f);
|
||||||
sizeZ = (int)((bmax.Z - bmin.Z) / cs + 0.5f);
|
sizeZ = (int)((bmax.Z - bmin.Z) / cs + 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void CalcTileCount(RcVec3f bmin, RcVec3f bmax, float cs, int tileSizeX, int tileSizeZ, out int tw, out int td)
|
public static void CalcTileCount(Vector3 bmin, Vector3 bmax, float cs, int tileSizeX, int tileSizeZ, out int tw, out int td)
|
||||||
{
|
{
|
||||||
CalcGridSize(bmin, bmax, cs, out var gw, out var gd);
|
CalcGridSize(bmin, bmax, cs, out var gw, out var gd);
|
||||||
tw = (gw + tileSizeX - 1) / tileSizeX;
|
tw = (gw + tileSizeX - 1) / tileSizeX;
|
||||||
|
@ -119,11 +120,11 @@ namespace DotRecast.Recast
|
||||||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
///
|
///
|
||||||
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
|
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
|
||||||
public static int[] MarkWalkableTriangles(RcContext ctx, float walkableSlopeAngle, float[] verts, int[] tris, int nt, RcAreaModification areaMod)
|
public static int[] MarkWalkableTriangles(RcTelemetry ctx, float walkableSlopeAngle, float[] verts, int[] tris, int nt, RcAreaModification areaMod)
|
||||||
{
|
{
|
||||||
int[] areas = new int[nt];
|
int[] areas = new int[nt];
|
||||||
float walkableThr = MathF.Cos(walkableSlopeAngle / 180.0f * MathF.PI);
|
float walkableThr = MathF.Cos(walkableSlopeAngle / 180.0f * MathF.PI);
|
||||||
RcVec3f norm = new RcVec3f();
|
Vector3 norm = new Vector3();
|
||||||
for (int i = 0; i < nt; ++i)
|
for (int i = 0; i < nt; ++i)
|
||||||
{
|
{
|
||||||
int tri = i * 3;
|
int tri = i * 3;
|
||||||
|
@ -136,12 +137,12 @@ namespace DotRecast.Recast
|
||||||
return areas;
|
return areas;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CalcTriNormal(float[] verts, int v0, int v1, int v2, ref RcVec3f norm)
|
public static void CalcTriNormal(float[] verts, int v0, int v1, int v2, ref Vector3 norm)
|
||||||
{
|
{
|
||||||
var e0 = RcVecUtils.Subtract(verts, v1 * 3, v0 * 3);
|
var e0 = RcVecUtils.Subtract(verts, v1 * 3, v0 * 3);
|
||||||
var e1 = RcVecUtils.Subtract(verts, v2 * 3, v0 * 3);
|
var e1 = RcVecUtils.Subtract(verts, v2 * 3, v0 * 3);
|
||||||
norm = RcVec3f.Cross(e0, e1);
|
norm = Vector3.Cross(e0, e1);
|
||||||
norm = RcVec3f.Normalize(norm);
|
norm = Vector3.Normalize(norm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,11 +154,11 @@ namespace DotRecast.Recast
|
||||||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
///
|
///
|
||||||
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
|
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
|
||||||
public static void ClearUnwalkableTriangles(RcContext ctx, float walkableSlopeAngle, float[] verts, int nv, int[] tris, int nt, int[] areas)
|
public static void ClearUnwalkableTriangles(RcTelemetry ctx, float walkableSlopeAngle, float[] verts, int nv, int[] tris, int nt, int[] areas)
|
||||||
{
|
{
|
||||||
float walkableThr = MathF.Cos(walkableSlopeAngle / 180.0f * MathF.PI);
|
float walkableThr = MathF.Cos(walkableSlopeAngle / 180.0f * MathF.PI);
|
||||||
|
|
||||||
RcVec3f norm = new RcVec3f();
|
Vector3 norm = new Vector3();
|
||||||
|
|
||||||
for (int i = 0; i < nt; ++i)
|
for (int i = 0; i < nt; ++i)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
|
@ -50,10 +51,10 @@ namespace DotRecast.Recast
|
||||||
public int maxRegions;
|
public int maxRegions;
|
||||||
|
|
||||||
/** The minimum bounds in world space. [(x, y, z)] */
|
/** The minimum bounds in world space. [(x, y, z)] */
|
||||||
public RcVec3f bmin = new RcVec3f();
|
public Vector3 bmin = new Vector3();
|
||||||
|
|
||||||
/** The maximum bounds in world space. [(x, y, z)] */
|
/** The maximum bounds in world space. [(x, y, z)] */
|
||||||
public RcVec3f bmax = new RcVec3f();
|
public Vector3 bmax = new Vector3();
|
||||||
|
|
||||||
/** The size of each cell. (On the xz-plane.) */
|
/** The size of each cell. (On the xz-plane.) */
|
||||||
public float cs;
|
public float cs;
|
||||||
|
|
|
@ -30,13 +30,10 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
public static class RcCompacts
|
public static class RcCompacts
|
||||||
{
|
{
|
||||||
private const int MAX_HEIGHT = RcConstants.RC_SPAN_MAX_HEIGHT;
|
private const int MAX_LAYERS = RC_NOT_CONNECTED - 1;
|
||||||
|
private const int MAX_HEIGHT = RcConstants.SPAN_MAX_HEIGHT;
|
||||||
|
|
||||||
/// @}
|
/// @par
|
||||||
/// @name Compact Heightfield Functions
|
|
||||||
/// @see rcCompactHeightfield
|
|
||||||
/// @{
|
|
||||||
/// Builds a compact heightfield representing open space, from a heightfield representing solid space.
|
|
||||||
///
|
///
|
||||||
/// This is just the beginning of the process of fully building a compact heightfield.
|
/// This is just the beginning of the process of fully building a compact heightfield.
|
||||||
/// Various filters may be applied, then the distance field and regions built.
|
/// Various filters may be applied, then the distance field and regions built.
|
||||||
|
@ -45,41 +42,31 @@ namespace DotRecast.Recast
|
||||||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
///
|
///
|
||||||
/// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig
|
/// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig
|
||||||
/// @ingroup recast
|
public static RcCompactHeightfield BuildCompactHeightfield(RcTelemetry ctx, int walkableHeight, int walkableClimb, RcHeightfield hf)
|
||||||
///
|
|
||||||
/// @param[in,out] context The build context to use during the operation.
|
|
||||||
/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area
|
|
||||||
/// to be considered walkable. [Limit: >= 3] [Units: vx]
|
|
||||||
/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
|
|
||||||
/// [Limit: >=0] [Units: vx]
|
|
||||||
/// @param[in] heightfield The heightfield to be compacted.
|
|
||||||
/// @param[out] compactHeightfield The resulting compact heightfield. (Must be pre-allocated.)
|
|
||||||
/// @returns True if the operation completed successfully.
|
|
||||||
public static RcCompactHeightfield BuildCompactHeightfield(RcContext context, int walkableHeight, int walkableClimb, RcHeightfield heightfield)
|
|
||||||
{
|
{
|
||||||
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
|
||||||
|
|
||||||
int xSize = heightfield.width;
|
RcCompactHeightfield chf = new RcCompactHeightfield();
|
||||||
int zSize = heightfield.height;
|
int w = hf.width;
|
||||||
int spanCount = GetHeightFieldSpanCount(context, heightfield);
|
int h = hf.height;
|
||||||
|
int spanCount = GetHeightFieldSpanCount(hf);
|
||||||
|
|
||||||
// Fill in header.
|
// Fill in header.
|
||||||
RcCompactHeightfield compactHeightfield = new RcCompactHeightfield();
|
chf.width = w;
|
||||||
compactHeightfield.width = xSize;
|
chf.height = h;
|
||||||
compactHeightfield.height = zSize;
|
chf.borderSize = hf.borderSize;
|
||||||
compactHeightfield.borderSize = heightfield.borderSize;
|
chf.spanCount = spanCount;
|
||||||
compactHeightfield.spanCount = spanCount;
|
chf.walkableHeight = walkableHeight;
|
||||||
compactHeightfield.walkableHeight = walkableHeight;
|
chf.walkableClimb = walkableClimb;
|
||||||
compactHeightfield.walkableClimb = walkableClimb;
|
chf.maxRegions = 0;
|
||||||
compactHeightfield.maxRegions = 0;
|
chf.bmin = hf.bmin;
|
||||||
compactHeightfield.bmin = heightfield.bmin;
|
chf.bmax = hf.bmax;
|
||||||
compactHeightfield.bmax = heightfield.bmax;
|
chf.bmax.Y += walkableHeight * hf.ch;
|
||||||
compactHeightfield.bmax.Y += walkableHeight * heightfield.ch;
|
chf.cs = hf.cs;
|
||||||
compactHeightfield.cs = heightfield.cs;
|
chf.ch = hf.ch;
|
||||||
compactHeightfield.ch = heightfield.ch;
|
chf.cells = new RcCompactCell[w * h];
|
||||||
compactHeightfield.cells = new RcCompactCell[xSize * zSize];
|
|
||||||
//chf.spans = new RcCompactSpan[spanCount];
|
//chf.spans = new RcCompactSpan[spanCount];
|
||||||
compactHeightfield.areas = new int[spanCount];
|
chf.areas = new int[spanCount];
|
||||||
|
|
||||||
var tempSpans = Enumerable
|
var tempSpans = Enumerable
|
||||||
.Range(0, spanCount)
|
.Range(0, spanCount)
|
||||||
|
@ -87,81 +74,80 @@ namespace DotRecast.Recast
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
// Fill in cells and spans.
|
// Fill in cells and spans.
|
||||||
int currentCellIndex = 0;
|
int idx = 0;
|
||||||
int numColumns = xSize * zSize;
|
for (int y = 0; y < h; ++y)
|
||||||
for (int columnIndex = 0; columnIndex < numColumns; ++columnIndex)
|
|
||||||
{
|
{
|
||||||
RcSpan span = heightfield.spans[columnIndex];
|
for (int x = 0; x < w; ++x)
|
||||||
|
|
||||||
// If there are no spans at this cell, just leave the data to index=0, count=0.
|
|
||||||
if (span == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int tmpIdx = currentCellIndex;
|
|
||||||
int tmpCount = 0;
|
|
||||||
for (; span != null; span = span.next)
|
|
||||||
{
|
{
|
||||||
if (span.area != RC_NULL_AREA)
|
RcSpan s = hf.spans[x + y * w];
|
||||||
{
|
// If there are no spans at this cell, just leave the data to index=0, count=0.
|
||||||
int bot = span.smax;
|
if (s == null)
|
||||||
int top = span.next != null ? (int)span.next.smin : MAX_HEIGHT;
|
continue;
|
||||||
tempSpans[currentCellIndex].y = Math.Clamp(bot, 0, MAX_HEIGHT);
|
|
||||||
tempSpans[currentCellIndex].h = Math.Clamp(top - bot, 0, MAX_HEIGHT);
|
|
||||||
compactHeightfield.areas[currentCellIndex] = span.area;
|
|
||||||
currentCellIndex++;
|
|
||||||
tmpCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compactHeightfield.cells[columnIndex] = new RcCompactCell(tmpIdx, tmpCount);
|
int tmpIdx = idx;
|
||||||
|
int tmpCount = 0;
|
||||||
|
while (s != null)
|
||||||
|
{
|
||||||
|
if (s.area != RC_NULL_AREA)
|
||||||
|
{
|
||||||
|
int bot = s.smax;
|
||||||
|
int top = s.next != null ? (int)s.next.smin : MAX_HEIGHT;
|
||||||
|
tempSpans[idx].y = Math.Clamp(bot, 0, MAX_HEIGHT);
|
||||||
|
tempSpans[idx].h = Math.Clamp(top - bot, 0, MAX_HEIGHT);
|
||||||
|
chf.areas[idx] = s.area;
|
||||||
|
idx++;
|
||||||
|
tmpCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = s.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
chf.cells[x + y * w] = new RcCompactCell(tmpIdx, tmpCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find neighbour connections.
|
// Find neighbour connections.
|
||||||
const int MAX_LAYERS = RC_NOT_CONNECTED - 1;
|
int tooHighNeighbour = 0;
|
||||||
int maxLayerIndex = 0;
|
for (int y = 0; y < h; ++y)
|
||||||
int zStride = xSize; // for readability
|
|
||||||
for (int z = 0; z < zSize; ++z)
|
|
||||||
{
|
{
|
||||||
for (int x = 0; x < xSize; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
ref RcCompactCell cell = ref compactHeightfield.cells[x + z * zStride];
|
ref RcCompactCell c = ref chf.cells[x + y * w];
|
||||||
for (int i = cell.index, ni = cell.index + cell.count; i < ni; ++i)
|
for (int i = c.index, ni = c.index + c.count; i < ni; ++i)
|
||||||
{
|
{
|
||||||
ref RcCompactSpanBuilder s = ref tempSpans[i];
|
ref RcCompactSpanBuilder s = ref tempSpans[i];
|
||||||
|
|
||||||
for (int dir = 0; dir < 4; ++dir)
|
for (int dir = 0; dir < 4; ++dir)
|
||||||
{
|
{
|
||||||
SetCon(s, dir, RC_NOT_CONNECTED);
|
SetCon(s, dir, RC_NOT_CONNECTED);
|
||||||
int neighborX = x + GetDirOffsetX(dir);
|
int nx = x + GetDirOffsetX(dir);
|
||||||
int neighborZ = z + GetDirOffsetY(dir);
|
int ny = y + GetDirOffsetY(dir);
|
||||||
// First check that the neighbour cell is in bounds.
|
// First check that the neighbour cell is in bounds.
|
||||||
if (neighborX < 0 || neighborZ < 0 || neighborX >= xSize || neighborZ >= zSize)
|
if (nx < 0 || ny < 0 || nx >= w || ny >= h)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate over all neighbour spans and check if any of the is
|
// Iterate over all neighbour spans and check if any of the is
|
||||||
// accessible from current cell.
|
// accessible from current cell.
|
||||||
ref RcCompactCell neighborCell = ref compactHeightfield.cells[neighborX + neighborZ * xSize];
|
ref RcCompactCell nc = ref chf.cells[nx + ny * w];
|
||||||
for (int k = neighborCell.index, nk = neighborCell.index + neighborCell.count; k < nk; ++k)
|
for (int k = nc.index, nk = nc.index + nc.count; k < nk; ++k)
|
||||||
{
|
{
|
||||||
ref RcCompactSpanBuilder neighborSpan = ref tempSpans[k];
|
ref RcCompactSpanBuilder ns = ref tempSpans[k];
|
||||||
int bot = Math.Max(s.y, neighborSpan.y);
|
int bot = Math.Max(s.y, ns.y);
|
||||||
int top = Math.Min(s.y + s.h, neighborSpan.y + neighborSpan.h);
|
int top = Math.Min(s.y + s.h, ns.y + ns.h);
|
||||||
|
|
||||||
// Check that the gap between the spans is walkable,
|
// Check that the gap between the spans is walkable,
|
||||||
// and that the climb height between the gaps is not too high.
|
// and that the climb height between the gaps is not too high.
|
||||||
if ((top - bot) >= walkableHeight && MathF.Abs(neighborSpan.y - s.y) <= walkableClimb)
|
if ((top - bot) >= walkableHeight && MathF.Abs(ns.y - s.y) <= walkableClimb)
|
||||||
{
|
{
|
||||||
// Mark direction as walkable.
|
// Mark direction as walkable.
|
||||||
int layerIndex = k - neighborCell.index;
|
int lidx = k - nc.index;
|
||||||
if (layerIndex < 0 || layerIndex > MAX_LAYERS)
|
if (lidx < 0 || lidx > MAX_LAYERS)
|
||||||
{
|
{
|
||||||
maxLayerIndex = Math.Max(maxLayerIndex, layerIndex);
|
tooHighNeighbour = Math.Max(tooHighNeighbour, lidx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCon(s, dir, layerIndex);
|
SetCon(s, dir, lidx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,32 +156,30 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxLayerIndex > MAX_LAYERS)
|
if (tooHighNeighbour > MAX_LAYERS)
|
||||||
{
|
{
|
||||||
throw new Exception($"rcBuildCompactHeightfield: Heightfield has too many layers {maxLayerIndex} (max: {MAX_LAYERS})");
|
throw new Exception("rcBuildCompactHeightfield: Heightfield has too many layers " + tooHighNeighbour
|
||||||
|
+ " (max: " + MAX_LAYERS + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
compactHeightfield.spans = tempSpans.Select(x => x.Build()).ToArray();
|
chf.spans = tempSpans.Select(x => x.Build()).ToArray();
|
||||||
|
|
||||||
return compactHeightfield;
|
return chf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of spans contained in the specified heightfield.
|
private static int GetHeightFieldSpanCount(RcHeightfield hf)
|
||||||
/// @ingroup recast
|
|
||||||
/// @param[in,out] context The build context to use during the operation.
|
|
||||||
/// @param[in] heightfield An initialized heightfield.
|
|
||||||
/// @returns The number of spans in the heightfield.
|
|
||||||
private static int GetHeightFieldSpanCount(RcContext context, RcHeightfield heightfield)
|
|
||||||
{
|
{
|
||||||
int numCols = heightfield.width * heightfield.height;
|
int w = hf.width;
|
||||||
|
int h = hf.height;
|
||||||
int spanCount = 0;
|
int spanCount = 0;
|
||||||
for (int columnIndex = 0; columnIndex < numCols; ++columnIndex)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
for (RcSpan span = heightfield.spans[columnIndex]; span != null; span = span.next)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
if (span.area != RC_NULL_AREA)
|
for (RcSpan s = hf.spans[x + y * w]; s != null; s = s.next)
|
||||||
{
|
{
|
||||||
spanCount++;
|
if (s.area != RC_NULL_AREA)
|
||||||
|
spanCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,14 +37,10 @@ namespace DotRecast.Recast
|
||||||
public const int RC_NOT_CONNECTED = 0x3f;
|
public const int RC_NOT_CONNECTED = 0x3f;
|
||||||
|
|
||||||
/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax.
|
/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax.
|
||||||
public const int RC_SPAN_HEIGHT_BITS = 20;
|
public const int SPAN_HEIGHT_BITS = 20;
|
||||||
|
|
||||||
/// Defines the maximum value for rcSpan::smin and rcSpan::smax.
|
/// Defines the maximum value for rcSpan::smin and rcSpan::smax.
|
||||||
public const int RC_SPAN_MAX_HEIGHT = (1 << RC_SPAN_HEIGHT_BITS) - 1;
|
public const int SPAN_MAX_HEIGHT = (1 << 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.
|
/// Heighfield border flag.
|
||||||
/// If a heightfield region ID has this bit set, then the region is a border
|
/// If a heightfield region ID has this bit set, then the region is a border
|
||||||
|
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
|
@ -30,10 +31,10 @@ namespace DotRecast.Recast
|
||||||
public List<RcContour> conts = new List<RcContour>();
|
public List<RcContour> conts = new List<RcContour>();
|
||||||
|
|
||||||
/** The minimum bounds in world space. [(x, y, z)] */
|
/** The minimum bounds in world space. [(x, y, z)] */
|
||||||
public RcVec3f bmin = new RcVec3f();
|
public Vector3 bmin = new Vector3();
|
||||||
|
|
||||||
/** The maximum bounds in world space. [(x, y, z)] */
|
/** The maximum bounds in world space. [(x, y, z)] */
|
||||||
public RcVec3f bmax = new RcVec3f();
|
public Vector3 bmax = new Vector3();
|
||||||
|
|
||||||
/** The size of each cell. (On the xz-plane.) */
|
/** The size of each cell. (On the xz-plane.) */
|
||||||
public float cs;
|
public float cs;
|
||||||
|
|
|
@ -614,7 +614,7 @@ namespace DotRecast.Recast
|
||||||
return new int[] { minx, minz, leftmost };
|
return new int[] { minx, minz, leftmost };
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MergeRegionHoles(RcContext ctx, RcContourRegion region)
|
private static void MergeRegionHoles(RcTelemetry ctx, RcContourRegion region)
|
||||||
{
|
{
|
||||||
// Sort holes from left to right.
|
// Sort holes from left to right.
|
||||||
for (int i = 0; i < region.nholes; i++)
|
for (int i = 0; i < region.nholes; i++)
|
||||||
|
@ -715,7 +715,7 @@ namespace DotRecast.Recast
|
||||||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
///
|
///
|
||||||
/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig
|
/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig
|
||||||
public static RcContourSet BuildContours(RcContext ctx, RcCompactHeightfield chf, float maxError, int maxEdgeLen,
|
public static RcContourSet BuildContours(RcTelemetry ctx, RcCompactHeightfield chf, float maxError, int maxEdgeLen,
|
||||||
int buildFlags)
|
int buildFlags)
|
||||||
{
|
{
|
||||||
int w = chf.width;
|
int w = chf.width;
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
namespace DotRecast.Recast
|
|
||||||
{
|
|
||||||
// Struct to keep track of entries in the region table that have been changed.
|
|
||||||
public readonly struct RcDirtyEntry
|
|
||||||
{
|
|
||||||
public readonly int index;
|
|
||||||
public readonly int region;
|
|
||||||
public readonly int distance2;
|
|
||||||
|
|
||||||
public RcDirtyEntry(int tempIndex, int tempRegion, int tempDistance2)
|
|
||||||
{
|
|
||||||
index = tempIndex;
|
|
||||||
region = tempRegion;
|
|
||||||
distance2 = tempDistance2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,6 +20,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using static DotRecast.Recast.RcConstants;
|
using static DotRecast.Recast.RcConstants;
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ namespace DotRecast.Recast
|
||||||
private const float EPSILON = 0.00001f;
|
private const float EPSILON = 0.00001f;
|
||||||
private static readonly int[] BOX_EDGES = new[] { 0, 1, 0, 2, 0, 4, 1, 3, 1, 5, 2, 3, 2, 6, 3, 7, 4, 5, 4, 6, 5, 7, 6, 7 };
|
private static readonly int[] BOX_EDGES = new[] { 0, 1, 0, 2, 0, 4, 1, 3, 1, 5, 2, 3, 2, 6, 3, 7, 4, 5, 4, 6, 5, 7, 6, 7 };
|
||||||
|
|
||||||
public static void RasterizeSphere(RcHeightfield hf, RcVec3f center, float radius, int area, int flagMergeThr, RcContext ctx)
|
public static void RasterizeSphere(RcHeightfield hf, Vector3 center, float radius, int area, int flagMergeThr, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_SPHERE);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_SPHERE);
|
||||||
float[] bounds =
|
float[] bounds =
|
||||||
|
@ -42,7 +43,7 @@ namespace DotRecast.Recast
|
||||||
rectangle => IntersectSphere(rectangle, center, radius * radius));
|
rectangle => IntersectSphere(rectangle, center, radius * radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RasterizeCapsule(RcHeightfield hf, RcVec3f start, RcVec3f end, float radius, int area, int flagMergeThr, RcContext ctx)
|
public static void RasterizeCapsule(RcHeightfield hf, Vector3 start, Vector3 end, float radius, int area, int flagMergeThr, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CAPSULE);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CAPSULE);
|
||||||
float[] bounds =
|
float[] bounds =
|
||||||
|
@ -51,12 +52,12 @@ namespace DotRecast.Recast
|
||||||
Math.Min(start.Z, end.Z) - radius, Math.Max(start.X, end.X) + radius, Math.Max(start.Y, end.Y) + radius,
|
Math.Min(start.Z, end.Z) - radius, Math.Max(start.X, end.X) + radius, Math.Max(start.Y, end.Y) + radius,
|
||||||
Math.Max(start.Z, end.Z) + radius
|
Math.Max(start.Z, end.Z) + radius
|
||||||
};
|
};
|
||||||
RcVec3f axis = new RcVec3f(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
Vector3 axis = new Vector3(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
||||||
RasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
RasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
||||||
rectangle => IntersectCapsule(rectangle, start, end, axis, radius * radius));
|
rectangle => IntersectCapsule(rectangle, start, end, axis, radius * radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RasterizeCylinder(RcHeightfield hf, RcVec3f start, RcVec3f end, float radius, int area, int flagMergeThr, RcContext ctx)
|
public static void RasterizeCylinder(RcHeightfield hf, Vector3 start, Vector3 end, float radius, int area, int flagMergeThr, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CYLINDER);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CYLINDER);
|
||||||
float[] bounds =
|
float[] bounds =
|
||||||
|
@ -65,23 +66,23 @@ namespace DotRecast.Recast
|
||||||
Math.Min(start.Z, end.Z) - radius, Math.Max(start.X, end.X) + radius, Math.Max(start.Y, end.Y) + radius,
|
Math.Min(start.Z, end.Z) - radius, Math.Max(start.X, end.X) + radius, Math.Max(start.Y, end.Y) + radius,
|
||||||
Math.Max(start.Z, end.Z) + radius
|
Math.Max(start.Z, end.Z) + radius
|
||||||
};
|
};
|
||||||
RcVec3f axis = new RcVec3f(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
Vector3 axis = new Vector3(end.X - start.X, end.Y - start.Y, end.Z - start.Z);
|
||||||
RasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
RasterizationFilledShape(hf, bounds, area, flagMergeThr,
|
||||||
rectangle => IntersectCylinder(rectangle, start, end, axis, radius * radius));
|
rectangle => IntersectCylinder(rectangle, start, end, axis, radius * radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RasterizeBox(RcHeightfield hf, RcVec3f center, RcVec3f[] halfEdges, int area, int flagMergeThr, RcContext ctx)
|
public static void RasterizeBox(RcHeightfield hf, Vector3 center, Vector3[] halfEdges, int area, int flagMergeThr, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_BOX);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_BOX);
|
||||||
RcVec3f[] normals =
|
Vector3[] normals =
|
||||||
{
|
{
|
||||||
new RcVec3f(halfEdges[0].X, halfEdges[0].Y, halfEdges[0].Z),
|
new Vector3(halfEdges[0].X, halfEdges[0].Y, halfEdges[0].Z),
|
||||||
new RcVec3f(halfEdges[1].X, halfEdges[1].Y, halfEdges[1].Z),
|
new Vector3(halfEdges[1].X, halfEdges[1].Y, halfEdges[1].Z),
|
||||||
new RcVec3f(halfEdges[2].X, halfEdges[2].Y, halfEdges[2].Z),
|
new Vector3(halfEdges[2].X, halfEdges[2].Y, halfEdges[2].Z),
|
||||||
};
|
};
|
||||||
normals[0] = RcVec3f.Normalize(normals[0]);
|
normals[0] = Vector3.Normalize(normals[0]);
|
||||||
normals[1] = RcVec3f.Normalize(normals[1]);
|
normals[1] = Vector3.Normalize(normals[1]);
|
||||||
normals[2] = RcVec3f.Normalize(normals[2]);
|
normals[2] = Vector3.Normalize(normals[2]);
|
||||||
|
|
||||||
float[] vertices = new float[8 * 3];
|
float[] vertices = new float[8 * 3];
|
||||||
float[] bounds = new float[]
|
float[] bounds = new float[]
|
||||||
|
@ -120,7 +121,7 @@ namespace DotRecast.Recast
|
||||||
RasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => IntersectBox(rectangle, vertices, planes));
|
RasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => IntersectBox(rectangle, vertices, planes));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RasterizeConvex(RcHeightfield hf, float[] vertices, int[] triangles, int area, int flagMergeThr, RcContext ctx)
|
public static void RasterizeConvex(RcHeightfield hf, float[] vertices, int[] triangles, int area, int flagMergeThr, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CONVEX);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CONVEX);
|
||||||
float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] };
|
float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] };
|
||||||
|
@ -221,8 +222,8 @@ namespace DotRecast.Recast
|
||||||
int smax = (int)MathF.Ceiling((h[1] - hf.bmin.Y) * ich);
|
int smax = (int)MathF.Ceiling((h[1] - hf.bmin.Y) * ich);
|
||||||
if (smin != smax)
|
if (smin != smax)
|
||||||
{
|
{
|
||||||
int ismin = Math.Clamp(smin, 0, RC_SPAN_MAX_HEIGHT);
|
int ismin = Math.Clamp(smin, 0, SPAN_MAX_HEIGHT);
|
||||||
int ismax = Math.Clamp(smax, ismin + 1, RC_SPAN_MAX_HEIGHT);
|
int ismax = Math.Clamp(smax, ismin + 1, SPAN_MAX_HEIGHT);
|
||||||
RcRasterizations.AddSpan(hf, x, z, ismin, ismax, area, flagMergeThr);
|
RcRasterizations.AddSpan(hf, x, z, ismin, ismax, area, flagMergeThr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,7 +231,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] IntersectSphere(float[] rectangle, RcVec3f center, float radiusSqr)
|
private static float[] IntersectSphere(float[] rectangle, Vector3 center, float radiusSqr)
|
||||||
{
|
{
|
||||||
float x = Math.Max(rectangle[0], Math.Min(center.X, rectangle[2]));
|
float x = Math.Max(rectangle[0], Math.Min(center.X, rectangle[2]));
|
||||||
float y = rectangle[4];
|
float y = rectangle[4];
|
||||||
|
@ -265,7 +266,7 @@ namespace DotRecast.Recast
|
||||||
return new float[] { y + tmin, y + tmax };
|
return new float[] { y + tmin, y + tmax };
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] IntersectCapsule(float[] rectangle, RcVec3f start, RcVec3f end, RcVec3f axis, float radiusSqr)
|
private static float[] IntersectCapsule(float[] rectangle, Vector3 start, Vector3 end, Vector3 axis, float radiusSqr)
|
||||||
{
|
{
|
||||||
float[] s = MergeIntersections(IntersectSphere(rectangle, start, radiusSqr), IntersectSphere(rectangle, end, radiusSqr));
|
float[] s = MergeIntersections(IntersectSphere(rectangle, start, radiusSqr), IntersectSphere(rectangle, end, radiusSqr));
|
||||||
float axisLen2dSqr = axis.X * axis.X + axis.Z * axis.Z;
|
float axisLen2dSqr = axis.X * axis.X + axis.Z * axis.Z;
|
||||||
|
@ -277,14 +278,14 @@ namespace DotRecast.Recast
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] IntersectCylinder(float[] rectangle, RcVec3f start, RcVec3f end, RcVec3f axis, float radiusSqr)
|
private static float[] IntersectCylinder(float[] rectangle, Vector3 start, Vector3 end, Vector3 axis, float radiusSqr)
|
||||||
{
|
{
|
||||||
float[] s = MergeIntersections(
|
float[] s = MergeIntersections(
|
||||||
RayCylinderIntersection(new RcVec3f(
|
RayCylinderIntersection(new Vector3(
|
||||||
Math.Clamp(start.X, rectangle[0], rectangle[2]), rectangle[4],
|
Math.Clamp(start.X, rectangle[0], rectangle[2]), rectangle[4],
|
||||||
Math.Clamp(start.Z, rectangle[1], rectangle[3])
|
Math.Clamp(start.Z, rectangle[1], rectangle[3])
|
||||||
), start, axis, radiusSqr),
|
), start, axis, radiusSqr),
|
||||||
RayCylinderIntersection(new RcVec3f(
|
RayCylinderIntersection(new Vector3(
|
||||||
Math.Clamp(end.X, rectangle[0], rectangle[2]), rectangle[4],
|
Math.Clamp(end.X, rectangle[0], rectangle[2]), rectangle[4],
|
||||||
Math.Clamp(end.Z, rectangle[1], rectangle[3])
|
Math.Clamp(end.Z, rectangle[1], rectangle[3])
|
||||||
), start, axis, radiusSqr));
|
), start, axis, radiusSqr));
|
||||||
|
@ -296,16 +297,16 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
if (axis.Y * axis.Y > EPSILON)
|
if (axis.Y * axis.Y > EPSILON)
|
||||||
{
|
{
|
||||||
RcVec3f[] rectangleOnStartPlane = new RcVec3f[4];
|
Vector3[] rectangleOnStartPlane = new Vector3[4];
|
||||||
RcVec3f[] rectangleOnEndPlane = new RcVec3f[4];
|
Vector3[] rectangleOnEndPlane = new Vector3[4];
|
||||||
float ds = RcVec3f.Dot(axis, start);
|
float ds = Vector3.Dot(axis, start);
|
||||||
float de = RcVec3f.Dot(axis, end);
|
float de = Vector3.Dot(axis, end);
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
float x = rectangle[(i + 1) & 2];
|
float x = rectangle[(i + 1) & 2];
|
||||||
float z = rectangle[(i & 2) + 1];
|
float z = rectangle[(i & 2) + 1];
|
||||||
RcVec3f a = new RcVec3f(x, rectangle[4], z);
|
Vector3 a = new Vector3(x, rectangle[4], z);
|
||||||
float dotAxisA = RcVec3f.Dot(axis, a);
|
float dotAxisA = Vector3.Dot(axis, a);
|
||||||
float t = (ds - dotAxisA) / axis.Y;
|
float t = (ds - dotAxisA) / axis.Y;
|
||||||
rectangleOnStartPlane[i].X = x;
|
rectangleOnStartPlane[i].X = x;
|
||||||
rectangleOnStartPlane[i].Y = rectangle[4] + t;
|
rectangleOnStartPlane[i].Y = rectangle[4] + t;
|
||||||
|
@ -326,23 +327,23 @@ namespace DotRecast.Recast
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] CylinderCapIntersection(RcVec3f start, float radiusSqr, float[] s, int i, RcVec3f[] rectangleOnPlane)
|
private static float[] CylinderCapIntersection(Vector3 start, float radiusSqr, float[] s, int i, Vector3[] rectangleOnPlane)
|
||||||
{
|
{
|
||||||
int j = (i + 1) % 4;
|
int j = (i + 1) % 4;
|
||||||
// Ray against sphere intersection
|
// Ray against sphere intersection
|
||||||
var m = new RcVec3f(
|
var m = new Vector3(
|
||||||
rectangleOnPlane[i].X - start.X,
|
rectangleOnPlane[i].X - start.X,
|
||||||
rectangleOnPlane[i].Y - start.Y,
|
rectangleOnPlane[i].Y - start.Y,
|
||||||
rectangleOnPlane[i].Z - start.Z
|
rectangleOnPlane[i].Z - start.Z
|
||||||
);
|
);
|
||||||
var d = new RcVec3f(
|
var d = new Vector3(
|
||||||
rectangleOnPlane[j].X - rectangleOnPlane[i].X,
|
rectangleOnPlane[j].X - rectangleOnPlane[i].X,
|
||||||
rectangleOnPlane[j].Y - rectangleOnPlane[i].Y,
|
rectangleOnPlane[j].Y - rectangleOnPlane[i].Y,
|
||||||
rectangleOnPlane[j].Z - rectangleOnPlane[i].Z
|
rectangleOnPlane[j].Z - rectangleOnPlane[i].Z
|
||||||
);
|
);
|
||||||
float dl = RcVec3f.Dot(d, d);
|
float dl = Vector3.Dot(d, d);
|
||||||
float b = RcVec3f.Dot(m, d) / dl;
|
float b = Vector3.Dot(m, d) / dl;
|
||||||
float c = (RcVec3f.Dot(m, m) - radiusSqr) / dl;
|
float c = (Vector3.Dot(m, m) - radiusSqr) / dl;
|
||||||
float discr = b * b - c;
|
float discr = b * b - c;
|
||||||
if (discr > EPSILON)
|
if (discr > EPSILON)
|
||||||
{
|
{
|
||||||
|
@ -363,7 +364,7 @@ namespace DotRecast.Recast
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] SlabsCylinderIntersection(float[] rectangle, RcVec3f start, RcVec3f end, RcVec3f axis, float radiusSqr, float[] s)
|
private static float[] SlabsCylinderIntersection(float[] rectangle, Vector3 start, Vector3 end, Vector3 axis, float radiusSqr, float[] s)
|
||||||
{
|
{
|
||||||
if (Math.Min(start.X, end.X) < rectangle[0])
|
if (Math.Min(start.X, end.X) < rectangle[0])
|
||||||
{
|
{
|
||||||
|
@ -388,42 +389,42 @@ namespace DotRecast.Recast
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] XSlabCylinderIntersection(float[] rectangle, RcVec3f start, RcVec3f axis, float radiusSqr, float x)
|
private static float[] XSlabCylinderIntersection(float[] rectangle, Vector3 start, Vector3 axis, float radiusSqr, float x)
|
||||||
{
|
{
|
||||||
return RayCylinderIntersection(XSlabRayIntersection(rectangle, start, axis, x), start, axis, radiusSqr);
|
return RayCylinderIntersection(XSlabRayIntersection(rectangle, start, axis, x), start, axis, radiusSqr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RcVec3f XSlabRayIntersection(float[] rectangle, RcVec3f start, RcVec3f direction, float x)
|
private static Vector3 XSlabRayIntersection(float[] rectangle, Vector3 start, Vector3 direction, float x)
|
||||||
{
|
{
|
||||||
// 2d intersection of plane and segment
|
// 2d intersection of plane and segment
|
||||||
float t = (x - start.X) / direction.X;
|
float t = (x - start.X) / direction.X;
|
||||||
float z = Math.Clamp(start.Z + t * direction.Z, rectangle[1], rectangle[3]);
|
float z = Math.Clamp(start.Z + t * direction.Z, rectangle[1], rectangle[3]);
|
||||||
return new RcVec3f(x, rectangle[4], z);
|
return new Vector3(x, rectangle[4], z);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] ZSlabCylinderIntersection(float[] rectangle, RcVec3f start, RcVec3f axis, float radiusSqr, float z)
|
private static float[] ZSlabCylinderIntersection(float[] rectangle, Vector3 start, Vector3 axis, float radiusSqr, float z)
|
||||||
{
|
{
|
||||||
return RayCylinderIntersection(ZSlabRayIntersection(rectangle, start, axis, z), start, axis, radiusSqr);
|
return RayCylinderIntersection(ZSlabRayIntersection(rectangle, start, axis, z), start, axis, radiusSqr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RcVec3f ZSlabRayIntersection(float[] rectangle, RcVec3f start, RcVec3f direction, float z)
|
private static Vector3 ZSlabRayIntersection(float[] rectangle, Vector3 start, Vector3 direction, float z)
|
||||||
{
|
{
|
||||||
// 2d intersection of plane and segment
|
// 2d intersection of plane and segment
|
||||||
float t = (z - start.Z) / direction.Z;
|
float t = (z - start.Z) / direction.Z;
|
||||||
float x = Math.Clamp(start.X + t * direction.X, rectangle[0], rectangle[2]);
|
float x = Math.Clamp(start.X + t * direction.X, rectangle[0], rectangle[2]);
|
||||||
return new RcVec3f(x, rectangle[4], z);
|
return new Vector3(x, rectangle[4], z);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on Christer Ericsons's "Real-Time Collision Detection"
|
// Based on Christer Ericsons's "Real-Time Collision Detection"
|
||||||
private static float[] RayCylinderIntersection(RcVec3f point, RcVec3f start, RcVec3f axis, float radiusSqr)
|
private static float[] RayCylinderIntersection(Vector3 point, Vector3 start, Vector3 axis, float radiusSqr)
|
||||||
{
|
{
|
||||||
RcVec3f d = axis;
|
Vector3 d = axis;
|
||||||
RcVec3f m = new RcVec3f(point.X - start.X, point.Y - start.Y, point.Z - start.Z);
|
Vector3 m = new Vector3(point.X - start.X, point.Y - start.Y, point.Z - start.Z);
|
||||||
// float[] n = { 0, 1, 0 };
|
// float[] n = { 0, 1, 0 };
|
||||||
float md = RcVec3f.Dot(m, d);
|
float md = Vector3.Dot(m, d);
|
||||||
// float nd = Dot(n, d);
|
// float nd = Dot(n, d);
|
||||||
float nd = axis.Y;
|
float nd = axis.Y;
|
||||||
float dd = RcVec3f.Dot(d, d);
|
float dd = Vector3.Dot(d, d);
|
||||||
|
|
||||||
// float nn = Dot(n, n);
|
// float nn = Dot(n, n);
|
||||||
float nn = 1;
|
float nn = 1;
|
||||||
|
@ -431,7 +432,7 @@ namespace DotRecast.Recast
|
||||||
float mn = m.Y;
|
float mn = m.Y;
|
||||||
// float a = dd * nn - nd * nd;
|
// float a = dd * nn - nd * nd;
|
||||||
float a = dd - nd * nd;
|
float a = dd - nd * nd;
|
||||||
float k = RcVec3f.Dot(m, m) - radiusSqr;
|
float k = Vector3.Dot(m, m) - radiusSqr;
|
||||||
float c = dd * k - md * md;
|
float c = dd * k - md * md;
|
||||||
if (MathF.Abs(a) < EPSILON)
|
if (MathF.Abs(a) < EPSILON)
|
||||||
{
|
{
|
||||||
|
@ -516,7 +517,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
// check intersection with rays starting in rectangle vertices
|
// check intersection with rays starting in rectangle vertices
|
||||||
var point = new RcVec3f(0, rectangle[1], 0);
|
var point = new Vector3(0, rectangle[1], 0);
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
point.X = ((i & 1) == 0) ? rectangle[0] : rectangle[2];
|
point.X = ((i & 1) == 0) ? rectangle[0] : rectangle[2];
|
||||||
|
@ -669,7 +670,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
// rectangle vertex
|
// rectangle vertex
|
||||||
var point = new RcVec3f(0, rectangle[1], 0);
|
var point = new Vector3(0, rectangle[1], 0);
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
point.X = ((i & 1) == 0) ? rectangle[0] : rectangle[2];
|
point.X = ((i & 1) == 0) ? rectangle[0] : rectangle[2];
|
||||||
|
@ -726,7 +727,7 @@ namespace DotRecast.Recast
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool RayTriangleIntersection(RcVec3f point, int plane, float[][] planes, out float y)
|
private static bool RayTriangleIntersection(Vector3 point, int plane, float[][] planes, out float y)
|
||||||
{
|
{
|
||||||
y = 0.0f;
|
y = 0.0f;
|
||||||
float t = (planes[plane][3] - RcVecUtils.Dot(planes[plane], point)) / planes[plane][1];
|
float t = (planes[plane][3] - RcVecUtils.Dot(planes[plane], point)) / planes[plane][1];
|
||||||
|
@ -773,7 +774,7 @@ namespace DotRecast.Recast
|
||||||
return dx * dx + dy * dy + dz * dz;
|
return dx * dx + dy * dy + dz * dz;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool OverlapBounds(RcVec3f amin, RcVec3f amax, float[] bounds)
|
private static bool OverlapBounds(Vector3 amin, Vector3 amax, float[] bounds)
|
||||||
{
|
{
|
||||||
bool overlap = true;
|
bool overlap = true;
|
||||||
overlap = (amin.X > bounds[3] || amax.X < bounds[0]) ? false : overlap;
|
overlap = (amin.X > bounds[3] || amax.X < bounds[0]) ? false : overlap;
|
||||||
|
|
|
@ -28,218 +28,172 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
public static class RcFilters
|
public static class RcFilters
|
||||||
{
|
{
|
||||||
/// Marks non-walkable spans as walkable if their maximum is within @p walkableClimb of the span below them.
|
/// @par
|
||||||
///
|
///
|
||||||
/// This removes small obstacles that the agent would be able to walk over such as curbs, and also allows agents to move up structures such as stairs.
|
/// Allows the formation of walkable regions that will flow over low lying
|
||||||
/// This removes small obstacles and rasterization artifacts that the agent would be able to walk over
|
/// objects such as curbs, and up structures such as stairways.
|
||||||
/// such as curbs. It also allows agents to move up terraced structures like stairs.
|
|
||||||
///
|
///
|
||||||
/// Obstacle spans are marked walkable if: <tt>obstacleSpan.smax - walkableSpan.smax < walkableClimb</tt>
|
/// Two neighboring spans are walkable if: <tt>RcAbs(currentSpan.smax - neighborSpan.smax) < walkableClimb</tt>
|
||||||
///
|
///
|
||||||
/// @warning Will override the effect of #rcFilterLedgeSpans. If both filters are used, call #rcFilterLedgeSpans only after applying this filter.
|
/// @warning Will override the effect of #rcFilterLedgeSpans. So if both filters are used, call
|
||||||
|
/// #rcFilterLedgeSpans after calling this filter.
|
||||||
///
|
///
|
||||||
/// @see rcHeightfield, rcConfig
|
/// @see rcHeightfield, rcConfig
|
||||||
///
|
public static void FilterLowHangingWalkableObstacles(RcTelemetry ctx, int walkableClimb, RcHeightfield solid)
|
||||||
/// @ingroup recast
|
|
||||||
/// @param[in,out] context The build context to use during the operation.
|
|
||||||
/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
|
|
||||||
/// [Limit: >=0] [Units: vx]
|
|
||||||
/// @param[in,out] heightfield A fully built heightfield. (All spans have been added.)
|
|
||||||
public static void FilterLowHangingWalkableObstacles(RcContext context, int walkableClimb, RcHeightfield heightfield)
|
|
||||||
{
|
{
|
||||||
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_LOW_OBSTACLES);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_LOW_OBSTACLES);
|
||||||
|
|
||||||
int xSize = heightfield.width;
|
int w = solid.width;
|
||||||
int zSize = heightfield.height;
|
int h = solid.height;
|
||||||
|
|
||||||
for (int z = 0; z < zSize; ++z)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < xSize; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
RcSpan previousSpan = null;
|
RcSpan ps = null;
|
||||||
bool previousWasWalkable = false;
|
bool previousWalkable = false;
|
||||||
int previousAreaID = RC_NULL_AREA;
|
int previousArea = RC_NULL_AREA;
|
||||||
|
|
||||||
// For each span in the column...
|
for (RcSpan s = solid.spans[x + y * w]; s != null; ps = s, s = s.next)
|
||||||
for (RcSpan span = heightfield.spans[x + z * xSize]; span != null; previousSpan = span, span = span.next)
|
|
||||||
{
|
{
|
||||||
bool walkable = span.area != RC_NULL_AREA;
|
bool walkable = s.area != RC_NULL_AREA;
|
||||||
// If current span is not walkable, but there is walkable span just below it and the height difference
|
// If current span is not walkable, but there is walkable
|
||||||
// is small enough for the agent to walk over, mark the current span as walkable too.
|
// span just below it, mark the span above it walkable too.
|
||||||
if (!walkable && previousWasWalkable && span.smax - previousSpan.smax <= walkableClimb)
|
if (!walkable && previousWalkable)
|
||||||
{
|
{
|
||||||
span.area = previousAreaID;
|
if (MathF.Abs(s.smax - ps.smax) <= walkableClimb)
|
||||||
|
s.area = previousArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the original walkable value regardless of whether we changed it.
|
// Copy walkable flag so that it cannot propagate
|
||||||
// This prevents multiple consecutive non-walkable spans from being erroneously marked as walkable.
|
// past multiple non-walkable objects.
|
||||||
previousWasWalkable = walkable;
|
previousWalkable = walkable;
|
||||||
previousAreaID = span.area;
|
previousArea = s.area;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks spans that are ledges as not-walkable.
|
/// @par
|
||||||
///
|
///
|
||||||
/// A ledge is a span with one or more neighbors whose maximum is further away than @p walkableClimb
|
/// A ledge is a span with one or more neighbors whose maximum is further away than @p walkableClimb
|
||||||
/// from the current span's maximum.
|
/// from the current span's maximum.
|
||||||
/// This method removes the impact of the overestimation of conservative voxelization
|
/// This method removes the impact of the overestimation of conservative voxelization
|
||||||
/// so the resulting mesh will not have regions hanging in the air over ledges.
|
/// so the resulting mesh will not have regions hanging in the air over ledges.
|
||||||
///
|
///
|
||||||
/// A span is a ledge if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
|
/// A span is a ledge if: <tt>RcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
|
||||||
///
|
///
|
||||||
/// @see rcHeightfield, rcConfig
|
/// @see rcHeightfield, rcConfig
|
||||||
///
|
public static void FilterLedgeSpans(RcTelemetry ctx, int walkableHeight, int walkableClimb, RcHeightfield solid)
|
||||||
/// @ingroup recast
|
|
||||||
/// @param[in,out] context The build context to use during the operation.
|
|
||||||
/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to
|
|
||||||
/// be considered walkable. [Limit: >= 3] [Units: vx]
|
|
||||||
/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
|
|
||||||
/// [Limit: >=0] [Units: vx]
|
|
||||||
/// @param[in,out] heightfield A fully built heightfield. (All spans have been added.)
|
|
||||||
public static void FilterLedgeSpans(RcContext context, int walkableHeight, int walkableClimb, RcHeightfield heightfield)
|
|
||||||
{
|
{
|
||||||
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_BORDER);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_BORDER);
|
||||||
|
|
||||||
int xSize = heightfield.width;
|
int w = solid.width;
|
||||||
int zSize = heightfield.height;
|
int h = solid.height;
|
||||||
|
|
||||||
// Mark spans that are adjacent to a ledge as unwalkable..
|
// Mark border spans.
|
||||||
for (int z = 0; z < zSize; ++z)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < xSize; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
for (RcSpan span = heightfield.spans[x + z * xSize]; span != null; span = span.next)
|
for (RcSpan s = solid.spans[x + y * w]; s != null; s = s.next)
|
||||||
{
|
{
|
||||||
// Skip non-walkable spans.
|
// Skip non walkable spans.
|
||||||
if (span.area == RC_NULL_AREA)
|
if (s.area == RC_NULL_AREA)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
int floor = (span.smax);
|
int bot = (s.smax);
|
||||||
int ceiling = span.next != null ? span.next.smin : RC_SPAN_MAX_HEIGHT;
|
int top = s.next != null ? s.next.smin : SPAN_MAX_HEIGHT;
|
||||||
|
|
||||||
// The difference between this walkable area and the lowest neighbor walkable area.
|
// Find neighbours minimum height.
|
||||||
// This is the difference between the current span and all neighbor spans that have
|
int minh = SPAN_MAX_HEIGHT;
|
||||||
// enough space for an agent to move between, but not accounting at all for surface slope.
|
|
||||||
int lowestNeighborFloorDifference = RC_SPAN_MAX_HEIGHT;
|
|
||||||
|
|
||||||
// Min and max height of accessible neighbours.
|
// Min and max height of accessible neighbours.
|
||||||
int lowestTraversableNeighborFloor = span.smax;
|
int asmin = s.smax;
|
||||||
int highestTraversableNeighborFloor = span.smax;
|
int asmax = s.smax;
|
||||||
|
|
||||||
for (int direction = 0; direction < 4; ++direction)
|
for (int dir = 0; dir < 4; ++dir)
|
||||||
{
|
{
|
||||||
int neighborX = x + GetDirOffsetX(direction);
|
int dx = x + GetDirOffsetX(dir);
|
||||||
int neighborZ = z + GetDirOffsetY(direction);
|
int dy = y + GetDirOffsetY(dir);
|
||||||
|
|
||||||
// Skip neighbours which are out of bounds.
|
// Skip neighbours which are out of bounds.
|
||||||
if (neighborX < 0 || neighborZ < 0 || neighborX >= xSize || neighborZ >= zSize)
|
if (dx < 0 || dy < 0 || dx >= w || dy >= h)
|
||||||
{
|
{
|
||||||
lowestNeighborFloorDifference = (-walkableClimb - 1);
|
minh = Math.Min(minh, -walkableClimb - bot);
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcSpan neighborSpan = heightfield.spans[neighborX + neighborZ * xSize];
|
// From minus infinity to the first span.
|
||||||
|
RcSpan ns = solid.spans[dx + dy * w];
|
||||||
// The most we can step down to the neighbor is the walkableClimb distance.
|
int nbot = -walkableClimb;
|
||||||
// Start with the area under the neighbor span
|
int ntop = ns != null ? ns.smin : SPAN_MAX_HEIGHT;
|
||||||
int neighborCeiling = neighborSpan != null ? neighborSpan.smin : RC_SPAN_MAX_HEIGHT;
|
|
||||||
|
|
||||||
// Skip neightbour if the gap between the spans is too small.
|
// Skip neightbour if the gap between the spans is too small.
|
||||||
if (Math.Min(ceiling, neighborCeiling) - floor >= walkableHeight)
|
if (Math.Min(top, ntop) - Math.Max(bot, nbot) > walkableHeight)
|
||||||
|
minh = Math.Min(minh, nbot - bot);
|
||||||
|
|
||||||
|
// Rest of the spans.
|
||||||
|
for (ns = solid.spans[dx + dy * w]; ns != null; ns = ns.next)
|
||||||
{
|
{
|
||||||
lowestNeighborFloorDifference = (-walkableClimb - 1);
|
nbot = ns.smax;
|
||||||
break;
|
ntop = ns.next != null ? ns.next.smin : SPAN_MAX_HEIGHT;
|
||||||
}
|
// Skip neightbour if the gap between the spans is too small.
|
||||||
|
if (Math.Min(top, ntop) - Math.Max(bot, nbot) > walkableHeight)
|
||||||
// For each span in the neighboring column...
|
|
||||||
for (; neighborSpan != null; neighborSpan = neighborSpan.next)
|
|
||||||
{
|
|
||||||
int neighborFloor = neighborSpan.smax;
|
|
||||||
neighborCeiling = neighborSpan.next != null ? neighborSpan.next.smin : RC_SPAN_MAX_HEIGHT;
|
|
||||||
|
|
||||||
// Only consider neighboring areas that have enough overlap to be potentially traversable.
|
|
||||||
if (Math.Min(ceiling, neighborCeiling) - Math.Max(floor, neighborFloor) < walkableHeight)
|
|
||||||
{
|
{
|
||||||
// No space to traverse between them.
|
minh = Math.Min(minh, nbot - bot);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int neighborFloorDifference = neighborFloor - floor;
|
// Find min/max accessible neighbour height.
|
||||||
lowestNeighborFloorDifference = Math.Min(lowestNeighborFloorDifference, neighborFloorDifference);
|
if (MathF.Abs(nbot - bot) <= walkableClimb)
|
||||||
|
{
|
||||||
// Find min/max accessible neighbor height.
|
if (nbot < asmin)
|
||||||
// Only consider neighbors that are at most walkableClimb away.
|
asmin = nbot;
|
||||||
if (MathF.Abs(neighborFloorDifference) <= walkableClimb)
|
if (nbot > asmax)
|
||||||
{
|
asmax = nbot;
|
||||||
// There is space to move to the neighbor cell and the slope isn't too much.
|
}
|
||||||
lowestTraversableNeighborFloor = Math.Min(lowestTraversableNeighborFloor, neighborFloor);
|
|
||||||
highestTraversableNeighborFloor = Math.Max(highestTraversableNeighborFloor, neighborFloor);
|
|
||||||
}
|
|
||||||
else if (neighborFloorDifference < -walkableClimb)
|
|
||||||
{
|
|
||||||
// We already know this will be considered a ledge span so we can early-out
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The current span is close to a ledge if the magnitude of the drop to any neighbour span is greater than the walkableClimb distance.
|
// The current span is close to a ledge if the drop to any
|
||||||
// That is, there is a gap that is large enough to let an agent move between them, but the drop (surface slope) is too large to allow it.
|
// neighbour span is less than the walkableClimb.
|
||||||
// (If this is the case, then biggestNeighborStepDown will be negative, so compare against the negative walkableClimb as a means of checking
|
if (minh < -walkableClimb)
|
||||||
// the magnitude of the delta)
|
s.area = RC_NULL_AREA;
|
||||||
if (lowestNeighborFloorDifference < -walkableClimb)
|
|
||||||
|
// If the difference between all neighbours is too large,
|
||||||
|
// we are at steep slope, mark the span as ledge.
|
||||||
|
if ((asmax - asmin) > walkableClimb)
|
||||||
{
|
{
|
||||||
span.area = RC_NULL_AREA;
|
s.area = RC_NULL_AREA;
|
||||||
}
|
|
||||||
// If the difference between all neighbor floors is too large, this is a steep slope, so mark the span as an unwalkable ledge.
|
|
||||||
else if ((highestTraversableNeighborFloor - lowestTraversableNeighborFloor) > walkableClimb)
|
|
||||||
{
|
|
||||||
span.area = RC_NULL_AREA;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks walkable spans as not walkable if the clearance above the span is less than the specified walkableHeight.
|
/// @par
|
||||||
///
|
///
|
||||||
/// For this filter, the clearance above the span is the distance from the span's
|
/// For this filter, the clearance above the span is the distance from the span's
|
||||||
/// maximum to the minimum of the next higher span in the same column.
|
/// maximum to the next higher span's minimum. (Same grid column.)
|
||||||
/// If there is no higher span in the column, the clearance is computed as the
|
|
||||||
/// distance from the top of the span to the maximum heightfield height.
|
|
||||||
///
|
///
|
||||||
/// @see rcHeightfield, rcConfig
|
/// @see rcHeightfield, rcConfig
|
||||||
/// @ingroup recast
|
public static void FilterWalkableLowHeightSpans(RcTelemetry ctx, int walkableHeight, RcHeightfield solid)
|
||||||
///
|
|
||||||
/// @param[in,out] context The build context to use during the operation.
|
|
||||||
/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to
|
|
||||||
/// be considered walkable. [Limit: >= 3] [Units: vx]
|
|
||||||
/// @param[in,out] heightfield A fully built heightfield. (All spans have been added.)
|
|
||||||
public static void FilterWalkableLowHeightSpans(RcContext context, int walkableHeight, RcHeightfield heightfield)
|
|
||||||
{
|
{
|
||||||
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_WALKABLE);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_WALKABLE);
|
||||||
|
|
||||||
int xSize = heightfield.width;
|
int w = solid.width;
|
||||||
int zSize = heightfield.height;
|
int h = solid.height;
|
||||||
|
|
||||||
// Remove walkable flag from spans which do not have enough
|
// Remove walkable flag from spans which do not have enough
|
||||||
// space above them for the agent to stand there.
|
// space above them for the agent to stand there.
|
||||||
for (int z = 0; z < zSize; ++z)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < xSize; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
for (RcSpan span = heightfield.spans[x + z * xSize]; span != null; span = span.next)
|
for (RcSpan s = solid.spans[x + y * w]; s != null; s = s.next)
|
||||||
{
|
{
|
||||||
int floor = (span.smax);
|
int bot = (s.smax);
|
||||||
int ceiling = span.next != null ? span.next.smin : RC_SPAN_MAX_HEIGHT;
|
int top = s.next != null ? s.next.smin : SPAN_MAX_HEIGHT;
|
||||||
if ((ceiling - floor) < walkableHeight)
|
if ((top - bot) < walkableHeight)
|
||||||
{
|
s.area = RC_NULL_AREA;
|
||||||
span.area = RC_NULL_AREA;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
|
@ -32,10 +33,10 @@ namespace DotRecast.Recast
|
||||||
public readonly int height;
|
public readonly int height;
|
||||||
|
|
||||||
/** The minimum bounds in world space. [(x, y, z)] */
|
/** The minimum bounds in world space. [(x, y, z)] */
|
||||||
public readonly RcVec3f bmin;
|
public readonly Vector3 bmin;
|
||||||
|
|
||||||
/** The maximum bounds in world space. [(x, y, z)] */
|
/** The maximum bounds in world space. [(x, y, z)] */
|
||||||
public RcVec3f bmax;
|
public Vector3 bmax;
|
||||||
|
|
||||||
/** The size of each cell. (On the xz-plane.) */
|
/** The size of each cell. (On the xz-plane.) */
|
||||||
public readonly float cs;
|
public readonly float cs;
|
||||||
|
@ -49,7 +50,7 @@ namespace DotRecast.Recast
|
||||||
/** Border size in cell units */
|
/** Border size in cell units */
|
||||||
public readonly int borderSize;
|
public readonly int borderSize;
|
||||||
|
|
||||||
public RcHeightfield(int width, int height, RcVec3f bmin, RcVec3f bmax, float cs, float ch, int borderSize)
|
public RcHeightfield(int width, int height, Vector3 bmin, Vector3 bmax, float cs, float ch, int borderSize)
|
||||||
{
|
{
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
|
@ -6,20 +7,48 @@ namespace DotRecast.Recast
|
||||||
/// @see rcHeightfieldLayerSet
|
/// @see rcHeightfieldLayerSet
|
||||||
public class RcHeightfieldLayer
|
public class RcHeightfieldLayer
|
||||||
{
|
{
|
||||||
public RcVec3f bmin = new RcVec3f(); // < The minimum bounds in world space. [(x, y, z)]
|
public Vector3 bmin = new Vector3();
|
||||||
public RcVec3f bmax = new RcVec3f(); // < The maximum bounds in world space. [(x, y, z)]
|
|
||||||
public float cs; // < The size of each cell. (On the xz-plane.)
|
/// < The minimum bounds in world space. [(x, y, z)]
|
||||||
public float ch; // < The height of each cell. (The minimum increment along the y-axis.)
|
public Vector3 bmax = new Vector3();
|
||||||
public int width; // < The width of the heightfield. (Along the x-axis in cell units.)
|
|
||||||
public int height; // < The height of the heightfield. (Along the z-axis in cell units.)
|
/// < The maximum bounds in world space. [(x, y, z)]
|
||||||
public int minx; // < The minimum x-bounds of usable data.
|
public float cs;
|
||||||
public int maxx; // < The maximum x-bounds of usable data.
|
|
||||||
public int miny; // < The minimum y-bounds of usable data. (Along the z-axis.)
|
/// < The size of each cell. (On the xz-plane.)
|
||||||
public int maxy; // < The maximum y-bounds of usable data. (Along the z-axis.)
|
public float ch;
|
||||||
public int hmin; // < The minimum height bounds of usable data. (Along the y-axis.)
|
|
||||||
public int hmax; // < The maximum height bounds of usable data. (Along the y-axis.)
|
/// < The height of each cell. (The minimum increment along the y-axis.)
|
||||||
public int[] heights; // < The heightfield. [Size: width * height]
|
public int width;
|
||||||
public int[] areas; // < Area ids. [Size: Same as #heights]
|
|
||||||
public int[] cons; // < Packed neighbor connection information. [Size: Same as #heights]
|
/// < The width of the heightfield. (Along the x-axis in cell units.)
|
||||||
|
public int height;
|
||||||
|
|
||||||
|
/// < The height of the heightfield. (Along the z-axis in cell units.)
|
||||||
|
public int minx;
|
||||||
|
|
||||||
|
/// < The minimum x-bounds of usable data.
|
||||||
|
public int maxx;
|
||||||
|
|
||||||
|
/// < The maximum x-bounds of usable data.
|
||||||
|
public int miny;
|
||||||
|
|
||||||
|
/// < The minimum y-bounds of usable data. (Along the z-axis.)
|
||||||
|
public int maxy;
|
||||||
|
|
||||||
|
/// < The maximum y-bounds of usable data. (Along the z-axis.)
|
||||||
|
public int hmin;
|
||||||
|
|
||||||
|
/// < The minimum height bounds of usable data. (Along the y-axis.)
|
||||||
|
public int hmax;
|
||||||
|
|
||||||
|
/// < The maximum height bounds of usable data. (Along the y-axis.)
|
||||||
|
public int[] heights;
|
||||||
|
|
||||||
|
/// < The heightfield. [Size: width * height]
|
||||||
|
public int[] areas;
|
||||||
|
|
||||||
|
/// < Area ids. [Size: Same as #heights]
|
||||||
|
public int[] cons; /// < Packed neighbor connection information. [Size: Same as #heights]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,8 @@ freely, subject to the following restrictions:
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,11 +5,11 @@ namespace DotRecast.Recast
|
||||||
public class RcLayerRegion
|
public class RcLayerRegion
|
||||||
{
|
{
|
||||||
public int id;
|
public int id;
|
||||||
public int layerId; // Layer ID
|
public int layerId;
|
||||||
public bool @base; // Flag indicating if the region is the base of merged regions.
|
public bool @base;
|
||||||
public int ymin, ymax;
|
public int ymin, ymax;
|
||||||
public List<int> layers; // Layer count
|
public List<int> layers;
|
||||||
public List<int> neis; // Neighbour count
|
public List<int> neis;
|
||||||
|
|
||||||
public RcLayerRegion(int i)
|
public RcLayerRegion(int i)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
|
@ -52,53 +53,30 @@ namespace DotRecast.Recast
|
||||||
return (amin > bmax || amax < bmin) ? false : true;
|
return (amin > bmax || amax < bmin) ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @par
|
public static RcHeightfieldLayerSet BuildHeightfieldLayers(RcTelemetry ctx, RcCompactHeightfield chf, int walkableHeight)
|
||||||
///
|
|
||||||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
|
||||||
///
|
|
||||||
/// @see rcAllocHeightfieldLayerSet, rcCompactHeightfield, rcHeightfieldLayerSet, rcConfig
|
|
||||||
/// @}
|
|
||||||
/// @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.
|
|
||||||
/// @param[in] chf A fully built compact heightfield.
|
|
||||||
/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0]
|
|
||||||
/// [Units: vx]
|
|
||||||
/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area
|
|
||||||
/// to be considered walkable. [Limit: >= 3] [Units: vx]
|
|
||||||
/// @param[out] lset The resulting layer set. (Must be pre-allocated.)
|
|
||||||
/// @returns True if the operation completed successfully.
|
|
||||||
public static bool BuildHeightfieldLayers(RcContext ctx, RcCompactHeightfield chf, int borderSize, int walkableHeight, out RcHeightfieldLayerSet lset)
|
|
||||||
{
|
{
|
||||||
lset = null;
|
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_LAYERS);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_LAYERS);
|
||||||
|
|
||||||
int w = chf.width;
|
int w = chf.width;
|
||||||
int h = chf.height;
|
int h = chf.height;
|
||||||
|
int borderSize = chf.borderSize;
|
||||||
int[] srcReg = new int[chf.spanCount];
|
int[] srcReg = new int[chf.spanCount];
|
||||||
Array.Fill(srcReg, 0xFF);
|
Array.Fill(srcReg, 0xFF);
|
||||||
|
|
||||||
int nsweeps = chf.width; // Math.Max(chf.width, chf.height);
|
int nsweeps = chf.width; // Math.Max(chf.width, chf.height);
|
||||||
RcLayerSweepSpan[] sweeps = new RcLayerSweepSpan[nsweeps];
|
RcSweepSpan[] sweeps = new RcSweepSpan[nsweeps];
|
||||||
for (int i = 0; i < sweeps.Length; i++)
|
for (int i = 0; i < sweeps.Length; i++)
|
||||||
{
|
{
|
||||||
sweeps[i] = new RcLayerSweepSpan();
|
sweeps[i] = new RcSweepSpan();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partition walkable area into monotone regions.
|
// Partition walkable area into monotone regions.
|
||||||
int[] prevCount = new int[256];
|
int[] prevCount = new int[256];
|
||||||
int regId = 0;
|
int regId = 0;
|
||||||
|
|
||||||
// Sweep one line at a time.
|
// Sweep one line at a time.
|
||||||
for (int y = borderSize; y < h - borderSize; ++y)
|
for (int y = borderSize; y < h - borderSize; ++y)
|
||||||
{
|
{
|
||||||
// Collect spans from this row.
|
// Collect spans from this row.
|
||||||
Array.Fill(prevCount, 0);
|
Array.Fill(prevCount, 0, 0, (regId) - (0));
|
||||||
int sweepId = 0;
|
int sweepId = 0;
|
||||||
|
|
||||||
for (int x = borderSize; x < w - borderSize; ++x)
|
for (int x = borderSize; x < w - borderSize; ++x)
|
||||||
|
@ -110,10 +88,9 @@ namespace DotRecast.Recast
|
||||||
ref RcCompactSpan s = ref chf.spans[i];
|
ref RcCompactSpan s = ref chf.spans[i];
|
||||||
if (chf.areas[i] == RC_NULL_AREA)
|
if (chf.areas[i] == RC_NULL_AREA)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int sid = 0xFF;
|
int sid = 0xFF;
|
||||||
|
|
||||||
// -x
|
// -x
|
||||||
|
|
||||||
if (GetCon(ref s, 0) != RC_NOT_CONNECTED)
|
if (GetCon(ref s, 0) != RC_NOT_CONNECTED)
|
||||||
{
|
{
|
||||||
int ax = x + GetDirOffsetX(0);
|
int ax = x + GetDirOffsetX(0);
|
||||||
|
@ -139,7 +116,8 @@ namespace DotRecast.Recast
|
||||||
int nr = srcReg[ai];
|
int nr = srcReg[ai];
|
||||||
if (nr != 0xff)
|
if (nr != 0xff)
|
||||||
{
|
{
|
||||||
// Set neighbour when first valid neighbour is encoutered.
|
// Set neighbour when first valid neighbour is
|
||||||
|
// encoutered.
|
||||||
if (sweeps[sid].ns == 0)
|
if (sweeps[sid].ns == 0)
|
||||||
sweeps[sid].nei = nr;
|
sweeps[sid].nei = nr;
|
||||||
|
|
||||||
|
@ -151,7 +129,8 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This is hit if there is nore than one neighbour.
|
// This is hit if there is nore than one
|
||||||
|
// neighbour.
|
||||||
// Invalidate the neighbour.
|
// Invalidate the neighbour.
|
||||||
sweeps[sid].nei = 0xff;
|
sweeps[sid].nei = 0xff;
|
||||||
}
|
}
|
||||||
|
@ -165,8 +144,10 @@ namespace DotRecast.Recast
|
||||||
// Create unique ID.
|
// Create unique ID.
|
||||||
for (int i = 0; i < sweepId; ++i)
|
for (int i = 0; i < sweepId; ++i)
|
||||||
{
|
{
|
||||||
// If the neighbour is set and there is only one continuous connection to it,
|
// If the neighbour is set and there is only one continuous
|
||||||
// the sweep will be merged with the previous one, else new region is created.
|
// connection to it,
|
||||||
|
// the sweep will be merged with the previous one, else new
|
||||||
|
// region is created.
|
||||||
if (sweeps[i].nei != 0xff && prevCount[sweeps[i].nei] == sweeps[i].ns)
|
if (sweeps[i].nei != 0xff && prevCount[sweeps[i].nei] == sweeps[i].ns)
|
||||||
{
|
{
|
||||||
sweeps[i].id = sweeps[i].nei;
|
sweeps[i].id = sweeps[i].nei;
|
||||||
|
@ -176,7 +157,6 @@ namespace DotRecast.Recast
|
||||||
if (regId == 255)
|
if (regId == 255)
|
||||||
{
|
{
|
||||||
throw new Exception("rcBuildHeightfieldLayers: Region ID overflow.");
|
throw new Exception("rcBuildHeightfieldLayers: Region ID overflow.");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sweeps[i].id = regId++;
|
sweeps[i].id = regId++;
|
||||||
|
@ -195,7 +175,6 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate and init layer regions.
|
|
||||||
int nregs = regId;
|
int nregs = regId;
|
||||||
RcLayerRegion[] regs = new RcLayerRegion[nregs];
|
RcLayerRegion[] regs = new RcLayerRegion[nregs];
|
||||||
|
|
||||||
|
@ -238,12 +217,7 @@ namespace DotRecast.Recast
|
||||||
int ai = chf.cells[ax + ay * w].index + GetCon(ref s, dir);
|
int ai = chf.cells[ax + ay * w].index + GetCon(ref s, dir);
|
||||||
int rai = srcReg[ai];
|
int rai = srcReg[ai];
|
||||||
if (rai != 0xff && rai != ri)
|
if (rai != 0xff && rai != ri)
|
||||||
{
|
|
||||||
// Don't check return value -- if we cannot add the neighbor
|
|
||||||
// it will just cause a few more regions to be created, which
|
|
||||||
// is fine.
|
|
||||||
AddUnique(regs[ri].neis, rai);
|
AddUnique(regs[ri].neis, rai);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,10 +288,7 @@ namespace DotRecast.Recast
|
||||||
regn.layerId = layerId;
|
regn.layerId = layerId;
|
||||||
// Merge current layers to root.
|
// Merge current layers to root.
|
||||||
foreach (int layer in regn.layers)
|
foreach (int layer in regn.layers)
|
||||||
{
|
|
||||||
AddUnique(root.layers, layer);
|
AddUnique(root.layers, layer);
|
||||||
}
|
|
||||||
|
|
||||||
root.ymin = Math.Min(root.ymin, regn.ymin);
|
root.ymin = Math.Min(root.ymin, regn.ymin);
|
||||||
root.ymax = Math.Max(root.ymax, regn.ymax);
|
root.ymax = Math.Max(root.ymax, regn.ymax);
|
||||||
}
|
}
|
||||||
|
@ -358,9 +329,11 @@ namespace DotRecast.Recast
|
||||||
if ((ymax - ymin) >= 255)
|
if ((ymax - ymin) >= 255)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Make sure that there is no overlap when merging 'ri' and 'rj'.
|
// Make sure that there is no overlap when merging 'ri' and
|
||||||
|
// 'rj'.
|
||||||
bool overlap = false;
|
bool overlap = false;
|
||||||
// Iterate over all regions which have the same layerId as 'rj'
|
// Iterate over all regions which have the same layerId as
|
||||||
|
// 'rj'
|
||||||
for (int k = 0; k < nregs; ++k)
|
for (int k = 0; k < nregs; ++k)
|
||||||
{
|
{
|
||||||
if (regs[k].layerId != rj.layerId)
|
if (regs[k].layerId != rj.layerId)
|
||||||
|
@ -398,10 +371,7 @@ namespace DotRecast.Recast
|
||||||
rj.layerId = newId;
|
rj.layerId = newId;
|
||||||
// Add overlaid layers from 'rj' to 'ri'.
|
// Add overlaid layers from 'rj' to 'ri'.
|
||||||
foreach (int layer in rj.layers)
|
foreach (int layer in rj.layers)
|
||||||
{
|
|
||||||
AddUnique(ri.layers, layer);
|
AddUnique(ri.layers, layer);
|
||||||
}
|
|
||||||
|
|
||||||
// Update height bounds.
|
// Update height bounds.
|
||||||
ri.ymin = Math.Min(ri.ymin, rj.ymin);
|
ri.ymin = Math.Min(ri.ymin, rj.ymin);
|
||||||
ri.ymax = Math.Max(ri.ymax, rj.ymax);
|
ri.ymax = Math.Max(ri.ymax, rj.ymax);
|
||||||
|
@ -427,14 +397,13 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
// Remap ids.
|
// Remap ids.
|
||||||
for (int i = 0; i < nregs; ++i)
|
for (int i = 0; i < nregs; ++i)
|
||||||
{
|
|
||||||
regs[i].layerId = remap[regs[i].layerId];
|
regs[i].layerId = remap[regs[i].layerId];
|
||||||
}
|
|
||||||
|
|
||||||
// No layers, return empty.
|
// No layers, return empty.
|
||||||
if (layerId == 0)
|
if (layerId == 0)
|
||||||
{
|
{
|
||||||
return true;
|
// ctx.Stop(RC_TIMER_BUILD_LAYERS);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create layers.
|
// Create layers.
|
||||||
|
@ -444,14 +413,14 @@ namespace DotRecast.Recast
|
||||||
int lh = h - borderSize * 2;
|
int lh = h - borderSize * 2;
|
||||||
|
|
||||||
// Build contracted bbox for layers.
|
// Build contracted bbox for layers.
|
||||||
RcVec3f bmin = chf.bmin;
|
Vector3 bmin = chf.bmin;
|
||||||
RcVec3f bmax = chf.bmax;
|
Vector3 bmax = chf.bmax;
|
||||||
bmin.X += borderSize * chf.cs;
|
bmin.X += borderSize * chf.cs;
|
||||||
bmin.Z += borderSize * chf.cs;
|
bmin.Z += borderSize * chf.cs;
|
||||||
bmax.X -= borderSize * chf.cs;
|
bmax.X -= borderSize * chf.cs;
|
||||||
bmax.Z -= borderSize * chf.cs;
|
bmax.Z -= borderSize * chf.cs;
|
||||||
|
|
||||||
lset = new RcHeightfieldLayerSet();
|
RcHeightfieldLayerSet lset = new RcHeightfieldLayerSet();
|
||||||
lset.layers = new RcHeightfieldLayer[layerId];
|
lset.layers = new RcHeightfieldLayer[layerId];
|
||||||
for (int i = 0; i < lset.layers.Length; i++)
|
for (int i = 0; i < lset.layers.Length; i++)
|
||||||
{
|
{
|
||||||
|
@ -547,7 +516,8 @@ namespace DotRecast.Recast
|
||||||
if (chf.areas[ai] != RC_NULL_AREA && lid != alid)
|
if (chf.areas[ai] != RC_NULL_AREA && lid != alid)
|
||||||
{
|
{
|
||||||
portal |= (char)(1 << dir);
|
portal |= (char)(1 << dir);
|
||||||
// Update height so that it matches on both sides of the portal.
|
// Update height so that it matches on both
|
||||||
|
// sides of the portal.
|
||||||
ref RcCompactSpan @as = ref chf.spans[ai];
|
ref RcCompactSpan @as = ref chf.spans[ai];
|
||||||
if (@as.y > hmin)
|
if (@as.y > hmin)
|
||||||
layer.heights[idx] = Math.Max(layer.heights[idx], (char)(@as.y - hmin));
|
layer.heights[idx] = Math.Max(layer.heights[idx], (char)(@as.y - hmin));
|
||||||
|
@ -575,7 +545,8 @@ namespace DotRecast.Recast
|
||||||
layer.miny = layer.maxy = 0;
|
layer.miny = layer.maxy = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
// ctx->StopTimer(RC_TIMER_BUILD_LAYERS);
|
||||||
|
return lset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
namespace DotRecast.Recast
|
|
||||||
{
|
|
||||||
public readonly struct RcLevelStackEntry
|
|
||||||
{
|
|
||||||
public readonly int x;
|
|
||||||
public readonly int y;
|
|
||||||
public readonly int index;
|
|
||||||
|
|
||||||
public RcLevelStackEntry(int tempX, int tempY, int tempIndex)
|
|
||||||
{
|
|
||||||
x = tempX;
|
|
||||||
y = tempY;
|
|
||||||
index = tempIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,6 +22,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using static DotRecast.Recast.RcConstants;
|
using static DotRecast.Recast.RcConstants;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
|
@ -35,7 +36,7 @@ namespace DotRecast.Recast
|
||||||
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_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 MAX_VERTS_PER_EDGE = 32;
|
||||||
|
|
||||||
public const int RC_UNSET_HEIGHT = RcConstants.RC_SPAN_MAX_HEIGHT;
|
public const int RC_UNSET_HEIGHT = RcConstants.SPAN_MAX_HEIGHT;
|
||||||
public const int EV_UNDEF = -1;
|
public const int EV_UNDEF = -1;
|
||||||
public const int EV_HULL = -2;
|
public const int EV_HULL = -2;
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ namespace DotRecast.Recast
|
||||||
return a[0] * b[0] + a[2] * b[2];
|
return a[0] * b[0] + a[2] * b[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float Vdot2(RcVec3f a, RcVec3f b)
|
private static float Vdot2(Vector3 a, Vector3 b)
|
||||||
{
|
{
|
||||||
return a.X * b.X + a.Z * b.Z;
|
return a.X * b.X + a.Z * b.Z;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +71,7 @@ namespace DotRecast.Recast
|
||||||
return dx * dx + dy * dy;
|
return dx * dx + dy * dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float VdistSq2(float[] p, RcVec3f q)
|
private static float VdistSq2(float[] p, Vector3 q)
|
||||||
{
|
{
|
||||||
float dx = q.X - p[0];
|
float dx = q.X - p[0];
|
||||||
float dy = q.Z - p[2];
|
float dy = q.Z - p[2];
|
||||||
|
@ -78,7 +79,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static float VdistSq2(RcVec3f p, RcVec3f q)
|
private static float VdistSq2(Vector3 p, Vector3 q)
|
||||||
{
|
{
|
||||||
float dx = q.X - p.X;
|
float dx = q.X - p.X;
|
||||||
float dy = q.Z - p.Z;
|
float dy = q.Z - p.Z;
|
||||||
|
@ -91,12 +92,12 @@ namespace DotRecast.Recast
|
||||||
return MathF.Sqrt(VdistSq2(p, q));
|
return MathF.Sqrt(VdistSq2(p, q));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float Vdist2(RcVec3f p, RcVec3f q)
|
private static float Vdist2(Vector3 p, Vector3 q)
|
||||||
{
|
{
|
||||||
return MathF.Sqrt(VdistSq2(p, q));
|
return MathF.Sqrt(VdistSq2(p, q));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float Vdist2(float[] p, RcVec3f q)
|
private static float Vdist2(float[] p, Vector3 q)
|
||||||
{
|
{
|
||||||
return MathF.Sqrt(VdistSq2(p, q));
|
return MathF.Sqrt(VdistSq2(p, q));
|
||||||
}
|
}
|
||||||
|
@ -109,7 +110,7 @@ namespace DotRecast.Recast
|
||||||
return dx * dx + dy * dy;
|
return dx * dx + dy * dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float VdistSq2(RcVec3f p, float[] verts, int q)
|
private static float VdistSq2(Vector3 p, float[] verts, int q)
|
||||||
{
|
{
|
||||||
float dx = verts[q + 0] - p.X;
|
float dx = verts[q + 0] - p.X;
|
||||||
float dy = verts[q + 2] - p.Z;
|
float dy = verts[q + 2] - p.Z;
|
||||||
|
@ -122,7 +123,7 @@ namespace DotRecast.Recast
|
||||||
return MathF.Sqrt(VdistSq2(p, verts, q));
|
return MathF.Sqrt(VdistSq2(p, verts, q));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float Vdist2(RcVec3f p, float[] verts, int q)
|
private static float Vdist2(Vector3 p, float[] verts, int q)
|
||||||
{
|
{
|
||||||
return MathF.Sqrt(VdistSq2(p, verts, q));
|
return MathF.Sqrt(VdistSq2(p, verts, q));
|
||||||
}
|
}
|
||||||
|
@ -146,7 +147,7 @@ namespace DotRecast.Recast
|
||||||
return u1 * v2 - v1 * u2;
|
return u1 * v2 - v1 * u2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float Vcross2(RcVec3f p1, RcVec3f p2, RcVec3f p3)
|
private static float Vcross2(Vector3 p1, Vector3 p2, Vector3 p3)
|
||||||
{
|
{
|
||||||
float u1 = p2.X - p1.X;
|
float u1 = p2.X - p1.X;
|
||||||
float v1 = p2.Z - p1.Z;
|
float v1 = p2.Z - p1.Z;
|
||||||
|
@ -156,11 +157,11 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static bool CircumCircle(float[] verts, int p1, int p2, int p3, ref RcVec3f c, RcAtomicFloat r)
|
private static bool CircumCircle(float[] verts, int p1, int p2, int p3, ref Vector3 c, RcAtomicFloat r)
|
||||||
{
|
{
|
||||||
const float EPS = 1e-6f;
|
const float EPS = 1e-6f;
|
||||||
// Calculate the circle relative to p1, to avoid some precision issues.
|
// Calculate the circle relative to p1, to avoid some precision issues.
|
||||||
var v1 = new RcVec3f();
|
var v1 = new Vector3();
|
||||||
var v2 = RcVecUtils.Subtract(verts, p2, p1);
|
var v2 = RcVecUtils.Subtract(verts, p2, p1);
|
||||||
var v3 = RcVecUtils.Subtract(verts, p3, p1);
|
var v3 = RcVecUtils.Subtract(verts, p3, p1);
|
||||||
|
|
||||||
|
@ -183,7 +184,7 @@ namespace DotRecast.Recast
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float DistPtTri(RcVec3f p, float[] verts, int a, int b, int c)
|
private static float DistPtTri(Vector3 p, float[] verts, int a, int b, int c)
|
||||||
{
|
{
|
||||||
var v0 = RcVecUtils.Subtract(verts, c, a);
|
var v0 = RcVecUtils.Subtract(verts, c, a);
|
||||||
var v1 = RcVecUtils.Subtract(verts, b, a);
|
var v1 = RcVecUtils.Subtract(verts, b, a);
|
||||||
|
@ -242,7 +243,7 @@ namespace DotRecast.Recast
|
||||||
return dx * dx + dy * dy + dz * dz;
|
return dx * dx + dy * dy + dz * dz;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float DistancePtSeg2d(RcVec3f verts, float[] poly, int p, int q)
|
private static float DistancePtSeg2d(Vector3 verts, float[] poly, int p, int q)
|
||||||
{
|
{
|
||||||
float pqx = poly[q + 0] - poly[p + 0];
|
float pqx = poly[q + 0] - poly[p + 0];
|
||||||
float pqz = poly[q + 2] - poly[p + 2];
|
float pqz = poly[q + 2] - poly[p + 2];
|
||||||
|
@ -298,7 +299,7 @@ namespace DotRecast.Recast
|
||||||
return dx * dx + dz * dz;
|
return dx * dx + dz * dz;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float DistToTriMesh(RcVec3f p, float[] verts, int nverts, List<int> tris, int ntris)
|
private static float DistToTriMesh(Vector3 p, float[] verts, int nverts, List<int> tris, int ntris)
|
||||||
{
|
{
|
||||||
float dmin = float.MaxValue;
|
float dmin = float.MaxValue;
|
||||||
for (int i = 0; i < ntris; ++i)
|
for (int i = 0; i < ntris; ++i)
|
||||||
|
@ -321,7 +322,7 @@ namespace DotRecast.Recast
|
||||||
return dmin;
|
return dmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float DistToPoly(int nvert, float[] verts, RcVec3f p)
|
private static float DistToPoly(int nvert, float[] verts, Vector3 p)
|
||||||
{
|
{
|
||||||
float dmin = float.MaxValue;
|
float dmin = float.MaxValue;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
@ -439,7 +440,7 @@ namespace DotRecast.Recast
|
||||||
return EV_UNDEF;
|
return EV_UNDEF;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddEdge(RcContext ctx, List<int> edges, int maxEdges, int s, int t, int l, int r)
|
private static void AddEdge(RcTelemetry ctx, List<int> edges, int maxEdges, int s, int t, int l, int r)
|
||||||
{
|
{
|
||||||
if (edges.Count / 4 >= maxEdges)
|
if (edges.Count / 4 >= maxEdges)
|
||||||
{
|
{
|
||||||
|
@ -507,7 +508,7 @@ namespace DotRecast.Recast
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CompleteFacet(RcContext ctx, float[] pts, int npts, List<int> edges, int maxEdges, int nfaces, int e)
|
static int CompleteFacet(RcTelemetry ctx, float[] pts, int npts, List<int> edges, int maxEdges, int nfaces, int e)
|
||||||
{
|
{
|
||||||
const float EPS = 1e-5f;
|
const float EPS = 1e-5f;
|
||||||
|
|
||||||
|
@ -533,7 +534,7 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
// Find best point on left of edge.
|
// Find best point on left of edge.
|
||||||
int pt = npts;
|
int pt = npts;
|
||||||
RcVec3f c = new RcVec3f();
|
Vector3 c = new Vector3();
|
||||||
RcAtomicFloat r = new RcAtomicFloat(-1f);
|
RcAtomicFloat r = new RcAtomicFloat(-1f);
|
||||||
for (int u = 0; u < npts; ++u)
|
for (int u = 0; u < npts; ++u)
|
||||||
{
|
{
|
||||||
|
@ -624,7 +625,7 @@ namespace DotRecast.Recast
|
||||||
return nfaces;
|
return nfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DelaunayHull(RcContext ctx, int npts, float[] pts, int nhull, int[] hull, List<int> tris)
|
private static void DelaunayHull(RcTelemetry ctx, int npts, float[] pts, int nhull, int[] hull, List<int> tris)
|
||||||
{
|
{
|
||||||
int nfaces = 0;
|
int nfaces = 0;
|
||||||
int maxEdges = npts * 10;
|
int maxEdges = npts * 10;
|
||||||
|
@ -828,7 +829,7 @@ namespace DotRecast.Recast
|
||||||
return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
|
return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BuildPolyDetail(RcContext ctx, float[] @in, int nin, float sampleDist, float sampleMaxError,
|
static int BuildPolyDetail(RcTelemetry ctx, float[] @in, int nin, float sampleDist, float sampleMaxError,
|
||||||
int heightSearchRadius, RcCompactHeightfield chf, RcHeightPatch hp, float[] verts, List<int> tris)
|
int heightSearchRadius, RcCompactHeightfield chf, RcHeightPatch hp, float[] verts, List<int> tris)
|
||||||
{
|
{
|
||||||
List<int> samples = new List<int>(512);
|
List<int> samples = new List<int>(512);
|
||||||
|
@ -869,7 +870,9 @@ namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
if (@in[vj + 2] > @in[vi + 2])
|
if (@in[vj + 2] > @in[vi + 2])
|
||||||
{
|
{
|
||||||
(vi, vj) = (vj, vi);
|
int temp = vi;
|
||||||
|
vi = vj;
|
||||||
|
vj = temp;
|
||||||
swapped = true;
|
swapped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -877,7 +880,9 @@ namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
if (@in[vj + 0] > @in[vi + 0])
|
if (@in[vj + 0] > @in[vi + 0])
|
||||||
{
|
{
|
||||||
(vi, vj) = (vj, vi);
|
int temp = vi;
|
||||||
|
vi = vj;
|
||||||
|
vj = temp;
|
||||||
swapped = true;
|
swapped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -997,8 +1002,8 @@ namespace DotRecast.Recast
|
||||||
if (sampleDist > 0)
|
if (sampleDist > 0)
|
||||||
{
|
{
|
||||||
// Create sample locations in a grid.
|
// Create sample locations in a grid.
|
||||||
RcVec3f bmin = RcVecUtils.Create(@in);
|
Vector3 bmin = RcVecUtils.Create(@in);
|
||||||
RcVec3f bmax = RcVecUtils.Create(@in);
|
Vector3 bmax = RcVecUtils.Create(@in);
|
||||||
for (int i = 1; i < nin; ++i)
|
for (int i = 1; i < nin; ++i)
|
||||||
{
|
{
|
||||||
bmin = RcVecUtils.Min(bmin, @in, i * 3);
|
bmin = RcVecUtils.Min(bmin, @in, i * 3);
|
||||||
|
@ -1014,7 +1019,7 @@ namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
for (int x = x0; x < x1; ++x)
|
for (int x = x0; x < x1; ++x)
|
||||||
{
|
{
|
||||||
RcVec3f pt = new RcVec3f();
|
Vector3 pt = new Vector3();
|
||||||
pt.X = x * sampleDist;
|
pt.X = x * sampleDist;
|
||||||
pt.Y = (bmax.Y + bmin.Y) * 0.5f;
|
pt.Y = (bmax.Y + bmin.Y) * 0.5f;
|
||||||
pt.Z = z * sampleDist;
|
pt.Z = z * sampleDist;
|
||||||
|
@ -1043,7 +1048,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find sample with most error.
|
// Find sample with most error.
|
||||||
RcVec3f bestpt = new RcVec3f();
|
Vector3 bestpt = new Vector3();
|
||||||
float bestd = 0;
|
float bestd = 0;
|
||||||
int besti = -1;
|
int besti = -1;
|
||||||
for (int i = 0; i < nsamples; ++i)
|
for (int i = 0; i < nsamples; ++i)
|
||||||
|
@ -1054,7 +1059,7 @@ namespace DotRecast.Recast
|
||||||
continue; // skip added.
|
continue; // skip added.
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVec3f pt = new RcVec3f();
|
Vector3 pt = new Vector3();
|
||||||
// The sample location is jittered to get rid of some bad triangulations
|
// The sample location is jittered to get rid of some bad triangulations
|
||||||
// which are cause by symmetrical data from the grid structure.
|
// which are cause by symmetrical data from the grid structure.
|
||||||
pt.X = samples[s + 0] * sampleDist + GetJitterX(i) * cs * 0.1f;
|
pt.X = samples[s + 0] * sampleDist + GetJitterX(i) * cs * 0.1f;
|
||||||
|
@ -1140,7 +1145,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void SeedArrayWithPolyCenter(RcContext ctx, RcCompactHeightfield chf, int[] meshpoly, int poly, int npoly,
|
static void SeedArrayWithPolyCenter(RcTelemetry ctx, RcCompactHeightfield chf, int[] meshpoly, int poly, int npoly,
|
||||||
int[] verts, int bs, RcHeightPatch hp, List<int> array)
|
int[] verts, int bs, RcHeightPatch hp, List<int> array)
|
||||||
{
|
{
|
||||||
// Note: Reads to the compact heightfield are offset by border size (bs)
|
// Note: Reads to the compact heightfield are offset by border size (bs)
|
||||||
|
@ -1298,7 +1303,7 @@ namespace DotRecast.Recast
|
||||||
queue.Add(v3);
|
queue.Add(v3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GetHeightData(RcContext ctx, RcCompactHeightfield chf, int[] meshpolys, int poly, int npoly, int[] verts,
|
static void GetHeightData(RcTelemetry ctx, RcCompactHeightfield chf, int[] meshpolys, int poly, int npoly, int[] verts,
|
||||||
int bs, RcHeightPatch hp, int region)
|
int bs, RcHeightPatch hp, int region)
|
||||||
{
|
{
|
||||||
// Note: Reads to the compact heightfield are offset by border size (bs)
|
// Note: Reads to the compact heightfield are offset by border size (bs)
|
||||||
|
@ -1424,7 +1429,7 @@ namespace DotRecast.Recast
|
||||||
/// See the #rcConfig documentation for more information on the configuration parameters.
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
///
|
///
|
||||||
/// @see rcAllocPolyMeshDetail, rcPolyMesh, rcCompactHeightfield, rcPolyMeshDetail, rcConfig
|
/// @see rcAllocPolyMeshDetail, rcPolyMesh, rcCompactHeightfield, rcPolyMeshDetail, rcConfig
|
||||||
public static RcPolyMeshDetail BuildPolyMeshDetail(RcContext ctx, RcPolyMesh mesh, RcCompactHeightfield chf,
|
public static RcPolyMeshDetail BuildPolyMeshDetail(RcTelemetry ctx, RcPolyMesh mesh, RcCompactHeightfield chf,
|
||||||
float sampleDist, float sampleMaxError)
|
float sampleDist, float sampleMaxError)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_POLYMESHDETAIL);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_POLYMESHDETAIL);
|
||||||
|
@ -1437,7 +1442,7 @@ namespace DotRecast.Recast
|
||||||
int nvp = mesh.nvp;
|
int nvp = mesh.nvp;
|
||||||
float cs = mesh.cs;
|
float cs = mesh.cs;
|
||||||
float ch = mesh.ch;
|
float ch = mesh.ch;
|
||||||
RcVec3f orig = mesh.bmin;
|
Vector3 orig = mesh.bmin;
|
||||||
int borderSize = mesh.borderSize;
|
int borderSize = mesh.borderSize;
|
||||||
int heightSearchRadius = (int)Math.Max(1, MathF.Ceiling(mesh.maxEdgeError));
|
int heightSearchRadius = (int)Math.Max(1, MathF.Ceiling(mesh.maxEdgeError));
|
||||||
|
|
||||||
|
@ -1614,7 +1619,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail
|
/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail
|
||||||
private static RcPolyMeshDetail MergePolyMeshDetails(RcContext ctx, RcPolyMeshDetail[] meshes, int nmeshes)
|
private static RcPolyMeshDetail MergePolyMeshDetails(RcTelemetry ctx, RcPolyMeshDetail[] meshes, int nmeshes)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MERGE_POLYMESHDETAIL);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MERGE_POLYMESHDETAIL);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
|
@ -577,7 +578,7 @@ namespace DotRecast.Recast
|
||||||
return an;
|
return an;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CanRemoveVertex(RcContext ctx, RcPolyMesh mesh, int rem)
|
private static bool CanRemoveVertex(RcTelemetry ctx, RcPolyMesh mesh, int rem)
|
||||||
{
|
{
|
||||||
int nvp = mesh.nvp;
|
int nvp = mesh.nvp;
|
||||||
|
|
||||||
|
@ -680,7 +681,7 @@ namespace DotRecast.Recast
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RemoveVertex(RcContext ctx, RcPolyMesh mesh, int rem, int maxTris)
|
private static void RemoveVertex(RcTelemetry ctx, RcPolyMesh mesh, int rem, int maxTris)
|
||||||
{
|
{
|
||||||
int nvp = mesh.nvp;
|
int nvp = mesh.nvp;
|
||||||
|
|
||||||
|
@ -967,7 +968,7 @@ namespace DotRecast.Recast
|
||||||
/// limit must be restricted to <= #DT_VERTS_PER_POLYGON.
|
/// limit must be restricted to <= #DT_VERTS_PER_POLYGON.
|
||||||
///
|
///
|
||||||
/// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig
|
/// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig
|
||||||
public static RcPolyMesh BuildPolyMesh(RcContext ctx, RcContourSet cset, int nvp)
|
public static RcPolyMesh BuildPolyMesh(RcTelemetry ctx, RcContourSet cset, int nvp)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_POLYMESH);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_POLYMESH);
|
||||||
|
|
||||||
|
@ -1212,7 +1213,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @see rcAllocPolyMesh, rcPolyMesh
|
/// @see rcAllocPolyMesh, rcPolyMesh
|
||||||
public static RcPolyMesh MergePolyMeshes(RcContext ctx, RcPolyMesh[] meshes, int nmeshes)
|
public static RcPolyMesh MergePolyMeshes(RcTelemetry ctx, RcPolyMesh[] meshes, int nmeshes)
|
||||||
{
|
{
|
||||||
if (nmeshes == 0 || meshes == null)
|
if (nmeshes == 0 || meshes == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -1231,8 +1232,8 @@ namespace DotRecast.Recast
|
||||||
int maxVertsPerMesh = 0;
|
int maxVertsPerMesh = 0;
|
||||||
for (int i = 0; i < nmeshes; ++i)
|
for (int i = 0; i < nmeshes; ++i)
|
||||||
{
|
{
|
||||||
mesh.bmin = RcVec3f.Min(mesh.bmin, meshes[i].bmin);
|
mesh.bmin = Vector3.Min(mesh.bmin, meshes[i].bmin);
|
||||||
mesh.bmax = RcVec3f.Max(mesh.bmax, meshes[i].bmax);
|
mesh.bmax = Vector3.Max(mesh.bmax, meshes[i].bmax);
|
||||||
maxVertsPerMesh = Math.Max(maxVertsPerMesh, meshes[i].nverts);
|
maxVertsPerMesh = Math.Max(maxVertsPerMesh, meshes[i].nverts);
|
||||||
maxVerts += meshes[i].nverts;
|
maxVerts += meshes[i].nverts;
|
||||||
maxPolys += meshes[i].npolys;
|
maxPolys += meshes[i].npolys;
|
||||||
|
@ -1340,7 +1341,7 @@ namespace DotRecast.Recast
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RcPolyMesh CopyPolyMesh(RcContext ctx, RcPolyMesh src)
|
public static RcPolyMesh CopyPolyMesh(RcTelemetry ctx, RcPolyMesh src)
|
||||||
{
|
{
|
||||||
RcPolyMesh dst = new RcPolyMesh();
|
RcPolyMesh dst = new RcPolyMesh();
|
||||||
|
|
||||||
|
|
|
@ -19,29 +19,56 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
/// Represents a polygon mesh suitable for use in building a navigation mesh.
|
/** Represents a polygon mesh suitable for use in building a navigation mesh. */
|
||||||
/// @ingroup recast
|
|
||||||
public class RcPolyMesh
|
public class RcPolyMesh
|
||||||
{
|
{
|
||||||
public int[] verts; // The mesh vertices. [Form: (x, y, z) coordinates * #nverts]
|
/** The mesh vertices. [Form: (x, y, z) coordinates * #nverts] */
|
||||||
public int[] polys; // Polygon and neighbor data. [Length: #maxpolys * 2 * #nvp]
|
public int[] verts;
|
||||||
public int[] regs; // The region id assigned to each polygon. [Length: #maxpolys]
|
|
||||||
public int[] areas; // The area id assigned to each polygon. [Length: #maxpolys]
|
|
||||||
public int nverts; // The number of vertices.
|
|
||||||
public int npolys; // The number of polygons.
|
|
||||||
public int nvp; // The maximum number of vertices per polygon.
|
|
||||||
public int maxpolys; // The number of allocated polygons.
|
|
||||||
public int[] flags; // The user defined flags for each polygon. [Length: #maxpolys]
|
|
||||||
public RcVec3f bmin = new RcVec3f(); // The minimum bounds in world space. [(x, y, z)]
|
|
||||||
public RcVec3f bmax = new RcVec3f(); // The maximum bounds in world space. [(x, y, z)]
|
|
||||||
|
|
||||||
public float cs; // The size of each cell. (On the xz-plane.)
|
/** Polygon and neighbor data. [Length: #maxpolys * 2 * #nvp] */
|
||||||
public float ch; // The height of each cell. (The minimum increment along the y-axis.)
|
public int[] polys;
|
||||||
|
|
||||||
public int borderSize; // The AABB border size used to generate the source data from which the mesh was derived.
|
/** The region id assigned to each polygon. [Length: #maxpolys] */
|
||||||
public float maxEdgeError; // The max error of the polygon edges in the mesh.
|
public int[] regs;
|
||||||
|
|
||||||
|
/** The area id assigned to each polygon. [Length: #maxpolys] */
|
||||||
|
public int[] areas;
|
||||||
|
|
||||||
|
/** The number of vertices. */
|
||||||
|
public int nverts;
|
||||||
|
|
||||||
|
/** The number of polygons. */
|
||||||
|
public int npolys;
|
||||||
|
|
||||||
|
/** The maximum number of vertices per polygon. */
|
||||||
|
public int nvp;
|
||||||
|
|
||||||
|
/** The number of allocated polygons. */
|
||||||
|
public int maxpolys;
|
||||||
|
|
||||||
|
/** The user defined flags for each polygon. [Length: #maxpolys] */
|
||||||
|
public int[] flags;
|
||||||
|
|
||||||
|
/** The minimum bounds in world space. [(x, y, z)] */
|
||||||
|
public Vector3 bmin = new Vector3();
|
||||||
|
|
||||||
|
/** The maximum bounds in world space. [(x, y, z)] */
|
||||||
|
public Vector3 bmax = new Vector3();
|
||||||
|
|
||||||
|
/** The size of each cell. (On the xz-plane.) */
|
||||||
|
public float cs;
|
||||||
|
|
||||||
|
/** The height of each cell. (The minimum increment along the y-axis.) */
|
||||||
|
public float ch;
|
||||||
|
|
||||||
|
/** The AABB border size used to generate the source data from which the mesh was derived. */
|
||||||
|
public int borderSize;
|
||||||
|
|
||||||
|
/** The max error of the polygon edges in the mesh. */
|
||||||
|
public float maxEdgeError;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,16 +20,28 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
/// Contains triangle meshes that represent detailed height data associated
|
/**
|
||||||
/// with the polygons in its associated polygon mesh object.
|
* Contains triangle meshes that represent detailed height data associated with the polygons in its associated polygon
|
||||||
/// @ingroup recast
|
* mesh object.
|
||||||
|
*/
|
||||||
public class RcPolyMeshDetail
|
public class RcPolyMeshDetail
|
||||||
{
|
{
|
||||||
public int[] meshes; //< The sub-mesh data. [Size: 4*#nmeshes]
|
/** The sub-mesh data. [Size: 4*#nmeshes] */
|
||||||
public float[] verts; //< The mesh vertices. [Size: 3*#nverts]
|
public int[] meshes;
|
||||||
public int[] tris; //< The mesh triangles. [Size: 4*#ntris]
|
|
||||||
public int nmeshes; //< The number of sub-meshes defined by #meshes.
|
/** The mesh vertices. [Size: 3*#nverts] */
|
||||||
public int nverts; //< The number of vertices in #verts.
|
public float[] verts;
|
||||||
public int ntris; //< The number of triangles in #tris.
|
|
||||||
|
/** The mesh triangles. [Size: 4*#ntris] */
|
||||||
|
public int[] tris;
|
||||||
|
|
||||||
|
/** The number of sub-meshes defined by #meshes. */
|
||||||
|
public int nmeshes;
|
||||||
|
|
||||||
|
/** The number of vertices in #verts. */
|
||||||
|
public int nverts;
|
||||||
|
|
||||||
|
/** The number of triangles in #tris. */
|
||||||
|
public int ntris;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,12 +20,13 @@ freely, subject to the following restrictions:
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
public static class RcPolyMeshRaycast
|
public static class RcPolyMeshRaycast
|
||||||
{
|
{
|
||||||
public static bool Raycast(IList<RcBuilderResult> results, RcVec3f src, RcVec3f dst, out float hitTime)
|
public static bool Raycast(IList<RcBuilderResult> results, Vector3 src, Vector3 dst, out float hitTime)
|
||||||
{
|
{
|
||||||
hitTime = 0.0f;
|
hitTime = 0.0f;
|
||||||
foreach (RcBuilderResult result in results)
|
foreach (RcBuilderResult result in results)
|
||||||
|
@ -42,7 +43,7 @@ namespace DotRecast.Recast
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool Raycast(RcPolyMesh poly, RcPolyMeshDetail meshDetail, RcVec3f sp, RcVec3f sq, out float hitTime)
|
private static bool Raycast(RcPolyMesh poly, RcPolyMeshDetail meshDetail, Vector3 sp, Vector3 sq, out float hitTime)
|
||||||
{
|
{
|
||||||
hitTime = 0;
|
hitTime = 0;
|
||||||
if (meshDetail != null)
|
if (meshDetail != null)
|
||||||
|
@ -57,7 +58,7 @@ namespace DotRecast.Recast
|
||||||
int tris = btris * 4;
|
int tris = btris * 4;
|
||||||
for (int j = 0; j < ntris; ++j)
|
for (int j = 0; j < ntris; ++j)
|
||||||
{
|
{
|
||||||
RcVec3f[] vs = new RcVec3f[3];
|
Vector3[] vs = new Vector3[3];
|
||||||
for (int k = 0; k < 3; ++k)
|
for (int k = 0; k < 3; ++k)
|
||||||
{
|
{
|
||||||
vs[k].X = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3];
|
vs[k].X = meshDetail.verts[verts + meshDetail.tris[tris + j * 4 + k] * 3];
|
||||||
|
|
|
@ -21,25 +21,42 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using static DotRecast.Recast.RcConstants;
|
using static DotRecast.Recast.RcConstants;
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
public static class RcRasterizations
|
public static class RcRasterizations
|
||||||
{
|
{
|
||||||
/// Check whether two bounding boxes overlap
|
/**
|
||||||
///
|
* Check whether two bounding boxes overlap
|
||||||
/// @param[in] aMin Min axis extents of bounding box A
|
*
|
||||||
/// @param[in] aMax Max axis extents of bounding box A
|
* @param amin
|
||||||
/// @param[in] bMin Min axis extents of bounding box B
|
* Min axis extents of bounding box A
|
||||||
/// @param[in] bMax Max axis extents of bounding box B
|
* @param amax
|
||||||
/// @returns true if the two bounding boxes overlap. False otherwise.
|
* Max axis extents of bounding box A
|
||||||
private static bool OverlapBounds(RcVec3f aMin, RcVec3f aMax, RcVec3f bMin, RcVec3f bMax)
|
* @param bmin
|
||||||
|
* Min axis extents of bounding box B
|
||||||
|
* @param bmax
|
||||||
|
* Max axis extents of bounding box B
|
||||||
|
* @returns true if the two bounding boxes overlap. False otherwise
|
||||||
|
*/
|
||||||
|
private static bool OverlapBounds(float[] amin, float[] amax, float[] bmin, float[] bmax)
|
||||||
{
|
{
|
||||||
return
|
bool overlap = true;
|
||||||
aMin.X <= bMax.X && aMax.X >= bMin.X &&
|
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||||
aMin.Y <= bMax.Y && aMax.Y >= bMin.Y &&
|
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||||
aMin.Z <= bMax.Z && aMax.Z >= bMin.Z;
|
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool OverlapBounds(Vector3 amin, Vector3 amax, Vector3 bmin, Vector3 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;
|
||||||
|
overlap = (amin.Z > bmax.Z || amax.Z < bmin.Z) ? false : overlap;
|
||||||
|
return overlap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,89 +70,72 @@ namespace DotRecast.Recast
|
||||||
/// @param[in] max The new span's maximum cell index
|
/// @param[in] max The new span's maximum cell index
|
||||||
/// @param[in] areaID The new span's area type ID
|
/// @param[in] areaID The new span's area type ID
|
||||||
/// @param[in] flagMergeThreshold How close two spans maximum extents need to be to merge area type IDs
|
/// @param[in] flagMergeThreshold How close two spans maximum extents need to be to merge area type IDs
|
||||||
public static void AddSpan(RcHeightfield heightfield, int x, int z, int min, int max, int areaID, int flagMergeThreshold)
|
public static void AddSpan(RcHeightfield heightfield, int x, int y, int spanMin, int spanMax, int areaId, int flagMergeThreshold)
|
||||||
{
|
{
|
||||||
// Create the new span.
|
int idx = x + y * heightfield.width;
|
||||||
RcSpan newSpan = new RcSpan();
|
|
||||||
newSpan.smin = min;
|
|
||||||
newSpan.smax = max;
|
|
||||||
newSpan.area = areaID;
|
|
||||||
newSpan.next = null;
|
|
||||||
|
|
||||||
int columnIndex = x + z * heightfield.width;
|
RcSpan s = new RcSpan();
|
||||||
|
s.smin = spanMin;
|
||||||
|
s.smax = spanMax;
|
||||||
|
s.area = areaId;
|
||||||
|
s.next = null;
|
||||||
|
|
||||||
// Empty cell, add the first span.
|
// Empty cell, add the first span.
|
||||||
if (heightfield.spans[columnIndex] == null)
|
if (heightfield.spans[idx] == null)
|
||||||
{
|
{
|
||||||
heightfield.spans[columnIndex] = newSpan;
|
heightfield.spans[idx] = s;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RcSpan previousSpan = null;
|
RcSpan prev = null;
|
||||||
RcSpan currentSpan = heightfield.spans[columnIndex];
|
RcSpan cur = heightfield.spans[idx];
|
||||||
|
|
||||||
// Insert the new span, possibly merging it with existing spans.
|
// Insert and merge spans.
|
||||||
while (currentSpan != null)
|
while (cur != null)
|
||||||
{
|
{
|
||||||
if (currentSpan.smin > newSpan.smax)
|
if (cur.smin > s.smax)
|
||||||
{
|
{
|
||||||
// Current span is further than the new span, break.
|
// Current span is further than the new span, break.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (cur.smax < s.smin)
|
||||||
if (currentSpan.smax < newSpan.smin)
|
|
||||||
{
|
{
|
||||||
// Current span is completely before the new span. Keep going.
|
// Current span is before the new span advance.
|
||||||
previousSpan = currentSpan;
|
prev = cur;
|
||||||
currentSpan = currentSpan.next;
|
cur = cur.next;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The new span overlaps with an existing span. Merge them.
|
// Merge spans.
|
||||||
if (currentSpan.smin < newSpan.smin)
|
if (cur.smin < s.smin)
|
||||||
{
|
s.smin = cur.smin;
|
||||||
newSpan.smin = currentSpan.smin;
|
if (cur.smax > s.smax)
|
||||||
}
|
s.smax = cur.smax;
|
||||||
|
|
||||||
if (currentSpan.smax > newSpan.smax)
|
|
||||||
{
|
|
||||||
newSpan.smax = currentSpan.smax;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge flags.
|
// Merge flags.
|
||||||
if (MathF.Abs(newSpan.smax - currentSpan.smax) <= flagMergeThreshold)
|
if (MathF.Abs(s.smax - cur.smax) <= flagMergeThreshold)
|
||||||
{
|
s.area = Math.Max(s.area, cur.area);
|
||||||
// Higher area ID numbers indicate higher resolution priority.
|
|
||||||
newSpan.area = Math.Max(newSpan.area, currentSpan.area);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the current span since it's now merged with newSpan.
|
// Remove current span.
|
||||||
// Keep going because there might be other overlapping spans that also need to be merged.
|
RcSpan next = cur.next;
|
||||||
RcSpan next = currentSpan.next;
|
if (prev != null)
|
||||||
if (previousSpan != null)
|
prev.next = next;
|
||||||
{
|
|
||||||
previousSpan.next = next;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
heightfield.spans[idx] = next;
|
||||||
heightfield.spans[columnIndex] = next;
|
cur = next;
|
||||||
}
|
|
||||||
|
|
||||||
currentSpan = next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert new span after prev
|
// Insert new span.
|
||||||
if (previousSpan != null)
|
if (prev != null)
|
||||||
{
|
{
|
||||||
newSpan.next = previousSpan.next;
|
s.next = prev.next;
|
||||||
previousSpan.next = newSpan;
|
prev.next = s;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This span should go before the others in the list
|
s.next = heightfield.spans[idx];
|
||||||
newSpan.next = heightfield.spans[columnIndex];
|
heightfield.spans[idx] = s;
|
||||||
heightfield.spans[columnIndex] = newSpan;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,53 +155,54 @@ namespace DotRecast.Recast
|
||||||
int outVerts2, out int outVerts2Count,
|
int outVerts2, out int outVerts2Count,
|
||||||
float axisOffset, int axis)
|
float axisOffset, int axis)
|
||||||
{
|
{
|
||||||
|
float[] d = new float[12];
|
||||||
|
|
||||||
// How far positive or negative away from the separating axis is each vertex.
|
// How far positive or negative away from the separating axis is each vertex.
|
||||||
float[] inVertAxisDelta = new float[12];
|
|
||||||
for (int inVert = 0; inVert < inVertsCount; ++inVert)
|
for (int inVert = 0; inVert < inVertsCount; ++inVert)
|
||||||
{
|
{
|
||||||
inVertAxisDelta[inVert] = axisOffset - inVerts[inVertsOffset + inVert * 3 + axis];
|
d[inVert] = axisOffset - inVerts[inVertsOffset + inVert * 3 + axis];
|
||||||
}
|
}
|
||||||
|
|
||||||
int poly1Vert = 0;
|
int poly1Vert = 0;
|
||||||
int poly2Vert = 0;
|
int poly2Vert = 0;
|
||||||
for (int inVertA = 0, inVertB = inVertsCount - 1; inVertA < inVertsCount; inVertB = inVertA, ++inVertA)
|
for (int inVertA = 0, inVertB = inVertsCount - 1; inVertA < inVertsCount; inVertB = inVertA, ++inVertA)
|
||||||
{
|
{
|
||||||
// If the two vertices are on the same side of the separating axis
|
bool ina = d[inVertB] >= 0;
|
||||||
bool sameSide = (inVertAxisDelta[inVertA] >= 0) == (inVertAxisDelta[inVertB] >= 0);
|
bool inb = d[inVertA] >= 0;
|
||||||
if (!sameSide)
|
if (ina != inb)
|
||||||
{
|
{
|
||||||
float s = inVertAxisDelta[inVertB] / (inVertAxisDelta[inVertB] - inVertAxisDelta[inVertA]);
|
float s = d[inVertB] / (d[inVertB] - d[inVertA]);
|
||||||
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 + 0] = inVerts[inVertsOffset + inVertB * 3 + 0] +
|
||||||
inVerts[outVerts1 + poly1Vert * 3 + 1] = inVerts[inVertsOffset + inVertB * 3 + 1] + (inVerts[inVertsOffset + inVertA * 3 + 1] - inVerts[inVertsOffset + inVertB * 3 + 1]) * s;
|
(inVerts[inVertsOffset + inVertA * 3 + 0] - inVerts[inVertsOffset + inVertB * 3 + 0]) * s;
|
||||||
inVerts[outVerts1 + poly1Vert * 3 + 2] = inVerts[inVertsOffset + inVertB * 3 + 2] + (inVerts[inVertsOffset + inVertA * 3 + 2] - inVerts[inVertsOffset + inVertB * 3 + 2]) * 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);
|
RcVecUtils.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, outVerts1 + poly1Vert * 3);
|
||||||
poly1Vert++;
|
poly1Vert++;
|
||||||
poly2Vert++;
|
poly2Vert++;
|
||||||
|
|
||||||
// add the i'th point to the right polygon. Do NOT add points that are on the dividing line
|
// add the i'th point to the right polygon. Do NOT add points that are on the dividing line
|
||||||
// since these were already added above
|
// since these were already added above
|
||||||
if (inVertAxisDelta[inVertA] > 0)
|
if (d[inVertA] > 0)
|
||||||
{
|
{
|
||||||
RcVecUtils.Copy(inVerts, outVerts1 + poly1Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
RcVecUtils.Copy(inVerts, outVerts1 + poly1Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||||
poly1Vert++;
|
poly1Vert++;
|
||||||
}
|
}
|
||||||
else if (inVertAxisDelta[inVertA] < 0)
|
else if (d[inVertA] < 0)
|
||||||
{
|
{
|
||||||
RcVecUtils.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
RcVecUtils.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||||
poly2Vert++;
|
poly2Vert++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else // same side
|
||||||
{
|
{
|
||||||
// add the i'th point to the right polygon. Addition is done even for points on the dividing line
|
// add the i'th point to the right polygon. Addition is done even for points on the dividing line
|
||||||
if (inVertAxisDelta[inVertA] >= 0)
|
if (d[inVertA] >= 0)
|
||||||
{
|
{
|
||||||
RcVecUtils.Copy(inVerts, outVerts1 + poly1Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
RcVecUtils.Copy(inVerts, outVerts1 + poly1Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||||
poly1Vert++;
|
poly1Vert++;
|
||||||
if (inVertAxisDelta[inVertA] != 0)
|
if (d[inVertA] != 0)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RcVecUtils.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
RcVecUtils.Copy(inVerts, outVerts2 + poly2Vert * 3, inVerts, inVertsOffset + inVertA * 3);
|
||||||
|
@ -229,35 +230,31 @@ namespace DotRecast.Recast
|
||||||
/// @param[in] inverseCellHeight 1 / cellHeight
|
/// @param[in] inverseCellHeight 1 / cellHeight
|
||||||
/// @param[in] flagMergeThreshold The threshold in which area flags will be merged
|
/// @param[in] flagMergeThreshold The threshold in which area flags will be merged
|
||||||
/// @returns true if the operation completes successfully. false if there was an error adding spans to the heightfield.
|
/// @returns true if the operation completes successfully. false if there was an error adding spans to the heightfield.
|
||||||
private static bool RasterizeTri(float[] verts, int v0, int v1, int v2,
|
private static void RasterizeTri(float[] verts, int v0, int v1, int v2, int area, RcHeightfield heightfield,
|
||||||
int areaID, RcHeightfield heightfield,
|
Vector3 heightfieldBBMin, Vector3 heightfieldBBMax,
|
||||||
RcVec3f heightfieldBBMin, RcVec3f heightfieldBBMax,
|
|
||||||
float cellSize, float inverseCellSize, float inverseCellHeight,
|
float cellSize, float inverseCellSize, float inverseCellHeight,
|
||||||
int flagMergeThreshold)
|
int flagMergeThreshold)
|
||||||
{
|
{
|
||||||
|
float by = heightfieldBBMax.Y - heightfieldBBMin.Y;
|
||||||
|
|
||||||
// Calculate the bounding box of the triangle.
|
// Calculate the bounding box of the triangle.
|
||||||
RcVec3f triBBMin = RcVecUtils.Create(verts, v0 * 3);
|
Vector3 tmin = RcVecUtils.Create(verts, v0 * 3);
|
||||||
triBBMin = RcVecUtils.Min(triBBMin, verts, v1 * 3);
|
Vector3 tmax = RcVecUtils.Create(verts, v0 * 3);
|
||||||
triBBMin = RcVecUtils.Min(triBBMin, verts, v2 * 3);
|
tmin = RcVecUtils.Min(tmin, verts, v1 * 3);
|
||||||
|
tmin = RcVecUtils.Min(tmin, verts, v2 * 3);
|
||||||
|
tmax = RcVecUtils.Max(tmax, verts, v1 * 3);
|
||||||
|
tmax = RcVecUtils.Max(tmax, verts, v2 * 3);
|
||||||
|
|
||||||
RcVec3f triBBMax = RcVecUtils.Create(verts, v0 * 3);
|
// If the triangle does not touch the bbox of the heightfield, skip the triagle.
|
||||||
triBBMax = RcVecUtils.Max(triBBMax, verts, v1 * 3);
|
if (!OverlapBounds(heightfieldBBMin, heightfieldBBMax, tmin, tmax))
|
||||||
triBBMax = RcVecUtils.Max(triBBMax, verts, v2 * 3);
|
return;
|
||||||
|
|
||||||
// If the triangle does not touch the bounding box of the heightfield, skip the triangle.
|
// Calculate the footprint of the triangle on the grid's y-axis
|
||||||
if (!OverlapBounds(triBBMin, triBBMax, heightfieldBBMin, heightfieldBBMax))
|
int z0 = (int)((tmin.Z - heightfieldBBMin.Z) * inverseCellSize);
|
||||||
{
|
int z1 = (int)((tmax.Z - heightfieldBBMin.Z) * inverseCellSize);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int w = heightfield.width;
|
int w = heightfield.width;
|
||||||
int h = heightfield.height;
|
int h = heightfield.height;
|
||||||
float by = heightfieldBBMax.Y - heightfieldBBMin.Y;
|
|
||||||
|
|
||||||
// Calculate the footprint of the triangle on the grid's y-axis
|
|
||||||
int z0 = (int)((triBBMin.Z - heightfieldBBMin.Z) * inverseCellSize);
|
|
||||||
int z1 = (int)((triBBMax.Z - heightfieldBBMin.Z) * inverseCellSize);
|
|
||||||
|
|
||||||
// use -1 rather than 0 to cut the polygon properly at the start of the tile
|
// use -1 rather than 0 to cut the polygon properly at the start of the tile
|
||||||
z0 = Math.Clamp(z0, -1, h - 1);
|
z0 = Math.Clamp(z0, -1, h - 1);
|
||||||
z1 = Math.Clamp(z1, 0, h - 1);
|
z1 = Math.Clamp(z1, 0, h - 1);
|
||||||
|
@ -272,29 +269,25 @@ namespace DotRecast.Recast
|
||||||
RcVecUtils.Copy(buf, 0, verts, v0 * 3);
|
RcVecUtils.Copy(buf, 0, verts, v0 * 3);
|
||||||
RcVecUtils.Copy(buf, 3, verts, v1 * 3);
|
RcVecUtils.Copy(buf, 3, verts, v1 * 3);
|
||||||
RcVecUtils.Copy(buf, 6, verts, v2 * 3);
|
RcVecUtils.Copy(buf, 6, verts, v2 * 3);
|
||||||
int nvRow;
|
int nvRow, nvIn = 3;
|
||||||
int nvIn = 3;
|
|
||||||
|
|
||||||
for (int z = z0; z <= z1; ++z)
|
for (int z = z0; z <= z1; ++z)
|
||||||
{
|
{
|
||||||
// Clip polygon to row. Store the remaining polygon as well
|
// Clip polygon to row. Store the remaining polygon as well
|
||||||
float cellZ = heightfieldBBMin.Z + z * cellSize;
|
float cellZ = heightfieldBBMin.Z + z * cellSize;
|
||||||
DividePoly(buf, @in, nvIn, inRow, out nvRow, p1, out nvIn, cellZ + cellSize, RcAxis.RC_AXIS_Z);
|
DividePoly(buf, @in, nvIn, inRow, out nvRow, p1, out nvIn, cellZ + cellSize, 2);
|
||||||
(@in, p1) = (p1, @in);
|
(@in, p1) = (p1, @in);
|
||||||
|
|
||||||
if (nvRow < 3)
|
if (nvRow < 3)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (z < 0)
|
if (z < 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find X-axis bounds of the row
|
// find the horizontal bounds in the row
|
||||||
float minX = buf[inRow];
|
float minX = buf[inRow], maxX = buf[inRow];
|
||||||
float maxX = buf[inRow];
|
|
||||||
for (int i = 1; i < nvRow; ++i)
|
for (int i = 1; i < nvRow; ++i)
|
||||||
{
|
{
|
||||||
float v = buf[inRow + i * 3];
|
float v = buf[inRow + i * 3];
|
||||||
|
@ -312,19 +305,16 @@ namespace DotRecast.Recast
|
||||||
x0 = Math.Clamp(x0, -1, w - 1);
|
x0 = Math.Clamp(x0, -1, w - 1);
|
||||||
x1 = Math.Clamp(x1, 0, w - 1);
|
x1 = Math.Clamp(x1, 0, w - 1);
|
||||||
|
|
||||||
int nv;
|
int nv, nv2 = nvRow;
|
||||||
int nv2 = nvRow;
|
|
||||||
for (int x = x0; x <= x1; ++x)
|
for (int x = x0; x <= x1; ++x)
|
||||||
{
|
{
|
||||||
// Clip polygon to column. store the remaining polygon as well
|
// Clip polygon to column. store the remaining polygon as well
|
||||||
float cx = heightfieldBBMin.X + x * cellSize;
|
float cx = heightfieldBBMin.X + x * cellSize;
|
||||||
DividePoly(buf, inRow, nv2, p1, out nv, p2, out nv2, cx + cellSize, RcAxis.RC_AXIS_X);
|
DividePoly(buf, inRow, nv2, p1, out nv, p2, out nv2, cx + cellSize, 0);
|
||||||
(inRow, p2) = (p2, inRow);
|
(inRow, p2) = (p2, inRow);
|
||||||
|
|
||||||
if (nv < 3)
|
if (nv < 3)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
{
|
{
|
||||||
|
@ -342,89 +332,80 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
spanMin -= heightfieldBBMin.Y;
|
spanMin -= heightfieldBBMin.Y;
|
||||||
spanMax -= heightfieldBBMin.Y;
|
spanMax -= heightfieldBBMin.Y;
|
||||||
|
|
||||||
// Skip the span if it is outside the heightfield bbox
|
// Skip the span if it is outside the heightfield bbox
|
||||||
if (spanMax < 0.0f)
|
if (spanMax < 0.0f)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (spanMin > by)
|
if (spanMin > by)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// Clamp the span to the heightfield bbox.
|
// Clamp the span to the heightfield bbox.
|
||||||
if (spanMin < 0.0f)
|
if (spanMin < 0.0f)
|
||||||
{
|
|
||||||
spanMin = 0;
|
spanMin = 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (spanMax > by)
|
if (spanMax > by)
|
||||||
{
|
|
||||||
spanMax = by;
|
spanMax = by;
|
||||||
}
|
|
||||||
|
|
||||||
// Snap the span to the heightfield height grid.
|
// Snap the span to the heightfield height grid.
|
||||||
int spanMinCellIndex = Math.Clamp((int)MathF.Floor(spanMin * inverseCellHeight), 0, RC_SPAN_MAX_HEIGHT);
|
int spanMinCellIndex = Math.Clamp((int)MathF.Floor(spanMin * inverseCellHeight), 0, SPAN_MAX_HEIGHT);
|
||||||
int spanMaxCellIndex = Math.Clamp((int)MathF.Ceiling(spanMax * inverseCellHeight), spanMinCellIndex + 1, RC_SPAN_MAX_HEIGHT);
|
int spanMaxCellIndex = Math.Clamp((int)MathF.Ceiling(spanMax * inverseCellHeight), spanMinCellIndex + 1, SPAN_MAX_HEIGHT);
|
||||||
|
|
||||||
AddSpan(heightfield, x, z, spanMinCellIndex, spanMaxCellIndex, areaID, flagMergeThreshold);
|
AddSpan(heightfield, x, z, spanMinCellIndex, spanMaxCellIndex, area, flagMergeThreshold);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rasterizes a single triangle into the specified heightfield.
|
/**
|
||||||
///
|
* Rasterizes a single triangle into the specified heightfield. Calling this for each triangle in a mesh is less
|
||||||
/// Calling this for each triangle in a mesh is less efficient than calling rcRasterizeTriangles
|
* efficient than calling rasterizeTriangles. No spans will be added if the triangle does not overlap the
|
||||||
///
|
* heightfield grid.
|
||||||
/// No spans will be added if the triangle does not overlap the heightfield grid.
|
*
|
||||||
///
|
* @param heightfield
|
||||||
/// @see rcHeightfield
|
* An initialized heightfield.
|
||||||
/// @ingroup recast
|
* @param verts
|
||||||
/// @param[in,out] context The build context to use during the operation.
|
* An array with vertex coordinates [(x, y, z) * N]
|
||||||
/// @param[in] v0 Triangle vertex 0 [(x, y, z)]
|
* @param v0
|
||||||
/// @param[in] v1 Triangle vertex 1 [(x, y, z)]
|
* Index of triangle vertex 0, will be multiplied by 3 to get vertex coordinates
|
||||||
/// @param[in] v2 Triangle vertex 2 [(x, y, z)]
|
* @param v1
|
||||||
/// @param[in] areaID The area id of the triangle. [Limit: <= #RC_WALKABLE_AREA]
|
* Triangle vertex 1 index
|
||||||
/// @param[in,out] heightfield An initialized heightfield.
|
* @param v2
|
||||||
/// @param[in] flagMergeThreshold The distance where the walkable flag is favored over the non-walkable flag.
|
* Triangle vertex 2 index
|
||||||
/// [Limit: >= 0] [Units: vx]
|
* @param areaId
|
||||||
/// @returns True if the operation completed successfully.
|
* The area id of the triangle. [Limit: <= WALKABLE_AREA)
|
||||||
public static void RasterizeTriangle(RcContext context, float[] verts, int v0, int v1, int v2, int areaID,
|
* @param flagMergeThreshold
|
||||||
RcHeightfield heightfield, int flagMergeThreshold)
|
* The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx]
|
||||||
|
* @see Heightfield
|
||||||
|
*/
|
||||||
|
public static void RasterizeTriangle(RcHeightfield heightfield, float[] verts, int v0, int v1, int v2, int area,
|
||||||
|
int flagMergeThreshold, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
|
||||||
|
|
||||||
// Rasterize the single triangle.
|
|
||||||
float inverseCellSize = 1.0f / heightfield.cs;
|
float inverseCellSize = 1.0f / heightfield.cs;
|
||||||
float inverseCellHeight = 1.0f / heightfield.ch;
|
float inverseCellHeight = 1.0f / heightfield.ch;
|
||||||
RasterizeTri(verts, v0, v1, v2, areaID, heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize,
|
RasterizeTri(verts, v0, v1, v2, area, heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize,
|
||||||
inverseCellHeight, flagMergeThreshold);
|
inverseCellHeight, flagMergeThreshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rasterizes an indexed triangle mesh into the specified heightfield.
|
/**
|
||||||
///
|
* Rasterizes an indexed triangle mesh into the specified heightfield. Spans will only be added for triangles that
|
||||||
/// Spans will only be added for triangles that overlap the heightfield grid.
|
* overlap the heightfield grid.
|
||||||
///
|
*
|
||||||
/// @see rcHeightfield
|
* @param heightfield
|
||||||
/// @ingroup recast
|
* An initialized heightfield.
|
||||||
/// @param[in,out] context The build context to use during the operation.
|
* @param verts
|
||||||
/// @param[in] verts The vertices. [(x, y, z) * @p nv]
|
* The vertices. [(x, y, z) * N]
|
||||||
/// @param[in] numVerts The number of vertices. (unused) TODO (graham): Remove in next major release
|
* @param tris
|
||||||
/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt]
|
* The triangle indices. [(vertA, vertB, vertC) * nt]
|
||||||
/// @param[in] triAreaIDs The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
|
* @param areaIds
|
||||||
/// @param[in] numTris The number of triangles.
|
* The area id's of the triangles. [Limit: <= WALKABLE_AREA] [Size: numTris]
|
||||||
/// @param[in,out] heightfield An initialized heightfield.
|
* @param numTris
|
||||||
/// @param[in] flagMergeThreshold The distance where the walkable flag is favored over the non-walkable flag.
|
* The number of triangles.
|
||||||
/// [Limit: >= 0] [Units: vx]
|
* @param flagMergeThreshold
|
||||||
/// @returns True if the operation completed successfully.
|
* The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx]
|
||||||
public static void RasterizeTriangles(RcContext context, float[] verts, int[] tris, int[] triAreaIDs, int numTris,
|
* @see Heightfield
|
||||||
RcHeightfield heightfield, int flagMergeThreshold)
|
*/
|
||||||
|
public static void RasterizeTriangles(RcHeightfield heightfield, float[] verts, int[] tris, int[] areaIds, int numTris,
|
||||||
|
int flagMergeThreshold, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
|
||||||
|
|
||||||
float inverseCellSize = 1.0f / heightfield.cs;
|
float inverseCellSize = 1.0f / heightfield.cs;
|
||||||
float inverseCellHeight = 1.0f / heightfield.ch;
|
float inverseCellHeight = 1.0f / heightfield.ch;
|
||||||
|
@ -433,30 +414,33 @@ namespace DotRecast.Recast
|
||||||
int v0 = tris[triIndex * 3 + 0];
|
int v0 = tris[triIndex * 3 + 0];
|
||||||
int v1 = tris[triIndex * 3 + 1];
|
int v1 = tris[triIndex * 3 + 1];
|
||||||
int v2 = tris[triIndex * 3 + 2];
|
int v2 = tris[triIndex * 3 + 2];
|
||||||
RasterizeTri(verts, v0, v1, v2, triAreaIDs[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs,
|
RasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs,
|
||||||
inverseCellSize, inverseCellHeight, flagMergeThreshold);
|
inverseCellSize, inverseCellHeight, flagMergeThreshold);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rasterizes a triangle list into the specified heightfield.
|
/**
|
||||||
///
|
* Rasterizes a triangle list into the specified heightfield. Expects each triangle to be specified as three
|
||||||
/// Expects each triangle to be specified as three sequential vertices of 3 floats.
|
* sequential vertices of 3 floats. Spans will only be added for triangles that overlap the heightfield grid.
|
||||||
///
|
*
|
||||||
/// Spans will only be added for triangles that overlap the heightfield grid.
|
* @param heightfield
|
||||||
///
|
* An initialized heightfield.
|
||||||
/// @see rcHeightfield
|
* @param verts
|
||||||
/// @ingroup recast
|
* The vertices. [(x, y, z) * numVerts]
|
||||||
/// @param[in,out] context The build context to use during the operation.
|
* @param areaIds
|
||||||
/// @param[in] verts The triangle vertices. [(ax, ay, az, bx, by, bz, cx, by, cx) * @p nt]
|
* The area id's of the triangles. [Limit: <= WALKABLE_AREA] [Size: numTris]
|
||||||
/// @param[in] triAreaIDs The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
|
* @param tris
|
||||||
/// @param[in] numTris The number of triangles.
|
* The triangle indices. [(vertA, vertB, vertC) * nt]
|
||||||
/// @param[in,out] heightfield An initialized heightfield.
|
* @param numTris
|
||||||
/// @param[in] flagMergeThreshold The distance where the walkable flag is favored over the non-walkable flag.
|
* The number of triangles.
|
||||||
/// [Limit: >= 0] [Units: vx]
|
* @param flagMergeThreshold
|
||||||
/// @returns True if the operation completed successfully.
|
* The distance where the walkable flag is favored over the non-walkable flag. [Limit: >= 0] [Units: vx]
|
||||||
public static void RasterizeTriangles(RcContext context, float[] verts, int[] triAreaIDs, int numTris, RcHeightfield heightfield, int flagMergeThreshold)
|
* @see Heightfield
|
||||||
|
*/
|
||||||
|
public static void RasterizeTriangles(RcHeightfield heightfield, float[] verts, int[] areaIds, int numTris,
|
||||||
|
int flagMergeThreshold, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
using var timer = context.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
|
||||||
|
|
||||||
float inverseCellSize = 1.0f / heightfield.cs;
|
float inverseCellSize = 1.0f / heightfield.cs;
|
||||||
float inverseCellHeight = 1.0f / heightfield.ch;
|
float inverseCellHeight = 1.0f / heightfield.ch;
|
||||||
|
@ -465,7 +449,7 @@ namespace DotRecast.Recast
|
||||||
int v0 = (triIndex * 3 + 0);
|
int v0 = (triIndex * 3 + 0);
|
||||||
int v1 = (triIndex * 3 + 1);
|
int v1 = (triIndex * 3 + 1);
|
||||||
int v2 = (triIndex * 3 + 2);
|
int v2 = (triIndex * 3 + 2);
|
||||||
RasterizeTri(verts, v0, v1, v2, triAreaIDs[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs,
|
RasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs,
|
||||||
inverseCellSize, inverseCellHeight, flagMergeThreshold);
|
inverseCellSize, inverseCellHeight, flagMergeThreshold);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -274,11 +274,8 @@ namespace DotRecast.Recast
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool FloodRegion(int x, int y, int i,
|
private static bool FloodRegion(int x, int y, int i, int level, int r, RcCompactHeightfield chf, int[] srcReg,
|
||||||
int level, int r,
|
int[] srcDist, List<int> stack)
|
||||||
RcCompactHeightfield chf,
|
|
||||||
int[] srcReg, int[] srcDist,
|
|
||||||
List<RcLevelStackEntry> stack)
|
|
||||||
{
|
{
|
||||||
int w = chf.width;
|
int w = chf.width;
|
||||||
|
|
||||||
|
@ -286,7 +283,9 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
// Flood fill mark region.
|
// Flood fill mark region.
|
||||||
stack.Clear();
|
stack.Clear();
|
||||||
stack.Add(new RcLevelStackEntry(x, y, i));
|
stack.Add(x);
|
||||||
|
stack.Add(y);
|
||||||
|
stack.Add(i);
|
||||||
srcReg[i] = r;
|
srcReg[i] = r;
|
||||||
srcDist[i] = 0;
|
srcDist[i] = 0;
|
||||||
|
|
||||||
|
@ -295,10 +294,13 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
while (stack.Count > 0)
|
while (stack.Count > 0)
|
||||||
{
|
{
|
||||||
RcLevelStackEntry back = stack[^1];
|
int ci = stack[^1];
|
||||||
int cx = back.x;
|
stack.RemoveAt(stack.Count - 1);
|
||||||
int cy = back.y;
|
|
||||||
int ci = back.index;
|
int cy = stack[^1];
|
||||||
|
stack.RemoveAt(stack.Count - 1);
|
||||||
|
|
||||||
|
int cx = stack[^1];
|
||||||
stack.RemoveAt(stack.Count - 1);
|
stack.RemoveAt(stack.Count - 1);
|
||||||
|
|
||||||
|
|
||||||
|
@ -379,7 +381,9 @@ namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
srcReg[ai] = r;
|
srcReg[ai] = r;
|
||||||
srcDist[ai] = 0;
|
srcDist[ai] = 0;
|
||||||
stack.Add(new RcLevelStackEntry(ax, ay, ai));
|
stack.Add(ax);
|
||||||
|
stack.Add(ay);
|
||||||
|
stack.Add(ai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,11 +392,8 @@ namespace DotRecast.Recast
|
||||||
return count > 0;
|
return count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ExpandRegions(int maxIter, int level,
|
private static int[] ExpandRegions(int maxIter, int level, RcCompactHeightfield chf, int[] srcReg, int[] srcDist,
|
||||||
RcCompactHeightfield chf,
|
List<int> stack, bool fillStack)
|
||||||
int[] srcReg, int[] srcDist,
|
|
||||||
List<RcLevelStackEntry> stack,
|
|
||||||
bool fillStack)
|
|
||||||
{
|
{
|
||||||
int w = chf.width;
|
int w = chf.width;
|
||||||
int h = chf.height;
|
int h = chf.height;
|
||||||
|
@ -410,7 +411,9 @@ namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
|
if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
|
||||||
{
|
{
|
||||||
stack.Add(new RcLevelStackEntry(x, y, i));
|
stack.Add(x);
|
||||||
|
stack.Add(y);
|
||||||
|
stack.Add(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -419,28 +422,28 @@ namespace DotRecast.Recast
|
||||||
else // use cells in the input stack
|
else // use cells in the input stack
|
||||||
{
|
{
|
||||||
// mark all cells which already have a region
|
// mark all cells which already have a region
|
||||||
for (int j = 0; j < stack.Count; j++)
|
for (int j = 0; j < stack.Count; j += 3)
|
||||||
{
|
{
|
||||||
int i = stack[j].index;
|
int i = stack[j + 2];
|
||||||
if (srcReg[i] != 0)
|
if (srcReg[i] != 0)
|
||||||
{
|
{
|
||||||
stack[j] = new RcLevelStackEntry(stack[j].x, stack[j].y, -1);
|
stack[j + 2] = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RcDirtyEntry> dirtyEntries = new List<RcDirtyEntry>();
|
List<int> dirtyEntries = new List<int>();
|
||||||
int iter = 0;
|
int iter = 0;
|
||||||
while (stack.Count > 0)
|
while (stack.Count > 0)
|
||||||
{
|
{
|
||||||
int failed = 0;
|
int failed = 0;
|
||||||
dirtyEntries.Clear();
|
dirtyEntries.Clear();
|
||||||
|
|
||||||
for (int j = 0; j < stack.Count; j++)
|
for (int j = 0; j < stack.Count; j += 3)
|
||||||
{
|
{
|
||||||
int x = stack[j].x;
|
int x = stack[j + 0];
|
||||||
int y = stack[j].y;
|
int y = stack[j + 1];
|
||||||
int i = stack[j].index;
|
int i = stack[j + 2];
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
{
|
{
|
||||||
failed++;
|
failed++;
|
||||||
|
@ -478,8 +481,10 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
{
|
{
|
||||||
stack[j] = new RcLevelStackEntry(stack[j].x, stack[j].y, -1); // mark as used
|
stack[j + 2] = -1; // mark as used
|
||||||
dirtyEntries.Add(new RcDirtyEntry(i, r, d2));
|
dirtyEntries.Add(i);
|
||||||
|
dirtyEntries.Add(r);
|
||||||
|
dirtyEntries.Add(d2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -488,14 +493,14 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy entries that differ between src and dst to keep them in sync.
|
// Copy entries that differ between src and dst to keep them in sync.
|
||||||
for (int i = 0; i < dirtyEntries.Count; i++)
|
for (int i = 0; i < dirtyEntries.Count; i += 3)
|
||||||
{
|
{
|
||||||
int idx = dirtyEntries[i].index;
|
int idx = dirtyEntries[i];
|
||||||
srcReg[idx] = dirtyEntries[i].region;
|
srcReg[idx] = dirtyEntries[i + 1];
|
||||||
srcDist[idx] = dirtyEntries[i].distance2;
|
srcDist[idx] = dirtyEntries[i + 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (failed == stack.Count())
|
if (failed * 3 == stack.Count())
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -509,13 +514,12 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return srcReg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SortCellsByLevel(int startLevel,
|
private static void SortCellsByLevel(int startLevel, RcCompactHeightfield chf, int[] srcReg, int nbStacks,
|
||||||
RcCompactHeightfield chf,
|
List<List<int>> stacks, int loglevelsPerStack) // the levels per stack (2 in our case) as a bit shift
|
||||||
int[] srcReg,
|
|
||||||
int nbStacks, List<List<RcLevelStackEntry>> stacks,
|
|
||||||
int loglevelsPerStack) // the levels per stack (2 in our case) as a bit shift
|
|
||||||
{
|
{
|
||||||
int w = chf.width;
|
int w = chf.width;
|
||||||
int h = chf.height;
|
int h = chf.height;
|
||||||
|
@ -551,25 +555,27 @@ namespace DotRecast.Recast
|
||||||
sId = 0;
|
sId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
stacks[sId].Add(new RcLevelStackEntry(x, y, i));
|
stacks[sId].Add(x);
|
||||||
|
stacks[sId].Add(y);
|
||||||
|
stacks[sId].Add(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AppendStacks(List<RcLevelStackEntry> srcStack,
|
private static void AppendStacks(List<int> srcStack, List<int> dstStack, int[] srcReg)
|
||||||
List<RcLevelStackEntry> dstStack,
|
|
||||||
int[] srcReg)
|
|
||||||
{
|
{
|
||||||
for (int j = 0; j < srcStack.Count; j++)
|
for (int j = 0; j < srcStack.Count; j += 3)
|
||||||
{
|
{
|
||||||
int i = srcStack[j].index;
|
int i = srcStack[j + 2];
|
||||||
if ((i < 0) || (srcReg[i] != 0))
|
if ((i < 0) || (srcReg[i] != 0))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
dstStack.Add(srcStack[j]);
|
dstStack.Add(srcStack[j]);
|
||||||
|
dstStack.Add(srcStack[j + 1]);
|
||||||
|
dstStack.Add(srcStack[j + 2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,7 +847,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int MergeAndFilterRegions(RcContext ctx, int minRegionArea, int mergeRegionSize, int maxRegionId,
|
private static int MergeAndFilterRegions(RcTelemetry ctx, int minRegionArea, int mergeRegionSize, int maxRegionId,
|
||||||
RcCompactHeightfield chf, int[] srcReg, List<int> overlaps)
|
RcCompactHeightfield chf, int[] srcReg, List<int> overlaps)
|
||||||
{
|
{
|
||||||
int w = chf.width;
|
int w = chf.width;
|
||||||
|
@ -1163,7 +1169,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool MergeAndFilterLayerRegions(RcContext ctx, int minRegionArea, ref int maxRegionId, RcCompactHeightfield chf, int[] srcReg)
|
private static int MergeAndFilterLayerRegions(RcTelemetry ctx, int minRegionArea, int maxRegionId, RcCompactHeightfield chf, int[] srcReg, List<int> overlaps)
|
||||||
{
|
{
|
||||||
int w = chf.width;
|
int w = chf.width;
|
||||||
int h = chf.height;
|
int h = chf.height;
|
||||||
|
@ -1398,7 +1404,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return maxRegionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @par
|
/// @par
|
||||||
|
@ -1411,7 +1417,7 @@ namespace DotRecast.Recast
|
||||||
/// and rcCompactHeightfield::dist fields.
|
/// and rcCompactHeightfield::dist fields.
|
||||||
///
|
///
|
||||||
/// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone
|
/// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone
|
||||||
public static void BuildDistanceField(RcContext ctx, RcCompactHeightfield chf)
|
public static void BuildDistanceField(RcTelemetry ctx, RcCompactHeightfield chf)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD);
|
||||||
|
|
||||||
|
@ -1472,7 +1478,7 @@ namespace DotRecast.Recast
|
||||||
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
||||||
///
|
///
|
||||||
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
||||||
public static void BuildRegionsMonotone(RcContext ctx, RcCompactHeightfield chf, int minRegionArea,
|
public static void BuildRegionsMonotone(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea,
|
||||||
int mergeRegionArea)
|
int mergeRegionArea)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
||||||
|
@ -1654,7 +1660,7 @@ namespace DotRecast.Recast
|
||||||
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
||||||
///
|
///
|
||||||
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
||||||
public static void BuildRegions(RcContext ctx, RcCompactHeightfield chf, int minRegionArea,
|
public static void BuildRegions(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea,
|
||||||
int mergeRegionArea)
|
int mergeRegionArea)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
||||||
|
@ -1667,13 +1673,13 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
int LOG_NB_STACKS = 3;
|
int LOG_NB_STACKS = 3;
|
||||||
int NB_STACKS = 1 << LOG_NB_STACKS;
|
int NB_STACKS = 1 << LOG_NB_STACKS;
|
||||||
List<List<RcLevelStackEntry>> lvlStacks = new List<List<RcLevelStackEntry>>();
|
List<List<int>> lvlStacks = new List<List<int>>();
|
||||||
for (int i = 0; i < NB_STACKS; ++i)
|
for (int i = 0; i < NB_STACKS; ++i)
|
||||||
{
|
{
|
||||||
lvlStacks.Add(new List<RcLevelStackEntry>(256));
|
lvlStacks.Add(new List<int>(1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RcLevelStackEntry> stack = new List<RcLevelStackEntry>(256);
|
List<int> stack = new List<int>(1024);
|
||||||
|
|
||||||
int[] srcReg = new int[chf.spanCount];
|
int[] srcReg = new int[chf.spanCount];
|
||||||
int[] srcDist = new int[chf.spanCount];
|
int[] srcDist = new int[chf.spanCount];
|
||||||
|
@ -1734,12 +1740,11 @@ namespace DotRecast.Recast
|
||||||
ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FLOOD);
|
ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FLOOD);
|
||||||
|
|
||||||
// Mark new regions with IDs.
|
// Mark new regions with IDs.
|
||||||
for (int j = 0; j < lvlStacks[sId].Count; j++)
|
for (int j = 0; j < lvlStacks[sId].Count; j += 3)
|
||||||
{
|
{
|
||||||
RcLevelStackEntry current = lvlStacks[sId][j];
|
int x = lvlStacks[sId][j];
|
||||||
int x = current.x;
|
int y = lvlStacks[sId][j + 1];
|
||||||
int y = current.y;
|
int i = lvlStacks[sId][j + 2];
|
||||||
int i = current.index;
|
|
||||||
if (i >= 0 && srcReg[i] == 0)
|
if (i >= 0 && srcReg[i] == 0)
|
||||||
{
|
{
|
||||||
if (FloodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
|
if (FloodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
|
||||||
|
@ -1781,7 +1786,7 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool BuildLayerRegions(RcContext ctx, RcCompactHeightfield chf, int minRegionArea)
|
public static void BuildLayerRegions(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
||||||
|
|
||||||
|
@ -1924,15 +1929,13 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var timerFilter = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER))
|
ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
{
|
|
||||||
// Merge monotone regions to layers and remove small regions.
|
// Merge monotone regions to layers and remove small regions.
|
||||||
chf.maxRegions = id;
|
List<int> overlaps = new List<int>();
|
||||||
if (!MergeAndFilterLayerRegions(ctx, minRegionArea, ref chf.maxRegions, chf, srcReg))
|
chf.maxRegions = MergeAndFilterLayerRegions(ctx, minRegionArea, id, chf, srcReg, overlaps);
|
||||||
{
|
|
||||||
return false;
|
ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the result out.
|
// Store the result out.
|
||||||
for (int i = 0; i < chf.spanCount; ++i)
|
for (int i = 0; i < chf.spanCount; ++i)
|
||||||
|
@ -1942,8 +1945,6 @@ namespace DotRecast.Recast
|
||||||
.WithReg(srcReg[i])
|
.WithReg(srcReg[i])
|
||||||
.Build();
|
.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,7 +25,7 @@ namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
public static class RcVoxelizations
|
public static class RcVoxelizations
|
||||||
{
|
{
|
||||||
public static RcHeightfield BuildSolidHeightfield(RcContext ctx, IInputGeomProvider geomProvider, RcBuilderConfig builderCfg)
|
public static RcHeightfield BuildSolidHeightfield(IInputGeomProvider geomProvider, RcBuilderConfig builderCfg, RcTelemetry ctx)
|
||||||
{
|
{
|
||||||
RcConfig cfg = builderCfg.cfg;
|
RcConfig cfg = builderCfg.cfg;
|
||||||
|
|
||||||
|
@ -34,10 +34,13 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
// Allocate array that can hold triangle area types.
|
// Allocate array that can hold triangle area types.
|
||||||
// If you have multiple meshes you need to process, allocate
|
// If you have multiple meshes you need to process, allocate
|
||||||
// and array which can hold the max number of triangles you need to process.
|
// and array which can hold the max number of triangles you need to
|
||||||
|
// process.
|
||||||
|
|
||||||
// Find triangles which are walkable based on their slope and rasterize them.
|
// Find triangles which are walkable based on their slope and rasterize
|
||||||
// If your input data is multiple meshes, you can transform them here, calculate
|
// 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.
|
// the are type for each of the meshes and rasterize them.
|
||||||
foreach (RcTriMesh geom in geomProvider.Meshes())
|
foreach (RcTriMesh geom in geomProvider.Meshes())
|
||||||
{
|
{
|
||||||
|
@ -56,7 +59,7 @@ namespace DotRecast.Recast
|
||||||
int[] tris = node.tris;
|
int[] tris = node.tris;
|
||||||
int ntris = tris.Length / 3;
|
int ntris = tris.Length / 3;
|
||||||
int[] m_triareas = RcCommons.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
int[] m_triareas = RcCommons.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
||||||
RcRasterizations.RasterizeTriangles(ctx, verts, tris, m_triareas, ntris, solid, cfg.WalkableClimb);
|
RcRasterizations.RasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.WalkableClimb, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -64,7 +67,7 @@ namespace DotRecast.Recast
|
||||||
int[] tris = geom.GetTris();
|
int[] tris = geom.GetTris();
|
||||||
int ntris = tris.Length / 3;
|
int ntris = tris.Length / 3;
|
||||||
int[] m_triareas = RcCommons.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
int[] m_triareas = RcCommons.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
||||||
RcRasterizations.RasterizeTriangles(ctx, verts, tris, m_triareas, ntris, solid, cfg.WalkableClimb);
|
RcRasterizations.RasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.WalkableClimb, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageReference Include="Moq" Version="4.20.70" />
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
<PackageReference Include="NUnit.Analyzers" Version="3.10.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using DotRecast.Core.Buffers;
|
|
||||||
using DotRecast.Core.Collections;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Test;
|
|
||||||
|
|
||||||
public class RcArrayBenchmarkTests
|
|
||||||
{
|
|
||||||
private const int StepLength = 512;
|
|
||||||
private const int RandomLoop = 1000;
|
|
||||||
private readonly RcRand _rand = new RcRand();
|
|
||||||
|
|
||||||
private (string title, long ticks) Bench(string title, Action<int> source)
|
|
||||||
{
|
|
||||||
var begin = RcFrequency.Ticks;
|
|
||||||
for (int step = StepLength; step > 0; --step)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < RandomLoop; ++i)
|
|
||||||
{
|
|
||||||
source.Invoke(step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var end = RcFrequency.Ticks - begin;
|
|
||||||
return (title, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void RoundForArray(int len)
|
|
||||||
{
|
|
||||||
var array = new int[len];
|
|
||||||
for (int ii = 0; ii < len; ++ii)
|
|
||||||
{
|
|
||||||
array[ii] = _rand.NextInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void RoundForPureRentArray(int len)
|
|
||||||
{
|
|
||||||
var array = ArrayPool<int>.Shared.Rent(len);
|
|
||||||
for (int ii = 0; ii < array.Length; ++ii)
|
|
||||||
{
|
|
||||||
array[ii] = _rand.NextInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayPool<int>.Shared.Return(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void RoundForRcRentedArray(int len)
|
|
||||||
{
|
|
||||||
using var rentedArray = RcRentedArray.Rent<int>(len);
|
|
||||||
var array = rentedArray.AsArray();
|
|
||||||
for (int i = 0; i < rentedArray.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = _rand.NextInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void RoundForRcStackArray(int len)
|
|
||||||
{
|
|
||||||
var array = new RcStackArray512<int>();
|
|
||||||
for (int ii = 0; ii < len; ++ii)
|
|
||||||
{
|
|
||||||
array[ii] = _rand.NextInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RoundForStackalloc(int len)
|
|
||||||
{
|
|
||||||
Span<int> array = stackalloc int[len];
|
|
||||||
for (int ii = 0; ii < len; ++ii)
|
|
||||||
{
|
|
||||||
array[ii] = _rand.NextInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[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));
|
|
||||||
|
|
||||||
list.Sort((x, y) => x.ticks.CompareTo(y.ticks));
|
|
||||||
|
|
||||||
foreach (var t in list)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"{t.title} {t.ticks / (double)TimeSpan.TicksPerMillisecond} ms");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,449 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using DotRecast.Core.Buffers;
|
|
||||||
using DotRecast.Core.Collections;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Test;
|
|
||||||
|
|
||||||
// https://github.com/joaoportela/CircularBuffer-CSharp/blob/master/CircularBuffer.Tests/CircularBufferTests.cs
|
|
||||||
public class RcCyclicBufferTests
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_GetEnumeratorConstructorCapacity_ReturnsEmptyCollection()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<string>(5);
|
|
||||||
Assert.That(buffer.ToArray(), Is.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_ConstructorSizeIndexAccess_CorrectContent()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3 });
|
|
||||||
|
|
||||||
Assert.That(buffer.Capacity, Is.EqualTo(5));
|
|
||||||
Assert.That(buffer.Size, Is.EqualTo(4));
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
Assert.That(buffer[i], Is.EqualTo(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_Constructor_ExceptionWhenSourceIsLargerThanCapacity()
|
|
||||||
{
|
|
||||||
Assert.Throws<ArgumentException>(() => new RcCyclicBuffer<int>(3, new[] { 0, 1, 2, 3 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_GetEnumeratorConstructorDefinedArray_CorrectContent()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3 });
|
|
||||||
|
|
||||||
int x = 0;
|
|
||||||
foreach (var item in buffer)
|
|
||||||
{
|
|
||||||
Assert.That(item, Is.EqualTo(x));
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_PushBack_CorrectContent()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5);
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
buffer.PushBack(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(buffer.Front(), Is.EqualTo(0));
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
Assert.That(buffer[i], Is.EqualTo(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_PushBackOverflowingBuffer_CorrectContent()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5);
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
buffer.PushBack(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 5, 6, 7, 8, 9 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_GetEnumeratorOverflowedArray_CorrectContent()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5);
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
buffer.PushBack(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// buffer should have [5,6,7,8,9]
|
|
||||||
int x = 5;
|
|
||||||
buffer.ForEach(item =>
|
|
||||||
{
|
|
||||||
Assert.That(item, Is.EqualTo(x));
|
|
||||||
x++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_ToArrayConstructorDefinedArray_CorrectContent()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3 });
|
|
||||||
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 0, 1, 2, 3 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_ToArrayOverflowedBuffer_CorrectContent()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5);
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
buffer.PushBack(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 5, 6, 7, 8, 9 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_PushFront_CorrectContent()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5);
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
buffer.PushFront(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 4, 3, 2, 1, 0 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_PushFrontAndOverflow_CorrectContent()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5);
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
buffer.PushFront(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 9, 8, 7, 6, 5 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_Front_CorrectItem()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
|
||||||
|
|
||||||
Assert.That(buffer.Front(), Is.EqualTo(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_Back_CorrectItem()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
|
||||||
Assert.That(buffer.Back(), Is.EqualTo(4));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_BackOfBufferOverflowByOne_CorrectItem()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
|
||||||
buffer.PushBack(42);
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 4, 42 }));
|
|
||||||
Assert.That(buffer.Back(), Is.EqualTo(42));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_Front_EmptyBufferThrowsException()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5);
|
|
||||||
|
|
||||||
Assert.Throws<InvalidOperationException>(() => buffer.Front());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_Back_EmptyBufferThrowsException()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5);
|
|
||||||
Assert.Throws<InvalidOperationException>(() => buffer.Back());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_PopBack_RemovesBackElement()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
|
||||||
|
|
||||||
Assert.That(buffer.Size, Is.EqualTo(5));
|
|
||||||
|
|
||||||
buffer.PopBack();
|
|
||||||
|
|
||||||
Assert.That(buffer.Size, Is.EqualTo(4));
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 0, 1, 2, 3 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_PopBackInOverflowBuffer_RemovesBackElement()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
|
||||||
buffer.PushBack(5);
|
|
||||||
|
|
||||||
Assert.That(buffer.Size, Is.EqualTo(5));
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 4, 5 }));
|
|
||||||
|
|
||||||
buffer.PopBack();
|
|
||||||
|
|
||||||
Assert.That(buffer.Size, Is.EqualTo(4));
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 4 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_PopFront_RemovesBackElement()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
|
||||||
|
|
||||||
Assert.That(buffer.Size, Is.EqualTo(5));
|
|
||||||
|
|
||||||
buffer.PopFront();
|
|
||||||
|
|
||||||
Assert.That(buffer.Size, Is.EqualTo(4));
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 4 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_PopFrontInOverflowBuffer_RemovesBackElement()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
|
||||||
buffer.PushFront(5);
|
|
||||||
|
|
||||||
Assert.That(buffer.Size, Is.EqualTo(5));
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 5, 0, 1, 2, 3 }));
|
|
||||||
|
|
||||||
buffer.PopFront();
|
|
||||||
|
|
||||||
Assert.That(buffer.Size, Is.EqualTo(4));
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 0, 1, 2, 3 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_SetIndex_ReplacesElement()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
|
||||||
|
|
||||||
buffer[1] = 10;
|
|
||||||
buffer[3] = 30;
|
|
||||||
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 0, 10, 2, 30, 4 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_WithDifferentSizeAndCapacity_BackReturnsLastArrayPosition()
|
|
||||||
{
|
|
||||||
// test to confirm this issue does not happen anymore:
|
|
||||||
// https://github.com/joaoportela/RcCyclicBuffer-CSharp/issues/2
|
|
||||||
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
|
||||||
|
|
||||||
buffer.PopFront(); // (make size and capacity different)
|
|
||||||
|
|
||||||
Assert.That(buffer.Back(), Is.EqualTo(4));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_Clear_ClearsContent()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 4, 3, 2, 1, 0 });
|
|
||||||
|
|
||||||
buffer.Clear();
|
|
||||||
|
|
||||||
Assert.That(buffer.Size, Is.EqualTo(0));
|
|
||||||
Assert.That(buffer.Capacity, Is.EqualTo(5));
|
|
||||||
Assert.That(buffer.ToArray(), Is.EqualTo(new int[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_Clear_WorksNormallyAfterClear()
|
|
||||||
{
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 4, 3, 2, 1, 0 });
|
|
||||||
|
|
||||||
buffer.Clear();
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
buffer.PushBack(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(buffer.Front(), Is.EqualTo(0));
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
Assert.That(buffer[i], Is.EqualTo(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_RegularForEachWorks()
|
|
||||||
{
|
|
||||||
var refValues = new[] { 4, 3, 2, 1, 0 };
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, refValues);
|
|
||||||
|
|
||||||
var index = 0;
|
|
||||||
foreach (var element in buffer)
|
|
||||||
{
|
|
||||||
Assert.That(element, Is.EqualTo(refValues[index++]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffer_EnumeratorWorks()
|
|
||||||
{
|
|
||||||
var refValues = new int[] { 4, 3, 2, 1, 0 };
|
|
||||||
var buffer = new RcCyclicBuffer<int>(5, refValues);
|
|
||||||
|
|
||||||
|
|
||||||
var index = 0;
|
|
||||||
using var enumerator = buffer.GetEnumerator();
|
|
||||||
enumerator.Reset();
|
|
||||||
while (enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
Assert.That(enumerator.Current, Is.EqualTo(refValues[index++]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure Reset works properly
|
|
||||||
index = 0;
|
|
||||||
enumerator.Reset();
|
|
||||||
while (enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
Assert.That(enumerator.Current, Is.EqualTo(refValues[index++]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_Sum()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
Assert.That(RcCyclicBuffers.Sum(buffer), Is.EqualTo(refValues.Sum()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_Average()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
Assert.That(RcCyclicBuffers.Average(buffer), Is.EqualTo(refValues.Average()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_Min()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
Assert.That(RcCyclicBuffers.Min(buffer), Is.EqualTo(refValues.Min()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_Max()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
Assert.That(RcCyclicBuffers.Max(buffer), Is.EqualTo(refValues.Max()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_SumUnaligned()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-1, 3).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
Assert.That(RcCyclicBuffers.Sum(buffer), Is.EqualTo(refValues.Sum()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_AverageUnaligned()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-1, 3).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
Assert.That(RcCyclicBuffers.Average(buffer), Is.EqualTo(refValues.Average()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_MinUnaligned()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(5, 3).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
Assert.That(RcCyclicBuffers.Min(buffer), Is.EqualTo(refValues.Min()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_MaxUnaligned()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-5, 3).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
Assert.That(RcCyclicBuffers.Max(buffer), Is.EqualTo(refValues.Max()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_SumDeleted()
|
|
||||||
{
|
|
||||||
var initialValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
|
|
||||||
var refValues = initialValues.Skip(1).SkipLast(1).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(initialValues.Length, initialValues);
|
|
||||||
buffer.PopBack();
|
|
||||||
buffer.PopFront();
|
|
||||||
|
|
||||||
Assert.That(RcCyclicBuffers.Sum(buffer), Is.EqualTo(refValues.Sum()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_SumSplit()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
buffer.PopFront();
|
|
||||||
buffer.PushBack(refValues[0]);
|
|
||||||
Assert.That(RcCyclicBuffers.Sum(buffer), Is.EqualTo(refValues.Sum()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_AverageSplit()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
buffer.PopFront();
|
|
||||||
buffer.PushBack(refValues[0]);
|
|
||||||
Assert.That(RcCyclicBuffers.Average(buffer), Is.EqualTo(refValues.Average()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_MinSplit()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
buffer.PopFront();
|
|
||||||
buffer.PushBack(refValues[0]);
|
|
||||||
Assert.That(RcCyclicBuffers.Min(buffer), Is.EqualTo(refValues.Min()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RcCyclicBuffers_MaxSplit()
|
|
||||||
{
|
|
||||||
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
|
|
||||||
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
|
|
||||||
buffer.PopFront();
|
|
||||||
buffer.PushBack(refValues[0]);
|
|
||||||
Assert.That(RcCyclicBuffers.Max(buffer), Is.EqualTo(refValues.Max()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Test;
|
|
||||||
|
|
||||||
public class RcHashCodesTest
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void TestCombineHashCodes()
|
|
||||||
{
|
|
||||||
Assert.That(RcHashCodes.CombineHashCodes(0, 0), Is.EqualTo(0));
|
|
||||||
Assert.That(RcHashCodes.CombineHashCodes(int.MaxValue, int.MaxValue), Is.EqualTo(32));
|
|
||||||
Assert.That(RcHashCodes.CombineHashCodes(int.MaxValue, int.MinValue), Is.EqualTo(-33));
|
|
||||||
Assert.That(RcHashCodes.CombineHashCodes(int.MinValue, int.MinValue), Is.EqualTo(0));
|
|
||||||
Assert.That(RcHashCodes.CombineHashCodes(int.MinValue, int.MaxValue), Is.EqualTo(-1));
|
|
||||||
Assert.That(RcHashCodes.CombineHashCodes(int.MaxValue / 2, int.MaxValue / 2), Is.EqualTo(32));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestIntHash()
|
|
||||||
{
|
|
||||||
Assert.That(RcHashCodes.WangHash(0), Is.EqualTo(4158654902));
|
|
||||||
Assert.That(RcHashCodes.WangHash(1), Is.EqualTo(357654460));
|
|
||||||
Assert.That(RcHashCodes.WangHash(2), Is.EqualTo(715307540));
|
|
||||||
Assert.That(RcHashCodes.WangHash(3), Is.EqualTo(1072960876));
|
|
||||||
|
|
||||||
Assert.That(RcHashCodes.WangHash(4), Is.EqualTo(1430614333));
|
|
||||||
Assert.That(RcHashCodes.WangHash(5), Is.EqualTo(1788267159));
|
|
||||||
Assert.That(RcHashCodes.WangHash(6), Is.EqualTo(2145921005));
|
|
||||||
Assert.That(RcHashCodes.WangHash(7), Is.EqualTo(2503556531));
|
|
||||||
|
|
||||||
Assert.That(RcHashCodes.WangHash(8), Is.EqualTo(2861226262));
|
|
||||||
Assert.That(RcHashCodes.WangHash(9), Is.EqualTo(3218863982));
|
|
||||||
Assert.That(RcHashCodes.WangHash(10), Is.EqualTo(3576533554));
|
|
||||||
Assert.That(RcHashCodes.WangHash(11), Is.EqualTo(3934169234));
|
|
||||||
|
|
||||||
//
|
|
||||||
Assert.That(RcHashCodes.WangHash(int.MaxValue), Is.EqualTo(1755403298));
|
|
||||||
Assert.That(RcHashCodes.WangHash(uint.MaxValue), Is.EqualTo(3971045735));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using DotRecast.Core.Buffers;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Test;
|
|
||||||
|
|
||||||
public class RcRentedArrayTest
|
|
||||||
{
|
|
||||||
public List<int> RandomValues(int length)
|
|
||||||
{
|
|
||||||
var rand = new RcRand();
|
|
||||||
|
|
||||||
// excepted values
|
|
||||||
var list = new List<int>();
|
|
||||||
for (int i = 0; i < length; ++i)
|
|
||||||
{
|
|
||||||
list.Add(rand.NextInt32());
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRentedArray()
|
|
||||||
{
|
|
||||||
var rand = new RcRand();
|
|
||||||
for (int loop = 0; loop < 1024; ++loop)
|
|
||||||
{
|
|
||||||
RcRentedArray<int> rentedArray;
|
|
||||||
{
|
|
||||||
int length = Math.Max(2, (int)(rand.Next() * 2048));
|
|
||||||
var values = RandomValues(length);
|
|
||||||
using var array = RcRentedArray.Rent<int>(length);
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(array[i], Is.EqualTo(values[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(array[^1], Is.EqualTo(values[^1]));
|
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[-1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[array.Length + 1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[-1]);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[array.Length + 1]);
|
|
||||||
|
|
||||||
// danger
|
|
||||||
rentedArray = array;
|
|
||||||
}
|
|
||||||
Assert.Throws<NullReferenceException>(() => rentedArray[^1] = 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using DotRecast.Core.Collections;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Test;
|
|
||||||
|
|
||||||
public class RcSortedQueueTest
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void TestEnqueueAndDequeue()
|
|
||||||
{
|
|
||||||
var sortedQueue = new RcSortedQueue<int>((a, b) => a.CompareTo(b));
|
|
||||||
|
|
||||||
var r = new RcRand();
|
|
||||||
var expectedList = new List<int>();
|
|
||||||
for (int i = 0; i < 999; ++i)
|
|
||||||
{
|
|
||||||
expectedList.Add(r.NextInt32() % 300); // allow duplication
|
|
||||||
}
|
|
||||||
|
|
||||||
// ready
|
|
||||||
foreach (var expected in expectedList)
|
|
||||||
{
|
|
||||||
sortedQueue.Enqueue(expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedList.Sort();
|
|
||||||
|
|
||||||
// check count
|
|
||||||
Assert.That(sortedQueue.Count(), Is.EqualTo(expectedList.Count));
|
|
||||||
Assert.That(sortedQueue.IsEmpty(), Is.False);
|
|
||||||
|
|
||||||
Assert.That(sortedQueue.ToList(), Is.EqualTo(expectedList));
|
|
||||||
|
|
||||||
// check Peek and Dequeue
|
|
||||||
for (int i = 0; i < expectedList.Count; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(sortedQueue.Peek(), Is.EqualTo(expectedList[i]));
|
|
||||||
Assert.That(sortedQueue.Count(), Is.EqualTo(expectedList.Count - i));
|
|
||||||
|
|
||||||
Assert.That(sortedQueue.Dequeue(), Is.EqualTo(expectedList[i]));
|
|
||||||
Assert.That(sortedQueue.Count(), Is.EqualTo(expectedList.Count - i - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// check count
|
|
||||||
Assert.That(sortedQueue.Count(), Is.EqualTo(0));
|
|
||||||
Assert.That(sortedQueue.IsEmpty(), Is.True);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRemoveForValueType()
|
|
||||||
{
|
|
||||||
var sortedQueue = new RcSortedQueue<int>((a, b) => a.CompareTo(b));
|
|
||||||
|
|
||||||
var r = new RcRand();
|
|
||||||
var expectedList = new List<int>();
|
|
||||||
for (int i = 0; i < 999; ++i)
|
|
||||||
{
|
|
||||||
expectedList.Add(r.NextInt32() % 300); // allow duplication
|
|
||||||
}
|
|
||||||
|
|
||||||
// ready
|
|
||||||
foreach (var expected in expectedList)
|
|
||||||
{
|
|
||||||
sortedQueue.Enqueue(expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedList.Shuffle();
|
|
||||||
|
|
||||||
// check
|
|
||||||
Assert.That(sortedQueue.Count(), Is.EqualTo(expectedList.Count));
|
|
||||||
|
|
||||||
foreach (var expected in expectedList)
|
|
||||||
{
|
|
||||||
Assert.That(sortedQueue.Remove(expected), Is.True);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(sortedQueue.IsEmpty(), Is.True);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRemoveForReferenceType()
|
|
||||||
{
|
|
||||||
var sortedQueue = new RcSortedQueue<RcAtomicLong>((a, b) => a.Read().CompareTo(b.Read()));
|
|
||||||
|
|
||||||
var r = new RcRand();
|
|
||||||
var expectedList = new List<RcAtomicLong>();
|
|
||||||
for (int i = 0; i < 999; ++i)
|
|
||||||
{
|
|
||||||
expectedList.Add(new RcAtomicLong(r.NextInt32() % 300)); // allow duplication
|
|
||||||
}
|
|
||||||
|
|
||||||
// ready
|
|
||||||
foreach (var expected in expectedList)
|
|
||||||
{
|
|
||||||
sortedQueue.Enqueue(expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedList.Shuffle();
|
|
||||||
|
|
||||||
// check
|
|
||||||
Assert.That(sortedQueue.Count(), Is.EqualTo(expectedList.Count));
|
|
||||||
|
|
||||||
foreach (var expected in expectedList)
|
|
||||||
{
|
|
||||||
Assert.That(sortedQueue.Remove(expected), Is.True);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(sortedQueue.IsEmpty(), Is.True);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,272 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using DotRecast.Core.Collections;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Test;
|
|
||||||
|
|
||||||
|
|
||||||
public class RcStackArrayTest
|
|
||||||
{
|
|
||||||
public List<int> RandomValues(int size)
|
|
||||||
{
|
|
||||||
var rand = new RcRand();
|
|
||||||
|
|
||||||
// excepted values
|
|
||||||
var list = new List<int>();
|
|
||||||
for (int i = 0; i < size; ++i)
|
|
||||||
{
|
|
||||||
list.Add(rand.NextInt32());
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestStackOverflow()
|
|
||||||
{
|
|
||||||
// normal
|
|
||||||
var array_128_512_1 = RcStackArray2<RcStackArray512<float>>.Empty; // 128 * 512 = 65536
|
|
||||||
|
|
||||||
// warn
|
|
||||||
//var array_128_512_2 = RcStackArray128<RcStackArray512<float>>.Empty; // 128 * 512 = 65536
|
|
||||||
|
|
||||||
// danger
|
|
||||||
// var array_32_512_1 = RcStackArray32<RcStackArray512<float>>.Empty; // 32 * 512 = 16384
|
|
||||||
// var array_16_512_1 = RcStackArray16<RcStackArray512<float>>.Empty; // 16 * 512 = 8192
|
|
||||||
// var array_8_512_1 = RcStackArray8<RcStackArray512<float>>.Empty; // 8 * 512 = 4196
|
|
||||||
// var array_4_256_1 = RcStackArray4<RcStackArray256<float>>.Empty; // 4 * 256 = 1024
|
|
||||||
// var array_4_64_1 = RcStackArray4<RcStackArray64<float>>.Empty; // 4 * 64 = 256
|
|
||||||
// var array_2_8_1 = RcStackArray2<RcStackArray8<float>>.Empty; // 2 * 8 = 16
|
|
||||||
// var array_2_4_1 = RcStackArray2<RcStackArray2<float>>.Empty; // 2 * 2 = 4
|
|
||||||
|
|
||||||
float f1 = 0.0f; // 1
|
|
||||||
//float f2 = 0.0f; // my system stack overflow!
|
|
||||||
Assert.That(f1, Is.EqualTo(0.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRcStackArray2()
|
|
||||||
{
|
|
||||||
var array = RcStackArray2<int>.Empty;
|
|
||||||
Assert.That(array.Length, Is.EqualTo(2));
|
|
||||||
|
|
||||||
var values = RandomValues(array.Length);
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(array[i], Is.EqualTo(values[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(array[^1], Is.EqualTo(values[^1]));
|
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[-1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[array.Length + 1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[-1]);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[array.Length + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRcStackArray4()
|
|
||||||
{
|
|
||||||
var array = RcStackArray4<int>.Empty;
|
|
||||||
Assert.That(array.Length, Is.EqualTo(4));
|
|
||||||
|
|
||||||
var values = RandomValues(array.Length);
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(array[i], Is.EqualTo(values[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(array[^1], Is.EqualTo(values[^1]));
|
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[-1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[array.Length + 1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[-1]);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[array.Length + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRcStackArray8()
|
|
||||||
{
|
|
||||||
var array = RcStackArray8<int>.Empty;
|
|
||||||
Assert.That(array.Length, Is.EqualTo(8));
|
|
||||||
|
|
||||||
var values = RandomValues(array.Length);
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(array[i], Is.EqualTo(values[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(array[^1], Is.EqualTo(values[^1]));
|
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[-1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[array.Length + 1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[-1]);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[array.Length + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRcStackArray16()
|
|
||||||
{
|
|
||||||
var array = RcStackArray16<int>.Empty;
|
|
||||||
Assert.That(array.Length, Is.EqualTo(16));
|
|
||||||
|
|
||||||
var values = RandomValues(array.Length);
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(array[i], Is.EqualTo(values[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(array[^1], Is.EqualTo(values[^1]));
|
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[-1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[array.Length + 1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[-1]);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[array.Length + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRcStackArray32()
|
|
||||||
{
|
|
||||||
var array = RcStackArray32<int>.Empty;
|
|
||||||
Assert.That(array.Length, Is.EqualTo(32));
|
|
||||||
|
|
||||||
var values = RandomValues(array.Length);
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(array[i], Is.EqualTo(values[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(array[^1], Is.EqualTo(values[^1]));
|
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[-1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[array.Length + 1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[-1]);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[array.Length + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRcStackArray64()
|
|
||||||
{
|
|
||||||
var array = RcStackArray64<int>.Empty;
|
|
||||||
Assert.That(array.Length, Is.EqualTo(64));
|
|
||||||
|
|
||||||
var values = RandomValues(array.Length);
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(array[i], Is.EqualTo(values[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(array[^1], Is.EqualTo(values[^1]));
|
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[-1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[array.Length + 1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[-1]);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[array.Length + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRcStackArray128()
|
|
||||||
{
|
|
||||||
var array = RcStackArray128<int>.Empty;
|
|
||||||
Assert.That(array.Length, Is.EqualTo(128));
|
|
||||||
|
|
||||||
var values = RandomValues(array.Length);
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(array[i], Is.EqualTo(values[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(array[^1], Is.EqualTo(values[^1]));
|
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[-1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[array.Length + 1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[-1]);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[array.Length + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRcStackArray256()
|
|
||||||
{
|
|
||||||
var array = RcStackArray256<int>.Empty;
|
|
||||||
Assert.That(array.Length, Is.EqualTo(256));
|
|
||||||
|
|
||||||
var values = RandomValues(array.Length);
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(array[i], Is.EqualTo(values[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(array[^1], Is.EqualTo(values[^1]));
|
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[-1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[array.Length + 1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[-1]);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[array.Length + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestRcStackArray512()
|
|
||||||
{
|
|
||||||
var array = RcStackArray512<int>.Empty;
|
|
||||||
Assert.That(array.Length, Is.EqualTo(512));
|
|
||||||
|
|
||||||
var values = RandomValues(array.Length);
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
array[i] = values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
|
||||||
{
|
|
||||||
Assert.That(array[i], Is.EqualTo(values[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(array[^1], Is.EqualTo(values[^1]));
|
|
||||||
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[-1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => array[array.Length + 1] = 0);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[-1]);
|
|
||||||
Assert.Throws<IndexOutOfRangeException>(() => _ = array[array.Length + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +1,19 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Core.Test;
|
namespace DotRecast.Core.Test;
|
||||||
|
|
||||||
public class Vector3Test
|
public class Vector3Tests
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
[Repeat(100000)]
|
[Repeat(100000)]
|
||||||
public void TestVectorLength()
|
public void TestVectorLength()
|
||||||
{
|
{
|
||||||
var v1 = new Vector3(Random.Shared.NextSingle(), Random.Shared.NextSingle(), Random.Shared.NextSingle());
|
var v1 = new Vector3(Random.Shared.NextSingle(), Random.Shared.NextSingle(), Random.Shared.NextSingle());
|
||||||
var v11 = new RcVec3f(v1.X, v1.Y, v1.Z);
|
var v11 = new Vector3(v1.X, v1.Y, v1.Z);
|
||||||
|
|
||||||
Assert.That(v1.Length(), Is.EqualTo(v11.Length()));
|
Assert.That(v1.Length(), Is.EqualTo(v11.Length()));
|
||||||
Assert.That(v1.LengthSquared(), Is.EqualTo(v11.LengthSquared()));
|
Assert.That(v1.LengthSquared(), Is.EqualTo(v11.LengthSquared()));
|
||||||
|
@ -28,9 +29,9 @@ public class Vector3Test
|
||||||
var v4 = v1 - v2;
|
var v4 = v1 - v2;
|
||||||
Assert.That(v3, Is.EqualTo(v4));
|
Assert.That(v3, Is.EqualTo(v4));
|
||||||
|
|
||||||
var v11 = new RcVec3f(v1.X, v1.Y, v1.Z);
|
var v11 = new Vector3(v1.X, v1.Y, v1.Z);
|
||||||
var v22 = new RcVec3f(v2.X, v2.Y, v2.Z);
|
var v22 = new Vector3(v2.X, v2.Y, v2.Z);
|
||||||
var v33 = RcVec3f.Subtract(v11, v22);
|
var v33 = Vector3.Subtract(v11, v22);
|
||||||
var v44 = v11 - v22;
|
var v44 = v11 - v22;
|
||||||
Assert.That(v33, Is.EqualTo(v44));
|
Assert.That(v33, Is.EqualTo(v44));
|
||||||
|
|
||||||
|
@ -50,9 +51,9 @@ public class Vector3Test
|
||||||
var v4 = v1 + v2;
|
var v4 = v1 + v2;
|
||||||
Assert.That(v3, Is.EqualTo(v4));
|
Assert.That(v3, Is.EqualTo(v4));
|
||||||
|
|
||||||
var v11 = new RcVec3f(v1.X, v1.Y, v1.Z);
|
var v11 = new Vector3(v1.X, v1.Y, v1.Z);
|
||||||
var v22 = new RcVec3f(v2.X, v2.Y, v2.Z);
|
var v22 = new Vector3(v2.X, v2.Y, v2.Z);
|
||||||
var v33 = RcVec3f.Add(v11, v22);
|
var v33 = Vector3.Add(v11, v22);
|
||||||
var v44 = v11 + v22;
|
var v44 = v11 + v22;
|
||||||
Assert.That(v33, Is.EqualTo(v44));
|
Assert.That(v33, Is.EqualTo(v44));
|
||||||
|
|
||||||
|
@ -68,8 +69,8 @@ public class Vector3Test
|
||||||
var v1 = new Vector3(Random.Shared.NextSingle(), Random.Shared.NextSingle(), Random.Shared.NextSingle());
|
var v1 = new Vector3(Random.Shared.NextSingle(), Random.Shared.NextSingle(), Random.Shared.NextSingle());
|
||||||
var v2 = Vector3.Normalize(v1);
|
var v2 = Vector3.Normalize(v1);
|
||||||
|
|
||||||
var v11 = new RcVec3f(v1.X, v1.Y, v1.Z);
|
var v11 = new Vector3(v1.X, v1.Y, v1.Z);
|
||||||
var v22 = RcVec3f.Normalize(v11);
|
var v22 = Vector3.Normalize(v11);
|
||||||
|
|
||||||
Assert.That(v2.X, Is.EqualTo(v22.X).Within(0.000001d));
|
Assert.That(v2.X, Is.EqualTo(v22.X).Within(0.000001d));
|
||||||
Assert.That(v2.Y, Is.EqualTo(v22.Y).Within(0.000001d));
|
Assert.That(v2.Y, Is.EqualTo(v22.Y).Within(0.000001d));
|
||||||
|
@ -84,9 +85,9 @@ public class Vector3Test
|
||||||
var v2 = new Vector3(Random.Shared.NextSingle(), Random.Shared.NextSingle(), Random.Shared.NextSingle());
|
var v2 = new Vector3(Random.Shared.NextSingle(), Random.Shared.NextSingle(), Random.Shared.NextSingle());
|
||||||
var v3 = Vector3.Cross(v1, v2);
|
var v3 = Vector3.Cross(v1, v2);
|
||||||
|
|
||||||
var v11 = new RcVec3f(v1.X, v1.Y, v1.Z);
|
var v11 = new Vector3(v1.X, v1.Y, v1.Z);
|
||||||
var v22 = new RcVec3f(v2.X, v2.Y, v2.Z);
|
var v22 = new Vector3(v2.X, v2.Y, v2.Z);
|
||||||
var v33 = RcVec3f.Cross(v11, v22);
|
var v33 = Vector3.Cross(v11, v22);
|
||||||
|
|
||||||
Assert.That(v3.X, Is.EqualTo(v33.X));
|
Assert.That(v3.X, Is.EqualTo(v33.X));
|
||||||
Assert.That(v3.Y, Is.EqualTo(v33.Y));
|
Assert.That(v3.Y, Is.EqualTo(v33.Y));
|
||||||
|
@ -103,7 +104,7 @@ public class Vector3Test
|
||||||
v1.CopyTo(array1);
|
v1.CopyTo(array1);
|
||||||
v1.CopyTo(array2, 0);
|
v1.CopyTo(array2, 0);
|
||||||
|
|
||||||
var v11 = new RcVec3f(v1.X, v1.Y, v1.Z);
|
var v11 = new Vector3(v1.X, v1.Y, v1.Z);
|
||||||
var array11 = new float[3];
|
var array11 = new float[3];
|
||||||
var array22 = new float[3];
|
var array22 = new float[3];
|
||||||
v11.CopyTo(array11);
|
v11.CopyTo(array11);
|
||||||
|
@ -121,9 +122,9 @@ public class Vector3Test
|
||||||
var v2 = new Vector3(Random.Shared.NextSingle(), Random.Shared.NextSingle(), Random.Shared.NextSingle());
|
var v2 = new Vector3(Random.Shared.NextSingle(), Random.Shared.NextSingle(), Random.Shared.NextSingle());
|
||||||
float d3 = Vector3.Dot(v1, v2);
|
float d3 = Vector3.Dot(v1, v2);
|
||||||
|
|
||||||
var v11 = new RcVec3f(v1.X, v1.Y, v1.Z);
|
var v11 = new Vector3(v1.X, v1.Y, v1.Z);
|
||||||
var v22 = new RcVec3f(v2.X, v2.Y, v2.Z);
|
var v22 = new Vector3(v2.X, v2.Y, v2.Z);
|
||||||
var d33 = RcVec3f.Dot(v11, v22);
|
var d33 = Vector3.Dot(v11, v22);
|
||||||
|
|
||||||
Assert.That(d3, Is.EqualTo(d33));
|
Assert.That(d3, Is.EqualTo(d33));
|
||||||
}
|
}
|
||||||
|
@ -137,10 +138,10 @@ public class Vector3Test
|
||||||
var d3 = Vector3.Distance(v1, v2);
|
var d3 = Vector3.Distance(v1, v2);
|
||||||
var d4 = Vector3.DistanceSquared(v1, v2);
|
var d4 = Vector3.DistanceSquared(v1, v2);
|
||||||
|
|
||||||
var v11 = new RcVec3f(v1.X, v1.Y, v1.Z);
|
var v11 = new Vector3(v1.X, v1.Y, v1.Z);
|
||||||
var v22 = new RcVec3f(v2.X, v2.Y, v2.Z);
|
var v22 = new Vector3(v2.X, v2.Y, v2.Z);
|
||||||
var d33 = RcVec3f.Distance(v11, v22);
|
var d33 = Vector3.Distance(v11, v22);
|
||||||
var d44 = RcVec3f.DistanceSquared(v11, v22);
|
var d44 = Vector3.DistanceSquared(v11, v22);
|
||||||
|
|
||||||
Assert.That(d3, Is.EqualTo(d33));
|
Assert.That(d3, Is.EqualTo(d33));
|
||||||
Assert.That(d4, Is.EqualTo(d44));
|
Assert.That(d4, Is.EqualTo(d44));
|
||||||
|
@ -155,10 +156,10 @@ public class Vector3Test
|
||||||
var v3 = Vector3.Min(v1, v2);
|
var v3 = Vector3.Min(v1, v2);
|
||||||
var v4 = Vector3.Max(v1, v2);
|
var v4 = Vector3.Max(v1, v2);
|
||||||
|
|
||||||
var v11 = new RcVec3f(v1.X, v1.Y, v1.Z);
|
var v11 = new Vector3(v1.X, v1.Y, v1.Z);
|
||||||
var v22 = new RcVec3f(v2.X, v2.Y, v2.Z);
|
var v22 = new Vector3(v2.X, v2.Y, v2.Z);
|
||||||
var v33 = RcVec3f.Min(v11, v22);
|
var v33 = Vector3.Min(v11, v22);
|
||||||
var v44 = RcVec3f.Max(v11, v22);
|
var v44 = Vector3.Max(v11, v22);
|
||||||
|
|
||||||
Assert.That(v3.X, Is.EqualTo(v33.X));
|
Assert.That(v3.X, Is.EqualTo(v33.X));
|
||||||
Assert.That(v3.Y, Is.EqualTo(v33.Y));
|
Assert.That(v3.Y, Is.EqualTo(v33.Y));
|
||||||
|
@ -179,9 +180,9 @@ public class Vector3Test
|
||||||
var v2 = new Vector3(Random.Shared.NextSingle(), Random.Shared.NextSingle(), Random.Shared.NextSingle());
|
var v2 = new Vector3(Random.Shared.NextSingle(), Random.Shared.NextSingle(), Random.Shared.NextSingle());
|
||||||
var v3 = Vector3.Lerp(v1, v2, amt);
|
var v3 = Vector3.Lerp(v1, v2, amt);
|
||||||
|
|
||||||
var v11 = new RcVec3f(v1.X, v1.Y, v1.Z);
|
var v11 = new Vector3(v1.X, v1.Y, v1.Z);
|
||||||
var v22 = new RcVec3f(v2.X, v2.Y, v2.Z);
|
var v22 = new Vector3(v2.X, v2.Y, v2.Z);
|
||||||
var v33 = RcVec3f.Lerp(v11, v22, amt);
|
var v33 = Vector3.Lerp(v11, v22, amt);
|
||||||
|
|
||||||
Assert.That(v3.X, Is.EqualTo(v33.X));
|
Assert.That(v3.X, Is.EqualTo(v33.X));
|
||||||
Assert.That(v3.Y, Is.EqualTo(v33.Y));
|
Assert.That(v3.Y, Is.EqualTo(v33.Y));
|
|
@ -21,11 +21,12 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd.Test;
|
namespace DotRecast.Detour.Crowd.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class AbstractCrowdTest
|
public class AbstractCrowdTest
|
||||||
{
|
{
|
||||||
protected readonly long[] startRefs =
|
protected readonly long[] startRefs =
|
||||||
|
@ -36,22 +37,22 @@ public class AbstractCrowdTest
|
||||||
|
|
||||||
protected readonly long[] endRefs = { 281474976710721L, 281474976710767L, 281474976710758L, 281474976710731L, 281474976710772L };
|
protected readonly long[] endRefs = { 281474976710721L, 281474976710767L, 281474976710758L, 281474976710731L, 281474976710772L };
|
||||||
|
|
||||||
protected readonly RcVec3f[] startPoss =
|
protected readonly Vector3[] startPoss =
|
||||||
{
|
{
|
||||||
new RcVec3f(22.60652f, 10.197294f, -45.918674f),
|
new Vector3(22.60652f, 10.197294f, -45.918674f),
|
||||||
new RcVec3f(22.331268f, 10.197294f, -1.0401875f),
|
new Vector3(22.331268f, 10.197294f, -1.0401875f),
|
||||||
new RcVec3f(18.694363f, 15.803535f, -73.090416f),
|
new Vector3(18.694363f, 15.803535f, -73.090416f),
|
||||||
new RcVec3f(0.7453353f, 10.197294f, -5.94005f),
|
new Vector3(0.7453353f, 10.197294f, -5.94005f),
|
||||||
new RcVec3f(-20.651257f, 5.904126f, -13.712508f),
|
new Vector3(-20.651257f, 5.904126f, -13.712508f),
|
||||||
};
|
};
|
||||||
|
|
||||||
protected readonly RcVec3f[] endPoss =
|
protected readonly Vector3[] endPoss =
|
||||||
{
|
{
|
||||||
new RcVec3f(6.4576626f, 10.197294f, -18.33406f),
|
new Vector3(6.4576626f, 10.197294f, -18.33406f),
|
||||||
new RcVec3f(-5.8023443f, 0.19729415f, 3.008419f),
|
new Vector3(-5.8023443f, 0.19729415f, 3.008419f),
|
||||||
new RcVec3f(38.423977f, 10.197294f, -0.116066754f),
|
new Vector3(38.423977f, 10.197294f, -0.116066754f),
|
||||||
new RcVec3f(0.8635526f, 10.197294f, -10.31032f),
|
new Vector3(0.8635526f, 10.197294f, -10.31032f),
|
||||||
new RcVec3f(18.784092f, 10.197294f, 3.0543678f),
|
new Vector3(18.784092f, 10.197294f, 3.0543678f),
|
||||||
};
|
};
|
||||||
|
|
||||||
protected DtMeshData nmd;
|
protected DtMeshData nmd;
|
||||||
|
@ -110,14 +111,14 @@ public class AbstractCrowdTest
|
||||||
return ap;
|
return ap;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void AddAgentGrid(int size, float distance, int updateFlags, int obstacleAvoidanceType, RcVec3f startPos)
|
protected void AddAgentGrid(int size, float distance, int updateFlags, int obstacleAvoidanceType, Vector3 startPos)
|
||||||
{
|
{
|
||||||
DtCrowdAgentParams ap = GetAgentParams(updateFlags, obstacleAvoidanceType);
|
DtCrowdAgentParams ap = GetAgentParams(updateFlags, obstacleAvoidanceType);
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < size; j++)
|
for (int j = 0; j < size; j++)
|
||||||
{
|
{
|
||||||
RcVec3f pos = new RcVec3f();
|
Vector3 pos = new Vector3();
|
||||||
pos.X = startPos.X + i * distance;
|
pos.X = startPos.X + i * distance;
|
||||||
pos.Y = startPos.Y;
|
pos.Y = startPos.Y;
|
||||||
pos.Z = startPos.Z + j * distance;
|
pos.Z = startPos.Z + j * distance;
|
||||||
|
@ -126,15 +127,15 @@ public class AbstractCrowdTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetMoveTarget(RcVec3f pos, bool adjust)
|
protected void SetMoveTarget(Vector3 pos, bool adjust)
|
||||||
{
|
{
|
||||||
RcVec3f ext = crowd.GetQueryExtents();
|
Vector3 ext = crowd.GetQueryExtents();
|
||||||
IDtQueryFilter filter = crowd.GetFilter(0);
|
IDtQueryFilter filter = crowd.GetFilter(0);
|
||||||
if (adjust)
|
if (adjust)
|
||||||
{
|
{
|
||||||
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
|
||||||
{
|
{
|
||||||
RcVec3f vel = CalcVel(ag.npos, pos, ag.option.maxSpeed);
|
Vector3 vel = CalcVel(ag.npos, pos, ag.option.maxSpeed);
|
||||||
crowd.RequestMoveVelocity(ag, vel);
|
crowd.RequestMoveVelocity(ag, vel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,11 +149,11 @@ public class AbstractCrowdTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RcVec3f CalcVel(RcVec3f pos, RcVec3f tgt, float speed)
|
protected Vector3 CalcVel(Vector3 pos, Vector3 tgt, float speed)
|
||||||
{
|
{
|
||||||
RcVec3f vel = RcVec3f.Subtract(tgt, pos);
|
Vector3 vel = Vector3.Subtract(tgt, pos);
|
||||||
vel.Y = 0.0f;
|
vel.Y = 0.0f;
|
||||||
vel = RcVec3f.Normalize(vel);
|
vel = Vector3.Normalize(vel);
|
||||||
vel = vel.Scale(speed);
|
vel = vel.Scale(speed);
|
||||||
return vel;
|
return vel;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd.Test;
|
namespace DotRecast.Detour.Crowd.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class Crowd1Test : AbstractCrowdTest
|
public class Crowd1Test : AbstractCrowdTest
|
||||||
{
|
{
|
||||||
static readonly float[][] EXPECTED_A1Q0TVTA =
|
static readonly float[][] EXPECTED_A1Q0TVTA =
|
||||||
|
|
|
@ -24,7 +24,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd.Test;
|
namespace DotRecast.Detour.Crowd.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class Crowd4Test : AbstractCrowdTest
|
public class Crowd4Test : AbstractCrowdTest
|
||||||
{
|
{
|
||||||
static readonly float[][] EXPECTED_A1Q2TVTA =
|
static readonly float[][] EXPECTED_A1Q2TVTA =
|
||||||
|
|
|
@ -22,7 +22,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd.Test;
|
namespace DotRecast.Detour.Crowd.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class Crowd4VelocityTest : AbstractCrowdTest
|
public class Crowd4VelocityTest : AbstractCrowdTest
|
||||||
{
|
{
|
||||||
static readonly float[][] EXPECTED_A1Q3TVTA =
|
static readonly float[][] EXPECTED_A1Q3TVTA =
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageReference Include="Moq" Version="4.20.70" />
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
<PackageReference Include="NUnit.Analyzers" Version="3.10.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
@ -19,13 +19,14 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd.Test;
|
namespace DotRecast.Detour.Crowd.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class PathCorridorTest
|
public class PathCorridorTest
|
||||||
{
|
{
|
||||||
private readonly DtPathCorridor corridor = new DtPathCorridor();
|
private readonly DtPathCorridor corridor = new DtPathCorridor();
|
||||||
|
@ -34,28 +35,27 @@ public class PathCorridorTest
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public void SetUp()
|
||||||
{
|
{
|
||||||
corridor.Init(256);
|
corridor.Reset(0, new Vector3(10, 20, 30));
|
||||||
corridor.Reset(0, new RcVec3f(10, 20, 30));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void ShouldKeepOriginalPathInFindCornersWhenNothingCanBePruned()
|
public void ShouldKeepOriginalPathInFindCornersWhenNothingCanBePruned()
|
||||||
{
|
{
|
||||||
List<DtStraightPath> straightPath = new();
|
List<DtStraightPath> straightPath = new();
|
||||||
straightPath.Add(new DtStraightPath(new RcVec3f(11, 20, 30.00001f), 0, 0));
|
straightPath.Add(new DtStraightPath(new Vector3(11, 20, 30.00001f), 0, 0));
|
||||||
straightPath.Add(new DtStraightPath(new RcVec3f(12, 20, 30.00002f), 0, 0));
|
straightPath.Add(new DtStraightPath(new Vector3(12, 20, 30.00002f), 0, 0));
|
||||||
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
|
straightPath.Add(new DtStraightPath(new Vector3(11f, 21, 32f), 0, 0));
|
||||||
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
|
straightPath.Add(new DtStraightPath(new Vector3(11f, 21, 32f), 0, 0));
|
||||||
var mockQuery = new Mock<DtNavMeshQuery>(It.IsAny<DtNavMesh>());
|
var mockQuery = new Mock<DtNavMeshQuery>(It.IsAny<DtNavMesh>());
|
||||||
mockQuery.Setup(q => q.FindStraightPath(
|
mockQuery.Setup(q => q.FindStraightPath(
|
||||||
It.IsAny<RcVec3f>(),
|
It.IsAny<Vector3>(),
|
||||||
It.IsAny<RcVec3f>(),
|
It.IsAny<Vector3>(),
|
||||||
It.IsAny<List<long>>(),
|
It.IsAny<List<long>>(),
|
||||||
ref It.Ref<List<DtStraightPath>>.IsAny,
|
ref It.Ref<List<DtStraightPath>>.IsAny,
|
||||||
It.IsAny<int>(),
|
It.IsAny<int>(),
|
||||||
It.IsAny<int>())
|
It.IsAny<int>())
|
||||||
)
|
)
|
||||||
.Callback((RcVec3f startPos, RcVec3f endPos, List<long> path,
|
.Callback((Vector3 startPos, Vector3 endPos, List<long> path,
|
||||||
ref List<DtStraightPath> refStraightPath, int maxStraightPath, int options) =>
|
ref List<DtStraightPath> refStraightPath, int maxStraightPath, int options) =>
|
||||||
{
|
{
|
||||||
refStraightPath = straightPath;
|
refStraightPath = straightPath;
|
||||||
|
@ -72,21 +72,21 @@ public class PathCorridorTest
|
||||||
public void ShouldPrunePathInFindCorners()
|
public void ShouldPrunePathInFindCorners()
|
||||||
{
|
{
|
||||||
List<DtStraightPath> straightPath = new();
|
List<DtStraightPath> straightPath = new();
|
||||||
straightPath.Add(new DtStraightPath(new RcVec3f(10, 20, 30.00001f), 0, 0)); // too close
|
straightPath.Add(new DtStraightPath(new Vector3(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 Vector3(10, 20, 30.00002f), 0, 0)); // too close
|
||||||
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
|
straightPath.Add(new DtStraightPath(new Vector3(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 Vector3(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
|
straightPath.Add(new DtStraightPath(new Vector3(11f, 21, 32f), DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
|
||||||
|
|
||||||
var mockQuery = new Mock<DtNavMeshQuery>(It.IsAny<DtNavMesh>());
|
var mockQuery = new Mock<DtNavMeshQuery>(It.IsAny<DtNavMesh>());
|
||||||
mockQuery.Setup(q => q.FindStraightPath(
|
mockQuery.Setup(q => q.FindStraightPath(
|
||||||
It.IsAny<RcVec3f>(),
|
It.IsAny<Vector3>(),
|
||||||
It.IsAny<RcVec3f>(),
|
It.IsAny<Vector3>(),
|
||||||
It.IsAny<List<long>>(),
|
It.IsAny<List<long>>(),
|
||||||
ref It.Ref<List<DtStraightPath>>.IsAny,
|
ref It.Ref<List<DtStraightPath>>.IsAny,
|
||||||
It.IsAny<int>(),
|
It.IsAny<int>(),
|
||||||
It.IsAny<int>())
|
It.IsAny<int>())
|
||||||
).Callback((RcVec3f startPos, RcVec3f endPos, List<long> path,
|
).Callback((Vector3 startPos, Vector3 endPos, List<long> path,
|
||||||
ref List<DtStraightPath> refStraightPath, int maxStraightPath, int options) =>
|
ref List<DtStraightPath> refStraightPath, int maxStraightPath, int options) =>
|
||||||
{
|
{
|
||||||
refStraightPath = straightPath;
|
refStraightPath = straightPath;
|
||||||
|
|
|
@ -17,6 +17,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
|
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageReference Include="Moq" Version="4.20.70" />
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
<PackageReference Include="NUnit.Analyzers" Version="3.10.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Dynamic.Colliders;
|
using DotRecast.Detour.Dynamic.Colliders;
|
||||||
using DotRecast.Detour.Dynamic.Io;
|
using DotRecast.Detour.Dynamic.Io;
|
||||||
using DotRecast.Detour.Dynamic.Test.Io;
|
using DotRecast.Detour.Dynamic.Test.Io;
|
||||||
|
@ -10,13 +11,13 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Test;
|
namespace DotRecast.Detour.Dynamic.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class DynamicNavMeshTest
|
public class DynamicNavMeshTest
|
||||||
{
|
{
|
||||||
private static readonly RcVec3f START_POS = new RcVec3f(70.87453f, 0.0010070801f, 86.69021f);
|
private static readonly Vector3 START_POS = new Vector3(70.87453f, 0.0010070801f, 86.69021f);
|
||||||
private static readonly RcVec3f END_POS = new RcVec3f(-50.22061f, 0.0010070801f, -70.761444f);
|
private static readonly Vector3 END_POS = new Vector3(-50.22061f, 0.0010070801f, -70.761444f);
|
||||||
private static readonly RcVec3f EXTENT = new RcVec3f(0.1f, 0.1f, 0.1f);
|
private static readonly Vector3 EXTENT = new Vector3(0.1f, 0.1f, 0.1f);
|
||||||
private static readonly RcVec3f SPHERE_POS = new RcVec3f(45.381645f, 0.0010070801f, 52.68981f);
|
private static readonly Vector3 SPHERE_POS = new Vector3(45.381645f, 0.0010070801f, 52.68981f);
|
||||||
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -20,12 +20,13 @@ freely, subject to the following restrictions:
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Dynamic.Io;
|
using DotRecast.Detour.Dynamic.Io;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Test.Io;
|
namespace DotRecast.Detour.Dynamic.Test.Io;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class VoxelFileReaderTest
|
public class VoxelFileReaderTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -50,8 +51,8 @@ public class VoxelFileReaderTest
|
||||||
Assert.That(f.tiles[0].cellHeight, Is.EqualTo(0.001f));
|
Assert.That(f.tiles[0].cellHeight, Is.EqualTo(0.001f));
|
||||||
Assert.That(f.tiles[0].width, Is.EqualTo(810));
|
Assert.That(f.tiles[0].width, Is.EqualTo(810));
|
||||||
Assert.That(f.tiles[0].depth, Is.EqualTo(810));
|
Assert.That(f.tiles[0].depth, Is.EqualTo(810));
|
||||||
Assert.That(f.tiles[0].boundsMin, Is.EqualTo(new RcVec3f(-101.25f, 0f, -101.25f)));
|
Assert.That(f.tiles[0].boundsMin, Is.EqualTo(new Vector3(-101.25f, 0f, -101.25f)));
|
||||||
Assert.That(f.tiles[0].boundsMax, Is.EqualTo(new RcVec3f(101.25f, 5.0f, 101.25f)));
|
Assert.That(f.tiles[0].boundsMax, Is.EqualTo(new Vector3(101.25f, 5.0f, 101.25f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -77,7 +78,7 @@ public class VoxelFileReaderTest
|
||||||
Assert.That(f.tiles[0].cellHeight, Is.EqualTo(0.001f));
|
Assert.That(f.tiles[0].cellHeight, Is.EqualTo(0.001f));
|
||||||
Assert.That(f.tiles[0].width, Is.EqualTo(90));
|
Assert.That(f.tiles[0].width, Is.EqualTo(90));
|
||||||
Assert.That(f.tiles[0].depth, Is.EqualTo(90));
|
Assert.That(f.tiles[0].depth, Is.EqualTo(90));
|
||||||
Assert.That(f.tiles[0].boundsMin, Is.EqualTo(new RcVec3f(-101.25f, 0f, -101.25f)));
|
Assert.That(f.tiles[0].boundsMin, Is.EqualTo(new Vector3(-101.25f, 0f, -101.25f)));
|
||||||
Assert.That(f.tiles[0].boundsMax, Is.EqualTo(new RcVec3f(-78.75f, 5.0f, -78.75f)));
|
Assert.That(f.tiles[0].boundsMax, Is.EqualTo(new Vector3(-78.75f, 5.0f, -78.75f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,12 +20,13 @@ freely, subject to the following restrictions:
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Dynamic.Io;
|
using DotRecast.Detour.Dynamic.Io;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Test.Io;
|
namespace DotRecast.Detour.Dynamic.Test.Io;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class VoxelFileReaderWriterTest
|
public class VoxelFileReaderWriterTest
|
||||||
{
|
{
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
|
@ -52,8 +53,8 @@ public class VoxelFileReaderWriterTest
|
||||||
Assert.That(f.tiles[0].width, Is.EqualTo(810));
|
Assert.That(f.tiles[0].width, Is.EqualTo(810));
|
||||||
Assert.That(f.tiles[0].depth, Is.EqualTo(810));
|
Assert.That(f.tiles[0].depth, Is.EqualTo(810));
|
||||||
Assert.That(f.tiles[0].spanData.Length, Is.EqualTo(9021024));
|
Assert.That(f.tiles[0].spanData.Length, Is.EqualTo(9021024));
|
||||||
Assert.That(f.tiles[0].boundsMin, Is.EqualTo(new RcVec3f(-101.25f, 0f, -101.25f)));
|
Assert.That(f.tiles[0].boundsMin, Is.EqualTo(new Vector3(-101.25f, 0f, -101.25f)));
|
||||||
Assert.That(f.tiles[0].boundsMax, Is.EqualTo(new RcVec3f(101.25f, 5.0f, 101.25f)));
|
Assert.That(f.tiles[0].boundsMax, Is.EqualTo(new Vector3(101.25f, 5.0f, 101.25f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
|
@ -83,8 +84,8 @@ public class VoxelFileReaderWriterTest
|
||||||
Assert.That(f.tiles[0].spanData.Length, Is.EqualTo(104952));
|
Assert.That(f.tiles[0].spanData.Length, Is.EqualTo(104952));
|
||||||
Assert.That(f.tiles[5].spanData.Length, Is.EqualTo(109080));
|
Assert.That(f.tiles[5].spanData.Length, Is.EqualTo(109080));
|
||||||
Assert.That(f.tiles[18].spanData.Length, Is.EqualTo(113400));
|
Assert.That(f.tiles[18].spanData.Length, Is.EqualTo(113400));
|
||||||
Assert.That(f.tiles[0].boundsMin, Is.EqualTo(new RcVec3f(-101.25f, 0f, -101.25f)));
|
Assert.That(f.tiles[0].boundsMin, Is.EqualTo(new Vector3(-101.25f, 0f, -101.25f)));
|
||||||
Assert.That(f.tiles[0].boundsMax, Is.EqualTo(new RcVec3f(-78.75f, 5.0f, -78.75f)));
|
Assert.That(f.tiles[0].boundsMax, Is.EqualTo(new Vector3(-78.75f, 5.0f, -78.75f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private DtVoxelFile ReadWriteRead(BinaryReader bis, bool compression)
|
private DtVoxelFile ReadWriteRead(BinaryReader bis, bool compression)
|
||||||
|
|
|
@ -23,6 +23,7 @@ using System.Threading.Tasks;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Dynamic.Io;
|
using DotRecast.Detour.Dynamic.Io;
|
||||||
using DotRecast.Detour.Dynamic.Test.Io;
|
using DotRecast.Detour.Dynamic.Test.Io;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
|
@ -31,12 +32,12 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Dynamic.Test;
|
namespace DotRecast.Detour.Dynamic.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class VoxelQueryTest
|
public class VoxelQueryTest
|
||||||
{
|
{
|
||||||
private const int TILE_WIDTH = 100;
|
private const int TILE_WIDTH = 100;
|
||||||
private const int TILE_DEPTH = 90;
|
private const int TILE_DEPTH = 90;
|
||||||
private static readonly RcVec3f ORIGIN = new RcVec3f(50, 10, 40);
|
private static readonly Vector3 ORIGIN = new Vector3(50, 10, 40);
|
||||||
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -58,8 +59,8 @@ public class VoxelQueryTest
|
||||||
});
|
});
|
||||||
|
|
||||||
DtVoxelQuery query = new DtVoxelQuery(ORIGIN, TILE_WIDTH, TILE_DEPTH, hfProvider.Object);
|
DtVoxelQuery query = new DtVoxelQuery(ORIGIN, TILE_WIDTH, TILE_DEPTH, hfProvider.Object);
|
||||||
RcVec3f start = new RcVec3f(120, 10, 365);
|
Vector3 start = new Vector3(120, 10, 365);
|
||||||
RcVec3f end = new RcVec3f(320, 10, 57);
|
Vector3 end = new Vector3(320, 10, 57);
|
||||||
|
|
||||||
// When
|
// When
|
||||||
query.Raycast(start, end, out var hit);
|
query.Raycast(start, end, out var hit);
|
||||||
|
@ -74,8 +75,8 @@ public class VoxelQueryTest
|
||||||
{
|
{
|
||||||
DtDynamicNavMesh mesh = CreateDynaMesh();
|
DtDynamicNavMesh mesh = CreateDynaMesh();
|
||||||
DtVoxelQuery query = mesh.VoxelQuery();
|
DtVoxelQuery query = mesh.VoxelQuery();
|
||||||
RcVec3f start = new RcVec3f(7.4f, 0.5f, -64.8f);
|
Vector3 start = new Vector3(7.4f, 0.5f, -64.8f);
|
||||||
RcVec3f end = new RcVec3f(31.2f, 0.5f, -75.3f);
|
Vector3 end = new Vector3(31.2f, 0.5f, -75.3f);
|
||||||
bool isHit = query.Raycast(start, end, out var hit);
|
bool isHit = query.Raycast(start, end, out var hit);
|
||||||
Assert.That(isHit, Is.EqualTo(false));
|
Assert.That(isHit, Is.EqualTo(false));
|
||||||
}
|
}
|
||||||
|
@ -85,8 +86,8 @@ public class VoxelQueryTest
|
||||||
{
|
{
|
||||||
DtDynamicNavMesh mesh = CreateDynaMesh();
|
DtDynamicNavMesh mesh = CreateDynaMesh();
|
||||||
DtVoxelQuery query = mesh.VoxelQuery();
|
DtVoxelQuery query = mesh.VoxelQuery();
|
||||||
RcVec3f start = new RcVec3f(32.3f, 0.5f, 47.9f);
|
Vector3 start = new Vector3(32.3f, 0.5f, 47.9f);
|
||||||
RcVec3f end = new RcVec3f(-31.2f, 0.5f, -29.8f);
|
Vector3 end = new Vector3(-31.2f, 0.5f, -29.8f);
|
||||||
bool isHit = query.Raycast(start, end, out var hit);
|
bool isHit = query.Raycast(start, end, out var hit);
|
||||||
Assert.That(isHit, Is.EqualTo(true));
|
Assert.That(isHit, Is.EqualTo(true));
|
||||||
Assert.That(hit, Is.EqualTo(0.5263836f).Within(1e-7f));
|
Assert.That(hit, Is.EqualTo(0.5263836f).Within(1e-7f));
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageReference Include="Moq" Version="4.20.70" />
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
<PackageReference Include="NUnit.Analyzers" Version="3.10.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
@ -20,21 +20,22 @@ using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Extras.Unity.Astar;
|
using DotRecast.Detour.Extras.Unity.Astar;
|
||||||
using DotRecast.Detour.Io;
|
using DotRecast.Detour.Io;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Extras.Test.Unity.Astar;
|
namespace DotRecast.Detour.Extras.Test.Unity.Astar;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class UnityAStarPathfindingImporterTest
|
public class UnityAStarPathfindingImporterTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void Test_v4_0_6()
|
public void Test_v4_0_6()
|
||||||
{
|
{
|
||||||
DtNavMesh mesh = LoadNavMesh("graph.zip");
|
DtNavMesh mesh = LoadNavMesh("graph.zip");
|
||||||
RcVec3f startPos = new RcVec3f(8.200293f, 2.155071f, -26.176147f);
|
Vector3 startPos = new Vector3(8.200293f, 2.155071f, -26.176147f);
|
||||||
RcVec3f endPos = new RcVec3f(11.971109f, 0.000000f, 8.663261f);
|
Vector3 endPos = new Vector3(11.971109f, 0.000000f, 8.663261f);
|
||||||
var path = new List<long>();
|
var path = new List<long>();
|
||||||
var status = FindPath(mesh, startPos, endPos, ref path);
|
var status = FindPath(mesh, startPos, endPos, ref path);
|
||||||
Assert.That(status, Is.EqualTo(DtStatus.DT_SUCCESS));
|
Assert.That(status, Is.EqualTo(DtStatus.DT_SUCCESS));
|
||||||
|
@ -46,8 +47,8 @@ public class UnityAStarPathfindingImporterTest
|
||||||
public void Test_v4_1_16()
|
public void Test_v4_1_16()
|
||||||
{
|
{
|
||||||
DtNavMesh mesh = LoadNavMesh("graph_v4_1_16.zip");
|
DtNavMesh mesh = LoadNavMesh("graph_v4_1_16.zip");
|
||||||
RcVec3f startPos = new RcVec3f(22.93f, -2.37f, -5.11f);
|
Vector3 startPos = new Vector3(22.93f, -2.37f, -5.11f);
|
||||||
RcVec3f endPos = new RcVec3f(16.81f, -2.37f, 25.52f);
|
Vector3 endPos = new Vector3(16.81f, -2.37f, 25.52f);
|
||||||
var path = new List<long>();
|
var path = new List<long>();
|
||||||
var status = FindPath(mesh, startPos, endPos, ref path);
|
var status = FindPath(mesh, startPos, endPos, ref path);
|
||||||
Assert.That(status.Succeeded(), Is.True);
|
Assert.That(status.Succeeded(), Is.True);
|
||||||
|
@ -59,7 +60,7 @@ public class UnityAStarPathfindingImporterTest
|
||||||
public void TestBoundsTree()
|
public void TestBoundsTree()
|
||||||
{
|
{
|
||||||
DtNavMesh mesh = LoadNavMesh("test_boundstree.zip");
|
DtNavMesh mesh = LoadNavMesh("test_boundstree.zip");
|
||||||
RcVec3f position = new RcVec3f(387.52988f, 19.997f, 368.86282f);
|
Vector3 position = new Vector3(387.52988f, 19.997f, 368.86282f);
|
||||||
|
|
||||||
mesh.CalcTileLoc(position, out var tileX, out var tileY);
|
mesh.CalcTileLoc(position, out var tileX, out var tileY);
|
||||||
long tileRef = mesh.GetTileRefAt(tileX, tileY, 0);
|
long tileRef = mesh.GetTileRefAt(tileX, tileY, 0);
|
||||||
|
@ -90,7 +91,7 @@ public class UnityAStarPathfindingImporterTest
|
||||||
return meshes[0];
|
return meshes[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private DtStatus FindPath(DtNavMesh mesh, RcVec3f startPos, RcVec3f endPos, ref List<long> path)
|
private DtStatus FindPath(DtNavMesh mesh, Vector3 startPos, Vector3 endPos, ref List<long> path)
|
||||||
{
|
{
|
||||||
// Perform a simple pathfinding
|
// Perform a simple pathfinding
|
||||||
DtNavMeshQuery query = new DtNavMeshQuery(mesh);
|
DtNavMeshQuery query = new DtNavMeshQuery(mesh);
|
||||||
|
@ -100,19 +101,19 @@ public class UnityAStarPathfindingImporterTest
|
||||||
return query.FindPath(polys[0].refs, polys[1].refs, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
|
return query.FindPath(polys[0].refs, polys[1].refs, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DtPolyPoint[] GetNearestPolys(DtNavMesh mesh, params RcVec3f[] positions)
|
private DtPolyPoint[] GetNearestPolys(DtNavMesh mesh, params Vector3[] positions)
|
||||||
{
|
{
|
||||||
DtNavMeshQuery query = new DtNavMeshQuery(mesh);
|
DtNavMeshQuery query = new DtNavMeshQuery(mesh);
|
||||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||||
RcVec3f extents = new RcVec3f(0.1f, 0.1f, 0.1f);
|
Vector3 extents = new Vector3(0.1f, 0.1f, 0.1f);
|
||||||
|
|
||||||
var results = new DtPolyPoint[positions.Length];
|
var results = new DtPolyPoint[positions.Length];
|
||||||
for (int i = 0; i < results.Length; i++)
|
for (int i = 0; i < results.Length; i++)
|
||||||
{
|
{
|
||||||
RcVec3f position = positions[i];
|
Vector3 position = positions[i];
|
||||||
var status = query.FindNearestPoly(position, extents, filter, out var nearestRef, out var nearestPt, out var _);
|
var status = query.FindNearestPoly(position, extents, filter, out var nearestRef, out var nearestPt, out var _);
|
||||||
Assert.That(status.Succeeded(), Is.True);
|
Assert.That(status.Succeeded(), Is.True);
|
||||||
Assert.That(nearestPt, Is.Not.EqualTo(RcVec3f.Zero), "Nearest start position is null!");
|
Assert.That(nearestPt, Is.Not.EqualTo(Vector3.Zero), "Nearest start position is null!");
|
||||||
|
|
||||||
results[i] = new DtPolyPoint(nearestRef, nearestPt);
|
results[i] = new DtPolyPoint(nearestRef, nearestPt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,12 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public abstract class AbstractDetourTest
|
public abstract class AbstractDetourTest
|
||||||
{
|
{
|
||||||
protected static readonly long[] startRefs =
|
protected static readonly long[] startRefs =
|
||||||
|
@ -34,22 +35,22 @@ public abstract class AbstractDetourTest
|
||||||
281474976710721L, 281474976710767L, 281474976710758L, 281474976710731L, 281474976710772L
|
281474976710721L, 281474976710767L, 281474976710758L, 281474976710731L, 281474976710772L
|
||||||
};
|
};
|
||||||
|
|
||||||
protected static readonly RcVec3f[] startPoss =
|
protected static readonly Vector3[] startPoss =
|
||||||
{
|
{
|
||||||
new RcVec3f(22.60652f, 10.197294f, -45.918674f),
|
new Vector3(22.60652f, 10.197294f, -45.918674f),
|
||||||
new RcVec3f(22.331268f, 10.197294f, -1.0401875f),
|
new Vector3(22.331268f, 10.197294f, -1.0401875f),
|
||||||
new RcVec3f(18.694363f, 15.803535f, -73.090416f),
|
new Vector3(18.694363f, 15.803535f, -73.090416f),
|
||||||
new RcVec3f(0.7453353f, 10.197294f, -5.94005f),
|
new Vector3(0.7453353f, 10.197294f, -5.94005f),
|
||||||
new RcVec3f(-20.651257f, 5.904126f, -13.712508f)
|
new Vector3(-20.651257f, 5.904126f, -13.712508f)
|
||||||
};
|
};
|
||||||
|
|
||||||
protected static readonly RcVec3f[] endPoss =
|
protected static readonly Vector3[] endPoss =
|
||||||
{
|
{
|
||||||
new RcVec3f(6.4576626f, 10.197294f, -18.33406f),
|
new Vector3(6.4576626f, 10.197294f, -18.33406f),
|
||||||
new RcVec3f(-5.8023443f, 0.19729415f, 3.008419f),
|
new Vector3(-5.8023443f, 0.19729415f, 3.008419f),
|
||||||
new RcVec3f(38.423977f, 10.197294f, -0.116066754f),
|
new Vector3(38.423977f, 10.197294f, -0.116066754f),
|
||||||
new RcVec3f(0.8635526f, 10.197294f, -10.31032f),
|
new Vector3(0.8635526f, 10.197294f, -10.31032f),
|
||||||
new RcVec3f(18.784092f, 10.197294f, 3.0543678f),
|
new Vector3(18.784092f, 10.197294f, 3.0543678f),
|
||||||
};
|
};
|
||||||
|
|
||||||
protected DtNavMeshQuery query;
|
protected DtNavMeshQuery query;
|
||||||
|
|
|
@ -21,7 +21,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class ConvexConvexIntersectionTest
|
public class ConvexConvexIntersectionTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageReference Include="Moq" Version="4.20.70" />
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
<PackageReference Include="NUnit.Analyzers" Version="3.10.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
using System.Collections.Immutable;
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
|
||||||
|
|
||||||
public class DtNodePoolTest
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void TestGetNode()
|
|
||||||
{
|
|
||||||
var pool = new DtNodePool();
|
|
||||||
|
|
||||||
var node1St = pool.GetNode(0);
|
|
||||||
var node2St = pool.GetNode(0);
|
|
||||||
Assert.That(node1St, Is.SameAs(node2St));
|
|
||||||
|
|
||||||
node1St.state = 1;
|
|
||||||
var node3St = pool.GetNode(0);
|
|
||||||
Assert.That(node1St, Is.Not.SameAs(node3St));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestFindNode()
|
|
||||||
{
|
|
||||||
var pool = new DtNodePool();
|
|
||||||
|
|
||||||
var counts = ImmutableArray.Create(2, 3, 5);
|
|
||||||
|
|
||||||
// get and create
|
|
||||||
for (int i = 0; i < counts.Length; ++i)
|
|
||||||
{
|
|
||||||
var count = counts[i];
|
|
||||||
for (int ii = 0; ii < count; ++ii)
|
|
||||||
{
|
|
||||||
var node = pool.GetNode(i);
|
|
||||||
node.state = ii + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int sum = counts.Sum();
|
|
||||||
Assert.That(sum, Is.EqualTo(10));
|
|
||||||
|
|
||||||
// check GetNodeIdx GetNodeAtIdx
|
|
||||||
for (int i = 0; i < sum; ++i)
|
|
||||||
{
|
|
||||||
var node = pool.GetNodeAtIdx(i);
|
|
||||||
var nodeIdx = pool.GetNodeIdx(node);
|
|
||||||
var nodeByIdx = pool.GetNodeAtIdx(nodeIdx);
|
|
||||||
|
|
||||||
Assert.That(node, Is.SameAs(nodeByIdx));
|
|
||||||
Assert.That(nodeIdx, Is.EqualTo(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// check count
|
|
||||||
for (int i = 0; i < counts.Length; ++i)
|
|
||||||
{
|
|
||||||
var count = counts[i];
|
|
||||||
var n = pool.FindNodes(i, out var nodes);
|
|
||||||
Assert.That(n, Is.EqualTo(count));
|
|
||||||
Assert.That(nodes, Has.Count.EqualTo(count));
|
|
||||||
|
|
||||||
var node = pool.FindNode(i);
|
|
||||||
Assert.That(nodes[0], Is.SameAs(node));
|
|
||||||
|
|
||||||
var node2 = pool.FindNode(i);
|
|
||||||
Assert.That(nodes[0], Is.SameAs(node2));
|
|
||||||
}
|
|
||||||
|
|
||||||
// check other count
|
|
||||||
{
|
|
||||||
var n = pool.FindNodes(4, out var nodes);
|
|
||||||
Assert.That(n, Is.EqualTo(0));
|
|
||||||
Assert.That(nodes, Is.Null);
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalCount = pool.GetNodeCount();
|
|
||||||
Assert.That(totalCount, Is.EqualTo(sum));
|
|
||||||
|
|
||||||
pool.Clear();
|
|
||||||
totalCount = pool.GetNodeCount();
|
|
||||||
Assert.That(totalCount, Is.EqualTo(0));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using DotRecast.Core;
|
|
||||||
using DotRecast.Core.Collections;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
|
||||||
|
|
||||||
public class DtNodeQueueTest
|
|
||||||
{
|
|
||||||
private static List<DtNode> ShuffledNodes(int count)
|
|
||||||
{
|
|
||||||
var nodes = new List<DtNode>();
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
var node = new DtNode(i);
|
|
||||||
node.total = i;
|
|
||||||
nodes.Add(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes.Shuffle();
|
|
||||||
return nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestPushAndPop()
|
|
||||||
{
|
|
||||||
var queue = new DtNodeQueue();
|
|
||||||
|
|
||||||
// check count
|
|
||||||
Assert.That(queue.Count(), Is.EqualTo(0));
|
|
||||||
|
|
||||||
// null push
|
|
||||||
queue.Push(null);
|
|
||||||
Assert.That(queue.Count(), Is.EqualTo(0));
|
|
||||||
|
|
||||||
// test push
|
|
||||||
const int count = 1000;
|
|
||||||
var expectedNodes = ShuffledNodes(count);
|
|
||||||
foreach (var node in expectedNodes)
|
|
||||||
{
|
|
||||||
queue.Push(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(queue.Count(), Is.EqualTo(count));
|
|
||||||
|
|
||||||
// test pop
|
|
||||||
expectedNodes.Sort(DtNode.ComparisonNodeTotal);
|
|
||||||
foreach (var node in expectedNodes)
|
|
||||||
{
|
|
||||||
Assert.That(queue.Peek(), Is.SameAs(node));
|
|
||||||
Assert.That(queue.Pop(), Is.SameAs(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(queue.Count(), Is.EqualTo(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestClear()
|
|
||||||
{
|
|
||||||
var queue = new DtNodeQueue();
|
|
||||||
|
|
||||||
const int count = 555;
|
|
||||||
var expectedNodes = ShuffledNodes(count);
|
|
||||||
foreach (var node in expectedNodes)
|
|
||||||
{
|
|
||||||
queue.Push(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(queue.Count(), Is.EqualTo(count));
|
|
||||||
|
|
||||||
queue.Clear();
|
|
||||||
Assert.That(queue.Count(), Is.EqualTo(0));
|
|
||||||
Assert.That(queue.IsEmpty(), Is.True);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestModify()
|
|
||||||
{
|
|
||||||
var queue = new DtNodeQueue();
|
|
||||||
|
|
||||||
const int count = 5000;
|
|
||||||
var expectedNodes = ShuffledNodes(count);
|
|
||||||
|
|
||||||
foreach (var node in expectedNodes)
|
|
||||||
{
|
|
||||||
queue.Push(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check modify
|
|
||||||
queue.Modify(null);
|
|
||||||
|
|
||||||
// change total
|
|
||||||
var r = new RcRand();
|
|
||||||
foreach (var node in expectedNodes)
|
|
||||||
{
|
|
||||||
node.total = r.NextInt32() % (count / 50); // duplication for test
|
|
||||||
}
|
|
||||||
|
|
||||||
// test modify
|
|
||||||
foreach (var node in expectedNodes)
|
|
||||||
{
|
|
||||||
queue.Modify(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check
|
|
||||||
expectedNodes.Sort(DtNode.ComparisonNodeTotal);
|
|
||||||
foreach (var node in expectedNodes)
|
|
||||||
{
|
|
||||||
Assert.That(queue.Pop(), Is.SameAs(node));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,32 +17,33 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class FindDistanceToWallTest : AbstractDetourTest
|
public class FindDistanceToWallTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
private static readonly float[] DISTANCES_TO_WALL = { 0.597511f, 3.201085f, 0.603713f, 2.791475f, 2.815544f };
|
private static readonly float[] DISTANCES_TO_WALL = { 0.597511f, 3.201085f, 0.603713f, 2.791475f, 2.815544f };
|
||||||
|
|
||||||
private static readonly RcVec3f[] HIT_POSITION =
|
private static readonly Vector3[] HIT_POSITION =
|
||||||
{
|
{
|
||||||
new RcVec3f(23.177608f, 10.197294f, -45.742954f),
|
new Vector3(23.177608f, 10.197294f, -45.742954f),
|
||||||
new RcVec3f(22.331268f, 10.197294f, -4.241272f),
|
new Vector3(22.331268f, 10.197294f, -4.241272f),
|
||||||
new RcVec3f(18.108675f, 15.743596f, -73.236839f),
|
new Vector3(18.108675f, 15.743596f, -73.236839f),
|
||||||
new RcVec3f(1.984785f, 10.197294f, -8.441269f),
|
new Vector3(1.984785f, 10.197294f, -8.441269f),
|
||||||
new RcVec3f(-22.315216f, 4.997294f, -11.441269f),
|
new Vector3(-22.315216f, 4.997294f, -11.441269f),
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly RcVec3f[] HIT_NORMAL =
|
private static readonly Vector3[] HIT_NORMAL =
|
||||||
{
|
{
|
||||||
new RcVec3f(-0.955779f, 0.0f, -0.29408592f),
|
new Vector3(-0.955779f, 0.0f, -0.29408592f),
|
||||||
new RcVec3f(0.0f, 0.0f, 1.0f),
|
new Vector3(0.0f, 0.0f, 1.0f),
|
||||||
new RcVec3f(0.97014254f, 0.0f, 0.24253564f),
|
new Vector3(0.97014254f, 0.0f, 0.24253564f),
|
||||||
new RcVec3f(-1.0f, 0.0f, 0.0f),
|
new Vector3(-1.0f, 0.0f, 0.0f),
|
||||||
new RcVec3f(1.0f, 0.0f, 0.0f),
|
new Vector3(1.0f, 0.0f, 0.0f),
|
||||||
};
|
};
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -51,7 +52,7 @@ public class FindDistanceToWallTest : AbstractDetourTest
|
||||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||||
for (int i = 0; i < startRefs.Length; i++)
|
for (int i = 0; i < startRefs.Length; i++)
|
||||||
{
|
{
|
||||||
RcVec3f startPos = startPoss[i];
|
Vector3 startPos = startPoss[i];
|
||||||
query.FindDistanceToWall(startRefs[i], startPos, 3.5f, filter,
|
query.FindDistanceToWall(startRefs[i], startPos, 3.5f, filter,
|
||||||
out var hitDist, out var hitPos, out var hitNormal);
|
out var hitDist, out var hitPos, out var hitNormal);
|
||||||
Assert.That(hitDist, Is.EqualTo(DISTANCES_TO_WALL[i]).Within(0.001f));
|
Assert.That(hitDist, Is.EqualTo(DISTANCES_TO_WALL[i]).Within(0.001f));
|
||||||
|
|
|
@ -18,11 +18,12 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class FindLocalNeighbourhoodTest : AbstractDetourTest
|
public class FindLocalNeighbourhoodTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
private static readonly long[][] REFS =
|
private static readonly long[][] REFS =
|
||||||
|
@ -57,7 +58,7 @@ public class FindLocalNeighbourhoodTest : AbstractDetourTest
|
||||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||||
for (int i = 0; i < startRefs.Length; i++)
|
for (int i = 0; i < startRefs.Length; i++)
|
||||||
{
|
{
|
||||||
RcVec3f startPos = startPoss[i];
|
Vector3 startPos = startPoss[i];
|
||||||
var refs = new List<long>();
|
var refs = new List<long>();
|
||||||
var parentRefs = new List<long>();
|
var parentRefs = new List<long>();
|
||||||
var status = query.FindLocalNeighbourhood(startRefs[i], startPos, 3.5f, filter, ref refs, ref parentRefs);
|
var status = query.FindLocalNeighbourhood(startRefs[i], startPos, 3.5f, filter, ref refs, ref parentRefs);
|
||||||
|
|
|
@ -17,32 +17,33 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class FindNearestPolyTest : AbstractDetourTest
|
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 =
|
private static readonly Vector3[] POLY_POS =
|
||||||
{
|
{
|
||||||
new RcVec3f(22.606520f, 10.197294f, -45.918674f),
|
new Vector3(22.606520f, 10.197294f, -45.918674f),
|
||||||
new RcVec3f(22.331268f, 10.197294f, -1.040187f),
|
new Vector3(22.331268f, 10.197294f, -1.040187f),
|
||||||
new RcVec3f(18.694363f, 15.803535f, -73.090416f),
|
new Vector3(18.694363f, 15.803535f, -73.090416f),
|
||||||
new RcVec3f(0.745335f, 10.197294f, -5.940050f),
|
new Vector3(0.745335f, 10.197294f, -5.940050f),
|
||||||
new RcVec3f(-20.651257f, 5.904126f, -13.712508f)
|
new Vector3(-20.651257f, 5.904126f, -13.712508f)
|
||||||
};
|
};
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestFindNearestPoly()
|
public void TestFindNearestPoly()
|
||||||
{
|
{
|
||||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||||
RcVec3f extents = new RcVec3f(2, 4, 2);
|
Vector3 extents = new Vector3(2, 4, 2);
|
||||||
for (int i = 0; i < startRefs.Length; i++)
|
for (int i = 0; i < startRefs.Length; i++)
|
||||||
{
|
{
|
||||||
RcVec3f startPos = startPoss[i];
|
Vector3 startPos = startPoss[i];
|
||||||
var status = query.FindNearestPoly(startPos, extents, filter, out var nearestRef, out var nearestPt, out var _);
|
var status = query.FindNearestPoly(startPos, extents, filter, out var nearestRef, out var nearestPt, out var _);
|
||||||
Assert.That(status.Succeeded(), Is.True);
|
Assert.That(status.Succeeded(), Is.True);
|
||||||
Assert.That(nearestRef, Is.EqualTo(POLY_REFS[i]));
|
Assert.That(nearestRef, Is.EqualTo(POLY_REFS[i]));
|
||||||
|
@ -56,10 +57,10 @@ public class FindNearestPolyTest : AbstractDetourTest
|
||||||
[Test]
|
[Test]
|
||||||
public void ShouldReturnStartPosWhenNoPolyIsValid()
|
public void ShouldReturnStartPosWhenNoPolyIsValid()
|
||||||
{
|
{
|
||||||
RcVec3f extents = new RcVec3f(2, 4, 2);
|
Vector3 extents = new Vector3(2, 4, 2);
|
||||||
for (int i = 0; i < startRefs.Length; i++)
|
for (int i = 0; i < startRefs.Length; i++)
|
||||||
{
|
{
|
||||||
RcVec3f startPos = startPoss[i];
|
Vector3 startPos = startPoss[i];
|
||||||
var status = query.FindNearestPoly(startPos, extents, DtQueryEmptyFilter.Shared, out var nearestRef, out var nearestPt, out var _);
|
var status = query.FindNearestPoly(startPos, extents, DtQueryEmptyFilter.Shared, out var nearestRef, out var nearestPt, out var _);
|
||||||
Assert.That(status.Succeeded(), Is.True);
|
Assert.That(status.Succeeded(), Is.True);
|
||||||
Assert.That(nearestRef, Is.EqualTo(0L));
|
Assert.That(nearestRef, Is.EqualTo(0L));
|
||||||
|
|
|
@ -18,11 +18,12 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class FindPathTest : AbstractDetourTest
|
public class FindPathTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
private static readonly DtStatus[] STATUSES =
|
private static readonly DtStatus[] STATUSES =
|
||||||
|
@ -74,59 +75,59 @@ public class FindPathTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new DtStraightPath(new RcVec3f(22.606520f, 10.197294f, -45.918674f), 1, 281474976710696L),
|
new DtStraightPath(new Vector3(22.606520f, 10.197294f, -45.918674f), 1, 281474976710696L),
|
||||||
new DtStraightPath(new RcVec3f(3.484785f, 10.197294f, -34.241272f), 0, 281474976710713L),
|
new DtStraightPath(new Vector3(3.484785f, 10.197294f, -34.241272f), 0, 281474976710713L),
|
||||||
new DtStraightPath(new RcVec3f(1.984785f, 10.197294f, -31.241272f), 0, 281474976710712L),
|
new DtStraightPath(new Vector3(1.984785f, 10.197294f, -31.241272f), 0, 281474976710712L),
|
||||||
new DtStraightPath(new RcVec3f(1.984785f, 10.197294f, -29.741272f), 0, 281474976710727L),
|
new DtStraightPath(new Vector3(1.984785f, 10.197294f, -29.741272f), 0, 281474976710727L),
|
||||||
new DtStraightPath(new RcVec3f(2.584784f, 10.197294f, -27.941273f), 0, 281474976710730L),
|
new DtStraightPath(new Vector3(2.584784f, 10.197294f, -27.941273f), 0, 281474976710730L),
|
||||||
new DtStraightPath(new RcVec3f(6.457663f, 10.197294f, -18.334061f), 2, 0L)
|
new DtStraightPath(new Vector3(6.457663f, 10.197294f, -18.334061f), 2, 0L)
|
||||||
},
|
},
|
||||||
|
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new DtStraightPath(new RcVec3f(22.331268f, 10.197294f, -1.040187f), 1, 281474976710773L),
|
new DtStraightPath(new Vector3(22.331268f, 10.197294f, -1.040187f), 1, 281474976710773L),
|
||||||
new DtStraightPath(new RcVec3f(9.784786f, 10.197294f, -2.141273f), 0, 281474976710755L),
|
new DtStraightPath(new Vector3(9.784786f, 10.197294f, -2.141273f), 0, 281474976710755L),
|
||||||
new DtStraightPath(new RcVec3f(7.984783f, 10.197294f, -2.441269f), 0, 281474976710753L),
|
new DtStraightPath(new Vector3(7.984783f, 10.197294f, -2.441269f), 0, 281474976710753L),
|
||||||
new DtStraightPath(new RcVec3f(1.984785f, 10.197294f, -8.441269f), 0, 281474976710752L),
|
new DtStraightPath(new Vector3(1.984785f, 10.197294f, -8.441269f), 0, 281474976710752L),
|
||||||
new DtStraightPath(new RcVec3f(-4.315216f, 10.197294f, -15.341270f), 0, 281474976710724L),
|
new DtStraightPath(new Vector3(-4.315216f, 10.197294f, -15.341270f), 0, 281474976710724L),
|
||||||
new DtStraightPath(new RcVec3f(-8.215216f, 10.197294f, -17.441269f), 0, 281474976710728L),
|
new DtStraightPath(new Vector3(-8.215216f, 10.197294f, -17.441269f), 0, 281474976710728L),
|
||||||
new DtStraightPath(new RcVec3f(-10.015216f, 10.197294f, -17.741272f), 0, 281474976710738L),
|
new DtStraightPath(new Vector3(-10.015216f, 10.197294f, -17.741272f), 0, 281474976710738L),
|
||||||
new DtStraightPath(new RcVec3f(-11.815216f, 9.997294f, -17.441269f), 0, 281474976710736L),
|
new DtStraightPath(new Vector3(-11.815216f, 9.997294f, -17.441269f), 0, 281474976710736L),
|
||||||
new DtStraightPath(new RcVec3f(-17.815216f, 5.197294f, -11.441269f), 0, 281474976710735L),
|
new DtStraightPath(new Vector3(-17.815216f, 5.197294f, -11.441269f), 0, 281474976710735L),
|
||||||
new DtStraightPath(new RcVec3f(-17.815216f, 5.197294f, -8.441269f), 0, 281474976710746L),
|
new DtStraightPath(new Vector3(-17.815216f, 5.197294f, -8.441269f), 0, 281474976710746L),
|
||||||
new DtStraightPath(new RcVec3f(-11.815216f, 0.197294f, 3.008419f), 2, 0L)
|
new DtStraightPath(new Vector3(-11.815216f, 0.197294f, 3.008419f), 2, 0L)
|
||||||
},
|
},
|
||||||
|
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new DtStraightPath(new RcVec3f(18.694363f, 15.803535f, -73.090416f), 1, 281474976710680L),
|
new DtStraightPath(new Vector3(18.694363f, 15.803535f, -73.090416f), 1, 281474976710680L),
|
||||||
new DtStraightPath(new RcVec3f(17.584785f, 10.197294f, -49.841274f), 0, 281474976710697L),
|
new DtStraightPath(new Vector3(17.584785f, 10.197294f, -49.841274f), 0, 281474976710697L),
|
||||||
new DtStraightPath(new RcVec3f(17.284786f, 10.197294f, -48.041275f), 0, 281474976710695L),
|
new DtStraightPath(new Vector3(17.284786f, 10.197294f, -48.041275f), 0, 281474976710695L),
|
||||||
new DtStraightPath(new RcVec3f(16.084785f, 10.197294f, -45.341274f), 0, 281474976710694L),
|
new DtStraightPath(new Vector3(16.084785f, 10.197294f, -45.341274f), 0, 281474976710694L),
|
||||||
new DtStraightPath(new RcVec3f(3.484785f, 10.197294f, -34.241272f), 0, 281474976710713L),
|
new DtStraightPath(new Vector3(3.484785f, 10.197294f, -34.241272f), 0, 281474976710713L),
|
||||||
new DtStraightPath(new RcVec3f(1.984785f, 10.197294f, -31.241272f), 0, 281474976710712L),
|
new DtStraightPath(new Vector3(1.984785f, 10.197294f, -31.241272f), 0, 281474976710712L),
|
||||||
new DtStraightPath(new RcVec3f(1.984785f, 10.197294f, -8.441269f), 0, 281474976710753L),
|
new DtStraightPath(new Vector3(1.984785f, 10.197294f, -8.441269f), 0, 281474976710753L),
|
||||||
new DtStraightPath(new RcVec3f(7.984783f, 10.197294f, -2.441269f), 0, 281474976710755L),
|
new DtStraightPath(new Vector3(7.984783f, 10.197294f, -2.441269f), 0, 281474976710755L),
|
||||||
new DtStraightPath(new RcVec3f(9.784786f, 10.197294f, -2.141273f), 0, 281474976710768L),
|
new DtStraightPath(new Vector3(9.784786f, 10.197294f, -2.141273f), 0, 281474976710768L),
|
||||||
new DtStraightPath(new RcVec3f(38.423977f, 10.197294f, -0.116067f), 2, 0L)
|
new DtStraightPath(new Vector3(38.423977f, 10.197294f, -0.116067f), 2, 0L)
|
||||||
},
|
},
|
||||||
|
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new DtStraightPath(new RcVec3f(0.745335f, 10.197294f, -5.940050f), 1, 281474976710753L),
|
new DtStraightPath(new Vector3(0.745335f, 10.197294f, -5.940050f), 1, 281474976710753L),
|
||||||
new DtStraightPath(new RcVec3f(0.863553f, 10.197294f, -10.310320f), 2, 0L)
|
new DtStraightPath(new Vector3(0.863553f, 10.197294f, -10.310320f), 2, 0L)
|
||||||
},
|
},
|
||||||
|
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new DtStraightPath(new RcVec3f(-20.651257f, 5.904126f, -13.712508f), 1, 281474976710733L),
|
new DtStraightPath(new Vector3(-20.651257f, 5.904126f, -13.712508f), 1, 281474976710733L),
|
||||||
new DtStraightPath(new RcVec3f(-11.815216f, 9.997294f, -17.441269f), 0, 281474976710738L),
|
new DtStraightPath(new Vector3(-11.815216f, 9.997294f, -17.441269f), 0, 281474976710738L),
|
||||||
new DtStraightPath(new RcVec3f(-10.015216f, 10.197294f, -17.741272f), 0, 281474976710728L),
|
new DtStraightPath(new Vector3(-10.015216f, 10.197294f, -17.741272f), 0, 281474976710728L),
|
||||||
new DtStraightPath(new RcVec3f(-8.215216f, 10.197294f, -17.441269f), 0, 281474976710724L),
|
new DtStraightPath(new Vector3(-8.215216f, 10.197294f, -17.441269f), 0, 281474976710724L),
|
||||||
new DtStraightPath(new RcVec3f(-4.315216f, 10.197294f, -15.341270f), 0, 281474976710729L),
|
new DtStraightPath(new Vector3(-4.315216f, 10.197294f, -15.341270f), 0, 281474976710729L),
|
||||||
new DtStraightPath(new RcVec3f(1.984785f, 10.197294f, -8.441269f), 0, 281474976710753L),
|
new DtStraightPath(new Vector3(1.984785f, 10.197294f, -8.441269f), 0, 281474976710753L),
|
||||||
new DtStraightPath(new RcVec3f(7.984783f, 10.197294f, -2.441269f), 0, 281474976710755L),
|
new DtStraightPath(new Vector3(7.984783f, 10.197294f, -2.441269f), 0, 281474976710755L),
|
||||||
new DtStraightPath(new RcVec3f(18.784092f, 10.197294f, 3.054368f), 2, 0L)
|
new DtStraightPath(new Vector3(18.784092f, 10.197294f, 3.054368f), 2, 0L)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -139,8 +140,8 @@ public class FindPathTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
long startRef = startRefs[i];
|
long startRef = startRefs[i];
|
||||||
long endRef = endRefs[i];
|
long endRef = endRefs[i];
|
||||||
RcVec3f startPos = startPoss[i];
|
Vector3 startPos = startPoss[i];
|
||||||
RcVec3f endPos = endPoss[i];
|
Vector3 endPos = endPoss[i];
|
||||||
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
|
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
|
||||||
Assert.That(status, Is.EqualTo(STATUSES[i]));
|
Assert.That(status, Is.EqualTo(STATUSES[i]));
|
||||||
Assert.That(path.Count, Is.EqualTo(RESULTS[i].Length));
|
Assert.That(path.Count, Is.EqualTo(RESULTS[i].Length));
|
||||||
|
|
|
@ -18,11 +18,12 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class FindPolysAroundCircleTest : AbstractDetourTest
|
public class FindPolysAroundCircleTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
private static readonly long[][] REFS =
|
private static readonly long[][] REFS =
|
||||||
|
@ -108,7 +109,7 @@ public class FindPolysAroundCircleTest : AbstractDetourTest
|
||||||
for (int i = 0; i < startRefs.Length; i++)
|
for (int i = 0; i < startRefs.Length; i++)
|
||||||
{
|
{
|
||||||
long startRef = startRefs[i];
|
long startRef = startRefs[i];
|
||||||
RcVec3f startPos = startPoss[i];
|
Vector3 startPos = startPoss[i];
|
||||||
var status = query.FindPolysAroundCircle(startRef, startPos, 7.5f, filter, ref refs, ref parentRefs, ref costs);
|
var status = query.FindPolysAroundCircle(startRef, startPos, 7.5f, filter, ref refs, ref parentRefs, ref costs);
|
||||||
Assert.That(status.Succeeded(), Is.True);
|
Assert.That(status.Succeeded(), Is.True);
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,12 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class FindPolysAroundShapeTest : AbstractDetourTest
|
public class FindPolysAroundShapeTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
private static readonly long[][] REFS =
|
private static readonly long[][] REFS =
|
||||||
|
@ -136,7 +137,7 @@ public class FindPolysAroundShapeTest : AbstractDetourTest
|
||||||
for (int i = 0; i < startRefs.Length; i++)
|
for (int i = 0; i < startRefs.Length; i++)
|
||||||
{
|
{
|
||||||
long startRef = startRefs[i];
|
long startRef = startRefs[i];
|
||||||
RcVec3f startPos = startPoss[i];
|
Vector3 startPos = startPoss[i];
|
||||||
query.FindPolysAroundShape(startRef, GetQueryPoly(startPos, endPoss[i]), filter, ref refs, ref parentRefs, ref costs);
|
query.FindPolysAroundShape(startRef, GetQueryPoly(startPos, endPoss[i]), filter, ref refs, ref parentRefs, ref costs);
|
||||||
|
|
||||||
Assert.That(refs.Count, Is.EqualTo(REFS[i].Length));
|
Assert.That(refs.Count, Is.EqualTo(REFS[i].Length));
|
||||||
|
@ -158,13 +159,13 @@ public class FindPolysAroundShapeTest : AbstractDetourTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RcVec3f[] GetQueryPoly(RcVec3f m_spos, RcVec3f m_epos)
|
private Vector3[] GetQueryPoly(Vector3 m_spos, Vector3 m_epos)
|
||||||
{
|
{
|
||||||
float nx = (m_epos.Z - m_spos.Z) * 0.25f;
|
float nx = (m_epos.Z - m_spos.Z) * 0.25f;
|
||||||
float nz = -(m_epos.X - m_spos.X) * 0.25f;
|
float nz = -(m_epos.X - m_spos.X) * 0.25f;
|
||||||
float agentHeight = 2.0f;
|
float agentHeight = 2.0f;
|
||||||
|
|
||||||
RcVec3f[] m_queryPoly = new RcVec3f[4];
|
Vector3[] m_queryPoly = new Vector3[4];
|
||||||
m_queryPoly[0].X = m_spos.X + nx * 1.2f;
|
m_queryPoly[0].X = m_spos.X + nx * 1.2f;
|
||||||
m_queryPoly[0].Y = m_spos.Y + agentHeight / 2;
|
m_queryPoly[0].Y = m_spos.Y + agentHeight / 2;
|
||||||
m_queryPoly[0].Z = m_spos.Z + nz * 1.2f;
|
m_queryPoly[0].Z = m_spos.Z + nz * 1.2f;
|
||||||
|
|
|
@ -22,7 +22,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class GetPolyWallSegmentsTest : AbstractDetourTest
|
public class GetPolyWallSegmentsTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
private static readonly RcSegmentVert[][] VERTICES =
|
private static readonly RcSegmentVert[][] VERTICES =
|
||||||
|
|
|
@ -23,7 +23,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test.Io;
|
namespace DotRecast.Detour.Test.Io;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class MeshDataReaderWriterTest
|
public class MeshDataReaderWriterTest
|
||||||
{
|
{
|
||||||
private const int VERTS_PER_POLYGON = 6;
|
private const int VERTS_PER_POLYGON = 6;
|
||||||
|
|
|
@ -24,7 +24,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test.Io;
|
namespace DotRecast.Detour.Test.Io;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class MeshSetReaderTest
|
public class MeshSetReaderTest
|
||||||
{
|
{
|
||||||
private readonly DtMeshSetReader reader = new DtMeshSetReader();
|
private readonly DtMeshSetReader reader = new DtMeshSetReader();
|
||||||
|
|
|
@ -20,6 +20,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.Io;
|
using DotRecast.Detour.Io;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
|
@ -28,7 +29,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test.Io;
|
namespace DotRecast.Detour.Test.Io;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class MeshSetReaderWriterTest
|
public class MeshSetReaderWriterTest
|
||||||
{
|
{
|
||||||
private readonly DtMeshSetWriter writer = new DtMeshSetWriter();
|
private readonly DtMeshSetWriter writer = new DtMeshSetWriter();
|
||||||
|
@ -68,8 +69,8 @@ public class MeshSetReaderWriterTest
|
||||||
header.numTiles = 0;
|
header.numTiles = 0;
|
||||||
DtNavMesh mesh = new DtNavMesh(header.option, 6);
|
DtNavMesh mesh = new DtNavMesh(header.option, 6);
|
||||||
|
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
Vector3 bmin = geom.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
Vector3 bmax = geom.GetMeshBoundsMax();
|
||||||
RcCommons.CalcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize, out var tw, out var th);
|
RcCommons.CalcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize, out var tw, out var th);
|
||||||
for (int y = 0; y < th; ++y)
|
for (int y = 0; y < th; ++y)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,11 +18,12 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class MoveAlongSurfaceTest : AbstractDetourTest
|
public class MoveAlongSurfaceTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
private static readonly long[][] VISITED =
|
private static readonly long[][] VISITED =
|
||||||
|
@ -56,13 +57,13 @@ public class MoveAlongSurfaceTest : AbstractDetourTest
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly RcVec3f[] POSITION =
|
private static readonly Vector3[] POSITION =
|
||||||
{
|
{
|
||||||
new RcVec3f(6.457663f, 10.197294f, -18.334061f),
|
new Vector3(6.457663f, 10.197294f, -18.334061f),
|
||||||
new RcVec3f(-1.433933f, 10.197294f, -1.359993f),
|
new Vector3(-1.433933f, 10.197294f, -1.359993f),
|
||||||
new RcVec3f(12.184784f, 9.997294f, -18.941269f),
|
new Vector3(12.184784f, 9.997294f, -18.941269f),
|
||||||
new RcVec3f(0.863553f, 10.197294f, -10.310320f),
|
new Vector3(0.863553f, 10.197294f, -10.310320f),
|
||||||
new RcVec3f(18.784092f, 10.197294f, 3.054368f),
|
new Vector3(18.784092f, 10.197294f, 3.054368f),
|
||||||
};
|
};
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -73,8 +74,8 @@ public class MoveAlongSurfaceTest : AbstractDetourTest
|
||||||
for (int i = 0; i < startRefs.Length; i++)
|
for (int i = 0; i < startRefs.Length; i++)
|
||||||
{
|
{
|
||||||
long startRef = startRefs[i];
|
long startRef = startRefs[i];
|
||||||
RcVec3f startPos = startPoss[i];
|
Vector3 startPos = startPoss[i];
|
||||||
RcVec3f endPos = endPoss[i];
|
Vector3 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, ref visited);
|
||||||
Assert.That(status.Succeeded(), Is.True);
|
Assert.That(status.Succeeded(), Is.True);
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class NavMeshBuilderTest
|
public class NavMeshBuilderTest
|
||||||
{
|
{
|
||||||
private DtMeshData nmd;
|
private DtMeshData nmd;
|
||||||
|
|
|
@ -18,11 +18,12 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class PolygonByCircleConstraintTest
|
public class PolygonByCircleConstraintTest
|
||||||
{
|
{
|
||||||
private readonly IDtPolygonByCircleConstraint _constraint = DtStrictDtPolygonByCircleConstraint.Shared;
|
private readonly IDtPolygonByCircleConstraint _constraint = DtStrictDtPolygonByCircleConstraint.Shared;
|
||||||
|
@ -31,7 +32,7 @@ public class PolygonByCircleConstraintTest
|
||||||
public void ShouldHandlePolygonFullyInsideCircle()
|
public void ShouldHandlePolygonFullyInsideCircle()
|
||||||
{
|
{
|
||||||
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
|
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
|
||||||
RcVec3f center = new RcVec3f(1, 0, 1);
|
Vector3 center = new Vector3(1, 0, 1);
|
||||||
float[] constrained = _constraint.Apply(polygon, center, 6);
|
float[] constrained = _constraint.Apply(polygon, center, 6);
|
||||||
|
|
||||||
Assert.That(constrained, Is.EqualTo(polygon));
|
Assert.That(constrained, Is.EqualTo(polygon));
|
||||||
|
@ -42,7 +43,7 @@ public class PolygonByCircleConstraintTest
|
||||||
{
|
{
|
||||||
int expectedSize = 21;
|
int expectedSize = 21;
|
||||||
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
|
float[] polygon = { -2, 0, 2, 2, 0, 2, 2, 0, -2, -2, 0, -2 };
|
||||||
RcVec3f center = new RcVec3f(2, 0, 0);
|
Vector3 center = new Vector3(2, 0, 0);
|
||||||
|
|
||||||
float[] constrained = _constraint.Apply(polygon, center, 3);
|
float[] constrained = _constraint.Apply(polygon, center, 3);
|
||||||
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
||||||
|
@ -54,7 +55,7 @@ public class PolygonByCircleConstraintTest
|
||||||
{
|
{
|
||||||
int expectedSize = 12 * 3;
|
int expectedSize = 12 * 3;
|
||||||
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||||
RcVec3f center = new RcVec3f(-1, 0, -1);
|
Vector3 center = new Vector3(-1, 0, -1);
|
||||||
float[] constrained = _constraint.Apply(polygon, center, 2);
|
float[] constrained = _constraint.Apply(polygon, center, 2);
|
||||||
|
|
||||||
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
||||||
|
@ -72,7 +73,7 @@ public class PolygonByCircleConstraintTest
|
||||||
{
|
{
|
||||||
int expectedSize = 9 * 3;
|
int expectedSize = 9 * 3;
|
||||||
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||||
RcVec3f center = new RcVec3f(-2, 0, -1);
|
Vector3 center = new Vector3(-2, 0, -1);
|
||||||
float[] constrained = _constraint.Apply(polygon, center, 3);
|
float[] constrained = _constraint.Apply(polygon, center, 3);
|
||||||
|
|
||||||
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
||||||
|
@ -84,7 +85,7 @@ public class PolygonByCircleConstraintTest
|
||||||
{
|
{
|
||||||
int expectedSize = 7 * 3;
|
int expectedSize = 7 * 3;
|
||||||
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
float[] polygon = { -4, 0, 0, -3, 0, 3, 2, 0, 3, 3, 0, -3, -2, 0, -4 };
|
||||||
RcVec3f center = new RcVec3f(4, 0, 0);
|
Vector3 center = new Vector3(4, 0, 0);
|
||||||
float[] constrained = _constraint.Apply(polygon, center, 4);
|
float[] constrained = _constraint.Apply(polygon, center, 4);
|
||||||
|
|
||||||
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
Assert.That(constrained.Length, Is.EqualTo(expectedSize));
|
||||||
|
|
|
@ -19,13 +19,14 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class RandomPointTest : AbstractDetourTest
|
public class RandomPointTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -17,6 +17,7 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,13 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class TiledFindPathTest
|
public class TiledFindPathTest
|
||||||
{
|
{
|
||||||
private static readonly DtStatus[] STATUSES = { DtStatus.DT_SUCCESS };
|
private static readonly DtStatus[] STATUSES = { DtStatus.DT_SUCCESS };
|
||||||
|
@ -43,8 +44,8 @@ public class TiledFindPathTest
|
||||||
|
|
||||||
protected static readonly long[] START_REFS = { 281475015507969L };
|
protected static readonly long[] START_REFS = { 281475015507969L };
|
||||||
protected static readonly long[] END_REFS = { 281474985099266L };
|
protected static readonly long[] END_REFS = { 281474985099266L };
|
||||||
protected static readonly RcVec3f[] START_POS = { new RcVec3f(39.447338f, 9.998177f, -0.784811f) };
|
protected static readonly Vector3[] START_POS = { new Vector3(39.447338f, 9.998177f, -0.784811f) };
|
||||||
protected static readonly RcVec3f[] END_POS = { new RcVec3f(19.292645f, 11.611748f, -57.750366f) };
|
protected static readonly Vector3[] END_POS = { new Vector3(19.292645f, 11.611748f, -57.750366f) };
|
||||||
|
|
||||||
protected DtNavMeshQuery query;
|
protected DtNavMeshQuery query;
|
||||||
protected DtNavMesh navmesh;
|
protected DtNavMesh navmesh;
|
||||||
|
@ -70,8 +71,8 @@ public class TiledFindPathTest
|
||||||
{
|
{
|
||||||
long startRef = START_REFS[i];
|
long startRef = START_REFS[i];
|
||||||
long endRef = END_REFS[i];
|
long endRef = END_REFS[i];
|
||||||
RcVec3f startPos = START_POS[i];
|
Vector3 startPos = START_POS[i];
|
||||||
RcVec3f endPos = END_POS[i];
|
Vector3 endPos = END_POS[i];
|
||||||
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
|
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
|
||||||
Assert.That(status, Is.EqualTo(STATUSES[i]));
|
Assert.That(status, Is.EqualTo(STATUSES[i]));
|
||||||
Assert.That(path.Count, Is.EqualTo(RESULTS[i].Length));
|
Assert.That(path.Count, Is.EqualTo(RESULTS[i].Length));
|
||||||
|
|
|
@ -27,7 +27,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache.Test;
|
namespace DotRecast.Detour.TileCache.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class AbstractTileCacheTest
|
public class AbstractTileCacheTest
|
||||||
{
|
{
|
||||||
private const int EXPECTED_LAYERS_PER_TILE = 4;
|
private const int EXPECTED_LAYERS_PER_TILE = 4;
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageReference Include="Moq" Version="4.20.70" />
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
<PackageReference Include="NUnit.Analyzers" Version="3.10.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
@ -27,7 +27,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache.Test.Io;
|
namespace DotRecast.Detour.TileCache.Test.Io;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class TileCacheReaderTest
|
public class TileCacheReaderTest
|
||||||
{
|
{
|
||||||
private readonly DtTileCacheReader reader = new DtTileCacheReader(DtTileCacheCompressorFactory.Shared);
|
private readonly DtTileCacheReader reader = new DtTileCacheReader(DtTileCacheCompressorFactory.Shared);
|
||||||
|
|
|
@ -28,7 +28,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache.Test.Io;
|
namespace DotRecast.Detour.TileCache.Test.Io;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class TileCacheReaderWriterTest : AbstractTileCacheTest
|
public class TileCacheReaderWriterTest : AbstractTileCacheTest
|
||||||
{
|
{
|
||||||
private readonly DtTileCacheReader reader = new DtTileCacheReader(DtTileCacheCompressorFactory.Shared);
|
private readonly DtTileCacheReader reader = new DtTileCacheReader(DtTileCacheCompressorFactory.Shared);
|
||||||
|
|
|
@ -21,12 +21,13 @@ freely, subject to the following restrictions:
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache.Test;
|
namespace DotRecast.Detour.TileCache.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class TempObstaclesTest : AbstractTileCacheTest
|
public class TempObstaclesTest : AbstractTileCacheTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -47,7 +48,7 @@ public class TempObstaclesTest : AbstractTileCacheTest
|
||||||
DtMeshTile tile = tiles[0];
|
DtMeshTile tile = tiles[0];
|
||||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
||||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
||||||
long o = tc.AddObstacle(new RcVec3f(-1.815208f, 9.998184f, -20.307983f), 1f, 2f);
|
long o = tc.AddObstacle(new Vector3(-1.815208f, 9.998184f, -20.307983f), 1f, 2f);
|
||||||
bool upToDate = tc.Update();
|
bool upToDate = tc.Update();
|
||||||
Assert.That(upToDate, Is.True);
|
Assert.That(upToDate, Is.True);
|
||||||
tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
tiles = tc.GetNavMesh().GetTilesAt(1, 4);
|
||||||
|
@ -82,8 +83,8 @@ public class TempObstaclesTest : AbstractTileCacheTest
|
||||||
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
Assert.That(tile.data.header.vertCount, Is.EqualTo(16));
|
||||||
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
Assert.That(tile.data.header.polyCount, Is.EqualTo(6));
|
||||||
long o = tc.AddBoxObstacle(
|
long o = tc.AddBoxObstacle(
|
||||||
new RcVec3f(-2.315208f, 9.998184f, -20.807983f),
|
new Vector3(-2.315208f, 9.998184f, -20.807983f),
|
||||||
new RcVec3f(-1.315208f, 11.998184f, -19.807983f)
|
new Vector3(-1.315208f, 11.998184f, -19.807983f)
|
||||||
);
|
);
|
||||||
bool upToDate = tc.Update();
|
bool upToDate = tc.Update();
|
||||||
Assert.That(upToDate, Is.True);
|
Assert.That(upToDate, Is.True);
|
||||||
|
|
|
@ -22,6 +22,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.TileCache.Io.Compress;
|
using DotRecast.Detour.TileCache.Io.Compress;
|
||||||
using DotRecast.Recast;
|
using DotRecast.Recast;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
|
@ -71,8 +72,8 @@ public class TestTileLayerBuilder : DtTileCacheLayerBuilder
|
||||||
true, true, true,
|
true, true, true,
|
||||||
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
|
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
|
||||||
|
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
Vector3 bmin = geom.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
Vector3 bmax = geom.GetMeshBoundsMax();
|
||||||
RcCommons.CalcTileCount(bmin, bmax, CellSize, m_tileSize, m_tileSize, out tw, out th);
|
RcCommons.CalcTileCount(bmin, bmax, CellSize, m_tileSize, m_tileSize, out tw, out th);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Detour.TileCache.Io;
|
using DotRecast.Detour.TileCache.Io;
|
||||||
using DotRecast.Detour.TileCache.Io.Compress;
|
using DotRecast.Detour.TileCache.Io.Compress;
|
||||||
using DotRecast.Detour.TileCache.Test.Io;
|
using DotRecast.Detour.TileCache.Test.Io;
|
||||||
|
@ -29,11 +30,11 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache.Test;
|
namespace DotRecast.Detour.TileCache.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class TileCacheFindPathTest : AbstractTileCacheTest
|
public class TileCacheFindPathTest : AbstractTileCacheTest
|
||||||
{
|
{
|
||||||
private readonly RcVec3f start = new RcVec3f(39.44734f, 9.998177f, -0.784811f);
|
private readonly Vector3 start = new Vector3(39.44734f, 9.998177f, -0.784811f);
|
||||||
private readonly RcVec3f end = new RcVec3f(19.292645f, 11.611748f, -57.750366f);
|
private readonly Vector3 end = new Vector3(19.292645f, 11.611748f, -57.750366f);
|
||||||
private readonly DtNavMesh navmesh;
|
private readonly DtNavMesh navmesh;
|
||||||
private readonly DtNavMeshQuery query;
|
private readonly DtNavMeshQuery query;
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ public class TileCacheFindPathTest : AbstractTileCacheTest
|
||||||
public void TestFindPath()
|
public void TestFindPath()
|
||||||
{
|
{
|
||||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||||
RcVec3f extents = new RcVec3f(2f, 4f, 2f);
|
Vector3 extents = new Vector3(2f, 4f, 2f);
|
||||||
query.FindNearestPoly(start, extents, filter, out var startRef, out var startPos, out var _);
|
query.FindNearestPoly(start, extents, filter, out var startRef, out var startPos, out var _);
|
||||||
query.FindNearestPoly(end, extents, filter, out var endRef, out var endPos, out var _);
|
query.FindNearestPoly(end, extents, filter, out var endRef, out var endPos, out var _);
|
||||||
|
|
||||||
|
|
|
@ -21,18 +21,19 @@ freely, subject to the following restrictions:
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache.Test;
|
namespace DotRecast.Detour.TileCache.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class TileCacheNavigationTest : AbstractTileCacheTest
|
public class TileCacheNavigationTest : AbstractTileCacheTest
|
||||||
{
|
{
|
||||||
protected readonly long[] startRefs = { 281475006070787L };
|
protected readonly long[] startRefs = { 281475006070787L };
|
||||||
protected readonly long[] endRefs = { 281474986147841L };
|
protected readonly long[] endRefs = { 281474986147841L };
|
||||||
protected readonly RcVec3f[] startPoss = { new RcVec3f(39.447338f, 9.998177f, -0.784811f) };
|
protected readonly Vector3[] startPoss = { new Vector3(39.447338f, 9.998177f, -0.784811f) };
|
||||||
protected readonly RcVec3f[] endPoss = { new RcVec3f(19.292645f, 11.611748f, -57.750366f) };
|
protected readonly Vector3[] endPoss = { new Vector3(19.292645f, 11.611748f, -57.750366f) };
|
||||||
private readonly DtStatus[] statuses = { DtStatus.DT_SUCCESS };
|
private readonly DtStatus[] statuses = { DtStatus.DT_SUCCESS };
|
||||||
|
|
||||||
private readonly long[][] results =
|
private readonly long[][] results =
|
||||||
|
@ -88,8 +89,8 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
|
||||||
{
|
{
|
||||||
long startRef = startRefs[i];
|
long startRef = startRefs[i];
|
||||||
long endRef = endRefs[i];
|
long endRef = endRefs[i];
|
||||||
RcVec3f startPos = startPoss[i];
|
Vector3 startPos = startPoss[i];
|
||||||
RcVec3f endPos = endPoss[i];
|
Vector3 endPos = endPoss[i];
|
||||||
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
|
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
|
||||||
Assert.That(status, Is.EqualTo(statuses[i]));
|
Assert.That(status, Is.EqualTo(statuses[i]));
|
||||||
Assert.That(path.Count, Is.EqualTo(results[i].Length));
|
Assert.That(path.Count, Is.EqualTo(results[i].Length));
|
||||||
|
@ -109,8 +110,8 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
|
||||||
{
|
{
|
||||||
long startRef = startRefs[i];
|
long startRef = startRefs[i];
|
||||||
long endRef = endRefs[i];
|
long endRef = endRefs[i];
|
||||||
RcVec3f startPos = startPoss[i];
|
Vector3 startPos = startPoss[i];
|
||||||
RcVec3f endPos = endPoss[i];
|
Vector3 endPos = endPoss[i];
|
||||||
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.ZeroScale);
|
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.ZeroScale);
|
||||||
Assert.That(status, Is.EqualTo(statuses[i]));
|
Assert.That(status, Is.EqualTo(statuses[i]));
|
||||||
Assert.That(path.Count, Is.EqualTo(results[i].Length));
|
Assert.That(path.Count, Is.EqualTo(results[i].Length));
|
||||||
|
|
|
@ -26,7 +26,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.TileCache.Test;
|
namespace DotRecast.Detour.TileCache.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class TileCacheTest : AbstractTileCacheTest
|
public class TileCacheTest : AbstractTileCacheTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageReference Include="Moq" Version="4.20.70" />
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
<PackageReference Include="NUnit" Version="4.0.1" />
|
<PackageReference Include="NUnit" Version="4.0.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="4.0.1">
|
<PackageReference Include="NUnit.Analyzers" Version="3.10.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.1">
|
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
@ -19,6 +19,7 @@ freely, subject to the following restrictions:
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ namespace DotRecast.Recast.Test;
|
||||||
|
|
||||||
using static RcConstants;
|
using static RcConstants;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class RecastLayersTest
|
public class RecastLayersTest
|
||||||
{
|
{
|
||||||
private const float m_cellSize = 0.3f;
|
private const float m_cellSize = 0.3f;
|
||||||
|
|
|
@ -20,6 +20,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
using System.Numerics;
|
||||||
using DotRecast.Recast.Geom;
|
using DotRecast.Recast.Geom;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ namespace DotRecast.Recast.Test;
|
||||||
using static RcConstants;
|
using static RcConstants;
|
||||||
using static RcAreas;
|
using static RcAreas;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class RecastSoloMeshTest
|
public class RecastSoloMeshTest
|
||||||
{
|
{
|
||||||
private const float m_cellSize = 0.3f;
|
private const float m_cellSize = 0.3f;
|
||||||
|
@ -99,9 +100,9 @@ public class RecastSoloMeshTest
|
||||||
m_partitionType = partitionType;
|
m_partitionType = partitionType;
|
||||||
IInputGeomProvider geomProvider = SimpleInputGeomProvider.LoadFile(filename);
|
IInputGeomProvider geomProvider = SimpleInputGeomProvider.LoadFile(filename);
|
||||||
long time = RcFrequency.Ticks;
|
long time = RcFrequency.Ticks;
|
||||||
RcVec3f bmin = geomProvider.GetMeshBoundsMin();
|
Vector3 bmin = geomProvider.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geomProvider.GetMeshBoundsMax();
|
Vector3 bmax = geomProvider.GetMeshBoundsMax();
|
||||||
RcContext m_ctx = new RcContext();
|
RcTelemetry m_ctx = new RcTelemetry();
|
||||||
//
|
//
|
||||||
// Step 1. Initialize build config.
|
// Step 1. Initialize build config.
|
||||||
//
|
//
|
||||||
|
@ -140,7 +141,7 @@ public class RecastSoloMeshTest
|
||||||
// If your input data is multiple meshes, you can transform them here, calculate
|
// If your input data is multiple meshes, you can transform them here, calculate
|
||||||
// the are type for each of the meshes and rasterize them.
|
// 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 = RcCommons.MarkWalkableTriangles(m_ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
|
||||||
RcRasterizations.RasterizeTriangles(m_ctx, verts, tris, m_triareas, ntris, m_solid, cfg.WalkableClimb);
|
RcRasterizations.RasterizeTriangles(m_solid, verts, tris, m_triareas, ntris, cfg.WalkableClimb, m_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace DotRecast.Recast.Test;
|
||||||
|
|
||||||
using static RcConstants;
|
using static RcConstants;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class RecastTest
|
public class RecastTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -36,7 +36,7 @@ public class RecastTest
|
||||||
int[] unwalkable_tri = { 0, 2, 1 };
|
int[] unwalkable_tri = { 0, 2, 1 };
|
||||||
int nt = 1;
|
int nt = 1;
|
||||||
|
|
||||||
RcContext ctx = new RcContext();
|
RcTelemetry ctx = new RcTelemetry();
|
||||||
{
|
{
|
||||||
int[] areas = { 42 };
|
int[] areas = { 42 };
|
||||||
RcCommons.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas);
|
RcCommons.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas);
|
||||||
|
|
|
@ -27,7 +27,7 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Test;
|
namespace DotRecast.Recast.Test;
|
||||||
|
|
||||||
|
[Parallelizable]
|
||||||
public class RecastTileMeshTest
|
public class RecastTileMeshTest
|
||||||
{
|
{
|
||||||
private const float m_cellSize = 0.3f;
|
private const float m_cellSize = 0.3f;
|
||||||
|
|
Loading…
Reference in New Issue