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
f4e36f4be5
238 changed files with 5472 additions and 1965 deletions
317
.gitlab-ci.yml
317
.gitlab-ci.yml
|
@ -16,6 +16,8 @@ stages:
|
||||||
- apt-cache/
|
- apt-cache/
|
||||||
- ccache/
|
- ccache/
|
||||||
stage: build
|
stage: build
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PIPELINE_SOURCE != "schedule"'
|
||||||
script:
|
script:
|
||||||
- export CCACHE_BASEDIR="`pwd`"
|
- export CCACHE_BASEDIR="`pwd`"
|
||||||
- export CCACHE_DIR="`pwd`/ccache" && mkdir -pv "$CCACHE_DIR"
|
- export CCACHE_DIR="`pwd`/ccache" && mkdir -pv "$CCACHE_DIR"
|
||||||
|
@ -30,6 +32,30 @@ stages:
|
||||||
paths:
|
paths:
|
||||||
- build/install/
|
- build/install/
|
||||||
|
|
||||||
|
Coverity:
|
||||||
|
extends: .Debian_Image
|
||||||
|
stage: build
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||||
|
before_script:
|
||||||
|
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic coverity
|
||||||
|
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64 --form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
|
||||||
|
- tar xfz /tmp/cov-analysis-linux64.tgz
|
||||||
|
script:
|
||||||
|
- CI/before_script.linux.sh
|
||||||
|
# Add more than just `openmw` once we can build everything under 3h
|
||||||
|
- cov-analysis-linux64-*/bin/cov-build --dir cov-int cmake --build build -- -j $(nproc) openmw
|
||||||
|
after_script:
|
||||||
|
- tar cfz cov-int.tar.gz cov-int
|
||||||
|
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
||||||
|
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
|
||||||
|
--form file=@cov-int.tar.gz --form version="`git describe --tags`"
|
||||||
|
--form description="`git describe --tags` / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
|
||||||
|
variables:
|
||||||
|
CC: gcc
|
||||||
|
CXX: g++
|
||||||
|
timeout: 8h
|
||||||
|
|
||||||
Debian_GCC:
|
Debian_GCC:
|
||||||
extends: .Debian
|
extends: .Debian
|
||||||
cache:
|
cache:
|
||||||
|
@ -93,125 +119,152 @@ Debian_Clang_tests:
|
||||||
CCACHE_SIZE: 1G
|
CCACHE_SIZE: 1G
|
||||||
BUILD_TESTS_ONLY: 1
|
BUILD_TESTS_ONLY: 1
|
||||||
|
|
||||||
MacOS:
|
.MacOS:
|
||||||
|
image: macos-11-xcode-12
|
||||||
tags:
|
tags:
|
||||||
- macos
|
- shared-macos-amd64
|
||||||
stage: build
|
stage: build
|
||||||
only:
|
only:
|
||||||
variables:
|
variables:
|
||||||
- $CI_PROJECT_ID == "7107382"
|
- $CI_PROJECT_ID == "7107382"
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- ccache/
|
||||||
script:
|
script:
|
||||||
- rm -fr build/* # remove anything in the build directory
|
- rm -fr build # remove the build directory
|
||||||
- CI/before_install.osx.sh
|
- CI/before_install.osx.sh
|
||||||
|
- export CCACHE_BASEDIR="$(pwd)"
|
||||||
|
- export CCACHE_DIR="$(pwd)/ccache"
|
||||||
|
- mkdir -pv "${CCACHE_DIR}"
|
||||||
|
- ccache -z -M "${CCACHE_SIZE}"
|
||||||
- CI/before_script.osx.sh
|
- CI/before_script.osx.sh
|
||||||
- cd build; make -j2 package
|
- cd build; make -j $(sysctl -n hw.logicalcpu) package
|
||||||
- for dmg in *.dmg; do mv "$dmg" "${dmg%.dmg}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.dmg"; done
|
- for dmg in *.dmg; do mv "$dmg" "${dmg%.dmg}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.dmg"; done
|
||||||
|
- ccache -s
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- build/OpenMW-*.dmg
|
- build/OpenMW-*.dmg
|
||||||
- "build/**/*.log"
|
- "build/**/*.log"
|
||||||
|
|
||||||
|
macOS11_Xcode12:
|
||||||
|
extends: .MacOS
|
||||||
|
image: macos-11-xcode-12
|
||||||
|
cache:
|
||||||
|
key: macOS11_Xcode12.v1
|
||||||
|
variables:
|
||||||
|
CCACHE_SIZE: 3G
|
||||||
|
|
||||||
|
macOS10.15_Xcode11:
|
||||||
|
extends: .MacOS
|
||||||
|
image: macos-10.15-xcode-11
|
||||||
|
allow_failure: true
|
||||||
|
cache:
|
||||||
|
key: macOS10.15_Xcode11.v1
|
||||||
|
variables:
|
||||||
|
CCACHE_SIZE: 3G
|
||||||
|
|
||||||
variables: &engine-targets
|
variables: &engine-targets
|
||||||
targets: "openmw_vr,openmw-essimporter,openmw-iniimporter,openmw-launcher,openmw-wizard"
|
targets: "openmw,openmw-essimporter,openmw-iniimporter,openmw-launcher,openmw-wizard"
|
||||||
package: "Engine"
|
package: "Engine"
|
||||||
|
|
||||||
variables: &cs-targets
|
variables: &cs-targets
|
||||||
targets: "openmw-cs,bsatool,esmtool,niftest"
|
targets: "openmw-cs,bsatool,esmtool,niftest"
|
||||||
package: "CS"
|
package: "CS"
|
||||||
|
|
||||||
#.Windows_Ninja_Base:
|
.Windows_Ninja_Base:
|
||||||
# tags:
|
tags:
|
||||||
# - windows
|
- windows
|
||||||
# before_script:
|
before_script:
|
||||||
# - Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
||||||
# - choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
|
- choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
|
||||||
# - choco install git --force --params "/GitAndUnixToolsOnPath" -y
|
- choco install git --force --params "/GitAndUnixToolsOnPath" -y
|
||||||
# - choco install 7zip -y
|
- choco install 7zip -y
|
||||||
# - choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y
|
- choco install cmake.install --installargs 'ADD_CMAKE_TO_PATH=System' -y
|
||||||
# - choco install vswhere -y
|
- choco install vswhere -y
|
||||||
# - choco install ninja -y
|
- choco install ninja -y
|
||||||
# - choco install python -y
|
- choco install python -y
|
||||||
# - refreshenv
|
- refreshenv
|
||||||
# stage: build
|
stage: build
|
||||||
# script:
|
rules:
|
||||||
# - $time = (Get-Date -Format "HH:mm:ss")
|
- if: '$CI_PIPELINE_SOURCE != "schedule"'
|
||||||
# - echo ${time}
|
script:
|
||||||
# - echo "started by ${GITLAB_USER_NAME}"
|
- $time = (Get-Date -Format "HH:mm:ss")
|
||||||
# - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -N
|
- echo ${time}
|
||||||
# - cd MSVC2019_64_Ninja
|
- echo "started by ${GITLAB_USER_NAME}"
|
||||||
# - .\ActivateMSVC.ps1
|
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -N
|
||||||
# - cmake --build . --config $config --target ($targets.Split(','))
|
- cd MSVC2019_64_Ninja
|
||||||
# - cd $config
|
- .\ActivateMSVC.ps1
|
||||||
# - 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
|
- cmake --build . --config $config --target ($targets.Split(','))
|
||||||
# - |
|
- cd $config
|
||||||
# if (Get-ChildItem -Recurse *.pdb) {
|
- 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
|
||||||
# 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
|
if (Get-ChildItem -Recurse *.pdb) {
|
||||||
# }
|
7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt
|
||||||
# - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*'
|
Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||||
# after_script:
|
}
|
||||||
# - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*'
|
||||||
# cache:
|
after_script:
|
||||||
# key: ninja-v2
|
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
||||||
# paths:
|
cache:
|
||||||
# - deps
|
key: ninja-v2
|
||||||
# - MSVC2019_64_Ninja/deps/Qt
|
paths:
|
||||||
# artifacts:
|
- deps
|
||||||
# when: always
|
- MSVC2019_64_Ninja/deps/Qt
|
||||||
# paths:
|
artifacts:
|
||||||
# - "*.zip"
|
when: always
|
||||||
# - "*.log"
|
paths:
|
||||||
# - MSVC2019_64_Ninja/*.log
|
- "*.zip"
|
||||||
# - MSVC2019_64_Ninja/*/*.log
|
- "*.log"
|
||||||
# - MSVC2019_64_Ninja/*/*/*.log
|
- MSVC2019_64_Ninja/*.log
|
||||||
# - MSVC2019_64_Ninja/*/*/*/*.log
|
- MSVC2019_64_Ninja/*/*.log
|
||||||
# - MSVC2019_64_Ninja/*/*/*/*/*.log
|
- MSVC2019_64_Ninja/*/*/*.log
|
||||||
# - MSVC2019_64_Ninja/*/*/*/*/*/*.log
|
- MSVC2019_64_Ninja/*/*/*/*.log
|
||||||
# - 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:
|
- .Windows_Ninja_Base
|
||||||
# - .Windows_Ninja_Base
|
variables:
|
||||||
# variables:
|
<<: *engine-targets
|
||||||
# <<: *engine-targets
|
config: "Release"
|
||||||
# config: "Release"
|
|
||||||
#
|
Windows_Ninja_Engine_Debug:
|
||||||
#Windows_Ninja_Engine_Debug:
|
extends:
|
||||||
# extends:
|
- .Windows_Ninja_Base
|
||||||
# - .Windows_Ninja_Base
|
variables:
|
||||||
# variables:
|
<<: *engine-targets
|
||||||
# <<: *engine-targets
|
config: "Debug"
|
||||||
# config: "Debug"
|
|
||||||
#
|
Windows_Ninja_Engine_RelWithDebInfo:
|
||||||
#Windows_Ninja_Engine_RelWithDebInfo:
|
extends:
|
||||||
# extends:
|
- .Windows_Ninja_Base
|
||||||
# - .Windows_Ninja_Base
|
variables:
|
||||||
# variables:
|
<<: *engine-targets
|
||||||
# <<: *engine-targets
|
config: "RelWithDebInfo"
|
||||||
# config: "RelWithDebInfo"
|
|
||||||
#
|
Windows_Ninja_CS_Release:
|
||||||
#Windows_Ninja_CS_Release:
|
extends:
|
||||||
# extends:
|
- .Windows_Ninja_Base
|
||||||
# - .Windows_Ninja_Base
|
variables:
|
||||||
# variables:
|
<<: *cs-targets
|
||||||
# <<: *cs-targets
|
config: "Release"
|
||||||
# config: "Release"
|
|
||||||
#
|
Windows_Ninja_CS_Debug:
|
||||||
#Windows_Ninja_CS_Debug:
|
extends:
|
||||||
# extends:
|
- .Windows_Ninja_Base
|
||||||
# - .Windows_Ninja_Base
|
variables:
|
||||||
# variables:
|
<<: *cs-targets
|
||||||
# <<: *cs-targets
|
config: "Debug"
|
||||||
# config: "Debug"
|
|
||||||
#
|
Windows_Ninja_CS_RelWithDebInfo:
|
||||||
#Windows_Ninja_CS_RelWithDebInfo:
|
extends:
|
||||||
# extends:
|
- .Windows_Ninja_Base
|
||||||
# - .Windows_Ninja_Base
|
variables:
|
||||||
# variables:
|
<<: *cs-targets
|
||||||
# <<: *cs-targets
|
config: "RelWithDebInfo"
|
||||||
# config: "RelWithDebInfo"
|
|
||||||
|
|
||||||
.Windows_MSBuild_Base:
|
.Windows_MSBuild_Base:
|
||||||
tags:
|
tags:
|
||||||
|
@ -226,6 +279,8 @@ variables: &cs-targets
|
||||||
- choco install python -y
|
- choco install python -y
|
||||||
- refreshenv
|
- refreshenv
|
||||||
stage: build
|
stage: build
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PIPELINE_SOURCE != "schedule"'
|
||||||
script:
|
script:
|
||||||
- $time = (Get-Date -Format "HH:mm:ss")
|
- $time = (Get-Date -Format "HH:mm:ss")
|
||||||
- echo ${time}
|
- echo ${time}
|
||||||
|
@ -304,37 +359,37 @@ Windows_MSBuild_CS_RelWithDebInfo:
|
||||||
<<: *cs-targets
|
<<: *cs-targets
|
||||||
config: "RelWithDebInfo"
|
config: "RelWithDebInfo"
|
||||||
|
|
||||||
#Debian_AndroidNDK_arm64-v8a:
|
Debian_AndroidNDK_arm64-v8a:
|
||||||
# tags:
|
tags:
|
||||||
# - linux
|
- linux
|
||||||
# image: debian:bullseye
|
image: debian:bullseye
|
||||||
# variables:
|
variables:
|
||||||
# CCACHE_SIZE: 3G
|
CCACHE_SIZE: 3G
|
||||||
# cache:
|
cache:
|
||||||
# key: Debian_AndroidNDK_arm64-v8a.v3
|
key: Debian_AndroidNDK_arm64-v8a.v3
|
||||||
# paths:
|
paths:
|
||||||
# - apt-cache/
|
- apt-cache/
|
||||||
# - ccache/
|
- ccache/
|
||||||
# - build/extern/fetched/
|
- 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 -q -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`"
|
||||||
# - export CCACHE_DIR="`pwd`/ccache" && mkdir -pv "$CCACHE_DIR"
|
- export CCACHE_DIR="`pwd`/ccache" && mkdir -pv "$CCACHE_DIR"
|
||||||
# - ccache -z -M "${CCACHE_SIZE}"
|
- ccache -z -M "${CCACHE_SIZE}"
|
||||||
# - CI/before_install.android.sh
|
- CI/before_install.android.sh
|
||||||
# - CI/before_script.android.sh
|
- CI/before_script.android.sh
|
||||||
# - cd build
|
- cd build
|
||||||
# - cmake --build . -- -j $(nproc)
|
- cmake --build . -- -j $(nproc)
|
||||||
# - cmake --install .
|
- cmake --install .
|
||||||
# - ccache -s
|
- ccache -s
|
||||||
# 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.
|
# 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
|
timeout: 1h30m
|
||||||
|
|
12
.travis.yml
12
.travis.yml
|
@ -10,7 +10,7 @@ addons:
|
||||||
- sourceline: 'ppa:openmw/openmw'
|
- sourceline: 'ppa:openmw/openmw'
|
||||||
packages: [
|
packages: [
|
||||||
# Dev
|
# Dev
|
||||||
build-essential, cmake, clang-tools, ccache,
|
build-essential, cmake, clang-tools-9, ccache,
|
||||||
# Boost
|
# Boost
|
||||||
libboost-filesystem-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-system-dev,
|
libboost-filesystem-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-system-dev,
|
||||||
# FFmpeg
|
# FFmpeg
|
||||||
|
@ -22,9 +22,9 @@ addons:
|
||||||
]
|
]
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- name: OpenMW (all) on MacOS 10.15 with Xcode 11.6
|
- name: OpenMW (all) on MacOS 10.15 with Xcode 10.2
|
||||||
os: osx
|
os: osx
|
||||||
osx_image: xcode11.6
|
osx_image: xcode10.2
|
||||||
- name: OpenMW (all) on Ubuntu Focal with GCC
|
- name: OpenMW (all) on Ubuntu Focal with GCC
|
||||||
os: linux
|
os: linux
|
||||||
dist: focal
|
dist: focal
|
||||||
|
@ -37,8 +37,8 @@ matrix:
|
||||||
os: linux
|
os: linux
|
||||||
dist: focal
|
dist: focal
|
||||||
env:
|
env:
|
||||||
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
- MATRIX_EVAL="CC=clang-9 && CXX=clang++-9"
|
||||||
- ANALYZE="scan-build --force-analyze-debug-code --use-cc clang --use-c++ clang++"
|
- ANALYZE="scan-build-9 --force-analyze-debug-code --use-cc clang-9 --use-c++ clang++-9"
|
||||||
compiler: clang
|
compiler: clang
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
|
@ -66,11 +66,13 @@ deploy:
|
||||||
repo: OpenMW/openmw
|
repo: OpenMW/openmw
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
|
if: repository_slug = OpenMW/openmw AND branch = master
|
||||||
recipients:
|
recipients:
|
||||||
- corrmage+travis-ci@gmail.com
|
- corrmage+travis-ci@gmail.com
|
||||||
on_success: change
|
on_success: change
|
||||||
on_failure: always
|
on_failure: always
|
||||||
irc:
|
irc:
|
||||||
|
if: repository_slug = OpenMW/openmw AND branch = master
|
||||||
channels:
|
channels:
|
||||||
- "chat.freenode.net#openmw"
|
- "chat.freenode.net#openmw"
|
||||||
on_success: change
|
on_success: change
|
||||||
|
|
12
AUTHORS.md
12
AUTHORS.md
|
@ -4,7 +4,7 @@ Contributors
|
||||||
The OpenMW project was started in 2008 by Nicolay Korslund.
|
The OpenMW project was started in 2008 by Nicolay Korslund.
|
||||||
In the course of years many people have contributed to the project.
|
In the course of years many people have contributed to the project.
|
||||||
|
|
||||||
If you feel your name is missing from this list, please notify a developer.
|
If you feel your name is missing from this list, please add it to `AUTHORS.md`.
|
||||||
|
|
||||||
|
|
||||||
Programmers
|
Programmers
|
||||||
|
@ -24,7 +24,7 @@ Programmers
|
||||||
Alex McKibben
|
Alex McKibben
|
||||||
alexanderkjall
|
alexanderkjall
|
||||||
Alexander Nadeau (wareya)
|
Alexander Nadeau (wareya)
|
||||||
Alexander Olofsson (Ace)
|
Alexander Olofsson (Ananace)
|
||||||
Alex Rice
|
Alex Rice
|
||||||
Alex S (docwest)
|
Alex S (docwest)
|
||||||
Allofich
|
Allofich
|
||||||
|
@ -49,6 +49,7 @@ Programmers
|
||||||
Cédric Mocquillon
|
Cédric Mocquillon
|
||||||
Chris Boyce (slothlife)
|
Chris Boyce (slothlife)
|
||||||
Chris Robinson (KittyCat)
|
Chris Robinson (KittyCat)
|
||||||
|
Cody Glassman (Wazabear)
|
||||||
Coleman Smith (olcoal)
|
Coleman Smith (olcoal)
|
||||||
Cory F. Cohen (cfcohen)
|
Cory F. Cohen (cfcohen)
|
||||||
Cris Mihalache (Mirceam)
|
Cris Mihalache (Mirceam)
|
||||||
|
@ -89,6 +90,7 @@ Programmers
|
||||||
Internecine
|
Internecine
|
||||||
Jackerty
|
Jackerty
|
||||||
Jacob Essex (Yacoby)
|
Jacob Essex (Yacoby)
|
||||||
|
Jacob Turnbull (Tankinfrank)
|
||||||
Jake Westrip (16bitint)
|
Jake Westrip (16bitint)
|
||||||
James Carty (MrTopCat)
|
James Carty (MrTopCat)
|
||||||
James Moore (moore.work)
|
James Moore (moore.work)
|
||||||
|
@ -150,6 +152,7 @@ Programmers
|
||||||
Nathan Jeffords (blunted2night)
|
Nathan Jeffords (blunted2night)
|
||||||
NeveHanter
|
NeveHanter
|
||||||
Nialsy
|
Nialsy
|
||||||
|
Nick Crawford (nighthawk469)
|
||||||
Nikolay Kasyanov (corristo)
|
Nikolay Kasyanov (corristo)
|
||||||
nobrakal
|
nobrakal
|
||||||
Nolan Poe (nopoe)
|
Nolan Poe (nopoe)
|
||||||
|
@ -184,6 +187,7 @@ Programmers
|
||||||
sergoz
|
sergoz
|
||||||
ShadowRadiance
|
ShadowRadiance
|
||||||
Siimacore
|
Siimacore
|
||||||
|
Simon Meulenbeek (simonmb)
|
||||||
sir_herrbatka
|
sir_herrbatka
|
||||||
smbas
|
smbas
|
||||||
Sophie Kirschner (pineapplemachine)
|
Sophie Kirschner (pineapplemachine)
|
||||||
|
@ -197,6 +201,7 @@ Programmers
|
||||||
Sylvain Thesnieres (Garvek)
|
Sylvain Thesnieres (Garvek)
|
||||||
t6
|
t6
|
||||||
terrorfisch
|
terrorfisch
|
||||||
|
Tess (tescoShoppah)
|
||||||
thegriglat
|
thegriglat
|
||||||
Thomas Luppi (Digmaster)
|
Thomas Luppi (Digmaster)
|
||||||
tlmullis
|
tlmullis
|
||||||
|
@ -235,7 +240,8 @@ Documentation
|
||||||
Packagers
|
Packagers
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Alexander Olofsson (Ace) - Windows
|
Alexander Olofsson (Ananace) - Windows and Flatpak
|
||||||
|
Alexey Sokolov (DarthGandalf) - Gentoo Linux
|
||||||
Bret Curtis (psi29a) - Debian and Ubuntu Linux
|
Bret Curtis (psi29a) - Debian and Ubuntu Linux
|
||||||
Edmondo Tommasina (edmondo) - Gentoo Linux
|
Edmondo Tommasina (edmondo) - Gentoo Linux
|
||||||
Julian Ospald (hasufell) - Gentoo Linux
|
Julian Ospald (hasufell) - Gentoo Linux
|
||||||
|
|
|
@ -115,6 +115,9 @@
|
||||||
Bug #5906: Sunglare doesn't work with Mesa drivers and AMD GPUs
|
Bug #5906: Sunglare doesn't work with Mesa drivers and AMD GPUs
|
||||||
Bug #5912: ImprovedBound mod doesn't work
|
Bug #5912: ImprovedBound mod doesn't work
|
||||||
Bug #5914: BM: The Swimmer can't reach destination
|
Bug #5914: BM: The Swimmer can't reach destination
|
||||||
|
Bug #5923: Clicking on empty spaces between journal entries might show random topics
|
||||||
|
Bug #5934: AddItem command doesn't accept negative values
|
||||||
|
Bug #5975: NIF controllers from sheath meshes are used
|
||||||
Feature #390: 3rd person look "over the shoulder"
|
Feature #390: 3rd person look "over the shoulder"
|
||||||
Feature #832: OpenMW-CS: Handle deleted references
|
Feature #832: OpenMW-CS: Handle deleted references
|
||||||
Feature #1536: Show more information about level on menu
|
Feature #1536: Show more information about level on menu
|
||||||
|
@ -122,8 +125,10 @@
|
||||||
Feature #2404: Levelled List can not be placed into a container
|
Feature #2404: Levelled List can not be placed into a container
|
||||||
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 #3983: Wizard: Add link to buy Morrowind
|
||||||
Feature #4894: Consider actors as obstacles for pathfinding
|
Feature #4894: Consider actors as obstacles for pathfinding
|
||||||
Feature #4899: Alpha-To-Coverage Anti-Aliasing for alpha testing
|
Feature #4899: Alpha-To-Coverage Anti-Aliasing for alpha testing
|
||||||
|
Feature #4917: Do not trigger NavMesh update when RecastMesh update should not change NavMesh
|
||||||
Feature #4977: Use the "default icon.tga" when an item's icon is not found
|
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: OpenMW-CS: Improve scene view colors
|
Feature #5199: OpenMW-CS: Improve scene view colors
|
||||||
|
@ -133,6 +138,7 @@
|
||||||
Feature #5456: Basic collada animation support
|
Feature #5456: Basic collada animation support
|
||||||
Feature #5457: Realistic diagonal movement
|
Feature #5457: Realistic diagonal movement
|
||||||
Feature #5486: Fixes trainers to choose their training skills based on their base skill points
|
Feature #5486: Fixes trainers to choose their training skills based on their base skill points
|
||||||
|
Feature #5511: Add in game option to toggle HRTF support in OpenMW
|
||||||
Feature #5519: Code Patch tab in launcher
|
Feature #5519: Code Patch tab in launcher
|
||||||
Feature #5524: Resume failed script execution after reload
|
Feature #5524: Resume failed script execution after reload
|
||||||
Feature #5545: Option to allow stealing from an unconscious NPC during combat
|
Feature #5545: Option to allow stealing from an unconscious NPC during combat
|
||||||
|
@ -147,6 +153,8 @@
|
||||||
Feature #5730: Add graphic herbalism option to the launcher and documents
|
Feature #5730: Add graphic herbalism option to the launcher and documents
|
||||||
Feature #5771: ori command should report where a mesh is loaded from and whether the x version is used.
|
Feature #5771: ori command should report where a mesh is loaded from and whether the x version is used.
|
||||||
Feature #5813: Instanced groundcover support
|
Feature #5813: Instanced groundcover support
|
||||||
|
Feature #5814: Bsatool should be able to create BSA archives, not only to extract it
|
||||||
|
Feature #5828: Support more than 8 lights
|
||||||
Feature #5910: Fall back to delta time when physics can't keep up
|
Feature #5910: Fall back to delta time when physics can't keep up
|
||||||
Task #5480: Drop Qt4 support
|
Task #5480: Drop Qt4 support
|
||||||
Task #5520: Improve cell name autocompleter implementation
|
Task #5520: Improve cell name autocompleter implementation
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#!/bin/sh -ex
|
#!/bin/sh -ex
|
||||||
|
|
||||||
# workaround python issue on travis
|
# workaround python issue on travis
|
||||||
HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall --ignore-dependencies python@3.8 || true
|
[-z "${TRAVIS}"] && HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall --ignore-dependencies python@3.8 || true
|
||||||
HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall --ignore-dependencies python@3.9 || true
|
[-z "${TRAVIS}"] && HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall --ignore-dependencies python@3.9 || true
|
||||||
HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall --ignore-dependencies qt@6 || true
|
[-z "${TRAVIS}"] && HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall --ignore-dependencies qt@6 || true
|
||||||
|
|
||||||
# Some of these tools can come from places other than brew, so check before installing
|
# Some of these tools can come from places other than brew, so check before installing
|
||||||
command -v ccache >/dev/null 2>&1 || brew install ccache
|
command -v ccache >/dev/null 2>&1 || brew install ccache
|
||||||
|
|
|
@ -16,7 +16,7 @@ cmake \
|
||||||
-D CMAKE_CXX_FLAGS="-stdlib=libc++" \
|
-D CMAKE_CXX_FLAGS="-stdlib=libc++" \
|
||||||
-D CMAKE_C_FLAGS_RELEASE="-g -O0" \
|
-D CMAKE_C_FLAGS_RELEASE="-g -O0" \
|
||||||
-D CMAKE_CXX_FLAGS_RELEASE="-g -O0" \
|
-D CMAKE_CXX_FLAGS_RELEASE="-g -O0" \
|
||||||
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.12" \
|
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.14" \
|
||||||
-D CMAKE_BUILD_TYPE=RELEASE \
|
-D CMAKE_BUILD_TYPE=RELEASE \
|
||||||
-D OPENMW_OSX_DEPLOYMENT=TRUE \
|
-D OPENMW_OSX_DEPLOYMENT=TRUE \
|
||||||
-D BUILD_OPENMW=TRUE \
|
-D BUILD_OPENMW=TRUE \
|
||||||
|
|
|
@ -29,6 +29,8 @@ declare -rA GROUPED_DEPS=(
|
||||||
# These dependencies can alternatively be built and linked statically.
|
# These dependencies can alternatively be built and linked statically.
|
||||||
[openmw-deps-dynamic]="libmygui-dev libopenscenegraph-dev"
|
[openmw-deps-dynamic]="libmygui-dev libopenscenegraph-dev"
|
||||||
|
|
||||||
|
[coverity]="curl"
|
||||||
|
|
||||||
# Pre-requisites for building MyGUI and OSG for static linking.
|
# Pre-requisites for building MyGUI and OSG for static linking.
|
||||||
#
|
#
|
||||||
# * MyGUI and OSG: libsdl2-dev liblz4-dev libfreetype6-dev
|
# * MyGUI and OSG: libsdl2-dev liblz4-dev libfreetype6-dev
|
||||||
|
|
|
@ -612,8 +612,8 @@ if (WIN32)
|
||||||
# Warnings that aren't enabled normally and don't need to be enabled
|
# Warnings that aren't enabled normally and don't need to be enabled
|
||||||
# They're unneeded and sometimes completely retarded warnings that /Wall enables
|
# They're unneeded and sometimes completely retarded warnings that /Wall enables
|
||||||
# Not going to bother commenting them as they tend to warn on every standard library file
|
# Not going to bother commenting them as they tend to warn on every standard library file
|
||||||
4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625
|
4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4582 4583 4610 4619 4623 4625
|
||||||
4626 4628 4640 4668 4710 4711 4768 4820 4826 4917 4946 5032 5039 5045
|
4626 4628 4640 4668 4710 4711 4768 4820 4826 4917 4946 5032 5039 5045 5219 5220
|
||||||
|
|
||||||
# Warnings that are thrown on standard libraries and not OpenMW
|
# Warnings that are thrown on standard libraries and not OpenMW
|
||||||
4347 # Non-template function with same name and parameter count as template function
|
4347 # Non-template function with same name and parameter count as template function
|
||||||
|
@ -635,7 +635,6 @@ if (WIN32)
|
||||||
5204 # Class has virtual functions, but its trivial destructor is not virtual
|
5204 # Class has virtual functions, but its trivial destructor is not virtual
|
||||||
|
|
||||||
# caused by MyGUI
|
# caused by MyGUI
|
||||||
4275 # non dll-interface class 'std::exception' used as base for dll-interface class 'MyGUI::Exception'
|
|
||||||
4297 # function assumed not to throw an exception but does
|
4297 # function assumed not to throw an exception but does
|
||||||
|
|
||||||
# OpenMW specific warnings
|
# OpenMW specific warnings
|
||||||
|
@ -671,6 +670,12 @@ if (WIN32)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if( "${MyGUI_VERSION}" VERSION_LESS_EQUAL "3.4.1" )
|
||||||
|
set(WARNINGS_DISABLE ${WARNINGS_DISABLE}
|
||||||
|
4275 # non dll-interface class 'MyGUI::delegates::IDelegateUnlink' used as base for dll-interface class 'MyGUI::Widget'
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
foreach(d ${WARNINGS_DISABLE})
|
foreach(d ${WARNINGS_DISABLE})
|
||||||
set(WARNINGS "${WARNINGS} /wd${d}")
|
set(WARNINGS "${WARNINGS} /wd${d}")
|
||||||
endforeach(d)
|
endforeach(d)
|
||||||
|
|
|
@ -20,6 +20,7 @@ struct Arguments
|
||||||
std::string mode;
|
std::string mode;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string extractfile;
|
std::string extractfile;
|
||||||
|
std::string addfile;
|
||||||
std::string outdir;
|
std::string outdir;
|
||||||
|
|
||||||
bool longformat;
|
bool longformat;
|
||||||
|
@ -36,6 +37,10 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
" Extract a file from the input archive.\n\n"
|
" Extract a file from the input archive.\n\n"
|
||||||
" bsatool extractall archivefile [output_directory]\n"
|
" bsatool extractall archivefile [output_directory]\n"
|
||||||
" Extract all files from the input archive.\n\n"
|
" Extract all files from the input archive.\n\n"
|
||||||
|
" bsatool add [-a] archivefile file_to_add\n"
|
||||||
|
" Add a file to the input archive.\n\n"
|
||||||
|
" bsatool create [-c] archivefile\n"
|
||||||
|
" Create an archive.\n\n"
|
||||||
"Allowed options");
|
"Allowed options");
|
||||||
|
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
|
@ -95,7 +100,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
}
|
}
|
||||||
|
|
||||||
info.mode = variables["mode"].as<std::string>();
|
info.mode = variables["mode"].as<std::string>();
|
||||||
if (!(info.mode == "list" || info.mode == "extract" || info.mode == "extractall"))
|
if (!(info.mode == "list" || info.mode == "extract" || info.mode == "extractall" || info.mode == "add" || info.mode == "create"))
|
||||||
{
|
{
|
||||||
std::cout << std::endl << "ERROR: invalid mode \"" << info.mode << "\"\n\n"
|
std::cout << std::endl << "ERROR: invalid mode \"" << info.mode << "\"\n\n"
|
||||||
<< desc << std::endl;
|
<< desc << std::endl;
|
||||||
|
@ -126,6 +131,17 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
if (variables["input-file"].as< std::vector<std::string> >().size() > 2)
|
if (variables["input-file"].as< std::vector<std::string> >().size() > 2)
|
||||||
info.outdir = variables["input-file"].as< std::vector<std::string> >()[2];
|
info.outdir = variables["input-file"].as< std::vector<std::string> >()[2];
|
||||||
}
|
}
|
||||||
|
else if (info.mode == "add")
|
||||||
|
{
|
||||||
|
if (variables["input-file"].as< std::vector<std::string> >().size() < 1)
|
||||||
|
{
|
||||||
|
std::cout << "\nERROR: file to add unspecified\n\n"
|
||||||
|
<< desc << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
|
||||||
|
info.addfile = variables["input-file"].as< std::vector<std::string> >()[1];
|
||||||
|
}
|
||||||
else if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
|
else if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
|
||||||
info.outdir = variables["input-file"].as< std::vector<std::string> >()[1];
|
info.outdir = variables["input-file"].as< std::vector<std::string> >()[1];
|
||||||
|
|
||||||
|
@ -138,6 +154,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
||||||
int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
||||||
int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
||||||
|
int add(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
@ -157,6 +174,12 @@ int main(int argc, char** argv)
|
||||||
else
|
else
|
||||||
bsa = std::make_unique<Bsa::BSAFile>(Bsa::BSAFile());
|
bsa = std::make_unique<Bsa::BSAFile>(Bsa::BSAFile());
|
||||||
|
|
||||||
|
if (info.mode == "create")
|
||||||
|
{
|
||||||
|
bsa->open(info.filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bsa->open(info.filename);
|
bsa->open(info.filename);
|
||||||
|
|
||||||
if (info.mode == "list")
|
if (info.mode == "list")
|
||||||
|
@ -165,6 +188,8 @@ int main(int argc, char** argv)
|
||||||
return extract(bsa, info);
|
return extract(bsa, info);
|
||||||
else if (info.mode == "extractall")
|
else if (info.mode == "extractall")
|
||||||
return extractAll(bsa, info);
|
return extractAll(bsa, info);
|
||||||
|
else if (info.mode == "add")
|
||||||
|
return add(bsa, info);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << "Unsupported mode. That is not supposed to happen." << std::endl;
|
std::cout << "Unsupported mode. That is not supposed to happen." << std::endl;
|
||||||
|
@ -188,13 +213,13 @@ int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
||||||
{
|
{
|
||||||
// Long format
|
// Long format
|
||||||
std::ios::fmtflags f(std::cout.flags());
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << std::setw(50) << std::left << file.name;
|
std::cout << std::setw(50) << std::left << file.name();
|
||||||
std::cout << std::setw(8) << std::left << std::dec << file.fileSize;
|
std::cout << std::setw(8) << std::left << std::dec << file.fileSize;
|
||||||
std::cout << "@ 0x" << std::hex << file.offset << std::endl;
|
std::cout << "@ 0x" << std::hex << file.offset << std::endl;
|
||||||
std::cout.flags(f);
|
std::cout.flags(f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << file.name << std::endl;
|
std::cout << file.name() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -253,7 +278,7 @@ int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
||||||
{
|
{
|
||||||
for (const auto &file : bsa->getList())
|
for (const auto &file : bsa->getList())
|
||||||
{
|
{
|
||||||
std::string extractPath(file.name);
|
std::string extractPath(file.name());
|
||||||
Misc::StringUtils::replaceAll(extractPath, "\\", "/");
|
Misc::StringUtils::replaceAll(extractPath, "\\", "/");
|
||||||
|
|
||||||
// Get the target path (the path the file will be extracted to)
|
// Get the target path (the path the file will be extracted to)
|
||||||
|
@ -272,7 +297,7 @@ int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
||||||
|
|
||||||
// Get a stream for the file to extract
|
// Get a stream for the file to extract
|
||||||
// (inefficient because getFile iter on the list again)
|
// (inefficient because getFile iter on the list again)
|
||||||
Files::IStreamPtr data = bsa->getFile(file.name);
|
Files::IStreamPtr data = bsa->getFile(file.name());
|
||||||
bfs::ofstream out(target, std::ios::binary);
|
bfs::ofstream out(target, std::ios::binary);
|
||||||
|
|
||||||
// Write the file to disk
|
// Write the file to disk
|
||||||
|
@ -283,3 +308,11 @@ int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int add(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
||||||
|
{
|
||||||
|
boost::filesystem::fstream stream(info.addfile, std::ios_base::binary | std::ios_base::out | std::ios_base::in);
|
||||||
|
bsa->addFile(info.addfile, stream);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -322,7 +322,7 @@ int load(Arguments& info)
|
||||||
std::string filename = info.filename;
|
std::string filename = info.filename;
|
||||||
std::cout << "Loading file: " << filename << std::endl;
|
std::cout << "Loading file: " << filename << std::endl;
|
||||||
|
|
||||||
std::list<int> skipped;
|
std::list<uint32_t> skipped;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace ESSImport
|
||||||
{
|
{
|
||||||
out.mId = Misc::StringUtils::lowerCase(scpt.mSCHD.mName.toString());
|
out.mId = Misc::StringUtils::lowerCase(scpt.mSCHD.mName.toString());
|
||||||
out.mRunning = scpt.mRunning;
|
out.mRunning = scpt.mRunning;
|
||||||
|
out.mTargetRef.unset(); // TODO: convert target reference of global script
|
||||||
convertSCRI(scpt.mSCRI, out.mLocals);
|
convertSCRI(scpt.mSCRI, out.mLocals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace ESSImport
|
||||||
item.mCount = contItem.mCount;
|
item.mCount = contItem.mCount;
|
||||||
item.mRelativeEquipmentSlot = -1;
|
item.mRelativeEquipmentSlot = -1;
|
||||||
item.mLockLevel = 0;
|
item.mLockLevel = 0;
|
||||||
|
item.mRefNum.unset();
|
||||||
|
|
||||||
unsigned int itemCount = std::abs(item.mCount);
|
unsigned int itemCount = std::abs(item.mCount);
|
||||||
bool separateStacks = false;
|
bool separateStacks = false;
|
||||||
|
|
|
@ -57,7 +57,7 @@ int main(int argc, char** argv)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const std::string& ext = ".omwsave";
|
const std::string& ext = ".omwsave";
|
||||||
if (boost::filesystem::exists(boost::filesystem::path(outputFile))
|
if (bfs::exists(bfs::path(outputFile))
|
||||||
&& (outputFile.size() < ext.size() || outputFile.substr(outputFile.size()-ext.size()) != ext))
|
&& (outputFile.size() < ext.size() || outputFile.substr(outputFile.size()-ext.size()) != ext))
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Output file already exists and does not end in .omwsave. Did you mean to use --compare?");
|
throw std::runtime_error("Output file already exists and does not end in .omwsave. Did you mean to use --compare?");
|
||||||
|
|
|
@ -13,6 +13,7 @@ set(LAUNCHER
|
||||||
utils/profilescombobox.cpp
|
utils/profilescombobox.cpp
|
||||||
utils/textinputdialog.cpp
|
utils/textinputdialog.cpp
|
||||||
utils/lineedit.cpp
|
utils/lineedit.cpp
|
||||||
|
utils/openalutil.cpp
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/files/windows/launcher.rc
|
${CMAKE_SOURCE_DIR}/files/windows/launcher.rc
|
||||||
)
|
)
|
||||||
|
@ -31,6 +32,7 @@ set(LAUNCHER_HEADER
|
||||||
utils/profilescombobox.hpp
|
utils/profilescombobox.hpp
|
||||||
utils/textinputdialog.hpp
|
utils/textinputdialog.hpp
|
||||||
utils/lineedit.hpp
|
utils/lineedit.hpp
|
||||||
|
utils/openalutil.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Headers that must be pre-processed
|
# Headers that must be pre-processed
|
||||||
|
@ -47,6 +49,7 @@ set(LAUNCHER_HEADER_MOC
|
||||||
utils/textinputdialog.hpp
|
utils/textinputdialog.hpp
|
||||||
utils/profilescombobox.hpp
|
utils/profilescombobox.hpp
|
||||||
utils/lineedit.hpp
|
utils/lineedit.hpp
|
||||||
|
utils/openalutil.hpp
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -95,6 +98,7 @@ endif (WIN32)
|
||||||
|
|
||||||
target_link_libraries(openmw-launcher
|
target_link_libraries(openmw-launcher
|
||||||
${SDL2_LIBRARY_ONLY}
|
${SDL2_LIBRARY_ONLY}
|
||||||
|
${OPENAL_LIBRARY}
|
||||||
components
|
components
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
#include "advancedpage.hpp"
|
#include "advancedpage.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include <components/config/gamesettings.hpp>
|
#include <components/config/gamesettings.hpp>
|
||||||
#include <components/config/launchersettings.hpp>
|
#include <components/config/launchersettings.hpp>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QCompleter>
|
#include <QCompleter>
|
||||||
#include <QProxyStyle>
|
#include <QProxyStyle>
|
||||||
|
#include <QString>
|
||||||
#include <components/contentselector/view/contentselector.hpp>
|
#include <components/contentselector/view/contentselector.hpp>
|
||||||
#include <components/contentselector/model/esmfile.hpp>
|
#include <components/contentselector/model/esmfile.hpp>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "utils/openalutil.hpp"
|
||||||
|
|
||||||
Launcher::AdvancedPage::AdvancedPage(Config::GameSettings &gameSettings,
|
Launcher::AdvancedPage::AdvancedPage(Config::GameSettings &gameSettings,
|
||||||
Settings::Manager &engineSettings, QWidget *parent)
|
Settings::Manager &engineSettings, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
|
@ -19,7 +24,17 @@ Launcher::AdvancedPage::AdvancedPage(Config::GameSettings &gameSettings,
|
||||||
setObjectName ("AdvancedPage");
|
setObjectName ("AdvancedPage");
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
|
||||||
|
for(const char * name : Launcher::enumerateOpenALDevices())
|
||||||
|
{
|
||||||
|
audioDeviceSelectorComboBox->addItem(QString::fromUtf8(name), QString::fromUtf8(name));
|
||||||
|
}
|
||||||
|
for(const char * name : Launcher::enumerateOpenALDevicesHrtf())
|
||||||
|
{
|
||||||
|
hrtfProfileSelectorComboBox->addItem(QString::fromUtf8(name), QString::fromUtf8(name));
|
||||||
|
}
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
mCellNameCompleter.setModel(&mCellNameCompleterModel);
|
mCellNameCompleter.setModel(&mCellNameCompleterModel);
|
||||||
startDefaultCharacterAtField->setCompleter(&mCellNameCompleter);
|
startDefaultCharacterAtField->setCompleter(&mCellNameCompleter);
|
||||||
}
|
}
|
||||||
|
@ -95,6 +110,7 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||||
int numPhysicsThreads = mEngineSettings.getInt("async num threads", "Physics");
|
int numPhysicsThreads = mEngineSettings.getInt("async num threads", "Physics");
|
||||||
if (numPhysicsThreads >= 0)
|
if (numPhysicsThreads >= 0)
|
||||||
physicsThreadsSpinBox->setValue(numPhysicsThreads);
|
physicsThreadsSpinBox->setValue(numPhysicsThreads);
|
||||||
|
loadSettingBool(allowNPCToFollowOverWaterSurfaceCheckBox, "allow actors to follow over water surface", "Game");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visuals
|
// Visuals
|
||||||
|
@ -124,8 +140,43 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||||
|
|
||||||
loadSettingBool(activeGridObjectPagingCheckBox, "object paging active grid", "Terrain");
|
loadSettingBool(activeGridObjectPagingCheckBox, "object paging active grid", "Terrain");
|
||||||
viewingDistanceComboBox->setValue(convertToCells(mEngineSettings.getInt("viewing distance", "Camera")));
|
viewingDistanceComboBox->setValue(convertToCells(mEngineSettings.getInt("viewing distance", "Camera")));
|
||||||
|
|
||||||
|
int lightingMethod = 1;
|
||||||
|
if (mEngineSettings.getString("lighting method", "Shaders") == "legacy")
|
||||||
|
lightingMethod = 0;
|
||||||
|
else if (mEngineSettings.getString("lighting method", "Shaders") == "shaders")
|
||||||
|
lightingMethod = 2;
|
||||||
|
lightingMethodComboBox->setCurrentIndex(lightingMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Audio
|
||||||
|
{
|
||||||
|
std::string selectedAudioDevice = mEngineSettings.getString("device", "Sound");
|
||||||
|
if (selectedAudioDevice.empty() == false)
|
||||||
|
{
|
||||||
|
int audioDeviceIndex = audioDeviceSelectorComboBox->findData(QString::fromStdString(selectedAudioDevice));
|
||||||
|
if (audioDeviceIndex != -1)
|
||||||
|
{
|
||||||
|
audioDeviceSelectorComboBox->setCurrentIndex(audioDeviceIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int hrtfEnabledIndex = mEngineSettings.getInt("hrtf enable", "Sound");
|
||||||
|
if (hrtfEnabledIndex >= -1 && hrtfEnabledIndex <= 1)
|
||||||
|
{
|
||||||
|
enableHRTFComboBox->setCurrentIndex(hrtfEnabledIndex + 1);
|
||||||
|
}
|
||||||
|
std::string selectedHRTFProfile = mEngineSettings.getString("hrtf", "Sound");
|
||||||
|
if (selectedHRTFProfile.empty() == false)
|
||||||
|
{
|
||||||
|
int hrtfProfileIndex = hrtfProfileSelectorComboBox->findData(QString::fromStdString(selectedHRTFProfile));
|
||||||
|
if (hrtfProfileIndex != -1)
|
||||||
|
{
|
||||||
|
hrtfProfileSelectorComboBox->setCurrentIndex(hrtfProfileIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Camera
|
// Camera
|
||||||
{
|
{
|
||||||
loadSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera");
|
loadSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera");
|
||||||
|
@ -152,6 +203,7 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||||
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
|
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
|
||||||
loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
||||||
loadSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
loadSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
||||||
|
scalingSpinBox->setValue(mEngineSettings.getFloat("scaling factor", "GUI"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bug fixes
|
// Bug fixes
|
||||||
|
@ -266,6 +318,36 @@ void Launcher::AdvancedPage::saveSettings()
|
||||||
{
|
{
|
||||||
mEngineSettings.setInt("viewing distance", "Camera", convertToUnits(viewingDistance));
|
mEngineSettings.setInt("viewing distance", "Camera", convertToUnits(viewingDistance));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::array<std::string, 3> lightingMethodMap = {"legacy", "shaders compatibility", "shaders"};
|
||||||
|
mEngineSettings.setString("lighting method", "Shaders", lightingMethodMap[lightingMethodComboBox->currentIndex()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Audio
|
||||||
|
{
|
||||||
|
int audioDeviceIndex = audioDeviceSelectorComboBox->currentIndex();
|
||||||
|
if (audioDeviceIndex != 0)
|
||||||
|
{
|
||||||
|
mEngineSettings.setString("device", "Sound", audioDeviceSelectorComboBox->currentText().toUtf8().constData());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mEngineSettings.setString("device", "Sound", "");
|
||||||
|
}
|
||||||
|
int hrtfEnabledIndex = enableHRTFComboBox->currentIndex() - 1;
|
||||||
|
if (hrtfEnabledIndex != mEngineSettings.getInt("hrtf enable", "Sound"))
|
||||||
|
{
|
||||||
|
mEngineSettings.setInt("hrtf enable", "Sound", hrtfEnabledIndex);
|
||||||
|
}
|
||||||
|
int selectedHRTFProfileIndex = hrtfProfileSelectorComboBox->currentIndex();
|
||||||
|
if (selectedHRTFProfileIndex != 0)
|
||||||
|
{
|
||||||
|
mEngineSettings.setString("hrtf", "Sound", hrtfProfileSelectorComboBox->currentText().toUtf8().constData());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mEngineSettings.setString("hrtf", "Sound", "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Camera
|
// Camera
|
||||||
|
@ -299,6 +381,9 @@ void Launcher::AdvancedPage::saveSettings()
|
||||||
mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex);
|
mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex);
|
||||||
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
||||||
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
||||||
|
float uiScalingFactor = scalingSpinBox->value();
|
||||||
|
if (uiScalingFactor != mEngineSettings.getFloat("scaling factor", "GUI"))
|
||||||
|
mEngineSettings.setFloat("scaling factor", "GUI", uiScalingFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bug fixes
|
// Bug fixes
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
QString getAspect(int x, int y)
|
QString getAspect(int x, int y)
|
||||||
{
|
{
|
||||||
int gcd = std::gcd (x, y);
|
int gcd = std::gcd (x, y);
|
||||||
|
if (gcd == 0)
|
||||||
|
return QString();
|
||||||
|
|
||||||
int xaspect = x / gcd;
|
int xaspect = x / gcd;
|
||||||
int yaspect = y / gcd;
|
int yaspect = y / gcd;
|
||||||
// special case: 8 : 5 is usually referred to as 16:10
|
// special case: 8 : 5 is usually referred to as 16:10
|
||||||
|
@ -298,9 +301,9 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString aspect = getAspect(mode.w, mode.h);
|
|
||||||
QString resolution = QString::number(mode.w) + QString(" x ") + QString::number(mode.h);
|
QString resolution = QString::number(mode.w) + QString(" x ") + QString::number(mode.h);
|
||||||
|
|
||||||
|
QString aspect = getAspect(mode.w, mode.h);
|
||||||
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) {
|
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) {
|
||||||
resolution.append(tr("\t(Wide ") + aspect + ")");
|
resolution.append(tr("\t(Wide ") + aspect + ")");
|
||||||
|
|
||||||
|
|
61
apps/launcher/utils/openalutil.cpp
Normal file
61
apps/launcher/utils/openalutil.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <apps/openmw/mwsound/alext.h>
|
||||||
|
|
||||||
|
#include "openalutil.hpp"
|
||||||
|
|
||||||
|
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
||||||
|
#define ALC_ALL_DEVICES_SPECIFIER 0x1013
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::vector<const char *> Launcher::enumerateOpenALDevices()
|
||||||
|
{
|
||||||
|
std::vector<const char *> devlist;
|
||||||
|
const ALCchar *devnames;
|
||||||
|
|
||||||
|
if(alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
|
||||||
|
{
|
||||||
|
devnames = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
devnames = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(devnames && *devnames)
|
||||||
|
{
|
||||||
|
devlist.emplace_back(devnames);
|
||||||
|
devnames += strlen(devnames)+1;
|
||||||
|
}
|
||||||
|
return devlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char *> Launcher::enumerateOpenALDevicesHrtf()
|
||||||
|
{
|
||||||
|
std::vector<const char *> ret;
|
||||||
|
|
||||||
|
ALCdevice *device = alcOpenDevice(nullptr);
|
||||||
|
if(device)
|
||||||
|
{
|
||||||
|
if(alcIsExtensionPresent(device, "ALC_SOFT_HRTF"))
|
||||||
|
{
|
||||||
|
LPALCGETSTRINGISOFT alcGetStringiSOFT = nullptr;
|
||||||
|
void* funcPtr = alcGetProcAddress(device, "alcGetStringiSOFT");
|
||||||
|
memcpy(&alcGetStringiSOFT, &funcPtr, sizeof(funcPtr));
|
||||||
|
ALCint num_hrtf;
|
||||||
|
alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf);
|
||||||
|
ret.reserve(num_hrtf);
|
||||||
|
for(ALCint i = 0;i < num_hrtf;++i)
|
||||||
|
{
|
||||||
|
const ALCchar *entry = alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i);
|
||||||
|
if(strcmp(entry, "") == 0)
|
||||||
|
break;
|
||||||
|
ret.emplace_back(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alcCloseDevice(device);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
7
apps/launcher/utils/openalutil.hpp
Normal file
7
apps/launcher/utils/openalutil.hpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Launcher
|
||||||
|
{
|
||||||
|
std::vector<const char *> enumerateOpenALDevices();
|
||||||
|
std::vector<const char *> enumerateOpenALDevicesHrtf();
|
||||||
|
}
|
|
@ -116,7 +116,7 @@ opencs_units (view/prefs
|
||||||
|
|
||||||
opencs_units (model/prefs
|
opencs_units (model/prefs
|
||||||
state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut
|
state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut
|
||||||
shortcuteventhandler shortcutmanager shortcutsetting modifiersetting
|
shortcuteventhandler shortcutmanager shortcutsetting modifiersetting stringsetting
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (model/prefs
|
opencs_units_noqt (model/prefs
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
|
|
||||||
namespace CSMPrefs
|
namespace CSMPrefs
|
||||||
{
|
{
|
||||||
const int ShortcutSetting::MaxKeys;
|
|
||||||
|
|
||||||
ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
|
ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
|
||||||
const std::string& label)
|
const std::string& label)
|
||||||
: Setting(parent, values, mutex, key, label)
|
: Setting(parent, values, mutex, key, label)
|
||||||
|
|
|
@ -421,6 +421,16 @@ void CSMPrefs::State::declare()
|
||||||
declareSubcategory ("Script Editor");
|
declareSubcategory ("Script Editor");
|
||||||
declareShortcut ("script-editor-comment", "Comment Selection", QKeySequence());
|
declareShortcut ("script-editor-comment", "Comment Selection", QKeySequence());
|
||||||
declareShortcut ("script-editor-uncomment", "Uncomment Selection", QKeySequence());
|
declareShortcut ("script-editor-uncomment", "Uncomment Selection", QKeySequence());
|
||||||
|
|
||||||
|
declareCategory ("Models");
|
||||||
|
declareString ("baseanim", "base animations", "meshes/base_anim.nif").
|
||||||
|
setTooltip("3rd person base model with textkeys-data");
|
||||||
|
declareString ("baseanimkna", "base animations, kna", "meshes/base_animkna.nif").
|
||||||
|
setTooltip("3rd person beast race base model with textkeys-data");
|
||||||
|
declareString ("baseanimfemale", "base animations, female", "meshes/base_anim_female.nif").
|
||||||
|
setTooltip("3rd person female base model with textkeys-data");
|
||||||
|
declareString ("wolfskin", "base animations, wolf", "meshes/wolf/skin.nif").
|
||||||
|
setTooltip("3rd person werewolf skin");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::State::declareCategory (const std::string& key)
|
void CSMPrefs::State::declareCategory (const std::string& key)
|
||||||
|
@ -557,6 +567,24 @@ CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string&
|
||||||
return *setting;
|
return *setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSMPrefs::StringSetting& CSMPrefs::State::declareString (const std::string& key, const std::string& label, std::string default_)
|
||||||
|
{
|
||||||
|
if (mCurrentCategory==mCategories.end())
|
||||||
|
throw std::logic_error ("no category for setting");
|
||||||
|
|
||||||
|
setDefault (key, default_);
|
||||||
|
|
||||||
|
default_ = mSettings.getString (key, mCurrentCategory->second.getKey());
|
||||||
|
|
||||||
|
CSMPrefs::StringSetting *setting =
|
||||||
|
new CSMPrefs::StringSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label,
|
||||||
|
default_);
|
||||||
|
|
||||||
|
mCurrentCategory->second.addSetting (setting);
|
||||||
|
|
||||||
|
return *setting;
|
||||||
|
}
|
||||||
|
|
||||||
CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(const std::string& key, const std::string& label,
|
CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(const std::string& key, const std::string& label,
|
||||||
int default_)
|
int default_)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "category.hpp"
|
#include "category.hpp"
|
||||||
#include "setting.hpp"
|
#include "setting.hpp"
|
||||||
#include "enumsetting.hpp"
|
#include "enumsetting.hpp"
|
||||||
|
#include "stringsetting.hpp"
|
||||||
#include "shortcutmanager.hpp"
|
#include "shortcutmanager.hpp"
|
||||||
|
|
||||||
class QColor;
|
class QColor;
|
||||||
|
@ -78,6 +79,8 @@ namespace CSMPrefs
|
||||||
ShortcutSetting& declareShortcut (const std::string& key, const std::string& label,
|
ShortcutSetting& declareShortcut (const std::string& key, const std::string& label,
|
||||||
const QKeySequence& default_);
|
const QKeySequence& default_);
|
||||||
|
|
||||||
|
StringSetting& declareString (const std::string& key, const std::string& label, std::string default_);
|
||||||
|
|
||||||
ModifierSetting& declareModifier(const std::string& key, const std::string& label, int modifier_);
|
ModifierSetting& declareModifier(const std::string& key, const std::string& label, int modifier_);
|
||||||
|
|
||||||
void declareSeparator();
|
void declareSeparator();
|
||||||
|
|
54
apps/opencs/model/prefs/stringsetting.cpp
Normal file
54
apps/opencs/model/prefs/stringsetting.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
#include "stringsetting.hpp"
|
||||||
|
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include "category.hpp"
|
||||||
|
#include "state.hpp"
|
||||||
|
|
||||||
|
CSMPrefs::StringSetting::StringSetting (Category *parent, Settings::Manager *values,
|
||||||
|
QMutex *mutex, const std::string& key, const std::string& label, std::string default_)
|
||||||
|
: Setting (parent, values, mutex, key, label), mDefault (default_), mWidget(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
CSMPrefs::StringSetting& CSMPrefs::StringSetting::setTooltip (const std::string& tooltip)
|
||||||
|
{
|
||||||
|
mTooltip = tooltip;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<QWidget *, QWidget *> CSMPrefs::StringSetting::makeWidgets (QWidget *parent)
|
||||||
|
{
|
||||||
|
mWidget = new QLineEdit (QString::fromUtf8 (mDefault.c_str()), parent);
|
||||||
|
|
||||||
|
if (!mTooltip.empty())
|
||||||
|
{
|
||||||
|
QString tooltip = QString::fromUtf8 (mTooltip.c_str());
|
||||||
|
mWidget->setToolTip (tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect (mWidget, SIGNAL (textChanged (QString)), this, SLOT (textChanged (QString)));
|
||||||
|
|
||||||
|
return std::make_pair (static_cast<QWidget *> (nullptr), mWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMPrefs::StringSetting::updateWidget()
|
||||||
|
{
|
||||||
|
if (mWidget)
|
||||||
|
{
|
||||||
|
mWidget->setText(QString::fromStdString(getValues().getString(getKey(), getParent()->getKey())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMPrefs::StringSetting::textChanged (const QString& text)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
QMutexLocker lock (getMutex());
|
||||||
|
getValues().setString (getKey(), getParent()->getKey(), text.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
getParent()->getState()->update (*this);
|
||||||
|
}
|
36
apps/opencs/model/prefs/stringsetting.hpp
Normal file
36
apps/opencs/model/prefs/stringsetting.hpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef CSM_PREFS_StringSetting_H
|
||||||
|
#define CSM_PREFS_StringSetting_H
|
||||||
|
|
||||||
|
#include "setting.hpp"
|
||||||
|
|
||||||
|
class QLineEdit;
|
||||||
|
|
||||||
|
namespace CSMPrefs
|
||||||
|
{
|
||||||
|
class StringSetting : public Setting
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
std::string mTooltip;
|
||||||
|
std::string mDefault;
|
||||||
|
QLineEdit* mWidget;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
StringSetting (Category *parent, Settings::Manager *values,
|
||||||
|
QMutex *mutex, const std::string& key, const std::string& label, std::string default_);
|
||||||
|
|
||||||
|
StringSetting& setTooltip (const std::string& tooltip);
|
||||||
|
|
||||||
|
/// Return label, input widget.
|
||||||
|
std::pair<QWidget *, QWidget *> makeWidgets (QWidget *parent) override;
|
||||||
|
|
||||||
|
void updateWidget() override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void textChanged (const QString& text);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -76,6 +76,7 @@ void CSMWorld::ImportLandTexturesCommand::redo()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> oldTextures;
|
std::vector<std::string> oldTextures;
|
||||||
|
oldTextures.reserve(texIndices.size());
|
||||||
for (int index : texIndices)
|
for (int index : texIndices)
|
||||||
{
|
{
|
||||||
oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index));
|
oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index));
|
||||||
|
|
|
@ -83,6 +83,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
||||||
defines["clamp"] = "1"; // Clamp lighting
|
defines["clamp"] = "1"; // Clamp lighting
|
||||||
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
|
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
|
||||||
defines["radialFog"] = "0";
|
defines["radialFog"] = "0";
|
||||||
|
defines["lightingModel"] = "0";
|
||||||
for (const auto& define : shadowDefines)
|
for (const auto& define : shadowDefines)
|
||||||
defines[define.first] = define.second;
|
defines[define.first] = define.second;
|
||||||
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
|
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
|
||||||
|
@ -985,20 +986,6 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
|
||||||
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, nullptr, &metaData));
|
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, nullptr, &metaData));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix uninitialized master data index
|
|
||||||
for (std::vector<ESM::Header::MasterData>::const_iterator masterData = mReader->getGameFiles().begin();
|
|
||||||
masterData != mReader->getGameFiles().end(); ++masterData)
|
|
||||||
{
|
|
||||||
std::map<std::string, int>::iterator nameResult = mContentFileNames.find(masterData->name);
|
|
||||||
if (nameResult != mContentFileNames.end())
|
|
||||||
{
|
|
||||||
ESM::Header::MasterData& hackedMasterData = const_cast<ESM::Header::MasterData&>(*masterData);
|
|
||||||
|
|
||||||
|
|
||||||
hackedMasterData.index = nameResult->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mReader->getRecordCount();
|
return mReader->getRecordCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,7 +201,7 @@ QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const
|
||||||
const std::pair<int, int>& address(unfoldIndexAddress(id));
|
const std::pair<int, int>& address(unfoldIndexAddress(id));
|
||||||
|
|
||||||
if (address.first >= this->rowCount() || address.second >= this->columnCount())
|
if (address.first >= this->rowCount() || address.second >= this->columnCount())
|
||||||
throw "Parent index is not present in the model";
|
throw std::logic_error("Parent index is not present in the model");
|
||||||
|
|
||||||
return createIndex(address.first, address.second);
|
return createIndex(address.first, address.second);
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ unsigned int CSMWorld::IdTree::foldIndexAddress (const QModelIndex& index) const
|
||||||
std::pair< int, int > CSMWorld::IdTree::unfoldIndexAddress (unsigned int id) const
|
std::pair< int, int > CSMWorld::IdTree::unfoldIndexAddress (unsigned int id) const
|
||||||
{
|
{
|
||||||
if (id == 0)
|
if (id == 0)
|
||||||
throw "Attempt to unfold index id of the top level data cell";
|
throw std::runtime_error("Attempt to unfold index id of the top level data cell");
|
||||||
|
|
||||||
--id;
|
--id;
|
||||||
int row = id / this->columnCount();
|
int row = id / this->columnCount();
|
||||||
|
|
|
@ -56,7 +56,9 @@ void CSMWorld::PotionRefIdAdapter::setData (const RefIdColumn *column, RefIdData
|
||||||
|
|
||||||
|
|
||||||
CSMWorld::IngredientColumns::IngredientColumns (const InventoryColumns& columns)
|
CSMWorld::IngredientColumns::IngredientColumns (const InventoryColumns& columns)
|
||||||
: InventoryColumns (columns) {}
|
: InventoryColumns (columns)
|
||||||
|
, mEffects(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
CSMWorld::IngredientRefIdAdapter::IngredientRefIdAdapter (const IngredientColumns& columns)
|
CSMWorld::IngredientRefIdAdapter::IngredientRefIdAdapter (const IngredientColumns& columns)
|
||||||
: InventoryRefIdAdapter<ESM::Ingredient> (UniversalId::Type_Ingredient, columns),
|
: InventoryRefIdAdapter<ESM::Ingredient> (UniversalId::Type_Ingredient, columns),
|
||||||
|
@ -585,7 +587,13 @@ void CSMWorld::DoorRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::LightColumns::LightColumns (const InventoryColumns& columns)
|
CSMWorld::LightColumns::LightColumns (const InventoryColumns& columns)
|
||||||
: InventoryColumns (columns) {}
|
: InventoryColumns (columns)
|
||||||
|
, mTime(nullptr)
|
||||||
|
, mRadius(nullptr)
|
||||||
|
, mColor(nullptr)
|
||||||
|
, mSound(nullptr)
|
||||||
|
, mEmitterType(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
CSMWorld::LightRefIdAdapter::LightRefIdAdapter (const LightColumns& columns)
|
CSMWorld::LightRefIdAdapter::LightRefIdAdapter (const LightColumns& columns)
|
||||||
: InventoryRefIdAdapter<ESM::Light> (UniversalId::Type_Light, columns), mColumns (columns)
|
: InventoryRefIdAdapter<ESM::Light> (UniversalId::Type_Light, columns), mColumns (columns)
|
||||||
|
@ -1454,7 +1462,15 @@ int CSMWorld::CreatureMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *co
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::WeaponColumns::WeaponColumns (const EnchantableColumns& columns)
|
CSMWorld::WeaponColumns::WeaponColumns (const EnchantableColumns& columns)
|
||||||
: EnchantableColumns (columns) {}
|
: EnchantableColumns (columns)
|
||||||
|
, mType(nullptr)
|
||||||
|
, mHealth(nullptr)
|
||||||
|
, mSpeed(nullptr)
|
||||||
|
, mReach(nullptr)
|
||||||
|
, mChop{nullptr}
|
||||||
|
, mSlash{nullptr}
|
||||||
|
, mThrust{nullptr}
|
||||||
|
{}
|
||||||
|
|
||||||
CSMWorld::WeaponRefIdAdapter::WeaponRefIdAdapter (const WeaponColumns& columns)
|
CSMWorld::WeaponRefIdAdapter::WeaponRefIdAdapter (const WeaponColumns& columns)
|
||||||
: EnchantableRefIdAdapter<ESM::Weapon> (UniversalId::Type_Weapon, columns), mColumns (columns)
|
: EnchantableRefIdAdapter<ESM::Weapon> (UniversalId::Type_Weapon, columns), mColumns (columns)
|
||||||
|
|
|
@ -178,7 +178,11 @@ namespace CSMWorld
|
||||||
const RefIdColumn *mName;
|
const RefIdColumn *mName;
|
||||||
const RefIdColumn *mScript;
|
const RefIdColumn *mScript;
|
||||||
|
|
||||||
NameColumns (const ModelColumns& base) : ModelColumns (base) {}
|
NameColumns (const ModelColumns& base)
|
||||||
|
: ModelColumns (base)
|
||||||
|
, mName(nullptr)
|
||||||
|
, mScript(nullptr)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Adapter for IDs with names (all but levelled lists and statics)
|
/// \brief Adapter for IDs with names (all but levelled lists and statics)
|
||||||
|
@ -247,7 +251,12 @@ namespace CSMWorld
|
||||||
const RefIdColumn *mWeight;
|
const RefIdColumn *mWeight;
|
||||||
const RefIdColumn *mValue;
|
const RefIdColumn *mValue;
|
||||||
|
|
||||||
InventoryColumns (const NameColumns& base) : NameColumns (base) {}
|
InventoryColumns (const NameColumns& base)
|
||||||
|
: NameColumns (base)
|
||||||
|
, mIcon(nullptr)
|
||||||
|
, mWeight(nullptr)
|
||||||
|
, mValue(nullptr)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Adapter for IDs that can go into an inventory
|
/// \brief Adapter for IDs that can go into an inventory
|
||||||
|
@ -405,7 +414,11 @@ namespace CSMWorld
|
||||||
const RefIdColumn *mEnchantment;
|
const RefIdColumn *mEnchantment;
|
||||||
const RefIdColumn *mEnchantmentPoints;
|
const RefIdColumn *mEnchantmentPoints;
|
||||||
|
|
||||||
EnchantableColumns (const InventoryColumns& base) : InventoryColumns (base) {}
|
EnchantableColumns (const InventoryColumns& base)
|
||||||
|
: InventoryColumns (base)
|
||||||
|
, mEnchantment(nullptr)
|
||||||
|
, mEnchantmentPoints(nullptr)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Adapter for enchantable IDs
|
/// \brief Adapter for enchantable IDs
|
||||||
|
@ -474,7 +487,11 @@ namespace CSMWorld
|
||||||
const RefIdColumn *mQuality;
|
const RefIdColumn *mQuality;
|
||||||
const RefIdColumn *mUses;
|
const RefIdColumn *mUses;
|
||||||
|
|
||||||
ToolColumns (const InventoryColumns& base) : InventoryColumns (base) {}
|
ToolColumns (const InventoryColumns& base)
|
||||||
|
: InventoryColumns (base)
|
||||||
|
, mQuality(nullptr)
|
||||||
|
, mUses(nullptr)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Adapter for tools with limited uses IDs (lockpick, repair, probes)
|
/// \brief Adapter for tools with limited uses IDs (lockpick, repair, probes)
|
||||||
|
@ -549,7 +566,17 @@ namespace CSMWorld
|
||||||
const RefIdColumn *mAiPackages;
|
const RefIdColumn *mAiPackages;
|
||||||
std::map<const RefIdColumn *, unsigned int> mServices;
|
std::map<const RefIdColumn *, unsigned int> mServices;
|
||||||
|
|
||||||
ActorColumns (const NameColumns& base) : NameColumns (base) {}
|
ActorColumns (const NameColumns& base)
|
||||||
|
: NameColumns (base)
|
||||||
|
, mHello(nullptr)
|
||||||
|
, mFlee(nullptr)
|
||||||
|
, mFight(nullptr)
|
||||||
|
, mAlarm(nullptr)
|
||||||
|
, mInventory(nullptr)
|
||||||
|
, mSpells(nullptr)
|
||||||
|
, mDestinations(nullptr)
|
||||||
|
, mAiPackages(nullptr)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Adapter for actor IDs (handles common AI functionality)
|
/// \brief Adapter for actor IDs (handles common AI functionality)
|
||||||
|
@ -2054,7 +2081,11 @@ namespace CSMWorld
|
||||||
const RefIdColumn *mLevList;
|
const RefIdColumn *mLevList;
|
||||||
const RefIdColumn *mNestedListLevList;
|
const RefIdColumn *mNestedListLevList;
|
||||||
|
|
||||||
LevListColumns (const BaseColumns& base) : BaseColumns (base) {}
|
LevListColumns (const BaseColumns& base)
|
||||||
|
: BaseColumns (base)
|
||||||
|
, mLevList(nullptr)
|
||||||
|
, mNestedListLevList(nullptr)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
|
|
|
@ -126,7 +126,7 @@ namespace CSVRender
|
||||||
{
|
{
|
||||||
// Try again without any mask
|
// Try again without any mask
|
||||||
boundsVisitor.reset();
|
boundsVisitor.reset();
|
||||||
boundsVisitor.setTraversalMask(~0);
|
boundsVisitor.setTraversalMask(~0u);
|
||||||
root->accept(boundsVisitor);
|
root->accept(boundsVisitor);
|
||||||
|
|
||||||
// Last resort, set a default
|
// Last resort, set a default
|
||||||
|
@ -458,7 +458,7 @@ namespace CSVRender
|
||||||
, mDown(false)
|
, mDown(false)
|
||||||
, mRollLeft(false)
|
, mRollLeft(false)
|
||||||
, mRollRight(false)
|
, mRollRight(false)
|
||||||
, mPickingMask(~0)
|
, mPickingMask(~0u)
|
||||||
, mCenter(0,0,0)
|
, mCenter(0,0,0)
|
||||||
, mDistance(0)
|
, mDistance(0)
|
||||||
, mOrbitSpeed(osg::PI / 4)
|
, mOrbitSpeed(osg::PI / 4)
|
||||||
|
|
|
@ -151,7 +151,7 @@ void CSVRender::CellArrow::buildShape()
|
||||||
osg::Vec4Array *colours = new osg::Vec4Array;
|
osg::Vec4Array *colours = new osg::Vec4Array;
|
||||||
|
|
||||||
for (int i=0; i<6; ++i)
|
for (int i=0; i<6; ++i)
|
||||||
colours->push_back (osg::Vec4f (0.11, 0.6f, 0.95f, 1.0f));
|
colours->push_back (osg::Vec4f (0.11f, 0.6f, 0.95f, 1.0f));
|
||||||
for (int i=0; i<6; ++i)
|
for (int i=0; i<6; ++i)
|
||||||
colours->push_back (osg::Vec4f (0.08f, 0.44f, 0.7f, 1.0f));
|
colours->push_back (osg::Vec4f (0.08f, 0.44f, 0.7f, 1.0f));
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace CSVRender
|
||||||
/// @note See the respective file in OpenMW (apps/openmw/mwrender/vismask.hpp)
|
/// @note See the respective file in OpenMW (apps/openmw/mwrender/vismask.hpp)
|
||||||
/// for general usage hints about node masks.
|
/// for general usage hints about node masks.
|
||||||
/// @copydoc MWRender::VisMask
|
/// @copydoc MWRender::VisMask
|
||||||
enum Mask
|
enum Mask : unsigned int
|
||||||
{
|
{
|
||||||
// elements that are part of the actual scene
|
// elements that are part of the actual scene
|
||||||
Mask_Reference = 0x2,
|
Mask_Reference = 0x2,
|
||||||
|
|
|
@ -121,7 +121,7 @@ void RenderWidget::flagAsModified()
|
||||||
mView->requestRedraw();
|
mView->requestRedraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderWidget::setVisibilityMask(int mask)
|
void RenderWidget::setVisibilityMask(unsigned int mask)
|
||||||
{
|
{
|
||||||
mView->getCamera()->setCullMask(mask | Mask_ParticleSystem | Mask_Lighting);
|
mView->getCamera()->setCullMask(mask | Mask_ParticleSystem | Mask_Lighting);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace CSVRender
|
||||||
/// Initiates a request to redraw the view
|
/// Initiates a request to redraw the view
|
||||||
void flagAsModified();
|
void flagAsModified();
|
||||||
|
|
||||||
void setVisibilityMask(int mask);
|
void setVisibilityMask(unsigned int mask);
|
||||||
|
|
||||||
osg::Camera *getCamera();
|
osg::Camera *getCamera();
|
||||||
|
|
||||||
|
|
|
@ -606,7 +606,7 @@ void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName)
|
||||||
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||||
if (ltexTable.getRecord(newId).isDeleted() == 0) counter = (counter + 1) % maxCounter;
|
if (ltexTable.getRecord(newId).isDeleted() == 0) counter = (counter + 1) % maxCounter;
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception&)
|
||||||
{
|
{
|
||||||
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||||
freeIndexFound = true;
|
freeIndexFound = true;
|
||||||
|
|
|
@ -163,7 +163,7 @@ void CSVRender::WorldspaceWidget::selectDefaultNavigationMode()
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::centerOrbitCameraOnSelection()
|
void CSVRender::WorldspaceWidget::centerOrbitCameraOnSelection()
|
||||||
{
|
{
|
||||||
std::vector<osg::ref_ptr<TagBase> > selection = getSelection(~0);
|
std::vector<osg::ref_ptr<TagBase> > selection = getSelection(~0u);
|
||||||
|
|
||||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it!=selection.end(); ++it)
|
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it!=selection.end(); ++it)
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,26 +43,6 @@ namespace Misc
|
||||||
class CallbackManager;
|
class CallbackManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWScript
|
|
||||||
{
|
|
||||||
class ScriptManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWSound
|
|
||||||
{
|
|
||||||
class SoundManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWWorld
|
|
||||||
{
|
|
||||||
class World;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWGui
|
|
||||||
{
|
|
||||||
class WindowManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Files
|
namespace Files
|
||||||
{
|
{
|
||||||
struct ConfigurationManager;
|
struct ConfigurationManager;
|
||||||
|
|
|
@ -32,7 +32,6 @@ namespace MyGUI
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct Class;
|
|
||||||
class ESMReader;
|
class ESMReader;
|
||||||
class ESMWriter;
|
class ESMWriter;
|
||||||
struct CellId;
|
struct CellId;
|
||||||
|
@ -173,6 +172,8 @@ namespace MWBase
|
||||||
virtual void setDragDrop(bool dragDrop) = 0;
|
virtual void setDragDrop(bool dragDrop) = 0;
|
||||||
virtual bool getWorldMouseOver() = 0;
|
virtual bool getWorldMouseOver() = 0;
|
||||||
|
|
||||||
|
virtual float getScalingFactor() = 0;
|
||||||
|
|
||||||
virtual bool toggleFogOfWar() = 0;
|
virtual bool toggleFogOfWar() = 0;
|
||||||
|
|
||||||
virtual bool toggleFullHelp() = 0;
|
virtual bool toggleFullHelp() = 0;
|
||||||
|
|
|
@ -288,13 +288,13 @@ namespace MWBase
|
||||||
virtual void deleteObject (const MWWorld::Ptr& ptr) = 0;
|
virtual void deleteObject (const MWWorld::Ptr& ptr) = 0;
|
||||||
virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0;
|
virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0;
|
||||||
|
|
||||||
virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z, bool moveToActive=false) = 0;
|
virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z, bool movePhysics=true, bool moveToActive=false) = 0;
|
||||||
///< @return an updated Ptr in case the Ptr's cell changes
|
///< @return an updated Ptr in case the Ptr's cell changes
|
||||||
|
|
||||||
virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z, bool movePhysics=true) = 0;
|
virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z, bool movePhysics=true) = 0;
|
||||||
///< @return an updated Ptr
|
///< @return an updated Ptr
|
||||||
|
|
||||||
virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, osg::Vec3f vec) = 0;
|
virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, osg::Vec3f vec, bool moveToActive) = 0;
|
||||||
///< @return an updated Ptr
|
///< @return an updated Ptr
|
||||||
|
|
||||||
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
||||||
|
@ -456,6 +456,8 @@ namespace MWBase
|
||||||
virtual void applyDeferredPreviewRotationToPlayer(float dt) = 0;
|
virtual void applyDeferredPreviewRotationToPlayer(float dt) = 0;
|
||||||
virtual void disableDeferredPreviewRotation() = 0;
|
virtual void disableDeferredPreviewRotation() = 0;
|
||||||
|
|
||||||
|
virtual void saveLoaded() = 0;
|
||||||
|
|
||||||
virtual void setupPlayer() = 0;
|
virtual void setupPlayer() = 0;
|
||||||
virtual void renderPlayer() = 0;
|
virtual void renderPlayer() = 0;
|
||||||
|
|
||||||
|
@ -618,7 +620,7 @@ namespace MWBase
|
||||||
|
|
||||||
/// Return a vector aiming the actor's weapon towards a target.
|
/// Return a vector aiming the actor's weapon towards a target.
|
||||||
/// @note The length of the vector is the distance between actor and target.
|
/// @note The length of the vector is the distance between actor and target.
|
||||||
virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) = 0;
|
virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target, bool isRangedCombat) = 0;
|
||||||
|
|
||||||
/// Return the distance between actor's weapon and target's collision box.
|
/// Return the distance between actor's weapon and target's collision box.
|
||||||
virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) = 0;
|
virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) = 0;
|
||||||
|
|
|
@ -46,11 +46,6 @@ namespace MWClass
|
||||||
mStore.readState(inventory);
|
mStore.readState(inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::CustomData *ContainerCustomData::clone() const
|
|
||||||
{
|
|
||||||
return new ContainerCustomData (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
ContainerCustomData& ContainerCustomData::asContainerCustomData()
|
ContainerCustomData& ContainerCustomData::asContainerCustomData()
|
||||||
{
|
{
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -72,7 +67,7 @@ namespace MWClass
|
||||||
MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
||||||
|
|
||||||
// store
|
// store
|
||||||
ptr.getRefData().setCustomData (std::make_unique<ContainerCustomData>(*ref->mBase, ptr.getCell()).release());
|
ptr.getRefData().setCustomData (std::make_unique<ContainerCustomData>(*ref->mBase, ptr.getCell()));
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->addContainerScripts(ptr, ptr.getCell());
|
MWBase::Environment::get().getWorld()->addContainerScripts(ptr, ptr.getCell());
|
||||||
}
|
}
|
||||||
|
@ -317,7 +312,7 @@ namespace MWClass
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const ESM::ContainerState& containerState = state.asContainerState();
|
const ESM::ContainerState& containerState = state.asContainerState();
|
||||||
ptr.getRefData().setCustomData(std::make_unique<ContainerCustomData>(containerState.mInventory).release());
|
ptr.getRefData().setCustomData(std::make_unique<ContainerCustomData>(containerState.mInventory));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
|
void Container::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
|
||||||
|
|
|
@ -13,15 +13,13 @@ namespace ESM
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
class ContainerCustomData : public MWWorld::CustomData
|
class ContainerCustomData : public MWWorld::TypedCustomData<ContainerCustomData>
|
||||||
{
|
{
|
||||||
MWWorld::ContainerStore mStore;
|
MWWorld::ContainerStore mStore;
|
||||||
public:
|
public:
|
||||||
ContainerCustomData(const ESM::Container& container, MWWorld::CellStore* cell);
|
ContainerCustomData(const ESM::Container& container, MWWorld::CellStore* cell);
|
||||||
ContainerCustomData(const ESM::InventoryState& inventory);
|
ContainerCustomData(const ESM::InventoryState& inventory);
|
||||||
|
|
||||||
MWWorld::CustomData *clone() const override;
|
|
||||||
|
|
||||||
ContainerCustomData& asContainerCustomData() override;
|
ContainerCustomData& asContainerCustomData() override;
|
||||||
const ContainerCustomData& asContainerCustomData() const override;
|
const ContainerCustomData& asContainerCustomData() const override;
|
||||||
|
|
||||||
|
|
|
@ -52,14 +52,16 @@ namespace
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
|
|
||||||
class CreatureCustomData : public MWWorld::CustomData
|
class CreatureCustomData : public MWWorld::TypedCustomData<CreatureCustomData>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MWMechanics::CreatureStats mCreatureStats;
|
MWMechanics::CreatureStats mCreatureStats;
|
||||||
MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures
|
std::unique_ptr<MWWorld::ContainerStore> mContainerStore; // may be InventoryStore for some creatures
|
||||||
MWMechanics::Movement mMovement;
|
MWMechanics::Movement mMovement;
|
||||||
|
|
||||||
MWWorld::CustomData *clone() const override;
|
CreatureCustomData() = default;
|
||||||
|
CreatureCustomData(const CreatureCustomData& other);
|
||||||
|
CreatureCustomData(CreatureCustomData&& other) = default;
|
||||||
|
|
||||||
CreatureCustomData& asCreatureCustomData() override
|
CreatureCustomData& asCreatureCustomData() override
|
||||||
{
|
{
|
||||||
|
@ -69,16 +71,13 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
CreatureCustomData() : mContainerStore(nullptr) {}
|
|
||||||
virtual ~CreatureCustomData() { delete mContainerStore; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MWWorld::CustomData *CreatureCustomData::clone() const
|
CreatureCustomData::CreatureCustomData(const CreatureCustomData& other)
|
||||||
|
: mCreatureStats(other.mCreatureStats),
|
||||||
|
mContainerStore(other.mContainerStore->clone()),
|
||||||
|
mMovement(other.mMovement)
|
||||||
{
|
{
|
||||||
CreatureCustomData* cloned = new CreatureCustomData (*this);
|
|
||||||
cloned->mContainerStore = mContainerStore->clone();
|
|
||||||
return cloned;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Creature::GMST& Creature::getGmst()
|
const Creature::GMST& Creature::getGmst()
|
||||||
|
@ -149,16 +148,16 @@ namespace MWClass
|
||||||
// inventory
|
// inventory
|
||||||
bool hasInventory = hasInventoryStore(ptr);
|
bool hasInventory = hasInventoryStore(ptr);
|
||||||
if (hasInventory)
|
if (hasInventory)
|
||||||
data->mContainerStore = new MWWorld::InventoryStore();
|
data->mContainerStore = std::make_unique<MWWorld::InventoryStore>();
|
||||||
else
|
else
|
||||||
data->mContainerStore = new MWWorld::ContainerStore();
|
data->mContainerStore = std::make_unique<MWWorld::ContainerStore>();
|
||||||
|
|
||||||
data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold);
|
data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold);
|
||||||
|
|
||||||
data->mCreatureStats.setNeedRecalcDynamicStats(false);
|
data->mCreatureStats.setNeedRecalcDynamicStats(false);
|
||||||
|
|
||||||
// store
|
// store
|
||||||
ptr.getRefData().setCustomData(data.release());
|
ptr.getRefData().setCustomData(std::move(data));
|
||||||
|
|
||||||
getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId());
|
getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId());
|
||||||
|
|
||||||
|
@ -772,11 +771,11 @@ namespace MWClass
|
||||||
std::unique_ptr<CreatureCustomData> data (new CreatureCustomData);
|
std::unique_ptr<CreatureCustomData> data (new CreatureCustomData);
|
||||||
|
|
||||||
if (hasInventoryStore(ptr))
|
if (hasInventoryStore(ptr))
|
||||||
data->mContainerStore = new MWWorld::InventoryStore();
|
data->mContainerStore = std::make_unique<MWWorld::InventoryStore>();
|
||||||
else
|
else
|
||||||
data->mContainerStore = new MWWorld::ContainerStore();
|
data->mContainerStore = std::make_unique<MWWorld::ContainerStore>();
|
||||||
|
|
||||||
ptr.getRefData().setCustomData (data.release());
|
ptr.getRefData().setCustomData (std::move(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -10,15 +10,13 @@
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
class CreatureLevListCustomData : public MWWorld::CustomData
|
class CreatureLevListCustomData : public MWWorld::TypedCustomData<CreatureLevListCustomData>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// actorId of the creature we spawned
|
// actorId of the creature we spawned
|
||||||
int mSpawnActorId;
|
int mSpawnActorId;
|
||||||
bool mSpawn; // Should a new creature be spawned?
|
bool mSpawn; // Should a new creature be spawned?
|
||||||
|
|
||||||
MWWorld::CustomData *clone() const override;
|
|
||||||
|
|
||||||
CreatureLevListCustomData& asCreatureLevListCustomData() override
|
CreatureLevListCustomData& asCreatureLevListCustomData() override
|
||||||
{
|
{
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -29,11 +27,6 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
MWWorld::CustomData *CreatureLevListCustomData::clone() const
|
|
||||||
{
|
|
||||||
return new CreatureLevListCustomData (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CreatureLevList::getName (const MWWorld::ConstPtr& ptr) const
|
std::string CreatureLevList::getName (const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
|
@ -138,11 +131,11 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
if (!ptr.getRefData().getCustomData())
|
if (!ptr.getRefData().getCustomData())
|
||||||
{
|
{
|
||||||
std::unique_ptr<CreatureLevListCustomData> data (new CreatureLevListCustomData);
|
std::unique_ptr<CreatureLevListCustomData> data = std::make_unique<CreatureLevListCustomData>();
|
||||||
data->mSpawnActorId = -1;
|
data->mSpawnActorId = -1;
|
||||||
data->mSpawn = true;
|
data->mSpawn = true;
|
||||||
|
|
||||||
ptr.getRefData().setCustomData(data.release());
|
ptr.getRefData().setCustomData(std::move(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,11 @@
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
class DoorCustomData : public MWWorld::CustomData
|
class DoorCustomData : public MWWorld::TypedCustomData<DoorCustomData>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MWWorld::DoorState mDoorState = MWWorld::DoorState::Idle;
|
MWWorld::DoorState mDoorState = MWWorld::DoorState::Idle;
|
||||||
|
|
||||||
MWWorld::CustomData *clone() const override;
|
|
||||||
|
|
||||||
DoorCustomData& asDoorCustomData() override
|
DoorCustomData& asDoorCustomData() override
|
||||||
{
|
{
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -48,11 +46,6 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
MWWorld::CustomData *DoorCustomData::clone() const
|
|
||||||
{
|
|
||||||
return new DoorCustomData (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
|
void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
|
||||||
{
|
{
|
||||||
if (!model.empty())
|
if (!model.empty())
|
||||||
|
@ -327,8 +320,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
if (!ptr.getRefData().getCustomData())
|
if (!ptr.getRefData().getCustomData())
|
||||||
{
|
{
|
||||||
std::unique_ptr<DoorCustomData> data(new DoorCustomData);
|
ptr.getRefData().setCustomData(std::make_unique<DoorCustomData>());
|
||||||
ptr.getRefData().setCustomData(data.release());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,15 +247,13 @@ namespace
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
|
|
||||||
class NpcCustomData : public MWWorld::CustomData
|
class NpcCustomData : public MWWorld::TypedCustomData<NpcCustomData>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MWMechanics::NpcStats mNpcStats;
|
MWMechanics::NpcStats mNpcStats;
|
||||||
MWMechanics::Movement mMovement;
|
MWMechanics::Movement mMovement;
|
||||||
MWWorld::InventoryStore mInventoryStore;
|
MWWorld::InventoryStore mInventoryStore;
|
||||||
|
|
||||||
MWWorld::CustomData *clone() const override;
|
|
||||||
|
|
||||||
NpcCustomData& asNpcCustomData() override
|
NpcCustomData& asNpcCustomData() override
|
||||||
{
|
{
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -266,11 +264,6 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
MWWorld::CustomData *NpcCustomData::clone() const
|
|
||||||
{
|
|
||||||
return new NpcCustomData (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Npc::GMST& Npc::getGmst()
|
const Npc::GMST& Npc::getGmst()
|
||||||
{
|
{
|
||||||
static GMST gmst;
|
static GMST gmst;
|
||||||
|
@ -398,7 +391,7 @@ namespace MWClass
|
||||||
data->mNpcStats.setGoldPool(gold);
|
data->mNpcStats.setGoldPool(gold);
|
||||||
|
|
||||||
// store
|
// store
|
||||||
ptr.getRefData().setCustomData (data.release());
|
ptr.getRefData().setCustomData(std::move(data));
|
||||||
|
|
||||||
getInventoryStore(ptr).autoEquip(ptr);
|
getInventoryStore(ptr).autoEquip(ptr);
|
||||||
}
|
}
|
||||||
|
@ -1331,8 +1324,7 @@ namespace MWClass
|
||||||
if (!ptr.getRefData().getCustomData())
|
if (!ptr.getRefData().getCustomData())
|
||||||
{
|
{
|
||||||
// Create a CustomData, but don't fill it from ESM records (not needed)
|
// Create a CustomData, but don't fill it from ESM records (not needed)
|
||||||
std::unique_ptr<NpcCustomData> data (new NpcCustomData);
|
ptr.getRefData().setCustomData(std::make_unique<NpcCustomData>());
|
||||||
ptr.getRefData().setCustomData (data.release());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace MWDialogue
|
||||||
std::vector<Token> parseHyperText(const std::string & text)
|
std::vector<Token> parseHyperText(const std::string & text)
|
||||||
{
|
{
|
||||||
std::vector<Token> result;
|
std::vector<Token> result;
|
||||||
size_t pos_end, iteration_pos = 0;
|
size_t pos_end = std::string::npos, iteration_pos = 0;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
size_t pos_begin = text.find('@', iteration_pos);
|
size_t pos_begin = text.find('@', iteration_pos);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "bookpage.hpp"
|
#include "bookpage.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "MyGUI_RenderItem.h"
|
#include "MyGUI_RenderItem.h"
|
||||||
#include "MyGUI_RenderManager.h"
|
#include "MyGUI_RenderManager.h"
|
||||||
#include "MyGUI_TextureUtility.h"
|
#include "MyGUI_TextureUtility.h"
|
||||||
|
@ -894,6 +896,27 @@ protected:
|
||||||
return mIsPageReset || (mPage != page);
|
return mIsPageReset || (mPage != page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<MyGUI::IntPoint> getAdjustedPos(int left, int top, bool move = false)
|
||||||
|
{
|
||||||
|
if (!mBook)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (mPage >= mBook->mPages.size())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
MyGUI::IntPoint pos (left, top);
|
||||||
|
#if MYGUI_VERSION < MYGUI_DEFINE_VERSION(3,2,3)
|
||||||
|
// work around inconsistency in MyGUI where the mouse press coordinates aren't
|
||||||
|
// transformed by the current Layer (even though mouse *move* events are).
|
||||||
|
if(!move)
|
||||||
|
pos = mNode->getLayer()->getPosition(left, top);
|
||||||
|
#endif
|
||||||
|
pos.left -= mCroppedParent->getAbsoluteLeft ();
|
||||||
|
pos.top -= mCroppedParent->getAbsoluteTop ();
|
||||||
|
pos.top += mViewTop;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef TypesetBookImpl::StyleImpl Style;
|
typedef TypesetBookImpl::StyleImpl Style;
|
||||||
|
@ -952,16 +975,10 @@ public:
|
||||||
|
|
||||||
void onMouseMove (int left, int top)
|
void onMouseMove (int left, int top)
|
||||||
{
|
{
|
||||||
if (!mBook)
|
Style * hit = nullptr;
|
||||||
return;
|
if(auto pos = getAdjustedPos(left, top, true))
|
||||||
|
if(pos->top <= mViewBottom)
|
||||||
if (mPage >= mBook->mPages.size())
|
hit = mBook->hitTestWithMargin (pos->left, pos->top);
|
||||||
return;
|
|
||||||
|
|
||||||
left -= mCroppedParent->getAbsoluteLeft ();
|
|
||||||
top -= mCroppedParent->getAbsoluteTop ();
|
|
||||||
|
|
||||||
Style * hit = mBook->hitTestWithMargin (left, mViewTop + top);
|
|
||||||
|
|
||||||
if (mLastDown == MyGUI::MouseButton::None)
|
if (mLastDown == MyGUI::MouseButton::None)
|
||||||
{
|
{
|
||||||
|
@ -991,24 +1008,11 @@ public:
|
||||||
|
|
||||||
void onMouseButtonPressed (int left, int top, MyGUI::MouseButton id)
|
void onMouseButtonPressed (int left, int top, MyGUI::MouseButton id)
|
||||||
{
|
{
|
||||||
if (!mBook)
|
auto pos = getAdjustedPos(left, top);
|
||||||
return;
|
|
||||||
|
|
||||||
if (mPage >= mBook->mPages.size())
|
if (pos && mLastDown == MyGUI::MouseButton::None)
|
||||||
return;
|
|
||||||
|
|
||||||
// work around inconsistency in MyGUI where the mouse press coordinates aren't
|
|
||||||
// transformed by the current Layer (even though mouse *move* events are).
|
|
||||||
MyGUI::IntPoint pos (left, top);
|
|
||||||
#if MYGUI_VERSION < MYGUI_DEFINE_VERSION(3,2,3)
|
|
||||||
pos = mNode->getLayer()->getPosition(left, top);
|
|
||||||
#endif
|
|
||||||
pos.left -= mCroppedParent->getAbsoluteLeft ();
|
|
||||||
pos.top -= mCroppedParent->getAbsoluteTop ();
|
|
||||||
|
|
||||||
if (mLastDown == MyGUI::MouseButton::None)
|
|
||||||
{
|
{
|
||||||
mFocusItem = mBook->hitTestWithMargin (pos.left, mViewTop + pos.top);
|
mFocusItem = pos->top <= mViewBottom ? mBook->hitTestWithMargin (pos->left, pos->top) : nullptr;
|
||||||
mItemActive = true;
|
mItemActive = true;
|
||||||
|
|
||||||
dirtyFocusItem ();
|
dirtyFocusItem ();
|
||||||
|
@ -1019,25 +1023,11 @@ public:
|
||||||
|
|
||||||
void onMouseButtonReleased(int left, int top, MyGUI::MouseButton id)
|
void onMouseButtonReleased(int left, int top, MyGUI::MouseButton id)
|
||||||
{
|
{
|
||||||
if (!mBook)
|
auto pos = getAdjustedPos(left, top);
|
||||||
return;
|
|
||||||
|
|
||||||
if (mPage >= mBook->mPages.size())
|
if (pos && mLastDown == id)
|
||||||
return;
|
|
||||||
|
|
||||||
// work around inconsistency in MyGUI where the mouse release coordinates aren't
|
|
||||||
// transformed by the current Layer (even though mouse *move* events are).
|
|
||||||
MyGUI::IntPoint pos (left, top);
|
|
||||||
#if MYGUI_VERSION < MYGUI_DEFINE_VERSION(3,2,3)
|
|
||||||
pos = mNode->getLayer()->getPosition(left, top);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pos.left -= mCroppedParent->getAbsoluteLeft ();
|
|
||||||
pos.top -= mCroppedParent->getAbsoluteTop ();
|
|
||||||
|
|
||||||
if (mLastDown == id)
|
|
||||||
{
|
{
|
||||||
Style * item = mBook->hitTestWithMargin (pos.left, mViewTop + pos.top);
|
Style * item = pos->top <= mViewBottom ? mBook->hitTestWithMargin (pos->left, pos->top) : nullptr;
|
||||||
|
|
||||||
bool clicked = mFocusItem == item;
|
bool clicked = mFocusItem == item;
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,6 @@
|
||||||
|
|
||||||
#include "itemmodel.hpp"
|
#include "itemmodel.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
|
||||||
{
|
|
||||||
class Environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MyGUI
|
namespace MyGUI
|
||||||
{
|
{
|
||||||
class Gui;
|
class Gui;
|
||||||
|
@ -19,7 +14,6 @@ namespace MyGUI
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class WindowManager;
|
|
||||||
class ContainerWindow;
|
class ContainerWindow;
|
||||||
class ItemView;
|
class ItemView;
|
||||||
class SortFilterItemModel;
|
class SortFilterItemModel;
|
||||||
|
|
|
@ -148,7 +148,7 @@ namespace MWGui
|
||||||
// We need this copy for when @# hyperlinks are replaced
|
// We need this copy for when @# hyperlinks are replaced
|
||||||
std::string text = mText;
|
std::string text = mText;
|
||||||
|
|
||||||
size_t pos_end;
|
size_t pos_end = std::string::npos;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
size_t pos_begin = text.find('@');
|
size_t pos_begin = text.find('@');
|
||||||
|
|
|
@ -15,11 +15,6 @@ namespace Gui
|
||||||
class MWList;
|
class MWList;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWGui
|
|
||||||
{
|
|
||||||
class WindowManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class ResponseCallback;
|
class ResponseCallback;
|
||||||
|
|
|
@ -71,13 +71,8 @@ namespace MWGui
|
||||||
, mLastYSize(0)
|
, mLastYSize(0)
|
||||||
, mPreview(new MWRender::InventoryPreview(parent, resourceSystem, MWMechanics::getPlayer()))
|
, mPreview(new MWRender::InventoryPreview(parent, resourceSystem, MWMechanics::getPlayer()))
|
||||||
, mTrading(false)
|
, mTrading(false)
|
||||||
, mScaleFactor(1.0f)
|
|
||||||
, mUpdateTimer(0.f)
|
, mUpdateTimer(0.f)
|
||||||
{
|
{
|
||||||
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
|
||||||
if (uiScale > 1.0)
|
|
||||||
mScaleFactor = uiScale;
|
|
||||||
|
|
||||||
mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture()));
|
mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture()));
|
||||||
mPreview->rebuild();
|
mPreview->rebuild();
|
||||||
|
|
||||||
|
@ -473,10 +468,11 @@ namespace MWGui
|
||||||
MyGUI::IntSize size = mAvatarImage->getSize();
|
MyGUI::IntSize size = mAvatarImage->getSize();
|
||||||
int width = std::min(mPreview->getTextureWidth(), size.width);
|
int width = std::min(mPreview->getTextureWidth(), size.width);
|
||||||
int height = std::min(mPreview->getTextureHeight(), size.height);
|
int height = std::min(mPreview->getTextureHeight(), size.height);
|
||||||
mPreview->setViewport(int(width*mScaleFactor), int(height*mScaleFactor));
|
float scalingFactor = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
||||||
|
mPreview->setViewport(int(width*scalingFactor), int(height*scalingFactor));
|
||||||
|
|
||||||
mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f,
|
mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f,
|
||||||
width*mScaleFactor/float(mPreview->getTextureWidth()), height*mScaleFactor/float(mPreview->getTextureHeight())));
|
width*scalingFactor/float(mPreview->getTextureWidth()), height*scalingFactor/float(mPreview->getTextureHeight())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryWindow::onNameFilterChanged(MyGUI::EditBox* _sender)
|
void InventoryWindow::onNameFilterChanged(MyGUI::EditBox* _sender)
|
||||||
|
@ -641,8 +637,9 @@ namespace MWGui
|
||||||
y = (mAvatarImage->getHeight()-1) - y;
|
y = (mAvatarImage->getHeight()-1) - y;
|
||||||
|
|
||||||
// Scale coordinates
|
// Scale coordinates
|
||||||
x = int(x*mScaleFactor);
|
float scalingFactor = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
||||||
y = int(y*mScaleFactor);
|
x = static_cast<int>(x*scalingFactor);
|
||||||
|
y = static_cast<int>(y*scalingFactor);
|
||||||
|
|
||||||
int slot = mPreview->getSlotSelected (x, y);
|
int slot = mPreview->getSlotSelected (x, y);
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,6 @@ namespace MWGui
|
||||||
std::unique_ptr<MWRender::InventoryPreview> mPreview;
|
std::unique_ptr<MWRender::InventoryPreview> mPreview;
|
||||||
|
|
||||||
bool mTrading;
|
bool mTrading;
|
||||||
float mScaleFactor;
|
|
||||||
float mUpdateTimer;
|
float mUpdateTimer;
|
||||||
|
|
||||||
void toggleMaximized();
|
void toggleMaximized();
|
||||||
|
|
|
@ -129,7 +129,7 @@ struct JournalViewModelImpl : JournalViewModel
|
||||||
|
|
||||||
utf8text.replace(pos_begin, pos_end+1-pos_begin, displayName);
|
utf8text.replace(pos_begin, pos_end+1-pos_begin, displayName);
|
||||||
|
|
||||||
intptr_t value;
|
intptr_t value = 0;
|
||||||
if (mModel->mKeywordSearch.containsKeyword(topicName, value))
|
if (mModel->mKeywordSearch.containsKeyword(topicName, value))
|
||||||
mHyperLinks[std::make_pair(pos_begin, pos_begin+displayName.size())] = value;
|
mHyperLinks[std::make_pair(pos_begin, pos_begin+displayName.size())] = value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,6 @@
|
||||||
#include <MyGUI_RenderManager.h>
|
#include <MyGUI_RenderManager.h>
|
||||||
|
|
||||||
|
|
||||||
namespace MWGui
|
|
||||||
{
|
|
||||||
class WindowManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
class RaceSelectionPreview;
|
class RaceSelectionPreview;
|
||||||
|
|
|
@ -11,11 +11,6 @@ namespace ESM
|
||||||
struct Spell;
|
struct Spell;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWGui
|
|
||||||
{
|
|
||||||
class WindowManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class ReviewDialog : public WindowModal
|
class ReviewDialog : public WindowModal
|
||||||
|
|
|
@ -11,12 +11,16 @@
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
#include <components/misc/constants.hpp>
|
#include <components/misc/constants.hpp>
|
||||||
#include <components/widgets/sharedstatebutton.hpp>
|
#include <components/widgets/sharedstatebutton.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
#include <components/resource/scenemanager.hpp>
|
||||||
|
#include <components/sceneutil/lightmanager.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -69,6 +73,9 @@ namespace
|
||||||
std::string getAspect (int x, int y)
|
std::string getAspect (int x, int y)
|
||||||
{
|
{
|
||||||
int gcd = std::gcd (x, y);
|
int gcd = std::gcd (x, y);
|
||||||
|
if (gcd == 0)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
int xaspect = x / gcd;
|
int xaspect = x / gcd;
|
||||||
int yaspect = y / gcd;
|
int yaspect = y / gcd;
|
||||||
// special case: 8 : 5 is usually referred to as 16:10
|
// special case: 8 : 5 is usually referred to as 16:10
|
||||||
|
@ -111,11 +118,24 @@ namespace
|
||||||
if (!widget->getUserString(settingMax).empty())
|
if (!widget->getUserString(settingMax).empty())
|
||||||
max = MyGUI::utility::parseFloat(widget->getUserString(settingMax));
|
max = MyGUI::utility::parseFloat(widget->getUserString(settingMax));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateMaxLightsComboBox(MyGUI::ComboBox* box)
|
||||||
|
{
|
||||||
|
constexpr int min = 8;
|
||||||
|
constexpr int max = 32;
|
||||||
|
constexpr int increment = 8;
|
||||||
|
int maxLights = Settings::Manager::getInt("max lights", "Shaders");
|
||||||
|
// show increments of 8 in dropdown
|
||||||
|
if (maxLights >= min && maxLights <= max && !(maxLights % increment))
|
||||||
|
box->setIndexSelected((maxLights / increment)-1);
|
||||||
|
else
|
||||||
|
box->setIndexSelected(MyGUI::ITEM_NONE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
void SettingsWindow::configureWidgets(MyGUI::Widget* widget)
|
void SettingsWindow::configureWidgets(MyGUI::Widget* widget, bool init)
|
||||||
{
|
{
|
||||||
MyGUI::EnumeratorWidgetPtr widgets = widget->getEnumerator();
|
MyGUI::EnumeratorWidgetPtr widgets = widget->getEnumerator();
|
||||||
while (widgets.next())
|
while (widgets.next())
|
||||||
|
@ -129,7 +149,8 @@ namespace MWGui
|
||||||
getSettingCategory(current))
|
getSettingCategory(current))
|
||||||
? "#{sOn}" : "#{sOff}";
|
? "#{sOn}" : "#{sOff}";
|
||||||
current->castType<MyGUI::Button>()->setCaptionWithReplacing(initialValue);
|
current->castType<MyGUI::Button>()->setCaptionWithReplacing(initialValue);
|
||||||
current->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
|
if (init)
|
||||||
|
current->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
|
||||||
}
|
}
|
||||||
if (type == sliderType)
|
if (type == sliderType)
|
||||||
{
|
{
|
||||||
|
@ -149,6 +170,12 @@ namespace MWGui
|
||||||
ss << std::fixed << std::setprecision(2) << value/Constants::CellSizeInUnits;
|
ss << std::fixed << std::setprecision(2) << value/Constants::CellSizeInUnits;
|
||||||
valueStr = ss.str();
|
valueStr = ss.str();
|
||||||
}
|
}
|
||||||
|
else if (valueType == "Float")
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::fixed << std::setprecision(2) << value;
|
||||||
|
valueStr = ss.str();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
valueStr = MyGUI::utility::toString(int(value));
|
valueStr = MyGUI::utility::toString(int(value));
|
||||||
|
|
||||||
|
@ -163,12 +190,13 @@ namespace MWGui
|
||||||
valueStr = MyGUI::utility::toString(value);
|
valueStr = MyGUI::utility::toString(value);
|
||||||
scroll->setScrollPosition(value);
|
scroll->setScrollPosition(value);
|
||||||
}
|
}
|
||||||
scroll->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition);
|
if (init)
|
||||||
|
scroll->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition);
|
||||||
if (scroll->getVisible())
|
if (scroll->getVisible())
|
||||||
updateSliderLabel(scroll, valueStr);
|
updateSliderLabel(scroll, valueStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
configureWidgets(current);
|
configureWidgets(current, init);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +227,7 @@ namespace MWGui
|
||||||
getWidget(unusedSlider, widgetName);
|
getWidget(unusedSlider, widgetName);
|
||||||
unusedSlider->setVisible(false);
|
unusedSlider->setVisible(false);
|
||||||
|
|
||||||
configureWidgets(mMainWidget);
|
configureWidgets(mMainWidget, true);
|
||||||
|
|
||||||
setTitle("#{sOptions}");
|
setTitle("#{sOptions}");
|
||||||
|
|
||||||
|
@ -216,6 +244,9 @@ namespace MWGui
|
||||||
getWidget(mControllerSwitch, "ControllerButton");
|
getWidget(mControllerSwitch, "ControllerButton");
|
||||||
getWidget(mWaterTextureSize, "WaterTextureSize");
|
getWidget(mWaterTextureSize, "WaterTextureSize");
|
||||||
getWidget(mWaterReflectionDetail, "WaterReflectionDetail");
|
getWidget(mWaterReflectionDetail, "WaterReflectionDetail");
|
||||||
|
getWidget(mLightingMethodButton, "LightingMethodButton");
|
||||||
|
getWidget(mLightsResetButton, "LightsResetButton");
|
||||||
|
getWidget(mMaxLights, "MaxLights");
|
||||||
|
|
||||||
if (MWBase::Environment::get().getVrMode())
|
if (MWBase::Environment::get().getVrMode())
|
||||||
{
|
{
|
||||||
|
@ -247,6 +278,10 @@ namespace MWGui
|
||||||
mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged);
|
mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged);
|
||||||
mWaterReflectionDetail->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterReflectionDetailChanged);
|
mWaterReflectionDetail->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterReflectionDetailChanged);
|
||||||
|
|
||||||
|
mLightingMethodButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onLightingMethodButtonChanged);
|
||||||
|
mLightsResetButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onLightsResetButtonClicked);
|
||||||
|
mMaxLights->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onMaxLightsChanged);
|
||||||
|
|
||||||
mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked);
|
mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked);
|
||||||
mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked);
|
mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked);
|
||||||
|
|
||||||
|
@ -273,8 +308,10 @@ namespace MWGui
|
||||||
std::sort(resolutions.begin(), resolutions.end(), sortResolutions);
|
std::sort(resolutions.begin(), resolutions.end(), sortResolutions);
|
||||||
for (std::pair<int, int>& resolution : resolutions)
|
for (std::pair<int, int>& resolution : resolutions)
|
||||||
{
|
{
|
||||||
std::string str = MyGUI::utility::toString(resolution.first) + " x " + MyGUI::utility::toString(resolution.second)
|
std::string str = MyGUI::utility::toString(resolution.first) + " x " + MyGUI::utility::toString(resolution.second);
|
||||||
+ " (" + getAspect(resolution.first, resolution.second) + ")";
|
std::string aspect = getAspect(resolution.first, resolution.second);
|
||||||
|
if (!aspect.empty())
|
||||||
|
str = str + " (" + aspect + ")";
|
||||||
|
|
||||||
if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE)
|
if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE)
|
||||||
mResolutionList->addItem(str);
|
mResolutionList->addItem(str);
|
||||||
|
@ -309,6 +346,8 @@ namespace MWGui
|
||||||
waterReflectionDetail = std::min(5, std::max(0, waterReflectionDetail));
|
waterReflectionDetail = std::min(5, std::max(0, waterReflectionDetail));
|
||||||
mWaterReflectionDetail->setIndexSelected(waterReflectionDetail);
|
mWaterReflectionDetail->setIndexSelected(waterReflectionDetail);
|
||||||
|
|
||||||
|
updateMaxLightsComboBox(mMaxLights);
|
||||||
|
|
||||||
mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video"));
|
mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video"));
|
||||||
|
|
||||||
mKeyboardSwitch->setStateSelected(true);
|
mKeyboardSwitch->setStateSelected(true);
|
||||||
|
@ -409,6 +448,54 @@ namespace MWGui
|
||||||
apply();
|
apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsWindow::onLightingMethodButtonChanged(MyGUI::ComboBox* _sender, size_t pos)
|
||||||
|
{
|
||||||
|
if (pos == MyGUI::ITEM_NONE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string message = "This change requires a restart to take effect.";
|
||||||
|
MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, {"#{sOK}"}, true);
|
||||||
|
|
||||||
|
Settings::Manager::setString("lighting method", "Shaders", _sender->getItemNameAt(pos));
|
||||||
|
apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsWindow::onMaxLightsChanged(MyGUI::ComboBox* _sender, size_t pos)
|
||||||
|
{
|
||||||
|
int count = 8 * (pos + 1);
|
||||||
|
|
||||||
|
Settings::Manager::setInt("max lights", "Shaders", count);
|
||||||
|
apply();
|
||||||
|
configureWidgets(mMainWidget, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsWindow::onLightsResetButtonClicked(MyGUI::Widget* _sender)
|
||||||
|
{
|
||||||
|
std::vector<std::string> buttons = {"#{sYes}", "#{sNo}"};
|
||||||
|
std::string message = "Resets to default values, would you like to continue? Changes to lighting method will require a restart.";
|
||||||
|
MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons, true);
|
||||||
|
int selectedButton = MWBase::Environment::get().getWindowManager()->readPressedButton();
|
||||||
|
if (selectedButton == 1 || selectedButton == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
constexpr std::array<const char*, 6> settings = {
|
||||||
|
"light bounds multiplier",
|
||||||
|
"maximum light distance",
|
||||||
|
"light fade start",
|
||||||
|
"minimum interior brightness",
|
||||||
|
"max lights",
|
||||||
|
"lighting method",
|
||||||
|
};
|
||||||
|
for (const auto& setting : settings)
|
||||||
|
Settings::Manager::setString(setting, "Shaders", Settings::Manager::mDefaultSettings[{"Shaders", setting}]);
|
||||||
|
|
||||||
|
mLightingMethodButton->setIndexSelected(mLightingMethodButton->findItemIndexWith(Settings::Manager::mDefaultSettings[{"Shaders", "lighting method"}]));
|
||||||
|
updateMaxLightsComboBox(mMaxLights);
|
||||||
|
|
||||||
|
apply();
|
||||||
|
configureWidgets(mMainWidget, false);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender)
|
void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender)
|
||||||
{
|
{
|
||||||
std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On");
|
std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On");
|
||||||
|
@ -511,6 +598,12 @@ namespace MWGui
|
||||||
ss << std::fixed << std::setprecision(2) << value/Constants::CellSizeInUnits;
|
ss << std::fixed << std::setprecision(2) << value/Constants::CellSizeInUnits;
|
||||||
valueStr = ss.str();
|
valueStr = ss.str();
|
||||||
}
|
}
|
||||||
|
else if (valueType == "Float")
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::fixed << std::setprecision(2) << value;
|
||||||
|
valueStr = ss.str();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
valueStr = MyGUI::utility::toString(int(value));
|
valueStr = MyGUI::utility::toString(int(value));
|
||||||
}
|
}
|
||||||
|
@ -609,6 +702,30 @@ namespace MWGui
|
||||||
layoutControlsBox();
|
layoutControlsBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsWindow::updateLightSettings()
|
||||||
|
{
|
||||||
|
auto lightingMethod = MWBase::Environment::get().getResourceSystem()->getSceneManager()->getLightingMethod();
|
||||||
|
std::string lightingMethodStr = SceneUtil::LightManager::getLightingMethodString(lightingMethod);
|
||||||
|
|
||||||
|
mLightingMethodButton->removeAllItems();
|
||||||
|
|
||||||
|
std::array<SceneUtil::LightingMethod, 3> methods = {
|
||||||
|
SceneUtil::LightingMethod::FFP,
|
||||||
|
SceneUtil::LightingMethod::PerObjectUniform,
|
||||||
|
SceneUtil::LightingMethod::SingleUBO,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& method : methods)
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getResourceSystem()->getSceneManager()->isSupportedLightingMethod(method))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mLightingMethodButton->addItem(SceneUtil::LightManager::getLightingMethodString(method));
|
||||||
|
}
|
||||||
|
|
||||||
|
mLightingMethodButton->setIndexSelected(mLightingMethodButton->findItemIndexWith(lightingMethodStr));
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsWindow::layoutControlsBox()
|
void SettingsWindow::layoutControlsBox()
|
||||||
{
|
{
|
||||||
const int h = 18;
|
const int h = 18;
|
||||||
|
@ -671,6 +788,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
highlightCurrentResolution();
|
highlightCurrentResolution();
|
||||||
updateControlsBox();
|
updateControlsBox();
|
||||||
|
updateLightSettings();
|
||||||
resetScrollbars();
|
resetScrollbars();
|
||||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton);
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,6 @@
|
||||||
|
|
||||||
#include "windowbase.hpp"
|
#include "windowbase.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
|
||||||
{
|
|
||||||
class WindowManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class SettingsWindow : public WindowBase
|
class SettingsWindow : public WindowBase
|
||||||
|
@ -19,6 +14,8 @@ namespace MWGui
|
||||||
|
|
||||||
void updateControlsBox();
|
void updateControlsBox();
|
||||||
|
|
||||||
|
void updateLightSettings();
|
||||||
|
|
||||||
void onResChange(int, int) override { center(); }
|
void onResChange(int, int) override { center(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -39,6 +36,10 @@ namespace MWGui
|
||||||
MyGUI::ComboBox* mWaterTextureSize;
|
MyGUI::ComboBox* mWaterTextureSize;
|
||||||
MyGUI::ComboBox* mWaterReflectionDetail;
|
MyGUI::ComboBox* mWaterReflectionDetail;
|
||||||
|
|
||||||
|
MyGUI::ComboBox* mMaxLights;
|
||||||
|
MyGUI::ComboBox* mLightingMethodButton;
|
||||||
|
MyGUI::Button* mLightsResetButton;
|
||||||
|
|
||||||
// controls
|
// controls
|
||||||
MyGUI::ScrollView* mControlsBox;
|
MyGUI::ScrollView* mControlsBox;
|
||||||
MyGUI::Button* mResetControlsButton;
|
MyGUI::Button* mResetControlsButton;
|
||||||
|
@ -62,6 +63,10 @@ namespace MWGui
|
||||||
void onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos);
|
void onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos);
|
||||||
void onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos);
|
void onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos);
|
||||||
|
|
||||||
|
void onLightingMethodButtonChanged(MyGUI::ComboBox* _sender, size_t pos);
|
||||||
|
void onLightsResetButtonClicked(MyGUI::Widget* _sender);
|
||||||
|
void onMaxLightsChanged(MyGUI::ComboBox* _sender, size_t pos);
|
||||||
|
|
||||||
void onRebindAction(MyGUI::Widget* _sender);
|
void onRebindAction(MyGUI::Widget* _sender);
|
||||||
void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel);
|
void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel);
|
||||||
void onResetDefaultBindings(MyGUI::Widget* _sender);
|
void onResetDefaultBindings(MyGUI::Widget* _sender);
|
||||||
|
@ -73,7 +78,7 @@ namespace MWGui
|
||||||
|
|
||||||
void apply();
|
void apply();
|
||||||
|
|
||||||
void configureWidgets(MyGUI::Widget* widget);
|
void configureWidgets(MyGUI::Widget* widget, bool init);
|
||||||
void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value);
|
void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value);
|
||||||
|
|
||||||
void layoutControlsBox();
|
void layoutControlsBox();
|
||||||
|
|
|
@ -15,11 +15,6 @@ namespace MyGUI
|
||||||
class Widget;
|
class Widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWGui
|
|
||||||
{
|
|
||||||
class WindowManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class SpellBuyingWindow : public ReferenceInterface, public WindowBase
|
class SpellBuyingWindow : public ReferenceInterface, public WindowBase
|
||||||
|
|
|
@ -393,7 +393,8 @@ namespace MWGui
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
|
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
|
||||||
|
|
||||||
if (MyGUI::utility::parseInt(mPriceLabel->getCaption()) > playerGold)
|
int price = MyGUI::utility::parseInt(mPriceLabel->getCaption());
|
||||||
|
if (price > playerGold)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}");
|
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}");
|
||||||
return;
|
return;
|
||||||
|
@ -401,8 +402,6 @@ namespace MWGui
|
||||||
|
|
||||||
mSpell.mName = mNameEdit->getCaption();
|
mSpell.mName = mNameEdit->getCaption();
|
||||||
|
|
||||||
int price = MyGUI::utility::parseInt(mPriceLabel->getCaption());
|
|
||||||
|
|
||||||
player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player);
|
player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player);
|
||||||
|
|
||||||
// add gold to NPC trading gold pool
|
// add gold to NPC trading gold pool
|
||||||
|
|
|
@ -97,7 +97,7 @@ namespace MWGui
|
||||||
int windowHeight = window->getSize().height;
|
int windowHeight = window->getSize().height;
|
||||||
|
|
||||||
//initial values defined in openmw_stats_window.layout, if custom options are not present in .layout, a default is loaded
|
//initial values defined in openmw_stats_window.layout, if custom options are not present in .layout, a default is loaded
|
||||||
float leftPaneRatio = 0.44;
|
float leftPaneRatio = 0.44f;
|
||||||
if (mLeftPane->isUserString("LeftPaneRatio"))
|
if (mLeftPane->isUserString("LeftPaneRatio"))
|
||||||
leftPaneRatio = MyGUI::utility::parseFloat(mLeftPane->getUserString("LeftPaneRatio"));
|
leftPaneRatio = MyGUI::utility::parseFloat(mLeftPane->getUserString("LeftPaneRatio"));
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class WindowManager;
|
|
||||||
|
|
||||||
class StatsWindow : public WindowPinnableBase, public NoDrop, public StatsListener
|
class StatsWindow : public WindowPinnableBase, public NoDrop, public StatsListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -3,11 +3,6 @@
|
||||||
|
|
||||||
#include "windowbase.hpp"
|
#include "windowbase.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
|
||||||
{
|
|
||||||
class WindowManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class TextInputDialog : public WindowModal
|
class TextInputDialog : public WindowModal
|
||||||
|
|
|
@ -58,12 +58,12 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int TimeAdvancer::getHours()
|
int TimeAdvancer::getHours() const
|
||||||
{
|
{
|
||||||
return mHours;
|
return mHours;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TimeAdvancer::isRunning()
|
bool TimeAdvancer::isRunning() const
|
||||||
{
|
{
|
||||||
return mRunning;
|
return mRunning;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@ namespace MWGui
|
||||||
void stop();
|
void stop();
|
||||||
void onFrame(float dt);
|
void onFrame(float dt);
|
||||||
|
|
||||||
int getHours();
|
int getHours() const;
|
||||||
bool isRunning();
|
bool isRunning() const;
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||||
|
|
|
@ -11,12 +11,6 @@ namespace MyGUI
|
||||||
class Widget;
|
class Widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWGui
|
|
||||||
{
|
|
||||||
class WindowManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class TravelWindow : public ReferenceInterface, public WindowBase
|
class TravelWindow : public ReferenceInterface, public WindowBase
|
||||||
|
|
|
@ -3,11 +3,6 @@
|
||||||
|
|
||||||
#include "layout.hpp"
|
#include "layout.hpp"
|
||||||
|
|
||||||
namespace MWBase
|
|
||||||
{
|
|
||||||
class WindowManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class Ptr;
|
class Ptr;
|
||||||
|
@ -15,7 +10,6 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class WindowManager;
|
|
||||||
class DragAndDrop;
|
class DragAndDrop;
|
||||||
|
|
||||||
class WindowBase: public Layout
|
class WindowBase: public Layout
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "windowmanagerimp.hpp"
|
#include "windowmanagerimp.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
@ -199,8 +200,8 @@ namespace MWGui
|
||||||
, mVersionDescription(versionDescription)
|
, mVersionDescription(versionDescription)
|
||||||
, mWindowVisible(true)
|
, mWindowVisible(true)
|
||||||
{
|
{
|
||||||
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
mScalingFactor = std::clamp(Settings::Manager::getFloat("scaling factor", "GUI"), 0.5f, 8.f);
|
||||||
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(), uiScale);
|
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(), mScalingFactor);
|
||||||
mGuiPlatform->initialise(resourcePath, (boost::filesystem::path(logpath) / "MyGUI.log").generic_string());
|
mGuiPlatform->initialise(resourcePath, (boost::filesystem::path(logpath) / "MyGUI.log").generic_string());
|
||||||
|
|
||||||
|
|
||||||
|
@ -216,7 +217,7 @@ namespace MWGui
|
||||||
MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag);
|
MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag);
|
||||||
|
|
||||||
// Load fonts
|
// Load fonts
|
||||||
mFontLoader.reset(new Gui::FontLoader(encoding, resourceSystem->getVFS(), userDataPath));
|
mFontLoader.reset(new Gui::FontLoader(encoding, resourceSystem->getVFS(), userDataPath, mScalingFactor));
|
||||||
mFontLoader->loadBitmapFonts(exportFonts);
|
mFontLoader->loadBitmapFonts(exportFonts);
|
||||||
|
|
||||||
//Register own widgets with MyGUI
|
//Register own widgets with MyGUI
|
||||||
|
@ -1372,6 +1373,11 @@ namespace MWGui
|
||||||
return mHud->getWorldMouseOver();
|
return mHud->getWorldMouseOver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float WindowManager::getScalingFactor()
|
||||||
|
{
|
||||||
|
return mScalingFactor;
|
||||||
|
}
|
||||||
|
|
||||||
void WindowManager::executeInConsole (const std::string& path)
|
void WindowManager::executeInConsole (const std::string& path)
|
||||||
{
|
{
|
||||||
mConsole->executeFile (path);
|
mConsole->executeFile (path);
|
||||||
|
|
|
@ -120,7 +120,6 @@ namespace MWGui
|
||||||
class TrainingWindow;
|
class TrainingWindow;
|
||||||
class SpellIcons;
|
class SpellIcons;
|
||||||
class MerchantRepair;
|
class MerchantRepair;
|
||||||
class Repair;
|
|
||||||
class SoulgemDialog;
|
class SoulgemDialog;
|
||||||
class Recharge;
|
class Recharge;
|
||||||
class CompanionWindow;
|
class CompanionWindow;
|
||||||
|
@ -216,6 +215,8 @@ namespace MWGui
|
||||||
void setDragDrop(bool dragDrop) override;
|
void setDragDrop(bool dragDrop) override;
|
||||||
bool getWorldMouseOver() override;
|
bool getWorldMouseOver() override;
|
||||||
|
|
||||||
|
float getScalingFactor() override;
|
||||||
|
|
||||||
bool toggleFogOfWar() override;
|
bool toggleFogOfWar() override;
|
||||||
bool toggleFullHelp() override; ///< show extra info in item tooltips (owner, script)
|
bool toggleFullHelp() override; ///< show extra info in item tooltips (owner, script)
|
||||||
bool getFullHelp() const override;
|
bool getFullHelp() const override;
|
||||||
|
@ -532,6 +533,8 @@ namespace MWGui
|
||||||
|
|
||||||
SDLUtil::VideoWrapper* mVideoWrapper;
|
SDLUtil::VideoWrapper* mVideoWrapper;
|
||||||
|
|
||||||
|
float mScalingFactor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property.
|
* Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property.
|
||||||
* Supported syntax:
|
* Supported syntax:
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class WindowManager;
|
|
||||||
|
|
||||||
class WindowPinnableBase: public WindowBase
|
class WindowPinnableBase: public WindowBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -32,7 +32,6 @@ namespace MWInput
|
||||||
, mMouseManager(mouseManager)
|
, mMouseManager(mouseManager)
|
||||||
, mJoystickEnabled (Settings::Manager::getBool("enable controller", "Input"))
|
, mJoystickEnabled (Settings::Manager::getBool("enable controller", "Input"))
|
||||||
, mGamepadCursorSpeed(Settings::Manager::getFloat("gamepad cursor speed", "Input"))
|
, mGamepadCursorSpeed(Settings::Manager::getFloat("gamepad cursor speed", "Input"))
|
||||||
, mInvUiScalingFactor(1.f)
|
|
||||||
, mSneakToggleShortcutTimer(0.f)
|
, mSneakToggleShortcutTimer(0.f)
|
||||||
, mGamepadZoom(0)
|
, mGamepadZoom(0)
|
||||||
, mGamepadGuiCursorEnabled(true)
|
, mGamepadGuiCursorEnabled(true)
|
||||||
|
@ -69,10 +68,6 @@ namespace MWInput
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
|
||||||
if (uiScale != 0.f)
|
|
||||||
mInvUiScalingFactor = 1.f / uiScale;
|
|
||||||
|
|
||||||
float deadZoneRadius = Settings::Manager::getFloat("joystick dead zone", "Input");
|
float deadZoneRadius = Settings::Manager::getFloat("joystick dead zone", "Input");
|
||||||
deadZoneRadius = std::min(std::max(deadZoneRadius, 0.0f), 0.5f);
|
deadZoneRadius = std::min(std::max(deadZoneRadius, 0.0f), 0.5f);
|
||||||
mBindingsManager->setJoystickDeadZone(deadZoneRadius);
|
mBindingsManager->setJoystickDeadZone(deadZoneRadius);
|
||||||
|
@ -102,8 +97,10 @@ namespace MWInput
|
||||||
|
|
||||||
// We keep track of our own mouse position, so that moving the mouse while in
|
// We keep track of our own mouse position, so that moving the mouse while in
|
||||||
// game mode does not move the position of the GUI cursor
|
// game mode does not move the position of the GUI cursor
|
||||||
float xMove = xAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
|
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
||||||
float yMove = yAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
|
float xMove = xAxis * dt * 1500.0f / uiScale;
|
||||||
|
float yMove = yAxis * dt * 1500.0f / uiScale;
|
||||||
|
|
||||||
float mouseWheelMove = -zAxis * dt * 1500.0f;
|
float mouseWheelMove = -zAxis * dt * 1500.0f;
|
||||||
if (xMove != 0 || yMove != 0 || mouseWheelMove != 0)
|
if (xMove != 0 || yMove != 0 || mouseWheelMove != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,7 +52,6 @@ namespace MWInput
|
||||||
|
|
||||||
bool mJoystickEnabled;
|
bool mJoystickEnabled;
|
||||||
float mGamepadCursorSpeed;
|
float mGamepadCursorSpeed;
|
||||||
float mInvUiScalingFactor;
|
|
||||||
float mSneakToggleShortcutTimer;
|
float mSneakToggleShortcutTimer;
|
||||||
float mGamepadZoom;
|
float mGamepadZoom;
|
||||||
bool mGamepadGuiCursorEnabled;
|
bool mGamepadGuiCursorEnabled;
|
||||||
|
|
|
@ -29,22 +29,18 @@ namespace MWInput
|
||||||
, mCameraYMultiplier(Settings::Manager::getFloat("camera y multiplier", "Input"))
|
, mCameraYMultiplier(Settings::Manager::getFloat("camera y multiplier", "Input"))
|
||||||
, mBindingsManager(bindingsManager)
|
, mBindingsManager(bindingsManager)
|
||||||
, mInputWrapper(inputWrapper)
|
, mInputWrapper(inputWrapper)
|
||||||
, mInvUiScalingFactor(1.f)
|
|
||||||
, mGuiCursorX(0)
|
, mGuiCursorX(0)
|
||||||
, mGuiCursorY(0)
|
, mGuiCursorY(0)
|
||||||
, mMouseWheel(0)
|
, mMouseWheel(0)
|
||||||
, mMouseLookEnabled(false)
|
, mMouseLookEnabled(false)
|
||||||
, mGuiCursorEnabled(true)
|
, mGuiCursorEnabled(true)
|
||||||
{
|
{
|
||||||
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
|
||||||
if (uiScale != 0.f)
|
|
||||||
mInvUiScalingFactor = 1.f / uiScale;
|
|
||||||
|
|
||||||
int w,h;
|
int w,h;
|
||||||
SDL_GetWindowSize(window, &w, &h);
|
SDL_GetWindowSize(window, &w, &h);
|
||||||
|
|
||||||
mGuiCursorX = mInvUiScalingFactor * w / 2.f;
|
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
||||||
mGuiCursorY = mInvUiScalingFactor * h / 2.f;
|
mGuiCursorX = w / (2.f * uiScale);
|
||||||
|
mGuiCursorY = h / (2.f * uiScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
void MouseManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||||
|
@ -82,8 +78,9 @@ namespace MWInput
|
||||||
|
|
||||||
// We keep track of our own mouse position, so that moving the mouse while in
|
// We keep track of our own mouse position, so that moving the mouse while in
|
||||||
// game mode does not move the position of the GUI cursor
|
// game mode does not move the position of the GUI cursor
|
||||||
mGuiCursorX = static_cast<float>(arg.x) * mInvUiScalingFactor;
|
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
||||||
mGuiCursorY = static_cast<float>(arg.y) * mInvUiScalingFactor;
|
mGuiCursorX = static_cast<float>(arg.x) / uiScale;
|
||||||
|
mGuiCursorY = static_cast<float>(arg.y) / uiScale;
|
||||||
|
|
||||||
mMouseWheel = static_cast<int>(arg.z);
|
mMouseWheel = static_cast<int>(arg.z);
|
||||||
|
|
||||||
|
@ -254,17 +251,14 @@ namespace MWInput
|
||||||
|
|
||||||
void MouseManager::warpMouse()
|
void MouseManager::warpMouse()
|
||||||
{
|
{
|
||||||
mInputWrapper->warpMouse(static_cast<int>(mGuiCursorX / mInvUiScalingFactor), static_cast<int>(mGuiCursorY / mInvUiScalingFactor));
|
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
||||||
|
mInputWrapper->warpMouse(static_cast<int>(mGuiCursorX*uiScale), static_cast<int>(mGuiCursorY*uiScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseManager::setMousePosition(int x, int y)
|
void MouseManager::setMousePosition(int x, int y)
|
||||||
{
|
{
|
||||||
mGuiCursorX = x * mInvUiScalingFactor;
|
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
||||||
mGuiCursorY = y * mInvUiScalingFactor;
|
mGuiCursorX = x / uiScale;
|
||||||
}
|
mGuiCursorY = y / uiScale;
|
||||||
|
|
||||||
void MouseManager::setGUIScale(float scale)
|
|
||||||
{
|
|
||||||
mInvUiScalingFactor = 1.f / scale;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ namespace MWInput
|
||||||
|
|
||||||
// Used to override mouse position when using controllers not through SDL, such as OpenXR.
|
// Used to override mouse position when using controllers not through SDL, such as OpenXR.
|
||||||
void setMousePosition(int x, int y);
|
void setMousePosition(int x, int y);
|
||||||
void setGUIScale(float scale);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool mInvertX;
|
bool mInvertX;
|
||||||
|
@ -51,7 +50,6 @@ namespace MWInput
|
||||||
|
|
||||||
BindingsManager* mBindingsManager;
|
BindingsManager* mBindingsManager;
|
||||||
SDLUtil::InputWrapper* mInputWrapper;
|
SDLUtil::InputWrapper* mInputWrapper;
|
||||||
float mInvUiScalingFactor;
|
|
||||||
|
|
||||||
float mGuiCursorX;
|
float mGuiCursorX;
|
||||||
float mGuiCursorY;
|
float mGuiCursorY;
|
||||||
|
|
|
@ -432,7 +432,8 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
|
void Actors::updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
|
||||||
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance)
|
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance,
|
||||||
|
bool inCombatOrPursue)
|
||||||
{
|
{
|
||||||
if (!actor.getRefData().getBaseNode())
|
if (!actor.getRefData().getBaseNode())
|
||||||
return;
|
return;
|
||||||
|
@ -453,7 +454,7 @@ namespace MWMechanics
|
||||||
const osg::Vec3f actor2Pos(targetActor.getRefData().getPosition().asVec3());
|
const osg::Vec3f actor2Pos(targetActor.getRefData().getPosition().asVec3());
|
||||||
float sqrDist = (actor1Pos - actor2Pos).length2();
|
float sqrDist = (actor1Pos - actor2Pos).length2();
|
||||||
|
|
||||||
if (sqrDist > std::min(maxDistance * maxDistance, sqrHeadTrackDistance))
|
if (sqrDist > std::min(maxDistance * maxDistance, sqrHeadTrackDistance) && !inCombatOrPursue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// stop tracking when target is behind the actor
|
// stop tracking when target is behind the actor
|
||||||
|
@ -461,7 +462,7 @@ namespace MWMechanics
|
||||||
osg::Vec3f targetDirection(actor2Pos - actor1Pos);
|
osg::Vec3f targetDirection(actor2Pos - actor1Pos);
|
||||||
actorDirection.z() = 0;
|
actorDirection.z() = 0;
|
||||||
targetDirection.z() = 0;
|
targetDirection.z() = 0;
|
||||||
if (actorDirection * targetDirection > 0
|
if ((actorDirection * targetDirection > 0 || inCombatOrPursue)
|
||||||
&& MWBase::Environment::get().getWorld()->getLOS(actor, targetActor) // check LOS and awareness last as it's the most expensive function
|
&& MWBase::Environment::get().getWorld()->getLOS(actor, targetActor) // check LOS and awareness last as it's the most expensive function
|
||||||
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(targetActor, actor))
|
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(targetActor, actor))
|
||||||
{
|
{
|
||||||
|
@ -2012,28 +2013,25 @@ namespace MWMechanics
|
||||||
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||||
bool firstPersonPlayer = isPlayer && world->isFirstPerson();
|
bool firstPersonPlayer = isPlayer && world->isFirstPerson();
|
||||||
bool inCombatOrPursue = stats.getAiSequence().isInCombat() || stats.getAiSequence().hasPackage(AiPackageTypeId::Pursue);
|
bool inCombatOrPursue = stats.getAiSequence().isInCombat() || stats.getAiSequence().hasPackage(AiPackageTypeId::Pursue);
|
||||||
|
MWWorld::Ptr activePackageTarget;
|
||||||
|
|
||||||
// 1. Unconsious actor can not track target
|
// 1. Unconsious actor can not track target
|
||||||
// 2. Actors in combat and pursue mode do not bother to headtrack
|
// 2. Actors in combat and pursue mode do not bother to headtrack anyone except their target
|
||||||
// 3. Player character does not use headtracking in the 1st-person view
|
// 3. Player character does not use headtracking in the 1st-person view
|
||||||
if (!stats.getKnockedDown() && !firstPersonPlayer && !inCombatOrPursue)
|
if (!stats.getKnockedDown() && !firstPersonPlayer)
|
||||||
{
|
{
|
||||||
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
if (inCombatOrPursue)
|
||||||
|
activePackageTarget = stats.getAiSequence().getActivePackage().getTarget();
|
||||||
|
|
||||||
|
for (PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->first == iter->first)
|
if (it->first == iter->first)
|
||||||
continue;
|
continue;
|
||||||
updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stats.getKnockedDown() && !isPlayer && inCombatOrPursue)
|
if (inCombatOrPursue && it->first != activePackageTarget)
|
||||||
{
|
continue;
|
||||||
// Actors in combat and pursue mode always look at their target.
|
|
||||||
for (const auto& package : stats.getAiSequence())
|
updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance, inCombatOrPursue);
|
||||||
{
|
|
||||||
headTrackTarget = package->getTarget();
|
|
||||||
if (!headTrackTarget.isEmpty())
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,8 @@ namespace MWMechanics
|
||||||
void turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor& actorState, const osg::Vec3f& dir);
|
void turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor& actorState, const osg::Vec3f& dir);
|
||||||
|
|
||||||
void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
|
void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
|
||||||
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance);
|
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance,
|
||||||
|
bool inCombatOrPursue);
|
||||||
|
|
||||||
void rest(double hours, bool sleep);
|
void rest(double hours, bool sleep);
|
||||||
///< Update actors while the player is waiting or sleeping.
|
///< Update actors while the player is waiting or sleeping.
|
||||||
|
|
|
@ -23,4 +23,10 @@ namespace MWMechanics
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
return (actor.getClass().canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor);
|
return (actor.getClass().canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasWaterWalking(const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects();
|
||||||
|
return effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace MWMechanics
|
||||||
MWWorld::Ptr getPlayer();
|
MWWorld::Ptr getPlayer();
|
||||||
bool isPlayerInCombat();
|
bool isPlayerInCombat();
|
||||||
bool canActorMoveByZAxis(const MWWorld::Ptr& actor);
|
bool canActorMoveByZAxis(const MWWorld::Ptr& actor);
|
||||||
|
bool hasWaterWalking(const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value)
|
void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value)
|
||||||
|
|
|
@ -45,13 +45,13 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
|
||||||
return true; //Door is no longer opening
|
return true; //Door is no longer opening
|
||||||
|
|
||||||
ESM::Position tPos = mDoorPtr.getRefData().getPosition(); //Position of the door
|
ESM::Position tPos = mDoorPtr.getRefData().getPosition(); //Position of the door
|
||||||
float x = pos.pos[0] - tPos.pos[0];
|
float x = pos.pos[1] - tPos.pos[1];
|
||||||
float y = pos.pos[1] - tPos.pos[1];
|
float y = pos.pos[0] - tPos.pos[0];
|
||||||
|
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||||
|
|
||||||
// Turn away from the door and move when turn completed
|
// Turn away from the door and move when turn completed
|
||||||
if (zTurn(actor, std::atan2(x,y) + getAdjustedAngle(), osg::DegreesToRadians(5.f)))
|
if (zTurn(actor, std::atan2(y,x) + getAdjustedAngle(), osg::DegreesToRadians(5.f)))
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||||
else
|
else
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
|
|
|
@ -23,7 +23,7 @@ bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterContro
|
||||||
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||||
|
|
||||||
actorClass.getMovementSettings(actor).mPosition[1] = 1;
|
actorClass.getMovementSettings(actor).mPosition[1] = 1;
|
||||||
smoothTurn(actor, -osg::PI / 2, 0);
|
smoothTurn(actor, static_cast<float>(-osg::PI_2), 0);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,7 +228,6 @@ namespace MWMechanics
|
||||||
const osg::Vec3f vActorPos(pos.asVec3());
|
const osg::Vec3f vActorPos(pos.asVec3());
|
||||||
const 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);
|
|
||||||
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
|
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
|
||||||
|
|
||||||
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS);
|
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS);
|
||||||
|
@ -236,13 +235,14 @@ 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
|
||||||
vAimDir = AimDirToMovingTarget(actor, target, storage.mLastTargetPos, AI_REACTION_TIME, (weapon ? weapon->mData.mType : 0), storage.mStrength);
|
osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, storage.mLastTargetPos, AI_REACTION_TIME, (weapon ? weapon->mData.mType : 0), storage.mStrength);
|
||||||
|
|
||||||
storage.mMovement.mRotation[0] = getXAngleToDir(vAimDir);
|
storage.mMovement.mRotation[0] = getXAngleToDir(vAimDir);
|
||||||
storage.mMovement.mRotation[2] = getZAngleToDir(vAimDir);
|
storage.mMovement.mRotation[2] = getZAngleToDir(vAimDir);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target, false);
|
||||||
storage.mMovement.mRotation[0] = getXAngleToDir(vAimDir);
|
storage.mMovement.mRotation[0] = getXAngleToDir(vAimDir);
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@ -263,8 +263,9 @@ namespace MWMechanics
|
||||||
&& ((!storage.mReadyToAttack && !mPathFinder.isPathConstructed())
|
&& ((!storage.mReadyToAttack && !mPathFinder.isPathConstructed())
|
||||||
|| (storage.mUseCustomDestination && (storage.mCustomDestination - vTargetPos).length() > rangeAttack)))
|
|| (storage.mUseCustomDestination && (storage.mCustomDestination - vTargetPos).length() > rangeAttack)))
|
||||||
{
|
{
|
||||||
|
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
// Try to build path to the target.
|
// Try to build path to the target.
|
||||||
const auto halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor);
|
const auto halfExtents = world->getPathfindingHalfExtents(actor);
|
||||||
const auto navigatorFlags = getNavigatorFlags(actor);
|
const auto navigatorFlags = getNavigatorFlags(actor);
|
||||||
const auto areaCosts = getAreaCosts(actor);
|
const auto areaCosts = getAreaCosts(actor);
|
||||||
const auto pathGridGraph = getPathGridGraph(actor.getCell());
|
const auto pathGridGraph = getPathGridGraph(actor.getCell());
|
||||||
|
@ -274,11 +275,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
// If there is no path, try to find a point on a line from the actor position to target projected
|
// 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.
|
// 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 navigator = world->getNavigator();
|
||||||
const auto navigatorFlags = getNavigatorFlags(actor);
|
|
||||||
const auto areaCosts = getAreaCosts(actor);
|
|
||||||
const auto hit = navigator->raycast(halfExtents, vActorPos, vTargetPos, navigatorFlags);
|
const auto hit = navigator->raycast(halfExtents, vActorPos, vTargetPos, navigatorFlags);
|
||||||
|
|
||||||
if (hit.has_value() && (*hit - vTargetPos).length() <= rangeAttack)
|
if (hit.has_value() && (*hit - vTargetPos).length() <= rangeAttack)
|
||||||
|
@ -534,7 +531,7 @@ namespace MWMechanics
|
||||||
// Otherwise apply a random side step (kind of dodging) with some probability
|
// Otherwise apply a random side step (kind of dodging) with some probability
|
||||||
// if actor is within range of target's weapon.
|
// if actor is within range of target's weapon.
|
||||||
if (std::abs(angleToTarget) > osg::PI / 4)
|
if (std::abs(angleToTarget) > osg::PI / 4)
|
||||||
moveDuration = 0.2;
|
moveDuration = 0.2f;
|
||||||
else if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25)
|
else if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25)
|
||||||
moveDuration = 0.1f + 0.1f * Misc::Rng::rollClosedProbability();
|
moveDuration = 0.1f + 0.1f * Misc::Rng::rollClosedProbability();
|
||||||
if (moveDuration > 0)
|
if (moveDuration > 0)
|
||||||
|
@ -698,7 +695,7 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t
|
||||||
// idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same
|
// idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same
|
||||||
|
|
||||||
osg::Vec3f vTargetPos = target.getRefData().getPosition().asVec3();
|
osg::Vec3f vTargetPos = target.getRefData().getPosition().asVec3();
|
||||||
osg::Vec3f vDirToTarget = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
|
osg::Vec3f vDirToTarget = MWBase::Environment::get().getWorld()->aimToTarget(actor, target, true);
|
||||||
float distToTarget = vDirToTarget.length();
|
float distToTarget = vDirToTarget.length();
|
||||||
|
|
||||||
osg::Vec3f vTargetMoveDir = vTargetPos - vLastTargetPos;
|
osg::Vec3f vTargetMoveDir = vTargetPos - vLastTargetPos;
|
||||||
|
|
|
@ -25,6 +25,14 @@
|
||||||
|
|
||||||
#include <osg/Quat>
|
#include <osg/Quat>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
float divOrMax(float dividend, float divisor)
|
||||||
|
{
|
||||||
|
return divisor == 0 ? std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon() : dividend / divisor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MWMechanics::AiPackage::AiPackage(AiPackageTypeId typeId, const Options& options) :
|
MWMechanics::AiPackage::AiPackage(AiPackageTypeId typeId, const Options& options) :
|
||||||
mTypeId(typeId),
|
mTypeId(typeId),
|
||||||
mOptions(options),
|
mOptions(options),
|
||||||
|
@ -411,13 +419,20 @@ bool MWMechanics::AiPackage::isReachableRotatingOnTheRun(const MWWorld::Ptr& act
|
||||||
|
|
||||||
DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld::Ptr& actor) const
|
DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld::Ptr& actor) const
|
||||||
{
|
{
|
||||||
|
static const bool allowToFollowOverWaterSurface = Settings::Manager::getBool("allow actors to follow over water surface", "Game");
|
||||||
|
|
||||||
const MWWorld::Class& actorClass = actor.getClass();
|
const MWWorld::Class& actorClass = actor.getClass();
|
||||||
DetourNavigator::Flags result = DetourNavigator::Flag_none;
|
DetourNavigator::Flags result = DetourNavigator::Flag_none;
|
||||||
|
|
||||||
if (actorClass.isPureWaterCreature(actor) || (getTypeId() != AiPackageTypeId::Wander && actorClass.canSwim(actor)))
|
if ((actorClass.isPureWaterCreature(actor)
|
||||||
|
|| (getTypeId() != AiPackageTypeId::Wander
|
||||||
|
&& ((allowToFollowOverWaterSurface && getTypeId() == AiPackageTypeId::Follow)
|
||||||
|
|| actorClass.canSwim(actor)
|
||||||
|
|| hasWaterWalking(actor)))
|
||||||
|
) && actorClass.getSwimSpeed(actor) > 0)
|
||||||
result |= DetourNavigator::Flag_swim;
|
result |= DetourNavigator::Flag_swim;
|
||||||
|
|
||||||
if (actorClass.canWalk(actor))
|
if (actorClass.canWalk(actor) && actor.getClass().getWalkSpeed(actor) > 0)
|
||||||
result |= DetourNavigator::Flag_walk;
|
result |= DetourNavigator::Flag_walk;
|
||||||
|
|
||||||
if (actorClass.isBipedal(actor) && getTypeId() != AiPackageTypeId::Wander)
|
if (actorClass.isBipedal(actor) && getTypeId() != AiPackageTypeId::Wander)
|
||||||
|
@ -433,15 +448,15 @@ DetourNavigator::AreaCosts MWMechanics::AiPackage::getAreaCosts(const MWWorld::P
|
||||||
const MWWorld::Class& actorClass = actor.getClass();
|
const MWWorld::Class& actorClass = actor.getClass();
|
||||||
|
|
||||||
if (flags & DetourNavigator::Flag_swim)
|
if (flags & DetourNavigator::Flag_swim)
|
||||||
costs.mWater = costs.mWater / actorClass.getSwimSpeed(actor);
|
costs.mWater = divOrMax(costs.mWater, actorClass.getSwimSpeed(actor));
|
||||||
|
|
||||||
if (flags & DetourNavigator::Flag_walk)
|
if (flags & DetourNavigator::Flag_walk)
|
||||||
{
|
{
|
||||||
float walkCost;
|
float walkCost;
|
||||||
if (getTypeId() == AiPackageTypeId::Wander)
|
if (getTypeId() == AiPackageTypeId::Wander)
|
||||||
walkCost = 1.0 / actorClass.getWalkSpeed(actor);
|
walkCost = divOrMax(1.0, actorClass.getWalkSpeed(actor));
|
||||||
else
|
else
|
||||||
walkCost = 1.0 / actorClass.getRunSpeed(actor);
|
walkCost = divOrMax(1.0, actorClass.getRunSpeed(actor));
|
||||||
costs.mDoor = costs.mDoor * walkCost;
|
costs.mDoor = costs.mDoor * walkCost;
|
||||||
costs.mPathgrid = costs.mPathgrid * walkCost;
|
costs.mPathgrid = costs.mPathgrid * walkCost;
|
||||||
costs.mGround = costs.mGround * walkCost;
|
costs.mGround = costs.mGround * walkCost;
|
||||||
|
|
|
@ -217,38 +217,48 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
|
||||||
if(mHitState == CharState_None)
|
if(mHitState == CharState_None)
|
||||||
{
|
{
|
||||||
if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0
|
if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0
|
||||||
|| mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0)
|
|| mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0))
|
||||||
&& mAnimation->hasAnimation("knockout"))
|
|
||||||
{
|
{
|
||||||
mTimeUntilWake = Misc::Rng::rollClosedProbability() * 2 + 1; // Wake up after 1 to 3 seconds
|
mTimeUntilWake = Misc::Rng::rollClosedProbability() * 2 + 1; // Wake up after 1 to 3 seconds
|
||||||
if (isSwimming && mAnimation->hasAnimation("swimknockout"))
|
if (isSwimming && mAnimation->hasAnimation("swimknockout"))
|
||||||
{
|
{
|
||||||
mHitState = CharState_SwimKnockOut;
|
mHitState = CharState_SwimKnockOut;
|
||||||
mCurrentHit = "swimknockout";
|
mCurrentHit = "swimknockout";
|
||||||
|
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul);
|
||||||
}
|
}
|
||||||
else
|
else if (!isSwimming && mAnimation->hasAnimation("knockout"))
|
||||||
{
|
{
|
||||||
mHitState = CharState_KnockOut;
|
mHitState = CharState_KnockOut;
|
||||||
mCurrentHit = "knockout";
|
mCurrentHit = "knockout";
|
||||||
|
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Knockout animations are missing. Fall back to idle animation, so target actor still can be killed via HtH.
|
||||||
|
mCurrentHit.erase();
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul);
|
|
||||||
mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true);
|
mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true);
|
||||||
}
|
}
|
||||||
else if(knockdown && mAnimation->hasAnimation("knockdown"))
|
else if (knockdown)
|
||||||
{
|
{
|
||||||
if (isSwimming && mAnimation->hasAnimation("swimknockdown"))
|
if (isSwimming && mAnimation->hasAnimation("swimknockdown"))
|
||||||
{
|
{
|
||||||
mHitState = CharState_SwimKnockDown;
|
mHitState = CharState_SwimKnockDown;
|
||||||
mCurrentHit = "swimknockdown";
|
mCurrentHit = "swimknockdown";
|
||||||
|
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
|
||||||
}
|
}
|
||||||
else
|
else if (!isSwimming && mAnimation->hasAnimation("knockdown"))
|
||||||
{
|
{
|
||||||
mHitState = CharState_KnockDown;
|
mHitState = CharState_KnockDown;
|
||||||
mCurrentHit = "knockdown";
|
mCurrentHit = "knockdown";
|
||||||
|
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Knockdown animation is missing. Cancel knockdown state.
|
||||||
|
mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
|
|
||||||
}
|
}
|
||||||
else if (recovery)
|
else if (recovery)
|
||||||
{
|
{
|
||||||
|
@ -2968,7 +2978,7 @@ void CharacterController::updateHeadTracking(float duration)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// no head node to look at, fall back to look at center of collision box
|
// no head node to look at, fall back to look at center of collision box
|
||||||
direction = MWBase::Environment::get().getWorld()->aimToTarget(mPtr, mHeadTrackTarget);
|
direction = MWBase::Environment::get().getWorld()->aimToTarget(mPtr, mHeadTrackTarget, false);
|
||||||
}
|
}
|
||||||
direction.normalize();
|
direction.normalize();
|
||||||
|
|
||||||
|
|
|
@ -681,7 +681,7 @@ namespace MWMechanics
|
||||||
// Deviating from Morrowind here: it doesn't increase disposition on marginal wins,
|
// Deviating from Morrowind here: it doesn't increase disposition on marginal wins,
|
||||||
// which seems to be a bug (MCP fixes it too).
|
// which seems to be a bug (MCP fixes it too).
|
||||||
// Original logic: x = 0, y = -iPerMinChange
|
// Original logic: x = 0, y = -iPerMinChange
|
||||||
x = -iPerMinChange;
|
x = iPerMinChange;
|
||||||
y = x; // This goes unused.
|
y = x; // This goes unused.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -153,23 +153,23 @@ namespace MWMechanics
|
||||||
|
|
||||||
void SpellList::addListener(Spells* spells)
|
void SpellList::addListener(Spells* spells)
|
||||||
{
|
{
|
||||||
for(const auto ptr : mListeners)
|
if (std::find(mListeners.begin(), mListeners.end(), spells) != mListeners.end())
|
||||||
{
|
return;
|
||||||
if(ptr == spells)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mListeners.push_back(spells);
|
mListeners.push_back(spells);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpellList::removeListener(Spells* spells)
|
void SpellList::removeListener(Spells* spells)
|
||||||
{
|
{
|
||||||
for(auto it = mListeners.begin(); it != mListeners.end(); it++)
|
const auto it = std::find(mListeners.begin(), mListeners.end(), spells);
|
||||||
{
|
if (it != mListeners.end())
|
||||||
if(*it == spells)
|
mListeners.erase(it);
|
||||||
{
|
}
|
||||||
mListeners.erase(it);
|
|
||||||
break;
|
void SpellList::updateListener(Spells* before, Spells* after)
|
||||||
}
|
{
|
||||||
}
|
const auto it = std::find(mListeners.begin(), mListeners.end(), before);
|
||||||
|
if (it == mListeners.end())
|
||||||
|
return mListeners.push_back(after);
|
||||||
|
*it = after;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void removeListener(Spells* spells);
|
void removeListener(Spells* spells);
|
||||||
|
|
||||||
|
void updateListener(Spells* before, Spells* after);
|
||||||
|
|
||||||
const std::vector<std::string> getSpells() const;
|
const std::vector<std::string> getSpells() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,15 @@ namespace MWMechanics
|
||||||
mSpellList->addListener(this);
|
mSpellList->addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spells::Spells(Spells&& spells) : mSpellList(std::move(spells.mSpellList)), mSpells(std::move(spells.mSpells)),
|
||||||
|
mSelectedSpell(std::move(spells.mSelectedSpell)), mUsedPowers(std::move(spells.mUsedPowers)),
|
||||||
|
mSpellsChanged(std::move(spells.mSpellsChanged)), mEffects(std::move(spells.mEffects)),
|
||||||
|
mSourcedEffects(std::move(spells.mSourcedEffects))
|
||||||
|
{
|
||||||
|
if (mSpellList)
|
||||||
|
mSpellList->updateListener(&spells, this);
|
||||||
|
}
|
||||||
|
|
||||||
std::map<const ESM::Spell*, SpellParams>::const_iterator Spells::begin() const
|
std::map<const ESM::Spell*, SpellParams>::const_iterator Spells::begin() const
|
||||||
{
|
{
|
||||||
return mSpells.begin();
|
return mSpells.begin();
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
Spells(const Spells&);
|
Spells(const Spells&);
|
||||||
|
|
||||||
Spells(const Spells&&) = delete;
|
Spells(Spells&& spells);
|
||||||
|
|
||||||
~Spells();
|
~Spells();
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,7 @@ void Actor::updatePosition()
|
||||||
mPreviousPosition = mWorldPosition;
|
mPreviousPosition = mWorldPosition;
|
||||||
mPosition = mWorldPosition;
|
mPosition = mWorldPosition;
|
||||||
mSimulationPosition = mWorldPosition;
|
mSimulationPosition = mWorldPosition;
|
||||||
|
mPositionOffset = osg::Vec3f();
|
||||||
mStandingOnPtr = nullptr;
|
mStandingOnPtr = nullptr;
|
||||||
mSkipSimulation = true;
|
mSkipSimulation = true;
|
||||||
}
|
}
|
||||||
|
@ -179,9 +180,10 @@ bool Actor::setPosition(const osg::Vec3f& position)
|
||||||
if (mSkipSimulation)
|
if (mSkipSimulation)
|
||||||
return false;
|
return false;
|
||||||
bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged;
|
bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged;
|
||||||
mPreviousPosition = mPosition + mPositionOffset;
|
updateWorldPosition();
|
||||||
mPosition = position + mPositionOffset;
|
applyOffsetChange();
|
||||||
mPositionOffset = osg::Vec3f();
|
mPreviousPosition = mPosition;
|
||||||
|
mPosition = position;
|
||||||
return hasChanged;
|
return hasChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,9 +197,9 @@ void Actor::applyOffsetChange()
|
||||||
{
|
{
|
||||||
if (mPositionOffset.length() == 0)
|
if (mPositionOffset.length() == 0)
|
||||||
return;
|
return;
|
||||||
mWorldPosition += mPositionOffset;
|
|
||||||
mPosition += mPositionOffset;
|
mPosition += mPositionOffset;
|
||||||
mPreviousPosition += mPositionOffset;
|
mPreviousPosition += mPositionOffset;
|
||||||
|
mSimulationPosition += mPositionOffset;
|
||||||
mPositionOffset = osg::Vec3f();
|
mPositionOffset = osg::Vec3f();
|
||||||
mWorldPositionChanged = true;
|
mWorldPositionChanged = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@ namespace MWPhysics
|
||||||
// Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
|
// Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
|
||||||
static constexpr int sMaxIterations = 8;
|
static constexpr int sMaxIterations = 8;
|
||||||
// Allows for more precise movement solving without getting stuck or snagging too easily.
|
// Allows for more precise movement solving without getting stuck or snagging too easily.
|
||||||
static constexpr float sCollisionMargin = 0.1;
|
static constexpr float sCollisionMargin = 0.1f;
|
||||||
// Allow for a small amount of penetration to prevent numerical precision issues from causing the "unstuck"ing code to run unnecessarily
|
// Allow for a small amount of penetration to prevent numerical precision issues from causing the "unstuck"ing code to run unnecessarily
|
||||||
// Currently set to 0 because having the "unstuck"ing code run whenever possible prevents some glitchy snagging issues
|
// Currently set to 0 because having the "unstuck"ing code run whenever possible prevents some glitchy snagging issues
|
||||||
static constexpr float sAllowedPenetration = 0.0;
|
static constexpr float sAllowedPenetration = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -593,8 +593,7 @@ namespace MWPhysics
|
||||||
const auto verticalHalfExtent = osg::Vec3f(0.0, 0.0, physicActor->getHalfExtents().z());
|
const auto verticalHalfExtent = osg::Vec3f(0.0, 0.0, physicActor->getHalfExtents().z());
|
||||||
|
|
||||||
// use a 3d approximation of the movement vector to better judge player intent
|
// use a 3d approximation of the movement vector to better judge player intent
|
||||||
const ESM::Position& refpos = ptr.getRefData().getPosition();
|
auto velocity = (osg::Quat(actor.mRefpos.rot[0], osg::Vec3f(-1, 0, 0)) * osg::Quat(actor.mRefpos.rot[2], osg::Vec3f(0, 0, -1))) * actor.mMovement;
|
||||||
auto velocity = (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * actor.mMovement;
|
|
||||||
// try to pop outside of the world before doing anything else if we're inside of it
|
// try to pop outside of the world before doing anything else if we're inside of it
|
||||||
if (!physicActor->getOnGround() || physicActor->getOnSlope())
|
if (!physicActor->getOnGround() || physicActor->getOnSlope())
|
||||||
velocity += physicActor->getInertialForce();
|
velocity += physicActor->getInertialForce();
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "components/settings/settings.hpp"
|
#include "components/settings/settings.hpp"
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
|
#include "../mwrender/bulletdebugdraw.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
@ -137,11 +138,12 @@ namespace
|
||||||
|
|
||||||
namespace MWPhysics
|
namespace MWPhysics
|
||||||
{
|
{
|
||||||
PhysicsTaskScheduler::PhysicsTaskScheduler(float physicsDt, std::shared_ptr<btCollisionWorld> collisionWorld)
|
PhysicsTaskScheduler::PhysicsTaskScheduler(float physicsDt, btCollisionWorld *collisionWorld, MWRender::DebugDrawer* debugDrawer)
|
||||||
: mDefaultPhysicsDt(physicsDt)
|
: mDefaultPhysicsDt(physicsDt)
|
||||||
, mPhysicsDt(physicsDt)
|
, mPhysicsDt(physicsDt)
|
||||||
, mTimeAccum(0.f)
|
, mTimeAccum(0.f)
|
||||||
, mCollisionWorld(std::move(collisionWorld))
|
, mCollisionWorld(collisionWorld)
|
||||||
|
, mDebugDrawer(debugDrawer)
|
||||||
, mNumJobs(0)
|
, mNumJobs(0)
|
||||||
, mRemainingSteps(0)
|
, mRemainingSteps(0)
|
||||||
, mLOSCacheExpiry(Settings::Manager::getInt("lineofsight keep inactive cache", "Physics"))
|
, mLOSCacheExpiry(Settings::Manager::getInt("lineofsight keep inactive cache", "Physics"))
|
||||||
|
@ -185,7 +187,7 @@ namespace MWPhysics
|
||||||
if (data.mActor.lock())
|
if (data.mActor.lock())
|
||||||
{
|
{
|
||||||
std::unique_lock lock(mCollisionWorldMutex);
|
std::unique_lock lock(mCollisionWorldMutex);
|
||||||
MovementSolver::unstuck(data, mCollisionWorld.get());
|
MovementSolver::unstuck(data, mCollisionWorld);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -315,7 +317,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
// init
|
// init
|
||||||
for (auto& data : actorsData)
|
for (auto& data : actorsData)
|
||||||
data.updatePosition();
|
data.updatePosition(mCollisionWorld);
|
||||||
mPrevStepCount = numSteps;
|
mPrevStepCount = numSteps;
|
||||||
mRemainingSteps = numSteps;
|
mRemainingSteps = numSteps;
|
||||||
mTimeAccum = timeAccum;
|
mTimeAccum = timeAccum;
|
||||||
|
@ -381,7 +383,7 @@ namespace MWPhysics
|
||||||
void PhysicsTaskScheduler::contactTest(btCollisionObject* colObj, btCollisionWorld::ContactResultCallback& resultCallback)
|
void PhysicsTaskScheduler::contactTest(btCollisionObject* colObj, btCollisionWorld::ContactResultCallback& resultCallback)
|
||||||
{
|
{
|
||||||
std::shared_lock lock(mCollisionWorldMutex);
|
std::shared_lock lock(mCollisionWorldMutex);
|
||||||
ContactTestWrapper::contactTest(mCollisionWorld.get(), colObj, resultCallback);
|
ContactTestWrapper::contactTest(mCollisionWorld, colObj, resultCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<btVector3> PhysicsTaskScheduler::getHitPoint(const btTransform& from, btCollisionObject* target)
|
std::optional<btVector3> PhysicsTaskScheduler::getHitPoint(const btTransform& from, btCollisionObject* target)
|
||||||
|
@ -532,7 +534,7 @@ namespace MWPhysics
|
||||||
if(const auto actor = mActorsFrameData[job].mActor.lock())
|
if(const auto actor = mActorsFrameData[job].mActor.lock())
|
||||||
{
|
{
|
||||||
MaybeSharedLock lockColWorld(mCollisionWorldMutex, mThreadSafeBullet);
|
MaybeSharedLock lockColWorld(mCollisionWorldMutex, mThreadSafeBullet);
|
||||||
MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld.get(), *mWorldFrameData);
|
MovementSolver::move(mActorsFrameData[job], mPhysicsDt, mCollisionWorld, *mWorldFrameData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,8 +596,8 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
for (auto& actorData : mActorsFrameData)
|
for (auto& actorData : mActorsFrameData)
|
||||||
{
|
{
|
||||||
MovementSolver::unstuck(actorData, mCollisionWorld.get());
|
MovementSolver::unstuck(actorData, mCollisionWorld);
|
||||||
MovementSolver::move(actorData, mPhysicsDt, mCollisionWorld.get(), *mWorldFrameData);
|
MovementSolver::move(actorData, mPhysicsDt, mCollisionWorld, *mWorldFrameData);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateActorsPositions();
|
updateActorsPositions();
|
||||||
|
@ -626,4 +628,10 @@ namespace MWPhysics
|
||||||
mTimeBegin = mTimer->tick();
|
mTimeBegin = mTimer->tick();
|
||||||
mFrameNumber = frameNumber;
|
mFrameNumber = frameNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhysicsTaskScheduler::debugDraw()
|
||||||
|
{
|
||||||
|
std::shared_lock lock(mCollisionWorldMutex);
|
||||||
|
mDebugDrawer->step();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,17 @@ namespace Misc
|
||||||
class Barrier;
|
class Barrier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
class DebugDrawer;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWPhysics
|
namespace MWPhysics
|
||||||
{
|
{
|
||||||
class PhysicsTaskScheduler
|
class PhysicsTaskScheduler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PhysicsTaskScheduler(float physicsDt, std::shared_ptr<btCollisionWorld> collisionWorld);
|
PhysicsTaskScheduler(float physicsDt, btCollisionWorld* collisionWorld, MWRender::DebugDrawer* debugDrawer);
|
||||||
~PhysicsTaskScheduler();
|
~PhysicsTaskScheduler();
|
||||||
|
|
||||||
/// @brief move actors taking into account desired movements and collisions
|
/// @brief move actors taking into account desired movements and collisions
|
||||||
|
@ -49,6 +54,7 @@ namespace MWPhysics
|
||||||
void removeCollisionObject(btCollisionObject* collisionObject);
|
void removeCollisionObject(btCollisionObject* collisionObject);
|
||||||
void updateSingleAabb(std::weak_ptr<PtrHolder> ptr, bool immediate=false);
|
void updateSingleAabb(std::weak_ptr<PtrHolder> ptr, bool immediate=false);
|
||||||
bool getLineOfSight(const std::weak_ptr<Actor>& actor1, const std::weak_ptr<Actor>& actor2);
|
bool getLineOfSight(const std::weak_ptr<Actor>& actor1, const std::weak_ptr<Actor>& actor2);
|
||||||
|
void debugDraw();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void syncComputation();
|
void syncComputation();
|
||||||
|
@ -67,7 +73,8 @@ namespace MWPhysics
|
||||||
float mDefaultPhysicsDt;
|
float mDefaultPhysicsDt;
|
||||||
float mPhysicsDt;
|
float mPhysicsDt;
|
||||||
float mTimeAccum;
|
float mTimeAccum;
|
||||||
std::shared_ptr<btCollisionWorld> mCollisionWorld;
|
btCollisionWorld* mCollisionWorld;
|
||||||
|
MWRender::DebugDrawer* mDebugDrawer;
|
||||||
std::vector<LOSRequest> mLOSCache;
|
std::vector<LOSRequest> mLOSCache;
|
||||||
std::set<std::weak_ptr<PtrHolder>, std::owner_less<std::weak_ptr<PtrHolder>>> mUpdateAabb;
|
std::set<std::weak_ptr<PtrHolder>, std::owner_less<std::weak_ptr<PtrHolder>>> mUpdateAabb;
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,22 @@
|
||||||
#include "movementsolver.hpp"
|
#include "movementsolver.hpp"
|
||||||
#include "mtphysics.hpp"
|
#include "mtphysics.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool canMoveToWaterSurface(const MWPhysics::Actor* physicActor, const float waterlevel, btCollisionWorld* world)
|
||||||
|
{
|
||||||
|
if (!physicActor)
|
||||||
|
return false;
|
||||||
|
const float halfZ = physicActor->getHalfExtents().z();
|
||||||
|
const osg::Vec3f actorPosition = physicActor->getPosition();
|
||||||
|
const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
|
||||||
|
const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
|
||||||
|
MWPhysics::ActorTracer tracer;
|
||||||
|
tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, world);
|
||||||
|
return (tracer.mFraction >= 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWPhysics
|
namespace MWPhysics
|
||||||
{
|
{
|
||||||
PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode)
|
PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode)
|
||||||
|
@ -79,7 +95,7 @@ namespace MWPhysics
|
||||||
mDispatcher = std::make_unique<btCollisionDispatcher>(mCollisionConfiguration.get());
|
mDispatcher = std::make_unique<btCollisionDispatcher>(mCollisionConfiguration.get());
|
||||||
mBroadphase = std::make_unique<btDbvtBroadphase>();
|
mBroadphase = std::make_unique<btDbvtBroadphase>();
|
||||||
|
|
||||||
mCollisionWorld = std::make_shared<btCollisionWorld>(mDispatcher.get(), mBroadphase.get(), mCollisionConfiguration.get());
|
mCollisionWorld = std::make_unique<btCollisionWorld>(mDispatcher.get(), mBroadphase.get(), mCollisionConfiguration.get());
|
||||||
|
|
||||||
// Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this.
|
// Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this.
|
||||||
// Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb.
|
// Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb.
|
||||||
|
@ -97,8 +113,8 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mTaskScheduler = std::make_unique<PhysicsTaskScheduler>(mPhysicsDt, mCollisionWorld);
|
|
||||||
mDebugDrawer = std::make_unique<MWRender::DebugDrawer>(mParentNode, mCollisionWorld.get(), mDebugDrawEnabled);
|
mDebugDrawer = std::make_unique<MWRender::DebugDrawer>(mParentNode, mCollisionWorld.get(), mDebugDrawEnabled);
|
||||||
|
mTaskScheduler = std::make_unique<PhysicsTaskScheduler>(mPhysicsDt, mCollisionWorld.get(), mDebugDrawer.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicsSystem::~PhysicsSystem()
|
PhysicsSystem::~PhysicsSystem()
|
||||||
|
@ -347,16 +363,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
|
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
|
||||||
{
|
{
|
||||||
const Actor* physicActor = getActor(actor);
|
return ::canMoveToWaterSurface(getActor(actor), waterlevel, mCollisionWorld.get());
|
||||||
if (!physicActor)
|
|
||||||
return false;
|
|
||||||
const float halfZ = physicActor->getHalfExtents().z();
|
|
||||||
const osg::Vec3f actorPosition = physicActor->getPosition();
|
|
||||||
const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
|
|
||||||
const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
|
|
||||||
ActorTracer tracer;
|
|
||||||
tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld.get());
|
|
||||||
return (tracer.mFraction >= 1.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const
|
osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const
|
||||||
|
@ -605,9 +612,6 @@ namespace MWPhysics
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
if (caster == nullptr)
|
|
||||||
Log(Debug::Warning) << "No caster for projectile " << projectileId;
|
|
||||||
|
|
||||||
ProjectileConvexCallback resultCallback(caster, btFrom, btTo, projectile);
|
ProjectileConvexCallback resultCallback(caster, btFrom, btTo, projectile);
|
||||||
resultCallback.m_collisionFilterMask = 0xff;
|
resultCallback.m_collisionFilterMask = 0xff;
|
||||||
resultCallback.m_collisionFilterGroup = CollisionType_Projectile;
|
resultCallback.m_collisionFilterGroup = CollisionType_Projectile;
|
||||||
|
@ -772,16 +776,10 @@ namespace MWPhysics
|
||||||
const MWMechanics::MagicEffects& effects = character.getClass().getCreatureStats(character).getMagicEffects();
|
const MWMechanics::MagicEffects& effects = character.getClass().getCreatureStats(character).getMagicEffects();
|
||||||
|
|
||||||
bool waterCollision = false;
|
bool waterCollision = false;
|
||||||
bool moveToWaterSurface = false;
|
|
||||||
if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude())
|
if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude())
|
||||||
{
|
{
|
||||||
if (!world->isUnderwater(character.getCell(), osg::Vec3f(character.getRefData().getPosition().asVec3())))
|
if (physicActor->getCollisionMode() || !world->isUnderwater(character.getCell(), osg::Vec3f(character.getRefData().getPosition().asVec3())))
|
||||||
waterCollision = true;
|
waterCollision = true;
|
||||||
else if (physicActor->getCollisionMode() && canMoveToWaterSurface(character, waterlevel))
|
|
||||||
{
|
|
||||||
moveToWaterSurface = true;
|
|
||||||
waterCollision = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
physicActor->setCanWaterWalk(waterCollision);
|
physicActor->setCanWaterWalk(waterCollision);
|
||||||
|
@ -794,7 +792,7 @@ namespace MWPhysics
|
||||||
if (!willSimulate)
|
if (!willSimulate)
|
||||||
standingOn = physicActor->getStandingOnPtr();
|
standingOn = physicActor->getStandingOnPtr();
|
||||||
|
|
||||||
actorsFrameData.emplace_back(std::move(physicActor), standingOn, moveToWaterSurface, movement, slowFall, waterlevel);
|
actorsFrameData.emplace_back(std::move(physicActor), standingOn, waterCollision, movement, slowFall, waterlevel);
|
||||||
}
|
}
|
||||||
mMovementQueue.clear();
|
mMovementQueue.clear();
|
||||||
return actorsFrameData;
|
return actorsFrameData;
|
||||||
|
@ -827,7 +825,7 @@ namespace MWPhysics
|
||||||
void PhysicsSystem::debugDraw()
|
void PhysicsSystem::debugDraw()
|
||||||
{
|
{
|
||||||
if (mDebugDrawEnabled)
|
if (mDebugDrawEnabled)
|
||||||
mDebugDrawer->step();
|
mTaskScheduler->debugDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const
|
bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const
|
||||||
|
@ -937,9 +935,9 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
|
|
||||||
ActorFrameData::ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr standingOn,
|
ActorFrameData::ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr standingOn,
|
||||||
bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel)
|
bool waterCollision, osg::Vec3f movement, float slowFall, float waterlevel)
|
||||||
: mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn),
|
: mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn),
|
||||||
mDidJump(false), mNeedLand(false), mMoveToWaterSurface(moveToWaterSurface),
|
mDidJump(false), mNeedLand(false), mWaterCollision(waterCollision),
|
||||||
mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(movement), mPosition(), mRefpos()
|
mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(movement), mPosition(), mRefpos()
|
||||||
{
|
{
|
||||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
@ -953,7 +951,7 @@ namespace MWPhysics
|
||||||
mWasOnGround = actor->getOnGround();
|
mWasOnGround = actor->getOnGround();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActorFrameData::updatePosition()
|
void ActorFrameData::updatePosition(btCollisionWorld* world)
|
||||||
{
|
{
|
||||||
mActorRaw->updateWorldPosition();
|
mActorRaw->updateWorldPosition();
|
||||||
// If physics runs "fast enough", position are interpolated without simulation
|
// If physics runs "fast enough", position are interpolated without simulation
|
||||||
|
@ -961,10 +959,10 @@ namespace MWPhysics
|
||||||
// regardless of simulation speed.
|
// regardless of simulation speed.
|
||||||
mActorRaw->applyOffsetChange();
|
mActorRaw->applyOffsetChange();
|
||||||
mPosition = mActorRaw->getPosition();
|
mPosition = mActorRaw->getPosition();
|
||||||
if (mMoveToWaterSurface)
|
if (mWaterCollision && mPosition.z() < mWaterlevel && canMoveToWaterSurface(mActorRaw, mWaterlevel, world))
|
||||||
{
|
{
|
||||||
mPosition.z() = mWaterlevel;
|
mPosition.z() = mWaterlevel;
|
||||||
MWBase::Environment::get().getWorld()->moveObject(mActorRaw->getPtr(), mPosition.x(), mPosition.y(), mPosition.z());
|
MWBase::Environment::get().getWorld()->moveObject(mActorRaw->getPtr(), mPosition.x(), mPosition.y(), mPosition.z(), false);
|
||||||
}
|
}
|
||||||
mOldHeight = mPosition.z();
|
mOldHeight = mPosition.z();
|
||||||
mRefpos = mActorRaw->getPtr().getRefData().getPosition();
|
mRefpos = mActorRaw->getPtr().getRefData().getPosition();
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace MWPhysics
|
||||||
struct ActorFrameData
|
struct ActorFrameData
|
||||||
{
|
{
|
||||||
ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel);
|
ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel);
|
||||||
void updatePosition();
|
void updatePosition(btCollisionWorld* world);
|
||||||
std::weak_ptr<Actor> mActor;
|
std::weak_ptr<Actor> mActor;
|
||||||
Actor* mActorRaw;
|
Actor* mActorRaw;
|
||||||
MWWorld::Ptr mStandingOn;
|
MWWorld::Ptr mStandingOn;
|
||||||
|
@ -90,7 +90,7 @@ namespace MWPhysics
|
||||||
bool mDidJump;
|
bool mDidJump;
|
||||||
bool mFloatToSurface;
|
bool mFloatToSurface;
|
||||||
bool mNeedLand;
|
bool mNeedLand;
|
||||||
bool mMoveToWaterSurface;
|
bool mWaterCollision;
|
||||||
float mWaterlevel;
|
float mWaterlevel;
|
||||||
float mSlowFall;
|
float mSlowFall;
|
||||||
float mOldHeight;
|
float mOldHeight;
|
||||||
|
@ -259,7 +259,7 @@ namespace MWPhysics
|
||||||
std::unique_ptr<btBroadphaseInterface> mBroadphase;
|
std::unique_ptr<btBroadphaseInterface> mBroadphase;
|
||||||
std::unique_ptr<btDefaultCollisionConfiguration> mCollisionConfiguration;
|
std::unique_ptr<btDefaultCollisionConfiguration> mCollisionConfiguration;
|
||||||
std::unique_ptr<btCollisionDispatcher> mDispatcher;
|
std::unique_ptr<btCollisionDispatcher> mDispatcher;
|
||||||
std::shared_ptr<btCollisionWorld> mCollisionWorld;
|
std::unique_ptr<btCollisionWorld> mCollisionWorld;
|
||||||
std::unique_ptr<PhysicsTaskScheduler> mTaskScheduler;
|
std::unique_ptr<PhysicsTaskScheduler> mTaskScheduler;
|
||||||
|
|
||||||
std::unique_ptr<Resource::BulletShapeManager> mShapeManager;
|
std::unique_ptr<Resource::BulletShapeManager> mShapeManager;
|
||||||
|
|
|
@ -60,14 +60,14 @@ namespace MWPhysics
|
||||||
// attempt 3: further, less tall fixed distance movement, same as above
|
// attempt 3: further, less tall fixed distance movement, same as above
|
||||||
// If you're making a full conversion you should purge the logic for attempts 2 and 3. Attempts 2 and 3 just try to work around problems with vanilla Morrowind assets.
|
// If you're making a full conversion you should purge the logic for attempts 2 and 3. Attempts 2 and 3 just try to work around problems with vanilla Morrowind assets.
|
||||||
int attempt = 0;
|
int attempt = 0;
|
||||||
float downStepSize;
|
float downStepSize = 0;
|
||||||
while(attempt < 3)
|
while(attempt < 3)
|
||||||
{
|
{
|
||||||
attempt++;
|
attempt++;
|
||||||
|
|
||||||
if(attempt == 1)
|
if(attempt == 1)
|
||||||
tracerDest = tracerPos + toMove;
|
tracerDest = tracerPos + toMove;
|
||||||
else if (!firstIteration || !sDoExtraStairHacks) // first attempt failed and not on first movement solver iteration, can't retry -- or we have extra hacks disabled
|
else if (!sDoExtraStairHacks) // early out if we have extra hacks disabled
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -358,6 +358,8 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
||||||
}
|
}
|
||||||
|
|
||||||
mScabbard = attachMesh(scabbardName, boneName);
|
mScabbard = attachMesh(scabbardName, boneName);
|
||||||
|
if (mScabbard)
|
||||||
|
resetControllers(mScabbard->getNode());
|
||||||
|
|
||||||
osg::Group* weaponNode = getBoneByName("Bip01 Weapon");
|
osg::Group* weaponNode = getBoneByName("Bip01 Weapon");
|
||||||
if (!weaponNode)
|
if (!weaponNode)
|
||||||
|
|
|
@ -500,6 +500,11 @@ namespace MWRender
|
||||||
mAlpha = alpha;
|
mAlpha = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLightSource(const osg::ref_ptr<SceneUtil::LightSource>& lightSource)
|
||||||
|
{
|
||||||
|
mLightSource = lightSource;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setDefaults(osg::StateSet* stateset) override
|
void setDefaults(osg::StateSet* stateset) override
|
||||||
{
|
{
|
||||||
|
@ -522,10 +527,13 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
osg::Material* material = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
|
osg::Material* material = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
|
||||||
material->setAlpha(osg::Material::FRONT_AND_BACK, mAlpha);
|
material->setAlpha(osg::Material::FRONT_AND_BACK, mAlpha);
|
||||||
|
if (mLightSource)
|
||||||
|
mLightSource->setActorFade(mAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float mAlpha;
|
float mAlpha;
|
||||||
|
osg::ref_ptr<SceneUtil::LightSource> mLightSource;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Animation::AnimSource
|
struct Animation::AnimSource
|
||||||
|
@ -1667,7 +1675,7 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior();
|
bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior();
|
||||||
|
|
||||||
SceneUtil::addLight(parent, esmLight, Mask_ParticleSystem, Mask_Lighting, exterior);
|
mExtraLightSource = SceneUtil::addLight(parent, esmLight, Mask_ParticleSystem, Mask_Lighting, exterior);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, const std::string& texture)
|
void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, const std::string& texture)
|
||||||
|
@ -1817,6 +1825,7 @@ namespace MWRender
|
||||||
if (mTransparencyUpdater == nullptr)
|
if (mTransparencyUpdater == nullptr)
|
||||||
{
|
{
|
||||||
mTransparencyUpdater = new TransparencyUpdater(alpha);
|
mTransparencyUpdater = new TransparencyUpdater(alpha);
|
||||||
|
mTransparencyUpdater->setLightSource(mExtraLightSource);
|
||||||
mObjectRoot->addCullCallback(mTransparencyUpdater);
|
mObjectRoot->addCullCallback(mTransparencyUpdater);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -278,6 +278,7 @@ protected:
|
||||||
osg::ref_ptr<SceneUtil::LightSource> mGlowLight;
|
osg::ref_ptr<SceneUtil::LightSource> mGlowLight;
|
||||||
osg::ref_ptr<SceneUtil::GlowUpdater> mGlowUpdater;
|
osg::ref_ptr<SceneUtil::GlowUpdater> mGlowUpdater;
|
||||||
osg::ref_ptr<TransparencyUpdater> mTransparencyUpdater;
|
osg::ref_ptr<TransparencyUpdater> mTransparencyUpdater;
|
||||||
|
osg::ref_ptr<SceneUtil::LightSource> mExtraLightSource;
|
||||||
|
|
||||||
float mAlpha;
|
float mAlpha;
|
||||||
|
|
||||||
|
|
|
@ -453,7 +453,7 @@ namespace MWRender
|
||||||
void Camera::setPitch(float angle)
|
void Camera::setPitch(float angle)
|
||||||
{
|
{
|
||||||
const float epsilon = 0.000001f;
|
const float epsilon = 0.000001f;
|
||||||
float limit = osg::PI_2 - epsilon;
|
float limit = static_cast<float>(osg::PI_2) - epsilon;
|
||||||
mPitch = osg::clampBetween(angle, -limit, limit);
|
mPitch = osg::clampBetween(angle, -limit, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,9 @@ namespace MWRender
|
||||||
|
|
||||||
mCamera->setNodeMask(Mask_RenderToTexture);
|
mCamera->setNodeMask(Mask_RenderToTexture);
|
||||||
|
|
||||||
osg::ref_ptr<SceneUtil::LightManager> lightManager = new SceneUtil::LightManager;
|
bool ffp = mResourceSystem->getSceneManager()->getLightingMethod() == SceneUtil::LightingMethod::FFP;
|
||||||
|
|
||||||
|
osg::ref_ptr<SceneUtil::LightManager> lightManager = new SceneUtil::LightManager(ffp);
|
||||||
lightManager->setStartLight(1);
|
lightManager->setStartLight(1);
|
||||||
osg::ref_ptr<osg::StateSet> stateset = lightManager->getOrCreateStateSet();
|
osg::ref_ptr<osg::StateSet> stateset = lightManager->getOrCreateStateSet();
|
||||||
stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
|
stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
|
||||||
|
@ -231,12 +233,22 @@ namespace MWRender
|
||||||
float positionZ = std::cos(altitude);
|
float positionZ = std::cos(altitude);
|
||||||
light->setPosition(osg::Vec4(positionX,positionY,positionZ, 0.0));
|
light->setPosition(osg::Vec4(positionX,positionY,positionZ, 0.0));
|
||||||
light->setDiffuse(osg::Vec4(diffuseR,diffuseG,diffuseB,1));
|
light->setDiffuse(osg::Vec4(diffuseR,diffuseG,diffuseB,1));
|
||||||
light->setAmbient(osg::Vec4(ambientR,ambientG,ambientB,1));
|
osg::Vec4 ambientRGBA = osg::Vec4(ambientR,ambientG,ambientB,1);
|
||||||
|
if (mResourceSystem->getSceneManager()->getForceShaders())
|
||||||
|
{
|
||||||
|
// When using shaders, we now skip the ambient sun calculation as this is the only place it's used.
|
||||||
|
// Using the scene ambient will give identical results.
|
||||||
|
lightmodel->setAmbientIntensity(ambientRGBA);
|
||||||
|
light->setAmbient(osg::Vec4(0,0,0,1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
light->setAmbient(ambientRGBA);
|
||||||
light->setSpecular(osg::Vec4(0,0,0,0));
|
light->setSpecular(osg::Vec4(0,0,0,0));
|
||||||
light->setLightNum(0);
|
light->setLightNum(0);
|
||||||
light->setConstantAttenuation(1.f);
|
light->setConstantAttenuation(1.f);
|
||||||
light->setLinearAttenuation(0.f);
|
light->setLinearAttenuation(0.f);
|
||||||
light->setQuadraticAttenuation(0.f);
|
light->setQuadraticAttenuation(0.f);
|
||||||
|
lightManager->setSunlight(light);
|
||||||
|
|
||||||
osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource;
|
osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource;
|
||||||
lightSource->setLight(light);
|
lightSource->setLight(light);
|
||||||
|
@ -414,7 +426,7 @@ namespace MWRender
|
||||||
visitor.setTraversalNumber(mDrawOnceCallback->getLastRenderedFrame());
|
visitor.setTraversalNumber(mDrawOnceCallback->getLastRenderedFrame());
|
||||||
|
|
||||||
osg::Node::NodeMask nodeMask = mCamera->getNodeMask();
|
osg::Node::NodeMask nodeMask = mCamera->getNodeMask();
|
||||||
mCamera->setNodeMask(~0);
|
mCamera->setNodeMask(~0u);
|
||||||
mCamera->accept(visitor);
|
mCamera->accept(visitor);
|
||||||
mCamera->setNodeMask(nodeMask);
|
mCamera->setNodeMask(nodeMask);
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue