mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 23:23:52 +00:00
Merge remote-tracking branch 'remotes/origin/master' into openmw-vr
This commit is contained in:
commit
d598923421
140 changed files with 1286 additions and 31063 deletions
12
.gitignore
vendored
12
.gitignore
vendored
|
@ -5,7 +5,7 @@ CMakeCache.txt
|
||||||
cmake_install.cmake
|
cmake_install.cmake
|
||||||
Makefile
|
Makefile
|
||||||
makefile
|
makefile
|
||||||
build*
|
build*/
|
||||||
prebuilt
|
prebuilt
|
||||||
|
|
||||||
##windows build process
|
##windows build process
|
||||||
|
@ -85,13 +85,3 @@ moc_*.cxx
|
||||||
*.[ao]
|
*.[ao]
|
||||||
*.so
|
*.so
|
||||||
venv/
|
venv/
|
||||||
|
|
||||||
## recastnavigation unused files
|
|
||||||
extern/recastnavigation/.travis.yml
|
|
||||||
extern/recastnavigation/CONTRIBUTING.md
|
|
||||||
extern/recastnavigation/Docs/
|
|
||||||
extern/recastnavigation/Doxyfile
|
|
||||||
extern/recastnavigation/README.md
|
|
||||||
extern/recastnavigation/RecastDemo/
|
|
||||||
extern/recastnavigation/Tests/
|
|
||||||
extern/recastnavigation/appveyor.yml
|
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
|
# Note: We set `needs` on each job to control the job DAG.
|
||||||
|
# See https://docs.gitlab.com/ee/ci/yaml/#needs
|
||||||
stages:
|
stages:
|
||||||
- build
|
- build
|
||||||
|
|
||||||
.Debian:
|
.Debian_Image:
|
||||||
tags:
|
tags:
|
||||||
- docker
|
- docker
|
||||||
- linux
|
- linux
|
||||||
image: debian:bullseye
|
image: debian:bullseye
|
||||||
|
|
||||||
|
.Debian:
|
||||||
|
extends: .Debian_Image
|
||||||
cache:
|
cache:
|
||||||
paths:
|
paths:
|
||||||
- apt-cache/
|
- apt-cache/
|
||||||
- ccache/
|
- ccache/
|
||||||
before_script:
|
|
||||||
- export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR
|
|
||||||
- apt-get update -yq
|
|
||||||
- apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake build-essential libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-iostreams-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev libsdl2-dev libqt5opengl5-dev libopenal-dev libopenscenegraph-dev libunshield-dev libtinyxml-dev libmygui-dev libbullet-dev liblz4-dev ccache git clang libxcb-glx0-dev libx11-dev
|
|
||||||
stage: build
|
stage: build
|
||||||
script:
|
script:
|
||||||
- export CCACHE_BASEDIR="`pwd`"
|
- export CCACHE_BASEDIR="`pwd`"
|
||||||
|
@ -33,6 +34,8 @@ Debian_GCC:
|
||||||
extends: .Debian
|
extends: .Debian
|
||||||
cache:
|
cache:
|
||||||
key: Debian_GCC.v2
|
key: Debian_GCC.v2
|
||||||
|
before_script:
|
||||||
|
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic
|
||||||
variables:
|
variables:
|
||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
|
@ -41,31 +44,52 @@ Debian_GCC:
|
||||||
timeout: 2h
|
timeout: 2h
|
||||||
|
|
||||||
Debian_GCC_tests:
|
Debian_GCC_tests:
|
||||||
extends: .Debian
|
extends: Debian_GCC
|
||||||
cache:
|
cache:
|
||||||
key: Debian_GCC_tests.v2
|
key: Debian_GCC_tests.v2
|
||||||
variables:
|
variables:
|
||||||
CC: gcc
|
CCACHE_SIZE: 1G
|
||||||
CXX: g++
|
BUILD_TESTS_ONLY: 1
|
||||||
|
|
||||||
|
Debian_GCC_Static_Deps:
|
||||||
|
extends: Debian_GCC
|
||||||
|
cache:
|
||||||
|
key: Debian_GCC_Static_Deps
|
||||||
|
paths:
|
||||||
|
- apt-cache/
|
||||||
|
- ccache/
|
||||||
|
- build/extern/fetched/
|
||||||
|
before_script:
|
||||||
|
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-static
|
||||||
|
variables:
|
||||||
|
CI_OPENMW_USE_STATIC_DEPS: 1
|
||||||
|
|
||||||
|
Debian_GCC_Static_Deps_tests:
|
||||||
|
extends: Debian_GCC_Static_Deps
|
||||||
|
cache:
|
||||||
|
key: Debian_GCC_Static_Deps_tests
|
||||||
|
variables:
|
||||||
CCACHE_SIZE: 1G
|
CCACHE_SIZE: 1G
|
||||||
BUILD_TESTS_ONLY: 1
|
BUILD_TESTS_ONLY: 1
|
||||||
|
|
||||||
Debian_Clang:
|
Debian_Clang:
|
||||||
extends: .Debian
|
extends: .Debian
|
||||||
|
before_script:
|
||||||
|
- CI/install_debian_deps.sh clang openmw-deps openmw-deps-dynamic
|
||||||
cache:
|
cache:
|
||||||
key: Debian_Clang.v2
|
key: Debian_Clang.v2
|
||||||
variables:
|
variables:
|
||||||
CC: clang
|
CC: clang
|
||||||
CXX: clang++
|
CXX: clang++
|
||||||
CCACHE_SIZE: 2G
|
CCACHE_SIZE: 2G
|
||||||
|
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||||
|
timeout: 2h
|
||||||
|
|
||||||
Debian_Clang_tests:
|
Debian_Clang_tests:
|
||||||
extends: .Debian
|
extends: Debian_Clang
|
||||||
cache:
|
cache:
|
||||||
key: Debian_Clang_tests.v2
|
key: Debian_Clang_tests.v2
|
||||||
variables:
|
variables:
|
||||||
CC: clang
|
|
||||||
CXX: clang++
|
|
||||||
CCACHE_SIZE: 1G
|
CCACHE_SIZE: 1G
|
||||||
BUILD_TESTS_ONLY: 1
|
BUILD_TESTS_ONLY: 1
|
||||||
|
|
||||||
|
@ -89,9 +113,11 @@ MacOS:
|
||||||
|
|
||||||
variables: &engine-targets
|
variables: &engine-targets
|
||||||
targets: "openmw_vr,openmw-essimporter,openmw-iniimporter,openmw-launcher,openmw-wizard"
|
targets: "openmw_vr,openmw-essimporter,openmw-iniimporter,openmw-launcher,openmw-wizard"
|
||||||
|
package: "Engine"
|
||||||
|
|
||||||
variables: &cs-targets
|
variables: &cs-targets
|
||||||
targets: "openmw-cs,bsatool,esmtool,niftest"
|
targets: "openmw-cs,bsatool,esmtool,niftest"
|
||||||
|
package: "CS"
|
||||||
|
|
||||||
#.Windows_Ninja_Base:
|
#.Windows_Ninja_Base:
|
||||||
# tags:
|
# tags:
|
||||||
|
@ -116,12 +142,13 @@ variables: &cs-targets
|
||||||
# - .\ActivateMSVC.ps1
|
# - .\ActivateMSVC.ps1
|
||||||
# - cmake --build . --config $config --target ($targets.Split(','))
|
# - cmake --build . --config $config --target ($targets.Split(','))
|
||||||
# - cd $config
|
# - cd $config
|
||||||
|
# - echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
||||||
# - |
|
# - |
|
||||||
# if (Get-ChildItem -Recurse *.pdb) {
|
# if (Get-ChildItem -Recurse *.pdb) {
|
||||||
# 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb'
|
# 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt
|
||||||
# Get-ChildItem -Recurse *.pdb | Remove-Item
|
# Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||||
# }
|
# }
|
||||||
# - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*'
|
# - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*'
|
||||||
# after_script:
|
# after_script:
|
||||||
# - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
# - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
||||||
# cache:
|
# cache:
|
||||||
|
@ -142,6 +169,7 @@ variables: &cs-targets
|
||||||
# - MSVC2019_64_Ninja/*/*/*/*/*/*.log
|
# - MSVC2019_64_Ninja/*/*/*/*/*/*.log
|
||||||
# - MSVC2019_64_Ninja/*/*/*/*/*/*/*.log
|
# - MSVC2019_64_Ninja/*/*/*/*/*/*/*.log
|
||||||
# - MSVC2019_64_Ninja/*/*/*/*/*/*/*/*.log
|
# - MSVC2019_64_Ninja/*/*/*/*/*/*/*/*.log
|
||||||
|
|
||||||
#
|
#
|
||||||
#Windows_Ninja_Engine_Release:
|
#Windows_Ninja_Engine_Release:
|
||||||
# extends:
|
# extends:
|
||||||
|
@ -206,12 +234,13 @@ variables: &cs-targets
|
||||||
- cd MSVC2019_64
|
- cd MSVC2019_64
|
||||||
- cmake --build . --config $config --target ($targets.Split(','))
|
- cmake --build . --config $config --target ($targets.Split(','))
|
||||||
- cd $config
|
- cd $config
|
||||||
|
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
||||||
- |
|
- |
|
||||||
if (Get-ChildItem -Recurse *.pdb) {
|
if (Get-ChildItem -Recurse *.pdb) {
|
||||||
7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb'
|
7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt
|
||||||
Get-ChildItem -Recurse *.pdb | Remove-Item
|
Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||||
}
|
}
|
||||||
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*'
|
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*'
|
||||||
after_script:
|
after_script:
|
||||||
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
||||||
cache:
|
cache:
|
||||||
|
@ -282,16 +311,17 @@ Windows_MSBuild_CS_RelWithDebInfo:
|
||||||
# variables:
|
# variables:
|
||||||
# CCACHE_SIZE: 3G
|
# CCACHE_SIZE: 3G
|
||||||
# cache:
|
# cache:
|
||||||
# key: Debian_AndroidNDK_arm64-v8a.v2
|
# key: Debian_AndroidNDK_arm64-v8a.v3
|
||||||
# paths:
|
# paths:
|
||||||
# - apt-cache/
|
# - apt-cache/
|
||||||
# - ccache/
|
# - ccache/
|
||||||
|
# - build/extern/fetched/
|
||||||
# before_script:
|
# before_script:
|
||||||
# - export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR
|
# - export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR
|
||||||
# - echo "deb http://deb.debian.org/debian unstable main contrib" > /etc/apt/sources.list
|
# - echo "deb http://deb.debian.org/debian unstable main contrib" > /etc/apt/sources.list
|
||||||
# - echo "google-android-ndk-installer google-android-installers/mirror select https://dl.google.com" | debconf-set-selections
|
# - echo "google-android-ndk-installer google-android-installers/mirror select https://dl.google.com" | debconf-set-selections
|
||||||
# - apt-get update -yq
|
# - apt-get update -yq
|
||||||
# - apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake ccache curl unzip git build-essential google-android-ndk-installer
|
# - apt-get -q -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake ccache curl unzip git build-essential google-android-ndk-installer
|
||||||
# stage: build
|
# stage: build
|
||||||
# script:
|
# script:
|
||||||
# - export CCACHE_BASEDIR="`pwd`"
|
# - export CCACHE_BASEDIR="`pwd`"
|
||||||
|
@ -306,3 +336,5 @@ Windows_MSBuild_CS_RelWithDebInfo:
|
||||||
# artifacts:
|
# artifacts:
|
||||||
# paths:
|
# paths:
|
||||||
# - build/install/
|
# - build/install/
|
||||||
|
# # When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||||
|
# timeout: 1h30m
|
||||||
|
|
|
@ -100,6 +100,10 @@
|
||||||
Bug #5821: NPCs from mods getting removed if mod order was changed
|
Bug #5821: NPCs from mods getting removed if mod order was changed
|
||||||
Bug #5835: OpenMW doesn't accept negative values for NPC's hello, alarm, fight, and flee
|
Bug #5835: OpenMW doesn't accept negative values for NPC's hello, alarm, fight, and flee
|
||||||
Bug #5836: OpenMW dialogue/greeting/voice filter doesn't accept negative Ai values for NPC's hello, alarm, fight, and flee
|
Bug #5836: OpenMW dialogue/greeting/voice filter doesn't accept negative Ai values for NPC's hello, alarm, fight, and flee
|
||||||
|
Bug #5838: Local map and other menus become blank in some locations while playing Wizards' Islands mod.
|
||||||
|
Bug #5840: GetSoundPlaying "Health Damage" doesn't play when NPC hits target with shield effect ( vanilla engine behavior )
|
||||||
|
Bug #5841: Can't Cast Zero Cost Spells When Magicka is < 0
|
||||||
|
Bug #5871: The console appears if you type the Russian letter "Ё" in the name of the enchantment
|
||||||
Feature #390: 3rd person look "over the shoulder"
|
Feature #390: 3rd person look "over the shoulder"
|
||||||
Feature #1536: Show more information about level on menu
|
Feature #1536: Show more information about level on menu
|
||||||
Feature #2386: Distant Statics in the form of Object Paging
|
Feature #2386: Distant Statics in the form of Object Paging
|
||||||
|
@ -107,6 +111,7 @@
|
||||||
Feature #2686: Timestamps in openmw.log
|
Feature #2686: Timestamps in openmw.log
|
||||||
Feature #3171: OpenMW-CS: Instance drag selection
|
Feature #3171: OpenMW-CS: Instance drag selection
|
||||||
Feature #4894: Consider actors as obstacles for pathfinding
|
Feature #4894: Consider actors as obstacles for pathfinding
|
||||||
|
Feature #4977: Use the "default icon.tga" when an item's icon is not found
|
||||||
Feature #5043: Head Bobbing
|
Feature #5043: Head Bobbing
|
||||||
Feature #5199: Improve Scene Colors
|
Feature #5199: Improve Scene Colors
|
||||||
Feature #5297: Add a search function to the "Datafiles" tab of the OpenMW launcher
|
Feature #5297: Add a search function to the "Datafiles" tab of the OpenMW launcher
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# hack to work around: FFmpeg version is too old, 3.2 is required
|
# hack to work around: FFmpeg version is too old, 3.2 is required
|
||||||
sed -i s/"NOT FFVER_OK"/"FALSE"/ CMakeLists.txt
|
sed -i s/"NOT FFVER_OK"/"FALSE"/ CMakeLists.txt
|
||||||
|
|
||||||
mkdir build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
cmake \
|
cmake \
|
||||||
|
@ -21,5 +21,7 @@ cmake \
|
||||||
-DBUILD_ESSIMPORTER=0 \
|
-DBUILD_ESSIMPORTER=0 \
|
||||||
-DBUILD_OPENCS=0 \
|
-DBUILD_OPENCS=0 \
|
||||||
-DBUILD_WIZARD=0 \
|
-DBUILD_WIZARD=0 \
|
||||||
-DMyGUI_LIBRARY="/usr/lib/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/libMyGUIEngineStatic.a" \
|
-DOPENMW_USE_SYSTEM_MYGUI=OFF \
|
||||||
|
-DOPENMW_USE_SYSTEM_OSG=OFF \
|
||||||
|
-DOPENMW_USE_SYSTEM_BULLET=OFF \
|
||||||
..
|
..
|
||||||
|
|
|
@ -1,44 +1,54 @@
|
||||||
#!/bin/bash -ex
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -xeo pipefail
|
||||||
|
|
||||||
free -m
|
free -m
|
||||||
|
|
||||||
if [[ "${BUILD_TESTS_ONLY}" ]]; then
|
if [[ "${BUILD_TESTS_ONLY}" ]]; then
|
||||||
export GOOGLETEST_DIR="$(pwd)/googletest/build/install"
|
export GOOGLETEST_DIR="${PWD}/googletest/build/install"
|
||||||
env GENERATOR='Unix Makefiles' CONFIGURATION=Release CI/build_googletest.sh
|
env GENERATOR='Unix Makefiles' CONFIGURATION=Release CI/build_googletest.sh
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir build
|
declare -a CMAKE_CONF_OPTS=(
|
||||||
|
-DCMAKE_C_COMPILER="${CC:-/usr/bin/cc}"
|
||||||
|
-DCMAKE_CXX_COMPILER="${CXX:-/usr/bin/c++}"
|
||||||
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
-DCMAKE_INSTALL_PREFIX=install
|
||||||
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
|
-DBUILD_SHARED_LIBS=OFF
|
||||||
|
-DUSE_SYSTEM_TINYXML=ON
|
||||||
|
-DCMAKE_INSTALL_PREFIX=install
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ $CI_OPENMW_USE_STATIC_DEPS ]]; then
|
||||||
|
CMAKE_CONF_OPTS+=(
|
||||||
|
-DOPENMW_USE_SYSTEM_MYGUI=OFF
|
||||||
|
-DOPENMW_USE_SYSTEM_OSG=OFF
|
||||||
|
-DOPENMW_USE_SYSTEM_BULLET=OFF
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
if [[ "${BUILD_TESTS_ONLY}" ]]; then
|
if [[ "${BUILD_TESTS_ONLY}" ]]; then
|
||||||
${ANALYZE} cmake \
|
${ANALYZE} cmake \
|
||||||
-D CMAKE_C_COMPILER="${CC}" \
|
"${CMAKE_CONF_OPTS[@]}" \
|
||||||
-D CMAKE_CXX_COMPILER="${CXX}" \
|
-DBUILD_OPENMW=OFF \
|
||||||
-D CMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DBUILD_BSATOOL=OFF \
|
||||||
-D CMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DBUILD_ESMTOOL=OFF \
|
||||||
-D CMAKE_INSTALL_PREFIX=install \
|
-DBUILD_LAUNCHER=OFF \
|
||||||
-D CMAKE_BUILD_TYPE=RelWithDebInfo \
|
-DBUILD_MWINIIMPORTER=OFF \
|
||||||
-D USE_SYSTEM_TINYXML=TRUE \
|
-DBUILD_ESSIMPORTER=OFF \
|
||||||
-D BUILD_OPENMW=OFF \
|
-DBUILD_OPENCS=OFF \
|
||||||
-D BUILD_BSATOOL=OFF \
|
-DBUILD_WIZARD=OFF \
|
||||||
-D BUILD_ESMTOOL=OFF \
|
-DBUILD_UNITTESTS=ON \
|
||||||
-D BUILD_LAUNCHER=OFF \
|
-DGTEST_ROOT="${GOOGLETEST_DIR}" \
|
||||||
-D BUILD_MWINIIMPORTER=OFF \
|
-DGMOCK_ROOT="${GOOGLETEST_DIR}" \
|
||||||
-D BUILD_ESSIMPORTER=OFF \
|
|
||||||
-D BUILD_OPENCS=OFF \
|
|
||||||
-D BUILD_WIZARD=OFF \
|
|
||||||
-D BUILD_UNITTESTS=ON \
|
|
||||||
-D GTEST_ROOT="${GOOGLETEST_DIR}" \
|
|
||||||
-D GMOCK_ROOT="${GOOGLETEST_DIR}" \
|
|
||||||
..
|
..
|
||||||
else
|
else
|
||||||
${ANALYZE} cmake \
|
${ANALYZE} cmake \
|
||||||
-D CMAKE_C_COMPILER="${CC}" \
|
"${CMAKE_CONF_OPTS[@]}" \
|
||||||
-D CMAKE_CXX_COMPILER="${CXX}" \
|
|
||||||
-D CMAKE_C_COMPILER_LAUNCHER=ccache \
|
|
||||||
-D CMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
|
||||||
-D USE_SYSTEM_TINYXML=TRUE \
|
|
||||||
-D CMAKE_INSTALL_PREFIX=install \
|
|
||||||
-D CMAKE_BUILD_TYPE=Debug \
|
|
||||||
..
|
..
|
||||||
fi
|
fi
|
||||||
|
|
64
CI/install_debian_deps.sh
Executable file
64
CI/install_debian_deps.sh
Executable file
|
@ -0,0 +1,64 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
print_help() {
|
||||||
|
echo "usage: $0 [group]..."
|
||||||
|
echo
|
||||||
|
echo " available groups: "${!GROUPED_DEPS[@]}""
|
||||||
|
}
|
||||||
|
|
||||||
|
declare -rA GROUPED_DEPS=(
|
||||||
|
[gcc]="binutils gcc g++ libc-dev"
|
||||||
|
[clang]="binutils clang"
|
||||||
|
|
||||||
|
# Common dependencies for building OpenMW.
|
||||||
|
[openmw-deps]="
|
||||||
|
make cmake ccache git pkg-config
|
||||||
|
|
||||||
|
libboost-filesystem-dev libboost-program-options-dev
|
||||||
|
libboost-system-dev libboost-iostreams-dev
|
||||||
|
|
||||||
|
libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev
|
||||||
|
libsdl2-dev libqt5opengl5-dev libopenal-dev libunshield-dev libtinyxml-dev
|
||||||
|
libbullet-dev liblz4-dev libpng-dev libjpeg-dev
|
||||||
|
"
|
||||||
|
|
||||||
|
# These dependencies can alternatively be built and linked statically.
|
||||||
|
[openmw-deps-dynamic]="libmygui-dev libopenscenegraph-dev"
|
||||||
|
|
||||||
|
# Pre-requisites for building MyGUI and OSG for static linking.
|
||||||
|
#
|
||||||
|
# * MyGUI and OSG: libsdl2-dev liblz4-dev libfreetype6-dev
|
||||||
|
# * OSG: libgl-dev
|
||||||
|
#
|
||||||
|
# Plugins:
|
||||||
|
# * DAE: libcollada-dom-dev libboost-system-dev libboost-filesystem-dev
|
||||||
|
# * JPEG: libjpeg-dev
|
||||||
|
# * PNG: libpng-dev
|
||||||
|
[openmw-deps-static]="
|
||||||
|
make cmake
|
||||||
|
ccache curl unzip libcollada-dom-dev libfreetype6-dev libjpeg-dev libpng-dev
|
||||||
|
libsdl2-dev libboost-system-dev libboost-filesystem-dev libgl-dev
|
||||||
|
"
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
>&2 print_help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
deps=()
|
||||||
|
for group in "$@"; do
|
||||||
|
if [[ ! -v GROUPED_DEPS[$group] ]]; then
|
||||||
|
>&2 echo "error: unknown group ${group}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
deps+=(${GROUPED_DEPS[$group]})
|
||||||
|
done
|
||||||
|
|
||||||
|
export APT_CACHE_DIR="${PWD}/apt-cache"
|
||||||
|
set -x
|
||||||
|
mkdir -pv "$APT_CACHE_DIR"
|
||||||
|
apt-get update -yq
|
||||||
|
apt-get -q -o dir::cache::archives="$APT_CACHE_DIR" install -y "${deps[@]}"
|
130
CMakeLists.txt
130
CMakeLists.txt
|
@ -3,14 +3,19 @@ cmake_minimum_required(VERSION 3.1.0)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
# Detect OS
|
|
||||||
include(cmake/OSIdentity.cmake)
|
|
||||||
|
|
||||||
# for link time optimization, remove if cmake version is >= 3.9
|
# for link time optimization, remove if cmake version is >= 3.9
|
||||||
if(POLICY CMP0069)
|
if(POLICY CMP0069) # LTO
|
||||||
cmake_policy(SET CMP0069 NEW)
|
cmake_policy(SET CMP0069 NEW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# for position-independent executable, remove if cmake version is >= 3.14
|
||||||
|
if(POLICY CMP0083)
|
||||||
|
cmake_policy(SET CMP0083 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Detect OS
|
||||||
|
include(cmake/OSIdentity.cmake)
|
||||||
|
|
||||||
# Apps and tools
|
# Apps and tools
|
||||||
option(BUILD_OPENMW "Build OpenMW" ON)
|
option(BUILD_OPENMW "Build OpenMW" ON)
|
||||||
option(BUILD_LAUNCHER "Build Launcher" ON)
|
option(BUILD_LAUNCHER "Build Launcher" ON)
|
||||||
|
@ -53,7 +58,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}")
|
set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}")
|
||||||
set (OSG_PLUGINS_DIR CACHE STRING "")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
|
@ -96,17 +100,42 @@ endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||||
|
|
||||||
# Macros
|
# Macros
|
||||||
include(OpenMWMacros)
|
include(OpenMWMacros)
|
||||||
|
include(WholeArchive)
|
||||||
|
|
||||||
# doxygen main page
|
# doxygen main page
|
||||||
|
|
||||||
configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp")
|
configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp")
|
||||||
|
|
||||||
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
|
|
||||||
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
||||||
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
|
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
|
||||||
option(OSG_STATIC "Link static build of OpenSceneGraph into the binaries" FALSE)
|
|
||||||
option(QT_STATIC "Link static build of QT into the binaries" FALSE)
|
option(QT_STATIC "Link static build of QT into the binaries" FALSE)
|
||||||
|
|
||||||
|
option(OPENMW_USE_SYSTEM_BULLET "Use system provided bullet physics library" ON)
|
||||||
|
|
||||||
|
option(OPENMW_USE_SYSTEM_OSG "Use system provided OpenSceneGraph libraries" ON)
|
||||||
|
if(OPENMW_USE_SYSTEM_OSG)
|
||||||
|
set(_osg_static_default OFF)
|
||||||
|
else()
|
||||||
|
set(_osg_static_default ON)
|
||||||
|
endif()
|
||||||
|
option(OSG_STATIC "Link static build of OpenSceneGraph into the binaries" ${_osg_static_default})
|
||||||
|
|
||||||
|
option(OPENMW_USE_SYSTEM_MYGUI "Use system provided mygui library" ON)
|
||||||
|
if(OPENMW_USE_SYSTEM_MYGUI)
|
||||||
|
set(_mygui_static_default OFF)
|
||||||
|
else()
|
||||||
|
set(_mygui_static_default ON)
|
||||||
|
endif()
|
||||||
|
option(MYGUI_STATIC "Link static build of Mygui into the binaries" ${_mygui_static_default})
|
||||||
|
|
||||||
|
option(OPENMW_USE_SYSTEM_RECASTNAVIGATION "Use system provided recastnavigation library" OFF)
|
||||||
|
if(OPENMW_USE_SYSTEM_RECASTNAVIGATION)
|
||||||
|
set(_recastnavigation_static_default OFF)
|
||||||
|
else()
|
||||||
|
set(_recastnavigation_static_default ON)
|
||||||
|
endif()
|
||||||
|
option(RECASTNAVIGATION_STATIC "Build recastnavigation static libraries" ${_recastnavigation_static_default})
|
||||||
|
|
||||||
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
|
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
|
||||||
option(OPENMW_LTO_BUILD "Build OpenMW with Link-Time Optimization (Needs ~2GB of RAM)" OFF)
|
option(OPENMW_LTO_BUILD "Build OpenMW with Link-Time Optimization (Needs ~2GB of RAM)" OFF)
|
||||||
|
|
||||||
|
@ -169,6 +198,28 @@ if (USE_QT)
|
||||||
#set(CMAKE_AUTOMOC ON)
|
#set(CMAKE_AUTOMOC ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(USED_OSG_COMPONENTS
|
||||||
|
osgDB
|
||||||
|
osgViewer
|
||||||
|
osgText
|
||||||
|
osgGA
|
||||||
|
osgParticle
|
||||||
|
osgUtil
|
||||||
|
osgFX
|
||||||
|
osgShadow
|
||||||
|
osgAnimation)
|
||||||
|
set(USED_OSG_PLUGINS
|
||||||
|
osgdb_bmp
|
||||||
|
osgdb_dds
|
||||||
|
osgdb_freetype
|
||||||
|
osgdb_jpeg
|
||||||
|
osgdb_osg
|
||||||
|
osgdb_png
|
||||||
|
osgdb_serializers_osg
|
||||||
|
osgdb_tga)
|
||||||
|
|
||||||
|
add_subdirectory(extern)
|
||||||
|
|
||||||
# Sound setup
|
# Sound setup
|
||||||
|
|
||||||
# Require at least ffmpeg 3.2 for now
|
# Require at least ffmpeg 3.2 for now
|
||||||
|
@ -244,6 +295,15 @@ if (WIN32)
|
||||||
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
|
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(OPENMW_USE_SYSTEM_BULLET)
|
||||||
|
set(REQUIRED_BULLET_VERSION 286) # Bullet 286 required due to runtime bugfixes for btCapsuleShape
|
||||||
|
if (DEFINED ENV{TRAVIS_BRANCH} OR DEFINED ENV{APPVEYOR})
|
||||||
|
set(REQUIRED_BULLET_VERSION 283) # but for build testing, 283 is fine
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(Bullet ${REQUIRED_BULLET_VERSION} REQUIRED COMPONENTS BulletCollision LinearMath)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT WIN32 AND BUILD_WIZARD) # windows users can just run the morrowind installer
|
if (NOT WIN32 AND BUILD_WIZARD) # windows users can just run the morrowind installer
|
||||||
find_package(LIBUNSHIELD REQUIRED) # required only for non win32 when building openmw-wizard
|
find_package(LIBUNSHIELD REQUIRED) # required only for non win32 when building openmw-wizard
|
||||||
set(OPENMW_USE_UNSHIELD TRUE)
|
set(OPENMW_USE_UNSHIELD TRUE)
|
||||||
|
@ -262,38 +322,23 @@ if(NOT HAVE_STDINT_H)
|
||||||
message(FATAL_ERROR "stdint.h was not found" )
|
message(FATAL_ERROR "stdint.h was not found" )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
set(OSG_VERSION_REQUIRED "3.3.4")
|
set(OSG_VERSION_REQUIRED "3.3.4")
|
||||||
if(BUILD_OPENMW_VR)
|
if(BUILD_OPENMW_VR)
|
||||||
set(OSG_VERSION_REQUIRED "3.6.5")
|
set(OSG_VERSION_REQUIRED "3.6.5")
|
||||||
endif()
|
endif()
|
||||||
find_package(OpenSceneGraph ${OSG_VERSION_REQUIRED} REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX osgShadow osgAnimation)
|
|
||||||
include_directories(SYSTEM ${OPENSCENEGRAPH_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
set(USED_OSG_PLUGINS
|
if(OPENMW_USE_SYSTEM_OSG)
|
||||||
osgdb_bmp
|
find_package(OpenSceneGraph ${OSG_VERSION_REQUIRED} REQUIRED ${USED_OSG_COMPONENTS})
|
||||||
osgdb_dds
|
if(OSG_STATIC)
|
||||||
osgdb_freetype
|
find_package(OSGPlugins REQUIRED COMPONENTS ${USED_OSG_PLUGINS})
|
||||||
osgdb_jpeg
|
|
||||||
osgdb_osg
|
|
||||||
osgdb_png
|
|
||||||
osgdb_serializers_osg
|
|
||||||
osgdb_tga
|
|
||||||
)
|
|
||||||
|
|
||||||
set(OSGPlugins_LIB_DIR "")
|
|
||||||
foreach(OSGDB_LIB ${OSGDB_LIBRARY})
|
|
||||||
# Skip library type names
|
|
||||||
if(EXISTS ${OSGDB_LIB} AND NOT IS_DIRECTORY ${OSGDB_LIB})
|
|
||||||
get_filename_component(OSG_LIB_DIR ${OSGDB_LIB} DIRECTORY)
|
|
||||||
list(APPEND OSGPlugins_LIB_DIR "${OSG_LIB_DIR}/osgPlugins-${OPENSCENEGRAPH_VERSION}")
|
|
||||||
endif()
|
endif()
|
||||||
endforeach(OSGDB_LIB)
|
endif()
|
||||||
|
|
||||||
|
include_directories(BEFORE SYSTEM ${OPENSCENEGRAPH_INCLUDE_DIRS})
|
||||||
|
|
||||||
if(OSG_STATIC)
|
if(OSG_STATIC)
|
||||||
add_definitions(-DOSG_LIBRARY_STATIC)
|
add_definitions(-DOSG_LIBRARY_STATIC)
|
||||||
|
|
||||||
find_package(OSGPlugins REQUIRED COMPONENTS ${USED_OSG_PLUGINS})
|
|
||||||
list(APPEND OPENSCENEGRAPH_LIBRARIES ${OSGPlugins_LIBRARIES})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(BOOST_COMPONENTS system filesystem program_options iostreams)
|
set(BOOST_COMPONENTS system filesystem program_options iostreams)
|
||||||
|
@ -308,21 +353,18 @@ IF(BOOST_STATIC)
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(REQUIRED_BULLET_VERSION 286) # Bullet 286 required due to runtime bugfixes for btCapsuleShape
|
|
||||||
if (DEFINED ENV{TRAVIS_BRANCH} OR DEFINED ENV{APPVEYOR})
|
|
||||||
set(REQUIRED_BULLET_VERSION 283) # but for build testing, 283 is fine
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(Boost_NO_BOOST_CMAKE ON)
|
set(Boost_NO_BOOST_CMAKE ON)
|
||||||
|
|
||||||
find_package(Boost 1.6.2 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
find_package(Boost 1.6.2 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||||
find_package(MyGUI 3.2.2 REQUIRED)
|
if(OPENMW_USE_SYSTEM_MYGUI)
|
||||||
|
find_package(MyGUI 3.2.2 REQUIRED)
|
||||||
|
endif()
|
||||||
find_package(SDL2 2.0.9 REQUIRED)
|
find_package(SDL2 2.0.9 REQUIRED)
|
||||||
find_package(OpenAL REQUIRED)
|
find_package(OpenAL REQUIRED)
|
||||||
find_package(Bullet ${REQUIRED_BULLET_VERSION} REQUIRED COMPONENTS BulletCollision LinearMath)
|
|
||||||
|
|
||||||
include_directories("."
|
include_directories(
|
||||||
SYSTEM
|
BEFORE SYSTEM
|
||||||
|
"."
|
||||||
${SDL2_INCLUDE_DIR}
|
${SDL2_INCLUDE_DIR}
|
||||||
${Boost_INCLUDE_DIR}
|
${Boost_INCLUDE_DIR}
|
||||||
${MyGUI_INCLUDE_DIRS}
|
${MyGUI_INCLUDE_DIRS}
|
||||||
|
@ -447,14 +489,10 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 5.0)
|
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 5.0)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override")
|
||||||
endif()
|
endif()
|
||||||
elseif (MSVC)
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /FORCE:MULTIPLE")
|
|
||||||
endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||||
|
|
||||||
# Extern
|
# Extern
|
||||||
set(RECASTNAVIGATION_STATIC ON CACHE BOOL "Build recastnavigation static libraries")
|
|
||||||
|
|
||||||
add_subdirectory (extern/recastnavigation EXCLUDE_FROM_ALL)
|
|
||||||
add_subdirectory (extern/osg-ffmpeg-videoplayer)
|
add_subdirectory (extern/osg-ffmpeg-videoplayer)
|
||||||
add_subdirectory (extern/oics)
|
add_subdirectory (extern/oics)
|
||||||
if (BUILD_OPENCS)
|
if (BUILD_OPENCS)
|
||||||
|
@ -881,11 +919,7 @@ elseif(NOT APPLE)
|
||||||
|
|
||||||
# Install binaries
|
# Install binaries
|
||||||
IF(BUILD_OPENMW)
|
IF(BUILD_OPENMW)
|
||||||
IF(ANDROID)
|
INSTALL(PROGRAMS "$<TARGET_FILE:openmw>" DESTINATION "${BINDIR}" )
|
||||||
INSTALL(PROGRAMS "${INSTALL_SOURCE}/libopenmw.so" DESTINATION "${BINDIR}" )
|
|
||||||
ELSE(ANDROID)
|
|
||||||
INSTALL(PROGRAMS "${INSTALL_SOURCE}/openmw" DESTINATION "${BINDIR}" )
|
|
||||||
ENDIF(ANDROID)
|
|
||||||
ENDIF(BUILD_OPENMW)
|
ENDIF(BUILD_OPENMW)
|
||||||
IF(BUILD_LAUNCHER)
|
IF(BUILD_LAUNCHER)
|
||||||
INSTALL(PROGRAMS "${INSTALL_SOURCE}/openmw-launcher" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${INSTALL_SOURCE}/openmw-launcher" DESTINATION "${BINDIR}" )
|
||||||
|
|
|
@ -228,6 +228,24 @@ target_link_libraries(openmw-cs
|
||||||
components
|
components
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(OSG_STATIC)
|
||||||
|
unset(_osg_plugins_static_files)
|
||||||
|
add_library(openmw_cs_osg_plugins INTERFACE)
|
||||||
|
foreach(_plugin ${USED_OSG_PLUGINS})
|
||||||
|
string(TOUPPER ${_plugin} _plugin_uc)
|
||||||
|
if (${_plugin_uc}_LIBRARY MATCHES "[/.]")
|
||||||
|
list(APPEND _osg_plugins_static_files ${${_plugin_uc}_LIBRARY})
|
||||||
|
else()
|
||||||
|
list(APPEND _osg_plugins_static_files $<TARGET_FILE:${${_plugin_uc}_LIBRARY}>)
|
||||||
|
endif()
|
||||||
|
target_link_libraries(openmw_cs_osg_plugins INTERFACE ${${_plugin_uc}_LIBRARY})
|
||||||
|
endforeach()
|
||||||
|
# We use --whole-archive because OSG plugins use registration.
|
||||||
|
get_whole_archive_options(_opts ${_osg_plugins_static_files})
|
||||||
|
target_link_options(openmw_cs_osg_plugins INTERFACE ${_opts})
|
||||||
|
target_link_libraries(openmw-cs openmw_cs_osg_plugins)
|
||||||
|
endif(OSG_STATIC)
|
||||||
|
|
||||||
target_link_libraries(openmw-cs Qt5::Widgets Qt5::Core Qt5::Network Qt5::OpenGL)
|
target_link_libraries(openmw-cs Qt5::Widgets Qt5::Core Qt5::Network Qt5::OpenGL)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|
|
@ -133,28 +133,28 @@ if (NOT UNIX)
|
||||||
${SDL2MAIN_LIBRARY})
|
${SDL2MAIN_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ANDROID)
|
if(OSG_STATIC)
|
||||||
set (OSG_PLUGINS
|
unset(_osg_plugins_static_files)
|
||||||
-Wl,--whole-archive
|
add_library(openmw_osg_plugins INTERFACE)
|
||||||
)
|
foreach(_plugin ${USED_OSG_PLUGINS})
|
||||||
foreach(PLUGIN_NAME ${USED_OSG_PLUGINS})
|
string(TOUPPER ${_plugin} _plugin_uc)
|
||||||
set(OSG_PLUGINS ${OSG_PLUGINS} ${OSG_PLUGINS_DIR}/lib${PLUGIN_NAME}.a)
|
if (${_plugin_uc}_LIBRARY MATCHES "[/.]")
|
||||||
|
list(APPEND _osg_plugins_static_files ${${_plugin_uc}_LIBRARY})
|
||||||
|
else()
|
||||||
|
list(APPEND _osg_plugins_static_files $<TARGET_FILE:${${_plugin_uc}_LIBRARY}>)
|
||||||
|
endif()
|
||||||
|
target_link_libraries(openmw_osg_plugins INTERFACE ${${_plugin_uc}_LIBRARY})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
# We use --whole-archive because OSG plugins use registration.
|
||||||
set (OSG_PLUGINS
|
get_whole_archive_options(_opts ${_osg_plugins_static_files})
|
||||||
${OSG_PLUGINS} -Wl,--no-whole-archive
|
target_link_options(openmw_osg_plugins INTERFACE ${_opts})
|
||||||
)
|
|
||||||
set(OPENMW_LINK_TARGETS ${OPENMW_LINK_TARGETS}
|
set(OPENMW_LINK_TARGETS ${OPENMW_LINK_TARGETS}
|
||||||
EGL
|
openmw_osg_plugins)
|
||||||
android
|
endif(OSG_STATIC)
|
||||||
log
|
|
||||||
dl
|
if (ANDROID)
|
||||||
z
|
set(OPENMW_LINK_TARGETS ${OPENMW_LINK_TARGETS}
|
||||||
${OPENSCENEGRAPH_LIBRARIES}
|
EGL android log z)
|
||||||
freetype
|
|
||||||
jpeg
|
|
||||||
png
|
|
||||||
)
|
|
||||||
endif (ANDROID)
|
endif (ANDROID)
|
||||||
|
|
||||||
# Fix for not visible pthreads functions for linker with glibc 2.15
|
# Fix for not visible pthreads functions for linker with glibc 2.15
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
|
|
||||||
#include <components/detournavigator/navigator.hpp>
|
#include <components/detournavigator/navigator.hpp>
|
||||||
|
|
||||||
|
#include <components/misc/frameratelimiter.hpp>
|
||||||
|
|
||||||
#include "mwinput/inputmanagerimp.hpp"
|
#include "mwinput/inputmanagerimp.hpp"
|
||||||
|
|
||||||
#include "mwgui/windowmanagerimp.hpp"
|
#include "mwgui/windowmanagerimp.hpp"
|
||||||
|
@ -1031,13 +1033,15 @@ void OMW::Engine::go()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the main rendering loop
|
// Start the main rendering loop
|
||||||
osg::Timer frameTimer;
|
|
||||||
double simulationTime = 0.0;
|
double simulationTime = 0.0;
|
||||||
|
Misc::FrameRateLimiter frameRateLimiter = Misc::makeFrameRateLimiter(mEnvironment.getFrameRateLimit());
|
||||||
|
const std::chrono::steady_clock::duration maxSimulationInterval(std::chrono::milliseconds(200));
|
||||||
while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest())
|
while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest())
|
||||||
{
|
{
|
||||||
double dt = frameTimer.time_s();
|
const double dt = std::chrono::duration_cast<std::chrono::duration<double>>(std::min(
|
||||||
frameTimer.setStartTick();
|
frameRateLimiter.getLastFrameDuration(),
|
||||||
dt = std::min(dt, 0.2);
|
maxSimulationInterval
|
||||||
|
)).count();
|
||||||
|
|
||||||
mViewer->advance(simulationTime);
|
mViewer->advance(simulationTime);
|
||||||
|
|
||||||
|
@ -1068,7 +1072,7 @@ void OMW::Engine::go()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mEnvironment.limitFrameRate(frameTimer.time_s());
|
frameRateLimiter.limit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save user settings
|
// Save user settings
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#include "environment.hpp"
|
#include "environment.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <chrono>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include <components/resource/resourcesystem.hpp>
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
|
||||||
|
@ -98,19 +96,6 @@ float MWBase::Environment::getFrameRateLimit() const
|
||||||
return mFrameRateLimit;
|
return mFrameRateLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWBase::Environment::limitFrameRate(double dt) const
|
|
||||||
{
|
|
||||||
if (mFrameRateLimit > 0.f)
|
|
||||||
{
|
|
||||||
double thisFrameTime = dt;
|
|
||||||
double minFrameTime = 1.0 / static_cast<double>(mFrameRateLimit);
|
|
||||||
if (thisFrameTime < minFrameTime)
|
|
||||||
{
|
|
||||||
std::this_thread::sleep_for(std::chrono::duration<double>(minFrameTime - thisFrameTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MWBase::Environment::setVrMode(bool vrMode)
|
void MWBase::Environment::setVrMode(bool vrMode)
|
||||||
{
|
{
|
||||||
mVrMode = vrMode;
|
mVrMode = vrMode;
|
||||||
|
|
|
@ -84,7 +84,6 @@ namespace MWBase
|
||||||
|
|
||||||
void setFrameRateLimit(float frameRateLimit);
|
void setFrameRateLimit(float frameRateLimit);
|
||||||
float getFrameRateLimit() const;
|
float getFrameRateLimit() const;
|
||||||
void limitFrameRate(double dt) const;
|
|
||||||
|
|
||||||
void setVrMode(bool vrMode);
|
void setVrMode(bool vrMode);
|
||||||
bool getVrMode(void) const;
|
bool getVrMode(void) const;
|
||||||
|
|
|
@ -192,6 +192,7 @@ namespace MWBase
|
||||||
///
|
///
|
||||||
/// \note If cell==0, the cell the player is currently in will be used instead to
|
/// \note If cell==0, the cell the player is currently in will be used instead to
|
||||||
/// generate a name.
|
/// generate a name.
|
||||||
|
virtual std::string getCellName(const ESM::Cell* cell) const = 0;
|
||||||
|
|
||||||
virtual void removeRefScript (MWWorld::RefData *ref) = 0;
|
virtual void removeRefScript (MWWorld::RefData *ref) = 0;
|
||||||
//< Remove the script attached to ref from mLocalScripts
|
//< Remove the script attached to ref from mLocalScripts
|
||||||
|
|
|
@ -302,30 +302,15 @@ namespace MWClass
|
||||||
|
|
||||||
std::string Door::getDestination (const MWWorld::LiveCellRef<ESM::Door>& door)
|
std::string Door::getDestination (const MWWorld::LiveCellRef<ESM::Door>& door)
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
std::string dest = door.mRef.getDestCell();
|
||||||
|
if (dest.empty())
|
||||||
std::string dest;
|
|
||||||
if (door.mRef.getDestCell() != "")
|
|
||||||
{
|
|
||||||
// door leads to an interior, use interior name as tooltip
|
|
||||||
dest = door.mRef.getDestCell();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// door leads to exterior, use cell name (if any), otherwise translated region name
|
// door leads to exterior, use cell name (if any), otherwise translated region name
|
||||||
int x,y;
|
int x,y;
|
||||||
MWBase::Environment::get().getWorld()->positionToIndex (door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1], x, y);
|
auto world = MWBase::Environment::get().getWorld();
|
||||||
const ESM::Cell* cell = store.get<ESM::Cell>().find(x,y);
|
world->positionToIndex (door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1], x, y);
|
||||||
if (cell->mName != "")
|
const ESM::Cell* cell = world->getStore().get<ESM::Cell>().search(x,y);
|
||||||
dest = cell->mName;
|
dest = world->getCellName(cell);
|
||||||
else
|
|
||||||
{
|
|
||||||
const ESM::Region* region =
|
|
||||||
store.get<ESM::Region>().find(cell->mRegion);
|
|
||||||
|
|
||||||
//name as is, not a token
|
|
||||||
return MyGUI::TextIterator::toTagsString(region->mName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "#{sCell=" + dest + "}";
|
return "#{sCell=" + dest + "}";
|
||||||
|
|
|
@ -419,10 +419,10 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||||
|
|
||||||
std::string model = "meshes\\base_anim.nif";
|
std::string model = Settings::Manager::getString("baseanim", "Models");
|
||||||
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(ref->mBase->mRace);
|
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(ref->mBase->mRace);
|
||||||
if(race->mData.mFlags & ESM::Race::Beast)
|
if(race->mData.mFlags & ESM::Race::Beast)
|
||||||
model = "meshes\\base_animkna.nif";
|
model = Settings::Manager::getString("baseanimkna", "Models");
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
@ -432,12 +432,12 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::NPC> *npc = ptr.get<ESM::NPC>();
|
const MWWorld::LiveCellRef<ESM::NPC> *npc = ptr.get<ESM::NPC>();
|
||||||
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().search(npc->mBase->mRace);
|
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().search(npc->mBase->mRace);
|
||||||
if(race && race->mData.mFlags & ESM::Race::Beast)
|
if(race && race->mData.mFlags & ESM::Race::Beast)
|
||||||
models.emplace_back("meshes\\base_animkna.nif");
|
models.emplace_back(Settings::Manager::getString("baseanimkna", "Models"));
|
||||||
|
|
||||||
// keep these always loaded just in case
|
// keep these always loaded just in case
|
||||||
models.emplace_back("meshes/xargonian_swimkna.nif");
|
models.emplace_back(Settings::Manager::getString("xargonianswimkna", "Models"));
|
||||||
models.emplace_back("meshes/xbase_anim_female.nif");
|
models.emplace_back(Settings::Manager::getString("xbaseanimfemale", "Models"));
|
||||||
models.emplace_back("meshes/xbase_anim.nif");
|
models.emplace_back(Settings::Manager::getString("xbaseanim", "Models"));
|
||||||
|
|
||||||
if (!npc->mBase->mModel.empty())
|
if (!npc->mBase->mModel.empty())
|
||||||
models.push_back("meshes/"+npc->mBase->mModel);
|
models.push_back("meshes/"+npc->mBase->mModel);
|
||||||
|
|
|
@ -249,7 +249,7 @@ namespace MWGui
|
||||||
size_t length = mCommandLine->getTextCursor() - max;
|
size_t length = mCommandLine->getTextCursor() - max;
|
||||||
if(length > 0)
|
if(length > 0)
|
||||||
{
|
{
|
||||||
std::string text = caption;
|
auto text = caption;
|
||||||
text.erase(max, length);
|
text.erase(max, length);
|
||||||
mCommandLine->setCaption(text);
|
mCommandLine->setCaption(text);
|
||||||
mCommandLine->setTextCursor(max);
|
mCommandLine->setTextCursor(max);
|
||||||
|
@ -259,7 +259,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if(mCommandLine->getTextCursor() > 0)
|
if(mCommandLine->getTextCursor() > 0)
|
||||||
{
|
{
|
||||||
std::string text = mCommandLine->getCaption();
|
auto text = mCommandLine->getCaption();
|
||||||
text.erase(0, mCommandLine->getTextCursor());
|
text.erase(0, mCommandLine->getTextCursor());
|
||||||
mCommandLine->setCaption(text);
|
mCommandLine->setCaption(text);
|
||||||
mCommandLine->setTextCursor(0);
|
mCommandLine->setTextCursor(0);
|
||||||
|
|
|
@ -5,7 +5,11 @@
|
||||||
#include <MyGUI_RenderManager.h>
|
#include <MyGUI_RenderManager.h>
|
||||||
#include <MyGUI_TextBox.h>
|
#include <MyGUI_TextBox.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
// correctIconPath
|
// correctIconPath
|
||||||
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
|
@ -106,7 +110,13 @@ namespace MWGui
|
||||||
std::string invIcon = ptr.getClass().getInventoryIcon(ptr);
|
std::string invIcon = ptr.getClass().getInventoryIcon(ptr);
|
||||||
if (invIcon.empty())
|
if (invIcon.empty())
|
||||||
invIcon = "default icon.tga";
|
invIcon = "default icon.tga";
|
||||||
setIcon(MWBase::Environment::get().getWindowManager()->correctIconPath(invIcon));
|
invIcon = MWBase::Environment::get().getWindowManager()->correctIconPath(invIcon);
|
||||||
|
if (!MWBase::Environment::get().getResourceSystem()->getVFS()->exists(invIcon))
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Failed to open image: '" << invIcon << "' not found, falling back to 'default-icon.tga'";
|
||||||
|
invIcon = MWBase::Environment::get().getWindowManager()->correctIconPath("default icon.tga");
|
||||||
|
}
|
||||||
|
setIcon(invIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,6 @@ namespace MWGui
|
||||||
, mNestedLoadingCount(0)
|
, mNestedLoadingCount(0)
|
||||||
, mProgress(0)
|
, mProgress(0)
|
||||||
, mShowWallpaper(true)
|
, mShowWallpaper(true)
|
||||||
, mOldCallback(nullptr)
|
|
||||||
, mHasCallback(false)
|
|
||||||
{
|
{
|
||||||
mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize());
|
mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize());
|
||||||
|
|
||||||
|
@ -147,36 +145,12 @@ namespace MWGui
|
||||||
|
|
||||||
void operator () (osg::RenderInfo& renderInfo) const override
|
void operator () (osg::RenderInfo& renderInfo) const override
|
||||||
{
|
{
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
|
||||||
mOneshot = false;
|
|
||||||
}
|
|
||||||
mSignal.notify_all();
|
|
||||||
|
|
||||||
int w = renderInfo.getCurrentCamera()->getViewport()->width();
|
int w = renderInfo.getCurrentCamera()->getViewport()->width();
|
||||||
int h = renderInfo.getCurrentCamera()->getViewport()->height();
|
int h = renderInfo.getCurrentCamera()->getViewport()->height();
|
||||||
mTexture->copyTexImage2D(*renderInfo.getState(), 0, 0, w, h);
|
mTexture->copyTexImage2D(*renderInfo.getState(), 0, 0, w, h);
|
||||||
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
|
||||||
mOneshot = false;
|
mOneshot = false;
|
||||||
}
|
}
|
||||||
mSignal.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
void wait()
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
|
||||||
while (mOneshot)
|
|
||||||
mSignal.wait(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void waitUntilInvoked()
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
|
||||||
while (mOneshot)
|
|
||||||
mSignal.wait(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
void reset()
|
||||||
{
|
{
|
||||||
|
@ -185,8 +159,6 @@ namespace MWGui
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable bool mOneshot;
|
mutable bool mOneshot;
|
||||||
mutable std::mutex mMutex;
|
|
||||||
mutable std::condition_variable mSignal;
|
|
||||||
osg::ref_ptr<osg::Texture2D> mTexture;
|
osg::ref_ptr<osg::Texture2D> mTexture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -362,14 +334,12 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
#if OSG_VERSION_GREATER_OR_EQUAL(3, 5, 10)
|
#if OSG_VERSION_GREATER_OR_EQUAL(3, 5, 10)
|
||||||
|
mViewer->getCamera()->removeInitialDrawCallback(mCopyFramebufferToTextureCallback);
|
||||||
mViewer->getCamera()->addInitialDrawCallback(mCopyFramebufferToTextureCallback);
|
mViewer->getCamera()->addInitialDrawCallback(mCopyFramebufferToTextureCallback);
|
||||||
#else
|
#else
|
||||||
// TODO: Remove once we officially end support for OSG versions pre 3.5.10
|
|
||||||
mOldCallback = mViewer->getCamera()->getInitialDrawCallback();
|
|
||||||
mViewer->getCamera()->setInitialDrawCallback(mCopyFramebufferToTextureCallback);
|
mViewer->getCamera()->setInitialDrawCallback(mCopyFramebufferToTextureCallback);
|
||||||
#endif
|
#endif
|
||||||
mCopyFramebufferToTextureCallback->reset();
|
mCopyFramebufferToTextureCallback->reset();
|
||||||
mHasCallback = true;
|
|
||||||
|
|
||||||
mBackgroundImage->setBackgroundImage("");
|
mBackgroundImage->setBackgroundImage("");
|
||||||
mBackgroundImage->setVisible(false);
|
mBackgroundImage->setVisible(false);
|
||||||
|
@ -410,21 +380,6 @@ namespace MWGui
|
||||||
MWBase::Environment::get().getWindowManager()->viewerTraversals(false);
|
MWBase::Environment::get().getWindowManager()->viewerTraversals(false);
|
||||||
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
|
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
|
||||||
|
|
||||||
if (mHasCallback)
|
|
||||||
{
|
|
||||||
mCopyFramebufferToTextureCallback->waitUntilInvoked();
|
|
||||||
|
|
||||||
// Note that we are removing the callback before the draw thread has returned from it.
|
|
||||||
// This is OK as we are retaining the ref_ptr.
|
|
||||||
#if OSG_VERSION_GREATER_OR_EQUAL(3, 5, 10)
|
|
||||||
mViewer->getCamera()->removeInitialDrawCallback(mCopyFramebufferToTextureCallback);
|
|
||||||
#else
|
|
||||||
// TODO: Remove once we officially end support for OSG versions pre 3.5.10
|
|
||||||
mViewer->getCamera()->setInitialDrawCallback(mOldCallback);
|
|
||||||
#endif
|
|
||||||
mHasCallback = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mLastRenderTime = mTimer.time_m();
|
mLastRenderTime = mTimer.time_m();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,8 +87,6 @@ namespace MWGui
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> mTexture;
|
osg::ref_ptr<osg::Texture2D> mTexture;
|
||||||
osg::ref_ptr<CopyFramebufferToTextureCallback> mCopyFramebufferToTextureCallback;
|
osg::ref_ptr<CopyFramebufferToTextureCallback> mCopyFramebufferToTextureCallback;
|
||||||
osg::ref_ptr<osg::Camera::DrawCallback> mOldCallback;
|
|
||||||
bool mHasCallback;
|
|
||||||
std::unique_ptr<MyGUI::ITexture> mGuiTexture;
|
std::unique_ptr<MyGUI::ITexture> mGuiTexture;
|
||||||
|
|
||||||
void changeWallpaper();
|
void changeWallpaper();
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include <components/widgets/tags.hpp>
|
#include <components/widgets/tags.hpp>
|
||||||
|
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
#include <components/misc/frameratelimiter.hpp>
|
||||||
|
|
||||||
#include "../mwbase/inputmanager.hpp"
|
#include "../mwbase/inputmanager.hpp"
|
||||||
#include "../mwbase/statemanager.hpp"
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
@ -757,12 +758,11 @@ namespace MWGui
|
||||||
|
|
||||||
if (block)
|
if (block)
|
||||||
{
|
{
|
||||||
osg::Timer frameTimer;
|
Misc::FrameRateLimiter frameRateLimiter = Misc::makeFrameRateLimiter(MWBase::Environment::get().getFrameRateLimit());
|
||||||
while (mMessageBoxManager->readPressedButton(false) == -1
|
while (mMessageBoxManager->readPressedButton(false) == -1
|
||||||
&& !MWBase::Environment::get().getStateManager()->hasQuitRequest())
|
&& !MWBase::Environment::get().getStateManager()->hasQuitRequest())
|
||||||
{
|
{
|
||||||
double dt = frameTimer.time_s();
|
const double dt = std::chrono::duration_cast<std::chrono::duration<double>>(frameRateLimiter.getLastFrameDuration()).count();
|
||||||
frameTimer.setStartTick();
|
|
||||||
|
|
||||||
mKeyboardNavigation->onFrame();
|
mKeyboardNavigation->onFrame();
|
||||||
mMessageBoxManager->onFrame(dt);
|
mMessageBoxManager->onFrame(dt);
|
||||||
|
@ -777,7 +777,7 @@ namespace MWGui
|
||||||
// refer to the advance() and frame() order in Engine::go()
|
// refer to the advance() and frame() order in Engine::go()
|
||||||
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
|
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
|
||||||
|
|
||||||
MWBase::Environment::get().limitFrameRate(frameTimer.time_s());
|
frameRateLimiter.limit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1807,12 +1807,10 @@ namespace MWGui
|
||||||
~MWSound::Type::Movie & MWSound::Type::Mask
|
~MWSound::Type::Movie & MWSound::Type::Mask
|
||||||
);
|
);
|
||||||
|
|
||||||
osg::Timer frameTimer;
|
Misc::FrameRateLimiter frameRateLimiter = Misc::makeFrameRateLimiter(MWBase::Environment::get().getFrameRateLimit());
|
||||||
while (mVideoEnabled && mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest())
|
while (mVideoEnabled && mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest())
|
||||||
{
|
{
|
||||||
|
const double dt = std::chrono::duration_cast<std::chrono::duration<double>>(frameRateLimiter.getLastFrameDuration()).count();
|
||||||
double dt = frameTimer.time_s();
|
|
||||||
frameTimer.setStartTick();
|
|
||||||
|
|
||||||
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
||||||
|
|
||||||
|
@ -1833,7 +1831,7 @@ namespace MWGui
|
||||||
// refer to the advance() and frame() order in Engine::go()
|
// refer to the advance() and frame() order in Engine::go()
|
||||||
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
|
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
|
||||||
|
|
||||||
MWBase::Environment::get().limitFrameRate(frameTimer.time_s());
|
frameRateLimiter.limit();
|
||||||
}
|
}
|
||||||
mVideoWidget->stop();
|
mVideoWidget->stop();
|
||||||
|
|
||||||
|
|
|
@ -39,12 +39,14 @@ namespace MWInput
|
||||||
&& MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
&& MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||||
SDL_StopTextInput();
|
SDL_StopTextInput();
|
||||||
|
|
||||||
bool consumed = false;
|
bool consumed = SDL_IsTextInputActive() && // Little trick to check if key is printable
|
||||||
|
(!(SDLK_SCANCODE_MASK & arg.keysym.sym) &&
|
||||||
|
(std::isprint(arg.keysym.sym) ||
|
||||||
|
// Don't trust isprint for symbols outside the extended ASCII range
|
||||||
|
(kc == MyGUI::KeyCode::None && arg.keysym.sym > 0xff)));
|
||||||
if (kc != MyGUI::KeyCode::None && !mBindingsManager->isDetectingBindingState())
|
if (kc != MyGUI::KeyCode::None && !mBindingsManager->isDetectingBindingState())
|
||||||
{
|
{
|
||||||
consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(kc, 0, arg.repeat);
|
if (MWBase::Environment::get().getWindowManager()->injectKeyPress(kc, 0, arg.repeat))
|
||||||
if (SDL_IsTextInputActive() && // Little trick to check if key is printable
|
|
||||||
(!(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)))
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
mBindingsManager->setPlayerControlsEnabled(!consumed);
|
mBindingsManager->setPlayerControlsEnabled(!consumed);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <components/misc/mathutil.hpp>
|
#include <components/misc/mathutil.hpp>
|
||||||
|
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
#include <components/detournavigator/navigator.hpp>
|
||||||
|
|
||||||
#include "../mwphysics/collisiontype.hpp"
|
#include "../mwphysics/collisiontype.hpp"
|
||||||
|
|
||||||
|
@ -127,10 +128,11 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
//Update every frame. UpdateLOS uses a timer, so the LOS check does not happen every frame.
|
//Update every frame. UpdateLOS uses a timer, so the LOS check does not happen every frame.
|
||||||
updateLOS(actor, target, duration, storage);
|
updateLOS(actor, target, duration, storage);
|
||||||
float targetReachedTolerance = 0.0f;
|
const float targetReachedTolerance = storage.mLOS && !storage.mUseCustomDestination
|
||||||
if (storage.mLOS)
|
? storage.mAttackRange : 0.0f;
|
||||||
targetReachedTolerance = storage.mAttackRange;
|
const osg::Vec3f destination = storage.mUseCustomDestination
|
||||||
const bool is_target_reached = pathTo(actor, target.getRefData().getPosition().asVec3(), duration, targetReachedTolerance);
|
? storage.mCustomDestination : target.getRefData().getPosition().asVec3();
|
||||||
|
const bool is_target_reached = pathTo(actor, destination, duration, targetReachedTolerance);
|
||||||
if (is_target_reached) storage.mReadyToAttack = true;
|
if (is_target_reached) storage.mReadyToAttack = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,8 +234,8 @@ namespace MWMechanics
|
||||||
const ESM::Weapon* weapon = currentAction->getWeapon();
|
const ESM::Weapon* weapon = currentAction->getWeapon();
|
||||||
|
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
osg::Vec3f vActorPos(pos.asVec3());
|
const osg::Vec3f vActorPos(pos.asVec3());
|
||||||
osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3());
|
const osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3());
|
||||||
|
|
||||||
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
|
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
|
||||||
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
|
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
|
||||||
|
@ -243,9 +245,7 @@ namespace MWMechanics
|
||||||
if (isRangedCombat)
|
if (isRangedCombat)
|
||||||
{
|
{
|
||||||
// rotate actor taking into account target movement direction and projectile speed
|
// rotate actor taking into account target movement direction and projectile speed
|
||||||
osg::Vec3f& lastTargetPos = storage.mLastTargetPos;
|
vAimDir = AimDirToMovingTarget(actor, target, storage.mLastTargetPos, AI_REACTION_TIME, (weapon ? weapon->mData.mType : 0), storage.mStrength);
|
||||||
vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, AI_REACTION_TIME, (weapon ? weapon->mData.mType : 0), storage.mStrength);
|
|
||||||
lastTargetPos = vTargetPos;
|
|
||||||
|
|
||||||
storage.mMovement.mRotation[0] = getXAngleToDir(vAimDir);
|
storage.mMovement.mRotation[0] = getXAngleToDir(vAimDir);
|
||||||
storage.mMovement.mRotation[2] = getZAngleToDir(vAimDir);
|
storage.mMovement.mRotation[2] = getZAngleToDir(vAimDir);
|
||||||
|
@ -256,12 +256,69 @@ namespace MWMechanics
|
||||||
storage.mMovement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); // using vAimDir results in spastic movements since the head is animated
|
storage.mMovement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); // using vAimDir results in spastic movements since the head is animated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
storage.mLastTargetPos = vTargetPos;
|
||||||
|
|
||||||
if (storage.mReadyToAttack)
|
if (storage.mReadyToAttack)
|
||||||
{
|
{
|
||||||
storage.startCombatMove(isRangedCombat, distToTarget, rangeAttack, actor, target);
|
storage.startCombatMove(isRangedCombat, distToTarget, rangeAttack, actor, target);
|
||||||
// start new attack
|
// start new attack
|
||||||
storage.startAttackIfReady(actor, characterController, weapon, isRangedCombat);
|
storage.startAttackIfReady(actor, characterController, weapon, isRangedCombat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If actor uses custom destination it has to try to rebuild path because environment can change
|
||||||
|
// (door is opened between actor and target) or target position has changed and current custom destination
|
||||||
|
// is not good enough to attack target.
|
||||||
|
if (storage.mCurrentAction->isAttackingOrSpell()
|
||||||
|
&& ((!storage.mReadyToAttack && !mPathFinder.isPathConstructed())
|
||||||
|
|| (storage.mUseCustomDestination && (storage.mCustomDestination - vTargetPos).length() > rangeAttack)))
|
||||||
|
{
|
||||||
|
// Try to build path to the target.
|
||||||
|
const auto halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor);
|
||||||
|
const auto navigatorFlags = getNavigatorFlags(actor);
|
||||||
|
const auto areaCosts = getAreaCosts(actor);
|
||||||
|
const auto pathGridGraph = getPathGridGraph(actor.getCell());
|
||||||
|
mPathFinder.buildPath(actor, vActorPos, vTargetPos, actor.getCell(), pathGridGraph, halfExtents, navigatorFlags, areaCosts);
|
||||||
|
|
||||||
|
if (!mPathFinder.isPathConstructed())
|
||||||
|
{
|
||||||
|
// If there is no path, try to find a point on a line from the actor position to target projected
|
||||||
|
// on navmesh to attack the target from there.
|
||||||
|
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
const auto halfExtents = world->getPathfindingHalfExtents(actor);
|
||||||
|
const auto navigator = world->getNavigator();
|
||||||
|
const auto navigatorFlags = getNavigatorFlags(actor);
|
||||||
|
const auto areaCosts = getAreaCosts(actor);
|
||||||
|
const auto hit = navigator->raycast(halfExtents, vActorPos, vTargetPos, navigatorFlags);
|
||||||
|
|
||||||
|
if (hit.has_value() && (*hit - vTargetPos).length() <= rangeAttack)
|
||||||
|
{
|
||||||
|
// If the point is close enough, try to find a path to that point.
|
||||||
|
mPathFinder.buildPath(actor, vActorPos, *hit, actor.getCell(), pathGridGraph, halfExtents, navigatorFlags, areaCosts);
|
||||||
|
if (mPathFinder.isPathConstructed())
|
||||||
|
{
|
||||||
|
// If path to that point is found use it as custom destination.
|
||||||
|
storage.mCustomDestination = *hit;
|
||||||
|
storage.mUseCustomDestination = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mPathFinder.isPathConstructed())
|
||||||
|
{
|
||||||
|
storage.mUseCustomDestination = false;
|
||||||
|
storage.stopAttack();
|
||||||
|
characterController.setAttackingOrSpell(false);
|
||||||
|
currentAction.reset(new ActionFlee());
|
||||||
|
actionCooldown = currentAction->getActionCooldown();
|
||||||
|
storage.startFleeing();
|
||||||
|
MWBase::Environment::get().getDialogueManager()->say(actor, "flee");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
storage.mUseCustomDestination = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,9 @@ namespace MWMechanics
|
||||||
float mFleeBlindRunTimer;
|
float mFleeBlindRunTimer;
|
||||||
ESM::Pathgrid::Point mFleeDest;
|
ESM::Pathgrid::Point mFleeDest;
|
||||||
|
|
||||||
|
bool mUseCustomDestination;
|
||||||
|
osg::Vec3f mCustomDestination;
|
||||||
|
|
||||||
AiCombatStorage():
|
AiCombatStorage():
|
||||||
mAttackCooldown(0.0f),
|
mAttackCooldown(0.0f),
|
||||||
mTimerReact(AI_REACTION_TIME),
|
mTimerReact(AI_REACTION_TIME),
|
||||||
|
@ -74,7 +77,9 @@ namespace MWMechanics
|
||||||
mFleeState(FleeState_None),
|
mFleeState(FleeState_None),
|
||||||
mLOS(false),
|
mLOS(false),
|
||||||
mUpdateLOSTimer(0.0f),
|
mUpdateLOSTimer(0.0f),
|
||||||
mFleeBlindRunTimer(0.0f)
|
mFleeBlindRunTimer(0.0f),
|
||||||
|
mUseCustomDestination(false),
|
||||||
|
mCustomDestination()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
|
void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
|
||||||
|
|
|
@ -305,6 +305,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
void applyElementalShields(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim)
|
void applyElementalShields(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim)
|
||||||
{
|
{
|
||||||
|
// Don't let elemental shields harm the player in god mode.
|
||||||
|
bool godmode = attacker == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
||||||
|
if (godmode)
|
||||||
|
return;
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
{
|
{
|
||||||
float magnitude = victim.getClass().getCreatureStats(victim).getMagicEffects().get(ESM::MagicEffect::FireShield+i).getMagnitude();
|
float magnitude = victim.getClass().getCreatureStats(victim).getMagicEffects().get(ESM::MagicEffect::FireShield+i).getMagnitude();
|
||||||
|
@ -345,6 +349,8 @@ namespace MWMechanics
|
||||||
MWMechanics::DynamicStat<float> health = attackerStats.getHealth();
|
MWMechanics::DynamicStat<float> health = attackerStats.getHealth();
|
||||||
health.setCurrent(health.getCurrent() - x);
|
health.setCurrent(health.getCurrent() - x);
|
||||||
attackerStats.setHealth(health);
|
attackerStats.setHealth(health);
|
||||||
|
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound3D(attacker, "Health Damage", 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ namespace MWMechanics
|
||||||
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||||
return 100;
|
return 100;
|
||||||
|
|
||||||
if (checkMagicka && stats.getMagicka().getCurrent() < spell->mData.mCost)
|
if (checkMagicka && spell->mData.mCost > 0 && stats.getMagicka().getCurrent() < spell->mData.mCost)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (spell->mData.mFlags & ESM::Spell::F_Always)
|
if (spell->mData.mFlags & ESM::Spell::F_Always)
|
||||||
|
|
|
@ -58,6 +58,15 @@ namespace MWPhysics
|
||||||
mShape->setUseDiamondSubdivision(true);
|
mShape->setUseDiamondSubdivision(true);
|
||||||
mShape->setLocalScaling(btVector3(triSize, triSize, 1));
|
mShape->setLocalScaling(btVector3(triSize, triSize, 1));
|
||||||
|
|
||||||
|
#if BT_BULLET_VERSION >= 289
|
||||||
|
// Accelerates some collision tests.
|
||||||
|
//
|
||||||
|
// Note: The accelerator data structure in Bullet is only used
|
||||||
|
// in some operations. This could be improved, see:
|
||||||
|
// https://github.com/bulletphysics/bullet3/issues/3276
|
||||||
|
mShape->buildAccelerator();
|
||||||
|
#endif
|
||||||
|
|
||||||
btTransform transform(btQuaternion::getIdentity(),
|
btTransform transform(btQuaternion::getIdentity(),
|
||||||
btVector3((x+0.5f) * triSize * (sqrtVerts-1),
|
btVector3((x+0.5f) * triSize * (sqrtVerts-1),
|
||||||
(y+0.5f) * triSize * (sqrtVerts-1),
|
(y+0.5f) * triSize * (sqrtVerts-1),
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace MWPhysics
|
||||||
ContactCollectionCallback(const btCollisionObject * me, osg::Vec3f velocity) : mMe(me)
|
ContactCollectionCallback(const btCollisionObject * me, osg::Vec3f velocity) : mMe(me)
|
||||||
{
|
{
|
||||||
m_collisionFilterGroup = me->getBroadphaseHandle()->m_collisionFilterGroup;
|
m_collisionFilterGroup = me->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||||
m_collisionFilterMask = me->getBroadphaseHandle()->m_collisionFilterMask;
|
m_collisionFilterMask = me->getBroadphaseHandle()->m_collisionFilterMask & ~CollisionType_Projectile;
|
||||||
mVelocity = Misc::Convert::toBullet(velocity);
|
mVelocity = Misc::Convert::toBullet(velocity);
|
||||||
}
|
}
|
||||||
btScalar addSingleResult(btManifoldPoint & contact, const btCollisionObjectWrapper * colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper * colObj1Wrap, int partId1, int index1) override
|
btScalar addSingleResult(btManifoldPoint & contact, const btCollisionObjectWrapper * colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper * colObj1Wrap, int partId1, int index1) override
|
||||||
|
|
|
@ -681,9 +681,14 @@ namespace MWPhysics
|
||||||
mActors.emplace(ptr, std::move(actor));
|
mActors.emplace(ptr, std::move(actor));
|
||||||
}
|
}
|
||||||
|
|
||||||
int PhysicsSystem::addProjectile (const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, bool canTraverseWater)
|
int PhysicsSystem::addProjectile (const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius, bool canTraverseWater)
|
||||||
{
|
{
|
||||||
|
osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance = mShapeManager->getInstance(mesh);
|
||||||
|
assert(shapeInstance);
|
||||||
|
float radius = computeRadius ? shapeInstance->mCollisionBox.extents.length() / 2.f : 1.f;
|
||||||
|
|
||||||
mProjectileId++;
|
mProjectileId++;
|
||||||
|
|
||||||
auto projectile = std::make_shared<Projectile>(caster, position, radius, canTraverseWater, mTaskScheduler.get(), this);
|
auto projectile = std::make_shared<Projectile>(caster, position, radius, canTraverseWater, mTaskScheduler.get(), this);
|
||||||
mProjectiles.emplace(mProjectileId, std::move(projectile));
|
mProjectiles.emplace(mProjectileId, std::move(projectile));
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace MWPhysics
|
||||||
void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType = CollisionType_World);
|
void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType = CollisionType_World);
|
||||||
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);
|
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||||
|
|
||||||
int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, bool canTraverseWater);
|
int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius, bool canTraverseWater);
|
||||||
void updateProjectile(const int projectileId, const osg::Vec3f &position) const;
|
void updateProjectile(const int projectileId, const osg::Vec3f &position) const;
|
||||||
void removeProjectile(const int projectileId);
|
void removeProjectile(const int projectileId);
|
||||||
|
|
||||||
|
|
|
@ -1554,7 +1554,7 @@ namespace MWRender
|
||||||
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
||||||
if(ref->mBase->mFlags & ESM::Creature::Bipedal)
|
if(ref->mBase->mFlags & ESM::Creature::Bipedal)
|
||||||
{
|
{
|
||||||
defaultSkeleton = "meshes\\xbase_anim.nif";
|
defaultSkeleton = Settings::Manager::getString("xbaseanim", "Models");
|
||||||
inject = true;
|
inject = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,7 @@ namespace MWRender
|
||||||
noBlendAlphaEnv->setCombine_RGB(osg::TexEnvCombine::REPLACE);
|
noBlendAlphaEnv->setCombine_RGB(osg::TexEnvCombine::REPLACE);
|
||||||
noBlendAlphaEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS);
|
noBlendAlphaEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS);
|
||||||
osg::ref_ptr<osg::Texture2D> dummyTexture = new osg::Texture2D();
|
osg::ref_ptr<osg::Texture2D> dummyTexture = new osg::Texture2D();
|
||||||
dummyTexture->setInternalFormat(GL_RED);
|
dummyTexture->setInternalFormat(GL_DEPTH_COMPONENT);
|
||||||
dummyTexture->setTextureSize(1, 1);
|
dummyTexture->setTextureSize(1, 1);
|
||||||
// This might clash with a shadow map, so make sure it doesn't cast shadows
|
// This might clash with a shadow map, so make sure it doesn't cast shadows
|
||||||
dummyTexture->setShadowComparison(true);
|
dummyTexture->setShadowComparison(true);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <components/sceneutil/visitor.hpp>
|
#include <components/sceneutil/visitor.hpp>
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
#include <components/sceneutil/skeleton.hpp>
|
#include <components/sceneutil/skeleton.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -35,7 +35,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr,
|
||||||
setObjectRoot(model, false, false, true);
|
setObjectRoot(model, false, false, true);
|
||||||
|
|
||||||
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
||||||
addAnimSource("meshes\\xbase_anim.nif", model);
|
addAnimSource(Settings::Manager::getString("xbaseanim", "Models"), model);
|
||||||
addAnimSource(model, model);
|
addAnimSource(model, model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const
|
||||||
|
|
||||||
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
||||||
{
|
{
|
||||||
addAnimSource("meshes\\xbase_anim.nif", model);
|
addAnimSource(Settings::Manager::getString("xbaseanim", "Models"), model);
|
||||||
}
|
}
|
||||||
addAnimSource(model, model);
|
addAnimSource(model, model);
|
||||||
|
|
||||||
|
|
|
@ -524,7 +524,7 @@ void NpcAnimation::updateNpcBase()
|
||||||
|
|
||||||
if(!is1stPerson)
|
if(!is1stPerson)
|
||||||
{
|
{
|
||||||
const std::string base = "meshes\\xbase_anim.nif";
|
const std::string base = Settings::Manager::getString("xbaseanim", "Models");
|
||||||
if (smodel != base && !isWerewolf)
|
if (smodel != base && !isWerewolf)
|
||||||
addAnimSource(base, smodel);
|
addAnimSource(base, smodel);
|
||||||
|
|
||||||
|
@ -538,7 +538,7 @@ void NpcAnimation::updateNpcBase()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const std::string base = "meshes\\xbase_anim.1st.nif";
|
const std::string base = Settings::Manager::getString("xbaseanim1st", "Models");
|
||||||
if (smodel != base && !isWerewolf)
|
if (smodel != base && !isWerewolf)
|
||||||
addAnimSource(base, smodel);
|
addAnimSource(base, smodel);
|
||||||
|
|
||||||
|
|
|
@ -472,12 +472,15 @@ namespace MWRender
|
||||||
mSky->listAssetsToPreload(workItem->mModels, workItem->mTextures);
|
mSky->listAssetsToPreload(workItem->mModels, workItem->mTextures);
|
||||||
mWater->listAssetsToPreload(workItem->mTextures);
|
mWater->listAssetsToPreload(workItem->mTextures);
|
||||||
|
|
||||||
const char* basemodels[] = {"xbase_anim", "xbase_anim.1st", "xbase_anim_female", "xbase_animkna"};
|
workItem->mModels.push_back(Settings::Manager::getString("xbaseanim", "Models"));
|
||||||
for (size_t i=0; i<sizeof(basemodels)/sizeof(basemodels[0]); ++i)
|
workItem->mModels.push_back(Settings::Manager::getString("xbaseanim1st", "Models"));
|
||||||
{
|
workItem->mModels.push_back(Settings::Manager::getString("xbaseanimfemale", "Models"));
|
||||||
workItem->mModels.push_back(std::string("meshes/") + basemodels[i] + ".nif");
|
workItem->mModels.push_back(Settings::Manager::getString("xargonianswimkna", "Models"));
|
||||||
workItem->mKeyframes.push_back(std::string("meshes/") + basemodels[i] + ".kf");
|
|
||||||
}
|
workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanimkf", "Models"));
|
||||||
|
workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanim1stkf", "Models"));
|
||||||
|
workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanimfemalekf", "Models"));
|
||||||
|
workItem->mKeyframes.push_back(Settings::Manager::getString("xargonianswimknakf", "Models"));
|
||||||
|
|
||||||
workItem->mTextures.emplace_back("textures/_land_default.dds");
|
workItem->mTextures.emplace_back("textures/_land_default.dds");
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,8 @@
|
||||||
#include <components/sceneutil/visitor.hpp>
|
#include <components/sceneutil/visitor.hpp>
|
||||||
#include <components/sceneutil/shadow.hpp>
|
#include <components/sceneutil/shadow.hpp>
|
||||||
|
|
||||||
|
#include <components/nifosg/particle.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
@ -1137,7 +1139,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana
|
||||||
, mBaseWindSpeed(0.f)
|
, mBaseWindSpeed(0.f)
|
||||||
, mEnabled(true)
|
, mEnabled(true)
|
||||||
, mSunEnabled(true)
|
, mSunEnabled(true)
|
||||||
, mWeatherAlpha(0.f)
|
, mEffectFade(0.f)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<CameraRelativeTransform> skyroot (new CameraRelativeTransform);
|
osg::ref_ptr<CameraRelativeTransform> skyroot (new CameraRelativeTransform);
|
||||||
skyroot->setName("Sky Root");
|
skyroot->setName("Sky Root");
|
||||||
|
@ -1278,16 +1280,10 @@ private:
|
||||||
class AlphaFader : public SceneUtil::StateSetUpdater
|
class AlphaFader : public SceneUtil::StateSetUpdater
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// @param alphaUpdate variable which to update with alpha value
|
/// @param alpha the variable alpha value is recovered from
|
||||||
AlphaFader(float *alphaUpdate)
|
AlphaFader(float& alpha)
|
||||||
: mAlpha(1.f)
|
: mAlpha(alpha)
|
||||||
{
|
{
|
||||||
mAlphaUpdate = alphaUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAlpha(float alpha)
|
|
||||||
{
|
|
||||||
mAlpha = alpha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDefaults(osg::StateSet* stateset) override
|
void setDefaults(osg::StateSet* stateset) override
|
||||||
|
@ -1301,19 +1297,16 @@ public:
|
||||||
{
|
{
|
||||||
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
|
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
|
||||||
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha));
|
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha));
|
||||||
|
|
||||||
if (mAlphaUpdate)
|
|
||||||
*mAlphaUpdate = mAlpha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper for adding AlphaFaders to a subgraph
|
// Helper for adding AlphaFaders to a subgraph
|
||||||
class SetupVisitor : public osg::NodeVisitor
|
class SetupVisitor : public osg::NodeVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetupVisitor(float *alphaUpdate)
|
SetupVisitor(float &alpha)
|
||||||
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
||||||
|
, mAlpha(alpha)
|
||||||
{
|
{
|
||||||
mAlphaUpdate = alphaUpdate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply(osg::Node &node) override
|
void apply(osg::Node &node) override
|
||||||
|
@ -1333,56 +1326,24 @@ public:
|
||||||
callback = callback->getNestedCallback();
|
callback = callback->getNestedCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<AlphaFader> alphaFader (new AlphaFader(mAlphaUpdate));
|
osg::ref_ptr<AlphaFader> alphaFader (new AlphaFader(mAlpha));
|
||||||
|
|
||||||
if (composite)
|
if (composite)
|
||||||
composite->addController(alphaFader);
|
composite->addController(alphaFader);
|
||||||
else
|
else
|
||||||
node.addUpdateCallback(alphaFader);
|
node.addUpdateCallback(alphaFader);
|
||||||
|
|
||||||
mAlphaFaders.push_back(alphaFader);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
traverse(node);
|
traverse(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<AlphaFader> > getAlphaFaders()
|
|
||||||
{
|
|
||||||
return mAlphaFaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<osg::ref_ptr<AlphaFader> > mAlphaFaders;
|
float &mAlpha;
|
||||||
float *mAlphaUpdate;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float mAlpha;
|
float &mAlpha;
|
||||||
float *mAlphaUpdate;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RainFader : public AlphaFader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RainFader(float *alphaUpdate): AlphaFader(alphaUpdate)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDefaults(osg::StateSet* stateset) override
|
|
||||||
{
|
|
||||||
osg::ref_ptr<osg::Material> mat (new osg::Material);
|
|
||||||
mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
|
||||||
mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1));
|
|
||||||
mat->setColorMode(osg::Material::OFF);
|
|
||||||
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
|
|
||||||
}
|
|
||||||
|
|
||||||
void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) override
|
|
||||||
{
|
|
||||||
AlphaFader::apply(stateset,nv);
|
|
||||||
*mAlphaUpdate = mAlpha * 2.0; // mAlpha is limited to 0.6 so multiply by 2 to reach full intensity
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void SkyManager::setCamera(osg::Camera *camera)
|
void SkyManager::setCamera(osg::Camera *camera)
|
||||||
|
@ -1466,6 +1427,37 @@ protected:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WeatherAlphaOperator : public osgParticle::Operator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WeatherAlphaOperator(float& alpha, bool rain)
|
||||||
|
: mAlpha(alpha)
|
||||||
|
, mIsRain(rain)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Object *cloneType() const override
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Object *clone(const osg::CopyOp &op) const override
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operate(osgParticle::Particle *particle, double dt) override
|
||||||
|
{
|
||||||
|
constexpr float rainThreshold = 0.6f; // Rain_Threshold?
|
||||||
|
const float alpha = mIsRain ? mAlpha * rainThreshold : mAlpha;
|
||||||
|
particle->setAlphaRange(osgParticle::rangef(alpha, alpha));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float &mAlpha;
|
||||||
|
bool mIsRain;
|
||||||
|
};
|
||||||
|
|
||||||
void SkyManager::createRain()
|
void SkyManager::createRain()
|
||||||
{
|
{
|
||||||
if (mRainNode)
|
if (mRainNode)
|
||||||
|
@ -1473,7 +1465,7 @@ void SkyManager::createRain()
|
||||||
|
|
||||||
mRainNode = new osg::Group;
|
mRainNode = new osg::Group;
|
||||||
|
|
||||||
mRainParticleSystem = new osgParticle::ParticleSystem;
|
mRainParticleSystem = new NifOsg::ParticleSystem;
|
||||||
osg::Vec3 rainRange = osg::Vec3(mRainDiameter, mRainDiameter, (mRainMinHeight+mRainMaxHeight)/2.f);
|
osg::Vec3 rainRange = osg::Vec3(mRainDiameter, mRainDiameter, (mRainMinHeight+mRainMaxHeight)/2.f);
|
||||||
|
|
||||||
mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED);
|
mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED);
|
||||||
|
@ -1492,6 +1484,12 @@ void SkyManager::createRain()
|
||||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||||
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
|
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Material> mat (new osg::Material);
|
||||||
|
mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
||||||
|
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
||||||
|
mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||||
|
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
|
||||||
|
|
||||||
osgParticle::Particle& particleTemplate = mRainParticleSystem->getDefaultParticleTemplate();
|
osgParticle::Particle& particleTemplate = mRainParticleSystem->getDefaultParticleTemplate();
|
||||||
particleTemplate.setSizeRange(osgParticle::rangef(5.f, 15.f));
|
particleTemplate.setSizeRange(osgParticle::rangef(5.f, 15.f));
|
||||||
particleTemplate.setAlphaRange(osgParticle::rangef(1.f, 1.f));
|
particleTemplate.setAlphaRange(osgParticle::rangef(1.f, 1.f));
|
||||||
|
@ -1524,6 +1522,7 @@ void SkyManager::createRain()
|
||||||
|
|
||||||
osg::ref_ptr<osgParticle::ModularProgram> program (new osgParticle::ModularProgram);
|
osg::ref_ptr<osgParticle::ModularProgram> program (new osgParticle::ModularProgram);
|
||||||
program->addOperator(new WrapAroundOperator(mCamera,rainRange));
|
program->addOperator(new WrapAroundOperator(mCamera,rainRange));
|
||||||
|
program->addOperator(new WeatherAlphaOperator(mEffectFade, true));
|
||||||
program->setParticleSystem(mRainParticleSystem);
|
program->setParticleSystem(mRainParticleSystem);
|
||||||
mRainNode->addChild(program);
|
mRainNode->addChild(program);
|
||||||
|
|
||||||
|
@ -1531,8 +1530,7 @@ void SkyManager::createRain()
|
||||||
mRainNode->addChild(mRainParticleSystem);
|
mRainNode->addChild(mRainParticleSystem);
|
||||||
mRainNode->addChild(updater);
|
mRainNode->addChild(updater);
|
||||||
|
|
||||||
mRainFader = new RainFader(&mWeatherAlpha);
|
// Note: if we ever switch to regular geometry rain, it'll need to use an AlphaFader.
|
||||||
mRainNode->addUpdateCallback(mRainFader);
|
|
||||||
mRainNode->addCullCallback(mUnderwaterSwitch);
|
mRainNode->addCullCallback(mUnderwaterSwitch);
|
||||||
mRainNode->setNodeMask(Mask_WeatherParticles);
|
mRainNode->setNodeMask(Mask_WeatherParticles);
|
||||||
|
|
||||||
|
@ -1550,7 +1548,6 @@ void SkyManager::destroyRain()
|
||||||
mCounter = nullptr;
|
mCounter = nullptr;
|
||||||
mRainParticleSystem = nullptr;
|
mRainParticleSystem = nullptr;
|
||||||
mRainShooter = nullptr;
|
mRainShooter = nullptr;
|
||||||
mRainFader = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkyManager::~SkyManager()
|
SkyManager::~SkyManager()
|
||||||
|
@ -1589,17 +1586,18 @@ void SkyManager::update(float duration)
|
||||||
if (!mEnabled)
|
if (!mEnabled)
|
||||||
{
|
{
|
||||||
if (mRainIntensityUniform)
|
if (mRainIntensityUniform)
|
||||||
mRainIntensityUniform->set((float) 0.0);
|
mRainIntensityUniform->set(0.f);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mRainIntensityUniform)
|
if (mRainIntensityUniform)
|
||||||
{
|
{
|
||||||
if (mIsStorm || (!hasRain() && !mParticleNode))
|
float rainIntensity = 0.f;
|
||||||
mRainIntensityUniform->set((float) 0.0);
|
if (!mIsStorm && (hasRain() || mParticleNode))
|
||||||
else
|
rainIntensity = mEffectFade;
|
||||||
mRainIntensityUniform->set((float) mWeatherAlpha);
|
|
||||||
|
mRainIntensityUniform->set(rainIntensity);
|
||||||
}
|
}
|
||||||
|
|
||||||
switchUnderwaterRain();
|
switchUnderwaterRain();
|
||||||
|
@ -1714,7 +1712,6 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
||||||
{
|
{
|
||||||
mParticleNode->removeChild(mParticleEffect);
|
mParticleNode->removeChild(mParticleEffect);
|
||||||
mParticleEffect = nullptr;
|
mParticleEffect = nullptr;
|
||||||
mParticleFaders.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCurrentParticleEffect.empty())
|
if (mCurrentParticleEffect.empty())
|
||||||
|
@ -1740,16 +1737,13 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
||||||
SceneUtil::AssignControllerSourcesVisitor assignVisitor(std::shared_ptr<SceneUtil::ControllerSource>(new SceneUtil::FrameTimeSource));
|
SceneUtil::AssignControllerSourcesVisitor assignVisitor(std::shared_ptr<SceneUtil::ControllerSource>(new SceneUtil::FrameTimeSource));
|
||||||
mParticleEffect->accept(assignVisitor);
|
mParticleEffect->accept(assignVisitor);
|
||||||
|
|
||||||
AlphaFader::SetupVisitor alphaFaderSetupVisitor(&mWeatherAlpha);
|
AlphaFader::SetupVisitor alphaFaderSetupVisitor(mEffectFade);
|
||||||
|
|
||||||
mParticleEffect->accept(alphaFaderSetupVisitor);
|
mParticleEffect->accept(alphaFaderSetupVisitor);
|
||||||
mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders();
|
|
||||||
|
|
||||||
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
|
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
|
||||||
mParticleEffect->accept(disableFreezeOnCullVisitor);
|
mParticleEffect->accept(disableFreezeOnCullVisitor);
|
||||||
|
|
||||||
if (!weather.mIsStorm)
|
|
||||||
{
|
|
||||||
SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem"));
|
SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem"));
|
||||||
mParticleEffect->accept(findPSVisitor);
|
mParticleEffect->accept(findPSVisitor);
|
||||||
|
|
||||||
|
@ -1758,13 +1752,14 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
||||||
osgParticle::ParticleSystem *ps = static_cast<osgParticle::ParticleSystem *>(findPSVisitor.mFoundNodes[i]);
|
osgParticle::ParticleSystem *ps = static_cast<osgParticle::ParticleSystem *>(findPSVisitor.mFoundNodes[i]);
|
||||||
|
|
||||||
osg::ref_ptr<osgParticle::ModularProgram> program (new osgParticle::ModularProgram);
|
osg::ref_ptr<osgParticle::ModularProgram> program (new osgParticle::ModularProgram);
|
||||||
|
if (!mIsStorm)
|
||||||
program->addOperator(new WrapAroundOperator(mCamera,osg::Vec3(1024,1024,800)));
|
program->addOperator(new WrapAroundOperator(mCamera,osg::Vec3(1024,1024,800)));
|
||||||
|
program->addOperator(new WeatherAlphaOperator(mEffectFade, false));
|
||||||
program->setParticleSystem(ps);
|
program->setParticleSystem(ps);
|
||||||
mParticleNode->addChild(program);
|
mParticleNode->addChild(program);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (mClouds != weather.mCloudTexture)
|
if (mClouds != weather.mCloudTexture)
|
||||||
{
|
{
|
||||||
|
@ -1848,11 +1843,7 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
||||||
|
|
||||||
mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0);
|
mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0);
|
||||||
|
|
||||||
if (mRainFader)
|
mEffectFade = weather.mEffectFade;
|
||||||
mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold?
|
|
||||||
|
|
||||||
for (AlphaFader* fader : mParticleFaders)
|
|
||||||
fader->setAlpha(weather.mEffectFade);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float SkyManager::getBaseWindSpeed() const
|
float SkyManager::getBaseWindSpeed() const
|
||||||
|
|
|
@ -203,7 +203,6 @@ namespace MWRender
|
||||||
|
|
||||||
osg::ref_ptr<osg::PositionAttitudeTransform> mParticleNode;
|
osg::ref_ptr<osg::PositionAttitudeTransform> mParticleNode;
|
||||||
osg::ref_ptr<osg::Node> mParticleEffect;
|
osg::ref_ptr<osg::Node> mParticleEffect;
|
||||||
std::vector<osg::ref_ptr<AlphaFader> > mParticleFaders;
|
|
||||||
osg::ref_ptr<UnderwaterSwitchCallback> mUnderwaterSwitch;
|
osg::ref_ptr<UnderwaterSwitchCallback> mUnderwaterSwitch;
|
||||||
|
|
||||||
osg::ref_ptr<osg::PositionAttitudeTransform> mCloudNode;
|
osg::ref_ptr<osg::PositionAttitudeTransform> mCloudNode;
|
||||||
|
@ -230,7 +229,6 @@ namespace MWRender
|
||||||
osg::ref_ptr<osgParticle::BoxPlacer> mPlacer;
|
osg::ref_ptr<osgParticle::BoxPlacer> mPlacer;
|
||||||
osg::ref_ptr<RainCounter> mCounter;
|
osg::ref_ptr<RainCounter> mCounter;
|
||||||
osg::ref_ptr<RainShooter> mRainShooter;
|
osg::ref_ptr<RainShooter> mRainShooter;
|
||||||
osg::ref_ptr<RainFader> mRainFader;
|
|
||||||
|
|
||||||
bool mCreated;
|
bool mCreated;
|
||||||
|
|
||||||
|
@ -273,7 +271,7 @@ namespace MWRender
|
||||||
bool mEnabled;
|
bool mEnabled;
|
||||||
bool mSunEnabled;
|
bool mSunEnabled;
|
||||||
|
|
||||||
float mWeatherAlpha;
|
float mEffectFade;
|
||||||
|
|
||||||
osg::Vec4f mMoonScriptColor;
|
osg::Vec4f mMoonScriptColor;
|
||||||
};
|
};
|
||||||
|
|
|
@ -187,6 +187,9 @@ namespace MWScript
|
||||||
.getCreatureStats(ptr)
|
.getCreatureStats(ptr)
|
||||||
.getDynamic(mIndex)
|
.getDynamic(mIndex)
|
||||||
.getCurrent();
|
.getCurrent();
|
||||||
|
// GetMagicka shouldn't return negative values
|
||||||
|
if(mIndex == 1 && value < 0)
|
||||||
|
value = 0;
|
||||||
}
|
}
|
||||||
runtime.push (value);
|
runtime.push (value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,7 @@ namespace MWWorld
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
float ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient,
|
void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient,
|
||||||
bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture)
|
bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture)
|
||||||
{
|
{
|
||||||
state.mNode = new osg::PositionAttitudeTransform;
|
state.mNode = new osg::PositionAttitudeTransform;
|
||||||
|
@ -258,7 +258,6 @@ namespace MWWorld
|
||||||
state.mNode->accept(assignVisitor);
|
state.mNode->accept(assignVisitor);
|
||||||
|
|
||||||
MWRender::overrideFirstRootTexture(texture, mResourceSystem, projectile);
|
MWRender::overrideFirstRootTexture(texture, mResourceSystem, projectile);
|
||||||
return projectile->getBound().radius();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectileManager::update(State& state, float duration)
|
void ProjectileManager::update(State& state, float duration)
|
||||||
|
@ -322,7 +321,8 @@ namespace MWWorld
|
||||||
|
|
||||||
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects);
|
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects);
|
||||||
|
|
||||||
const auto radius = createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, lightDiffuseColor, texture);
|
auto model = ptr.getClass().getModel(ptr);
|
||||||
|
createModel(state, model, pos, orient, true, true, lightDiffuseColor, texture);
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
for (const std::string &soundid : state.mSoundIds)
|
for (const std::string &soundid : state.mSoundIds)
|
||||||
|
@ -333,7 +333,10 @@ namespace MWWorld
|
||||||
state.mSounds.push_back(sound);
|
state.mSounds.push_back(sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mProjectileId = mPhysics->addProjectile(caster, pos, radius, false);
|
// in case there are multiple effects, the model is a dummy without geometry. Use the second effect for physics shape
|
||||||
|
if (state.mIdMagic.size() > 1)
|
||||||
|
model = "meshes\\" + MWBase::Environment::get().getWorld()->getStore().get<ESM::Weapon>().find(state.mIdMagic.at(1))->mModel;
|
||||||
|
state.mProjectileId = mPhysics->addProjectile(caster, pos, model, true, false);
|
||||||
state.mToDelete = false;
|
state.mToDelete = false;
|
||||||
mMagicBolts.push_back(state);
|
mMagicBolts.push_back(state);
|
||||||
}
|
}
|
||||||
|
@ -353,11 +356,12 @@ namespace MWWorld
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId());
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId());
|
||||||
MWWorld::Ptr ptr = ref.getPtr();
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
|
||||||
createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false, osg::Vec4(0,0,0,0));
|
const auto model = ptr.getClass().getModel(ptr);
|
||||||
|
createModel(state, model, pos, orient, false, false, osg::Vec4(0,0,0,0));
|
||||||
if (!ptr.getClass().getEnchantment(ptr).empty())
|
if (!ptr.getClass().getEnchantment(ptr).empty())
|
||||||
SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr));
|
SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr));
|
||||||
|
|
||||||
state.mProjectileId = mPhysics->addProjectile(actor, pos, 1.f, true);
|
state.mProjectileId = mPhysics->addProjectile(actor, pos, model, false, true);
|
||||||
state.mToDelete = false;
|
state.mToDelete = false;
|
||||||
mProjectiles.push_back(state);
|
mProjectiles.push_back(state);
|
||||||
}
|
}
|
||||||
|
@ -643,7 +647,7 @@ namespace MWWorld
|
||||||
int weaponType = ptr.get<ESM::Weapon>()->mBase->mData.mType;
|
int weaponType = ptr.get<ESM::Weapon>()->mBase->mData.mType;
|
||||||
state.mThrown = MWMechanics::getWeaponType(weaponType)->mWeaponClass == ESM::WeaponType::Thrown;
|
state.mThrown = MWMechanics::getWeaponType(weaponType)->mWeaponClass == ESM::WeaponType::Thrown;
|
||||||
|
|
||||||
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), 1.f, true);
|
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, false, true);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -695,8 +699,8 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects);
|
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects);
|
||||||
const auto radius = createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture);
|
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture);
|
||||||
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), radius, false);
|
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, true, false);
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
for (const std::string &soundid : state.mSoundIds)
|
for (const std::string &soundid : state.mSoundIds)
|
||||||
|
|
|
@ -130,7 +130,7 @@ namespace MWWorld
|
||||||
void moveProjectiles(float dt);
|
void moveProjectiles(float dt);
|
||||||
void moveMagicBolts(float dt);
|
void moveMagicBolts(float dt);
|
||||||
|
|
||||||
float createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient,
|
void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient,
|
||||||
bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture = "");
|
bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture = "");
|
||||||
void update (State& state, float duration);
|
void update (State& state, float duration);
|
||||||
|
|
||||||
|
|
|
@ -666,13 +666,19 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
if (!cell)
|
if (!cell)
|
||||||
cell = mWorldScene->getCurrentCell();
|
cell = mWorldScene->getCurrentCell();
|
||||||
|
return getCellName(cell->getCell());
|
||||||
|
}
|
||||||
|
|
||||||
if (!cell->getCell()->isExterior() || !cell->getCell()->mName.empty())
|
std::string World::getCellName(const ESM::Cell* cell) const
|
||||||
return cell->getCell()->mName;
|
{
|
||||||
|
if (cell)
|
||||||
|
{
|
||||||
|
if (!cell->isExterior() || !cell->mName.empty())
|
||||||
|
return cell->mName;
|
||||||
|
|
||||||
if (const ESM::Region* region = mStore.get<ESM::Region>().search (cell->getCell()->mRegion))
|
if (const ESM::Region* region = mStore.get<ESM::Region>().search (cell->mRegion))
|
||||||
return region->mName;
|
return region->mName;
|
||||||
|
}
|
||||||
return mStore.get<ESM::GameSetting>().find ("sDefaultCellname")->mValue.getString();
|
return mStore.get<ESM::GameSetting>().find ("sDefaultCellname")->mValue.getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1903,6 +1909,13 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
doPhysics (duration, frameStart, frameNumber, stats);
|
doPhysics (duration, frameStart, frameNumber, stats);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// zero the async stats if we are paused
|
||||||
|
stats.setAttribute(frameNumber, "physicsworker_time_begin", 0);
|
||||||
|
stats.setAttribute(frameNumber, "physicsworker_time_taken", 0);
|
||||||
|
stats.setAttribute(frameNumber, "physicsworker_time_end", 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::updatePlayer()
|
void World::updatePlayer()
|
||||||
|
@ -3051,7 +3064,7 @@ namespace MWWorld
|
||||||
// Check mana
|
// Check mana
|
||||||
bool godmode = (isPlayer && mGodMode);
|
bool godmode = (isPlayer && mGodMode);
|
||||||
MWMechanics::DynamicStat<float> magicka = stats.getMagicka();
|
MWMechanics::DynamicStat<float> magicka = stats.getMagicka();
|
||||||
if (magicka.getCurrent() < spell->mData.mCost && !godmode)
|
if (spell->mData.mCost > 0 && magicka.getCurrent() < spell->mData.mCost && !godmode)
|
||||||
{
|
{
|
||||||
message = "#{sMagicInsufficientSP}";
|
message = "#{sMagicInsufficientSP}";
|
||||||
fail = true;
|
fail = true;
|
||||||
|
|
|
@ -286,6 +286,7 @@ namespace MWWorld
|
||||||
///
|
///
|
||||||
/// \note If cell==0, the cell the player is currently in will be used instead to
|
/// \note If cell==0, the cell the player is currently in will be used instead to
|
||||||
/// generate a name.
|
/// generate a name.
|
||||||
|
std::string getCellName(const ESM::Cell* cell) const override;
|
||||||
|
|
||||||
void removeRefScript (MWWorld::RefData *ref) override;
|
void removeRefScript (MWWorld::RefData *ref) override;
|
||||||
//< Remove the script attached to ref from mLocalScripts
|
//< Remove the script attached to ref from mLocalScripts
|
||||||
|
|
|
@ -15,6 +15,7 @@ if (GTEST_FOUND AND GMOCK_FOUND)
|
||||||
esm/test_fixed_string.cpp
|
esm/test_fixed_string.cpp
|
||||||
|
|
||||||
misc/test_stringops.cpp
|
misc/test_stringops.cpp
|
||||||
|
misc/test_endianness.cpp
|
||||||
|
|
||||||
nifloader/testbulletnifloader.cpp
|
nifloader/testbulletnifloader.cpp
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,17 @@ namespace
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <std::size_t size>
|
||||||
|
btHeightfieldTerrainShape makeSquareHeightfieldTerrainShape(const std::array<btScalar, size>& values,
|
||||||
|
btScalar heightScale = 1, int upAxis = 2, PHY_ScalarType heightDataType = PHY_FLOAT, bool flipQuadEdges = false)
|
||||||
|
{
|
||||||
|
const int width = static_cast<int>(std::sqrt(size));
|
||||||
|
const btScalar min = *std::min_element(values.begin(), values.end());
|
||||||
|
const btScalar max = *std::max_element(values.begin(), values.end());
|
||||||
|
const btScalar greater = std::max(std::abs(min), std::abs(max));
|
||||||
|
return btHeightfieldTerrainShape(width, width, values.data(), heightScale, -greater, greater, upAxis, heightDataType, flipQuadEdges);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty)
|
TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty)
|
||||||
{
|
{
|
||||||
EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut),
|
EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut),
|
||||||
|
@ -108,7 +119,7 @@ namespace
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
@ -154,7 +165,7 @@ namespace
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape heightfieldShape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape heightfieldShape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
heightfieldShape.setLocalScaling(btVector3(128, 128, 1));
|
heightfieldShape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
btBoxShape boxShape(btVector3(20, 20, 100));
|
btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
|
@ -238,7 +249,7 @@ namespace
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape heightfieldShape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape heightfieldShape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
heightfieldShape.setLocalScaling(btVector3(128, 128, 1));
|
heightfieldShape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
btBoxShape boxShape(btVector3(20, 20, 100));
|
btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
|
@ -325,7 +336,7 @@ namespace
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
const std::array<btScalar, 5 * 5> heightfieldData2 {{
|
const std::array<btScalar, 5 * 5> heightfieldData2 {{
|
||||||
|
@ -335,7 +346,7 @@ namespace
|
||||||
-25, -25, -25, -25, -25,
|
-25, -25, -25, -25, -25,
|
||||||
-25, -25, -25, -25, -25,
|
-25, -25, -25, -25, -25,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shape2(5, 5, heightfieldData2.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shape2 = makeSquareHeightfieldTerrainShape(heightfieldData2);
|
||||||
shape2.setLocalScaling(btVector3(128, 128, 1));
|
shape2.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
@ -382,7 +393,7 @@ namespace
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
std::array<btScalar, 5 * 5> heightfieldDataAvoid {{
|
std::array<btScalar, 5 * 5> heightfieldDataAvoid {{
|
||||||
|
@ -392,7 +403,7 @@ namespace
|
||||||
-25, -25, -25, -25, -25,
|
-25, -25, -25, -25, -25,
|
||||||
-25, -25, -25, -25, -25,
|
-25, -25, -25, -25, -25,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shapeAvoid(5, 5, heightfieldDataAvoid.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shapeAvoid = makeSquareHeightfieldTerrainShape(heightfieldDataAvoid);
|
||||||
shapeAvoid.setLocalScaling(btVector3(128, 128, 1));
|
shapeAvoid.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
@ -439,7 +450,7 @@ namespace
|
||||||
-50, -100, -150, -100, -100,
|
-50, -100, -150, -100, -100,
|
||||||
0, -50, -100, -100, -100,
|
0, -50, -100, -100, -100,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
@ -487,7 +498,7 @@ namespace
|
||||||
0, -100, -100, -100, -100, -100, 0,
|
0, -100, -100, -100, -100, -100, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shape(7, 7, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
@ -534,7 +545,7 @@ namespace
|
||||||
0, -100, -100, -100, -100, -100, 0,
|
0, -100, -100, -100, -100, -100, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shape(7, 7, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
@ -581,7 +592,7 @@ namespace
|
||||||
0, -100, -100, -100, -100, -100, 0,
|
0, -100, -100, -100, -100, -100, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shape(7, 7, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
@ -626,7 +637,7 @@ namespace
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
@ -680,7 +691,7 @@ namespace
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
@ -711,7 +722,7 @@ namespace
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
0, -25, -100, -100, -100,
|
0, -25, -100, -100, -100,
|
||||||
}};
|
}};
|
||||||
btHeightfieldTerrainShape heightfieldShape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
btHeightfieldTerrainShape heightfieldShape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
heightfieldShape.setLocalScaling(btVector3(128, 128, 1));
|
heightfieldShape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
const std::vector<btBoxShape> boxShapes(100, btVector3(20, 20, 100));
|
const std::vector<btBoxShape> boxShapes(100, btVector3(20, 20, 100));
|
||||||
|
@ -802,4 +813,26 @@ namespace
|
||||||
EXPECT_GT(duration, mSettings.mMinUpdateInterval)
|
EXPECT_GT(duration, mSettings.mMinUpdateInterval)
|
||||||
<< std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(duration).count() << " ms";
|
<< std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(duration).count() << " ms";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DetourNavigatorNavigatorTest, update_then_raycast_should_return_position)
|
||||||
|
{
|
||||||
|
const std::array<btScalar, 5 * 5> heightfieldData {{
|
||||||
|
0, 0, 0, 0, 0,
|
||||||
|
0, -25, -25, -25, -25,
|
||||||
|
0, -25, -100, -100, -100,
|
||||||
|
0, -25, -100, -100, -100,
|
||||||
|
0, -25, -100, -100, -100,
|
||||||
|
}};
|
||||||
|
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData);
|
||||||
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
|
||||||
|
mNavigator->update(mPlayerPosition);
|
||||||
|
mNavigator->wait();
|
||||||
|
|
||||||
|
const auto result = mNavigator->raycast(mAgentHalfExtents, mStart, mEnd, Flag_walk);
|
||||||
|
|
||||||
|
ASSERT_THAT(result, Optional(Vec3fEq(mEnd.x(), mEnd.y(), 1.87719)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,6 @@
|
||||||
#include <components/detournavigator/settingsutils.hpp>
|
#include <components/detournavigator/settingsutils.hpp>
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
||||||
#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
|
|
||||||
#include <BulletCollision/CollisionShapes/btTriangleMesh.h>
|
|
||||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
|
||||||
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
|
|
122
apps/openmw_test_suite/misc/test_endianness.cpp
Normal file
122
apps/openmw_test_suite/misc/test_endianness.cpp
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "components/misc/endianness.hpp"
|
||||||
|
|
||||||
|
struct EndiannessTest : public ::testing::Test {};
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace1)
|
||||||
|
{
|
||||||
|
uint8_t zero=0x00;
|
||||||
|
uint8_t ff=0xFF;
|
||||||
|
uint8_t fortytwo=0x42;
|
||||||
|
uint8_t half=128;
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x00);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(ff);
|
||||||
|
EXPECT_EQ(ff, 0xFF);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(fortytwo);
|
||||||
|
EXPECT_EQ(fortytwo, 0x42);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(half);
|
||||||
|
EXPECT_EQ(half, 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace2)
|
||||||
|
{
|
||||||
|
uint16_t zero = 0x0000;
|
||||||
|
uint16_t ffff = 0xFFFF;
|
||||||
|
uint16_t n12 = 0x0102;
|
||||||
|
uint16_t fortytwo = 0x0042;
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x0000);
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x0000);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFF);
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFF);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(n12);
|
||||||
|
EXPECT_EQ(n12, 0x0201);
|
||||||
|
Misc::swapEndiannessInplace(n12);
|
||||||
|
EXPECT_EQ(n12, 0x0102);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(fortytwo);
|
||||||
|
EXPECT_EQ(fortytwo, 0x4200);
|
||||||
|
Misc::swapEndiannessInplace(fortytwo);
|
||||||
|
EXPECT_EQ(fortytwo, 0x0042);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace4)
|
||||||
|
{
|
||||||
|
uint32_t zero = 0x00000000;
|
||||||
|
uint32_t n1234 = 0x01020304;
|
||||||
|
uint32_t ffff = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x00000000);
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x00000000);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(n1234);
|
||||||
|
EXPECT_EQ(n1234, 0x04030201);
|
||||||
|
Misc::swapEndiannessInplace(n1234);
|
||||||
|
EXPECT_EQ(n1234, 0x01020304);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFFFFFF);
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace8)
|
||||||
|
{
|
||||||
|
uint64_t zero = 0x0000'0000'0000'0000;
|
||||||
|
uint64_t n1234 = 0x0102'0304'0506'0708;
|
||||||
|
uint64_t ffff = 0xFFFF'FFFF'FFFF'FFFF;
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x0000'0000'0000'0000);
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x0000'0000'0000'0000);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFF'FFFF'FFFF'FFFF);
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFF'FFFF'FFFF'FFFF);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(n1234);
|
||||||
|
EXPECT_EQ(n1234, 0x0807'0605'0403'0201);
|
||||||
|
Misc::swapEndiannessInplace(n1234);
|
||||||
|
EXPECT_EQ(n1234, 0x0102'0304'0506'0708);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace_float)
|
||||||
|
{
|
||||||
|
const uint32_t original = 0x4023d70a;
|
||||||
|
const uint32_t expected = 0x0ad72340;
|
||||||
|
|
||||||
|
float number;
|
||||||
|
memcpy(&number, &original, sizeof(original));
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(number);
|
||||||
|
|
||||||
|
EXPECT_TRUE(!memcmp(&number, &expected, sizeof(expected)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace_double)
|
||||||
|
{
|
||||||
|
const uint64_t original = 0x040047ae147ae147ul;
|
||||||
|
const uint64_t expected = 0x47e17a14ae470004ul;
|
||||||
|
|
||||||
|
double number;
|
||||||
|
memcpy(&number, &original, sizeof(original));
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(number);
|
||||||
|
|
||||||
|
EXPECT_TRUE(!memcmp(&number, &expected, sizeof(expected)) );
|
||||||
|
}
|
|
@ -95,9 +95,9 @@ void Wizard::ExistingInstallationPage::on_browseButton_clicked()
|
||||||
{
|
{
|
||||||
QString selectedFile = QFileDialog::getOpenFileName(
|
QString selectedFile = QFileDialog::getOpenFileName(
|
||||||
this,
|
this,
|
||||||
tr("Select master file"),
|
tr("Select Morrowind.esm (located in Data Files)"),
|
||||||
QDir::currentPath(),
|
QDir::currentPath(),
|
||||||
QString(tr("Morrowind master file (*.esm)")),
|
QString(tr("Morrowind master file (Morrowind.esm)")),
|
||||||
nullptr,
|
nullptr,
|
||||||
QFileDialog::DontResolveSymlinks);
|
QFileDialog::DontResolveSymlinks);
|
||||||
|
|
||||||
|
@ -110,7 +110,18 @@ void Wizard::ExistingInstallationPage::on_browseButton_clicked()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mWizard->findFiles(QLatin1String("Morrowind"), info.absolutePath()))
|
if (!mWizard->findFiles(QLatin1String("Morrowind"), info.absolutePath()))
|
||||||
return; // No valid Morrowind installation found
|
{
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setWindowTitle(tr("Error detecting Morrowind files"));
|
||||||
|
msgBox.setIcon(QMessageBox::Warning);
|
||||||
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
|
msgBox.setText(QObject::tr(
|
||||||
|
"<b>Morrowind.bsa</b> is missing!<br>\
|
||||||
|
Make sure your Morrowind installation is complete."
|
||||||
|
));
|
||||||
|
msgBox.exec();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString path(QDir::toNativeSeparators(info.absolutePath()));
|
QString path(QDir::toNativeSeparators(info.absolutePath()));
|
||||||
QList<QListWidgetItem*> items = installationsList->findItems(path, Qt::MatchExactly);
|
QList<QListWidgetItem*> items = installationsList->findItems(path, Qt::MatchExactly);
|
||||||
|
|
|
@ -15,6 +15,17 @@
|
||||||
include(LibFindMacros)
|
include(LibFindMacros)
|
||||||
include(Findosg_functions)
|
include(Findosg_functions)
|
||||||
|
|
||||||
|
if (NOT OSGPlugins_LIB_DIR)
|
||||||
|
unset(OSGPlugins_LIB_DIR)
|
||||||
|
foreach(OSGDB_LIB ${OSGDB_LIBRARY})
|
||||||
|
# Skip library type names
|
||||||
|
if(EXISTS ${OSGDB_LIB} AND NOT IS_DIRECTORY ${OSGDB_LIB})
|
||||||
|
get_filename_component(OSG_LIB_DIR ${OSGDB_LIB} DIRECTORY)
|
||||||
|
list(APPEND OSGPlugins_LIB_DIR "${OSG_LIB_DIR}/osgPlugins-${OPENSCENEGRAPH_VERSION}")
|
||||||
|
endif()
|
||||||
|
endforeach(OSGDB_LIB)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT OSGPlugins_LIB_DIR)
|
if (NOT OSGPlugins_LIB_DIR)
|
||||||
set(_mode WARNING)
|
set(_mode WARNING)
|
||||||
if (OSGPlugins_FIND_REQUIRED)
|
if (OSGPlugins_FIND_REQUIRED)
|
||||||
|
|
10
cmake/WholeArchive.cmake
Normal file
10
cmake/WholeArchive.cmake
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
function (get_whole_archive_options OUT_VAR)
|
||||||
|
# We use --whole-archive because OSG plugins use registration.
|
||||||
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
|
set(${OUT_VAR} -Wl,--whole-archive ${ARGN} -Wl,--no-whole-archive PARENT_SCOPE)
|
||||||
|
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||||
|
set(${OUT_VAR} -Wl,-all_load ${ARGN} -Wl,-noall_load PARENT_SCOPE)
|
||||||
|
else ()
|
||||||
|
message(FATAL_ERROR "get_whole_archive_options not implemented for CMAKE_CXX_COMPILER_ID ${CMAKE_CXX_COMPILER_ID}")
|
||||||
|
endif()
|
||||||
|
endfunction ()
|
|
@ -181,6 +181,7 @@ add_component_dir(detournavigator
|
||||||
settings
|
settings
|
||||||
navigator
|
navigator
|
||||||
findrandompointaroundcircle
|
findrandompointaroundcircle
|
||||||
|
raycast
|
||||||
)
|
)
|
||||||
|
|
||||||
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
||||||
|
@ -245,7 +246,7 @@ target_link_libraries(components
|
||||||
RecastNavigation::Recast
|
RecastNavigation::Recast
|
||||||
)
|
)
|
||||||
|
|
||||||
if (BULLET_USE_DOUBLES AND (UBUNTU_FOUND OR DEBIAN_FOUND))
|
if (BULLET_USE_DOUBLES AND (UBUNTU_FOUND OR DEBIAN_FOUND) AND OPENMW_USE_SYSTEM_BULLET)
|
||||||
target_link_libraries(components BulletCollision-float64 LinearMath-float64)
|
target_link_libraries(components BulletCollision-float64 LinearMath-float64)
|
||||||
else()
|
else()
|
||||||
target_link_libraries(components ${BULLET_LIBRARIES})
|
target_link_libraries(components ${BULLET_LIBRARIES})
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||||
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||||
|
|
|
@ -20,16 +20,7 @@ namespace DetourNavigator
|
||||||
dtQueryFilter queryFilter;
|
dtQueryFilter queryFilter;
|
||||||
queryFilter.setIncludeFlags(includeFlags);
|
queryFilter.setIncludeFlags(includeFlags);
|
||||||
|
|
||||||
dtPolyRef startRef = 0;
|
dtPolyRef startRef = findNearestPolyExpanding(navMeshQuery, queryFilter, start, halfExtents);
|
||||||
osg::Vec3f startPolygonPosition;
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
{
|
|
||||||
const auto status = navMeshQuery.findNearestPoly(start.ptr(), (halfExtents * (1 << i)).ptr(), &queryFilter,
|
|
||||||
&startRef, startPolygonPosition.ptr());
|
|
||||||
if (!dtStatusFailed(status) && startRef != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startRef == 0)
|
if (startRef == 0)
|
||||||
return std::optional<osg::Vec3f>();
|
return std::optional<osg::Vec3f>();
|
||||||
|
|
||||||
|
|
|
@ -108,13 +108,13 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
// Find steer target.
|
// Find steer target.
|
||||||
SteerTarget result;
|
SteerTarget result;
|
||||||
const int MAX_STEER_POINTS = 3;
|
constexpr int maxSteerPoints = 3;
|
||||||
std::array<float, MAX_STEER_POINTS * 3> steerPath;
|
std::array<float, maxSteerPoints * 3> steerPath;
|
||||||
std::array<unsigned char, MAX_STEER_POINTS> steerPathFlags;
|
std::array<unsigned char, maxSteerPoints> steerPathFlags;
|
||||||
std::array<dtPolyRef, MAX_STEER_POINTS> steerPathPolys;
|
std::array<dtPolyRef, maxSteerPoints> steerPathPolys;
|
||||||
int nsteerPath = 0;
|
int nsteerPath = 0;
|
||||||
navQuery.findStraightPath(startPos.ptr(), endPos.ptr(), path.data(), int(path.size()), steerPath.data(),
|
navQuery.findStraightPath(startPos.ptr(), endPos.ptr(), path.data(), int(path.size()), steerPath.data(),
|
||||||
steerPathFlags.data(), steerPathPolys.data(), &nsteerPath, MAX_STEER_POINTS);
|
steerPathFlags.data(), steerPathPolys.data(), &nsteerPath, maxSteerPoints);
|
||||||
assert(nsteerPath >= 0);
|
assert(nsteerPath >= 0);
|
||||||
if (!nsteerPath)
|
if (!nsteerPath)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
@ -140,4 +140,17 @@ namespace DetourNavigator
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dtPolyRef findNearestPolyExpanding(const dtNavMeshQuery& query, const dtQueryFilter& filter,
|
||||||
|
const osg::Vec3f& center, const osg::Vec3f& halfExtents)
|
||||||
|
{
|
||||||
|
dtPolyRef ref = 0;
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
const dtStatus status = query.findNearestPoly(center.ptr(), (halfExtents * (1 << i)).ptr(), &filter, &ref, nullptr);
|
||||||
|
if (!dtStatusFailed(status) && ref != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,9 @@ namespace DetourNavigator
|
||||||
return dtStatusSucceed(status);
|
return dtStatusSucceed(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dtPolyRef findNearestPolyExpanding(const dtNavMeshQuery& query, const dtQueryFilter& filter,
|
||||||
|
const osg::Vec3f& center, const osg::Vec3f& halfExtents);
|
||||||
|
|
||||||
struct MoveAlongSurfaceResult
|
struct MoveAlongSurfaceResult
|
||||||
{
|
{
|
||||||
osg::Vec3f mResultPos;
|
osg::Vec3f mResultPos;
|
||||||
|
@ -163,7 +166,7 @@ namespace DetourNavigator
|
||||||
osg::Vec3f targetPos;
|
osg::Vec3f targetPos;
|
||||||
navMeshQuery.closestPointOnPoly(polygonPath.back(), end.ptr(), targetPos.ptr(), nullptr);
|
navMeshQuery.closestPointOnPoly(polygonPath.back(), end.ptr(), targetPos.ptr(), nullptr);
|
||||||
|
|
||||||
const float SLOP = 0.01f;
|
constexpr float slop = 0.01f;
|
||||||
|
|
||||||
*out++ = iterPos;
|
*out++ = iterPos;
|
||||||
|
|
||||||
|
@ -174,7 +177,7 @@ namespace DetourNavigator
|
||||||
while (!polygonPath.empty() && smoothPathSize < maxSmoothPathSize)
|
while (!polygonPath.empty() && smoothPathSize < maxSmoothPathSize)
|
||||||
{
|
{
|
||||||
// Find location to steer towards.
|
// Find location to steer towards.
|
||||||
const auto steerTarget = getSteerTarget(navMeshQuery, iterPos, targetPos, SLOP, polygonPath);
|
const auto steerTarget = getSteerTarget(navMeshQuery, iterPos, targetPos, slop, polygonPath);
|
||||||
|
|
||||||
if (!steerTarget)
|
if (!steerTarget)
|
||||||
break;
|
break;
|
||||||
|
@ -206,7 +209,7 @@ namespace DetourNavigator
|
||||||
iterPos.y() = h;
|
iterPos.y() = h;
|
||||||
|
|
||||||
// Handle end of path and off-mesh links when close enough.
|
// Handle end of path and off-mesh links when close enough.
|
||||||
if (endOfPath && inRange(iterPos, steerTarget->steerPos, SLOP, 1.0f))
|
if (endOfPath && inRange(iterPos, steerTarget->steerPos, slop, 1.0f))
|
||||||
{
|
{
|
||||||
// Reached end of path.
|
// Reached end of path.
|
||||||
iterPos = targetPos;
|
iterPos = targetPos;
|
||||||
|
@ -214,7 +217,7 @@ namespace DetourNavigator
|
||||||
++smoothPathSize;
|
++smoothPathSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (offMeshConnection && inRange(iterPos, steerTarget->steerPos, SLOP, 1.0f))
|
else if (offMeshConnection && inRange(iterPos, steerTarget->steerPos, slop, 1.0f))
|
||||||
{
|
{
|
||||||
// Advance the path up to and over the off-mesh connection.
|
// Advance the path up to and over the off-mesh connection.
|
||||||
dtPolyRef prevRef = 0;
|
dtPolyRef prevRef = 0;
|
||||||
|
@ -282,29 +285,11 @@ namespace DetourNavigator
|
||||||
queryFilter.setAreaCost(AreaType_pathgrid, areaCosts.mPathgrid);
|
queryFilter.setAreaCost(AreaType_pathgrid, areaCosts.mPathgrid);
|
||||||
queryFilter.setAreaCost(AreaType_ground, areaCosts.mGround);
|
queryFilter.setAreaCost(AreaType_ground, areaCosts.mGround);
|
||||||
|
|
||||||
dtPolyRef startRef = 0;
|
dtPolyRef startRef = findNearestPolyExpanding(navMeshQuery, queryFilter, start, halfExtents);
|
||||||
osg::Vec3f startPolygonPosition;
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
{
|
|
||||||
const auto status = navMeshQuery.findNearestPoly(start.ptr(), (halfExtents * (1 << i)).ptr(), &queryFilter,
|
|
||||||
&startRef, startPolygonPosition.ptr());
|
|
||||||
if (!dtStatusFailed(status) && startRef != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startRef == 0)
|
if (startRef == 0)
|
||||||
return Status::StartPolygonNotFound;
|
return Status::StartPolygonNotFound;
|
||||||
|
|
||||||
dtPolyRef endRef = 0;
|
dtPolyRef endRef = findNearestPolyExpanding(navMeshQuery, queryFilter, end, halfExtents);
|
||||||
osg::Vec3f endPolygonPosition;
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
{
|
|
||||||
const auto status = navMeshQuery.findNearestPoly(end.ptr(), (halfExtents * (1 << i)).ptr(), &queryFilter,
|
|
||||||
&endRef, endPolygonPosition.ptr());
|
|
||||||
if (!dtStatusFailed(status) && endRef != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endRef == 0)
|
if (endRef == 0)
|
||||||
return Status::EndPolygonNotFound;
|
return Status::EndPolygonNotFound;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "findrandompointaroundcircle.hpp"
|
#include "findrandompointaroundcircle.hpp"
|
||||||
#include "navigator.hpp"
|
#include "navigator.hpp"
|
||||||
|
#include "raycast.hpp"
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
|
@ -17,4 +18,19 @@ namespace DetourNavigator
|
||||||
return std::optional<osg::Vec3f>();
|
return std::optional<osg::Vec3f>();
|
||||||
return std::optional<osg::Vec3f>(fromNavMeshCoordinates(settings, *result));
|
return std::optional<osg::Vec3f>(fromNavMeshCoordinates(settings, *result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<osg::Vec3f> Navigator::raycast(const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start,
|
||||||
|
const osg::Vec3f& end, const Flags includeFlags) const
|
||||||
|
{
|
||||||
|
const auto navMesh = getNavMesh(agentHalfExtents);
|
||||||
|
if (navMesh == nullptr)
|
||||||
|
return {};
|
||||||
|
const auto settings = getSettings();
|
||||||
|
const auto result = DetourNavigator::raycast(navMesh->lockConst()->getImpl(),
|
||||||
|
toNavMeshCoordinates(settings, agentHalfExtents), toNavMeshCoordinates(settings, start),
|
||||||
|
toNavMeshCoordinates(settings, end), includeFlags, settings);
|
||||||
|
if (!result)
|
||||||
|
return {};
|
||||||
|
return fromNavMeshCoordinates(settings, *result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,6 +223,17 @@ namespace DetourNavigator
|
||||||
std::optional<osg::Vec3f> findRandomPointAroundCircle(const osg::Vec3f& agentHalfExtents,
|
std::optional<osg::Vec3f> findRandomPointAroundCircle(const osg::Vec3f& agentHalfExtents,
|
||||||
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags) const;
|
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief raycast finds farest navmesh point from start on a line from start to end that has path from start.
|
||||||
|
* @param agentHalfExtents allows to find navmesh for given actor.
|
||||||
|
* @param start of the line
|
||||||
|
* @param end of the line
|
||||||
|
* @param includeFlags setup allowed surfaces for actor to walk.
|
||||||
|
* @return not empty optional with position if point is found and empty optional if point is not found.
|
||||||
|
*/
|
||||||
|
std::optional<osg::Vec3f> raycast(const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start,
|
||||||
|
const osg::Vec3f& end, const Flags includeFlags) const;
|
||||||
|
|
||||||
virtual RecastMeshTiles getRecastMeshTiles() = 0;
|
virtual RecastMeshTiles getRecastMeshTiles() = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void update(const osg::Vec3f& /*playerPosition*/) override {}
|
void update(const osg::Vec3f& /*playerPosition*/) override {}
|
||||||
|
|
||||||
void setUpdatesEnabled(bool enabled) override {}
|
void setUpdatesEnabled(bool /*enabled*/) override {}
|
||||||
|
|
||||||
void wait() override {}
|
void wait() override {}
|
||||||
|
|
||||||
|
|
44
components/detournavigator/raycast.cpp
Normal file
44
components/detournavigator/raycast.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include "raycast.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
#include "findsmoothpath.hpp"
|
||||||
|
|
||||||
|
#include <DetourCommon.h>
|
||||||
|
#include <DetourNavMesh.h>
|
||||||
|
#include <DetourNavMeshQuery.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace DetourNavigator
|
||||||
|
{
|
||||||
|
std::optional<osg::Vec3f> raycast(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents,
|
||||||
|
const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const Settings& settings)
|
||||||
|
{
|
||||||
|
dtNavMeshQuery navMeshQuery;
|
||||||
|
if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
dtQueryFilter queryFilter;
|
||||||
|
queryFilter.setIncludeFlags(includeFlags);
|
||||||
|
|
||||||
|
dtPolyRef ref = 0;
|
||||||
|
if (dtStatus status = navMeshQuery.findNearestPoly(start.ptr(), halfExtents.ptr(), &queryFilter, &ref, nullptr);
|
||||||
|
dtStatusFailed(status) || ref == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const unsigned options = 0;
|
||||||
|
std::array<dtPolyRef, 16> path;
|
||||||
|
dtRaycastHit hit;
|
||||||
|
hit.path = path.data();
|
||||||
|
hit.maxPath = path.size();
|
||||||
|
if (dtStatus status = navMeshQuery.raycast(ref, start.ptr(), end.ptr(), &queryFilter, options, &hit);
|
||||||
|
dtStatusFailed(status) || hit.pathCount == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
osg::Vec3f hitPosition;
|
||||||
|
if (dtStatus status = navMeshQuery.closestPointOnPoly(path[hit.pathCount - 1], end.ptr(), hitPosition.ptr(), nullptr);
|
||||||
|
dtStatusFailed(status))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return hitPosition;
|
||||||
|
}
|
||||||
|
}
|
19
components/detournavigator/raycast.hpp
Normal file
19
components/detournavigator/raycast.hpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_RAYCAST_H
|
||||||
|
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RAYCAST_H
|
||||||
|
|
||||||
|
#include "flags.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
class dtNavMesh;
|
||||||
|
|
||||||
|
namespace DetourNavigator
|
||||||
|
{
|
||||||
|
struct Settings;
|
||||||
|
|
||||||
|
std::optional<osg::Vec3f> raycast(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents,
|
||||||
|
const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const Settings& settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "recasttempallocator.hpp"
|
#include "recasttempallocator.hpp"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
class RecastGlobalAllocator
|
class RecastGlobalAllocator
|
||||||
|
@ -32,7 +34,7 @@ namespace DetourNavigator
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(BufferType_perm == getDataPtrBufferType(ptr));
|
assert(BufferType_perm == getDataPtrBufferType(ptr));
|
||||||
::free(getPermDataPtrHeapPtr(ptr));
|
std::free(getPermDataPtrHeapPtr(ptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +58,7 @@ namespace DetourNavigator
|
||||||
|
|
||||||
static void* allocPerm(size_t size)
|
static void* allocPerm(size_t size)
|
||||||
{
|
{
|
||||||
const auto ptr = ::malloc(size + sizeof(std::size_t));
|
const auto ptr = std::malloc(size + sizeof(std::size_t));
|
||||||
if (rcUnlikely(!ptr))
|
if (rcUnlikely(!ptr))
|
||||||
return ptr;
|
return ptr;
|
||||||
setPermPtrBufferType(ptr, BufferType_perm);
|
setPermPtrBufferType(ptr, BufferType_perm);
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace DetourNavigator
|
||||||
|
|
||||||
inline float getTileSize(const Settings& settings)
|
inline float getTileSize(const Settings& settings)
|
||||||
{
|
{
|
||||||
return settings.mTileSize * settings.mCellSize;
|
return static_cast<float>(settings.mTileSize) * settings.mCellSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline TilePosition getTilePosition(const Settings& settings, const osg::Vec3f& position)
|
inline TilePosition getTilePosition(const Settings& settings, const osg::Vec3f& position)
|
||||||
|
@ -73,7 +73,7 @@ namespace DetourNavigator
|
||||||
|
|
||||||
inline float getBorderSize(const Settings& settings)
|
inline float getBorderSize(const Settings& settings)
|
||||||
{
|
{
|
||||||
return settings.mBorderSize * settings.mCellSize;
|
return static_cast<float>(settings.mBorderSize) * settings.mCellSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float getSwimLevel(const Settings& settings, const float agentHalfExtentsZ)
|
inline float getSwimLevel(const Settings& settings, const float agentHalfExtentsZ)
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace Misc
|
||||||
{
|
{
|
||||||
uint32_t v32;
|
uint32_t v32;
|
||||||
std::memcpy(&v32, &v, sizeof(T));
|
std::memcpy(&v32, &v, sizeof(T));
|
||||||
v32 = (v32 >> 24) | ((v32 >> 8) & 0xff00) | ((v32 & 0xff00) << 8) | v32 << 24;
|
v32 = (v32 >> 24) | ((v32 >> 8) & 0xff00) | ((v32 & 0xff00) << 8) | (v32 << 24);
|
||||||
std::memcpy(&v, &v32, sizeof(T));
|
std::memcpy(&v, &v32, sizeof(T));
|
||||||
}
|
}
|
||||||
if constexpr (sizeof(T) == 8)
|
if constexpr (sizeof(T) == 8)
|
||||||
|
|
56
components/misc/frameratelimiter.hpp
Normal file
56
components/misc/frameratelimiter.hpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_MISC_FRAMERATELIMITER_H
|
||||||
|
#define OPENMW_COMPONENTS_MISC_FRAMERATELIMITER_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace Misc
|
||||||
|
{
|
||||||
|
class FrameRateLimiter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <class Rep, class Ratio>
|
||||||
|
explicit FrameRateLimiter(std::chrono::duration<Rep, Ratio> maxFrameDuration,
|
||||||
|
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now())
|
||||||
|
: mMaxFrameDuration(std::chrono::duration_cast<std::chrono::steady_clock::duration>(maxFrameDuration))
|
||||||
|
, mLastMeasurement(now)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::chrono::steady_clock::duration getLastFrameDuration() const
|
||||||
|
{
|
||||||
|
return mLastFrameDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
void limit(std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now())
|
||||||
|
{
|
||||||
|
const auto passed = now - mLastMeasurement;
|
||||||
|
const auto left = mMaxFrameDuration - passed;
|
||||||
|
if (left > left.zero())
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(left);
|
||||||
|
mLastMeasurement = now + left;
|
||||||
|
mLastFrameDuration = mMaxFrameDuration;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mLastMeasurement = now;
|
||||||
|
mLastFrameDuration = passed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::chrono::steady_clock::duration mMaxFrameDuration;
|
||||||
|
std::chrono::steady_clock::time_point mLastMeasurement;
|
||||||
|
std::chrono::steady_clock::duration mLastFrameDuration;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Misc::FrameRateLimiter makeFrameRateLimiter(float frameRateLimit)
|
||||||
|
{
|
||||||
|
if (frameRateLimit > 0.0f)
|
||||||
|
return Misc::FrameRateLimiter(std::chrono::duration<float>(1.0f / frameRateLimit));
|
||||||
|
else
|
||||||
|
return Misc::FrameRateLimiter(std::chrono::steady_clock::duration::zero());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -32,7 +32,7 @@ namespace Resource
|
||||||
osg::Vec3f extents;
|
osg::Vec3f extents;
|
||||||
osg::Vec3f center;
|
osg::Vec3f center;
|
||||||
};
|
};
|
||||||
// Used for actors. mCollisionShape is used for actors only when we need to autogenerate collision box for creatures.
|
// Used for actors and projectiles. mCollisionShape is used for actors only when we need to autogenerate collision box for creatures.
|
||||||
// For now, use one file <-> one resource for simplicity.
|
// For now, use one file <-> one resource for simplicity.
|
||||||
CollisionBox mCollisionBox;
|
CollisionBox mCollisionBox;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btTriangleMesh.h>
|
#include <BulletCollision/CollisionShapes/btTriangleMesh.h>
|
||||||
|
|
||||||
|
#include <components/sceneutil/visitor.hpp>
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
#include <components/nifbullet/bulletnifloader.hpp>
|
#include <components/nifbullet/bulletnifloader.hpp>
|
||||||
|
@ -145,12 +146,32 @@ osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(const std::string &
|
||||||
|
|
||||||
osg::ref_ptr<const osg::Node> constNode (mSceneManager->getTemplate(normalized));
|
osg::ref_ptr<const osg::Node> constNode (mSceneManager->getTemplate(normalized));
|
||||||
osg::ref_ptr<osg::Node> node (const_cast<osg::Node*>(constNode.get())); // const-trickery required because there is no const version of NodeVisitor
|
osg::ref_ptr<osg::Node> node (const_cast<osg::Node*>(constNode.get())); // const-trickery required because there is no const version of NodeVisitor
|
||||||
|
|
||||||
|
// Check first if there's a custom collision node
|
||||||
|
unsigned int visitAllNodesMask = 0xffffffff;
|
||||||
|
SceneUtil::FindByNameVisitor nameFinder("Collision");
|
||||||
|
nameFinder.setTraversalMask(visitAllNodesMask);
|
||||||
|
nameFinder.setNodeMaskOverride(visitAllNodesMask);
|
||||||
|
node->accept(nameFinder);
|
||||||
|
if (nameFinder.mFoundNode)
|
||||||
|
{
|
||||||
|
NodeToShapeVisitor visitor;
|
||||||
|
visitor.setTraversalMask(visitAllNodesMask);
|
||||||
|
visitor.setNodeMaskOverride(visitAllNodesMask);
|
||||||
|
nameFinder.mFoundNode->accept(visitor);
|
||||||
|
shape = visitor.getShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a collision shape from the mesh
|
||||||
|
if (!shape)
|
||||||
|
{
|
||||||
NodeToShapeVisitor visitor;
|
NodeToShapeVisitor visitor;
|
||||||
node->accept(visitor);
|
node->accept(visitor);
|
||||||
shape = visitor.getShape();
|
shape = visitor.getShape();
|
||||||
if (!shape)
|
if (!shape)
|
||||||
return osg::ref_ptr<BulletShape>();
|
return osg::ref_ptr<BulletShape>();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mCache->addEntryToObjectCache(normalized, shape);
|
mCache->addEntryToObjectCache(normalized, shape);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <components/nifosg/nifloader.hpp>
|
#include <components/nifosg/nifloader.hpp>
|
||||||
#include <components/sceneutil/keyframe.hpp>
|
#include <components/sceneutil/keyframe.hpp>
|
||||||
#include <components/sceneutil/osgacontroller.hpp>
|
#include <components/sceneutil/osgacontroller.hpp>
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "animation.hpp"
|
#include "animation.hpp"
|
||||||
#include "objectcache.hpp"
|
#include "objectcache.hpp"
|
||||||
|
@ -17,11 +18,13 @@
|
||||||
namespace Resource
|
namespace Resource
|
||||||
{
|
{
|
||||||
|
|
||||||
RetrieveAnimationsVisitor::RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr<osgAnimation::BasicAnimationManager> animationManager) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target), mAnimationManager(animationManager) {}
|
RetrieveAnimationsVisitor::RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr<osgAnimation::BasicAnimationManager> animationManager,
|
||||||
|
const std::string& normalized, const VFS::Manager* vfs) :
|
||||||
|
osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target), mAnimationManager(animationManager), mNormalized(normalized), mVFS(vfs) {}
|
||||||
|
|
||||||
void RetrieveAnimationsVisitor::apply(osg::Node& node)
|
void RetrieveAnimationsVisitor::apply(osg::Node& node)
|
||||||
{
|
{
|
||||||
if (node.libraryName() == std::string("osgAnimation") && node.className() == std::string("Bone") && node.getName() == std::string("bip01"))
|
if (node.libraryName() == std::string("osgAnimation") && node.className() == std::string("Bone") && Misc::StringUtils::lowerCase(node.getName()) == std::string("bip01"))
|
||||||
{
|
{
|
||||||
osg::ref_ptr<SceneUtil::OsgAnimationController> callback = new SceneUtil::OsgAnimationController();
|
osg::ref_ptr<SceneUtil::OsgAnimationController> callback = new SceneUtil::OsgAnimationController();
|
||||||
|
|
||||||
|
@ -38,27 +41,19 @@ namespace Resource
|
||||||
|
|
||||||
osg::ref_ptr<Resource::Animation> mergedAnimationTrack = new Resource::Animation;
|
osg::ref_ptr<Resource::Animation> mergedAnimationTrack = new Resource::Animation;
|
||||||
std::string animationName = animation->getName();
|
std::string animationName = animation->getName();
|
||||||
std::string start = animationName + std::string(": start");
|
mergedAnimationTrack->setName(animationName);
|
||||||
std::string stop = animationName + std::string(": stop");
|
|
||||||
|
|
||||||
const osgAnimation::ChannelList& channels = animation->getChannels();
|
const osgAnimation::ChannelList& channels = animation->getChannels();
|
||||||
for (const auto& channel: channels)
|
for (const auto& channel: channels)
|
||||||
{
|
{
|
||||||
mergedAnimationTrack->addChannel(channel.get()->clone()); // is ->clone needed?
|
mergedAnimationTrack->addChannel(channel.get()->clone()); // is ->clone needed?
|
||||||
}
|
}
|
||||||
mergedAnimationTrack->setName(animation->getName());
|
|
||||||
callback->addMergedAnimationTrack(mergedAnimationTrack);
|
callback->addMergedAnimationTrack(mergedAnimationTrack);
|
||||||
|
|
||||||
float startTime = animation->getStartTime();
|
float startTime = animation->getStartTime();
|
||||||
float stopTime = startTime + animation->getDuration();
|
float stopTime = startTime + animation->getDuration();
|
||||||
|
|
||||||
// mTextKeys is a nif-thing, used by OpenMW's animation system
|
|
||||||
// Format is likely "AnimationName: [Keyword_optional] [Start OR Stop]"
|
|
||||||
// AnimationNames are keywords like idle2, idle3... AiPackages and various mechanics control which animations are played
|
|
||||||
// Keywords can be stuff like Loop, Equip, Unequip, Block, InventoryHandtoHand, InventoryWeaponOneHand, PickProbe, Slash, Thrust, Chop... even "Slash Small Follow"
|
|
||||||
mTarget.mTextKeys.emplace(startTime, std::move(start));
|
|
||||||
mTarget.mTextKeys.emplace(stopTime, std::move(stop));
|
|
||||||
|
|
||||||
SceneUtil::EmulatedAnimation emulatedAnimation;
|
SceneUtil::EmulatedAnimation emulatedAnimation;
|
||||||
emulatedAnimation.mStartTime = startTime;
|
emulatedAnimation.mStartTime = startTime;
|
||||||
emulatedAnimation.mStopTime = stopTime;
|
emulatedAnimation.mStopTime = stopTime;
|
||||||
|
@ -66,12 +61,61 @@ namespace Resource
|
||||||
emulatedAnimations.emplace_back(emulatedAnimation);
|
emulatedAnimations.emplace_back(emulatedAnimation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mTextKeys is a nif-thing, used by OpenMW's animation system
|
||||||
|
// Format is likely "AnimationName: [Keyword_optional] [Start OR Stop]"
|
||||||
|
// AnimationNames are keywords like idle2, idle3... AiPackages and various mechanics control which animations are played
|
||||||
|
// Keywords can be stuff like Loop, Equip, Unequip, Block, InventoryHandtoHand, InventoryWeaponOneHand, PickProbe, Slash, Thrust, Chop... even "Slash Small Follow"
|
||||||
|
// osgAnimation formats should have a .txt file with the same name, each line holding a textkey and whitespace separated time value
|
||||||
|
// e.g. idle: start 0.0333
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Files::IStreamPtr textKeysFile = mVFS->get(changeFileExtension(mNormalized, "txt"));
|
||||||
|
std::string line;
|
||||||
|
while ( getline (*textKeysFile, line) )
|
||||||
|
{
|
||||||
|
mTarget.mTextKeys.emplace(parseTimeSignature(line), parseTextKey(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "No textkey file found for " << mNormalized;
|
||||||
|
}
|
||||||
|
|
||||||
callback->setEmulatedAnimations(emulatedAnimations);
|
callback->setEmulatedAnimations(emulatedAnimations);
|
||||||
mTarget.mKeyframeControllers.emplace(node.getName(), callback);
|
mTarget.mKeyframeControllers.emplace(node.getName(), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
traverse(node);
|
traverse(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string RetrieveAnimationsVisitor::parseTextKey(const std::string& line)
|
||||||
|
{
|
||||||
|
size_t spacePos = line.find_last_of(' ');
|
||||||
|
if (spacePos != std::string::npos)
|
||||||
|
return line.substr(0, spacePos);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
double RetrieveAnimationsVisitor::parseTimeSignature(const std::string& line)
|
||||||
|
{
|
||||||
|
size_t spacePos = line.find_last_of(' ');
|
||||||
|
double time = 0.0;
|
||||||
|
if (spacePos != std::string::npos && spacePos + 1 < line.size())
|
||||||
|
time = std::stod(line.substr(spacePos + 1));
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RetrieveAnimationsVisitor::changeFileExtension(const std::string file, const std::string ext)
|
||||||
|
{
|
||||||
|
size_t extPos = file.find_last_of('.');
|
||||||
|
if (extPos != std::string::npos && extPos+1 < file.size())
|
||||||
|
{
|
||||||
|
return file.substr(0, extPos + 1) + ext;
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Resource
|
namespace Resource
|
||||||
|
@ -109,7 +153,7 @@ namespace Resource
|
||||||
osg::ref_ptr<osgAnimation::BasicAnimationManager> bam = dynamic_cast<osgAnimation::BasicAnimationManager*> (scene->getUpdateCallback());
|
osg::ref_ptr<osgAnimation::BasicAnimationManager> bam = dynamic_cast<osgAnimation::BasicAnimationManager*> (scene->getUpdateCallback());
|
||||||
if (bam)
|
if (bam)
|
||||||
{
|
{
|
||||||
Resource::RetrieveAnimationsVisitor rav(*loaded.get(), bam);
|
Resource::RetrieveAnimationsVisitor rav(*loaded.get(), bam, normalized, mVFS);
|
||||||
scene->accept(rav);
|
scene->accept(rav);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,21 @@ namespace Resource
|
||||||
class RetrieveAnimationsVisitor : public osg::NodeVisitor
|
class RetrieveAnimationsVisitor : public osg::NodeVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr<osgAnimation::BasicAnimationManager> animationManager);
|
RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr<osgAnimation::BasicAnimationManager> animationManager,
|
||||||
|
const std::string& normalized, const VFS::Manager* vfs);
|
||||||
|
|
||||||
virtual void apply(osg::Node& node) override;
|
virtual void apply(osg::Node& node) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
std::string changeFileExtension(const std::string file, const std::string ext);
|
||||||
|
std::string parseTextKey(const std::string& line);
|
||||||
|
double parseTimeSignature(const std::string& line);
|
||||||
|
|
||||||
SceneUtil::KeyframeHolder& mTarget;
|
SceneUtil::KeyframeHolder& mTarget;
|
||||||
osg::ref_ptr<osgAnimation::BasicAnimationManager> mAnimationManager;
|
osg::ref_ptr<osgAnimation::BasicAnimationManager> mAnimationManager;
|
||||||
|
std::string mNormalized;
|
||||||
|
const VFS::Manager* mVFS;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <components/sceneutil/util.hpp>
|
#include <components/sceneutil/util.hpp>
|
||||||
#include <components/sceneutil/controller.hpp>
|
#include <components/sceneutil/controller.hpp>
|
||||||
#include <components/sceneutil/optimizer.hpp>
|
#include <components/sceneutil/optimizer.hpp>
|
||||||
|
#include <components/sceneutil/visitor.hpp>
|
||||||
|
|
||||||
#include <components/shader/shadervisitor.hpp>
|
#include <components/shader/shadervisitor.hpp>
|
||||||
#include <components/shader/shadermanager.hpp>
|
#include <components/shader/shadermanager.hpp>
|
||||||
|
@ -373,6 +374,14 @@ namespace Resource
|
||||||
errormsg << "Error loading " << normalizedFilename << ": " << result.message() << " code " << result.status() << std::endl;
|
errormsg << "Error loading " << normalizedFilename << ": " << result.message() << " code " << result.status() << std::endl;
|
||||||
throw std::runtime_error(errormsg.str());
|
throw std::runtime_error(errormsg.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recognize and hide collision node
|
||||||
|
unsigned int hiddenNodeMask = 0;
|
||||||
|
SceneUtil::FindByNameVisitor nameFinder("Collision");
|
||||||
|
result.getNode()->accept(nameFinder);
|
||||||
|
if (nameFinder.mFoundNode)
|
||||||
|
nameFinder.mFoundNode->setNodeMask(hiddenNodeMask);
|
||||||
|
|
||||||
return result.getNode();
|
return result.getNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,31 +395,20 @@ namespace Resource
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
static std::vector<std::string> reservedNames;
|
static std::vector<std::string> reservedNames;
|
||||||
static std::mutex reservedNamesMutex;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(reservedNamesMutex);
|
|
||||||
if (reservedNames.empty())
|
if (reservedNames.empty())
|
||||||
{
|
{
|
||||||
// This keeps somehow accessing garbage so i rewrote it using safer types.
|
const char* reserved[] = {"Head", "Neck", "Chest", "Groin", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", "Shield Bone", "Right Forearm", "Left Forearm", "Right Upper Arm",
|
||||||
//const char* reserved[] = {"Head", "Neck", "Chest", "Groin", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", "Shield Bone", "Right Forearm", "Left Forearm", "Right Upper Arm",
|
|
||||||
// "Left Upper Arm", "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", "Left Knee", "Right Upper Leg", "Left Upper Leg", "Right Clavicle",
|
|
||||||
// "Left Clavicle", "Weapon Bone", "Tail", "Bip01", "Root Bone", "BoneOffset", "AttachLight", "Arrow", "Camera"};
|
|
||||||
|
|
||||||
//reservedNames = std::vector<std::string>(reserved, reserved + sizeof(reserved)/sizeof(const char*));
|
|
||||||
|
|
||||||
//for (unsigned int i=0; i<sizeof(reserved)/sizeof(const char*); ++i)
|
|
||||||
// reservedNames.push_back(std::string("Tri ") + reserved[i]);
|
|
||||||
|
|
||||||
std::vector<std::string> r = { "Head", "Neck", "Chest", "Groin", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", "Shield Bone", "Right Forearm", "Left Forearm", "Right Upper Arm",
|
|
||||||
"Left Upper Arm", "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", "Left Knee", "Right Upper Leg", "Left Upper Leg", "Right Clavicle",
|
"Left Upper Arm", "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", "Left Knee", "Right Upper Leg", "Left Upper Leg", "Right Clavicle",
|
||||||
"Left Clavicle", "Weapon Bone", "Tail", "Bip01", "Root Bone", "BoneOffset", "AttachLight", "Arrow", "Camera" };
|
"Left Clavicle", "Weapon Bone", "Tail", "Bip01", "Root Bone", "BoneOffset", "AttachLight", "Arrow", "Camera", "Collision", "Right_Wrist", "Left_Wrist",
|
||||||
reservedNames = std::vector<std::string>(r.begin(), r.end());
|
"Shield_Bone", "Right_Forearm", "Left_Forearm", "Right_Upper_Arm", "Left_Clavicle", "Weapon_Bone", "Root_Bone"};
|
||||||
for (auto& reservedName : r)
|
|
||||||
reservedNames.emplace_back(std::string("Tri ") + reservedName);
|
reservedNames = std::vector<std::string>(reserved, reserved + sizeof(reserved)/sizeof(reserved[0]));
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<sizeof(reserved)/sizeof(reserved[0]); ++i)
|
||||||
|
reservedNames.push_back(std::string("Tri ") + reserved[i]);
|
||||||
|
|
||||||
std::sort(reservedNames.begin(), reservedNames.end(), Misc::StringUtils::ciLess);
|
std::sort(reservedNames.begin(), reservedNames.end(), Misc::StringUtils::ciLess);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string>::iterator it = Misc::StringUtils::partialBinarySearch(reservedNames.begin(), reservedNames.end(), name);
|
std::vector<std::string>::iterator it = Misc::StringUtils::partialBinarySearch(reservedNames.begin(), reservedNames.end(), name);
|
||||||
return it != reservedNames.end();
|
return it != reservedNames.end();
|
||||||
|
|
|
@ -127,7 +127,7 @@ bool Profiler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter
|
||||||
if (viewer)
|
if (viewer)
|
||||||
{
|
{
|
||||||
// Add/remove openmw stats to the osd as necessary
|
// Add/remove openmw stats to the osd as necessary
|
||||||
viewer->getViewerStats()->collectStats("engine", _statsType == StatsHandler::StatsType::VIEWER_STATS);
|
viewer->getViewerStats()->collectStats("engine", _statsType >= StatsHandler::StatsType::VIEWER_STATS);
|
||||||
|
|
||||||
if (_offlineCollect)
|
if (_offlineCollect)
|
||||||
CollectStatistics(viewer);
|
CollectStatistics(viewer);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
std::string getActorSkeleton(bool firstPerson, bool isFemale, bool isBeast, bool isWerewolf)
|
std::string getActorSkeleton(bool firstPerson, bool isFemale, bool isBeast, bool isWerewolf)
|
||||||
|
@ -7,24 +9,24 @@ namespace SceneUtil
|
||||||
if (!firstPerson)
|
if (!firstPerson)
|
||||||
{
|
{
|
||||||
if (isWerewolf)
|
if (isWerewolf)
|
||||||
return "meshes\\wolf\\skin.nif";
|
return Settings::Manager::getString("wolfskin", "Models");
|
||||||
else if (isBeast)
|
else if (isBeast)
|
||||||
return "meshes\\base_animkna.nif";
|
return Settings::Manager::getString("baseanimkna", "Models");
|
||||||
else if (isFemale)
|
else if (isFemale)
|
||||||
return "meshes\\base_anim_female.nif";
|
return Settings::Manager::getString("baseanimfemale", "Models");
|
||||||
else
|
else
|
||||||
return "meshes\\base_anim.nif";
|
return Settings::Manager::getString("baseanim", "Models");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (isWerewolf)
|
if (isWerewolf)
|
||||||
return "meshes\\wolf\\skin.1st.nif";
|
return Settings::Manager::getString("wolfskin1st", "Models");
|
||||||
else if (isBeast)
|
else if (isBeast)
|
||||||
return "meshes\\base_animkna.1st.nif";
|
return Settings::Manager::getString("baseanimkna1st", "Models");
|
||||||
else if (isFemale)
|
else if (isFemale)
|
||||||
return "meshes\\base_anim_female.1st.nif";
|
return Settings::Manager::getString("baseanimfemale1st", "Models");
|
||||||
else
|
else
|
||||||
return "meshes\\base_anim.1st.nif";
|
return Settings::Manager::getString("xbaseanim1st", "Models");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <osgAnimation/UpdateMatrixTransform>
|
#include <osgAnimation/UpdateMatrixTransform>
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
#include <components/resource/animation.hpp>
|
#include <components/resource/animation.hpp>
|
||||||
#include <components/sceneutil/controller.hpp>
|
#include <components/sceneutil/controller.hpp>
|
||||||
#include <components/sceneutil/keyframe.hpp>
|
#include <components/sceneutil/keyframe.hpp>
|
||||||
|
@ -83,7 +84,7 @@ namespace SceneUtil
|
||||||
{
|
{
|
||||||
osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(cb);
|
osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(cb);
|
||||||
if (umt)
|
if (umt)
|
||||||
if (node.getName() != "bip01") link(umt);
|
if (Misc::StringUtils::lowerCase(node.getName()) != "bip01") link(umt);
|
||||||
cb = cb->getNestedCallback();
|
cb = cb->getNestedCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,10 +103,14 @@ namespace SceneUtil
|
||||||
}
|
}
|
||||||
|
|
||||||
OsgAnimationController::OsgAnimationController(const OsgAnimationController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop)
|
OsgAnimationController::OsgAnimationController(const OsgAnimationController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop)
|
||||||
, mMergedAnimationTracks(copy.mMergedAnimationTracks)
|
|
||||||
, mEmulatedAnimations(copy.mEmulatedAnimations)
|
, mEmulatedAnimations(copy.mEmulatedAnimations)
|
||||||
{
|
{
|
||||||
mLinker = nullptr;
|
mLinker = nullptr;
|
||||||
|
for (const auto& mergedAnimationTrack : copy.mMergedAnimationTracks)
|
||||||
|
{
|
||||||
|
Resource::Animation* copiedAnimationTrack = static_cast<Resource::Animation*>(mergedAnimationTrack.get()->clone(copyop));
|
||||||
|
mMergedAnimationTracks.emplace_back(copiedAnimationTrack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f OsgAnimationController::getTranslation(float time) const
|
osg::Vec3f OsgAnimationController::getTranslation(float time) const
|
||||||
|
|
|
@ -60,7 +60,20 @@ namespace SceneUtil
|
||||||
void NodeMapVisitor::apply(osg::MatrixTransform& trans)
|
void NodeMapVisitor::apply(osg::MatrixTransform& trans)
|
||||||
{
|
{
|
||||||
// Take transformation for first found node in file
|
// Take transformation for first found node in file
|
||||||
const std::string nodeName = Misc::StringUtils::lowerCase(trans.getName());
|
std::string originalNodeName = Misc::StringUtils::lowerCase(trans.getName());
|
||||||
|
|
||||||
|
if (trans.libraryName() == std::string("osgAnimation"))
|
||||||
|
{
|
||||||
|
// Convert underscores to whitespaces as a workaround for Collada (OpenMW's animation system uses whitespace-separated names)
|
||||||
|
std::string underscore = "_";
|
||||||
|
std::size_t foundUnderscore = originalNodeName.find(underscore);
|
||||||
|
|
||||||
|
if (foundUnderscore != std::string::npos)
|
||||||
|
std::replace(originalNodeName.begin(), originalNodeName.end(), '_', ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string nodeName = originalNodeName;
|
||||||
|
|
||||||
mMap.emplace(nodeName, &trans);
|
mMap.emplace(nodeName, &trans);
|
||||||
|
|
||||||
traverse(trans);
|
traverse(trans);
|
||||||
|
|
152
extern/CMakeLists.txt
vendored
Normal file
152
extern/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
# Like `FetchContent_MakeAvailable` but passes EXCLUDE_FROM_ALL to `add_subdirectory`.
|
||||||
|
macro(FetchContent_MakeAvailableExcludeFromAll)
|
||||||
|
foreach(contentName IN ITEMS ${ARGV})
|
||||||
|
string(TOLOWER ${contentName} contentNameLower)
|
||||||
|
FetchContent_GetProperties(${contentName})
|
||||||
|
if(NOT ${contentNameLower}_POPULATED)
|
||||||
|
FetchContent_Populate(${contentName})
|
||||||
|
if(EXISTS ${${contentNameLower}_SOURCE_DIR}/CMakeLists.txt)
|
||||||
|
add_subdirectory(${${contentNameLower}_SOURCE_DIR}
|
||||||
|
${${contentNameLower}_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
if(NOT OPENMW_USE_SYSTEM_BULLET)
|
||||||
|
cmake_minimum_required(VERSION 3.11) # for FetchContent
|
||||||
|
|
||||||
|
set(BUILD_BULLET3 OFF CACHE BOOL "")
|
||||||
|
set(BUILD_EXTRAS OFF CACHE BOOL "")
|
||||||
|
set(BUILD_OPENGL3_DEMOS OFF CACHE BOOL "")
|
||||||
|
set(BUILD_UNIT_TESTS OFF CACHE BOOL "")
|
||||||
|
set(BUILD_BULLET2_DEMOS OFF CACHE BOOL "")
|
||||||
|
set(BUILD_CLSOCKET OFF CACHE BOOL "")
|
||||||
|
set(BUILD_ENET OFF CACHE BOOL "")
|
||||||
|
set(BUILD_CPU_DEMOS OFF CACHE BOOL "")
|
||||||
|
set(BUILD_EGL OFF CACHE BOOL "")
|
||||||
|
|
||||||
|
set(USE_DOUBLE_PRECISION ${BULLET_USE_DOUBLES} CACHE BOOL "")
|
||||||
|
set(BULLET2_MULTITHREADING ON CACHE BOOL "")
|
||||||
|
|
||||||
|
# Version 3.08 with the following changes:
|
||||||
|
# 1. Fixes the linking of Threads:
|
||||||
|
# https://github.com/bulletphysics/bullet3/pull/3237
|
||||||
|
# 2. Removes ~300 MiB of files not used here:
|
||||||
|
# rm -rf build3 data docs examples test Doxyfile
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(bullet
|
||||||
|
URL https://github.com/glebm/bullet3/archive/ed5256454f4f84bd2c1728c88ddb0405d614e7d2.zip
|
||||||
|
URL_HASH MD5=e3c94fac35a7be885ad8843f828a0f96
|
||||||
|
SOURCE_DIR fetched/bullet
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailableExcludeFromAll(bullet)
|
||||||
|
|
||||||
|
set(BULLET_INCLUDE_DIRS ${bullet_SOURCE_DIR}/src PARENT_SCOPE)
|
||||||
|
|
||||||
|
# The order here is important to work around a bug in Bullet:
|
||||||
|
# https://github.com/bulletphysics/bullet3/issues/3233
|
||||||
|
set(BULLET_LIBRARIES BulletCollision LinearMath PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT OPENMW_USE_SYSTEM_MYGUI)
|
||||||
|
cmake_minimum_required(VERSION 3.11) # for FetchContent
|
||||||
|
|
||||||
|
set(MYGUI_RENDERSYSTEM 4 CACHE STRING "")
|
||||||
|
set(MYGUI_DISABLE_PLUGINS TRUE CACHE BOOL "")
|
||||||
|
set(MYGUI_BUILD_DEMOS OFF CACHE BOOL "")
|
||||||
|
set(MYGUI_BUILD_PLUGINS OFF CACHE BOOL "")
|
||||||
|
set(MYGUI_BUILD_TOOLS OFF CACHE BOOL "")
|
||||||
|
|
||||||
|
if(MYGUI_STATIC)
|
||||||
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
|
else()
|
||||||
|
set(BUILD_SHARED_LIBS ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(mygui
|
||||||
|
URL https://github.com/MyGUI/mygui/archive/MyGUI3.4.0.zip
|
||||||
|
URL_HASH MD5=9e990a4240430cbf567bfe73488a274e
|
||||||
|
SOURCE_DIR fetched/mygui
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailableExcludeFromAll(mygui)
|
||||||
|
|
||||||
|
set(MyGUI_INCLUDE_DIRS ${mygui_SOURCE_DIR}/MyGUIEngine/include PARENT_SCOPE)
|
||||||
|
set(MyGUI_LIBRARIES MyGUIEngine PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT OPENMW_USE_SYSTEM_OSG)
|
||||||
|
cmake_minimum_required(VERSION 3.11) # for FetchContent
|
||||||
|
|
||||||
|
set(DYNAMIC_OPENTHREADS OFF CACHE BOOL "")
|
||||||
|
set(DYNAMIC_OPENSCENEGRAPH OFF CACHE BOOL "")
|
||||||
|
set(BUILD_OSG_APPLICATIONS OFF CACHE BOOL "")
|
||||||
|
set(BUILD_OSG_DEPRECATED_SERIALIZERS OFF CACHE BOOL "")
|
||||||
|
set(OSG_FIND_3RD_PARTY_DEPS OFF CACHE BOOL "")
|
||||||
|
|
||||||
|
set(BUILD_OSG_PLUGINS_BY_DEFAULT OFF CACHE BOOL "")
|
||||||
|
set(BUILD_OSG_PLUGIN_BMP ON CACHE BOOL "")
|
||||||
|
set(BUILD_OSG_PLUGIN_DDS ON CACHE BOOL "")
|
||||||
|
set(BUILD_OSG_PLUGIN_FREETYPE ON CACHE BOOL "")
|
||||||
|
set(BUILD_OSG_PLUGIN_JPEG ON CACHE BOOL "")
|
||||||
|
set(BUILD_OSG_PLUGIN_OSG ON CACHE BOOL "")
|
||||||
|
set(BUILD_OSG_PLUGIN_PNG ON CACHE BOOL "")
|
||||||
|
set(BUILD_OSG_PLUGIN_TGA ON CACHE BOOL "")
|
||||||
|
set(BUILD_OSG_PLUGIN_KTX ON CACHE BOOL "")
|
||||||
|
|
||||||
|
set(OSG_USE_FLOAT_MATRIX ON CACHE BOOL "")
|
||||||
|
set(OSG_USE_FLOAT_PLANE ON CACHE BOOL "")
|
||||||
|
set(OSG_USE_FLOAT_QUAT ON CACHE BOOL "")
|
||||||
|
|
||||||
|
set(OPENGL_PROFILE "GL2" CACHE STRING "")
|
||||||
|
|
||||||
|
if(OSG_STATIC)
|
||||||
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
|
else()
|
||||||
|
set(BUILD_SHARED_LIBS ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# branch OpenSceneGraph-3.6 on 23 Jan 2021.
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(osg
|
||||||
|
URL https://github.com/OpenMW/osg/archive/e65f47c4ab3a0b53cc19f517961671e5f840a08d.zip
|
||||||
|
URL_HASH MD5=0c967fe48d80744f6956f6b0b67ef7c6
|
||||||
|
SOURCE_DIR fetched/osg
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailableExcludeFromAll(osg)
|
||||||
|
|
||||||
|
set(OPENSCENEGRAPH_INCLUDE_DIRS ${osg_SOURCE_DIR}/include ${osg_BINARY_DIR}/include PARENT_SCOPE)
|
||||||
|
set(OSG_LIBRARIES OpenThreads osg PARENT_SCOPE)
|
||||||
|
foreach(_name ${USED_OSG_COMPONENTS})
|
||||||
|
string(TOUPPER ${_name} _name_uc)
|
||||||
|
set(${_name_uc}_LIBRARIES ${_name} PARENT_SCOPE)
|
||||||
|
endforeach()
|
||||||
|
foreach(_name ${USED_OSG_PLUGINS})
|
||||||
|
string(TOUPPER ${_name} _name_uc)
|
||||||
|
set(${_name_uc}_LIBRARY ${_name} PARENT_SCOPE)
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT OPENMW_USE_SYSTEM_RECASTNAVIGATION)
|
||||||
|
if(RECASTNAVIGATION_STATIC)
|
||||||
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
|
else()
|
||||||
|
set(BUILD_SHARED_LIBS ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(RECASTNAVIGATION_DEMO OFF CACHE BOOL "")
|
||||||
|
set(RECASTNAVIGATION_TESTS OFF CACHE BOOL "")
|
||||||
|
set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "")
|
||||||
|
|
||||||
|
# master on 15 Feb 2021
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(recastnavigation
|
||||||
|
URL https://github.com/recastnavigation/recastnavigation/archive/e75adf86f91eb3082220085e42dda62679f9a3ea.zip
|
||||||
|
URL_HASH MD5=af905d121ef9d1cdfa979b0495cba059
|
||||||
|
SOURCE_DIR fetched/recastnavigation
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailableExcludeFromAll(recastnavigation)
|
||||||
|
endif()
|
1
extern/osg-ffmpeg-videoplayer/CMakeLists.txt
vendored
1
extern/osg-ffmpeg-videoplayer/CMakeLists.txt
vendored
|
@ -13,5 +13,6 @@ set(OSG_FFMPEG_VIDEOPLAYER_SOURCE_FILES
|
||||||
include_directories(${FFmpeg_INCLUDE_DIRS})
|
include_directories(${FFmpeg_INCLUDE_DIRS})
|
||||||
add_library(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OSG_FFMPEG_VIDEOPLAYER_SOURCE_FILES})
|
add_library(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} STATIC ${OSG_FFMPEG_VIDEOPLAYER_SOURCE_FILES})
|
||||||
target_link_libraries(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} ${FFmpeg_LIBRARIES} ${Boost_THREAD_LIBRARY})
|
target_link_libraries(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} ${FFmpeg_LIBRARIES} ${Boost_THREAD_LIBRARY})
|
||||||
|
target_link_libraries(${OSG_FFMPEG_VIDEOPLAYER_LIBRARY} ${OSG_LIBRARIES})
|
||||||
|
|
||||||
link_directories(${CMAKE_CURRENT_BINARY_DIR})
|
link_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
12
extern/recastnavigation/.editorconfig
vendored
12
extern/recastnavigation/.editorconfig
vendored
|
@ -1,12 +0,0 @@
|
||||||
# editorconfig.org
|
|
||||||
|
|
||||||
# top-most EditorConfig file
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_size = 4
|
|
||||||
indent_style = tab
|
|
||||||
|
|
||||||
[*.yml]
|
|
||||||
indent_size = 2
|
|
||||||
indent_style = space
|
|
49
extern/recastnavigation/.gitignore
vendored
49
extern/recastnavigation/.gitignore
vendored
|
@ -1,49 +0,0 @@
|
||||||
## Compiled source #
|
|
||||||
*.com
|
|
||||||
*.class
|
|
||||||
*.dll
|
|
||||||
*.exe
|
|
||||||
*.ilk
|
|
||||||
*.o
|
|
||||||
*.pdb
|
|
||||||
*.so
|
|
||||||
*.idb
|
|
||||||
|
|
||||||
## Linux exes have no extension
|
|
||||||
RecastDemo/Bin/RecastDemo
|
|
||||||
RecastDemo/Bin/Tests
|
|
||||||
|
|
||||||
# Build directory
|
|
||||||
RecastDemo/Build
|
|
||||||
|
|
||||||
# Ignore meshes
|
|
||||||
RecastDemo/Bin/Meshes/*
|
|
||||||
|
|
||||||
## Logs and databases #
|
|
||||||
*.log
|
|
||||||
*.sql
|
|
||||||
*.sqlite
|
|
||||||
|
|
||||||
## OS generated files #
|
|
||||||
.DS_Store
|
|
||||||
.DS_Store?
|
|
||||||
._*
|
|
||||||
.Spotlight-V100
|
|
||||||
.Trashes
|
|
||||||
ehthumbs.db
|
|
||||||
Thumbs.db
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
|
|
||||||
## xcode specific
|
|
||||||
*xcuserdata*
|
|
||||||
|
|
||||||
## SDL contrib
|
|
||||||
RecastDemo/Contrib/SDL/*
|
|
||||||
|
|
||||||
## Generated doc files
|
|
||||||
Docs/html
|
|
||||||
|
|
||||||
## IDE files
|
|
||||||
.idea/
|
|
||||||
cmake-build-*/
|
|
1
extern/recastnavigation/.id
vendored
1
extern/recastnavigation/.id
vendored
|
@ -1 +0,0 @@
|
||||||
6624e7aef5e15df11cb2f5673574df8e4c96af6a
|
|
1
extern/recastnavigation/.url
vendored
1
extern/recastnavigation/.url
vendored
|
@ -1 +0,0 @@
|
||||||
https://github.com/recastnavigation/recastnavigation.git
|
|
26
extern/recastnavigation/CMakeLists.txt
vendored
26
extern/recastnavigation/CMakeLists.txt
vendored
|
@ -1,26 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
|
|
||||||
# for link time optimization, remove if cmake version is >= 3.9
|
|
||||||
if(POLICY CMP0069)
|
|
||||||
cmake_policy(SET CMP0069 NEW)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
project(RecastNavigation)
|
|
||||||
|
|
||||||
# lib versions
|
|
||||||
SET(SOVERSION 1)
|
|
||||||
SET(VERSION 1.0.0)
|
|
||||||
|
|
||||||
option(RECASTNAVIGATION_STATIC "Build static libraries" ON)
|
|
||||||
|
|
||||||
if(MSVC AND BUILD_SHARED_LIBS)
|
|
||||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
|
||||||
|
|
||||||
add_subdirectory(DebugUtils)
|
|
||||||
add_subdirectory(Detour)
|
|
||||||
add_subdirectory(DetourCrowd)
|
|
||||||
add_subdirectory(DetourTileCache)
|
|
||||||
add_subdirectory(Recast)
|
|
|
@ -1,36 +0,0 @@
|
||||||
file(GLOB SOURCES Source/*.cpp)
|
|
||||||
add_library(DebugUtils ${SOURCES})
|
|
||||||
|
|
||||||
add_library(RecastNavigation::DebugUtils ALIAS DebugUtils)
|
|
||||||
set_target_properties(DebugUtils PROPERTIES DEBUG_POSTFIX -d)
|
|
||||||
|
|
||||||
set(DebugUtils_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Include")
|
|
||||||
|
|
||||||
target_include_directories(DebugUtils PUBLIC
|
|
||||||
"$<BUILD_INTERFACE:${DebugUtils_INCLUDE_DIR}>"
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(DebugUtils
|
|
||||||
Recast
|
|
||||||
Detour
|
|
||||||
DetourTileCache
|
|
||||||
)
|
|
||||||
|
|
||||||
set_target_properties(DebugUtils PROPERTIES
|
|
||||||
SOVERSION ${SOVERSION}
|
|
||||||
VERSION ${VERSION}
|
|
||||||
COMPILE_PDB_OUTPUT_DIRECTORY .
|
|
||||||
COMPILE_PDB_NAME "DebugUtils-d"
|
|
||||||
)
|
|
||||||
|
|
||||||
install(TARGETS DebugUtils
|
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
COMPONENT library
|
|
||||||
)
|
|
||||||
|
|
||||||
file(GLOB INCLUDES Include/*.h)
|
|
||||||
install(FILES ${INCLUDES} DESTINATION
|
|
||||||
${CMAKE_INSTALL_INCLUDEDIR}/recastnavigation)
|
|
||||||
install(FILES "$<TARGET_FILE_DIR:DebugUtils>/DebugUtils-d.pdb" CONFIGURATIONS "Debug" DESTINATION "lib")
|
|
|
@ -1,223 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DEBUGDRAW_H
|
|
||||||
#define DEBUGDRAW_H
|
|
||||||
|
|
||||||
// Some math headers don't have PI defined.
|
|
||||||
static const float DU_PI = 3.14159265f;
|
|
||||||
|
|
||||||
enum duDebugDrawPrimitives
|
|
||||||
{
|
|
||||||
DU_DRAW_POINTS,
|
|
||||||
DU_DRAW_LINES,
|
|
||||||
DU_DRAW_TRIS,
|
|
||||||
DU_DRAW_QUADS,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Abstract debug draw interface.
|
|
||||||
struct duDebugDraw
|
|
||||||
{
|
|
||||||
virtual ~duDebugDraw() = 0;
|
|
||||||
|
|
||||||
virtual void depthMask(bool state) = 0;
|
|
||||||
|
|
||||||
virtual void texture(bool state) = 0;
|
|
||||||
|
|
||||||
/// Begin drawing primitives.
|
|
||||||
/// @param prim [in] primitive type to draw, one of rcDebugDrawPrimitives.
|
|
||||||
/// @param size [in] size of a primitive, applies to point size and line width only.
|
|
||||||
virtual void begin(duDebugDrawPrimitives prim, float size = 1.0f) = 0;
|
|
||||||
|
|
||||||
/// Submit a vertex
|
|
||||||
/// @param pos [in] position of the verts.
|
|
||||||
/// @param color [in] color of the verts.
|
|
||||||
virtual void vertex(const float* pos, unsigned int color) = 0;
|
|
||||||
|
|
||||||
/// Submit a vertex
|
|
||||||
/// @param x,y,z [in] position of the verts.
|
|
||||||
/// @param color [in] color of the verts.
|
|
||||||
virtual void vertex(const float x, const float y, const float z, unsigned int color) = 0;
|
|
||||||
|
|
||||||
/// Submit a vertex
|
|
||||||
/// @param pos [in] position of the verts.
|
|
||||||
/// @param color [in] color of the verts.
|
|
||||||
virtual void vertex(const float* pos, unsigned int color, const float* uv) = 0;
|
|
||||||
|
|
||||||
/// Submit a vertex
|
|
||||||
/// @param x,y,z [in] position of the verts.
|
|
||||||
/// @param color [in] color of the verts.
|
|
||||||
virtual void vertex(const float x, const float y, const float z, unsigned int color, const float u, const float v) = 0;
|
|
||||||
|
|
||||||
/// End drawing primitives.
|
|
||||||
virtual void end() = 0;
|
|
||||||
|
|
||||||
/// Compute a color for given area.
|
|
||||||
virtual unsigned int areaToCol(unsigned int area);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline unsigned int duRGBA(int r, int g, int b, int a)
|
|
||||||
{
|
|
||||||
return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int duRGBAf(float fr, float fg, float fb, float fa)
|
|
||||||
{
|
|
||||||
unsigned char r = (unsigned char)(fr*255.0f);
|
|
||||||
unsigned char g = (unsigned char)(fg*255.0f);
|
|
||||||
unsigned char b = (unsigned char)(fb*255.0f);
|
|
||||||
unsigned char a = (unsigned char)(fa*255.0f);
|
|
||||||
return duRGBA(r,g,b,a);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int duIntToCol(int i, int a);
|
|
||||||
void duIntToCol(int i, float* col);
|
|
||||||
|
|
||||||
inline unsigned int duMultCol(const unsigned int col, const unsigned int d)
|
|
||||||
{
|
|
||||||
const unsigned int r = col & 0xff;
|
|
||||||
const unsigned int g = (col >> 8) & 0xff;
|
|
||||||
const unsigned int b = (col >> 16) & 0xff;
|
|
||||||
const unsigned int a = (col >> 24) & 0xff;
|
|
||||||
return duRGBA((r*d) >> 8, (g*d) >> 8, (b*d) >> 8, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int duDarkenCol(unsigned int col)
|
|
||||||
{
|
|
||||||
return ((col >> 1) & 0x007f7f7f) | (col & 0xff000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int duLerpCol(unsigned int ca, unsigned int cb, unsigned int u)
|
|
||||||
{
|
|
||||||
const unsigned int ra = ca & 0xff;
|
|
||||||
const unsigned int ga = (ca >> 8) & 0xff;
|
|
||||||
const unsigned int ba = (ca >> 16) & 0xff;
|
|
||||||
const unsigned int aa = (ca >> 24) & 0xff;
|
|
||||||
const unsigned int rb = cb & 0xff;
|
|
||||||
const unsigned int gb = (cb >> 8) & 0xff;
|
|
||||||
const unsigned int bb = (cb >> 16) & 0xff;
|
|
||||||
const unsigned int ab = (cb >> 24) & 0xff;
|
|
||||||
|
|
||||||
unsigned int r = (ra*(255-u) + rb*u)/255;
|
|
||||||
unsigned int g = (ga*(255-u) + gb*u)/255;
|
|
||||||
unsigned int b = (ba*(255-u) + bb*u)/255;
|
|
||||||
unsigned int a = (aa*(255-u) + ab*u)/255;
|
|
||||||
return duRGBA(r,g,b,a);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int duTransCol(unsigned int c, unsigned int a)
|
|
||||||
{
|
|
||||||
return (a<<24) | (c & 0x00ffffff);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void duCalcBoxColors(unsigned int* colors, unsigned int colTop, unsigned int colSide);
|
|
||||||
|
|
||||||
void duDebugDrawCylinderWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col, const float lineWidth);
|
|
||||||
|
|
||||||
void duDebugDrawBoxWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col, const float lineWidth);
|
|
||||||
|
|
||||||
void duDebugDrawArc(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
|
||||||
const float x1, const float y1, const float z1, const float h,
|
|
||||||
const float as0, const float as1, unsigned int col, const float lineWidth);
|
|
||||||
|
|
||||||
void duDebugDrawArrow(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
|
||||||
const float x1, const float y1, const float z1,
|
|
||||||
const float as0, const float as1, unsigned int col, const float lineWidth);
|
|
||||||
|
|
||||||
void duDebugDrawCircle(struct duDebugDraw* dd, const float x, const float y, const float z,
|
|
||||||
const float r, unsigned int col, const float lineWidth);
|
|
||||||
|
|
||||||
void duDebugDrawCross(struct duDebugDraw* dd, const float x, const float y, const float z,
|
|
||||||
const float size, unsigned int col, const float lineWidth);
|
|
||||||
|
|
||||||
void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, const unsigned int* fcol);
|
|
||||||
|
|
||||||
void duDebugDrawCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col);
|
|
||||||
|
|
||||||
void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz,
|
|
||||||
const int w, const int h, const float size,
|
|
||||||
const unsigned int col, const float lineWidth);
|
|
||||||
|
|
||||||
|
|
||||||
// Versions without begin/end, can be used to draw multiple primitives.
|
|
||||||
void duAppendCylinderWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col);
|
|
||||||
|
|
||||||
void duAppendBoxWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col);
|
|
||||||
|
|
||||||
void duAppendBoxPoints(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col);
|
|
||||||
|
|
||||||
void duAppendArc(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
|
||||||
const float x1, const float y1, const float z1, const float h,
|
|
||||||
const float as0, const float as1, unsigned int col);
|
|
||||||
|
|
||||||
void duAppendArrow(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
|
||||||
const float x1, const float y1, const float z1,
|
|
||||||
const float as0, const float as1, unsigned int col);
|
|
||||||
|
|
||||||
void duAppendCircle(struct duDebugDraw* dd, const float x, const float y, const float z,
|
|
||||||
const float r, unsigned int col);
|
|
||||||
|
|
||||||
void duAppendCross(struct duDebugDraw* dd, const float x, const float y, const float z,
|
|
||||||
const float size, unsigned int col);
|
|
||||||
|
|
||||||
void duAppendBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, const unsigned int* fcol);
|
|
||||||
|
|
||||||
void duAppendCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col);
|
|
||||||
|
|
||||||
|
|
||||||
class duDisplayList : public duDebugDraw
|
|
||||||
{
|
|
||||||
float* m_pos;
|
|
||||||
unsigned int* m_color;
|
|
||||||
int m_size;
|
|
||||||
int m_cap;
|
|
||||||
|
|
||||||
bool m_depthMask;
|
|
||||||
duDebugDrawPrimitives m_prim;
|
|
||||||
float m_primSize;
|
|
||||||
|
|
||||||
void resize(int cap);
|
|
||||||
|
|
||||||
public:
|
|
||||||
duDisplayList(int cap = 512);
|
|
||||||
~duDisplayList();
|
|
||||||
void depthMask(bool state) override;
|
|
||||||
void begin(duDebugDrawPrimitives prim, float size = 1.0f) override;
|
|
||||||
void vertex(const float x, const float y, const float z, unsigned int color) override;
|
|
||||||
void vertex(const float* pos, unsigned int color) override;
|
|
||||||
void end() override;
|
|
||||||
void clear();
|
|
||||||
void draw(struct duDebugDraw* dd);
|
|
||||||
private:
|
|
||||||
// Explicitly disabled copy constructor and copy assignment operator.
|
|
||||||
duDisplayList(const duDisplayList&);
|
|
||||||
duDisplayList& operator=(const duDisplayList&);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // DEBUGDRAW_H
|
|
|
@ -1,48 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURDEBUGDRAW_H
|
|
||||||
#define DETOURDEBUGDRAW_H
|
|
||||||
|
|
||||||
#include "DetourNavMesh.h"
|
|
||||||
#include "DetourNavMeshQuery.h"
|
|
||||||
#include "DetourTileCacheBuilder.h"
|
|
||||||
|
|
||||||
enum DrawNavMeshFlags
|
|
||||||
{
|
|
||||||
DU_DRAWNAVMESH_OFFMESHCONS = 0x01,
|
|
||||||
DU_DRAWNAVMESH_CLOSEDLIST = 0x02,
|
|
||||||
DU_DRAWNAVMESH_COLOR_TILES = 0x04,
|
|
||||||
};
|
|
||||||
|
|
||||||
void duDebugDrawNavMesh(struct duDebugDraw* dd, const dtNavMesh& mesh, unsigned char flags);
|
|
||||||
void duDebugDrawNavMeshWithClosedList(struct duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery& query, unsigned char flags);
|
|
||||||
void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query);
|
|
||||||
void duDebugDrawNavMeshBVTree(struct duDebugDraw* dd, const dtNavMesh& mesh);
|
|
||||||
void duDebugDrawNavMeshPortals(struct duDebugDraw* dd, const dtNavMesh& mesh);
|
|
||||||
void duDebugDrawNavMeshPolysWithFlags(struct duDebugDraw* dd, const dtNavMesh& mesh, const unsigned short polyFlags, const unsigned int col);
|
|
||||||
void duDebugDrawNavMeshPoly(struct duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col);
|
|
||||||
|
|
||||||
void duDebugDrawTileCacheLayerAreas(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch);
|
|
||||||
void duDebugDrawTileCacheLayerRegions(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch);
|
|
||||||
void duDebugDrawTileCacheContours(duDebugDraw* dd, const struct dtTileCacheContourSet& lcset,
|
|
||||||
const float* orig, const float cs, const float ch);
|
|
||||||
void duDebugDrawTileCachePolyMesh(duDebugDraw* dd, const struct dtTileCachePolyMesh& lmesh,
|
|
||||||
const float* orig, const float cs, const float ch);
|
|
||||||
|
|
||||||
#endif // DETOURDEBUGDRAW_H
|
|
|
@ -1,42 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef RECAST_DEBUGDRAW_H
|
|
||||||
#define RECAST_DEBUGDRAW_H
|
|
||||||
|
|
||||||
void duDebugDrawTriMesh(struct duDebugDraw* dd, const float* verts, int nverts, const int* tris, const float* normals, int ntris, const unsigned char* flags, const float texScale);
|
|
||||||
void duDebugDrawTriMeshSlope(struct duDebugDraw* dd, const float* verts, int nverts, const int* tris, const float* normals, int ntris, const float walkableSlopeAngle, const float texScale);
|
|
||||||
|
|
||||||
void duDebugDrawHeightfieldSolid(struct duDebugDraw* dd, const struct rcHeightfield& hf);
|
|
||||||
void duDebugDrawHeightfieldWalkable(struct duDebugDraw* dd, const struct rcHeightfield& hf);
|
|
||||||
|
|
||||||
void duDebugDrawCompactHeightfieldSolid(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
|
|
||||||
void duDebugDrawCompactHeightfieldRegions(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
|
|
||||||
void duDebugDrawCompactHeightfieldDistance(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
|
|
||||||
|
|
||||||
void duDebugDrawHeightfieldLayer(duDebugDraw* dd, const struct rcHeightfieldLayer& layer, const int idx);
|
|
||||||
void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset);
|
|
||||||
void duDebugDrawHeightfieldLayersRegions(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset);
|
|
||||||
|
|
||||||
void duDebugDrawRegionConnections(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
|
||||||
void duDebugDrawRawContours(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
|
||||||
void duDebugDrawContours(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f);
|
|
||||||
void duDebugDrawPolyMesh(struct duDebugDraw* dd, const struct rcPolyMesh& mesh);
|
|
||||||
void duDebugDrawPolyMeshDetail(struct duDebugDraw* dd, const struct rcPolyMeshDetail& dmesh);
|
|
||||||
|
|
||||||
#endif // RECAST_DEBUGDRAW_H
|
|
|
@ -1,43 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef RECAST_DUMP_H
|
|
||||||
#define RECAST_DUMP_H
|
|
||||||
|
|
||||||
struct duFileIO
|
|
||||||
{
|
|
||||||
virtual ~duFileIO() = 0;
|
|
||||||
virtual bool isWriting() const = 0;
|
|
||||||
virtual bool isReading() const = 0;
|
|
||||||
virtual bool write(const void* ptr, const size_t size) = 0;
|
|
||||||
virtual bool read(void* ptr, const size_t size) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool duDumpPolyMeshToObj(struct rcPolyMesh& pmesh, duFileIO* io);
|
|
||||||
bool duDumpPolyMeshDetailToObj(struct rcPolyMeshDetail& dmesh, duFileIO* io);
|
|
||||||
|
|
||||||
bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io);
|
|
||||||
bool duReadContourSet(struct rcContourSet& cset, duFileIO* io);
|
|
||||||
|
|
||||||
bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io);
|
|
||||||
bool duReadCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io);
|
|
||||||
|
|
||||||
void duLogBuildTimes(rcContext& ctx, const int totalTileUsec);
|
|
||||||
|
|
||||||
|
|
||||||
#endif // RECAST_DUMP_H
|
|
|
@ -1,612 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#define _USE_MATH_DEFINES
|
|
||||||
#include <string.h>
|
|
||||||
#include "DebugDraw.h"
|
|
||||||
#include "DetourMath.h"
|
|
||||||
#include "DetourNavMesh.h"
|
|
||||||
|
|
||||||
|
|
||||||
duDebugDraw::~duDebugDraw()
|
|
||||||
{
|
|
||||||
// Empty
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int duDebugDraw::areaToCol(unsigned int area)
|
|
||||||
{
|
|
||||||
if (area == 0)
|
|
||||||
{
|
|
||||||
// Treat zero area type as default.
|
|
||||||
return duRGBA(0, 192, 255, 255);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return duIntToCol(area, 255);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int bit(int a, int b)
|
|
||||||
{
|
|
||||||
return (a & (1 << b)) >> b;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int duIntToCol(int i, int a)
|
|
||||||
{
|
|
||||||
int r = bit(i, 1) + bit(i, 3) * 2 + 1;
|
|
||||||
int g = bit(i, 2) + bit(i, 4) * 2 + 1;
|
|
||||||
int b = bit(i, 0) + bit(i, 5) * 2 + 1;
|
|
||||||
return duRGBA(r*63,g*63,b*63,a);
|
|
||||||
}
|
|
||||||
|
|
||||||
void duIntToCol(int i, float* col)
|
|
||||||
{
|
|
||||||
int r = bit(i, 0) + bit(i, 3) * 2 + 1;
|
|
||||||
int g = bit(i, 1) + bit(i, 4) * 2 + 1;
|
|
||||||
int b = bit(i, 2) + bit(i, 5) * 2 + 1;
|
|
||||||
col[0] = 1 - r*63.0f/255.0f;
|
|
||||||
col[1] = 1 - g*63.0f/255.0f;
|
|
||||||
col[2] = 1 - b*63.0f/255.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void duCalcBoxColors(unsigned int* colors, unsigned int colTop, unsigned int colSide)
|
|
||||||
{
|
|
||||||
if (!colors) return;
|
|
||||||
|
|
||||||
colors[0] = duMultCol(colTop, 250);
|
|
||||||
colors[1] = duMultCol(colSide, 140);
|
|
||||||
colors[2] = duMultCol(colSide, 165);
|
|
||||||
colors[3] = duMultCol(colSide, 217);
|
|
||||||
colors[4] = duMultCol(colSide, 165);
|
|
||||||
colors[5] = duMultCol(colSide, 217);
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawCylinderWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col, const float lineWidth)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
|
||||||
duAppendCylinderWire(dd, minx,miny,minz, maxx,maxy,maxz, col);
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawBoxWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col, const float lineWidth)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
|
||||||
duAppendBoxWire(dd, minx,miny,minz, maxx,maxy,maxz, col);
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawArc(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
|
||||||
const float x1, const float y1, const float z1, const float h,
|
|
||||||
const float as0, const float as1, unsigned int col, const float lineWidth)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
|
||||||
duAppendArc(dd, x0,y0,z0, x1,y1,z1, h, as0, as1, col);
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawArrow(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
|
||||||
const float x1, const float y1, const float z1,
|
|
||||||
const float as0, const float as1, unsigned int col, const float lineWidth)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
|
||||||
duAppendArrow(dd, x0,y0,z0, x1,y1,z1, as0, as1, col);
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawCircle(struct duDebugDraw* dd, const float x, const float y, const float z,
|
|
||||||
const float r, unsigned int col, const float lineWidth)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
|
||||||
duAppendCircle(dd, x,y,z, r, col);
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawCross(struct duDebugDraw* dd, const float x, const float y, const float z,
|
|
||||||
const float size, unsigned int col, const float lineWidth)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
|
||||||
duAppendCross(dd, x,y,z, size, col);
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, const unsigned int* fcol)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_QUADS);
|
|
||||||
duAppendBox(dd, minx,miny,minz, maxx,maxy,maxz, fcol);
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_TRIS);
|
|
||||||
duAppendCylinder(dd, minx,miny,minz, maxx,maxy,maxz, col);
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz,
|
|
||||||
const int w, const int h, const float size,
|
|
||||||
const unsigned int col, const float lineWidth)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
|
||||||
for (int i = 0; i <= h; ++i)
|
|
||||||
{
|
|
||||||
dd->vertex(ox,oy,oz+i*size, col);
|
|
||||||
dd->vertex(ox+w*size,oy,oz+i*size, col);
|
|
||||||
}
|
|
||||||
for (int i = 0; i <= w; ++i)
|
|
||||||
{
|
|
||||||
dd->vertex(ox+i*size,oy,oz, col);
|
|
||||||
dd->vertex(ox+i*size,oy,oz+h*size, col);
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void duAppendCylinderWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
static const int NUM_SEG = 16;
|
|
||||||
static float dir[NUM_SEG*2];
|
|
||||||
static bool init = false;
|
|
||||||
if (!init)
|
|
||||||
{
|
|
||||||
init = true;
|
|
||||||
for (int i = 0; i < NUM_SEG; ++i)
|
|
||||||
{
|
|
||||||
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
|
||||||
dir[i*2] = dtMathCosf(a);
|
|
||||||
dir[i*2+1] = dtMathSinf(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const float cx = (maxx + minx)/2;
|
|
||||||
const float cz = (maxz + minz)/2;
|
|
||||||
const float rx = (maxx - minx)/2;
|
|
||||||
const float rz = (maxz - minz)/2;
|
|
||||||
|
|
||||||
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
|
|
||||||
{
|
|
||||||
dd->vertex(cx+dir[j*2+0]*rx, miny, cz+dir[j*2+1]*rz, col);
|
|
||||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col);
|
|
||||||
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
|
|
||||||
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < NUM_SEG; i += NUM_SEG/4)
|
|
||||||
{
|
|
||||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col);
|
|
||||||
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void duAppendBoxWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
// Top
|
|
||||||
dd->vertex(minx, miny, minz, col);
|
|
||||||
dd->vertex(maxx, miny, minz, col);
|
|
||||||
dd->vertex(maxx, miny, minz, col);
|
|
||||||
dd->vertex(maxx, miny, maxz, col);
|
|
||||||
dd->vertex(maxx, miny, maxz, col);
|
|
||||||
dd->vertex(minx, miny, maxz, col);
|
|
||||||
dd->vertex(minx, miny, maxz, col);
|
|
||||||
dd->vertex(minx, miny, minz, col);
|
|
||||||
|
|
||||||
// bottom
|
|
||||||
dd->vertex(minx, maxy, minz, col);
|
|
||||||
dd->vertex(maxx, maxy, minz, col);
|
|
||||||
dd->vertex(maxx, maxy, minz, col);
|
|
||||||
dd->vertex(maxx, maxy, maxz, col);
|
|
||||||
dd->vertex(maxx, maxy, maxz, col);
|
|
||||||
dd->vertex(minx, maxy, maxz, col);
|
|
||||||
dd->vertex(minx, maxy, maxz, col);
|
|
||||||
dd->vertex(minx, maxy, minz, col);
|
|
||||||
|
|
||||||
// Sides
|
|
||||||
dd->vertex(minx, miny, minz, col);
|
|
||||||
dd->vertex(minx, maxy, minz, col);
|
|
||||||
dd->vertex(maxx, miny, minz, col);
|
|
||||||
dd->vertex(maxx, maxy, minz, col);
|
|
||||||
dd->vertex(maxx, miny, maxz, col);
|
|
||||||
dd->vertex(maxx, maxy, maxz, col);
|
|
||||||
dd->vertex(minx, miny, maxz, col);
|
|
||||||
dd->vertex(minx, maxy, maxz, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
void duAppendBoxPoints(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
// Top
|
|
||||||
dd->vertex(minx, miny, minz, col);
|
|
||||||
dd->vertex(maxx, miny, minz, col);
|
|
||||||
dd->vertex(maxx, miny, minz, col);
|
|
||||||
dd->vertex(maxx, miny, maxz, col);
|
|
||||||
dd->vertex(maxx, miny, maxz, col);
|
|
||||||
dd->vertex(minx, miny, maxz, col);
|
|
||||||
dd->vertex(minx, miny, maxz, col);
|
|
||||||
dd->vertex(minx, miny, minz, col);
|
|
||||||
|
|
||||||
// bottom
|
|
||||||
dd->vertex(minx, maxy, minz, col);
|
|
||||||
dd->vertex(maxx, maxy, minz, col);
|
|
||||||
dd->vertex(maxx, maxy, minz, col);
|
|
||||||
dd->vertex(maxx, maxy, maxz, col);
|
|
||||||
dd->vertex(maxx, maxy, maxz, col);
|
|
||||||
dd->vertex(minx, maxy, maxz, col);
|
|
||||||
dd->vertex(minx, maxy, maxz, col);
|
|
||||||
dd->vertex(minx, maxy, minz, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
void duAppendBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, const unsigned int* fcol)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
const float verts[8*3] =
|
|
||||||
{
|
|
||||||
minx, miny, minz,
|
|
||||||
maxx, miny, minz,
|
|
||||||
maxx, miny, maxz,
|
|
||||||
minx, miny, maxz,
|
|
||||||
minx, maxy, minz,
|
|
||||||
maxx, maxy, minz,
|
|
||||||
maxx, maxy, maxz,
|
|
||||||
minx, maxy, maxz,
|
|
||||||
};
|
|
||||||
static const unsigned char inds[6*4] =
|
|
||||||
{
|
|
||||||
7, 6, 5, 4,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
1, 5, 6, 2,
|
|
||||||
3, 7, 4, 0,
|
|
||||||
2, 6, 7, 3,
|
|
||||||
0, 4, 5, 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char* in = inds;
|
|
||||||
for (int i = 0; i < 6; ++i)
|
|
||||||
{
|
|
||||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
|
||||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
|
||||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
|
||||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void duAppendCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
|
|
||||||
float maxx, float maxy, float maxz, unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
static const int NUM_SEG = 16;
|
|
||||||
static float dir[NUM_SEG*2];
|
|
||||||
static bool init = false;
|
|
||||||
if (!init)
|
|
||||||
{
|
|
||||||
init = true;
|
|
||||||
for (int i = 0; i < NUM_SEG; ++i)
|
|
||||||
{
|
|
||||||
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
|
||||||
dir[i*2] = cosf(a);
|
|
||||||
dir[i*2+1] = sinf(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int col2 = duMultCol(col, 160);
|
|
||||||
|
|
||||||
const float cx = (maxx + minx)/2;
|
|
||||||
const float cz = (maxz + minz)/2;
|
|
||||||
const float rx = (maxx - minx)/2;
|
|
||||||
const float rz = (maxz - minz)/2;
|
|
||||||
|
|
||||||
for (int i = 2; i < NUM_SEG; ++i)
|
|
||||||
{
|
|
||||||
const int a = 0, b = i-1, c = i;
|
|
||||||
dd->vertex(cx+dir[a*2+0]*rx, miny, cz+dir[a*2+1]*rz, col2);
|
|
||||||
dd->vertex(cx+dir[b*2+0]*rx, miny, cz+dir[b*2+1]*rz, col2);
|
|
||||||
dd->vertex(cx+dir[c*2+0]*rx, miny, cz+dir[c*2+1]*rz, col2);
|
|
||||||
}
|
|
||||||
for (int i = 2; i < NUM_SEG; ++i)
|
|
||||||
{
|
|
||||||
const int a = 0, b = i, c = i-1;
|
|
||||||
dd->vertex(cx+dir[a*2+0]*rx, maxy, cz+dir[a*2+1]*rz, col);
|
|
||||||
dd->vertex(cx+dir[b*2+0]*rx, maxy, cz+dir[b*2+1]*rz, col);
|
|
||||||
dd->vertex(cx+dir[c*2+0]*rx, maxy, cz+dir[c*2+1]*rz, col);
|
|
||||||
}
|
|
||||||
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
|
|
||||||
{
|
|
||||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col2);
|
|
||||||
dd->vertex(cx+dir[j*2+0]*rx, miny, cz+dir[j*2+1]*rz, col2);
|
|
||||||
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
|
|
||||||
|
|
||||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col2);
|
|
||||||
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
|
|
||||||
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void evalArc(const float x0, const float y0, const float z0,
|
|
||||||
const float dx, const float dy, const float dz,
|
|
||||||
const float h, const float u, float* res)
|
|
||||||
{
|
|
||||||
res[0] = x0 + dx * u;
|
|
||||||
res[1] = y0 + dy * u + h * (1-(u*2-1)*(u*2-1));
|
|
||||||
res[2] = z0 + dz * u;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void vcross(float* dest, const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
|
||||||
dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
|
||||||
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void vnormalize(float* v)
|
|
||||||
{
|
|
||||||
float d = 1.0f / sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
|
||||||
v[0] *= d;
|
|
||||||
v[1] *= d;
|
|
||||||
v[2] *= d;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void vsub(float* dest, const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
dest[0] = v1[0]-v2[0];
|
|
||||||
dest[1] = v1[1]-v2[1];
|
|
||||||
dest[2] = v1[2]-v2[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float vdistSqr(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
const float x = v1[0]-v2[0];
|
|
||||||
const float y = v1[1]-v2[1];
|
|
||||||
const float z = v1[2]-v2[2];
|
|
||||||
return x*x + y*y + z*z;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void appendArrowHead(struct duDebugDraw* dd, const float* p, const float* q,
|
|
||||||
const float s, unsigned int col)
|
|
||||||
{
|
|
||||||
const float eps = 0.001f;
|
|
||||||
if (!dd) return;
|
|
||||||
if (vdistSqr(p,q) < eps*eps) return;
|
|
||||||
float ax[3], ay[3] = {0,1,0}, az[3];
|
|
||||||
vsub(az, q, p);
|
|
||||||
vnormalize(az);
|
|
||||||
vcross(ax, ay, az);
|
|
||||||
vcross(ay, az, ax);
|
|
||||||
vnormalize(ay);
|
|
||||||
|
|
||||||
dd->vertex(p, col);
|
|
||||||
// dd->vertex(p[0]+az[0]*s+ay[0]*s/2, p[1]+az[1]*s+ay[1]*s/2, p[2]+az[2]*s+ay[2]*s/2, col);
|
|
||||||
dd->vertex(p[0]+az[0]*s+ax[0]*s/3, p[1]+az[1]*s+ax[1]*s/3, p[2]+az[2]*s+ax[2]*s/3, col);
|
|
||||||
|
|
||||||
dd->vertex(p, col);
|
|
||||||
// dd->vertex(p[0]+az[0]*s-ay[0]*s/2, p[1]+az[1]*s-ay[1]*s/2, p[2]+az[2]*s-ay[2]*s/2, col);
|
|
||||||
dd->vertex(p[0]+az[0]*s-ax[0]*s/3, p[1]+az[1]*s-ax[1]*s/3, p[2]+az[2]*s-ax[2]*s/3, col);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void duAppendArc(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
|
||||||
const float x1, const float y1, const float z1, const float h,
|
|
||||||
const float as0, const float as1, unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
static const int NUM_ARC_PTS = 8;
|
|
||||||
static const float PAD = 0.05f;
|
|
||||||
static const float ARC_PTS_SCALE = (1.0f-PAD*2) / (float)NUM_ARC_PTS;
|
|
||||||
const float dx = x1 - x0;
|
|
||||||
const float dy = y1 - y0;
|
|
||||||
const float dz = z1 - z0;
|
|
||||||
const float len = sqrtf(dx*dx + dy*dy + dz*dz);
|
|
||||||
float prev[3];
|
|
||||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, PAD, prev);
|
|
||||||
for (int i = 1; i <= NUM_ARC_PTS; ++i)
|
|
||||||
{
|
|
||||||
const float u = PAD + i * ARC_PTS_SCALE;
|
|
||||||
float pt[3];
|
|
||||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, u, pt);
|
|
||||||
dd->vertex(prev[0],prev[1],prev[2], col);
|
|
||||||
dd->vertex(pt[0],pt[1],pt[2], col);
|
|
||||||
prev[0] = pt[0]; prev[1] = pt[1]; prev[2] = pt[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
// End arrows
|
|
||||||
if (as0 > 0.001f)
|
|
||||||
{
|
|
||||||
float p[3], q[3];
|
|
||||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, PAD, p);
|
|
||||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, PAD+0.05f, q);
|
|
||||||
appendArrowHead(dd, p, q, as0, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (as1 > 0.001f)
|
|
||||||
{
|
|
||||||
float p[3], q[3];
|
|
||||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, 1-PAD, p);
|
|
||||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, 1-(PAD+0.05f), q);
|
|
||||||
appendArrowHead(dd, p, q, as1, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void duAppendArrow(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
|
||||||
const float x1, const float y1, const float z1,
|
|
||||||
const float as0, const float as1, unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
dd->vertex(x0,y0,z0, col);
|
|
||||||
dd->vertex(x1,y1,z1, col);
|
|
||||||
|
|
||||||
// End arrows
|
|
||||||
const float p[3] = {x0,y0,z0}, q[3] = {x1,y1,z1};
|
|
||||||
if (as0 > 0.001f)
|
|
||||||
appendArrowHead(dd, p, q, as0, col);
|
|
||||||
if (as1 > 0.001f)
|
|
||||||
appendArrowHead(dd, q, p, as1, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
void duAppendCircle(struct duDebugDraw* dd, const float x, const float y, const float z,
|
|
||||||
const float r, unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
static const int NUM_SEG = 40;
|
|
||||||
static float dir[40*2];
|
|
||||||
static bool init = false;
|
|
||||||
if (!init)
|
|
||||||
{
|
|
||||||
init = true;
|
|
||||||
for (int i = 0; i < NUM_SEG; ++i)
|
|
||||||
{
|
|
||||||
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
|
||||||
dir[i*2] = cosf(a);
|
|
||||||
dir[i*2+1] = sinf(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
|
|
||||||
{
|
|
||||||
dd->vertex(x+dir[j*2+0]*r, y, z+dir[j*2+1]*r, col);
|
|
||||||
dd->vertex(x+dir[i*2+0]*r, y, z+dir[i*2+1]*r, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void duAppendCross(struct duDebugDraw* dd, const float x, const float y, const float z,
|
|
||||||
const float s, unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
dd->vertex(x-s,y,z, col);
|
|
||||||
dd->vertex(x+s,y,z, col);
|
|
||||||
dd->vertex(x,y-s,z, col);
|
|
||||||
dd->vertex(x,y+s,z, col);
|
|
||||||
dd->vertex(x,y,z-s, col);
|
|
||||||
dd->vertex(x,y,z+s, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
duDisplayList::duDisplayList(int cap) :
|
|
||||||
m_pos(0),
|
|
||||||
m_color(0),
|
|
||||||
m_size(0),
|
|
||||||
m_cap(0),
|
|
||||||
m_depthMask(true),
|
|
||||||
m_prim(DU_DRAW_LINES),
|
|
||||||
m_primSize(1.0f)
|
|
||||||
{
|
|
||||||
if (cap < 8)
|
|
||||||
cap = 8;
|
|
||||||
resize(cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
duDisplayList::~duDisplayList()
|
|
||||||
{
|
|
||||||
delete [] m_pos;
|
|
||||||
delete [] m_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDisplayList::resize(int cap)
|
|
||||||
{
|
|
||||||
float* newPos = new float[cap*3];
|
|
||||||
if (m_size)
|
|
||||||
memcpy(newPos, m_pos, sizeof(float)*3*m_size);
|
|
||||||
delete [] m_pos;
|
|
||||||
m_pos = newPos;
|
|
||||||
|
|
||||||
unsigned int* newColor = new unsigned int[cap];
|
|
||||||
if (m_size)
|
|
||||||
memcpy(newColor, m_color, sizeof(unsigned int)*m_size);
|
|
||||||
delete [] m_color;
|
|
||||||
m_color = newColor;
|
|
||||||
|
|
||||||
m_cap = cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDisplayList::clear()
|
|
||||||
{
|
|
||||||
m_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDisplayList::depthMask(bool state)
|
|
||||||
{
|
|
||||||
m_depthMask = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDisplayList::begin(duDebugDrawPrimitives prim, float size)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
m_prim = prim;
|
|
||||||
m_primSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDisplayList::vertex(const float x, const float y, const float z, unsigned int color)
|
|
||||||
{
|
|
||||||
if (m_size+1 >= m_cap)
|
|
||||||
resize(m_cap*2);
|
|
||||||
float* p = &m_pos[m_size*3];
|
|
||||||
p[0] = x;
|
|
||||||
p[1] = y;
|
|
||||||
p[2] = z;
|
|
||||||
m_color[m_size] = color;
|
|
||||||
m_size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDisplayList::vertex(const float* pos, unsigned int color)
|
|
||||||
{
|
|
||||||
vertex(pos[0],pos[1],pos[2],color);
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDisplayList::end()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDisplayList::draw(struct duDebugDraw* dd)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
if (!m_size) return;
|
|
||||||
dd->depthMask(m_depthMask);
|
|
||||||
dd->begin(m_prim, m_primSize);
|
|
||||||
for (int i = 0; i < m_size; ++i)
|
|
||||||
dd->vertex(&m_pos[i*3], m_color[i]);
|
|
||||||
dd->end();
|
|
||||||
}
|
|
|
@ -1,864 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "DebugDraw.h"
|
|
||||||
#include "DetourDebugDraw.h"
|
|
||||||
#include "DetourNavMesh.h"
|
|
||||||
#include "DetourCommon.h"
|
|
||||||
#include "DetourNode.h"
|
|
||||||
|
|
||||||
|
|
||||||
static float distancePtLine2d(const float* pt, const float* p, const float* q)
|
|
||||||
{
|
|
||||||
float pqx = q[0] - p[0];
|
|
||||||
float pqz = q[2] - p[2];
|
|
||||||
float dx = pt[0] - p[0];
|
|
||||||
float dz = pt[2] - p[2];
|
|
||||||
float d = pqx*pqx + pqz*pqz;
|
|
||||||
float t = pqx*dx + pqz*dz;
|
|
||||||
if (d != 0) t /= d;
|
|
||||||
dx = p[0] + t*pqx - pt[0];
|
|
||||||
dz = p[2] + t*pqz - pt[2];
|
|
||||||
return dx*dx + dz*dz;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drawPolyBoundaries(duDebugDraw* dd, const dtMeshTile* tile,
|
|
||||||
const unsigned int col, const float linew,
|
|
||||||
bool inner)
|
|
||||||
{
|
|
||||||
static const float thr = 0.01f*0.01f;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, linew);
|
|
||||||
|
|
||||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
|
||||||
{
|
|
||||||
const dtPoly* p = &tile->polys[i];
|
|
||||||
|
|
||||||
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) continue;
|
|
||||||
|
|
||||||
const dtPolyDetail* pd = &tile->detailMeshes[i];
|
|
||||||
|
|
||||||
for (int j = 0, nj = (int)p->vertCount; j < nj; ++j)
|
|
||||||
{
|
|
||||||
unsigned int c = col;
|
|
||||||
if (inner)
|
|
||||||
{
|
|
||||||
if (p->neis[j] == 0) continue;
|
|
||||||
if (p->neis[j] & DT_EXT_LINK)
|
|
||||||
{
|
|
||||||
bool con = false;
|
|
||||||
for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
|
|
||||||
{
|
|
||||||
if (tile->links[k].edge == j)
|
|
||||||
{
|
|
||||||
con = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (con)
|
|
||||||
c = duRGBA(255,255,255,48);
|
|
||||||
else
|
|
||||||
c = duRGBA(0,0,0,48);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
c = duRGBA(0,48,64,32);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (p->neis[j] != 0) continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float* v0 = &tile->verts[p->verts[j]*3];
|
|
||||||
const float* v1 = &tile->verts[p->verts[(j+1) % nj]*3];
|
|
||||||
|
|
||||||
// Draw detail mesh edges which align with the actual poly edge.
|
|
||||||
// This is really slow.
|
|
||||||
for (int k = 0; k < pd->triCount; ++k)
|
|
||||||
{
|
|
||||||
const unsigned char* t = &tile->detailTris[(pd->triBase+k)*4];
|
|
||||||
const float* tv[3];
|
|
||||||
for (int m = 0; m < 3; ++m)
|
|
||||||
{
|
|
||||||
if (t[m] < p->vertCount)
|
|
||||||
tv[m] = &tile->verts[p->verts[t[m]]*3];
|
|
||||||
else
|
|
||||||
tv[m] = &tile->detailVerts[(pd->vertBase+(t[m]-p->vertCount))*3];
|
|
||||||
}
|
|
||||||
for (int m = 0, n = 2; m < 3; n=m++)
|
|
||||||
{
|
|
||||||
if ((dtGetDetailTriEdgeFlags(t[3], n) & DT_DETAIL_EDGE_BOUNDARY) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (distancePtLine2d(tv[n],v0,v1) < thr &&
|
|
||||||
distancePtLine2d(tv[m],v0,v1) < thr)
|
|
||||||
{
|
|
||||||
dd->vertex(tv[n], c);
|
|
||||||
dd->vertex(tv[m], c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery* query,
|
|
||||||
const dtMeshTile* tile, unsigned char flags)
|
|
||||||
{
|
|
||||||
dtPolyRef base = mesh.getPolyRefBase(tile);
|
|
||||||
|
|
||||||
int tileNum = mesh.decodePolyIdTile(base);
|
|
||||||
const unsigned int tileColor = duIntToCol(tileNum, 128);
|
|
||||||
|
|
||||||
dd->depthMask(false);
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_TRIS);
|
|
||||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
|
||||||
{
|
|
||||||
const dtPoly* p = &tile->polys[i];
|
|
||||||
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) // Skip off-mesh links.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const dtPolyDetail* pd = &tile->detailMeshes[i];
|
|
||||||
|
|
||||||
unsigned int col;
|
|
||||||
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
|
||||||
col = duRGBA(255,196,0,64);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (flags & DU_DRAWNAVMESH_COLOR_TILES)
|
|
||||||
col = tileColor;
|
|
||||||
else
|
|
||||||
col = duTransCol(dd->areaToCol(p->getArea()), 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 0; j < pd->triCount; ++j)
|
|
||||||
{
|
|
||||||
const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
|
|
||||||
for (int k = 0; k < 3; ++k)
|
|
||||||
{
|
|
||||||
if (t[k] < p->vertCount)
|
|
||||||
dd->vertex(&tile->verts[p->verts[t[k]]*3], col);
|
|
||||||
else
|
|
||||||
dd->vertex(&tile->detailVerts[(pd->vertBase+t[k]-p->vertCount)*3], col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
|
|
||||||
// Draw inter poly boundaries
|
|
||||||
drawPolyBoundaries(dd, tile, duRGBA(0,48,64,32), 1.5f, true);
|
|
||||||
|
|
||||||
// Draw outer poly boundaries
|
|
||||||
drawPolyBoundaries(dd, tile, duRGBA(0,48,64,220), 2.5f, false);
|
|
||||||
|
|
||||||
if (flags & DU_DRAWNAVMESH_OFFMESHCONS)
|
|
||||||
{
|
|
||||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
|
||||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
|
||||||
{
|
|
||||||
const dtPoly* p = &tile->polys[i];
|
|
||||||
if (p->getType() != DT_POLYTYPE_OFFMESH_CONNECTION) // Skip regular polys.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
unsigned int col, col2;
|
|
||||||
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
|
||||||
col = duRGBA(255,196,0,220);
|
|
||||||
else
|
|
||||||
col = duDarkenCol(duTransCol(dd->areaToCol(p->getArea()), 220));
|
|
||||||
|
|
||||||
const dtOffMeshConnection* con = &tile->offMeshCons[i - tile->header->offMeshBase];
|
|
||||||
const float* va = &tile->verts[p->verts[0]*3];
|
|
||||||
const float* vb = &tile->verts[p->verts[1]*3];
|
|
||||||
|
|
||||||
// Check to see if start and end end-points have links.
|
|
||||||
bool startSet = false;
|
|
||||||
bool endSet = false;
|
|
||||||
for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
|
|
||||||
{
|
|
||||||
if (tile->links[k].edge == 0)
|
|
||||||
startSet = true;
|
|
||||||
if (tile->links[k].edge == 1)
|
|
||||||
endSet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// End points and their on-mesh locations.
|
|
||||||
dd->vertex(va[0],va[1],va[2], col);
|
|
||||||
dd->vertex(con->pos[0],con->pos[1],con->pos[2], col);
|
|
||||||
col2 = startSet ? col : duRGBA(220,32,16,196);
|
|
||||||
duAppendCircle(dd, con->pos[0],con->pos[1]+0.1f,con->pos[2], con->rad, col2);
|
|
||||||
|
|
||||||
dd->vertex(vb[0],vb[1],vb[2], col);
|
|
||||||
dd->vertex(con->pos[3],con->pos[4],con->pos[5], col);
|
|
||||||
col2 = endSet ? col : duRGBA(220,32,16,196);
|
|
||||||
duAppendCircle(dd, con->pos[3],con->pos[4]+0.1f,con->pos[5], con->rad, col2);
|
|
||||||
|
|
||||||
// End point vertices.
|
|
||||||
dd->vertex(con->pos[0],con->pos[1],con->pos[2], duRGBA(0,48,64,196));
|
|
||||||
dd->vertex(con->pos[0],con->pos[1]+0.2f,con->pos[2], duRGBA(0,48,64,196));
|
|
||||||
|
|
||||||
dd->vertex(con->pos[3],con->pos[4],con->pos[5], duRGBA(0,48,64,196));
|
|
||||||
dd->vertex(con->pos[3],con->pos[4]+0.2f,con->pos[5], duRGBA(0,48,64,196));
|
|
||||||
|
|
||||||
// Connection arc.
|
|
||||||
duAppendArc(dd, con->pos[0],con->pos[1],con->pos[2], con->pos[3],con->pos[4],con->pos[5], 0.25f,
|
|
||||||
(con->flags & 1) ? 0.6f : 0, 0.6f, col);
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned int vcol = duRGBA(0,0,0,196);
|
|
||||||
dd->begin(DU_DRAW_POINTS, 3.0f);
|
|
||||||
for (int i = 0; i < tile->header->vertCount; ++i)
|
|
||||||
{
|
|
||||||
const float* v = &tile->verts[i*3];
|
|
||||||
dd->vertex(v[0], v[1], v[2], vcol);
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
|
|
||||||
dd->depthMask(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawNavMesh(duDebugDraw* dd, const dtNavMesh& mesh, unsigned char flags)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
|
||||||
{
|
|
||||||
const dtMeshTile* tile = mesh.getTile(i);
|
|
||||||
if (!tile->header) continue;
|
|
||||||
drawMeshTile(dd, mesh, 0, tile, flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawNavMeshWithClosedList(struct duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery& query, unsigned char flags)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
const dtNavMeshQuery* q = (flags & DU_DRAWNAVMESH_CLOSEDLIST) ? &query : 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
|
||||||
{
|
|
||||||
const dtMeshTile* tile = mesh.getTile(i);
|
|
||||||
if (!tile->header) continue;
|
|
||||||
drawMeshTile(dd, mesh, q, tile, flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
const dtNodePool* pool = query.getNodePool();
|
|
||||||
if (pool)
|
|
||||||
{
|
|
||||||
const float off = 0.5f;
|
|
||||||
dd->begin(DU_DRAW_POINTS, 4.0f);
|
|
||||||
for (int i = 0; i < pool->getHashSize(); ++i)
|
|
||||||
{
|
|
||||||
for (dtNodeIndex j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
|
|
||||||
{
|
|
||||||
const dtNode* node = pool->getNodeAtIdx(j+1);
|
|
||||||
if (!node) continue;
|
|
||||||
dd->vertex(node->pos[0],node->pos[1]+off,node->pos[2], duRGBA(255,192,0,255));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
|
||||||
for (int i = 0; i < pool->getHashSize(); ++i)
|
|
||||||
{
|
|
||||||
for (dtNodeIndex j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
|
|
||||||
{
|
|
||||||
const dtNode* node = pool->getNodeAtIdx(j+1);
|
|
||||||
if (!node) continue;
|
|
||||||
if (!node->pidx) continue;
|
|
||||||
const dtNode* parent = pool->getNodeAtIdx(node->pidx);
|
|
||||||
if (!parent) continue;
|
|
||||||
dd->vertex(node->pos[0],node->pos[1]+off,node->pos[2], duRGBA(255,192,0,128));
|
|
||||||
dd->vertex(parent->pos[0],parent->pos[1]+off,parent->pos[2], duRGBA(255,192,0,128));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void drawMeshTileBVTree(duDebugDraw* dd, const dtMeshTile* tile)
|
|
||||||
{
|
|
||||||
// Draw BV nodes.
|
|
||||||
const float cs = 1.0f / tile->header->bvQuantFactor;
|
|
||||||
dd->begin(DU_DRAW_LINES, 1.0f);
|
|
||||||
for (int i = 0; i < tile->header->bvNodeCount; ++i)
|
|
||||||
{
|
|
||||||
const dtBVNode* n = &tile->bvTree[i];
|
|
||||||
if (n->i < 0) // Leaf indices are positive.
|
|
||||||
continue;
|
|
||||||
duAppendBoxWire(dd, tile->header->bmin[0] + n->bmin[0]*cs,
|
|
||||||
tile->header->bmin[1] + n->bmin[1]*cs,
|
|
||||||
tile->header->bmin[2] + n->bmin[2]*cs,
|
|
||||||
tile->header->bmin[0] + n->bmax[0]*cs,
|
|
||||||
tile->header->bmin[1] + n->bmax[1]*cs,
|
|
||||||
tile->header->bmin[2] + n->bmax[2]*cs,
|
|
||||||
duRGBA(255,255,255,128));
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawNavMeshBVTree(duDebugDraw* dd, const dtNavMesh& mesh)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
|
||||||
{
|
|
||||||
const dtMeshTile* tile = mesh.getTile(i);
|
|
||||||
if (!tile->header) continue;
|
|
||||||
drawMeshTileBVTree(dd, tile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drawMeshTilePortal(duDebugDraw* dd, const dtMeshTile* tile)
|
|
||||||
{
|
|
||||||
// Draw portals
|
|
||||||
const float padx = 0.04f;
|
|
||||||
const float pady = tile->header->walkableClimb;
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
|
||||||
|
|
||||||
for (int side = 0; side < 8; ++side)
|
|
||||||
{
|
|
||||||
unsigned short m = DT_EXT_LINK | (unsigned short)side;
|
|
||||||
|
|
||||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
|
||||||
{
|
|
||||||
dtPoly* poly = &tile->polys[i];
|
|
||||||
|
|
||||||
// Create new links.
|
|
||||||
const int nv = poly->vertCount;
|
|
||||||
for (int j = 0; j < nv; ++j)
|
|
||||||
{
|
|
||||||
// Skip edges which do not point to the right side.
|
|
||||||
if (poly->neis[j] != m)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Create new links
|
|
||||||
const float* va = &tile->verts[poly->verts[j]*3];
|
|
||||||
const float* vb = &tile->verts[poly->verts[(j+1) % nv]*3];
|
|
||||||
|
|
||||||
if (side == 0 || side == 4)
|
|
||||||
{
|
|
||||||
unsigned int col = side == 0 ? duRGBA(128,0,0,128) : duRGBA(128,0,128,128);
|
|
||||||
|
|
||||||
const float x = va[0] + ((side == 0) ? -padx : padx);
|
|
||||||
|
|
||||||
dd->vertex(x,va[1]-pady,va[2], col);
|
|
||||||
dd->vertex(x,va[1]+pady,va[2], col);
|
|
||||||
|
|
||||||
dd->vertex(x,va[1]+pady,va[2], col);
|
|
||||||
dd->vertex(x,vb[1]+pady,vb[2], col);
|
|
||||||
|
|
||||||
dd->vertex(x,vb[1]+pady,vb[2], col);
|
|
||||||
dd->vertex(x,vb[1]-pady,vb[2], col);
|
|
||||||
|
|
||||||
dd->vertex(x,vb[1]-pady,vb[2], col);
|
|
||||||
dd->vertex(x,va[1]-pady,va[2], col);
|
|
||||||
}
|
|
||||||
else if (side == 2 || side == 6)
|
|
||||||
{
|
|
||||||
unsigned int col = side == 2 ? duRGBA(0,128,0,128) : duRGBA(0,128,128,128);
|
|
||||||
|
|
||||||
const float z = va[2] + ((side == 2) ? -padx : padx);
|
|
||||||
|
|
||||||
dd->vertex(va[0],va[1]-pady,z, col);
|
|
||||||
dd->vertex(va[0],va[1]+pady,z, col);
|
|
||||||
|
|
||||||
dd->vertex(va[0],va[1]+pady,z, col);
|
|
||||||
dd->vertex(vb[0],vb[1]+pady,z, col);
|
|
||||||
|
|
||||||
dd->vertex(vb[0],vb[1]+pady,z, col);
|
|
||||||
dd->vertex(vb[0],vb[1]-pady,z, col);
|
|
||||||
|
|
||||||
dd->vertex(vb[0],vb[1]-pady,z, col);
|
|
||||||
dd->vertex(va[0],va[1]-pady,z, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawNavMeshPortals(duDebugDraw* dd, const dtNavMesh& mesh)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
|
||||||
{
|
|
||||||
const dtMeshTile* tile = mesh.getTile(i);
|
|
||||||
if (!tile->header) continue;
|
|
||||||
drawMeshTilePortal(dd, tile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawNavMeshPolysWithFlags(struct duDebugDraw* dd, const dtNavMesh& mesh,
|
|
||||||
const unsigned short polyFlags, const unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
|
||||||
{
|
|
||||||
const dtMeshTile* tile = mesh.getTile(i);
|
|
||||||
if (!tile->header) continue;
|
|
||||||
dtPolyRef base = mesh.getPolyRefBase(tile);
|
|
||||||
|
|
||||||
for (int j = 0; j < tile->header->polyCount; ++j)
|
|
||||||
{
|
|
||||||
const dtPoly* p = &tile->polys[j];
|
|
||||||
if ((p->flags & polyFlags) == 0) continue;
|
|
||||||
duDebugDrawNavMeshPoly(dd, mesh, base|(dtPolyRef)j, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawNavMeshPoly(duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
const dtMeshTile* tile = 0;
|
|
||||||
const dtPoly* poly = 0;
|
|
||||||
if (dtStatusFailed(mesh.getTileAndPolyByRef(ref, &tile, &poly)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
dd->depthMask(false);
|
|
||||||
|
|
||||||
const unsigned int c = duTransCol(col, 64);
|
|
||||||
const unsigned int ip = (unsigned int)(poly - tile->polys);
|
|
||||||
|
|
||||||
if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
|
|
||||||
{
|
|
||||||
dtOffMeshConnection* con = &tile->offMeshCons[ip - tile->header->offMeshBase];
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
|
||||||
|
|
||||||
// Connection arc.
|
|
||||||
duAppendArc(dd, con->pos[0],con->pos[1],con->pos[2], con->pos[3],con->pos[4],con->pos[5], 0.25f,
|
|
||||||
(con->flags & 1) ? 0.6f : 0.0f, 0.6f, c);
|
|
||||||
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const dtPolyDetail* pd = &tile->detailMeshes[ip];
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_TRIS);
|
|
||||||
for (int i = 0; i < pd->triCount; ++i)
|
|
||||||
{
|
|
||||||
const unsigned char* t = &tile->detailTris[(pd->triBase+i)*4];
|
|
||||||
for (int j = 0; j < 3; ++j)
|
|
||||||
{
|
|
||||||
if (t[j] < poly->vertCount)
|
|
||||||
dd->vertex(&tile->verts[poly->verts[t[j]]*3], c);
|
|
||||||
else
|
|
||||||
dd->vertex(&tile->detailVerts[(pd->vertBase+t[j]-poly->vertCount)*3], c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
dd->depthMask(true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void debugDrawTileCachePortals(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
|
||||||
{
|
|
||||||
const int w = (int)layer.header->width;
|
|
||||||
const int h = (int)layer.header->height;
|
|
||||||
const float* bmin = layer.header->bmin;
|
|
||||||
|
|
||||||
// Portals
|
|
||||||
unsigned int pcol = duRGBA(255,255,255,255);
|
|
||||||
|
|
||||||
const int segs[4*4] = {0,0,0,1, 0,1,1,1, 1,1,1,0, 1,0,0,0};
|
|
||||||
|
|
||||||
// Layer portals
|
|
||||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
|
||||||
for (int y = 0; y < h; ++y)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < w; ++x)
|
|
||||||
{
|
|
||||||
const int idx = x+y*w;
|
|
||||||
const int lh = (int)layer.heights[idx];
|
|
||||||
if (lh == 0xff) continue;
|
|
||||||
|
|
||||||
for (int dir = 0; dir < 4; ++dir)
|
|
||||||
{
|
|
||||||
if (layer.cons[idx] & (1<<(dir+4)))
|
|
||||||
{
|
|
||||||
const int* seg = &segs[dir*4];
|
|
||||||
const float ax = bmin[0] + (x+seg[0])*cs;
|
|
||||||
const float ay = bmin[1] + (lh+2)*ch;
|
|
||||||
const float az = bmin[2] + (y+seg[1])*cs;
|
|
||||||
const float bx = bmin[0] + (x+seg[2])*cs;
|
|
||||||
const float by = bmin[1] + (lh+2)*ch;
|
|
||||||
const float bz = bmin[2] + (y+seg[3])*cs;
|
|
||||||
dd->vertex(ax, ay, az, pcol);
|
|
||||||
dd->vertex(bx, by, bz, pcol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawTileCacheLayerAreas(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
|
||||||
{
|
|
||||||
const int w = (int)layer.header->width;
|
|
||||||
const int h = (int)layer.header->height;
|
|
||||||
const float* bmin = layer.header->bmin;
|
|
||||||
const float* bmax = layer.header->bmax;
|
|
||||||
const int idx = layer.header->tlayer;
|
|
||||||
|
|
||||||
unsigned int color = duIntToCol(idx+1, 255);
|
|
||||||
|
|
||||||
// Layer bounds
|
|
||||||
float lbmin[3], lbmax[3];
|
|
||||||
lbmin[0] = bmin[0] + layer.header->minx*cs;
|
|
||||||
lbmin[1] = bmin[1];
|
|
||||||
lbmin[2] = bmin[2] + layer.header->miny*cs;
|
|
||||||
lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
|
|
||||||
lbmax[1] = bmax[1];
|
|
||||||
lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
|
|
||||||
duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
|
|
||||||
|
|
||||||
// Layer height
|
|
||||||
dd->begin(DU_DRAW_QUADS);
|
|
||||||
for (int y = 0; y < h; ++y)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < w; ++x)
|
|
||||||
{
|
|
||||||
const int lidx = x+y*w;
|
|
||||||
const int lh = (int)layer.heights[lidx];
|
|
||||||
if (lh == 0xff) continue;
|
|
||||||
|
|
||||||
const unsigned char area = layer.areas[lidx];
|
|
||||||
unsigned int col;
|
|
||||||
if (area == 63)
|
|
||||||
col = duLerpCol(color, duRGBA(0,192,255,64), 32);
|
|
||||||
else if (area == 0)
|
|
||||||
col = duLerpCol(color, duRGBA(0,0,0,64), 32);
|
|
||||||
else
|
|
||||||
col = duLerpCol(color, dd->areaToCol(area), 32);
|
|
||||||
|
|
||||||
const float fx = bmin[0] + x*cs;
|
|
||||||
const float fy = bmin[1] + (lh+1)*ch;
|
|
||||||
const float fz = bmin[2] + y*cs;
|
|
||||||
|
|
||||||
dd->vertex(fx, fy, fz, col);
|
|
||||||
dd->vertex(fx, fy, fz+cs, col);
|
|
||||||
dd->vertex(fx+cs, fy, fz+cs, col);
|
|
||||||
dd->vertex(fx+cs, fy, fz, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
|
|
||||||
debugDrawTileCachePortals(dd, layer, cs, ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawTileCacheLayerRegions(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
|
||||||
{
|
|
||||||
const int w = (int)layer.header->width;
|
|
||||||
const int h = (int)layer.header->height;
|
|
||||||
const float* bmin = layer.header->bmin;
|
|
||||||
const float* bmax = layer.header->bmax;
|
|
||||||
const int idx = layer.header->tlayer;
|
|
||||||
|
|
||||||
unsigned int color = duIntToCol(idx+1, 255);
|
|
||||||
|
|
||||||
// Layer bounds
|
|
||||||
float lbmin[3], lbmax[3];
|
|
||||||
lbmin[0] = bmin[0] + layer.header->minx*cs;
|
|
||||||
lbmin[1] = bmin[1];
|
|
||||||
lbmin[2] = bmin[2] + layer.header->miny*cs;
|
|
||||||
lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
|
|
||||||
lbmax[1] = bmax[1];
|
|
||||||
lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
|
|
||||||
duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
|
|
||||||
|
|
||||||
// Layer height
|
|
||||||
dd->begin(DU_DRAW_QUADS);
|
|
||||||
for (int y = 0; y < h; ++y)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < w; ++x)
|
|
||||||
{
|
|
||||||
const int lidx = x+y*w;
|
|
||||||
const int lh = (int)layer.heights[lidx];
|
|
||||||
if (lh == 0xff) continue;
|
|
||||||
const unsigned char reg = layer.regs[lidx];
|
|
||||||
|
|
||||||
unsigned int col = duLerpCol(color, duIntToCol(reg, 255), 192);
|
|
||||||
|
|
||||||
const float fx = bmin[0] + x*cs;
|
|
||||||
const float fy = bmin[1] + (lh+1)*ch;
|
|
||||||
const float fz = bmin[2] + y*cs;
|
|
||||||
|
|
||||||
dd->vertex(fx, fy, fz, col);
|
|
||||||
dd->vertex(fx, fy, fz+cs, col);
|
|
||||||
dd->vertex(fx+cs, fy, fz+cs, col);
|
|
||||||
dd->vertex(fx+cs, fy, fz, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
|
|
||||||
debugDrawTileCachePortals(dd, layer, cs, ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*struct dtTileCacheContour
|
|
||||||
{
|
|
||||||
int nverts;
|
|
||||||
unsigned char* verts;
|
|
||||||
unsigned char reg;
|
|
||||||
unsigned char area;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dtTileCacheContourSet
|
|
||||||
{
|
|
||||||
int nconts;
|
|
||||||
dtTileCacheContour* conts;
|
|
||||||
};*/
|
|
||||||
|
|
||||||
void duDebugDrawTileCacheContours(duDebugDraw* dd, const struct dtTileCacheContourSet& lcset,
|
|
||||||
const float* orig, const float cs, const float ch)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
const unsigned char a = 255;// (unsigned char)(alpha*255.0f);
|
|
||||||
|
|
||||||
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
|
||||||
|
|
||||||
for (int i = 0; i < lcset.nconts; ++i)
|
|
||||||
{
|
|
||||||
const dtTileCacheContour& c = lcset.conts[i];
|
|
||||||
unsigned int color = 0;
|
|
||||||
|
|
||||||
color = duIntToCol(i, a);
|
|
||||||
|
|
||||||
for (int j = 0; j < c.nverts; ++j)
|
|
||||||
{
|
|
||||||
const int k = (j+1) % c.nverts;
|
|
||||||
const unsigned char* va = &c.verts[j*4];
|
|
||||||
const unsigned char* vb = &c.verts[k*4];
|
|
||||||
const float ax = orig[0] + va[0]*cs;
|
|
||||||
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
|
|
||||||
const float az = orig[2] + va[2]*cs;
|
|
||||||
const float bx = orig[0] + vb[0]*cs;
|
|
||||||
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
|
|
||||||
const float bz = orig[2] + vb[2]*cs;
|
|
||||||
unsigned int col = color;
|
|
||||||
if ((va[3] & 0xf) != 0xf)
|
|
||||||
{
|
|
||||||
// Portal segment
|
|
||||||
col = duRGBA(255,255,255,128);
|
|
||||||
int d = va[3] & 0xf;
|
|
||||||
|
|
||||||
const float cx = (ax+bx)*0.5f;
|
|
||||||
const float cy = (ay+by)*0.5f;
|
|
||||||
const float cz = (az+bz)*0.5f;
|
|
||||||
|
|
||||||
const float dx = cx + offs[d*2+0]*2*cs;
|
|
||||||
const float dy = cy;
|
|
||||||
const float dz = cz + offs[d*2+1]*2*cs;
|
|
||||||
|
|
||||||
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
|
|
||||||
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
|
|
||||||
}
|
|
||||||
|
|
||||||
duAppendArrow(dd, ax,ay,az, bx,by,bz, 0.0f, cs*0.5f, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_POINTS, 4.0f);
|
|
||||||
|
|
||||||
for (int i = 0; i < lcset.nconts; ++i)
|
|
||||||
{
|
|
||||||
const dtTileCacheContour& c = lcset.conts[i];
|
|
||||||
unsigned int color = 0;
|
|
||||||
|
|
||||||
for (int j = 0; j < c.nverts; ++j)
|
|
||||||
{
|
|
||||||
const unsigned char* va = &c.verts[j*4];
|
|
||||||
|
|
||||||
color = duDarkenCol(duIntToCol(i, a));
|
|
||||||
if (va[3] & 0x80)
|
|
||||||
{
|
|
||||||
// Border vertex
|
|
||||||
color = duRGBA(255,0,0,255);
|
|
||||||
}
|
|
||||||
|
|
||||||
float fx = orig[0] + va[0]*cs;
|
|
||||||
float fy = orig[1] + (va[1]+1+(i&1))*ch;
|
|
||||||
float fz = orig[2] + va[2]*cs;
|
|
||||||
dd->vertex(fx,fy,fz, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void duDebugDrawTileCachePolyMesh(duDebugDraw* dd, const struct dtTileCachePolyMesh& lmesh,
|
|
||||||
const float* orig, const float cs, const float ch)
|
|
||||||
{
|
|
||||||
if (!dd) return;
|
|
||||||
|
|
||||||
const int nvp = lmesh.nvp;
|
|
||||||
|
|
||||||
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_TRIS);
|
|
||||||
|
|
||||||
for (int i = 0; i < lmesh.npolys; ++i)
|
|
||||||
{
|
|
||||||
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
|
||||||
const unsigned char area = lmesh.areas[i];
|
|
||||||
|
|
||||||
unsigned int color;
|
|
||||||
if (area == DT_TILECACHE_WALKABLE_AREA)
|
|
||||||
color = duRGBA(0,192,255,64);
|
|
||||||
else if (area == DT_TILECACHE_NULL_AREA)
|
|
||||||
color = duRGBA(0,0,0,64);
|
|
||||||
else
|
|
||||||
color = dd->areaToCol(area);
|
|
||||||
|
|
||||||
unsigned short vi[3];
|
|
||||||
for (int j = 2; j < nvp; ++j)
|
|
||||||
{
|
|
||||||
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
|
||||||
vi[0] = p[0];
|
|
||||||
vi[1] = p[j-1];
|
|
||||||
vi[2] = p[j];
|
|
||||||
for (int k = 0; k < 3; ++k)
|
|
||||||
{
|
|
||||||
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
|
||||||
const float x = orig[0] + v[0]*cs;
|
|
||||||
const float y = orig[1] + (v[1]+1)*ch;
|
|
||||||
const float z = orig[2] + v[2]*cs;
|
|
||||||
dd->vertex(x,y,z, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
|
|
||||||
// Draw neighbours edges
|
|
||||||
const unsigned int coln = duRGBA(0,48,64,32);
|
|
||||||
dd->begin(DU_DRAW_LINES, 1.5f);
|
|
||||||
for (int i = 0; i < lmesh.npolys; ++i)
|
|
||||||
{
|
|
||||||
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
|
||||||
for (int j = 0; j < nvp; ++j)
|
|
||||||
{
|
|
||||||
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
|
||||||
if (p[nvp+j] & 0x8000) continue;
|
|
||||||
const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1;
|
|
||||||
int vi[2] = {p[j], p[nj]};
|
|
||||||
|
|
||||||
for (int k = 0; k < 2; ++k)
|
|
||||||
{
|
|
||||||
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
|
||||||
const float x = orig[0] + v[0]*cs;
|
|
||||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
|
||||||
const float z = orig[2] + v[2]*cs;
|
|
||||||
dd->vertex(x, y, z, coln);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
|
|
||||||
// Draw boundary edges
|
|
||||||
const unsigned int colb = duRGBA(0,48,64,220);
|
|
||||||
dd->begin(DU_DRAW_LINES, 2.5f);
|
|
||||||
for (int i = 0; i < lmesh.npolys; ++i)
|
|
||||||
{
|
|
||||||
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
|
||||||
for (int j = 0; j < nvp; ++j)
|
|
||||||
{
|
|
||||||
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
|
||||||
if ((p[nvp+j] & 0x8000) == 0) continue;
|
|
||||||
const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1;
|
|
||||||
int vi[2] = {p[j], p[nj]};
|
|
||||||
|
|
||||||
unsigned int col = colb;
|
|
||||||
if ((p[nvp+j] & 0xf) != 0xf)
|
|
||||||
{
|
|
||||||
const unsigned short* va = &lmesh.verts[vi[0]*3];
|
|
||||||
const unsigned short* vb = &lmesh.verts[vi[1]*3];
|
|
||||||
|
|
||||||
const float ax = orig[0] + va[0]*cs;
|
|
||||||
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
|
|
||||||
const float az = orig[2] + va[2]*cs;
|
|
||||||
const float bx = orig[0] + vb[0]*cs;
|
|
||||||
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
|
|
||||||
const float bz = orig[2] + vb[2]*cs;
|
|
||||||
|
|
||||||
const float cx = (ax+bx)*0.5f;
|
|
||||||
const float cy = (ay+by)*0.5f;
|
|
||||||
const float cz = (az+bz)*0.5f;
|
|
||||||
|
|
||||||
int d = p[nvp+j] & 0xf;
|
|
||||||
|
|
||||||
const float dx = cx + offs[d*2+0]*2*cs;
|
|
||||||
const float dy = cy;
|
|
||||||
const float dz = cz + offs[d*2+1]*2*cs;
|
|
||||||
|
|
||||||
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
|
|
||||||
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
|
|
||||||
|
|
||||||
col = duRGBA(255,255,255,128);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int k = 0; k < 2; ++k)
|
|
||||||
{
|
|
||||||
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
|
||||||
const float x = orig[0] + v[0]*cs;
|
|
||||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
|
||||||
const float z = orig[2] + v[2]*cs;
|
|
||||||
dd->vertex(x, y, z, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
|
|
||||||
dd->begin(DU_DRAW_POINTS, 3.0f);
|
|
||||||
const unsigned int colv = duRGBA(0,0,0,220);
|
|
||||||
for (int i = 0; i < lmesh.nverts; ++i)
|
|
||||||
{
|
|
||||||
const unsigned short* v = &lmesh.verts[i*3];
|
|
||||||
const float x = orig[0] + v[0]*cs;
|
|
||||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
|
||||||
const float z = orig[2] + v[2]*cs;
|
|
||||||
dd->vertex(x,y,z, colv);
|
|
||||||
}
|
|
||||||
dd->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,451 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#define _USE_MATH_DEFINES
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "Recast.h"
|
|
||||||
#include "RecastAlloc.h"
|
|
||||||
#include "RecastDump.h"
|
|
||||||
|
|
||||||
|
|
||||||
duFileIO::~duFileIO()
|
|
||||||
{
|
|
||||||
// Empty
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ioprintf(duFileIO* io, const char* format, ...)
|
|
||||||
{
|
|
||||||
char line[256];
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, format);
|
|
||||||
const int n = vsnprintf(line, sizeof(line), format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
if (n > 0)
|
|
||||||
io->write(line, sizeof(char)*n);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool duDumpPolyMeshToObj(rcPolyMesh& pmesh, duFileIO* io)
|
|
||||||
{
|
|
||||||
if (!io)
|
|
||||||
{
|
|
||||||
printf("duDumpPolyMeshToObj: input IO is null.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!io->isWriting())
|
|
||||||
{
|
|
||||||
printf("duDumpPolyMeshToObj: input IO not writing.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int nvp = pmesh.nvp;
|
|
||||||
const float cs = pmesh.cs;
|
|
||||||
const float ch = pmesh.ch;
|
|
||||||
const float* orig = pmesh.bmin;
|
|
||||||
|
|
||||||
ioprintf(io, "# Recast Navmesh\n");
|
|
||||||
ioprintf(io, "o NavMesh\n");
|
|
||||||
|
|
||||||
ioprintf(io, "\n");
|
|
||||||
|
|
||||||
for (int i = 0; i < pmesh.nverts; ++i)
|
|
||||||
{
|
|
||||||
const unsigned short* v = &pmesh.verts[i*3];
|
|
||||||
const float x = orig[0] + v[0]*cs;
|
|
||||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
|
||||||
const float z = orig[2] + v[2]*cs;
|
|
||||||
ioprintf(io, "v %f %f %f\n", x,y,z);
|
|
||||||
}
|
|
||||||
|
|
||||||
ioprintf(io, "\n");
|
|
||||||
|
|
||||||
for (int i = 0; i < pmesh.npolys; ++i)
|
|
||||||
{
|
|
||||||
const unsigned short* p = &pmesh.polys[i*nvp*2];
|
|
||||||
for (int j = 2; j < nvp; ++j)
|
|
||||||
{
|
|
||||||
if (p[j] == RC_MESH_NULL_IDX) break;
|
|
||||||
ioprintf(io, "f %d %d %d\n", p[0]+1, p[j-1]+1, p[j]+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool duDumpPolyMeshDetailToObj(rcPolyMeshDetail& dmesh, duFileIO* io)
|
|
||||||
{
|
|
||||||
if (!io)
|
|
||||||
{
|
|
||||||
printf("duDumpPolyMeshDetailToObj: input IO is null.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!io->isWriting())
|
|
||||||
{
|
|
||||||
printf("duDumpPolyMeshDetailToObj: input IO not writing.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ioprintf(io, "# Recast Navmesh\n");
|
|
||||||
ioprintf(io, "o NavMesh\n");
|
|
||||||
|
|
||||||
ioprintf(io, "\n");
|
|
||||||
|
|
||||||
for (int i = 0; i < dmesh.nverts; ++i)
|
|
||||||
{
|
|
||||||
const float* v = &dmesh.verts[i*3];
|
|
||||||
ioprintf(io, "v %f %f %f\n", v[0],v[1],v[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ioprintf(io, "\n");
|
|
||||||
|
|
||||||
for (int i = 0; i < dmesh.nmeshes; ++i)
|
|
||||||
{
|
|
||||||
const unsigned int* m = &dmesh.meshes[i*4];
|
|
||||||
const unsigned int bverts = m[0];
|
|
||||||
const unsigned int btris = m[2];
|
|
||||||
const unsigned int ntris = m[3];
|
|
||||||
const unsigned char* tris = &dmesh.tris[btris*4];
|
|
||||||
for (unsigned int j = 0; j < ntris; ++j)
|
|
||||||
{
|
|
||||||
ioprintf(io, "f %d %d %d\n",
|
|
||||||
(int)(bverts+tris[j*4+0])+1,
|
|
||||||
(int)(bverts+tris[j*4+1])+1,
|
|
||||||
(int)(bverts+tris[j*4+2])+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const int CSET_MAGIC = ('c' << 24) | ('s' << 16) | ('e' << 8) | 't';
|
|
||||||
static const int CSET_VERSION = 2;
|
|
||||||
|
|
||||||
bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io)
|
|
||||||
{
|
|
||||||
if (!io)
|
|
||||||
{
|
|
||||||
printf("duDumpContourSet: input IO is null.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!io->isWriting())
|
|
||||||
{
|
|
||||||
printf("duDumpContourSet: input IO not writing.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
io->write(&CSET_MAGIC, sizeof(CSET_MAGIC));
|
|
||||||
io->write(&CSET_VERSION, sizeof(CSET_VERSION));
|
|
||||||
|
|
||||||
io->write(&cset.nconts, sizeof(cset.nconts));
|
|
||||||
|
|
||||||
io->write(cset.bmin, sizeof(cset.bmin));
|
|
||||||
io->write(cset.bmax, sizeof(cset.bmax));
|
|
||||||
|
|
||||||
io->write(&cset.cs, sizeof(cset.cs));
|
|
||||||
io->write(&cset.ch, sizeof(cset.ch));
|
|
||||||
|
|
||||||
io->write(&cset.width, sizeof(cset.width));
|
|
||||||
io->write(&cset.height, sizeof(cset.height));
|
|
||||||
io->write(&cset.borderSize, sizeof(cset.borderSize));
|
|
||||||
|
|
||||||
for (int i = 0; i < cset.nconts; ++i)
|
|
||||||
{
|
|
||||||
const rcContour& cont = cset.conts[i];
|
|
||||||
io->write(&cont.nverts, sizeof(cont.nverts));
|
|
||||||
io->write(&cont.nrverts, sizeof(cont.nrverts));
|
|
||||||
io->write(&cont.reg, sizeof(cont.reg));
|
|
||||||
io->write(&cont.area, sizeof(cont.area));
|
|
||||||
io->write(cont.verts, sizeof(int)*4*cont.nverts);
|
|
||||||
io->write(cont.rverts, sizeof(int)*4*cont.nrverts);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool duReadContourSet(struct rcContourSet& cset, duFileIO* io)
|
|
||||||
{
|
|
||||||
if (!io)
|
|
||||||
{
|
|
||||||
printf("duReadContourSet: input IO is null.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!io->isReading())
|
|
||||||
{
|
|
||||||
printf("duReadContourSet: input IO not reading.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int magic = 0;
|
|
||||||
int version = 0;
|
|
||||||
|
|
||||||
io->read(&magic, sizeof(magic));
|
|
||||||
io->read(&version, sizeof(version));
|
|
||||||
|
|
||||||
if (magic != CSET_MAGIC)
|
|
||||||
{
|
|
||||||
printf("duReadContourSet: Bad voodoo.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (version != CSET_VERSION)
|
|
||||||
{
|
|
||||||
printf("duReadContourSet: Bad version.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
io->read(&cset.nconts, sizeof(cset.nconts));
|
|
||||||
|
|
||||||
cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*cset.nconts, RC_ALLOC_PERM);
|
|
||||||
if (!cset.conts)
|
|
||||||
{
|
|
||||||
printf("duReadContourSet: Could not alloc contours (%d)\n", cset.nconts);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
memset(cset.conts, 0, sizeof(rcContour)*cset.nconts);
|
|
||||||
|
|
||||||
io->read(cset.bmin, sizeof(cset.bmin));
|
|
||||||
io->read(cset.bmax, sizeof(cset.bmax));
|
|
||||||
|
|
||||||
io->read(&cset.cs, sizeof(cset.cs));
|
|
||||||
io->read(&cset.ch, sizeof(cset.ch));
|
|
||||||
|
|
||||||
io->read(&cset.width, sizeof(cset.width));
|
|
||||||
io->read(&cset.height, sizeof(cset.height));
|
|
||||||
io->read(&cset.borderSize, sizeof(cset.borderSize));
|
|
||||||
|
|
||||||
for (int i = 0; i < cset.nconts; ++i)
|
|
||||||
{
|
|
||||||
rcContour& cont = cset.conts[i];
|
|
||||||
io->read(&cont.nverts, sizeof(cont.nverts));
|
|
||||||
io->read(&cont.nrverts, sizeof(cont.nrverts));
|
|
||||||
io->read(&cont.reg, sizeof(cont.reg));
|
|
||||||
io->read(&cont.area, sizeof(cont.area));
|
|
||||||
|
|
||||||
cont.verts = (int*)rcAlloc(sizeof(int)*4*cont.nverts, RC_ALLOC_PERM);
|
|
||||||
if (!cont.verts)
|
|
||||||
{
|
|
||||||
printf("duReadContourSet: Could not alloc contour verts (%d)\n", cont.nverts);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cont.rverts = (int*)rcAlloc(sizeof(int)*4*cont.nrverts, RC_ALLOC_PERM);
|
|
||||||
if (!cont.rverts)
|
|
||||||
{
|
|
||||||
printf("duReadContourSet: Could not alloc contour rverts (%d)\n", cont.nrverts);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
io->read(cont.verts, sizeof(int)*4*cont.nverts);
|
|
||||||
io->read(cont.rverts, sizeof(int)*4*cont.nrverts);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const int CHF_MAGIC = ('r' << 24) | ('c' << 16) | ('h' << 8) | 'f';
|
|
||||||
static const int CHF_VERSION = 3;
|
|
||||||
|
|
||||||
bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
|
|
||||||
{
|
|
||||||
if (!io)
|
|
||||||
{
|
|
||||||
printf("duDumpCompactHeightfield: input IO is null.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!io->isWriting())
|
|
||||||
{
|
|
||||||
printf("duDumpCompactHeightfield: input IO not writing.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
io->write(&CHF_MAGIC, sizeof(CHF_MAGIC));
|
|
||||||
io->write(&CHF_VERSION, sizeof(CHF_VERSION));
|
|
||||||
|
|
||||||
io->write(&chf.width, sizeof(chf.width));
|
|
||||||
io->write(&chf.height, sizeof(chf.height));
|
|
||||||
io->write(&chf.spanCount, sizeof(chf.spanCount));
|
|
||||||
|
|
||||||
io->write(&chf.walkableHeight, sizeof(chf.walkableHeight));
|
|
||||||
io->write(&chf.walkableClimb, sizeof(chf.walkableClimb));
|
|
||||||
io->write(&chf.borderSize, sizeof(chf.borderSize));
|
|
||||||
|
|
||||||
io->write(&chf.maxDistance, sizeof(chf.maxDistance));
|
|
||||||
io->write(&chf.maxRegions, sizeof(chf.maxRegions));
|
|
||||||
|
|
||||||
io->write(chf.bmin, sizeof(chf.bmin));
|
|
||||||
io->write(chf.bmax, sizeof(chf.bmax));
|
|
||||||
|
|
||||||
io->write(&chf.cs, sizeof(chf.cs));
|
|
||||||
io->write(&chf.ch, sizeof(chf.ch));
|
|
||||||
|
|
||||||
int tmp = 0;
|
|
||||||
if (chf.cells) tmp |= 1;
|
|
||||||
if (chf.spans) tmp |= 2;
|
|
||||||
if (chf.dist) tmp |= 4;
|
|
||||||
if (chf.areas) tmp |= 8;
|
|
||||||
|
|
||||||
io->write(&tmp, sizeof(tmp));
|
|
||||||
|
|
||||||
if (chf.cells)
|
|
||||||
io->write(chf.cells, sizeof(rcCompactCell)*chf.width*chf.height);
|
|
||||||
if (chf.spans)
|
|
||||||
io->write(chf.spans, sizeof(rcCompactSpan)*chf.spanCount);
|
|
||||||
if (chf.dist)
|
|
||||||
io->write(chf.dist, sizeof(unsigned short)*chf.spanCount);
|
|
||||||
if (chf.areas)
|
|
||||||
io->write(chf.areas, sizeof(unsigned char)*chf.spanCount);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool duReadCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
|
|
||||||
{
|
|
||||||
if (!io)
|
|
||||||
{
|
|
||||||
printf("duReadCompactHeightfield: input IO is null.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!io->isReading())
|
|
||||||
{
|
|
||||||
printf("duReadCompactHeightfield: input IO not reading.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int magic = 0;
|
|
||||||
int version = 0;
|
|
||||||
|
|
||||||
io->read(&magic, sizeof(magic));
|
|
||||||
io->read(&version, sizeof(version));
|
|
||||||
|
|
||||||
if (magic != CHF_MAGIC)
|
|
||||||
{
|
|
||||||
printf("duReadCompactHeightfield: Bad voodoo.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (version != CHF_VERSION)
|
|
||||||
{
|
|
||||||
printf("duReadCompactHeightfield: Bad version.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
io->read(&chf.width, sizeof(chf.width));
|
|
||||||
io->read(&chf.height, sizeof(chf.height));
|
|
||||||
io->read(&chf.spanCount, sizeof(chf.spanCount));
|
|
||||||
|
|
||||||
io->read(&chf.walkableHeight, sizeof(chf.walkableHeight));
|
|
||||||
io->read(&chf.walkableClimb, sizeof(chf.walkableClimb));
|
|
||||||
io->read(&chf.borderSize, sizeof(chf.borderSize));
|
|
||||||
|
|
||||||
io->read(&chf.maxDistance, sizeof(chf.maxDistance));
|
|
||||||
io->read(&chf.maxRegions, sizeof(chf.maxRegions));
|
|
||||||
|
|
||||||
io->read(chf.bmin, sizeof(chf.bmin));
|
|
||||||
io->read(chf.bmax, sizeof(chf.bmax));
|
|
||||||
|
|
||||||
io->read(&chf.cs, sizeof(chf.cs));
|
|
||||||
io->read(&chf.ch, sizeof(chf.ch));
|
|
||||||
|
|
||||||
int tmp = 0;
|
|
||||||
io->read(&tmp, sizeof(tmp));
|
|
||||||
|
|
||||||
if (tmp & 1)
|
|
||||||
{
|
|
||||||
chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*chf.width*chf.height, RC_ALLOC_PERM);
|
|
||||||
if (!chf.cells)
|
|
||||||
{
|
|
||||||
printf("duReadCompactHeightfield: Could not alloc cells (%d)\n", chf.width*chf.height);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
io->read(chf.cells, sizeof(rcCompactCell)*chf.width*chf.height);
|
|
||||||
}
|
|
||||||
if (tmp & 2)
|
|
||||||
{
|
|
||||||
chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*chf.spanCount, RC_ALLOC_PERM);
|
|
||||||
if (!chf.spans)
|
|
||||||
{
|
|
||||||
printf("duReadCompactHeightfield: Could not alloc spans (%d)\n", chf.spanCount);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
io->read(chf.spans, sizeof(rcCompactSpan)*chf.spanCount);
|
|
||||||
}
|
|
||||||
if (tmp & 4)
|
|
||||||
{
|
|
||||||
chf.dist = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_PERM);
|
|
||||||
if (!chf.dist)
|
|
||||||
{
|
|
||||||
printf("duReadCompactHeightfield: Could not alloc dist (%d)\n", chf.spanCount);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
io->read(chf.dist, sizeof(unsigned short)*chf.spanCount);
|
|
||||||
}
|
|
||||||
if (tmp & 8)
|
|
||||||
{
|
|
||||||
chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_PERM);
|
|
||||||
if (!chf.areas)
|
|
||||||
{
|
|
||||||
printf("duReadCompactHeightfield: Could not alloc areas (%d)\n", chf.spanCount);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
io->read(chf.areas, sizeof(unsigned char)*chf.spanCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void logLine(rcContext& ctx, rcTimerLabel label, const char* name, const float pc)
|
|
||||||
{
|
|
||||||
const int t = ctx.getAccumulatedTime(label);
|
|
||||||
if (t < 0) return;
|
|
||||||
ctx.log(RC_LOG_PROGRESS, "%s:\t%.2fms\t(%.1f%%)", name, t/1000.0f, t*pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void duLogBuildTimes(rcContext& ctx, const int totalTimeUsec)
|
|
||||||
{
|
|
||||||
const float pc = 100.0f / totalTimeUsec;
|
|
||||||
|
|
||||||
ctx.log(RC_LOG_PROGRESS, "Build Times");
|
|
||||||
logLine(ctx, RC_TIMER_RASTERIZE_TRIANGLES, "- Rasterize", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_COMPACTHEIGHTFIELD, "- Build Compact", pc);
|
|
||||||
logLine(ctx, RC_TIMER_FILTER_BORDER, "- Filter Border", pc);
|
|
||||||
logLine(ctx, RC_TIMER_FILTER_WALKABLE, "- Filter Walkable", pc);
|
|
||||||
logLine(ctx, RC_TIMER_ERODE_AREA, "- Erode Area", pc);
|
|
||||||
logLine(ctx, RC_TIMER_MEDIAN_AREA, "- Median Area", pc);
|
|
||||||
logLine(ctx, RC_TIMER_MARK_BOX_AREA, "- Mark Box Area", pc);
|
|
||||||
logLine(ctx, RC_TIMER_MARK_CONVEXPOLY_AREA, "- Mark Convex Area", pc);
|
|
||||||
logLine(ctx, RC_TIMER_MARK_CYLINDER_AREA, "- Mark Cylinder Area", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD, "- Build Distance Field", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_DIST, " - Distance", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_BLUR, " - Blur", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_REGIONS, "- Build Regions", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_WATERSHED, " - Watershed", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_EXPAND, " - Expand", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_FLOOD, " - Find Basins", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_FILTER, " - Filter", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_LAYERS, "- Build Layers", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS, "- Build Contours", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS_TRACE, " - Trace", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS_SIMPLIFY, " - Simplify", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_POLYMESH, "- Build Polymesh", pc);
|
|
||||||
logLine(ctx, RC_TIMER_BUILD_POLYMESHDETAIL, "- Build Polymesh Detail", pc);
|
|
||||||
logLine(ctx, RC_TIMER_MERGE_POLYMESH, "- Merge Polymeshes", pc);
|
|
||||||
logLine(ctx, RC_TIMER_MERGE_POLYMESHDETAIL, "- Merge Polymesh Details", pc);
|
|
||||||
ctx.log(RC_LOG_PROGRESS, "=== TOTAL:\t%.2fms", totalTimeUsec/1000.0f);
|
|
||||||
}
|
|
||||||
|
|
30
extern/recastnavigation/Detour/CMakeLists.txt
vendored
30
extern/recastnavigation/Detour/CMakeLists.txt
vendored
|
@ -1,30 +0,0 @@
|
||||||
file(GLOB SOURCES Source/*.cpp)
|
|
||||||
add_library(Detour ${SOURCES})
|
|
||||||
|
|
||||||
add_library(RecastNavigation::Detour ALIAS Detour)
|
|
||||||
set_target_properties(Detour PROPERTIES DEBUG_POSTFIX -d)
|
|
||||||
|
|
||||||
set(Detour_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Include")
|
|
||||||
|
|
||||||
target_include_directories(Detour PUBLIC
|
|
||||||
"$<BUILD_INTERFACE:${Detour_INCLUDE_DIR}>"
|
|
||||||
)
|
|
||||||
|
|
||||||
set_target_properties(Detour PROPERTIES
|
|
||||||
SOVERSION ${SOVERSION}
|
|
||||||
VERSION ${VERSION}
|
|
||||||
COMPILE_PDB_OUTPUT_DIRECTORY .
|
|
||||||
COMPILE_PDB_NAME "Detour-d"
|
|
||||||
)
|
|
||||||
|
|
||||||
install(TARGETS Detour
|
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
COMPONENT library
|
|
||||||
)
|
|
||||||
|
|
||||||
file(GLOB INCLUDES Include/*.h)
|
|
||||||
install(FILES ${INCLUDES} DESTINATION
|
|
||||||
${CMAKE_INSTALL_INCLUDEDIR}/recastnavigation)
|
|
||||||
install(FILES "$<TARGET_FILE_DIR:Detour>/Detour-d.pdb" CONFIGURATIONS "Debug" DESTINATION "lib")
|
|
|
@ -1,61 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURALLOCATOR_H
|
|
||||||
#define DETOURALLOCATOR_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
/// Provides hint values to the memory allocator on how long the
|
|
||||||
/// memory is expected to be used.
|
|
||||||
enum dtAllocHint
|
|
||||||
{
|
|
||||||
DT_ALLOC_PERM, ///< Memory persist after a function call.
|
|
||||||
DT_ALLOC_TEMP ///< Memory used temporarily within a function.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A memory allocation function.
|
|
||||||
// @param[in] size The size, in bytes of memory, to allocate.
|
|
||||||
// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
|
|
||||||
// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
|
||||||
/// @see dtAllocSetCustom
|
|
||||||
typedef void* (dtAllocFunc)(size_t size, dtAllocHint hint);
|
|
||||||
|
|
||||||
/// A memory deallocation function.
|
|
||||||
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAllocFunc.
|
|
||||||
/// @see dtAllocSetCustom
|
|
||||||
typedef void (dtFreeFunc)(void* ptr);
|
|
||||||
|
|
||||||
/// Sets the base custom allocation functions to be used by Detour.
|
|
||||||
/// @param[in] allocFunc The memory allocation function to be used by #dtAlloc
|
|
||||||
/// @param[in] freeFunc The memory de-allocation function to be used by #dtFree
|
|
||||||
void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc);
|
|
||||||
|
|
||||||
/// Allocates a memory block.
|
|
||||||
/// @param[in] size The size, in bytes of memory, to allocate.
|
|
||||||
/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
|
|
||||||
/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
|
||||||
/// @see dtFree
|
|
||||||
void* dtAlloc(size_t size, dtAllocHint hint);
|
|
||||||
|
|
||||||
/// Deallocates a memory block.
|
|
||||||
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAlloc.
|
|
||||||
/// @see dtAlloc
|
|
||||||
void dtFree(void* ptr);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,56 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURASSERT_H
|
|
||||||
#define DETOURASSERT_H
|
|
||||||
|
|
||||||
// Note: This header file's only purpose is to include define assert.
|
|
||||||
// Feel free to change the file and include your own implementation instead.
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
|
|
||||||
// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
|
|
||||||
# define dtAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
/// An assertion failure function.
|
|
||||||
// @param[in] expression asserted expression.
|
|
||||||
// @param[in] file Filename of the failed assertion.
|
|
||||||
// @param[in] line Line number of the failed assertion.
|
|
||||||
/// @see dtAssertFailSetCustom
|
|
||||||
typedef void (dtAssertFailFunc)(const char* expression, const char* file, int line);
|
|
||||||
|
|
||||||
/// Sets the base custom assertion failure function to be used by Detour.
|
|
||||||
/// @param[in] assertFailFunc The function to be invoked in case of failure of #dtAssert
|
|
||||||
void dtAssertFailSetCustom(dtAssertFailFunc *assertFailFunc);
|
|
||||||
|
|
||||||
/// Gets the base custom assertion failure function to be used by Detour.
|
|
||||||
dtAssertFailFunc* dtAssertFailGetCustom();
|
|
||||||
|
|
||||||
# include <assert.h>
|
|
||||||
# define dtAssert(expression) \
|
|
||||||
{ \
|
|
||||||
dtAssertFailFunc* failFunc = dtAssertFailGetCustom(); \
|
|
||||||
if(failFunc == NULL) { assert(expression); } \
|
|
||||||
else if(!(expression)) { (*failFunc)(#expression, __FILE__, __LINE__); } \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // DETOURASSERT_H
|
|
|
@ -1,572 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURCOMMON_H
|
|
||||||
#define DETOURCOMMON_H
|
|
||||||
|
|
||||||
#include "DetourMath.h"
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
@defgroup detour Detour
|
|
||||||
|
|
||||||
Members in this module are used to create, manipulate, and query navigation
|
|
||||||
meshes.
|
|
||||||
|
|
||||||
@note This is a summary list of members. Use the index or search
|
|
||||||
feature to find minor members.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// @name General helper functions
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
/// Used to ignore a function parameter. VS complains about unused parameters
|
|
||||||
/// and this silences the warning.
|
|
||||||
/// @param [in] _ Unused parameter
|
|
||||||
template<class T> void dtIgnoreUnused(const T&) { }
|
|
||||||
|
|
||||||
/// Swaps the values of the two parameters.
|
|
||||||
/// @param[in,out] a Value A
|
|
||||||
/// @param[in,out] b Value B
|
|
||||||
template<class T> inline void dtSwap(T& a, T& b) { T t = a; a = b; b = t; }
|
|
||||||
|
|
||||||
/// Returns the minimum of two values.
|
|
||||||
/// @param[in] a Value A
|
|
||||||
/// @param[in] b Value B
|
|
||||||
/// @return The minimum of the two values.
|
|
||||||
template<class T> inline T dtMin(T a, T b) { return a < b ? a : b; }
|
|
||||||
|
|
||||||
/// Returns the maximum of two values.
|
|
||||||
/// @param[in] a Value A
|
|
||||||
/// @param[in] b Value B
|
|
||||||
/// @return The maximum of the two values.
|
|
||||||
template<class T> inline T dtMax(T a, T b) { return a > b ? a : b; }
|
|
||||||
|
|
||||||
/// Returns the absolute value.
|
|
||||||
/// @param[in] a The value.
|
|
||||||
/// @return The absolute value of the specified value.
|
|
||||||
template<class T> inline T dtAbs(T a) { return a < 0 ? -a : a; }
|
|
||||||
|
|
||||||
/// Returns the square of the value.
|
|
||||||
/// @param[in] a The value.
|
|
||||||
/// @return The square of the value.
|
|
||||||
template<class T> inline T dtSqr(T a) { return a*a; }
|
|
||||||
|
|
||||||
/// Clamps the value to the specified range.
|
|
||||||
/// @param[in] v The value to clamp.
|
|
||||||
/// @param[in] mn The minimum permitted return value.
|
|
||||||
/// @param[in] mx The maximum permitted return value.
|
|
||||||
/// @return The value, clamped to the specified range.
|
|
||||||
template<class T> inline T dtClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
/// @name Vector helper functions.
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
/// Derives the cross product of two vectors. (@p v1 x @p v2)
|
|
||||||
/// @param[out] dest The cross product. [(x, y, z)]
|
|
||||||
/// @param[in] v1 A Vector [(x, y, z)]
|
|
||||||
/// @param[in] v2 A vector [(x, y, z)]
|
|
||||||
inline void dtVcross(float* dest, const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
|
||||||
dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
|
||||||
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derives the dot product of two vectors. (@p v1 . @p v2)
|
|
||||||
/// @param[in] v1 A Vector [(x, y, z)]
|
|
||||||
/// @param[in] v2 A vector [(x, y, z)]
|
|
||||||
/// @return The dot product.
|
|
||||||
inline float dtVdot(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
|
|
||||||
/// @param[out] dest The result vector. [(x, y, z)]
|
|
||||||
/// @param[in] v1 The base vector. [(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.
|
|
||||||
inline void dtVmad(float* dest, const float* v1, const float* v2, const float s)
|
|
||||||
{
|
|
||||||
dest[0] = v1[0]+v2[0]*s;
|
|
||||||
dest[1] = v1[1]+v2[1]*s;
|
|
||||||
dest[2] = v1[2]+v2[2]*s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a linear interpolation between two vectors. (@p v1 toward @p v2)
|
|
||||||
/// @param[out] dest The result vector. [(x, y, x)]
|
|
||||||
/// @param[in] v1 The starting vector.
|
|
||||||
/// @param[in] v2 The destination vector.
|
|
||||||
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
|
|
||||||
inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t)
|
|
||||||
{
|
|
||||||
dest[0] = v1[0]+(v2[0]-v1[0])*t;
|
|
||||||
dest[1] = v1[1]+(v2[1]-v1[1])*t;
|
|
||||||
dest[2] = v1[2]+(v2[2]-v1[2])*t;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a vector addition. (@p v1 + @p v2)
|
|
||||||
/// @param[out] dest The result vector. [(x, y, z)]
|
|
||||||
/// @param[in] v1 The base vector. [(x, y, z)]
|
|
||||||
/// @param[in] v2 The vector to add to @p v1. [(x, y, z)]
|
|
||||||
inline void dtVadd(float* dest, const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
dest[0] = v1[0]+v2[0];
|
|
||||||
dest[1] = v1[1]+v2[1];
|
|
||||||
dest[2] = v1[2]+v2[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a vector subtraction. (@p v1 - @p v2)
|
|
||||||
/// @param[out] dest The result vector. [(x, y, z)]
|
|
||||||
/// @param[in] v1 The base vector. [(x, y, z)]
|
|
||||||
/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)]
|
|
||||||
inline void dtVsub(float* dest, const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
dest[0] = v1[0]-v2[0];
|
|
||||||
dest[1] = v1[1]-v2[1];
|
|
||||||
dest[2] = v1[2]-v2[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Scales the vector by the specified value. (@p v * @p t)
|
|
||||||
/// @param[out] dest The result vector. [(x, y, z)]
|
|
||||||
/// @param[in] v The vector to scale. [(x, y, z)]
|
|
||||||
/// @param[in] t The scaling factor.
|
|
||||||
inline void dtVscale(float* dest, const float* v, const float t)
|
|
||||||
{
|
|
||||||
dest[0] = v[0]*t;
|
|
||||||
dest[1] = v[1]*t;
|
|
||||||
dest[2] = v[2]*t;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Selects the minimum value of each element from the specified vectors.
|
|
||||||
/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)]
|
|
||||||
/// @param[in] v A vector. [(x, y, z)]
|
|
||||||
inline void dtVmin(float* mn, const float* v)
|
|
||||||
{
|
|
||||||
mn[0] = dtMin(mn[0], v[0]);
|
|
||||||
mn[1] = dtMin(mn[1], v[1]);
|
|
||||||
mn[2] = dtMin(mn[2], v[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Selects the maximum value of each element from the specified vectors.
|
|
||||||
/// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)]
|
|
||||||
/// @param[in] v A vector. [(x, y, z)]
|
|
||||||
inline void dtVmax(float* mx, const float* v)
|
|
||||||
{
|
|
||||||
mx[0] = dtMax(mx[0], v[0]);
|
|
||||||
mx[1] = dtMax(mx[1], v[1]);
|
|
||||||
mx[2] = dtMax(mx[2], v[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the vector elements to the specified values.
|
|
||||||
/// @param[out] dest The result vector. [(x, y, z)]
|
|
||||||
/// @param[in] x The x-value of the vector.
|
|
||||||
/// @param[in] y The y-value of the vector.
|
|
||||||
/// @param[in] z The z-value of the vector.
|
|
||||||
inline void dtVset(float* dest, const float x, const float y, const float z)
|
|
||||||
{
|
|
||||||
dest[0] = x; dest[1] = y; dest[2] = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a vector copy.
|
|
||||||
/// @param[out] dest The result. [(x, y, z)]
|
|
||||||
/// @param[in] a The vector to copy. [(x, y, z)]
|
|
||||||
inline void dtVcopy(float* dest, const float* a)
|
|
||||||
{
|
|
||||||
dest[0] = a[0];
|
|
||||||
dest[1] = a[1];
|
|
||||||
dest[2] = a[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derives the scalar length of the vector.
|
|
||||||
/// @param[in] v The vector. [(x, y, z)]
|
|
||||||
/// @return The scalar length of the vector.
|
|
||||||
inline float dtVlen(const float* v)
|
|
||||||
{
|
|
||||||
return dtMathSqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derives the square of the scalar length of the vector. (len * len)
|
|
||||||
/// @param[in] v The vector. [(x, y, z)]
|
|
||||||
/// @return The square of the scalar length of the vector.
|
|
||||||
inline float dtVlenSqr(const float* v)
|
|
||||||
{
|
|
||||||
return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the distance between two points.
|
|
||||||
/// @param[in] v1 A point. [(x, y, z)]
|
|
||||||
/// @param[in] v2 A point. [(x, y, z)]
|
|
||||||
/// @return The distance between the two points.
|
|
||||||
inline float dtVdist(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
const float dx = v2[0] - v1[0];
|
|
||||||
const float dy = v2[1] - v1[1];
|
|
||||||
const float dz = v2[2] - v1[2];
|
|
||||||
return dtMathSqrtf(dx*dx + dy*dy + dz*dz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the square of the distance between two points.
|
|
||||||
/// @param[in] v1 A point. [(x, y, z)]
|
|
||||||
/// @param[in] v2 A point. [(x, y, z)]
|
|
||||||
/// @return The square of the distance between the two points.
|
|
||||||
inline float dtVdistSqr(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
const float dx = v2[0] - v1[0];
|
|
||||||
const float dy = v2[1] - v1[1];
|
|
||||||
const float dz = v2[2] - v1[2];
|
|
||||||
return dx*dx + dy*dy + dz*dz;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derives the distance between the specified points on the xz-plane.
|
|
||||||
/// @param[in] v1 A point. [(x, y, z)]
|
|
||||||
/// @param[in] v2 A point. [(x, y, z)]
|
|
||||||
/// @return The distance between the point on the xz-plane.
|
|
||||||
///
|
|
||||||
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
|
||||||
inline float dtVdist2D(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
const float dx = v2[0] - v1[0];
|
|
||||||
const float dz = v2[2] - v1[2];
|
|
||||||
return dtMathSqrtf(dx*dx + dz*dz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derives the square of the distance between the specified points on the xz-plane.
|
|
||||||
/// @param[in] v1 A point. [(x, y, z)]
|
|
||||||
/// @param[in] v2 A point. [(x, y, z)]
|
|
||||||
/// @return The square of the distance between the point on the xz-plane.
|
|
||||||
inline float dtVdist2DSqr(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
const float dx = v2[0] - v1[0];
|
|
||||||
const float dz = v2[2] - v1[2];
|
|
||||||
return dx*dx + dz*dz;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Normalizes the vector.
|
|
||||||
/// @param[in,out] v The vector to normalize. [(x, y, z)]
|
|
||||||
inline void dtVnormalize(float* v)
|
|
||||||
{
|
|
||||||
float d = 1.0f / dtMathSqrtf(dtSqr(v[0]) + dtSqr(v[1]) + dtSqr(v[2]));
|
|
||||||
v[0] *= d;
|
|
||||||
v[1] *= d;
|
|
||||||
v[2] *= d;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a 'sloppy' colocation check of the specified points.
|
|
||||||
/// @param[in] p0 A point. [(x, y, z)]
|
|
||||||
/// @param[in] p1 A point. [(x, y, z)]
|
|
||||||
/// @return True if the points are considered to be at the same location.
|
|
||||||
///
|
|
||||||
/// Basically, this function will return true if the specified points are
|
|
||||||
/// close enough to eachother to be considered colocated.
|
|
||||||
inline bool dtVequal(const float* p0, const float* p1)
|
|
||||||
{
|
|
||||||
static const float thr = dtSqr(1.0f/16384.0f);
|
|
||||||
const float d = dtVdistSqr(p0, p1);
|
|
||||||
return d < thr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks that the specified vector's components are all finite.
|
|
||||||
/// @param[in] v A point. [(x, y, z)]
|
|
||||||
/// @return True if all of the point's components are finite, i.e. not NaN
|
|
||||||
/// or any of the infinities.
|
|
||||||
inline bool dtVisfinite(const float* v)
|
|
||||||
{
|
|
||||||
bool result =
|
|
||||||
dtMathIsfinite(v[0]) &&
|
|
||||||
dtMathIsfinite(v[1]) &&
|
|
||||||
dtMathIsfinite(v[2]);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks that the specified vector's 2D components are finite.
|
|
||||||
/// @param[in] v A point. [(x, y, z)]
|
|
||||||
inline bool dtVisfinite2D(const float* v)
|
|
||||||
{
|
|
||||||
bool result = dtMathIsfinite(v[0]) && dtMathIsfinite(v[2]);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derives the dot product of two vectors on the xz-plane. (@p u . @p v)
|
|
||||||
/// @param[in] u A vector [(x, y, z)]
|
|
||||||
/// @param[in] v A vector [(x, y, z)]
|
|
||||||
/// @return The dot product on the xz-plane.
|
|
||||||
///
|
|
||||||
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
|
||||||
inline float dtVdot2D(const float* u, const float* v)
|
|
||||||
{
|
|
||||||
return u[0]*v[0] + u[2]*v[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derives the xz-plane 2D perp product of the two vectors. (uz*vx - ux*vz)
|
|
||||||
/// @param[in] u The LHV vector [(x, y, z)]
|
|
||||||
/// @param[in] v The RHV vector [(x, y, z)]
|
|
||||||
/// @return The dot product on the xz-plane.
|
|
||||||
///
|
|
||||||
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
|
||||||
inline float dtVperp2D(const float* u, const float* v)
|
|
||||||
{
|
|
||||||
return u[2]*v[0] - u[0]*v[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
/// @name Computational geometry helper functions.
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
/// Derives the signed xz-plane area of the triangle ABC, or the relationship of line AB to point C.
|
|
||||||
/// @param[in] a Vertex A. [(x, y, z)]
|
|
||||||
/// @param[in] b Vertex B. [(x, y, z)]
|
|
||||||
/// @param[in] c Vertex C. [(x, y, z)]
|
|
||||||
/// @return The signed xz-plane area of the triangle.
|
|
||||||
inline float dtTriArea2D(const float* a, const float* b, const float* c)
|
|
||||||
{
|
|
||||||
const float abx = b[0] - a[0];
|
|
||||||
const float abz = b[2] - a[2];
|
|
||||||
const float acx = c[0] - a[0];
|
|
||||||
const float acz = c[2] - a[2];
|
|
||||||
return acx*abz - abx*acz;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determines if two axis-aligned bounding boxes overlap.
|
|
||||||
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
|
||||||
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
|
||||||
/// @param[in] bmin Minimum 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.
|
|
||||||
/// @see dtOverlapBounds
|
|
||||||
inline bool dtOverlapQuantBounds(const unsigned short amin[3], const unsigned short amax[3],
|
|
||||||
const unsigned short bmin[3], const unsigned short bmax[3])
|
|
||||||
{
|
|
||||||
bool overlap = true;
|
|
||||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
|
||||||
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
|
||||||
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
|
||||||
return overlap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determines if two axis-aligned bounding boxes overlap.
|
|
||||||
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
|
||||||
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
|
||||||
/// @param[in] bmin Minimum 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.
|
|
||||||
/// @see dtOverlapQuantBounds
|
|
||||||
inline bool dtOverlapBounds(const float* amin, const float* amax,
|
|
||||||
const float* bmin, const float* bmax)
|
|
||||||
{
|
|
||||||
bool overlap = true;
|
|
||||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
|
||||||
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
|
||||||
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
|
||||||
return overlap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derives the closest point on a triangle from the specified reference point.
|
|
||||||
/// @param[out] closest The closest point on the triangle.
|
|
||||||
/// @param[in] p The reference point from which to test. [(x, y, z)]
|
|
||||||
/// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
|
|
||||||
/// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
|
|
||||||
/// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
|
|
||||||
void dtClosestPtPointTriangle(float* closest, const float* p,
|
|
||||||
const float* a, const float* b, const float* c);
|
|
||||||
|
|
||||||
/// Derives the y-axis height of the closest point on the triangle from the specified reference point.
|
|
||||||
/// @param[in] p The reference point from which to test. [(x, y, z)]
|
|
||||||
/// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
|
|
||||||
/// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
|
|
||||||
/// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
|
|
||||||
/// @param[out] h The resulting height.
|
|
||||||
bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h);
|
|
||||||
|
|
||||||
bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
|
|
||||||
const float* verts, int nverts,
|
|
||||||
float& tmin, float& tmax,
|
|
||||||
int& segMin, int& segMax);
|
|
||||||
|
|
||||||
bool dtIntersectSegSeg2D(const float* ap, const float* aq,
|
|
||||||
const float* bp, const float* bq,
|
|
||||||
float& s, float& t);
|
|
||||||
|
|
||||||
/// Determines if the specified point is inside the convex polygon on the xz-plane.
|
|
||||||
/// @param[in] pt The point to check. [(x, y, z)]
|
|
||||||
/// @param[in] verts The polygon vertices. [(x, y, z) * @p nverts]
|
|
||||||
/// @param[in] nverts The number of vertices. [Limit: >= 3]
|
|
||||||
/// @return True if the point is inside the polygon.
|
|
||||||
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts);
|
|
||||||
|
|
||||||
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
|
|
||||||
float* ed, float* et);
|
|
||||||
|
|
||||||
float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t);
|
|
||||||
|
|
||||||
/// Derives the centroid of a convex polygon.
|
|
||||||
/// @param[out] tc The centroid of the polgyon. [(x, y, z)]
|
|
||||||
/// @param[in] idx The polygon indices. [(vertIndex) * @p nidx]
|
|
||||||
/// @param[in] nidx The number of indices in the polygon. [Limit: >= 3]
|
|
||||||
/// @param[in] verts The polygon vertices. [(x, y, z) * vertCount]
|
|
||||||
void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts);
|
|
||||||
|
|
||||||
/// Determines if the two convex polygons overlap on the xz-plane.
|
|
||||||
/// @param[in] polya Polygon A vertices. [(x, y, z) * @p npolya]
|
|
||||||
/// @param[in] npolya The number of vertices in polygon A.
|
|
||||||
/// @param[in] polyb Polygon B vertices. [(x, y, z) * @p npolyb]
|
|
||||||
/// @param[in] npolyb The number of vertices in polygon B.
|
|
||||||
/// @return True if the two polygons overlap.
|
|
||||||
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
|
||||||
const float* polyb, const int npolyb);
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
/// @name Miscellanious functions.
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
inline unsigned int dtNextPow2(unsigned int v)
|
|
||||||
{
|
|
||||||
v--;
|
|
||||||
v |= v >> 1;
|
|
||||||
v |= v >> 2;
|
|
||||||
v |= v >> 4;
|
|
||||||
v |= v >> 8;
|
|
||||||
v |= v >> 16;
|
|
||||||
v++;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int dtIlog2(unsigned int v)
|
|
||||||
{
|
|
||||||
unsigned int r;
|
|
||||||
unsigned int shift;
|
|
||||||
r = (v > 0xffff) << 4; v >>= r;
|
|
||||||
shift = (v > 0xff) << 3; v >>= shift; r |= shift;
|
|
||||||
shift = (v > 0xf) << 2; v >>= shift; r |= shift;
|
|
||||||
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
|
|
||||||
r |= (v >> 1);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int dtAlign4(int x) { return (x+3) & ~3; }
|
|
||||||
|
|
||||||
inline int dtOppositeTile(int side) { return (side+4) & 0x7; }
|
|
||||||
|
|
||||||
inline void dtSwapByte(unsigned char* a, unsigned char* b)
|
|
||||||
{
|
|
||||||
unsigned char tmp = *a;
|
|
||||||
*a = *b;
|
|
||||||
*b = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtSwapEndian(unsigned short* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
dtSwapByte(x+0, x+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtSwapEndian(short* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
dtSwapByte(x+0, x+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtSwapEndian(unsigned int* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtSwapEndian(int* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtSwapEndian(float* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
|
||||||
const float s, const float t, float* out);
|
|
||||||
|
|
||||||
template<typename TypeToRetrieveAs>
|
|
||||||
TypeToRetrieveAs* dtGetThenAdvanceBufferPointer(const unsigned char*& buffer, const size_t distanceToAdvance)
|
|
||||||
{
|
|
||||||
TypeToRetrieveAs* returnPointer = reinterpret_cast<TypeToRetrieveAs*>(buffer);
|
|
||||||
buffer += distanceToAdvance;
|
|
||||||
return returnPointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TypeToRetrieveAs>
|
|
||||||
TypeToRetrieveAs* dtGetThenAdvanceBufferPointer(unsigned char*& buffer, const size_t distanceToAdvance)
|
|
||||||
{
|
|
||||||
TypeToRetrieveAs* returnPointer = reinterpret_cast<TypeToRetrieveAs*>(buffer);
|
|
||||||
buffer += distanceToAdvance;
|
|
||||||
return returnPointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
#endif // DETOURCOMMON_H
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// This section contains detailed documentation for members that don't have
|
|
||||||
// a source file. It reduces clutter in the main section of the header.
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
@fn float dtTriArea2D(const float* a, const float* b, const float* c)
|
|
||||||
@par
|
|
||||||
|
|
||||||
The vertices are projected onto the xz-plane, so the y-values are ignored.
|
|
||||||
|
|
||||||
This is a low cost function than can be used for various purposes. Its main purpose
|
|
||||||
is for point/line relationship testing.
|
|
||||||
|
|
||||||
In all cases: A value of zero indicates that all vertices are collinear or represent the same point.
|
|
||||||
(On the xz-plane.)
|
|
||||||
|
|
||||||
When used for point/line relationship tests, AB usually represents a line against which
|
|
||||||
the C point is to be tested. In this case:
|
|
||||||
|
|
||||||
A positive value indicates that point C is to the left of line AB, looking from A toward B.<br/>
|
|
||||||
A negative value indicates that point C is to the right of lineAB, looking from A toward B.
|
|
||||||
|
|
||||||
When used for evaluating a triangle:
|
|
||||||
|
|
||||||
The absolute value of the return value is two times the area of the triangle when it is
|
|
||||||
projected onto the xz-plane.
|
|
||||||
|
|
||||||
A positive return value indicates:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>The vertices are wrapped in the normal Detour wrap direction.</li>
|
|
||||||
<li>The triangle's 3D face normal is in the general up direction.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
A negative return value indicates:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>The vertices are reverse wrapped. (Wrapped opposite the normal Detour wrap direction.)</li>
|
|
||||||
<li>The triangle's 3D face normal is in the general down direction.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
*/
|
|
|
@ -1,24 +0,0 @@
|
||||||
/**
|
|
||||||
@defgroup detour Detour
|
|
||||||
|
|
||||||
Members in this module are wrappers around the standard math library
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DETOURMATH_H
|
|
||||||
#define DETOURMATH_H
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
// This include is required because libstdc++ has problems with isfinite
|
|
||||||
// if cmath is included before math.h.
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
inline float dtMathFabsf(float x) { return fabsf(x); }
|
|
||||||
inline float dtMathSqrtf(float x) { return sqrtf(x); }
|
|
||||||
inline float dtMathFloorf(float x) { return floorf(x); }
|
|
||||||
inline float dtMathCeilf(float x) { return ceilf(x); }
|
|
||||||
inline float dtMathCosf(float x) { return cosf(x); }
|
|
||||||
inline float dtMathSinf(float x) { return sinf(x); }
|
|
||||||
inline float dtMathAtan2f(float y, float x) { return atan2f(y, x); }
|
|
||||||
inline bool dtMathIsfinite(float x) { return std::isfinite(x); }
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,785 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURNAVMESH_H
|
|
||||||
#define DETOURNAVMESH_H
|
|
||||||
|
|
||||||
#include "DetourAlloc.h"
|
|
||||||
#include "DetourStatus.h"
|
|
||||||
|
|
||||||
// Undefine (or define in a build cofnig) the following line to use 64bit polyref.
|
|
||||||
// Generally not needed, useful for very large worlds.
|
|
||||||
// Note: tiles build using 32bit refs are not compatible with 64bit refs!
|
|
||||||
//#define DT_POLYREF64 1
|
|
||||||
|
|
||||||
#ifdef DT_POLYREF64
|
|
||||||
// TODO: figure out a multiplatform version of uint64_t
|
|
||||||
// - maybe: https://code.google.com/p/msinttypes/
|
|
||||||
// - or: http://www.azillionmonkeys.com/qed/pstdint.h
|
|
||||||
#include <stdint.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef.
|
|
||||||
// It is also recommended that you change dtHashRef() to a proper 64-bit hash.
|
|
||||||
|
|
||||||
/// A handle to a polygon within a navigation mesh tile.
|
|
||||||
/// @ingroup detour
|
|
||||||
#ifdef DT_POLYREF64
|
|
||||||
static const unsigned int DT_SALT_BITS = 16;
|
|
||||||
static const unsigned int DT_TILE_BITS = 28;
|
|
||||||
static const unsigned int DT_POLY_BITS = 20;
|
|
||||||
typedef uint64_t dtPolyRef;
|
|
||||||
#else
|
|
||||||
typedef unsigned int dtPolyRef;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// A handle to a tile within a navigation mesh.
|
|
||||||
/// @ingroup detour
|
|
||||||
#ifdef DT_POLYREF64
|
|
||||||
typedef uint64_t dtTileRef;
|
|
||||||
#else
|
|
||||||
typedef unsigned int dtTileRef;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// The maximum number of vertices per navigation polygon.
|
|
||||||
/// @ingroup detour
|
|
||||||
static const int DT_VERTS_PER_POLYGON = 6;
|
|
||||||
|
|
||||||
/// @{
|
|
||||||
/// @name Tile Serialization Constants
|
|
||||||
/// These constants are used to detect whether a navigation tile's data
|
|
||||||
/// and state format is compatible with the current build.
|
|
||||||
///
|
|
||||||
|
|
||||||
/// A magic number used to detect compatibility of navigation tile data.
|
|
||||||
static const int DT_NAVMESH_MAGIC = 'D'<<24 | 'N'<<16 | 'A'<<8 | 'V';
|
|
||||||
|
|
||||||
/// A version number used to detect compatibility of navigation tile data.
|
|
||||||
static const int DT_NAVMESH_VERSION = 7;
|
|
||||||
|
|
||||||
/// A magic number used to detect the compatibility of navigation tile states.
|
|
||||||
static const int DT_NAVMESH_STATE_MAGIC = 'D'<<24 | 'N'<<16 | 'M'<<8 | 'S';
|
|
||||||
|
|
||||||
/// A version number used to detect compatibility of navigation tile states.
|
|
||||||
static const int DT_NAVMESH_STATE_VERSION = 1;
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
/// A flag that indicates that an entity links to an external entity.
|
|
||||||
/// (E.g. A polygon edge is a portal that links to another polygon.)
|
|
||||||
static const unsigned short DT_EXT_LINK = 0x8000;
|
|
||||||
|
|
||||||
/// A value that indicates the entity does not link to anything.
|
|
||||||
static const unsigned int DT_NULL_LINK = 0xffffffff;
|
|
||||||
|
|
||||||
/// A flag that indicates that an off-mesh connection can be traversed in both directions. (Is bidirectional.)
|
|
||||||
static const unsigned int DT_OFFMESH_CON_BIDIR = 1;
|
|
||||||
|
|
||||||
/// The maximum number of user defined area ids.
|
|
||||||
/// @ingroup detour
|
|
||||||
static const int DT_MAX_AREAS = 64;
|
|
||||||
|
|
||||||
/// Tile flags used for various functions and fields.
|
|
||||||
/// For an example, see dtNavMesh::addTile().
|
|
||||||
enum dtTileFlags
|
|
||||||
{
|
|
||||||
/// The navigation mesh owns the tile memory and is responsible for freeing it.
|
|
||||||
DT_TILE_FREE_DATA = 0x01,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Vertex flags returned by dtNavMeshQuery::findStraightPath.
|
|
||||||
enum dtStraightPathFlags
|
|
||||||
{
|
|
||||||
DT_STRAIGHTPATH_START = 0x01, ///< The vertex is the start position in the path.
|
|
||||||
DT_STRAIGHTPATH_END = 0x02, ///< The vertex is the end position in the path.
|
|
||||||
DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04, ///< The vertex is the start of an off-mesh connection.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Options for dtNavMeshQuery::findStraightPath.
|
|
||||||
enum dtStraightPathOptions
|
|
||||||
{
|
|
||||||
DT_STRAIGHTPATH_AREA_CROSSINGS = 0x01, ///< Add a vertex at every polygon edge crossing where area changes.
|
|
||||||
DT_STRAIGHTPATH_ALL_CROSSINGS = 0x02, ///< Add a vertex at every polygon edge crossing.
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Options for dtNavMeshQuery::initSlicedFindPath and updateSlicedFindPath
|
|
||||||
enum dtFindPathOptions
|
|
||||||
{
|
|
||||||
DT_FINDPATH_ANY_ANGLE = 0x02, ///< use raycasts during pathfind to "shortcut" (raycast still consider costs)
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Options for dtNavMeshQuery::raycast
|
|
||||||
enum dtRaycastOptions
|
|
||||||
{
|
|
||||||
DT_RAYCAST_USE_COSTS = 0x01, ///< Raycast should calculate movement cost along the ray and fill RaycastHit::cost
|
|
||||||
};
|
|
||||||
|
|
||||||
enum dtDetailTriEdgeFlags
|
|
||||||
{
|
|
||||||
DT_DETAIL_EDGE_BOUNDARY = 0x01, ///< Detail triangle edge is part of the poly boundary
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Limit raycasting during any angle pahfinding
|
|
||||||
/// The limit is given as a multiple of the character radius
|
|
||||||
static const float DT_RAY_CAST_LIMIT_PROPORTIONS = 50.0f;
|
|
||||||
|
|
||||||
/// Flags representing the type of a navigation mesh polygon.
|
|
||||||
enum dtPolyTypes
|
|
||||||
{
|
|
||||||
/// The polygon is a standard convex polygon that is part of the surface of the mesh.
|
|
||||||
DT_POLYTYPE_GROUND = 0,
|
|
||||||
/// The polygon is an off-mesh connection consisting of two vertices.
|
|
||||||
DT_POLYTYPE_OFFMESH_CONNECTION = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Defines a polygon within a dtMeshTile object.
|
|
||||||
/// @ingroup detour
|
|
||||||
struct dtPoly
|
|
||||||
{
|
|
||||||
/// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.)
|
|
||||||
unsigned int firstLink;
|
|
||||||
|
|
||||||
/// The indices of the polygon's vertices.
|
|
||||||
/// The actual vertices are located in dtMeshTile::verts.
|
|
||||||
unsigned short verts[DT_VERTS_PER_POLYGON];
|
|
||||||
|
|
||||||
/// Packed data representing neighbor polygons references and flags for each edge.
|
|
||||||
unsigned short neis[DT_VERTS_PER_POLYGON];
|
|
||||||
|
|
||||||
/// The user defined polygon flags.
|
|
||||||
unsigned short flags;
|
|
||||||
|
|
||||||
/// The number of vertices in the polygon.
|
|
||||||
unsigned char vertCount;
|
|
||||||
|
|
||||||
/// The bit packed area id and polygon type.
|
|
||||||
/// @note Use the structure's set and get methods to acess this value.
|
|
||||||
unsigned char areaAndtype;
|
|
||||||
|
|
||||||
/// Sets the user defined area id. [Limit: < #DT_MAX_AREAS]
|
|
||||||
inline void setArea(unsigned char a) { areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f); }
|
|
||||||
|
|
||||||
/// Sets the polygon type. (See: #dtPolyTypes.)
|
|
||||||
inline void setType(unsigned char t) { areaAndtype = (areaAndtype & 0x3f) | (t << 6); }
|
|
||||||
|
|
||||||
/// Gets the user defined area id.
|
|
||||||
inline unsigned char getArea() const { return areaAndtype & 0x3f; }
|
|
||||||
|
|
||||||
/// Gets the polygon type. (See: #dtPolyTypes)
|
|
||||||
inline unsigned char getType() const { return areaAndtype >> 6; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Defines the location of detail sub-mesh data within a dtMeshTile.
|
|
||||||
struct dtPolyDetail
|
|
||||||
{
|
|
||||||
unsigned int vertBase; ///< The offset of the vertices in the dtMeshTile::detailVerts array.
|
|
||||||
unsigned int triBase; ///< The offset of the triangles in the dtMeshTile::detailTris array.
|
|
||||||
unsigned char vertCount; ///< The number of vertices in the sub-mesh.
|
|
||||||
unsigned char triCount; ///< The number of triangles in the sub-mesh.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Defines a link between polygons.
|
|
||||||
/// @note This structure is rarely if ever used by the end user.
|
|
||||||
/// @see dtMeshTile
|
|
||||||
struct dtLink
|
|
||||||
{
|
|
||||||
dtPolyRef ref; ///< Neighbour reference. (The neighbor that is linked to.)
|
|
||||||
unsigned int next; ///< Index of the next link.
|
|
||||||
unsigned char edge; ///< Index of the polygon edge that owns this link.
|
|
||||||
unsigned char side; ///< If a boundary link, defines on which side the link is.
|
|
||||||
unsigned char bmin; ///< If a boundary link, defines the minimum sub-edge area.
|
|
||||||
unsigned char bmax; ///< If a boundary link, defines the maximum sub-edge area.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Bounding volume node.
|
|
||||||
/// @note This structure is rarely if ever used by the end user.
|
|
||||||
/// @see dtMeshTile
|
|
||||||
struct dtBVNode
|
|
||||||
{
|
|
||||||
unsigned short bmin[3]; ///< Minimum bounds of the node's AABB. [(x, y, z)]
|
|
||||||
unsigned short bmax[3]; ///< Maximum bounds of the node's AABB. [(x, y, z)]
|
|
||||||
int i; ///< The node's index. (Negative for escape sequence.)
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Defines an navigation mesh off-mesh connection within a dtMeshTile object.
|
|
||||||
/// An off-mesh connection is a user defined traversable connection made up to two vertices.
|
|
||||||
struct dtOffMeshConnection
|
|
||||||
{
|
|
||||||
/// The endpoints of the connection. [(ax, ay, az, bx, by, bz)]
|
|
||||||
float pos[6];
|
|
||||||
|
|
||||||
/// The radius of the endpoints. [Limit: >= 0]
|
|
||||||
float rad;
|
|
||||||
|
|
||||||
/// The polygon reference of the connection within the tile.
|
|
||||||
unsigned short poly;
|
|
||||||
|
|
||||||
/// Link flags.
|
|
||||||
/// @note These are not the connection's user defined flags. Those are assigned via the
|
|
||||||
/// connection's dtPoly definition. These are link flags used for internal purposes.
|
|
||||||
unsigned char flags;
|
|
||||||
|
|
||||||
/// End point side.
|
|
||||||
unsigned char side;
|
|
||||||
|
|
||||||
/// The id of the offmesh connection. (User assigned when the navigation mesh is built.)
|
|
||||||
unsigned int userId;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Provides high level information related to a dtMeshTile object.
|
|
||||||
/// @ingroup detour
|
|
||||||
struct dtMeshHeader
|
|
||||||
{
|
|
||||||
int magic; ///< Tile magic number. (Used to identify the data format.)
|
|
||||||
int version; ///< Tile data format version number.
|
|
||||||
int x; ///< The x-position of the tile within the dtNavMesh tile grid. (x, y, layer)
|
|
||||||
int y; ///< The y-position of the tile within the dtNavMesh tile grid. (x, y, layer)
|
|
||||||
int layer; ///< The layer of the tile within the dtNavMesh tile grid. (x, y, layer)
|
|
||||||
unsigned int userId; ///< The user defined id of the tile.
|
|
||||||
int polyCount; ///< The number of polygons in the tile.
|
|
||||||
int vertCount; ///< The number of vertices in the tile.
|
|
||||||
int maxLinkCount; ///< The number of allocated links.
|
|
||||||
int detailMeshCount; ///< The number of sub-meshes in the detail mesh.
|
|
||||||
|
|
||||||
/// The number of unique vertices in the detail mesh. (In addition to the polygon vertices.)
|
|
||||||
int detailVertCount;
|
|
||||||
|
|
||||||
int detailTriCount; ///< The number of triangles in the detail mesh.
|
|
||||||
int bvNodeCount; ///< The number of bounding volume nodes. (Zero if bounding volumes are disabled.)
|
|
||||||
int offMeshConCount; ///< The number of off-mesh connections.
|
|
||||||
int offMeshBase; ///< The index of the first polygon which is an off-mesh connection.
|
|
||||||
float walkableHeight; ///< The height of the agents using the tile.
|
|
||||||
float walkableRadius; ///< The radius of the agents using the tile.
|
|
||||||
float walkableClimb; ///< The maximum climb height of the agents using the tile.
|
|
||||||
float bmin[3]; ///< The minimum bounds of the tile's AABB. [(x, y, z)]
|
|
||||||
float bmax[3]; ///< The maximum bounds of the tile's AABB. [(x, y, z)]
|
|
||||||
|
|
||||||
/// The bounding volume quantization factor.
|
|
||||||
float bvQuantFactor;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Defines a navigation mesh tile.
|
|
||||||
/// @ingroup detour
|
|
||||||
struct dtMeshTile
|
|
||||||
{
|
|
||||||
unsigned int salt; ///< Counter describing modifications to the tile.
|
|
||||||
|
|
||||||
unsigned int linksFreeList; ///< Index to the next free link.
|
|
||||||
dtMeshHeader* header; ///< The tile header.
|
|
||||||
dtPoly* polys; ///< The tile polygons. [Size: dtMeshHeader::polyCount]
|
|
||||||
float* verts; ///< The tile vertices. [Size: dtMeshHeader::vertCount]
|
|
||||||
dtLink* links; ///< The tile links. [Size: dtMeshHeader::maxLinkCount]
|
|
||||||
dtPolyDetail* detailMeshes; ///< The tile's detail sub-meshes. [Size: dtMeshHeader::detailMeshCount]
|
|
||||||
|
|
||||||
/// The detail mesh's unique vertices. [(x, y, z) * dtMeshHeader::detailVertCount]
|
|
||||||
float* detailVerts;
|
|
||||||
|
|
||||||
/// The detail mesh's triangles. [(vertA, vertB, vertC, triFlags) * dtMeshHeader::detailTriCount].
|
|
||||||
/// See dtDetailTriEdgeFlags and dtGetDetailTriEdgeFlags.
|
|
||||||
unsigned char* detailTris;
|
|
||||||
|
|
||||||
/// The tile bounding volume nodes. [Size: dtMeshHeader::bvNodeCount]
|
|
||||||
/// (Will be null if bounding volumes are disabled.)
|
|
||||||
dtBVNode* bvTree;
|
|
||||||
|
|
||||||
dtOffMeshConnection* offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
|
||||||
|
|
||||||
unsigned char* data; ///< The tile data. (Not directly accessed under normal situations.)
|
|
||||||
int dataSize; ///< Size of the tile data.
|
|
||||||
int flags; ///< Tile flags. (See: #dtTileFlags)
|
|
||||||
dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid.
|
|
||||||
// OpenMW code - make dtMeshTile POD since R&D init it by memset
|
|
||||||
//private:
|
|
||||||
// dtMeshTile(const dtMeshTile&);
|
|
||||||
// dtMeshTile& operator=(const dtMeshTile&);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Get flags for edge in detail triangle.
|
|
||||||
/// @param triFlags[in] The flags for the triangle (last component of detail vertices above).
|
|
||||||
/// @param edgeIndex[in] The index of the first vertex of the edge. For instance, if 0,
|
|
||||||
/// returns flags for edge AB.
|
|
||||||
inline int dtGetDetailTriEdgeFlags(unsigned char triFlags, int edgeIndex)
|
|
||||||
{
|
|
||||||
return (triFlags >> (edgeIndex * 2)) & 0x3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configuration parameters used to define multi-tile navigation meshes.
|
|
||||||
/// The values are used to allocate space during the initialization of a navigation mesh.
|
|
||||||
/// @see dtNavMesh::init()
|
|
||||||
/// @ingroup detour
|
|
||||||
struct dtNavMeshParams
|
|
||||||
{
|
|
||||||
float orig[3]; ///< The world space origin of the navigation mesh's tile space. [(x, y, z)]
|
|
||||||
float tileWidth; ///< The width of each tile. (Along the x-axis.)
|
|
||||||
float tileHeight; ///< The height of each tile. (Along the z-axis.)
|
|
||||||
int maxTiles; ///< The maximum number of tiles the navigation mesh can contain.
|
|
||||||
int maxPolys; ///< The maximum number of polygons each tile can contain.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A navigation mesh based on tiles of convex polygons.
|
|
||||||
/// @ingroup detour
|
|
||||||
class dtNavMesh
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dtNavMesh();
|
|
||||||
~dtNavMesh();
|
|
||||||
|
|
||||||
/// @{
|
|
||||||
/// @name Initialization and Tile Management
|
|
||||||
|
|
||||||
/// Initializes the navigation mesh for tiled use.
|
|
||||||
/// @param[in] params Initialization parameters.
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus init(const dtNavMeshParams* params);
|
|
||||||
|
|
||||||
/// Initializes the navigation mesh for single tile use.
|
|
||||||
/// @param[in] data Data of the new tile. (See: #dtCreateNavMeshData)
|
|
||||||
/// @param[in] dataSize The data size of the new tile.
|
|
||||||
/// @param[in] flags The tile flags. (See: #dtTileFlags)
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
/// @see dtCreateNavMeshData
|
|
||||||
dtStatus init(unsigned char* data, const int dataSize, const int flags);
|
|
||||||
|
|
||||||
/// The navigation mesh initialization params.
|
|
||||||
const dtNavMeshParams* getParams() const;
|
|
||||||
|
|
||||||
/// Adds a tile to the navigation mesh.
|
|
||||||
/// @param[in] data Data for the new tile mesh. (See: #dtCreateNavMeshData)
|
|
||||||
/// @param[in] dataSize Data size of the new tile mesh.
|
|
||||||
/// @param[in] flags Tile flags. (See: #dtTileFlags)
|
|
||||||
/// @param[in] lastRef The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
|
|
||||||
/// @param[out] result The tile reference. (If the tile was succesfully added.) [opt]
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result);
|
|
||||||
|
|
||||||
/// Removes the specified tile from the navigation mesh.
|
|
||||||
/// @param[in] ref The reference of the tile to remove.
|
|
||||||
/// @param[out] data Data associated with deleted tile.
|
|
||||||
/// @param[out] dataSize Size of the data associated with deleted tile.
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus removeTile(dtTileRef ref, unsigned char** data, int* dataSize);
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
/// @{
|
|
||||||
/// @name Query Functions
|
|
||||||
|
|
||||||
/// Calculates the tile grid location for the specified world position.
|
|
||||||
/// @param[in] pos The world position for the query. [(x, y, z)]
|
|
||||||
/// @param[out] tx The tile's x-location. (x, y)
|
|
||||||
/// @param[out] ty The tile's y-location. (x, y)
|
|
||||||
void calcTileLoc(const float* pos, int* tx, int* ty) const;
|
|
||||||
|
|
||||||
/// Gets the tile at the specified grid location.
|
|
||||||
/// @param[in] x The tile's x-location. (x, y, layer)
|
|
||||||
/// @param[in] y The tile's y-location. (x, y, layer)
|
|
||||||
/// @param[in] layer The tile's layer. (x, y, layer)
|
|
||||||
/// @return The tile, or null if the tile does not exist.
|
|
||||||
const dtMeshTile* getTileAt(const int x, const int y, const int layer) const;
|
|
||||||
|
|
||||||
/// Gets all tiles at the specified grid location. (All layers.)
|
|
||||||
/// @param[in] x The tile's x-location. (x, y)
|
|
||||||
/// @param[in] y The tile's y-location. (x, y)
|
|
||||||
/// @param[out] tiles A pointer to an array of tiles that will hold the result.
|
|
||||||
/// @param[in] maxTiles The maximum tiles the tiles parameter can hold.
|
|
||||||
/// @return The number of tiles returned in the tiles array.
|
|
||||||
int getTilesAt(const int x, const int y,
|
|
||||||
dtMeshTile const** tiles, const int maxTiles) const;
|
|
||||||
|
|
||||||
/// Gets the tile reference for the tile at specified grid location.
|
|
||||||
/// @param[in] x The tile's x-location. (x, y, layer)
|
|
||||||
/// @param[in] y The tile's y-location. (x, y, layer)
|
|
||||||
/// @param[in] layer The tile's layer. (x, y, layer)
|
|
||||||
/// @return The tile reference of the tile, or 0 if there is none.
|
|
||||||
dtTileRef getTileRefAt(int x, int y, int layer) const;
|
|
||||||
|
|
||||||
/// Gets the tile reference for the specified tile.
|
|
||||||
/// @param[in] tile The tile.
|
|
||||||
/// @return The tile reference of the tile.
|
|
||||||
dtTileRef getTileRef(const dtMeshTile* tile) const;
|
|
||||||
|
|
||||||
/// Gets the tile for the specified tile reference.
|
|
||||||
/// @param[in] ref The tile reference of the tile to retrieve.
|
|
||||||
/// @return The tile for the specified reference, or null if the
|
|
||||||
/// reference is invalid.
|
|
||||||
const dtMeshTile* getTileByRef(dtTileRef ref) const;
|
|
||||||
|
|
||||||
/// The maximum number of tiles supported by the navigation mesh.
|
|
||||||
/// @return The maximum number of tiles supported by the navigation mesh.
|
|
||||||
int getMaxTiles() const;
|
|
||||||
|
|
||||||
/// Gets the tile at the specified index.
|
|
||||||
/// @param[in] i The tile index. [Limit: 0 >= index < #getMaxTiles()]
|
|
||||||
/// @return The tile at the specified index.
|
|
||||||
const dtMeshTile* getTile(int i) const;
|
|
||||||
|
|
||||||
/// Gets the tile and polygon for the specified polygon reference.
|
|
||||||
/// @param[in] ref The reference for the a polygon.
|
|
||||||
/// @param[out] tile The tile containing the polygon.
|
|
||||||
/// @param[out] poly The polygon.
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
|
||||||
|
|
||||||
/// Returns the tile and polygon for the specified polygon reference.
|
|
||||||
/// @param[in] ref A known valid reference for a polygon.
|
|
||||||
/// @param[out] tile The tile containing the polygon.
|
|
||||||
/// @param[out] poly The polygon.
|
|
||||||
void getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
|
||||||
|
|
||||||
/// Checks the validity of a polygon reference.
|
|
||||||
/// @param[in] ref The polygon reference to check.
|
|
||||||
/// @return True if polygon reference is valid for the navigation mesh.
|
|
||||||
bool isValidPolyRef(dtPolyRef ref) const;
|
|
||||||
|
|
||||||
/// Gets the polygon reference for the tile's base polygon.
|
|
||||||
/// @param[in] tile The tile.
|
|
||||||
/// @return The polygon reference for the base polygon in the specified tile.
|
|
||||||
dtPolyRef getPolyRefBase(const dtMeshTile* tile) const;
|
|
||||||
|
|
||||||
/// Gets the endpoints for an off-mesh connection, ordered by "direction of travel".
|
|
||||||
/// @param[in] prevRef The reference of the polygon before the connection.
|
|
||||||
/// @param[in] polyRef The reference of the off-mesh connection polygon.
|
|
||||||
/// @param[out] startPos The start position of the off-mesh connection. [(x, y, z)]
|
|
||||||
/// @param[out] endPos The end position of the off-mesh connection. [(x, y, z)]
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const;
|
|
||||||
|
|
||||||
/// Gets the specified off-mesh connection.
|
|
||||||
/// @param[in] ref The polygon reference of the off-mesh connection.
|
|
||||||
/// @return The specified off-mesh connection, or null if the polygon reference is not valid.
|
|
||||||
const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const;
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
/// @{
|
|
||||||
/// @name State Management
|
|
||||||
/// These functions do not effect #dtTileRef or #dtPolyRef's.
|
|
||||||
|
|
||||||
/// Sets the user defined flags for the specified polygon.
|
|
||||||
/// @param[in] ref The polygon reference.
|
|
||||||
/// @param[in] flags The new flags for the polygon.
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus setPolyFlags(dtPolyRef ref, unsigned short flags);
|
|
||||||
|
|
||||||
/// Gets the user defined flags for the specified polygon.
|
|
||||||
/// @param[in] ref The polygon reference.
|
|
||||||
/// @param[out] resultFlags The polygon flags.
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) const;
|
|
||||||
|
|
||||||
/// Sets the user defined area for the specified polygon.
|
|
||||||
/// @param[in] ref The polygon reference.
|
|
||||||
/// @param[in] area The new area id for the polygon. [Limit: < #DT_MAX_AREAS]
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus setPolyArea(dtPolyRef ref, unsigned char area);
|
|
||||||
|
|
||||||
/// Gets the user defined area for the specified polygon.
|
|
||||||
/// @param[in] ref The polygon reference.
|
|
||||||
/// @param[out] resultArea The area id for the polygon.
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus getPolyArea(dtPolyRef ref, unsigned char* resultArea) const;
|
|
||||||
|
|
||||||
/// Gets the size of the buffer required by #storeTileState to store the specified tile's state.
|
|
||||||
/// @param[in] tile The tile.
|
|
||||||
/// @return The size of the buffer required to store the state.
|
|
||||||
int getTileStateSize(const dtMeshTile* tile) const;
|
|
||||||
|
|
||||||
/// Stores the non-structural state of the tile in the specified buffer. (Flags, area ids, etc.)
|
|
||||||
/// @param[in] tile The tile.
|
|
||||||
/// @param[out] data The buffer to store the tile's state in.
|
|
||||||
/// @param[in] maxDataSize The size of the data buffer. [Limit: >= #getTileStateSize]
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus storeTileState(const dtMeshTile* tile, unsigned char* data, const int maxDataSize) const;
|
|
||||||
|
|
||||||
/// Restores the state of the tile.
|
|
||||||
/// @param[in] tile The tile.
|
|
||||||
/// @param[in] data The new state. (Obtained from #storeTileState.)
|
|
||||||
/// @param[in] maxDataSize The size of the state within the data buffer.
|
|
||||||
/// @return The status flags for the operation.
|
|
||||||
dtStatus restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize);
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
/// @{
|
|
||||||
/// @name Encoding and Decoding
|
|
||||||
/// These functions are generally meant for internal use only.
|
|
||||||
|
|
||||||
/// Derives a standard polygon reference.
|
|
||||||
/// @note This function is generally meant for internal use only.
|
|
||||||
/// @param[in] salt The tile's salt value.
|
|
||||||
/// @param[in] it The index of the tile.
|
|
||||||
/// @param[in] ip The index of the polygon within the tile.
|
|
||||||
inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const
|
|
||||||
{
|
|
||||||
#ifdef DT_POLYREF64
|
|
||||||
return ((dtPolyRef)salt << (DT_POLY_BITS+DT_TILE_BITS)) | ((dtPolyRef)it << DT_POLY_BITS) | (dtPolyRef)ip;
|
|
||||||
#else
|
|
||||||
return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decodes a standard polygon reference.
|
|
||||||
/// @note This function is generally meant for internal use only.
|
|
||||||
/// @param[in] ref The polygon reference to decode.
|
|
||||||
/// @param[out] salt The tile's salt value.
|
|
||||||
/// @param[out] it The index of the tile.
|
|
||||||
/// @param[out] ip The index of the polygon within the tile.
|
|
||||||
/// @see #encodePolyId
|
|
||||||
inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
|
|
||||||
{
|
|
||||||
#ifdef DT_POLYREF64
|
|
||||||
const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
|
|
||||||
const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
|
|
||||||
const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
|
|
||||||
salt = (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
|
|
||||||
it = (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
|
|
||||||
ip = (unsigned int)(ref & polyMask);
|
|
||||||
#else
|
|
||||||
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
|
||||||
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
|
||||||
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
|
||||||
salt = (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
|
||||||
it = (unsigned int)((ref >> m_polyBits) & tileMask);
|
|
||||||
ip = (unsigned int)(ref & polyMask);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts a tile's salt value from the specified polygon reference.
|
|
||||||
/// @note This function is generally meant for internal use only.
|
|
||||||
/// @param[in] ref The polygon reference.
|
|
||||||
/// @see #encodePolyId
|
|
||||||
inline unsigned int decodePolyIdSalt(dtPolyRef ref) const
|
|
||||||
{
|
|
||||||
#ifdef DT_POLYREF64
|
|
||||||
const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
|
|
||||||
return (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
|
|
||||||
#else
|
|
||||||
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
|
||||||
return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts the tile's index from the specified polygon reference.
|
|
||||||
/// @note This function is generally meant for internal use only.
|
|
||||||
/// @param[in] ref The polygon reference.
|
|
||||||
/// @see #encodePolyId
|
|
||||||
inline unsigned int decodePolyIdTile(dtPolyRef ref) const
|
|
||||||
{
|
|
||||||
#ifdef DT_POLYREF64
|
|
||||||
const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
|
|
||||||
return (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
|
|
||||||
#else
|
|
||||||
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
|
||||||
return (unsigned int)((ref >> m_polyBits) & tileMask);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts the polygon's index (within its tile) from the specified polygon reference.
|
|
||||||
/// @note This function is generally meant for internal use only.
|
|
||||||
/// @param[in] ref The polygon reference.
|
|
||||||
/// @see #encodePolyId
|
|
||||||
inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
|
|
||||||
{
|
|
||||||
#ifdef DT_POLYREF64
|
|
||||||
const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
|
|
||||||
return (unsigned int)(ref & polyMask);
|
|
||||||
#else
|
|
||||||
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
|
||||||
return (unsigned int)(ref & polyMask);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Explicitly disabled copy constructor and copy assignment operator.
|
|
||||||
dtNavMesh(const dtNavMesh&);
|
|
||||||
dtNavMesh& operator=(const dtNavMesh&);
|
|
||||||
|
|
||||||
/// Returns pointer to tile in the tile array.
|
|
||||||
dtMeshTile* getTile(int i);
|
|
||||||
|
|
||||||
/// Returns neighbour tile based on side.
|
|
||||||
int getTilesAt(const int x, const int y,
|
|
||||||
dtMeshTile** tiles, const int maxTiles) const;
|
|
||||||
|
|
||||||
/// Returns neighbour tile based on side.
|
|
||||||
int getNeighbourTilesAt(const int x, const int y, const int side,
|
|
||||||
dtMeshTile** tiles, const int maxTiles) const;
|
|
||||||
|
|
||||||
/// Returns all polygons in neighbour tile based on portal defined by the segment.
|
|
||||||
int findConnectingPolys(const float* va, const float* vb,
|
|
||||||
const dtMeshTile* tile, int side,
|
|
||||||
dtPolyRef* con, float* conarea, int maxcon) const;
|
|
||||||
|
|
||||||
/// Builds internal polygons links for a tile.
|
|
||||||
void connectIntLinks(dtMeshTile* tile);
|
|
||||||
/// Builds internal polygons links for a tile.
|
|
||||||
void baseOffMeshLinks(dtMeshTile* tile);
|
|
||||||
|
|
||||||
/// Builds external polygon links for a tile.
|
|
||||||
void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
|
||||||
/// Builds external polygon links for a tile.
|
|
||||||
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
|
||||||
|
|
||||||
/// Removes external links at specified side.
|
|
||||||
void unconnectLinks(dtMeshTile* tile, dtMeshTile* target);
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.
|
|
||||||
|
|
||||||
/// Queries polygons within a tile.
|
|
||||||
int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
|
||||||
dtPolyRef* polys, const int maxPolys) const;
|
|
||||||
/// Find nearest polygon within a tile.
|
|
||||||
dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center,
|
|
||||||
const float* halfExtents, float* nearestPt) const;
|
|
||||||
/// Returns whether position is over the poly and the height at the position if so.
|
|
||||||
bool getPolyHeight(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* height) const;
|
|
||||||
/// Returns closest point on polygon.
|
|
||||||
void closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
|
||||||
|
|
||||||
dtNavMeshParams m_params; ///< Current initialization params. TODO: do not store this info twice.
|
|
||||||
float m_orig[3]; ///< Origin of the tile (0,0)
|
|
||||||
float m_tileWidth, m_tileHeight; ///< Dimensions of each tile.
|
|
||||||
int m_maxTiles; ///< Max number of tiles.
|
|
||||||
int m_tileLutSize; ///< Tile hash lookup size (must be pot).
|
|
||||||
int m_tileLutMask; ///< Tile hash lookup mask.
|
|
||||||
|
|
||||||
dtMeshTile** m_posLookup; ///< Tile hash lookup.
|
|
||||||
dtMeshTile* m_nextFree; ///< Freelist of tiles.
|
|
||||||
dtMeshTile* m_tiles; ///< List of tiles.
|
|
||||||
|
|
||||||
#ifndef DT_POLYREF64
|
|
||||||
unsigned int m_saltBits; ///< Number of salt bits in the tile ID.
|
|
||||||
unsigned int m_tileBits; ///< Number of tile bits in the tile ID.
|
|
||||||
unsigned int m_polyBits; ///< Number of poly bits in the tile ID.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
friend class dtNavMeshQuery;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Allocates a navigation mesh object using the Detour allocator.
|
|
||||||
/// @return A navigation mesh that is ready for initialization, or null on failure.
|
|
||||||
/// @ingroup detour
|
|
||||||
dtNavMesh* dtAllocNavMesh();
|
|
||||||
|
|
||||||
/// Frees the specified navigation mesh object using the Detour allocator.
|
|
||||||
/// @param[in] navmesh A navigation mesh allocated using #dtAllocNavMesh
|
|
||||||
/// @ingroup detour
|
|
||||||
void dtFreeNavMesh(dtNavMesh* navmesh);
|
|
||||||
|
|
||||||
#endif // DETOURNAVMESH_H
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// This section contains detailed documentation for members that don't have
|
|
||||||
// a source file. It reduces clutter in the main section of the header.
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
@typedef dtPolyRef
|
|
||||||
@par
|
|
||||||
|
|
||||||
Polygon references are subject to the same invalidate/preserve/restore
|
|
||||||
rules that apply to #dtTileRef's. If the #dtTileRef for the polygon's
|
|
||||||
tile changes, the polygon reference becomes invalid.
|
|
||||||
|
|
||||||
Changing a polygon's flags, area id, etc. does not impact its polygon
|
|
||||||
reference.
|
|
||||||
|
|
||||||
@typedef dtTileRef
|
|
||||||
@par
|
|
||||||
|
|
||||||
The following changes will invalidate a tile reference:
|
|
||||||
|
|
||||||
- The referenced tile has been removed from the navigation mesh.
|
|
||||||
- The navigation mesh has been initialized using a different set
|
|
||||||
of #dtNavMeshParams.
|
|
||||||
|
|
||||||
A tile reference is preserved/restored if the tile is added to a navigation
|
|
||||||
mesh initialized with the original #dtNavMeshParams and is added at the
|
|
||||||
original reference location. (E.g. The lastRef parameter is used with
|
|
||||||
dtNavMesh::addTile.)
|
|
||||||
|
|
||||||
Basically, if the storage structure of a tile changes, its associated
|
|
||||||
tile reference changes.
|
|
||||||
|
|
||||||
|
|
||||||
@var unsigned short dtPoly::neis[DT_VERTS_PER_POLYGON]
|
|
||||||
@par
|
|
||||||
|
|
||||||
Each entry represents data for the edge starting at the vertex of the same index.
|
|
||||||
E.g. The entry at index n represents the edge data for vertex[n] to vertex[n+1].
|
|
||||||
|
|
||||||
A value of zero indicates the edge has no polygon connection. (It makes up the
|
|
||||||
border of the navigation mesh.)
|
|
||||||
|
|
||||||
The information can be extracted as follows:
|
|
||||||
@code
|
|
||||||
neighborRef = neis[n] & 0xff; // Get the neighbor polygon reference.
|
|
||||||
|
|
||||||
if (neis[n] & #DT_EX_LINK)
|
|
||||||
{
|
|
||||||
// The edge is an external (portal) edge.
|
|
||||||
}
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
@var float dtMeshHeader::bvQuantFactor
|
|
||||||
@par
|
|
||||||
|
|
||||||
This value is used for converting between world and bounding volume coordinates.
|
|
||||||
For example:
|
|
||||||
@code
|
|
||||||
const float cs = 1.0f / tile->header->bvQuantFactor;
|
|
||||||
const dtBVNode* n = &tile->bvTree[i];
|
|
||||||
if (n->i >= 0)
|
|
||||||
{
|
|
||||||
// This is a leaf node.
|
|
||||||
float worldMinX = tile->header->bmin[0] + n->bmin[0]*cs;
|
|
||||||
float worldMinY = tile->header->bmin[0] + n->bmin[1]*cs;
|
|
||||||
// Etc...
|
|
||||||
}
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
@struct dtMeshTile
|
|
||||||
@par
|
|
||||||
|
|
||||||
Tiles generally only exist within the context of a dtNavMesh object.
|
|
||||||
|
|
||||||
Some tile content is optional. For example, a tile may not contain any
|
|
||||||
off-mesh connections. In this case the associated pointer will be null.
|
|
||||||
|
|
||||||
If a detail mesh exists it will share vertices with the base polygon mesh.
|
|
||||||
Only the vertices unique to the detail mesh will be stored in #detailVerts.
|
|
||||||
|
|
||||||
@warning Tiles returned by a dtNavMesh object are not guarenteed to be populated.
|
|
||||||
For example: The tile at a location might not have been loaded yet, or may have been removed.
|
|
||||||
In this case, pointers will be null. So if in doubt, check the polygon count in the
|
|
||||||
tile's header to determine if a tile has polygons defined.
|
|
||||||
|
|
||||||
@var float dtOffMeshConnection::pos[6]
|
|
||||||
@par
|
|
||||||
|
|
||||||
For a properly built navigation mesh, vertex A will always be within the bounds of the mesh.
|
|
||||||
Vertex B is not required to be within the bounds of the mesh.
|
|
||||||
|
|
||||||
*/
|
|
|
@ -1,149 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURNAVMESHBUILDER_H
|
|
||||||
#define DETOURNAVMESHBUILDER_H
|
|
||||||
|
|
||||||
#include "DetourAlloc.h"
|
|
||||||
|
|
||||||
/// Represents the source data used to build an navigation mesh tile.
|
|
||||||
/// @ingroup detour
|
|
||||||
struct dtNavMeshCreateParams
|
|
||||||
{
|
|
||||||
|
|
||||||
/// @name Polygon Mesh Attributes
|
|
||||||
/// Used to create the base navigation graph.
|
|
||||||
/// See #rcPolyMesh for details related to these attributes.
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
const unsigned short* verts; ///< The polygon mesh vertices. [(x, y, z) * #vertCount] [Unit: vx]
|
|
||||||
int vertCount; ///< The number vertices in the polygon mesh. [Limit: >= 3]
|
|
||||||
const unsigned short* polys; ///< The polygon data. [Size: #polyCount * 2 * #nvp]
|
|
||||||
const unsigned short* polyFlags; ///< The user defined flags assigned to each polygon. [Size: #polyCount]
|
|
||||||
const unsigned char* polyAreas; ///< The user defined area ids assigned to each polygon. [Size: #polyCount]
|
|
||||||
int polyCount; ///< Number of polygons in the mesh. [Limit: >= 1]
|
|
||||||
int nvp; ///< Number maximum number of vertices per polygon. [Limit: >= 3]
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
/// @name Height Detail Attributes (Optional)
|
|
||||||
/// See #rcPolyMeshDetail for details related to these attributes.
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
const unsigned int* detailMeshes; ///< The height detail sub-mesh data. [Size: 4 * #polyCount]
|
|
||||||
const float* detailVerts; ///< The detail mesh vertices. [Size: 3 * #detailVertsCount] [Unit: wu]
|
|
||||||
int detailVertsCount; ///< The number of vertices in the detail mesh.
|
|
||||||
const unsigned char* detailTris; ///< The detail mesh triangles. [Size: 4 * #detailTriCount]
|
|
||||||
int detailTriCount; ///< The number of triangles in the detail mesh.
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
/// @name Off-Mesh Connections Attributes (Optional)
|
|
||||||
/// Used to define a custom point-to-point edge within the navigation graph, an
|
|
||||||
/// off-mesh connection is a user defined traversable connection made up to two vertices,
|
|
||||||
/// at least one of which resides within a navigation mesh polygon.
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
/// Off-mesh connection vertices. [(ax, ay, az, bx, by, bz) * #offMeshConCount] [Unit: wu]
|
|
||||||
const float* offMeshConVerts;
|
|
||||||
/// Off-mesh connection radii. [Size: #offMeshConCount] [Unit: wu]
|
|
||||||
const float* offMeshConRad;
|
|
||||||
/// User defined flags assigned to the off-mesh connections. [Size: #offMeshConCount]
|
|
||||||
const unsigned short* offMeshConFlags;
|
|
||||||
/// User defined area ids assigned to the off-mesh connections. [Size: #offMeshConCount]
|
|
||||||
const unsigned char* offMeshConAreas;
|
|
||||||
/// The permitted travel direction of the off-mesh connections. [Size: #offMeshConCount]
|
|
||||||
///
|
|
||||||
/// 0 = Travel only from endpoint A to endpoint B.<br/>
|
|
||||||
/// #DT_OFFMESH_CON_BIDIR = Bidirectional travel.
|
|
||||||
const unsigned char* offMeshConDir;
|
|
||||||
/// The user defined ids of the off-mesh connection. [Size: #offMeshConCount]
|
|
||||||
const unsigned int* offMeshConUserID;
|
|
||||||
/// The number of off-mesh connections. [Limit: >= 0]
|
|
||||||
int offMeshConCount;
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
/// @name Tile Attributes
|
|
||||||
/// @note The tile grid/layer data can be left at zero if the destination is a single tile mesh.
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
unsigned int userId; ///< The user defined id of the tile.
|
|
||||||
int tileX; ///< The tile's x-grid location within the multi-tile destination mesh. (Along the x-axis.)
|
|
||||||
int tileY; ///< The tile's y-grid location within the multi-tile desitation mesh. (Along the z-axis.)
|
|
||||||
int tileLayer; ///< The tile's layer within the layered destination mesh. [Limit: >= 0] (Along the y-axis.)
|
|
||||||
float bmin[3]; ///< The minimum bounds of the tile. [(x, y, z)] [Unit: wu]
|
|
||||||
float bmax[3]; ///< The maximum bounds of the tile. [(x, y, z)] [Unit: wu]
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
/// @name General Configuration Attributes
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
float walkableHeight; ///< The agent height. [Unit: wu]
|
|
||||||
float walkableRadius; ///< The agent radius. [Unit: wu]
|
|
||||||
float walkableClimb; ///< The agent maximum traversable ledge. (Up/Down) [Unit: wu]
|
|
||||||
float cs; ///< The xz-plane cell size of the polygon mesh. [Limit: > 0] [Unit: wu]
|
|
||||||
float ch; ///< The y-axis cell height of the polygon mesh. [Limit: > 0] [Unit: wu]
|
|
||||||
|
|
||||||
/// True if a bounding volume tree should be built for the tile.
|
|
||||||
/// @note The BVTree is not normally needed for layered navigation meshes.
|
|
||||||
bool buildBvTree;
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Builds navigation mesh tile data from the provided tile creation data.
|
|
||||||
/// @ingroup detour
|
|
||||||
/// @param[in] params Tile creation data.
|
|
||||||
/// @param[out] outData The resulting tile data.
|
|
||||||
/// @param[out] outDataSize The size of the tile data array.
|
|
||||||
/// @return True if the tile data was successfully created.
|
|
||||||
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize);
|
|
||||||
|
|
||||||
/// Swaps the endianess of the tile data's header (#dtMeshHeader).
|
|
||||||
/// @param[in,out] data The tile data array.
|
|
||||||
/// @param[in] dataSize The size of the data array.
|
|
||||||
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int dataSize);
|
|
||||||
|
|
||||||
/// Swaps endianess of the tile data.
|
|
||||||
/// @param[in,out] data The tile data array.
|
|
||||||
/// @param[in] dataSize The size of the data array.
|
|
||||||
bool dtNavMeshDataSwapEndian(unsigned char* data, const int dataSize);
|
|
||||||
|
|
||||||
#endif // DETOURNAVMESHBUILDER_H
|
|
||||||
|
|
||||||
// This section contains detailed documentation for members that don't have
|
|
||||||
// a source file. It reduces clutter in the main section of the header.
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
@struct dtNavMeshCreateParams
|
|
||||||
@par
|
|
||||||
|
|
||||||
This structure is used to marshal data between the Recast mesh generation pipeline and Detour navigation components.
|
|
||||||
|
|
||||||
See the rcPolyMesh and rcPolyMeshDetail documentation for detailed information related to mesh structure.
|
|
||||||
|
|
||||||
Units are usually in voxels (vx) or world units (wu). The units for voxels, grid size, and cell size
|
|
||||||
are all based on the values of #cs and #ch.
|
|
||||||
|
|
||||||
The standard navigation mesh build process is to create tile data using dtCreateNavMeshData, then add the tile
|
|
||||||
to a navigation mesh using either the dtNavMesh single tile <tt>init()</tt> function or the dtNavMesh::addTile()
|
|
||||||
function.
|
|
||||||
|
|
||||||
@see dtCreateNavMeshData
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
|
@ -1,573 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURNAVMESHQUERY_H
|
|
||||||
#define DETOURNAVMESHQUERY_H
|
|
||||||
|
|
||||||
#include "DetourNavMesh.h"
|
|
||||||
#include "DetourStatus.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.
|
|
||||||
// On certain platforms indirect or virtual function call is expensive. The default
|
|
||||||
// setting is to use non-virtual functions, the actual implementations of the functions
|
|
||||||
// are declared as inline for maximum speed.
|
|
||||||
|
|
||||||
//#define DT_VIRTUAL_QUERYFILTER 1
|
|
||||||
|
|
||||||
/// Defines polygon filtering and traversal costs for navigation mesh query operations.
|
|
||||||
/// @ingroup detour
|
|
||||||
class dtQueryFilter
|
|
||||||
{
|
|
||||||
float m_areaCost[DT_MAX_AREAS]; ///< Cost per area type. (Used by default implementation.)
|
|
||||||
unsigned short m_includeFlags; ///< Flags for polygons that can be visited. (Used by default implementation.)
|
|
||||||
unsigned short m_excludeFlags; ///< Flags for polygons that should not be visted. (Used by default implementation.)
|
|
||||||
|
|
||||||
public:
|
|
||||||
dtQueryFilter();
|
|
||||||
|
|
||||||
#ifdef DT_VIRTUAL_QUERYFILTER
|
|
||||||
virtual ~dtQueryFilter() { }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Returns true if the polygon can be visited. (I.e. Is traversable.)
|
|
||||||
/// @param[in] ref The reference id of the polygon test.
|
|
||||||
/// @param[in] tile The tile containing the polygon.
|
|
||||||
/// @param[in] poly The polygon to test.
|
|
||||||
#ifdef DT_VIRTUAL_QUERYFILTER
|
|
||||||
virtual bool passFilter(const dtPolyRef ref,
|
|
||||||
const dtMeshTile* tile,
|
|
||||||
const dtPoly* poly) const;
|
|
||||||
#else
|
|
||||||
bool passFilter(const dtPolyRef ref,
|
|
||||||
const dtMeshTile* tile,
|
|
||||||
const dtPoly* poly) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Returns cost to move from the beginning to the end of a line segment
|
|
||||||
/// that is fully contained within a polygon.
|
|
||||||
/// @param[in] pa The start position on the edge of the previous and current polygon. [(x, y, z)]
|
|
||||||
/// @param[in] pb The end position on the edge of the current and next polygon. [(x, y, z)]
|
|
||||||
/// @param[in] prevRef The reference id of the previous polygon. [opt]
|
|
||||||
/// @param[in] prevTile The tile containing the previous polygon. [opt]
|
|
||||||
/// @param[in] prevPoly The previous polygon. [opt]
|
|
||||||
/// @param[in] curRef The reference id of the current polygon.
|
|
||||||
/// @param[in] curTile The tile containing the current polygon.
|
|
||||||
/// @param[in] curPoly The current polygon.
|
|
||||||
/// @param[in] nextRef The refernece id of the next polygon. [opt]
|
|
||||||
/// @param[in] nextTile The tile containing the next polygon. [opt]
|
|
||||||
/// @param[in] nextPoly The next polygon. [opt]
|
|
||||||
#ifdef DT_VIRTUAL_QUERYFILTER
|
|
||||||
virtual float getCost(const float* pa, const float* pb,
|
|
||||||
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
|
||||||
const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly,
|
|
||||||
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
|
||||||
#else
|
|
||||||
float getCost(const float* pa, const float* pb,
|
|
||||||
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
|
||||||
const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly,
|
|
||||||
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// @name Getters and setters for the default implementation data.
|
|
||||||
///@{
|
|
||||||
|
|
||||||
/// Returns the traversal cost of the area.
|
|
||||||
/// @param[in] i The id of the area.
|
|
||||||
/// @returns The traversal cost of the area.
|
|
||||||
inline float getAreaCost(const int i) const { return m_areaCost[i]; }
|
|
||||||
|
|
||||||
/// Sets the traversal cost of the area.
|
|
||||||
/// @param[in] i The id of the area.
|
|
||||||
/// @param[in] cost The new cost of traversing the area.
|
|
||||||
inline void setAreaCost(const int i, const float cost) { m_areaCost[i] = cost; }
|
|
||||||
|
|
||||||
/// Returns the include flags for the filter.
|
|
||||||
/// Any polygons that include one or more of these flags will be
|
|
||||||
/// included in the operation.
|
|
||||||
inline unsigned short getIncludeFlags() const { return m_includeFlags; }
|
|
||||||
|
|
||||||
/// Sets the include flags for the filter.
|
|
||||||
/// @param[in] flags The new flags.
|
|
||||||
inline void setIncludeFlags(const unsigned short flags) { m_includeFlags = flags; }
|
|
||||||
|
|
||||||
/// Returns the exclude flags for the filter.
|
|
||||||
/// Any polygons that include one ore more of these flags will be
|
|
||||||
/// excluded from the operation.
|
|
||||||
inline unsigned short getExcludeFlags() const { return m_excludeFlags; }
|
|
||||||
|
|
||||||
/// Sets the exclude flags for the filter.
|
|
||||||
/// @param[in] flags The new flags.
|
|
||||||
inline void setExcludeFlags(const unsigned short flags) { m_excludeFlags = flags; }
|
|
||||||
|
|
||||||
///@}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Provides information about raycast hit
|
|
||||||
/// filled by dtNavMeshQuery::raycast
|
|
||||||
/// @ingroup detour
|
|
||||||
struct dtRaycastHit
|
|
||||||
{
|
|
||||||
/// The hit parameter. (FLT_MAX if no wall hit.)
|
|
||||||
float t;
|
|
||||||
|
|
||||||
/// hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
|
||||||
float hitNormal[3];
|
|
||||||
|
|
||||||
/// The index of the edge on the final polygon where the wall was hit.
|
|
||||||
int hitEdgeIndex;
|
|
||||||
|
|
||||||
/// Pointer to an array of reference ids of the visited polygons. [opt]
|
|
||||||
dtPolyRef* path;
|
|
||||||
|
|
||||||
/// The number of visited polygons. [opt]
|
|
||||||
int pathCount;
|
|
||||||
|
|
||||||
/// The maximum number of polygons the @p path array can hold.
|
|
||||||
int maxPath;
|
|
||||||
|
|
||||||
/// The cost of the path until hit.
|
|
||||||
float pathCost;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Provides custom polygon query behavior.
|
|
||||||
/// Used by dtNavMeshQuery::queryPolygons.
|
|
||||||
/// @ingroup detour
|
|
||||||
class dtPolyQuery
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~dtPolyQuery() { }
|
|
||||||
|
|
||||||
/// Called for each batch of unique polygons touched by the search area in dtNavMeshQuery::queryPolygons.
|
|
||||||
/// This can be called multiple times for a single query.
|
|
||||||
virtual void process(const dtMeshTile* tile, dtPoly** polys, dtPolyRef* refs, int count) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Provides the ability to perform pathfinding related queries against
|
|
||||||
/// a navigation mesh.
|
|
||||||
/// @ingroup detour
|
|
||||||
class dtNavMeshQuery
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dtNavMeshQuery();
|
|
||||||
~dtNavMeshQuery();
|
|
||||||
|
|
||||||
/// Initializes the query object.
|
|
||||||
/// @param[in] nav Pointer to the dtNavMesh object to use for all queries.
|
|
||||||
/// @param[in] maxNodes Maximum number of search nodes. [Limits: 0 < value <= 65535]
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus init(const dtNavMesh* nav, const int maxNodes);
|
|
||||||
|
|
||||||
/// @name Standard Pathfinding Functions
|
|
||||||
// /@{
|
|
||||||
|
|
||||||
/// Finds a path from the start polygon to the end polygon.
|
|
||||||
/// @param[in] startRef The refrence id of the start polygon.
|
|
||||||
/// @param[in] endRef The reference id of the end polygon.
|
|
||||||
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
|
||||||
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
|
||||||
/// [(polyRef) * @p pathCount]
|
|
||||||
/// @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]
|
|
||||||
dtStatus findPath(dtPolyRef startRef, dtPolyRef endRef,
|
|
||||||
const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* path, int* pathCount, const int maxPath) const;
|
|
||||||
|
|
||||||
/// Finds the straight path from the start to the end position within the polygon corridor.
|
|
||||||
/// @param[in] startPos Path start position. [(x, y, z)]
|
|
||||||
/// @param[in] endPos Path end position. [(x, y, z)]
|
|
||||||
/// @param[in] path An array of polygon references that represent the path corridor.
|
|
||||||
/// @param[in] pathSize The number of polygons in the @p path array.
|
|
||||||
/// @param[out] straightPath Points describing the straight path. [(x, y, z) * @p straightPathCount].
|
|
||||||
/// @param[out] straightPathFlags Flags describing each point. (See: #dtStraightPathFlags) [opt]
|
|
||||||
/// @param[out] straightPathRefs The reference id of the polygon that is being entered at each point. [opt]
|
|
||||||
/// @param[out] straightPathCount The number of points in the straight path.
|
|
||||||
/// @param[in] maxStraightPath The maximum number of points the straight path arrays can hold. [Limit: > 0]
|
|
||||||
/// @param[in] options Query options. (see: #dtStraightPathOptions)
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus findStraightPath(const float* startPos, const float* endPos,
|
|
||||||
const dtPolyRef* path, const int pathSize,
|
|
||||||
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
|
||||||
int* straightPathCount, const int maxStraightPath, const int options = 0) const;
|
|
||||||
|
|
||||||
///@}
|
|
||||||
/// @name Sliced Pathfinding Functions
|
|
||||||
/// Common use case:
|
|
||||||
/// -# Call initSlicedFindPath() to initialize the sliced path query.
|
|
||||||
/// -# Call updateSlicedFindPath() until it returns complete.
|
|
||||||
/// -# Call finalizeSlicedFindPath() to get the path.
|
|
||||||
///@{
|
|
||||||
|
|
||||||
/// Intializes a sliced path query.
|
|
||||||
/// @param[in] startRef The refrence id of the start polygon.
|
|
||||||
/// @param[in] endRef The reference id of the end polygon.
|
|
||||||
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
|
||||||
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[in] options query options (see: #dtFindPathOptions)
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef,
|
|
||||||
const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter, const unsigned int options = 0);
|
|
||||||
|
|
||||||
/// Updates an in-progress sliced path query.
|
|
||||||
/// @param[in] maxIter The maximum number of iterations to perform.
|
|
||||||
/// @param[out] doneIters The actual number of iterations completed. [opt]
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus updateSlicedFindPath(const int maxIter, int* doneIters);
|
|
||||||
|
|
||||||
/// Finalizes and returns the results of a sliced path query.
|
|
||||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
|
||||||
/// [(polyRef) * @p pathCount]
|
|
||||||
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
|
||||||
/// @param[in] maxPath The max number of polygons the path array can hold. [Limit: >= 1]
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath);
|
|
||||||
|
|
||||||
/// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest
|
|
||||||
/// polygon on the existing path that was visited during the search.
|
|
||||||
/// @param[in] existing An array of polygon references for the existing path.
|
|
||||||
/// @param[in] existingSize The number of polygon in the @p existing array.
|
|
||||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
|
||||||
/// [(polyRef) * @p pathCount]
|
|
||||||
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
|
||||||
/// @param[in] maxPath The max number of polygons the @p path array can hold. [Limit: >= 1]
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
|
|
||||||
dtPolyRef* path, int* pathCount, const int maxPath);
|
|
||||||
|
|
||||||
///@}
|
|
||||||
/// @name Dijkstra Search Functions
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
/// Finds the polygons along the navigation graph that touch the specified circle.
|
|
||||||
/// @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] radius The radius of the search circle.
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[out] resultRef The reference ids of the polygons touched by the circle. [opt]
|
|
||||||
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
|
||||||
/// Zero if a result polygon has no parent. [opt]
|
|
||||||
/// @param[out] resultCost The search cost from @p centerPos to the polygon. [opt]
|
|
||||||
/// @param[out] resultCount The number of polygons found. [opt]
|
|
||||||
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
|
||||||
int* resultCount, const int maxResult) const;
|
|
||||||
|
|
||||||
/// Finds the polygons along the naviation graph that touch the specified convex polygon.
|
|
||||||
/// @param[in] startRef The reference id of the polygon where the search starts.
|
|
||||||
/// @param[in] verts The vertices describing the convex polygon. (CCW)
|
|
||||||
/// [(x, y, z) * @p nverts]
|
|
||||||
/// @param[in] nverts The number of vertices in the polygon.
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[out] resultRef The reference ids of the polygons touched by the search polygon. [opt]
|
|
||||||
/// @param[out] resultParent The reference ids of the parent polygons for each result. Zero if a
|
|
||||||
/// result polygon has no parent. [opt]
|
|
||||||
/// @param[out] resultCost The search cost from the centroid point to the polygon. [opt]
|
|
||||||
/// @param[out] resultCount The number of polygons found.
|
|
||||||
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus findPolysAroundShape(dtPolyRef startRef, const float* verts, const int nverts,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
|
||||||
int* resultCount, const int maxResult) const;
|
|
||||||
|
|
||||||
/// Gets a path from the explored nodes in the previous search.
|
|
||||||
/// @param[in] endRef The reference id of the end polygon.
|
|
||||||
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
|
||||||
/// [(polyRef) * @p pathCount]
|
|
||||||
/// @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: >= 0]
|
|
||||||
/// @returns The status flags. Returns DT_FAILURE | DT_INVALID_PARAM if any parameter is wrong, or if
|
|
||||||
/// @p endRef was not explored in the previous search. Returns DT_SUCCESS | DT_BUFFER_TOO_SMALL
|
|
||||||
/// 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.
|
|
||||||
dtStatus getPathFromDijkstraSearch(dtPolyRef endRef, dtPolyRef* path, int* pathCount, int maxPath) const;
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
/// @name Local Query Functions
|
|
||||||
///@{
|
|
||||||
|
|
||||||
/// Finds the polygon nearest to the specified center point.
|
|
||||||
/// @param[in] center The center of the search box. [(x, y, z)]
|
|
||||||
/// @param[in] halfExtents The search distance along each axis. [(x, y, z)]
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[out] nearestRef The reference id of the nearest polygon.
|
|
||||||
/// @param[out] nearestPt The nearest point on the polygon. [opt] [(x, y, z)]
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus findNearestPoly(const float* center, const float* halfExtents,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* nearestRef, float* nearestPt) const;
|
|
||||||
|
|
||||||
/// Finds polygons that overlap the search box.
|
|
||||||
/// @param[in] center The center of the search box. [(x, y, z)]
|
|
||||||
/// @param[in] halfExtents The search distance along each axis. [(x, y, z)]
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[out] polys The reference ids of the polygons that overlap the query box.
|
|
||||||
/// @param[out] polyCount The number of polygons in the search result.
|
|
||||||
/// @param[in] maxPolys The maximum number of polygons the search result can hold.
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus queryPolygons(const float* center, const float* halfExtents,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* polys, int* polyCount, const int maxPolys) const;
|
|
||||||
|
|
||||||
/// Finds polygons that overlap the search box.
|
|
||||||
/// @param[in] center The center of the search box. [(x, y, z)]
|
|
||||||
/// @param[in] halfExtents The search distance along each axis. [(x, y, z)]
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[in] query The query. Polygons found will be batched together and passed to this query.
|
|
||||||
dtStatus queryPolygons(const float* center, const float* halfExtents,
|
|
||||||
const dtQueryFilter* filter, dtPolyQuery* query) const;
|
|
||||||
|
|
||||||
/// Finds the non-overlapping navigation polygons in the local neighbourhood around the center position.
|
|
||||||
/// @param[in] startRef The reference id of the polygon where the search starts.
|
|
||||||
/// @param[in] centerPos The center of the query circle. [(x, y, z)]
|
|
||||||
/// @param[in] radius The radius of the query circle.
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @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.
|
|
||||||
/// Zero if a result polygon has no parent. [opt]
|
|
||||||
/// @param[out] resultCount The number of polygons found.
|
|
||||||
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* resultRef, dtPolyRef* resultParent,
|
|
||||||
int* resultCount, const int maxResult) const;
|
|
||||||
|
|
||||||
/// Moves from the start to the end position constrained to the navigation mesh.
|
|
||||||
/// @param[in] startRef The reference id of the start polygon.
|
|
||||||
/// @param[in] startPos A position of the mover within the start polygon. [(x, y, x)]
|
|
||||||
/// @param[in] endPos The desired end position of the mover. [(x, y, z)]
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[out] resultPos The result position of the mover. [(x, y, z)]
|
|
||||||
/// @param[out] visited The reference ids of the 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.
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const;
|
|
||||||
|
|
||||||
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
|
||||||
/// the start position toward the end position.
|
|
||||||
/// @note A wrapper around raycast(..., RaycastHit*). Retained for backward compatibility.
|
|
||||||
/// @param[in] startRef The reference id of the start polygon.
|
|
||||||
/// @param[in] startPos A position within the start polygon representing
|
|
||||||
/// the start of the ray. [(x, y, z)]
|
|
||||||
/// @param[in] endPos The position to cast the ray toward. [(x, y, z)]
|
|
||||||
/// @param[out] t The hit parameter. (FLT_MAX if no wall hit.)
|
|
||||||
/// @param[out] hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[out] path The reference ids of the 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.
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const;
|
|
||||||
|
|
||||||
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
|
||||||
/// the start position toward the end position.
|
|
||||||
/// @param[in] startRef The reference id of the start polygon.
|
|
||||||
/// @param[in] startPos A position within the start polygon representing
|
|
||||||
/// the start of the ray. [(x, y, z)]
|
|
||||||
/// @param[in] endPos The position to cast the ray toward. [(x, y, z)]
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[in] flags govern how the raycast behaves. See dtRaycastOptions
|
|
||||||
/// @param[out] hit Pointer to a raycast hit structure which will be filled by the results.
|
|
||||||
/// @param[in] prevRef parent of start ref. Used during for cost calculation [opt]
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter, const unsigned int options,
|
|
||||||
dtRaycastHit* hit, dtPolyRef prevRef = 0) const;
|
|
||||||
|
|
||||||
|
|
||||||
/// Finds the distance from the specified position to the nearest polygon wall.
|
|
||||||
/// @param[in] startRef The reference id of the polygon containing @p centerPos.
|
|
||||||
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
|
||||||
/// @param[in] maxRadius The radius of the search circle.
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[out] hitDist The distance to the nearest wall from @p centerPos.
|
|
||||||
/// @param[out] hitPos The nearest position on the wall that was hit. [(x, y, z)]
|
|
||||||
/// @param[out] hitNormal The normalized ray formed from the wall point to the
|
|
||||||
/// source point. [(x, y, z)]
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
float* hitDist, float* hitPos, float* hitNormal) const;
|
|
||||||
|
|
||||||
/// Returns the segments for the specified polygon, optionally including portals.
|
|
||||||
/// @param[in] ref The reference id of the polygon.
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[out] segmentVerts The segments. [(ax, ay, az, bx, by, bz) * segmentCount]
|
|
||||||
/// @param[out] segmentRefs The reference ids of each segment's neighbor polygon.
|
|
||||||
/// Or zero if the segment is a wall. [opt] [(parentRef) * @p segmentCount]
|
|
||||||
/// @param[out] segmentCount The number of segments returned.
|
|
||||||
/// @param[in] maxSegments The maximum number of segments the result arrays can hold.
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter,
|
|
||||||
float* segmentVerts, dtPolyRef* segmentRefs, int* segmentCount,
|
|
||||||
const int maxSegments) const;
|
|
||||||
|
|
||||||
/// Returns random location on navmesh.
|
|
||||||
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
|
||||||
/// @param[in] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[in] frand Function returning a random number [0..1).
|
|
||||||
/// @param[out] randomRef The reference id of the random location.
|
|
||||||
/// @param[out] randomPt The random location.
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus findRandomPoint(const dtQueryFilter* filter, float (*frand)(),
|
|
||||||
dtPolyRef* randomRef, float* randomPt) const;
|
|
||||||
|
|
||||||
/// 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.
|
|
||||||
/// 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] filter The polygon filter to apply to the query.
|
|
||||||
/// @param[in] frand Function returning a random number [0..1).
|
|
||||||
/// @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.
|
|
||||||
dtStatus findRandomPointAroundCircle(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
|
||||||
const dtQueryFilter* filter, float (*frand)(),
|
|
||||||
dtPolyRef* randomRef, float* randomPt) const;
|
|
||||||
|
|
||||||
/// Finds the closest point on the specified polygon.
|
|
||||||
/// @param[in] ref The reference id of the polygon.
|
|
||||||
/// @param[in] pos The position to check. [(x, y, z)]
|
|
||||||
/// @param[out] closest The closest point on the polygon. [(x, y, z)]
|
|
||||||
/// @param[out] posOverPoly True of the position is over the polygon.
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
|
||||||
|
|
||||||
/// Returns a point on the boundary closest to the source point if the source point is outside the
|
|
||||||
/// polygon's xz-bounds.
|
|
||||||
/// @param[in] ref The reference id to the polygon.
|
|
||||||
/// @param[in] pos The position to check. [(x, y, z)]
|
|
||||||
/// @param[out] closest The closest point. [(x, y, z)]
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const;
|
|
||||||
|
|
||||||
/// Gets the height of the polygon at the provided position using the height detail. (Most accurate.)
|
|
||||||
/// @param[in] ref The reference id of the polygon.
|
|
||||||
/// @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.
|
|
||||||
/// @returns The status flags for the query.
|
|
||||||
dtStatus getPolyHeight(dtPolyRef ref, const float* pos, float* height) const;
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
/// @name Miscellaneous Functions
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
/// Returns true if the polygon reference is valid and passes the filter restrictions.
|
|
||||||
/// @param[in] ref The polygon reference to check.
|
|
||||||
/// @param[in] filter The filter to apply.
|
|
||||||
bool isValidPolyRef(dtPolyRef ref, const dtQueryFilter* filter) const;
|
|
||||||
|
|
||||||
/// Returns true if the polygon reference is in the closed list.
|
|
||||||
/// @param[in] ref The reference id of the polygon to check.
|
|
||||||
/// @returns True if the polygon is in closed list.
|
|
||||||
bool isInClosedList(dtPolyRef ref) const;
|
|
||||||
|
|
||||||
/// Gets the node pool.
|
|
||||||
/// @returns The node pool.
|
|
||||||
class dtNodePool* getNodePool() const { return m_nodePool; }
|
|
||||||
|
|
||||||
/// Gets the navigation mesh the query object is using.
|
|
||||||
/// @return The navigation mesh the query object is using.
|
|
||||||
const dtNavMesh* getAttachedNavMesh() const { return m_nav; }
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Explicitly disabled copy constructor and copy assignment operator
|
|
||||||
dtNavMeshQuery(const dtNavMeshQuery&);
|
|
||||||
dtNavMeshQuery& operator=(const dtNavMeshQuery&);
|
|
||||||
|
|
||||||
/// Queries polygons within a tile.
|
|
||||||
void queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
|
||||||
const dtQueryFilter* filter, dtPolyQuery* query) const;
|
|
||||||
|
|
||||||
/// Returns portal points between two polygons.
|
|
||||||
dtStatus getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
|
|
||||||
unsigned char& fromType, unsigned char& toType) const;
|
|
||||||
dtStatus getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
|
||||||
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
|
||||||
float* left, float* right) const;
|
|
||||||
|
|
||||||
/// Returns edge mid point between two polygons.
|
|
||||||
dtStatus getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const;
|
|
||||||
dtStatus getEdgeMidPoint(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
|
||||||
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
|
||||||
float* mid) const;
|
|
||||||
|
|
||||||
// Appends vertex to a straight path
|
|
||||||
dtStatus appendVertex(const float* pos, const unsigned char flags, const dtPolyRef ref,
|
|
||||||
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
|
||||||
int* straightPathCount, const int maxStraightPath) const;
|
|
||||||
|
|
||||||
// Appends intermediate portal points to a straight path.
|
|
||||||
dtStatus appendPortals(const int startIdx, const int endIdx, const float* endPos, const dtPolyRef* path,
|
|
||||||
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
|
||||||
int* straightPathCount, const int maxStraightPath, const int options) const;
|
|
||||||
|
|
||||||
// Gets the path leading to the specified end node.
|
|
||||||
dtStatus getPathToNode(struct dtNode* endNode, dtPolyRef* path, int* pathCount, int maxPath) const;
|
|
||||||
|
|
||||||
const dtNavMesh* m_nav; ///< Pointer to navmesh data.
|
|
||||||
|
|
||||||
struct dtQueryData
|
|
||||||
{
|
|
||||||
dtStatus status;
|
|
||||||
struct dtNode* lastBestNode;
|
|
||||||
float lastBestNodeCost;
|
|
||||||
dtPolyRef startRef, endRef;
|
|
||||||
float startPos[3], endPos[3];
|
|
||||||
const dtQueryFilter* filter;
|
|
||||||
unsigned int options;
|
|
||||||
float raycastLimitSqr;
|
|
||||||
};
|
|
||||||
dtQueryData m_query; ///< Sliced query state.
|
|
||||||
|
|
||||||
class dtNodePool* m_tinyNodePool; ///< Pointer to small node pool.
|
|
||||||
class dtNodePool* m_nodePool; ///< Pointer to node pool.
|
|
||||||
class dtNodeQueue* m_openList; ///< Pointer to open list queue.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Allocates a query object using the Detour allocator.
|
|
||||||
/// @return An allocated query object, or null on failure.
|
|
||||||
/// @ingroup detour
|
|
||||||
dtNavMeshQuery* dtAllocNavMeshQuery();
|
|
||||||
|
|
||||||
/// Frees the specified query object using the Detour allocator.
|
|
||||||
/// @param[in] query A query object allocated using #dtAllocNavMeshQuery
|
|
||||||
/// @ingroup detour
|
|
||||||
void dtFreeNavMeshQuery(dtNavMeshQuery* query);
|
|
||||||
|
|
||||||
#endif // DETOURNAVMESHQUERY_H
|
|
168
extern/recastnavigation/Detour/Include/DetourNode.h
vendored
168
extern/recastnavigation/Detour/Include/DetourNode.h
vendored
|
@ -1,168 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURNODE_H
|
|
||||||
#define DETOURNODE_H
|
|
||||||
|
|
||||||
#include "DetourNavMesh.h"
|
|
||||||
|
|
||||||
enum dtNodeFlags
|
|
||||||
{
|
|
||||||
DT_NODE_OPEN = 0x01,
|
|
||||||
DT_NODE_CLOSED = 0x02,
|
|
||||||
DT_NODE_PARENT_DETACHED = 0x04, // parent of the node is not adjacent. Found using raycast.
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef unsigned short dtNodeIndex;
|
|
||||||
static const dtNodeIndex DT_NULL_IDX = (dtNodeIndex)~0;
|
|
||||||
|
|
||||||
static const int DT_NODE_PARENT_BITS = 24;
|
|
||||||
static const int DT_NODE_STATE_BITS = 2;
|
|
||||||
struct dtNode
|
|
||||||
{
|
|
||||||
float pos[3]; ///< Position of the node.
|
|
||||||
float cost; ///< Cost from previous node to current node.
|
|
||||||
float total; ///< Cost up to the node.
|
|
||||||
unsigned int pidx : DT_NODE_PARENT_BITS; ///< Index to parent node.
|
|
||||||
unsigned int state : DT_NODE_STATE_BITS; ///< extra state information. A polyRef can have multiple nodes with different extra info. see DT_MAX_STATES_PER_NODE
|
|
||||||
unsigned int flags : 3; ///< Node flags. A combination of dtNodeFlags.
|
|
||||||
dtPolyRef id; ///< Polygon ref the node corresponds to.
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int DT_MAX_STATES_PER_NODE = 1 << DT_NODE_STATE_BITS; // number of extra states per node. See dtNode::state
|
|
||||||
|
|
||||||
class dtNodePool
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dtNodePool(int maxNodes, int hashSize);
|
|
||||||
~dtNodePool();
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
// Get a dtNode by ref and extra state information. If there is none then - allocate
|
|
||||||
// There can be more than one node for the same polyRef but with different extra state information
|
|
||||||
dtNode* getNode(dtPolyRef id, unsigned char state=0);
|
|
||||||
dtNode* findNode(dtPolyRef id, unsigned char state);
|
|
||||||
unsigned int findNodes(dtPolyRef id, dtNode** nodes, const int maxNodes);
|
|
||||||
|
|
||||||
inline unsigned int getNodeIdx(const dtNode* node) const
|
|
||||||
{
|
|
||||||
if (!node) return 0;
|
|
||||||
return (unsigned int)(node - m_nodes) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline dtNode* getNodeAtIdx(unsigned int idx)
|
|
||||||
{
|
|
||||||
if (!idx) return 0;
|
|
||||||
return &m_nodes[idx - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const dtNode* getNodeAtIdx(unsigned int idx) const
|
|
||||||
{
|
|
||||||
if (!idx) return 0;
|
|
||||||
return &m_nodes[idx - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int getMemUsed() const
|
|
||||||
{
|
|
||||||
return sizeof(*this) +
|
|
||||||
sizeof(dtNode)*m_maxNodes +
|
|
||||||
sizeof(dtNodeIndex)*m_maxNodes +
|
|
||||||
sizeof(dtNodeIndex)*m_hashSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int getMaxNodes() const { return m_maxNodes; }
|
|
||||||
|
|
||||||
inline int getHashSize() const { return m_hashSize; }
|
|
||||||
inline dtNodeIndex getFirst(int bucket) const { return m_first[bucket]; }
|
|
||||||
inline dtNodeIndex getNext(int i) const { return m_next[i]; }
|
|
||||||
inline int getNodeCount() const { return m_nodeCount; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Explicitly disabled copy constructor and copy assignment operator.
|
|
||||||
dtNodePool(const dtNodePool&);
|
|
||||||
dtNodePool& operator=(const dtNodePool&);
|
|
||||||
|
|
||||||
dtNode* m_nodes;
|
|
||||||
dtNodeIndex* m_first;
|
|
||||||
dtNodeIndex* m_next;
|
|
||||||
const int m_maxNodes;
|
|
||||||
const int m_hashSize;
|
|
||||||
int m_nodeCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
class dtNodeQueue
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dtNodeQueue(int n);
|
|
||||||
~dtNodeQueue();
|
|
||||||
|
|
||||||
inline void clear() { m_size = 0; }
|
|
||||||
|
|
||||||
inline dtNode* top() { return m_heap[0]; }
|
|
||||||
|
|
||||||
inline dtNode* pop()
|
|
||||||
{
|
|
||||||
dtNode* result = m_heap[0];
|
|
||||||
m_size--;
|
|
||||||
trickleDown(0, m_heap[m_size]);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void push(dtNode* node)
|
|
||||||
{
|
|
||||||
m_size++;
|
|
||||||
bubbleUp(m_size-1, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void modify(dtNode* node)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < m_size; ++i)
|
|
||||||
{
|
|
||||||
if (m_heap[i] == node)
|
|
||||||
{
|
|
||||||
bubbleUp(i, node);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool empty() const { return m_size == 0; }
|
|
||||||
|
|
||||||
inline int getMemUsed() const
|
|
||||||
{
|
|
||||||
return sizeof(*this) +
|
|
||||||
sizeof(dtNode*) * (m_capacity + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int getCapacity() const { return m_capacity; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Explicitly disabled copy constructor and copy assignment operator.
|
|
||||||
dtNodeQueue(const dtNodeQueue&);
|
|
||||||
dtNodeQueue& operator=(const dtNodeQueue&);
|
|
||||||
|
|
||||||
void bubbleUp(int i, dtNode* node);
|
|
||||||
void trickleDown(int i, dtNode* node);
|
|
||||||
|
|
||||||
dtNode** m_heap;
|
|
||||||
const int m_capacity;
|
|
||||||
int m_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // DETOURNODE_H
|
|
|
@ -1,65 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURSTATUS_H
|
|
||||||
#define DETOURSTATUS_H
|
|
||||||
|
|
||||||
typedef unsigned int dtStatus;
|
|
||||||
|
|
||||||
// High level status.
|
|
||||||
static const unsigned int DT_FAILURE = 1u << 31; // Operation failed.
|
|
||||||
static const unsigned int DT_SUCCESS = 1u << 30; // Operation succeed.
|
|
||||||
static const unsigned int DT_IN_PROGRESS = 1u << 29; // Operation still in progress.
|
|
||||||
|
|
||||||
// Detail information for status.
|
|
||||||
static const unsigned int DT_STATUS_DETAIL_MASK = 0x0ffffff;
|
|
||||||
static const unsigned int DT_WRONG_MAGIC = 1 << 0; // Input data is not recognized.
|
|
||||||
static const unsigned int DT_WRONG_VERSION = 1 << 1; // Input data is in wrong version.
|
|
||||||
static const unsigned int DT_OUT_OF_MEMORY = 1 << 2; // Operation ran out of memory.
|
|
||||||
static const unsigned int DT_INVALID_PARAM = 1 << 3; // An input parameter was invalid.
|
|
||||||
static const unsigned int DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the query was too small to store all results.
|
|
||||||
static const unsigned int DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search.
|
|
||||||
static const unsigned int DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess.
|
|
||||||
static const unsigned int DT_ALREADY_OCCUPIED = 1 << 7; // A tile has already been assigned to the given x,y coordinate
|
|
||||||
|
|
||||||
|
|
||||||
// Returns true of status is success.
|
|
||||||
inline bool dtStatusSucceed(dtStatus status)
|
|
||||||
{
|
|
||||||
return (status & DT_SUCCESS) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true of status is failure.
|
|
||||||
inline bool dtStatusFailed(dtStatus status)
|
|
||||||
{
|
|
||||||
return (status & DT_FAILURE) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true of status is in progress.
|
|
||||||
inline bool dtStatusInProgress(dtStatus status)
|
|
||||||
{
|
|
||||||
return (status & DT_IN_PROGRESS) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if specific detail is set.
|
|
||||||
inline bool dtStatusDetail(dtStatus status, unsigned int detail)
|
|
||||||
{
|
|
||||||
return (status & detail) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // DETOURSTATUS_H
|
|
|
@ -1,50 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "DetourAlloc.h"
|
|
||||||
|
|
||||||
static void *dtAllocDefault(size_t size, dtAllocHint)
|
|
||||||
{
|
|
||||||
return malloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dtFreeDefault(void *ptr)
|
|
||||||
{
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static dtAllocFunc* sAllocFunc = dtAllocDefault;
|
|
||||||
static dtFreeFunc* sFreeFunc = dtFreeDefault;
|
|
||||||
|
|
||||||
void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc)
|
|
||||||
{
|
|
||||||
sAllocFunc = allocFunc ? allocFunc : dtAllocDefault;
|
|
||||||
sFreeFunc = freeFunc ? freeFunc : dtFreeDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* dtAlloc(size_t size, dtAllocHint hint)
|
|
||||||
{
|
|
||||||
return sAllocFunc(size, hint);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtFree(void* ptr)
|
|
||||||
{
|
|
||||||
if (ptr)
|
|
||||||
sFreeFunc(ptr);
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "DetourAssert.h"
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
|
|
||||||
static dtAssertFailFunc* sAssertFailFunc = 0;
|
|
||||||
|
|
||||||
void dtAssertFailSetCustom(dtAssertFailFunc *assertFailFunc)
|
|
||||||
{
|
|
||||||
sAssertFailFunc = assertFailFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
dtAssertFailFunc* dtAssertFailGetCustom()
|
|
||||||
{
|
|
||||||
return sAssertFailFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,387 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "DetourCommon.h"
|
|
||||||
#include "DetourMath.h"
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void dtClosestPtPointTriangle(float* closest, const float* p,
|
|
||||||
const float* a, const float* b, const float* c)
|
|
||||||
{
|
|
||||||
// Check if P in vertex region outside A
|
|
||||||
float ab[3], ac[3], ap[3];
|
|
||||||
dtVsub(ab, b, a);
|
|
||||||
dtVsub(ac, c, a);
|
|
||||||
dtVsub(ap, p, a);
|
|
||||||
float d1 = dtVdot(ab, ap);
|
|
||||||
float d2 = dtVdot(ac, ap);
|
|
||||||
if (d1 <= 0.0f && d2 <= 0.0f)
|
|
||||||
{
|
|
||||||
// barycentric coordinates (1,0,0)
|
|
||||||
dtVcopy(closest, a);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if P in vertex region outside B
|
|
||||||
float bp[3];
|
|
||||||
dtVsub(bp, p, b);
|
|
||||||
float d3 = dtVdot(ab, bp);
|
|
||||||
float d4 = dtVdot(ac, bp);
|
|
||||||
if (d3 >= 0.0f && d4 <= d3)
|
|
||||||
{
|
|
||||||
// barycentric coordinates (0,1,0)
|
|
||||||
dtVcopy(closest, b);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if P in edge region of AB, if so return projection of P onto AB
|
|
||||||
float vc = d1*d4 - d3*d2;
|
|
||||||
if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f)
|
|
||||||
{
|
|
||||||
// barycentric coordinates (1-v,v,0)
|
|
||||||
float v = d1 / (d1 - d3);
|
|
||||||
closest[0] = a[0] + v * ab[0];
|
|
||||||
closest[1] = a[1] + v * ab[1];
|
|
||||||
closest[2] = a[2] + v * ab[2];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if P in vertex region outside C
|
|
||||||
float cp[3];
|
|
||||||
dtVsub(cp, p, c);
|
|
||||||
float d5 = dtVdot(ab, cp);
|
|
||||||
float d6 = dtVdot(ac, cp);
|
|
||||||
if (d6 >= 0.0f && d5 <= d6)
|
|
||||||
{
|
|
||||||
// barycentric coordinates (0,0,1)
|
|
||||||
dtVcopy(closest, c);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if P in edge region of AC, if so return projection of P onto AC
|
|
||||||
float vb = d5*d2 - d1*d6;
|
|
||||||
if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f)
|
|
||||||
{
|
|
||||||
// barycentric coordinates (1-w,0,w)
|
|
||||||
float w = d2 / (d2 - d6);
|
|
||||||
closest[0] = a[0] + w * ac[0];
|
|
||||||
closest[1] = a[1] + w * ac[1];
|
|
||||||
closest[2] = a[2] + w * ac[2];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if P in edge region of BC, if so return projection of P onto BC
|
|
||||||
float va = d3*d6 - d5*d4;
|
|
||||||
if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f)
|
|
||||||
{
|
|
||||||
// barycentric coordinates (0,1-w,w)
|
|
||||||
float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
|
|
||||||
closest[0] = b[0] + w * (c[0] - b[0]);
|
|
||||||
closest[1] = b[1] + w * (c[1] - b[1]);
|
|
||||||
closest[2] = b[2] + w * (c[2] - b[2]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// P inside face region. Compute Q through its barycentric coordinates (u,v,w)
|
|
||||||
float denom = 1.0f / (va + vb + vc);
|
|
||||||
float v = vb * denom;
|
|
||||||
float w = vc * denom;
|
|
||||||
closest[0] = a[0] + ab[0] * v + ac[0] * w;
|
|
||||||
closest[1] = a[1] + ab[1] * v + ac[1] * w;
|
|
||||||
closest[2] = a[2] + ab[2] * v + ac[2] * w;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
|
|
||||||
const float* verts, int nverts,
|
|
||||||
float& tmin, float& tmax,
|
|
||||||
int& segMin, int& segMax)
|
|
||||||
{
|
|
||||||
static const float EPS = 0.00000001f;
|
|
||||||
|
|
||||||
tmin = 0;
|
|
||||||
tmax = 1;
|
|
||||||
segMin = -1;
|
|
||||||
segMax = -1;
|
|
||||||
|
|
||||||
float dir[3];
|
|
||||||
dtVsub(dir, p1, p0);
|
|
||||||
|
|
||||||
for (int i = 0, j = nverts-1; i < nverts; j=i++)
|
|
||||||
{
|
|
||||||
float edge[3], diff[3];
|
|
||||||
dtVsub(edge, &verts[i*3], &verts[j*3]);
|
|
||||||
dtVsub(diff, p0, &verts[j*3]);
|
|
||||||
const float n = dtVperp2D(edge, diff);
|
|
||||||
const float d = dtVperp2D(dir, edge);
|
|
||||||
if (fabsf(d) < EPS)
|
|
||||||
{
|
|
||||||
// S is nearly parallel to this edge
|
|
||||||
if (n < 0)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const float t = n / d;
|
|
||||||
if (d < 0)
|
|
||||||
{
|
|
||||||
// segment S is entering across this edge
|
|
||||||
if (t > tmin)
|
|
||||||
{
|
|
||||||
tmin = t;
|
|
||||||
segMin = j;
|
|
||||||
// S enters after leaving polygon
|
|
||||||
if (tmin > tmax)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// segment S is leaving across this edge
|
|
||||||
if (t < tmax)
|
|
||||||
{
|
|
||||||
tmax = t;
|
|
||||||
segMax = j;
|
|
||||||
// S leaves before entering polygon
|
|
||||||
if (tmax < tmin)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t)
|
|
||||||
{
|
|
||||||
float pqx = q[0] - p[0];
|
|
||||||
float pqz = q[2] - p[2];
|
|
||||||
float dx = pt[0] - p[0];
|
|
||||||
float dz = pt[2] - p[2];
|
|
||||||
float d = pqx*pqx + pqz*pqz;
|
|
||||||
t = pqx*dx + pqz*dz;
|
|
||||||
if (d > 0) t /= d;
|
|
||||||
if (t < 0) t = 0;
|
|
||||||
else if (t > 1) t = 1;
|
|
||||||
dx = p[0] + t*pqx - pt[0];
|
|
||||||
dz = p[2] + t*pqz - pt[2];
|
|
||||||
return dx*dx + dz*dz;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts)
|
|
||||||
{
|
|
||||||
tc[0] = 0.0f;
|
|
||||||
tc[1] = 0.0f;
|
|
||||||
tc[2] = 0.0f;
|
|
||||||
for (int j = 0; j < nidx; ++j)
|
|
||||||
{
|
|
||||||
const float* v = &verts[idx[j]*3];
|
|
||||||
tc[0] += v[0];
|
|
||||||
tc[1] += v[1];
|
|
||||||
tc[2] += v[2];
|
|
||||||
}
|
|
||||||
const float s = 1.0f / nidx;
|
|
||||||
tc[0] *= s;
|
|
||||||
tc[1] *= s;
|
|
||||||
tc[2] *= s;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h)
|
|
||||||
{
|
|
||||||
const float EPS = 1e-6f;
|
|
||||||
float v0[3], v1[3], v2[3];
|
|
||||||
|
|
||||||
dtVsub(v0, c, a);
|
|
||||||
dtVsub(v1, b, a);
|
|
||||||
dtVsub(v2, p, a);
|
|
||||||
|
|
||||||
// Compute scaled barycentric coordinates
|
|
||||||
float denom = v0[0] * v1[2] - v0[2] * v1[0];
|
|
||||||
if (fabsf(denom) < EPS)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
float u = v1[2] * v2[0] - v1[0] * v2[2];
|
|
||||||
float v = v0[0] * v2[2] - v0[2] * v2[0];
|
|
||||||
|
|
||||||
if (denom < 0) {
|
|
||||||
denom = -denom;
|
|
||||||
u = -u;
|
|
||||||
v = -v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If point lies inside the triangle, return interpolated ycoord.
|
|
||||||
if (u >= 0.0f && v >= 0.0f && (u + v) <= denom) {
|
|
||||||
h = a[1] + (v0[1] * u + v1[1] * v) / denom;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @par
|
|
||||||
///
|
|
||||||
/// All points are projected onto the xz-plane, so the y-values are ignored.
|
|
||||||
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts)
|
|
||||||
{
|
|
||||||
// TODO: Replace pnpoly with triArea2D tests?
|
|
||||||
int i, j;
|
|
||||||
bool c = false;
|
|
||||||
for (i = 0, j = nverts-1; i < nverts; j = i++)
|
|
||||||
{
|
|
||||||
const float* vi = &verts[i*3];
|
|
||||||
const float* vj = &verts[j*3];
|
|
||||||
if (((vi[2] > pt[2]) != (vj[2] > pt[2])) &&
|
|
||||||
(pt[0] < (vj[0]-vi[0]) * (pt[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) )
|
|
||||||
c = !c;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
|
|
||||||
float* ed, float* et)
|
|
||||||
{
|
|
||||||
// TODO: Replace pnpoly with triArea2D tests?
|
|
||||||
int i, j;
|
|
||||||
bool c = false;
|
|
||||||
for (i = 0, j = nverts-1; i < nverts; j = i++)
|
|
||||||
{
|
|
||||||
const float* vi = &verts[i*3];
|
|
||||||
const float* vj = &verts[j*3];
|
|
||||||
if (((vi[2] > pt[2]) != (vj[2] > pt[2])) &&
|
|
||||||
(pt[0] < (vj[0]-vi[0]) * (pt[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) )
|
|
||||||
c = !c;
|
|
||||||
ed[j] = dtDistancePtSegSqr2D(pt, vj, vi, et[j]);
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void projectPoly(const float* axis, const float* poly, const int npoly,
|
|
||||||
float& rmin, float& rmax)
|
|
||||||
{
|
|
||||||
rmin = rmax = dtVdot2D(axis, &poly[0]);
|
|
||||||
for (int i = 1; i < npoly; ++i)
|
|
||||||
{
|
|
||||||
const float d = dtVdot2D(axis, &poly[i*3]);
|
|
||||||
rmin = dtMin(rmin, d);
|
|
||||||
rmax = dtMax(rmax, d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool overlapRange(const float amin, const float amax,
|
|
||||||
const float bmin, const float bmax,
|
|
||||||
const float eps)
|
|
||||||
{
|
|
||||||
return ((amin+eps) > bmax || (amax-eps) < bmin) ? false : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @par
|
|
||||||
///
|
|
||||||
/// All vertices are projected onto the xz-plane, so the y-values are ignored.
|
|
||||||
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
|
||||||
const float* polyb, const int npolyb)
|
|
||||||
{
|
|
||||||
const float eps = 1e-4f;
|
|
||||||
|
|
||||||
for (int i = 0, j = npolya-1; i < npolya; j=i++)
|
|
||||||
{
|
|
||||||
const float* va = &polya[j*3];
|
|
||||||
const float* vb = &polya[i*3];
|
|
||||||
const float n[3] = { vb[2]-va[2], 0, -(vb[0]-va[0]) };
|
|
||||||
float amin,amax,bmin,bmax;
|
|
||||||
projectPoly(n, polya, npolya, amin,amax);
|
|
||||||
projectPoly(n, polyb, npolyb, bmin,bmax);
|
|
||||||
if (!overlapRange(amin,amax, bmin,bmax, eps))
|
|
||||||
{
|
|
||||||
// Found separating axis
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0, j = npolyb-1; i < npolyb; j=i++)
|
|
||||||
{
|
|
||||||
const float* va = &polyb[j*3];
|
|
||||||
const float* vb = &polyb[i*3];
|
|
||||||
const float n[3] = { vb[2]-va[2], 0, -(vb[0]-va[0]) };
|
|
||||||
float amin,amax,bmin,bmax;
|
|
||||||
projectPoly(n, polya, npolya, amin,amax);
|
|
||||||
projectPoly(n, polyb, npolyb, bmin,bmax);
|
|
||||||
if (!overlapRange(amin,amax, bmin,bmax, eps))
|
|
||||||
{
|
|
||||||
// Found separating axis
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a random point in a convex polygon.
|
|
||||||
// Adapted from Graphics Gems article.
|
|
||||||
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
|
||||||
const float s, const float t, float* out)
|
|
||||||
{
|
|
||||||
// Calc triangle araes
|
|
||||||
float areasum = 0.0f;
|
|
||||||
for (int i = 2; i < npts; i++) {
|
|
||||||
areas[i] = dtTriArea2D(&pts[0], &pts[(i-1)*3], &pts[i*3]);
|
|
||||||
areasum += dtMax(0.001f, areas[i]);
|
|
||||||
}
|
|
||||||
// Find sub triangle weighted by area.
|
|
||||||
const float thr = s*areasum;
|
|
||||||
float acc = 0.0f;
|
|
||||||
float u = 1.0f;
|
|
||||||
int tri = npts - 1;
|
|
||||||
for (int i = 2; i < npts; i++) {
|
|
||||||
const float dacc = areas[i];
|
|
||||||
if (thr >= acc && thr < (acc+dacc))
|
|
||||||
{
|
|
||||||
u = (thr - acc) / dacc;
|
|
||||||
tri = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
acc += dacc;
|
|
||||||
}
|
|
||||||
|
|
||||||
float v = dtMathSqrtf(t);
|
|
||||||
|
|
||||||
const float a = 1 - v;
|
|
||||||
const float b = (1 - u) * v;
|
|
||||||
const float c = u * v;
|
|
||||||
const float* pa = &pts[0];
|
|
||||||
const float* pb = &pts[(tri-1)*3];
|
|
||||||
const float* pc = &pts[tri*3];
|
|
||||||
|
|
||||||
out[0] = a*pa[0] + b*pb[0] + c*pc[0];
|
|
||||||
out[1] = a*pa[1] + b*pb[1] + c*pc[1];
|
|
||||||
out[2] = a*pa[2] + b*pb[2] + c*pc[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float vperpXZ(const float* a, const float* b) { return a[0]*b[2] - a[2]*b[0]; }
|
|
||||||
|
|
||||||
bool dtIntersectSegSeg2D(const float* ap, const float* aq,
|
|
||||||
const float* bp, const float* bq,
|
|
||||||
float& s, float& t)
|
|
||||||
{
|
|
||||||
float u[3], v[3], w[3];
|
|
||||||
dtVsub(u,aq,ap);
|
|
||||||
dtVsub(v,bq,bp);
|
|
||||||
dtVsub(w,ap,bp);
|
|
||||||
float d = vperpXZ(u,v);
|
|
||||||
if (fabsf(d) < 1e-6f) return false;
|
|
||||||
s = vperpXZ(v,w) / d;
|
|
||||||
t = vperpXZ(u,w) / d;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue