Add OpenMW 0.47 commits to OpenMW VR up to 4 Dec 2021

# Conflicts:
#   .gitlab-ci.yml
#   CI/before_script.msvc.sh
#   CI/install_debian_deps.sh
#   CMakeLists.txt
#   apps/openmw/mwrender/screenshotmanager.cpp
#   files/ui/advancedpage.ui
pull/615/head
David Cernat 3 years ago
commit 572b16af41

@ -16,8 +16,6 @@ stages:
- apt-cache/
- ccache/
stage: build
rules:
- if: '$CI_PIPELINE_SOURCE != "schedule"'
script:
- export CCACHE_BASEDIR="`pwd`"
- export CCACHE_DIR="`pwd`/ccache" && mkdir -pv "$CCACHE_DIR"
@ -27,6 +25,7 @@ stages:
- cmake --build . -- -j $(nproc)
- cmake --install .
- if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw_test_suite; fi
- if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw_detournavigator_navmeshtilescache_benchmark; fi
- ccache -s
artifacts:
paths:
@ -149,6 +148,7 @@ Debian_Clang_tests:
macOS11_Xcode12:
extends: .MacOS
image: macos-11-xcode-12
allow_failure: true
cache:
key: macOS11_Xcode12.v1
variables:
@ -157,7 +157,6 @@ macOS11_Xcode12:
macOS10.15_Xcode11:
extends: .MacOS
image: macos-10.15-xcode-11
allow_failure: true
cache:
key: macOS10.15_Xcode11.v1
variables:
@ -171,6 +170,10 @@ variables: &cs-targets
targets: "openmw-cs,bsatool,esmtool,niftest"
package: "CS"
variables: &tests-targets
targets: "openmw_test_suite,openmw_detournavigator_navmeshtilescache_benchmark"
package: "Tests"
.Windows_Ninja_Base:
tags:
- windows
@ -185,13 +188,11 @@ variables: &cs-targets
- choco install python -y
- refreshenv
stage: build
rules:
- if: '$CI_PIPELINE_SOURCE != "schedule"'
script:
- $time = (Get-Date -Format "HH:mm:ss")
- echo ${time}
- echo "started by ${GITLAB_USER_NAME}"
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -N
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -N -b -t
- cd MSVC2019_64_Ninja
- .\ActivateMSVC.ps1
- cmake --build . --config $config --target ($targets.Split(','))
@ -203,6 +204,7 @@ variables: &cs-targets
Get-ChildItem -Recurse *.pdb | Remove-Item
}
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*'
- if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } }
after_script:
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
cache:
@ -266,6 +268,15 @@ Windows_Ninja_CS_RelWithDebInfo:
<<: *cs-targets
config: "RelWithDebInfo"
Windows_Ninja_Tests_RelWithDebInfo:
extends: .Windows_Ninja_Base
stage: build
variables:
<<: *tests-targets
config: "RelWithDebInfo"
# Gitlab can't successfully execute following binaries due to unknown reason
# executables: "openmw_test_suite.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe"
.Windows_MSBuild_Base:
tags:
- windows
@ -279,13 +290,11 @@ Windows_Ninja_CS_RelWithDebInfo:
- choco install python -y
- refreshenv
stage: build
rules:
- if: '$CI_PIPELINE_SOURCE != "schedule"'
script:
- $time = (Get-Date -Format "HH:mm:ss")
- echo ${time}
- echo "started by ${GITLAB_USER_NAME}"
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -b -t
- cd MSVC2019_64
- cmake --build . --config $config --target ($targets.Split(','))
- cd $config
@ -296,6 +305,7 @@ Windows_Ninja_CS_RelWithDebInfo:
Get-ChildItem -Recurse *.pdb | Remove-Item
}
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*'
- if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } }
after_script:
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
cache:
@ -359,6 +369,15 @@ Windows_MSBuild_CS_RelWithDebInfo:
<<: *cs-targets
config: "RelWithDebInfo"
Windows_MSBuild_Tests_RelWithDebInfo:
extends: .Windows_MSBuild_Base
stage: build
variables:
<<: *tests-targets
config: "RelWithDebInfo"
# Gitlab can't successfully execute following binaries due to unknown reason
# executables: "openmw_test_suite.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe"
#Debian_AndroidNDK_arm64-v8a:
# tags:
# - linux

@ -0,0 +1,10 @@
version: 2
sphinx:
configuration: docs/source/conf.py
python:
version: 3.8
install:
- requirements: docs/requirements.txt

@ -22,9 +22,9 @@ addons:
]
matrix:
include:
- name: OpenMW (all) on MacOS 10.15 with Xcode 10.2
- name: OpenMW (all) on MacOS 10.15 with Xcode 11.6
os: osx
osx_image: xcode10.2
osx_image: xcode11.6
- name: OpenMW (all) on Ubuntu Focal with GCC
os: linux
dist: focal
@ -74,7 +74,7 @@ notifications:
irc:
if: repository_slug = OpenMW/openmw AND branch = master
channels:
- "chat.freenode.net#openmw"
- "irc.libera.chat#openmw"
on_success: change
on_failure: always
use_notice: true

@ -222,6 +222,7 @@ Programmers
Yuri Krupenin
zelurker
Noah Gooder
Andrew Appuhamy (andrew-app)
Documentation
-------------

@ -7,7 +7,6 @@
Bug #2069: Fireflies in Fireflies invade Morrowind look wrong
Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs
Bug #2473: Unable to overstock merchants
Bug #2798: Mutable ESM records
Bug #2976: [reopened]: Issues combining settings from the command line and both config files
Bug #3137: Walking into a wall prevents jumping
Bug #3372: Projectiles and magic bolts go through moving targets
@ -20,7 +19,6 @@
Bug #4039: Multiple followers should have the same following distance
Bug #4055: Local scripts don't inherit variables from their base record
Bug #4083: Door animation freezes when colliding with actors
Bug #4201: Projectile-projectile collision
Bug #4247: Cannot walk up stairs in Ebonheart docks
Bug #4357: OpenMW-CS: TopicInfos index sorting and rearranging isn't fully functional
Bug #4363: OpenMW-CS: Defect in Clone Function for Dialogue Info records
@ -64,6 +62,7 @@
Bug #5452: Autowalk is being included in savegames
Bug #5469: Local map is reset when re-entering certain cells
Bug #5472: Mistify mod causes CTD in 0.46 on Mac
Bug #5473: OpenMW-CS: Cell border lines don't update properly on terrain change
Bug #5479: NPCs who should be walking around town are standing around without walking
Bug #5484: Zero value items shouldn't be able to be bought or sold for 1 gold
Bug #5485: Intimidate doesn't increase disposition on marginal wins
@ -80,6 +79,7 @@
Bug #5603: Setting constant effect cast style doesn't correct effects view
Bug #5604: Only one valid NIF root node is loaded from a single file
Bug #5611: Usable items with "0 Uses" should be used only once
Bug #5619: Input events are queued during save loading
Bug #5622: Can't properly interact with the console when in pause menu
Bug #5627: Bookart not shown if it isn't followed by <BR> statement
Bug #5633: Damage Spells in effect before god mode is enabled continue to hurt the player character and can kill them
@ -87,7 +87,7 @@
Bug #5644: Summon effects running on the player during game initialization cause crashes
Bug #5656: Sneaking characters block hits while standing
Bug #5661: Region sounds don't play at the right interval
Bug #5675: OpenMW-cs. FRMR subrecords are saved with the wrong MastIdx
Bug #5675: OpenMW-CS: FRMR subrecords are saved with the wrong MastIdx
Bug #5680: Bull Netches incorrectly aim over the player character's head and always miss
Bug #5681: Player character can clip or pass through bridges instead of colliding against them
Bug #5687: Bound items covering the same inventory slot expiring at the same time freezes the game
@ -100,6 +100,7 @@
Bug #5739: Saving and loading the save a second or two before hitting the ground doesn't count fall damage
Bug #5758: Paralyzed actors behavior is inconsistent with vanilla
Bug #5762: Movement solver is insufficiently robust
Bug #5800: Equipping a CE enchanted ring deselects an already equipped and selected enchanted ring from the spell menu
Bug #5807: Video decoding crash on ARM
Bug #5821: NPCs from mods getting removed if mod order was changed
Bug #5835: OpenMW doesn't accept negative values for NPC's hello, alarm, fight, and flee
@ -118,14 +119,31 @@
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
Bug #5991: Activate should always be allowed for inventory items
Bug #5995: NiUVController doesn't calculate the UV offset properly
Bug #6007: Crash when ending cutscene is playing
Bug #6016: Greeting interrupts Fargoth's sneak-walk
Bug #6022: OpenMW-CS: Terrain selection is not updated when undoing/redoing terrain changes
Bug #6023: OpenMW-CS: Clicking on a reference in "Terrain land editing" mode discards corresponding select/edit action
Bug #6028: Particle system controller values are incorrectly used
Bug #6035: OpenMW-CS: Circle brush in "Terrain land editing" mode sometimes includes vertices outside its radius
Bug #6036: OpenMW-CS: Terrain selection at the border of cells omits certain corner vertices
Bug #6043: Actor can have torch missing when torch animation is played
Bug #6047: Mouse bindings can be triggered during save loading
Bug #6136: Game freezes when NPCs try to open doors that are about to be closed
Bug #6294: Game crashes with empty pathgrid
Feature #390: 3rd person look "over the shoulder"
Feature #832: OpenMW-CS: Handle deleted references
Feature #1536: Show more information about level on menu
Feature #2159: "Graying out" exhausted dialogue topics
Feature #2386: Distant Statics in the form of Object Paging
Feature #2404: Levelled List can not be placed into a container
Feature #2686: Timestamps in openmw.log
Feature #2798: Mutable ESM records
Feature #3171: OpenMW-CS: Instance drag selection
Feature #3983: Wizard: Add link to buy Morrowind
Feature #4201: Projectile-projectile collision
Feature #4486: Handle crashes on Windows
Feature #4894: Consider actors as obstacles for pathfinding
Feature #4899: Alpha-To-Coverage Anti-Aliasing for alpha testing
Feature #4917: Do not trigger NavMesh update when RecastMesh update should not change NavMesh
@ -138,10 +156,12 @@
Feature #5456: Basic collada animation support
Feature #5457: Realistic diagonal movement
Feature #5486: Fixes trainers to choose their training skills based on their base skill points
Feature #5500: Prepare enough navmesh tiles before scene loading ends
Feature #5511: Add in game option to toggle HRTF support in OpenMW
Feature #5519: Code Patch tab in launcher
Feature #5524: Resume failed script execution after reload
Feature #5545: Option to allow stealing from an unconscious NPC during combat
Feature #5551: Do not reboot PC after OpenMW installation on Windows
Feature #5563: Run physics update in background thread
Feature #5579: MCP SetAngle enhancement
Feature #5580: Service refusal filtering
@ -156,9 +176,12 @@
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 #5980: Support Bullet with double precision instead of one with single precision
Feature #6024: OpenMW-CS: Selecting terrain in "Terrain land editing" should support "Add to selection" and "Remove from selection" modes
Feature #6033: Include pathgrid to navigation mesh
Feature #6034: Find path based on area cost depending on NPC stats
Task #5480: Drop Qt4 support
Task #5520: Improve cell name autocompleter implementation
Task #5844: Update 'toggle sneak' documentation
0.46.0
------
@ -168,7 +191,7 @@
Bug #2395: Duplicated plugins in the launcher when multiple data directories provide the same plugin
Bug #2679: Unable to map mouse wheel under control settings
Bug #2969: Scripted items can stack
Bug #2976: Data lines in global openmw.cfg take priority over user openmw.cfg
Bug #2976: [reopened in 0.47] Data lines in global openmw.cfg take priority over user openmw.cfg
Bug #2987: Editor: some chance and AI data fields can overflow
Bug #3006: 'else if' operator breaks script compilation
Bug #3109: SetPos/Position handles actors differently
@ -186,7 +209,6 @@
Bug #4009: Launcher does not show data files on the first run after installing
Bug #4077: Enchanted items are not recharged if they are not in the player's inventory
Bug #4141: PCSkipEquip isn't set to 1 when reading books/scrolls
Bug #4202: Open .omwaddon files without needing toopen openmw-cs first
Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect
Bug #4262: Rain settings are hardcoded
Bug #4270: Closing doors while they are obstructed desyncs closing sfx
@ -276,7 +298,6 @@
Bug #4964: Multiple effect spell projectile sounds play louder than vanilla
Bug #4965: Global light attenuation settings setup is lacking
Bug #4969: "Miss" sound plays for any actor
Bug #4971: OpenMW-CS: Make rotations display as degrees instead of radians
Bug #4972: Player is able to use quickkeys while disableplayerfighting is active
Bug #4979: AiTravel maximum range depends on "actors processing range" setting
Bug #4980: Drowning mechanics is applied for actors indifferently from distance to player
@ -374,7 +395,6 @@
Bug #5350: An attempt to launch magic bolt causes "AL error invalid value" error
Bug #5352: Light source items' duration is decremented while they aren't visible
Feature #1724: Handle AvoidNode
Feature #2159: "Graying out" exhausted dialogue topics
Feature #2229: Improve pathfinding AI
Feature #3025: Analogue gamepad movement controls
Feature #3442: Default values for fallbacks from ini file
@ -387,6 +407,7 @@
Feature #4001: Toggle sneak controller shortcut
Feature #4068: OpenMW-CS: Add a button to reset key bindings to defaults
Feature #4129: Beta Comment to File
Feature #4202: Open .omwaddon files without needing to open openmw-cs first
Feature #4209: Editor: Faction rank sub-table
Feature #4255: Handle broken RepairedOnMe script function
Feature #4316: Implement RaiseRank/LowerRank functions properly
@ -409,6 +430,7 @@
Feature #4958: Support eight blood types
Feature #4962: Add casting animations for magic items
Feature #4968: Scalable UI widget skins
Feature #4971: OpenMW-CS: Make rotations display as degrees instead of radians
Feature #4994: Persistent pinnable windows hiding
Feature #5000: Compressed BSA format support
Feature #5005: Editor: Instance window via Scene window

@ -38,9 +38,15 @@ Editor Bug Fixes:
- Disabled record sorting in Topic and Journal Info tables, implemented drag-move for records (#4357)
- Topic and Journal Info records can now be cloned with a different parent Topic/Journal Id (#4363)
- Verifier no longer checks for alleged 'race' entries in clothing body parts (#5400)
- Cell borders are now properly redrawn when undoing/redoing terrain changes (#5473)
- Loading mods now keeps the master index (#5675)
- Flicker and crashing on XFCE4 fixed (#5703)
- Collada models render properly in the Editor (#5713)
- Terrain-selection grid is now properly updated when undoing/redoing terrain changes (#6022)
- Tool outline and select/edit actions in "Terrain land editing" mode now ignore references (#6023)
- Primary-select and secondary-select actions in "Terrain land editing" mode now behave like in "Instance editing" mode (#6024)
- Using the circle brush to select terrain in the "Terrain land editing" mode no longer selects vertices outside the circle (#6035)
- Vertices at the NW and SE corners of a cell can now also be selected in "Terrain land editing" mode if the adjacent cells aren't loaded yet (#6036)
Miscellaneous:
- Prevent save-game bloating by using an appropriate fog texture format (#5108)

@ -30,55 +30,11 @@ command -v unixPathAsWindows >/dev/null 2>&1 || function unixPathAsWindows {
fi
}
function windowsSystemPathAsUnix {
if command -v cygpath >/dev/null 2>&1; then
cygpath -u -p $1
else
IFS=';' read -r -a paths <<< "$1"
declare -a convertedPaths
for entry in paths; do
convertedPaths+=(windowsPathAsUnix $entry)
done
convertedPath=printf ":%s" ${convertedPaths[@]}
echo ${convertedPath:1}
fi
}
# capture CMD environment so we know what's been changed
declare -A originalCmdEnv
originalIFS="$IFS"
IFS=$'\n\r'
for pair in $(cmd //c "set"); do
IFS='=' read -r -a separatedPair <<< "${pair}"
if [ ${#separatedPair[@]} -ne 2 ]; then
echo "Parsed '$pair' as ${#separatedPair[@]} parts, expected 2."
continue
fi
originalCmdEnv["${separatedPair[0]}"]="${separatedPair[1]}"
done
# capture CMD environment in a shell with MSVC activated
cmdEnv="$(cmd //c "$(unixPathAsWindows "$(dirname "${BASH_SOURCE[0]}")")\ActivateMSVC.bat" "&&" set)"
declare -A cmdEnvChanges
for pair in $cmdEnv; do
if [ -n "$pair" ]; then
IFS='=' read -r -a separatedPair <<< "${pair}"
if [ ${#separatedPair[@]} -ne 2 ]; then
echo "Parsed '$pair' as ${#separatedPair[@]} parts, expected 2."
continue
fi
key="${separatedPair[0]}"
value="${separatedPair[1]}"
if ! [ ${originalCmdEnv[$key]+_} ] || [ "${originalCmdEnv[$key]}" != "$value" ]; then
if [ $key != 'PATH' ] && [ $key != 'path' ] && [ $key != 'Path' ]; then
export "$key=$value"
else
export PATH=$(windowsSystemPathAsUnix $value)
fi
fi
fi
done
cmd //c "$(unixPathAsWindows "$(dirname "${BASH_SOURCE[0]}")")\ActivateMSVC.bat" "&&" "bash" "-c" "declare -px > declared_env.sh"
source ./declared_env.sh
rm declared_env.sh
MISSINGTOOLS=0
@ -93,6 +49,4 @@ if [ $MISSINGTOOLS -ne 0 ]; then
return 1
fi
IFS="$originalIFS"
restoreOldSettings
restoreOldSettings

@ -1,9 +1,9 @@
#!/bin/sh -ex
# workaround python issue on travis
[-z "${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.9 || true
[-z "${TRAVIS}"] && HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall --ignore-dependencies qt@6 || true
[ -z "${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.9 || 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
command -v ccache >/dev/null 2>&1 || brew install ccache
@ -15,5 +15,8 @@ ccache --version
cmake --version
qmake --version
curl -fSL -R -J https://downloads.openmw.org/osx/dependencies/openmw-deps-f8918dd.zip -o ~/openmw-deps.zip
curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20210617.zip -o ~/openmw-deps.zip
unzip -o ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null
# additional libraries
[ -z "${TRAVIS}" ] && HOMEBREW_NO_AUTO_UPDATE=1 brew install fontconfig

@ -4,9 +4,14 @@ set -xeo pipefail
free -m
BUILD_UNITTESTS=OFF
BUILD_BENCHMARKS=OFF
if [[ "${BUILD_TESTS_ONLY}" ]]; then
export GOOGLETEST_DIR="${PWD}/googletest/build/install"
env GENERATOR='Unix Makefiles' CONFIGURATION=Release CI/build_googletest.sh
BUILD_UNITTESTS=ON
BUILD_BENCHMARKS=ON
fi
declare -a CMAKE_CONF_OPTS=(
@ -43,7 +48,8 @@ if [[ "${BUILD_TESTS_ONLY}" ]]; then
-DBUILD_ESSIMPORTER=OFF \
-DBUILD_OPENCS=OFF \
-DBUILD_WIZARD=OFF \
-DBUILD_UNITTESTS=ON \
-DBUILD_UNITTESTS=${BUILD_UNITTESTS} \
-DBUILD_BENCHMARKS=${BUILD_BENCHMARKS} \
-DGTEST_ROOT="${GOOGLETEST_DIR}" \
-DGMOCK_ROOT="${GOOGLETEST_DIR}" \
..

@ -73,10 +73,7 @@ CONFIGURATIONS=()
TEST_FRAMEWORK=""
GOOGLE_INSTALL_ROOT=""
INSTALL_PREFIX="."
BULLET_DOUBLE=true
BULLET_DBL=""
BULLET_DBL_DISPLAY="Single precision"
SKIP_VR=""
BUILD_BENCHMARKS=""
ACTIVATE_MSVC=""
SINGLE_CONFIG=""
@ -103,9 +100,6 @@ while [ $# -gt 0 ]; do
d )
SKIP_DOWNLOAD=true ;;
D )
BULLET_DOUBLE=true ;;
e )
SKIP_EXTRACT=true ;;
@ -143,6 +137,9 @@ while [ $# -gt 0 ]; do
INSTALL_PREFIX=$(echo "$1" | sed 's;\\;/;g' | sed -E 's;/+;/;g')
shift ;;
b )
BUILD_BENCHMARKS=true ;;
h )
cat <<EOF
Usage: $0 [-cdehkpuvVi]
@ -153,8 +150,6 @@ Options:
For single-config generators, several configurations can be set up at once by specifying -c multiple times.
-d
Skip checking the downloads.
-D
Use double-precision Bullet
-e
Skip extracting dependencies.
-h
@ -179,6 +174,8 @@ Options:
Run verbosely
-i
CMake install prefix
-b
Build benchmarks
EOF
wrappedExit 0
;;
@ -437,9 +434,6 @@ if [ -n "$SINGLE_CONFIG" ]; then
if [ -n "$SKIP_DOWNLOAD" ]; then
RECURSIVE_OPTIONS+=("-d")
fi
if [ -n "$BULLET_DOUBLE" ]; then
RECURSIVE_OPTIONS+=("-D")
fi
if [ -n "$SKIP_EXTRACT" ]; then
RECURSIVE_OPTIONS+=("-e")
fi
@ -512,12 +506,6 @@ if ! [ -z $UNITY_BUILD ]; then
add_cmake_opts "-DOPENMW_UNITY_BUILD=True"
fi
if [ -n "$BULLET_DOUBLE" ]; then
BULLET_DBL="-double"
BULLET_DBL_DISPLAY="Double precision"
add_cmake_opts "-DBULLET_USE_DOUBLES=True"
fi
echo
echo "==================================="
echo "Starting prebuild on MSVC${MSVC_DISPLAY_YEAR} WIN${BITS}"
@ -542,9 +530,9 @@ if [ -z $SKIP_DOWNLOAD ]; then
fi
# Bullet
download "Bullet 2.89 (${BULLET_DBL_DISPLAY})" \
"https://gitlab.com/OpenMW/openmw-deps/-/raw/main/windows/Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}.7z" \
"Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}.7z"
download "Bullet 2.89" \
"https://gitlab.com/OpenMW/openmw-deps/-/raw/main/windows/Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}-double.7z" \
"Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}-double.7z"
# FFmpeg
download "FFmpeg 4.2.2" \
@ -684,15 +672,15 @@ fi
cd $DEPS
echo
# Bullet
printf "Bullet 2.89 (${BULLET_DBL_DISPLAY})... "
printf "Bullet 2.89... "
{
cd $DEPS_INSTALL
if [ -d Bullet ]; then
printf -- "Exists. (No version checking) "
elif [ -z $SKIP_EXTRACT ]; then
rm -rf Bullet
eval 7z x -y "${DEPS}/Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}.7z" $STRIP
mv "Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}" Bullet
eval 7z x -y "${DEPS}/Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}-double.7z" $STRIP
mv "Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}-double" Bullet
fi
add_cmake_opts -DBULLET_ROOT="$(real_pwd)/Bullet"
echo Done.
@ -1106,6 +1094,10 @@ fi
done
#fi
if [ "${BUILD_BENCHMARKS}" ]; then
add_cmake_opts -DBUILD_BENCHMARKS=ON
fi
if [ -n "$ACTIVATE_MSVC" ]; then
echo -n "- Activating MSVC in the current shell... "
command -v vswhere >/dev/null 2>&1 || { echo "Error: vswhere is not on the path."; wrappedExit 1; }

@ -25,6 +25,5 @@ cmake \
-D BUILD_BSATOOL=TRUE \
-D BUILD_ESSIMPORTER=TRUE \
-D BUILD_NIFTEST=TRUE \
-D BULLET_USE_DOUBLES=TRUE \
-G"Unix Makefiles" \
..

@ -21,14 +21,13 @@ declare -rA GROUPED_DEPS=(
libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev
libsdl2-dev libqt5opengl5-dev libopenal-dev libunshield-dev libtinyxml-dev
libbullet-dev liblz4-dev libpng-dev libjpeg-dev
libxcb-glx0-dev libx11-dev
libbullet-dev liblz4-dev libpng-dev libjpeg-dev
ca-certificates
"
# TODO: add librecastnavigation-dev when debian is ready
# These dependencies can alternatively be built and linked statically.
[openmw-deps-dynamic]="libmygui-dev libopenscenegraph-dev"
[coverity]="curl"
# Pre-requisites for building MyGUI and OSG for static linking.
@ -65,4 +64,4 @@ export APT_CACHE_DIR="${PWD}/apt-cache"
set -x
mkdir -pv "$APT_CACHE_DIR"
apt-get update -yq
apt-get -q -o dir::cache::archives="$APT_CACHE_DIR" install -y "${deps[@]}"
apt-get -q -o dir::cache::archives="$APT_CACHE_DIR" install -y --no-install-recommends "${deps[@]}"

@ -13,9 +13,6 @@ if(POLICY CMP0083)
cmake_policy(SET CMP0083 NEW)
endif()
# Detect OS
include(cmake/OSIdentity.cmake)
option(OPENMW_GL4ES_MANUAL_INIT "Manually initialize gl4es. This is more reliable on platforms without a windowing system. Requires gl4es to be configured with -DNOEGL=ON -DNO_LOADER=ON -DNO_INIT_CONSTRUCTOR=ON." OFF)
if(OPENMW_GL4ES_MANUAL_INIT)
add_definitions(-DOPENMW_GL4ES_MANUAL_INIT)
@ -35,7 +32,7 @@ option(BUILD_DOCS "Build documentation." OFF )
option(BUILD_OPENMW_VR "Build VR support using OpenXR" ON)
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
option(BULLET_USE_DOUBLES "Use double precision for Bullet" ON)
option(BUILD_BENCHMARKS "Build benchmarks with Google Benchmark" OFF)
set(OpenGL_GL_PREFERENCE LEGACY) # Use LEGACY as we use GL2; GLNVD is for GL3 and up.
@ -265,16 +262,16 @@ if(FFmpeg_FOUND)
set(FFVER_OK FALSE)
endif()
endif()
if(NOT FFVER_OK AND NOT APPLE) # unable to detect on version on MacOS < 11.0
message(FATAL_ERROR "FFmpeg version is too old, 3.2 is required" )
endif()
endif()
if(NOT FFmpeg_FOUND)
message(FATAL_ERROR "FFmpeg was not found" )
endif()
if(NOT FFVER_OK)
message(FATAL_ERROR "FFmpeg version is too old, 3.2 is required" )
endif()
if(WIN32)
message("Can not detect FFmpeg version, at least the 3.2 is required" )
endif()
@ -313,7 +310,31 @@ if(OPENMW_USE_SYSTEM_BULLET)
set(REQUIRED_BULLET_VERSION 283) # but for build testing, 283 is fine
endif()
find_package(Bullet ${REQUIRED_BULLET_VERSION} REQUIRED COMPONENTS BulletCollision LinearMath)
# First, try BulletConfig-float64.cmake which comes with Debian derivatives.
# This file does not define the Bullet version in a CMake-friendly way.
find_package(Bullet CONFIGS BulletConfig-float64.cmake QUIET COMPONENTS BulletCollision LinearMath)
if (BULLET_FOUND)
string(REPLACE "." "" _bullet_version_num ${BULLET_VERSION_STRING})
if (_bullet_version_num VERSION_LESS REQUIRED_BULLET_VERSION)
message(FATAL_ERROR "System bullet version too old, OpenMW requires at least ${REQUIRED_BULLET_VERSION}, got ${_bullet_version_num}")
endif()
# Fix the relative include:
set(BULLET_INCLUDE_DIRS "${BULLET_ROOT_DIR}/${BULLET_INCLUDE_DIRS}")
include(FindPackageMessage)
find_package_message(Bullet "Found Bullet: ${BULLET_LIBRARIES} ${BULLET_VERSION_STRING}" "${BULLET_VERSION_STRING}-float64")
else()
find_package(Bullet ${REQUIRED_BULLET_VERSION} REQUIRED COMPONENTS BulletCollision LinearMath)
endif()
# Only link the Bullet libraries that we need:
string(REGEX MATCHALL "((optimized|debug);)?[^;]*(BulletCollision|LinearMath)[^;]*" BULLET_LIBRARIES "${BULLET_LIBRARIES}")
include(cmake/CheckBulletPrecision.cmake)
if (HAS_DOUBLE_PRECISION_BULLET)
message(STATUS "Bullet uses double precision")
else()
message(FATAL_ERROR "Bullet does not uses double precision")
endif()
endif()
if (NOT WIN32 AND BUILD_WIZARD) # windows users can just run the morrowind installer
@ -342,6 +363,11 @@ endif()
if(OPENMW_USE_SYSTEM_OSG)
find_package(OpenSceneGraph ${OSG_VERSION_REQUIRED} REQUIRED ${USED_OSG_COMPONENTS})
if (${OPENSCENEGRAPH_VERSION} VERSION_GREATER 3.6.2 AND ${OPENSCENEGRAPH_VERSION} VERSION_LESS 3.6.5)
message(FATAL_ERROR "OpenSceneGraph version ${OPENSCENEGRAPH_VERSION} has critical regressions which cause crashes. Please upgrade to 3.6.5 or later. We strongly recommend using the tip of the official 'OpenSceneGraph-3.6' branch or the tip of '3.6' OpenMW/osg (OSGoS).")
endif()
if(OSG_STATIC)
find_package(OSGPlugins REQUIRED COMPONENTS ${USED_OSG_PLUGINS})
endif()
@ -424,8 +450,8 @@ endif (APPLE)
# Other files
configure_resource_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
"${OpenMW_BINARY_DIR}" "settings-default.cfg")
pack_resource_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
"${OpenMW_BINARY_DIR}" "defaults.bin")
configure_resource_file(${OpenMW_SOURCE_DIR}/files/settings-overrides-vr.cfg
"${OpenMW_BINARY_DIR}" "settings-overrides-vr.cfg")
@ -443,8 +469,8 @@ else ()
"${OpenMW_BINARY_DIR}/openmw.cfg")
endif ()
configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
"${OpenMW_BINARY_DIR}" "openmw-cs.cfg")
pack_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
"${OpenMW_BINARY_DIR}" "defaults-cs.bin")
# Needs the copy version because the configure version assumes the end of the file has been reached when a null character is reached and there are no CMake expressions to evaluate.
copy_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
@ -499,16 +525,13 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.6 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.6)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-parameter")
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 5.0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override")
endif()
endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
# Extern
add_subdirectory (extern/osg-ffmpeg-videoplayer)
add_subdirectory (extern/oics)
add_subdirectory (extern/Base64)
if (BUILD_OPENCS)
add_subdirectory (extern/osgQt)
endif()
@ -559,6 +582,10 @@ if (BUILD_UNITTESTS)
add_subdirectory( apps/openmw_test_suite )
endif()
if (BUILD_BENCHMARKS)
add_subdirectory(apps/benchmarks)
endif()
if (WIN32)
if (MSVC)
if (OPENMW_MP_BUILD)
@ -606,63 +633,13 @@ if (WIN32)
# Play a bit with the warning levels
set(WARNINGS "/Wall") # Since windows can only disable specific warnings, not enable them
set(WARNINGS "/W4")
set(WARNINGS_DISABLE
# Warnings that aren't enabled normally and don't need to be enabled
# 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
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 5219 5220
# Warnings that are thrown on standard libraries and not OpenMW
4347 # Non-template function with same name and parameter count as template function
4365 # Variable signed/unsigned mismatch
4510 4512 # Unable to generate copy constructor/assignment operator as it's not public in the base
4706 # Assignment in conditional expression
4738 # Storing 32-bit float result in memory, possible loss of performance
4774 # Format string expected in argument is not a string literal
4986 # Undocumented warning that occurs in the crtdbg.h file
4987 # nonstandard extension used (triggered by setjmp.h)
4996 # Function was declared deprecated
# caused by OSG
4589 # Constructor of abstract class 'osg::Operation' ignores initializer for virtual base class 'osg::Referenced' (False warning)
# caused by boost
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
4643 # Forward declaring 'X' in namespace std is not permitted by the C++ Standard. (in *_std_fwd.h files)
5204 # Class has virtual functions, but its trivial destructor is not virtual
# caused by MyGUI
4297 # function assumed not to throw an exception but does
# OpenMW specific warnings
4099 # Type mismatch, declared class or struct is defined with other type
4100 # Unreferenced formal parameter (-Wunused-parameter)
4101 # Unreferenced local variable (-Wunused-variable)
4127 # Conditional expression is constant
4242 # Storing value in a variable of a smaller type, possible loss of data
4244 # Storing value of one type in variable of another (size_t in int, for example)
4245 # Signed/unsigned mismatch
4267 # Conversion from 'size_t' to 'int', possible loss of data
4305 # Truncating value (double to float, for example)
4309 # Variable overflow, trying to store 128 in a signed char for example
4351 # New behavior: elements of array 'array' will be default initialized (desired behavior)
4355 # Using 'this' in member initialization list
4464 # relative include path contains '..'
4505 # Unreferenced local function has been removed
4701 # Potentially uninitialized local variable used
4702 # Unreachable code
4714 # function 'QString QString::trimmed(void) &&' marked as __forceinline not inlined
4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt
)
if (MSVC_VERSION GREATER 1800)
set(WARNINGS_DISABLE ${WARNINGS_DISABLE} 5026 5027
5031 # #pragma warning(pop): likely mismatch, popping warning state pushed in different file (config_begin.hpp, config_end.hpp)
4996 # Function was declared deprecated
)
endif()
if( "${MyGUI_VERSION}" VERSION_LESS_EQUAL "3.4.0" )
set(WARNINGS_DISABLE ${WARNINGS_DISABLE}
@ -730,6 +707,10 @@ if (WIN32)
if (BUILD_WIZARD)
set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
if (BUILD_BENCHMARKS)
set_target_properties(openmw_detournavigator_navmeshtilescache_benchmark PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
endif(MSVC)
# TODO: At some point release builds should not use the console but rather write to a log file
@ -869,7 +850,7 @@ elseif(NOT APPLE)
INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt")
INSTALL(FILES "${OpenMW_SOURCE_DIR}/LICENSE" DESTINATION "." RENAME "LICENSE.txt")
INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/mygui/DejaVuFontLicense.txt" DESTINATION ".")
INSTALL(FILES "${INSTALL_SOURCE}/settings-default.cfg" DESTINATION ".")
INSTALL(FILES "${INSTALL_SOURCE}/defaults.bin" DESTINATION ".")
INSTALL(FILES "${INSTALL_SOURCE}/gamecontrollerdb.txt" DESTINATION ".")
INSTALL(FILES "${INSTALL_SOURCE}/xrcontrollersuggestions.xml" DESTINATION ".")
@ -912,13 +893,13 @@ elseif(NOT APPLE)
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
if(EXISTS ${VCREDIST32})
INSTALL(FILES ${VCREDIST32} DESTINATION "redist")
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x86.exe\\\" /q'" )
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x86.exe\\\" /q /norestart'" )
endif(EXISTS ${VCREDIST32})
SET(VCREDIST64 "${OpenMW_BINARY_DIR}/vcredist_x64.exe")
if(EXISTS ${VCREDIST64})
INSTALL(FILES ${VCREDIST64} DESTINATION "redist")
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x64.exe\\\" /q'" )
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x64.exe\\\" /q /norestart'" )
endif(EXISTS ${VCREDIST64})
SET(OALREDIST "${OpenMW_BINARY_DIR}/oalinst.exe")
@ -978,14 +959,14 @@ elseif(NOT APPLE)
ENDIF(BUILD_OPENCS)
# Install global configuration files
INSTALL(FILES "${INSTALL_SOURCE}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${INSTALL_SOURCE}/defaults.bin" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${INSTALL_SOURCE}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw")
INSTALL(FILES "${INSTALL_SOURCE}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${INSTALL_SOURCE}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${INSTALL_SOURCE}/xrcontrollersuggestions.xml" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
IF(BUILD_OPENCS)
INSTALL(FILES "${INSTALL_SOURCE}/openmw-cs.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs")
INSTALL(FILES "${INSTALL_SOURCE}/defaults-cs.bin" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs")
ENDIF(BUILD_OPENCS)
# Install resources

@ -12,7 +12,7 @@ OpenMW also comes with OpenMW-CS, a replacement for Bethesda's Construction Set.
* Version: 0.47.0
* License: GPLv3 (see [LICENSE](https://github.com/OpenMW/openmw/blob/master/LICENSE) for more information)
* Website: https://www.openmw.org
* IRC: #openmw on irc.freenode.net
* IRC: #openmw on irc.libera.chat
Font Licenses:
* DejaVuLGCSansMono.ttf: custom (see [files/mygui/DejaVuFontLicense.txt](https://github.com/OpenMW/openmw/blob/master/files/mygui/DejaVuFontLicense.txt) for more information)

@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.11)
set(BENCHMARK_ENABLE_TESTING OFF)
set(BENCHMARK_ENABLE_INSTALL OFF)
set(BENCHMARK_ENABLE_GTEST_TESTS OFF)
set(SAVED_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE "-Wsuggest-override" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE "-Wundef" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
include(FetchContent)
FetchContent_Declare(benchmark
URL https://github.com/google/benchmark/archive/refs/tags/v1.5.2.zip
URL_HASH MD5=49395b757a7c4656d70f1328d93efd00
SOURCE_DIR fetched/benchmark
)
FetchContent_MakeAvailableExcludeFromAll(benchmark)
set(CMAKE_CXX_FLAGS "${SAVED_CMAKE_CXX_FLAGS}")
openmw_add_executable(openmw_detournavigator_navmeshtilescache_benchmark detournavigator/navmeshtilescache.cpp)
target_compile_features(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE cxx_std_17)
target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark benchmark::benchmark components)
if (UNIX AND NOT APPLE)
target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark ${CMAKE_THREAD_LIBS_INIT})
endif()

@ -0,0 +1,214 @@
#include <benchmark/benchmark.h>
#include <components/detournavigator/navmeshtilescache.hpp>
#include <algorithm>
#include <random>
#include <iostream>
namespace
{
using namespace DetourNavigator;
struct Key
{
osg::Vec3f mAgentHalfExtents;
TilePosition mTilePosition;
RecastMesh mRecastMesh;
std::vector<OffMeshConnection> mOffMeshConnections;
};
struct Item
{
Key mKey;
NavMeshData mValue;
};
template <typename Random>
TilePosition generateTilePosition(int max, Random& random)
{
std::uniform_int_distribution<int> distribution(0, max);
return TilePosition(distribution(random), distribution(random));
}
template <typename Random>
osg::Vec3f generateAgentHalfExtents(float min, float max, Random& random)
{
std::uniform_int_distribution<int> distribution(min, max);
return osg::Vec3f(distribution(random), distribution(random), distribution(random));
}
template <typename OutputIterator, typename Random>
void generateVertices(OutputIterator out, std::size_t number, Random& random)
{
std::uniform_real_distribution<float> distribution(0.0, 1.0);
std::generate_n(out, 3 * (number - number % 3), [&] { return distribution(random); });
}
template <typename OutputIterator, typename Random>
void generateIndices(OutputIterator out, int max, std::size_t number, Random& random)
{
std::uniform_int_distribution<int> distribution(0, max);
std::generate_n(out, number - number % 3, [&] { return distribution(random); });
}
AreaType toAreaType(int index)
{
switch (index)
{
case 0: return AreaType_null;
case 1: return AreaType_water;
case 2: return AreaType_door;
case 3: return AreaType_pathgrid;
case 4: return AreaType_ground;
}
return AreaType_null;
}
template <typename Random>
AreaType generateAreaType(Random& random)
{
std::uniform_int_distribution<int> distribution(0, 4);
return toAreaType(distribution(random));;
}
template <typename OutputIterator, typename Random>
void generateAreaTypes(OutputIterator out, std::size_t triangles, Random& random)
{
std::generate_n(out, triangles, [&] { return generateAreaType(random); });
}
template <typename OutputIterator, typename Random>
void generateWater(OutputIterator out, std::size_t count, Random& random)
{
std::uniform_real_distribution<btScalar> distribution(0.0, 1.0);
std::generate_n(out, count, [&] {
const btVector3 shift(distribution(random), distribution(random), distribution(random));
return RecastMesh::Water {1, btTransform(btMatrix3x3::getIdentity(), shift)};
});
}
template <typename OutputIterator, typename Random>
void generateOffMeshConnection(OutputIterator out, std::size_t count, Random& random)
{
std::uniform_real_distribution<btScalar> distribution(0.0, 1.0);
std::generate_n(out, count, [&] {
const osg::Vec3f start(distribution(random), distribution(random), distribution(random));
const osg::Vec3f end(distribution(random), distribution(random), distribution(random));
return OffMeshConnection {start, end, generateAreaType(random)};
});
}
template <class Random>
Key generateKey(std::size_t triangles, Random& random)
{
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random);
const TilePosition tilePosition = generateTilePosition(10000, random);
const std::size_t generation = std::uniform_int_distribution<std::size_t>(0, 100)(random);
const std::size_t revision = std::uniform_int_distribution<std::size_t>(0, 10000)(random);
std::vector<float> vertices;
generateVertices(std::back_inserter(vertices), triangles * 1.98, random);
std::vector<int> indices;
generateIndices(std::back_inserter(indices), static_cast<int>(vertices.size() / 3) - 1, vertices.size() * 1.53, random);
std::vector<AreaType> areaTypes;
generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random);
std::vector<RecastMesh::Water> water;
generateWater(std::back_inserter(water), 2, random);
RecastMesh recastMesh(generation, revision, std::move(indices), std::move(vertices),
std::move(areaTypes), std::move(water));
std::vector<OffMeshConnection> offMeshConnections;
generateOffMeshConnection(std::back_inserter(offMeshConnections), 300, random);
return Key {agentHalfExtents, tilePosition, std::move(recastMesh), std::move(offMeshConnections)};
}
constexpr std::size_t trianglesPerTile = 310;
template <typename OutputIterator, typename Random>
void generateKeys(OutputIterator out, std::size_t count, Random& random)
{
std::generate_n(out, count, [&] { return generateKey(trianglesPerTile, random); });
}
template <typename OutputIterator, typename Random>
void fillCache(OutputIterator out, Random& random, NavMeshTilesCache& cache)
{
std::size_t size = cache.getStats().mNavMeshCacheSize;
while (true)
{
Key key = generateKey(trianglesPerTile, random);
cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh, key.mOffMeshConnections, NavMeshData());
*out++ = std::move(key);
const std::size_t newSize = cache.getStats().mNavMeshCacheSize;
if (size >= newSize)
break;
size = newSize;
}
}
template <std::size_t maxCacheSize, int hitPercentage>
void getFromFilledCache(benchmark::State& state)
{
NavMeshTilesCache cache(maxCacheSize);
std::minstd_rand random;
std::vector<Key> keys;
fillCache(std::back_inserter(keys), random, cache);
generateKeys(std::back_inserter(keys), keys.size() * (100 - hitPercentage) / 100, random);
std::size_t n = 0;
while (state.KeepRunning())
{
const auto& key = keys[n++ % keys.size()];
const auto result = cache.get(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh, key.mOffMeshConnections);
benchmark::DoNotOptimize(result);
}
}
constexpr auto getFromFilledCache_1m_100hit = getFromFilledCache<1 * 1024 * 1024, 100>;
constexpr auto getFromFilledCache_4m_100hit = getFromFilledCache<4 * 1024 * 1024, 100>;
constexpr auto getFromFilledCache_16m_100hit = getFromFilledCache<16 * 1024 * 1024, 100>;
constexpr auto getFromFilledCache_64m_100hit = getFromFilledCache<64 * 1024 * 1024, 100>;
constexpr auto getFromFilledCache_1m_70hit = getFromFilledCache<1 * 1024 * 1024, 70>;
constexpr auto getFromFilledCache_4m_70hit = getFromFilledCache<4 * 1024 * 1024, 70>;
constexpr auto getFromFilledCache_16m_70hit = getFromFilledCache<16 * 1024 * 1024, 70>;
constexpr auto getFromFilledCache_64m_70hit = getFromFilledCache<64 * 1024 * 1024, 70>;
template <std::size_t maxCacheSize>
void setToBoundedNonEmptyCache(benchmark::State& state)
{
NavMeshTilesCache cache(maxCacheSize);
std::minstd_rand random;
std::vector<Key> keys;
fillCache(std::back_inserter(keys), random, cache);
generateKeys(std::back_inserter(keys), keys.size() * 2, random);
std::reverse(keys.begin(), keys.end());
std::size_t n = 0;
while (state.KeepRunning())
{
const auto& key = keys[n++ % keys.size()];
const auto result = cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh, key.mOffMeshConnections, NavMeshData());
benchmark::DoNotOptimize(result);
}
}
constexpr auto setToBoundedNonEmptyCache_1m = setToBoundedNonEmptyCache<1 * 1024 * 1024>;
constexpr auto setToBoundedNonEmptyCache_4m = setToBoundedNonEmptyCache<4 * 1024 * 1024>;
constexpr auto setToBoundedNonEmptyCache_16m = setToBoundedNonEmptyCache<16 * 1024 * 1024>;
constexpr auto setToBoundedNonEmptyCache_64m = setToBoundedNonEmptyCache<64 * 1024 * 1024>;
} // namespace
BENCHMARK(getFromFilledCache_1m_100hit);
BENCHMARK(getFromFilledCache_4m_100hit);
BENCHMARK(getFromFilledCache_16m_100hit);
BENCHMARK(getFromFilledCache_64m_100hit);
BENCHMARK(getFromFilledCache_1m_70hit);
BENCHMARK(getFromFilledCache_4m_70hit);
BENCHMARK(getFromFilledCache_16m_70hit);
BENCHMARK(getFromFilledCache_64m_70hit);
BENCHMARK(setToBoundedNonEmptyCache_1m);
BENCHMARK(setToBoundedNonEmptyCache_4m);
BENCHMARK(setToBoundedNonEmptyCache_16m);
BENCHMARK(setToBoundedNonEmptyCache_64m);
BENCHMARK_MAIN();

@ -2,6 +2,7 @@
#include <vector>
#include <deque>
#include <list>
#include <unordered_set>
#include <map>
#include <set>
#include <fstream>
@ -322,7 +323,7 @@ int load(Arguments& info)
std::string filename = info.filename;
std::cout << "Loading file: " << filename << std::endl;
std::list<uint32_t> skipped;
std::unordered_set<uint32_t> skipped;
try {
@ -364,17 +365,17 @@ int load(Arguments& info)
// Loop through all records
while(esm.hasMoreRecs())
{
ESM::NAME n = esm.getRecName();
const ESM::NAME n = esm.getRecName();
uint32_t flags;
esm.getRecHeader(flags);
EsmTool::RecordBase *record = EsmTool::RecordBase::create(n);
if (record == nullptr)
{
if (std::find(skipped.begin(), skipped.end(), n.intval) == skipped.end())
if (skipped.count(n.intval) == 0)
{
std::cout << "Skipping " << n.toString() << " records." << std::endl;
skipped.push_back(n.intval);
skipped.emplace(n.intval);
}
esm.skipRecord();

@ -172,7 +172,7 @@ void printTransport(const std::vector<ESM::Transport::Dest>& transport)
namespace EsmTool {
RecordBase *
RecordBase::create(ESM::NAME type)
RecordBase::create(const ESM::NAME type)
{
RecordBase *record = nullptr;

@ -3,10 +3,8 @@
#include <array>
#include <components/config/gamesettings.hpp>
#include <components/config/launchersettings.hpp>
#include <QFileDialog>
#include <QCompleter>
#include <QProxyStyle>
#include <QString>
#include <components/contentselector/view/contentselector.hpp>
#include <components/contentselector/model/esmfile.hpp>
@ -15,11 +13,9 @@
#include "utils/openalutil.hpp"
Launcher::AdvancedPage::AdvancedPage(Config::GameSettings &gameSettings,
Settings::Manager &engineSettings, QWidget *parent)
Launcher::AdvancedPage::AdvancedPage(Config::GameSettings &gameSettings, QWidget *parent)
: QWidget(parent)
, mGameSettings(gameSettings)
, mEngineSettings(engineSettings)
{
setObjectName ("AdvancedPage");
setupUi(this);
@ -102,12 +98,12 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game");
loadSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game");
loadSettingBool(avoidCollisionsCheckBox, "NPCs avoid collisions", "Game");
int unarmedFactorsStrengthIndex = mEngineSettings.getInt("strength influences hand to hand", "Game");
int unarmedFactorsStrengthIndex = Settings::Manager::getInt("strength influences hand to hand", "Game");
if (unarmedFactorsStrengthIndex >= 0 && unarmedFactorsStrengthIndex <= 2)
unarmedFactorsStrengthComboBox->setCurrentIndex(unarmedFactorsStrengthIndex);
loadSettingBool(stealingFromKnockedOutCheckBox, "always allow stealing from knocked out actors", "Game");
loadSettingBool(enableNavigatorCheckBox, "enable", "Navigator");
int numPhysicsThreads = mEngineSettings.getInt("async num threads", "Physics");
int numPhysicsThreads = Settings::Manager::getInt("async num threads", "Physics");
if (numPhysicsThreads >= 0)
physicsThreadsSpinBox->setValue(numPhysicsThreads);
loadSettingBool(allowNPCToFollowOverWaterSurfaceCheckBox, "allow actors to follow over water surface", "Game");
@ -132,26 +128,20 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(turnToMovementDirectionCheckBox, "turn to movement direction", "Game");
loadSettingBool(smoothMovementCheckBox, "smooth movement", "Game");
const bool distantTerrain = mEngineSettings.getBool("distant terrain", "Terrain");
const bool objectPaging = mEngineSettings.getBool("object paging", "Terrain");
const bool distantTerrain = Settings::Manager::getBool("distant terrain", "Terrain");
const bool objectPaging = Settings::Manager::getBool("object paging", "Terrain");
if (distantTerrain && objectPaging) {
distantLandCheckBox->setCheckState(Qt::Checked);
}
loadSettingBool(activeGridObjectPagingCheckBox, "object paging active grid", "Terrain");
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);
viewingDistanceComboBox->setValue(convertToCells(Settings::Manager::getInt("viewing distance", "Camera")));
objectPagingMinSizeComboBox->setValue(Settings::Manager::getDouble("object paging min size", "Terrain"));
}
// Audio
{
std::string selectedAudioDevice = mEngineSettings.getString("device", "Sound");
std::string selectedAudioDevice = Settings::Manager::getString("device", "Sound");
if (selectedAudioDevice.empty() == false)
{
int audioDeviceIndex = audioDeviceSelectorComboBox->findData(QString::fromStdString(selectedAudioDevice));
@ -160,12 +150,12 @@ bool Launcher::AdvancedPage::loadSettings()
audioDeviceSelectorComboBox->setCurrentIndex(audioDeviceIndex);
}
}
int hrtfEnabledIndex = mEngineSettings.getInt("hrtf enable", "Sound");
int hrtfEnabledIndex = Settings::Manager::getInt("hrtf enable", "Sound");
if (hrtfEnabledIndex >= -1 && hrtfEnabledIndex <= 1)
{
enableHRTFComboBox->setCurrentIndex(hrtfEnabledIndex + 1);
}
std::string selectedHRTFProfile = mEngineSettings.getString("hrtf", "Sound");
std::string selectedHRTFProfile = Settings::Manager::getString("hrtf", "Sound");
if (selectedHRTFProfile.empty() == false)
{
int hrtfProfileIndex = hrtfProfileSelectorComboBox->findData(QString::fromStdString(selectedHRTFProfile));
@ -187,7 +177,7 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(deferredPreviewRotationCheckBox, "deferred preview rotation", "Camera");
loadSettingBool(headBobbingCheckBox, "head bobbing", "Camera");
defaultShoulderComboBox->setCurrentIndex(
mEngineSettings.getVector2("view over shoulder offset", "Camera").x() >= 0 ? 0 : 1);
Settings::Manager::getVector2("view over shoulder offset", "Camera").x() >= 0 ? 0 : 1);
}
// Interface Changes
@ -197,13 +187,13 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
loadSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
loadSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI");
int showOwnedIndex = mEngineSettings.getInt("show owned", "Game");
int showOwnedIndex = Settings::Manager::getInt("show owned", "Game");
// Match the index with the option (only 0, 1, 2, or 3 are valid). Will default to 0 if invalid.
if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
loadSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
scalingSpinBox->setValue(mEngineSettings.getFloat("scaling factor", "GUI"));
scalingSpinBox->setValue(Settings::Manager::getFloat("scaling factor", "GUI"));
}
// Bug fixes
@ -216,10 +206,10 @@ bool Launcher::AdvancedPage::loadSettings()
{
// Saves
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
maximumQuicksavesComboBox->setValue(mEngineSettings.getInt("max quicksaves", "Saves"));
maximumQuicksavesComboBox->setValue(Settings::Manager::getInt("max quicksaves", "Saves"));
// Other Settings
QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper();
QString screenshotFormatString = QString::fromStdString(Settings::Manager::getString("screenshot format", "General")).toUpper();
if (screenshotFormatComboBox->findText(screenshotFormatString) == -1)
screenshotFormatComboBox->addItem(screenshotFormatString);
screenshotFormatComboBox->setCurrentIndex(screenshotFormatComboBox->findText(screenshotFormatString));
@ -280,13 +270,13 @@ void Launcher::AdvancedPage::saveSettings()
saveSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game");
saveSettingBool(avoidCollisionsCheckBox, "NPCs avoid collisions", "Game");
int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex();
if (unarmedFactorsStrengthIndex != mEngineSettings.getInt("strength influences hand to hand", "Game"))
mEngineSettings.setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex);
if (unarmedFactorsStrengthIndex != Settings::Manager::getInt("strength influences hand to hand", "Game"))
Settings::Manager::setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex);
saveSettingBool(stealingFromKnockedOutCheckBox, "always allow stealing from knocked out actors", "Game");
saveSettingBool(enableNavigatorCheckBox, "enable", "Navigator");
int numPhysicsThreads = physicsThreadsSpinBox->value();
if (numPhysicsThreads != mEngineSettings.getInt("async num threads", "Physics"))
mEngineSettings.setInt("async num threads", "Physics", numPhysicsThreads);
if (numPhysicsThreads != Settings::Manager::getInt("async num threads", "Physics"))
Settings::Manager::setInt("async num threads", "Physics", numPhysicsThreads);
}
// Visuals
@ -304,23 +294,23 @@ void Launcher::AdvancedPage::saveSettings()
saveSettingBool(turnToMovementDirectionCheckBox, "turn to movement direction", "Game");
saveSettingBool(smoothMovementCheckBox, "smooth movement", "Game");
const bool distantTerrain = mEngineSettings.getBool("distant terrain", "Terrain");
const bool objectPaging = mEngineSettings.getBool("object paging", "Terrain");
const bool distantTerrain = Settings::Manager::getBool("distant terrain", "Terrain");
const bool objectPaging = Settings::Manager::getBool("object paging", "Terrain");
const bool wantDistantLand = distantLandCheckBox->checkState();
if (wantDistantLand != (distantTerrain && objectPaging)) {
mEngineSettings.setBool("distant terrain", "Terrain", wantDistantLand);
mEngineSettings.setBool("object paging", "Terrain", wantDistantLand);
Settings::Manager::setBool("distant terrain", "Terrain", wantDistantLand);
Settings::Manager::setBool("object paging", "Terrain", wantDistantLand);
}
saveSettingBool(activeGridObjectPagingCheckBox, "object paging active grid", "Terrain");
double viewingDistance = viewingDistanceComboBox->value();
if (viewingDistance != convertToCells(mEngineSettings.getInt("viewing distance", "Camera")))
if (viewingDistance != convertToCells(Settings::Manager::getInt("viewing distance", "Camera")))
{
mEngineSettings.setInt("viewing distance", "Camera", convertToUnits(viewingDistance));
Settings::Manager::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()]);
double objectPagingMinSize = objectPagingMinSizeComboBox->value();
if (objectPagingMinSize != Settings::Manager::getDouble("object paging min size", "Terrain"))
Settings::Manager::setDouble("object paging min size", "Terrain", objectPagingMinSize);
}
// Audio
@ -328,25 +318,25 @@ void Launcher::AdvancedPage::saveSettings()
int audioDeviceIndex = audioDeviceSelectorComboBox->currentIndex();
if (audioDeviceIndex != 0)
{
mEngineSettings.setString("device", "Sound", audioDeviceSelectorComboBox->currentText().toUtf8().constData());
Settings::Manager::setString("device", "Sound", audioDeviceSelectorComboBox->currentText().toUtf8().constData());
}
else
{
mEngineSettings.setString("device", "Sound", "");
Settings::Manager::setString("device", "Sound", "");
}
int hrtfEnabledIndex = enableHRTFComboBox->currentIndex() - 1;
if (hrtfEnabledIndex != mEngineSettings.getInt("hrtf enable", "Sound"))
if (hrtfEnabledIndex != Settings::Manager::getInt("hrtf enable", "Sound"))
{
mEngineSettings.setInt("hrtf enable", "Sound", hrtfEnabledIndex);
Settings::Manager::setInt("hrtf enable", "Sound", hrtfEnabledIndex);
}
int selectedHRTFProfileIndex = hrtfProfileSelectorComboBox->currentIndex();
if (selectedHRTFProfileIndex != 0)
{
mEngineSettings.setString("hrtf", "Sound", hrtfProfileSelectorComboBox->currentText().toUtf8().constData());
Settings::Manager::setString("hrtf", "Sound", hrtfProfileSelectorComboBox->currentText().toUtf8().constData());
}
else
{
mEngineSettings.setString("hrtf", "Sound", "");
Settings::Manager::setString("hrtf", "Sound", "");
}
}
@ -358,14 +348,14 @@ void Launcher::AdvancedPage::saveSettings()
saveSettingBool(deferredPreviewRotationCheckBox, "deferred preview rotation", "Camera");
saveSettingBool(headBobbingCheckBox, "head bobbing", "Camera");
osg::Vec2f shoulderOffset = mEngineSettings.getVector2("view over shoulder offset", "Camera");
osg::Vec2f shoulderOffset = Settings::Manager::getVector2("view over shoulder offset", "Camera");
if (defaultShoulderComboBox->currentIndex() != (shoulderOffset.x() >= 0 ? 0 : 1))
{
if (defaultShoulderComboBox->currentIndex() == 0)
shoulderOffset.x() = std::abs(shoulderOffset.x());
else
shoulderOffset.x() = -std::abs(shoulderOffset.x());
mEngineSettings.setVector2("view over shoulder offset", "Camera", shoulderOffset);
Settings::Manager::setVector2("view over shoulder offset", "Camera", shoulderOffset);
}
}
@ -377,13 +367,13 @@ void Launcher::AdvancedPage::saveSettings()
saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
saveSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI");
int showOwnedCurrentIndex = showOwnedComboBox->currentIndex();
if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game"))
mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex);
if (showOwnedCurrentIndex != Settings::Manager::getInt("show owned", "Game"))
Settings::Manager::setInt("show owned", "Game", showOwnedCurrentIndex);
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
float uiScalingFactor = scalingSpinBox->value();
if (uiScalingFactor != mEngineSettings.getFloat("scaling factor", "GUI"))
mEngineSettings.setFloat("scaling factor", "GUI", uiScalingFactor);
if (uiScalingFactor != Settings::Manager::getFloat("scaling factor", "GUI"))
Settings::Manager::setFloat("scaling factor", "GUI", uiScalingFactor);
}
// Bug fixes
@ -397,15 +387,15 @@ void Launcher::AdvancedPage::saveSettings()
// Saves Settings
saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
int maximumQuicksaves = maximumQuicksavesComboBox->value();
if (maximumQuicksaves != mEngineSettings.getInt("max quicksaves", "Saves"))
if (maximumQuicksaves != Settings::Manager::getInt("max quicksaves", "Saves"))
{
mEngineSettings.setInt("max quicksaves", "Saves", maximumQuicksaves);
Settings::Manager::setInt("max quicksaves", "Saves", maximumQuicksaves);
}
// Other Settings
std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString();
if (screenshotFormatString != mEngineSettings.getString("screenshot format", "General"))
mEngineSettings.setString("screenshot format", "General", screenshotFormatString);
if (screenshotFormatString != Settings::Manager::getString("screenshot format", "General"))
Settings::Manager::setString("screenshot format", "General", screenshotFormatString);
}
// Testing
@ -457,15 +447,15 @@ void Launcher::AdvancedPage::saveSettings()
void Launcher::AdvancedPage::loadSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group)
{
if (mEngineSettings.getBool(setting, group))
if (Settings::Manager::getBool(setting, group))
checkbox->setCheckState(Qt::Checked);
}
void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group)
{
bool cValue = checkbox->checkState();
if (cValue != mEngineSettings.getBool(setting, group))
mEngineSettings.setBool(setting, group, cValue);
if (cValue != Settings::Manager::getBool(setting, group))
Settings::Manager::setBool(setting, group, cValue);
}
void Launcher::AdvancedPage::slotLoadedCellsChanged(QStringList cellNames)

@ -1,7 +1,6 @@
#ifndef ADVANCEDPAGE_H
#define ADVANCEDPAGE_H
#include <QWidget>
#include <QCompleter>
#include <QStringListModel>
@ -18,8 +17,7 @@ namespace Launcher
Q_OBJECT
public:
AdvancedPage(Config::GameSettings &gameSettings,
Settings::Manager &engineSettings, QWidget *parent = nullptr);
explicit AdvancedPage(Config::GameSettings &gameSettings, QWidget *parent = nullptr);
bool loadSettings();
void saveSettings();
@ -35,7 +33,6 @@ namespace Launcher
private:
Config::GameSettings &mGameSettings;
Settings::Manager &mEngineSettings;
QCompleter mCellNameCompleter;
QStringListModel mCellNameCompleterModel;

@ -4,7 +4,6 @@
#include <QPushButton>
#include <QMessageBox>
#include <QCheckBox>
#include <QMenu>
#include <QSortFilterProxyModel>
#include <thread>
@ -14,7 +13,6 @@
#include <components/files/configurationmanager.hpp>
#include <components/contentselector/model/esmfile.hpp>
#include <components/contentselector/model/naturalsort.hpp>
#include <components/contentselector/view/contentselector.hpp>
#include <components/config/gamesettings.hpp>

@ -6,7 +6,6 @@
#include <QDir>
#include <QFile>
#include <QStringList>
class QSortFilterProxyModel;

@ -32,9 +32,8 @@ QString getAspect(int x, int y)
return QString(QString::number(xaspect) + ":" + QString::number(yaspect));
}
Launcher::GraphicsPage::GraphicsPage(Settings::Manager &engineSettings, QWidget *parent)
Launcher::GraphicsPage::GraphicsPage(QWidget *parent)
: QWidget(parent)
, mEngineSettings(engineSettings)
{
setObjectName ("GraphicsPage");
setupUi(this);
@ -93,26 +92,27 @@ bool Launcher::GraphicsPage::loadSettings()
if (!setupSDL())
return false;
if (mEngineSettings.getBool("vsync", "Video"))
// Visuals
if (Settings::Manager::getBool("vsync", "Video"))
vSyncCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("fullscreen", "Video"))
if (Settings::Manager::getBool("fullscreen", "Video"))
fullScreenCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("window border", "Video"))
if (Settings::Manager::getBool("window border", "Video"))
windowBorderCheckBox->setCheckState(Qt::Checked);
// aaValue is the actual value (0, 1, 2, 4, 8, 16)
int aaValue = mEngineSettings.getInt("antialiasing", "Video");
int aaValue = Settings::Manager::getInt("antialiasing", "Video");
// aaIndex is the index into the allowed values in the pull down.
int aaIndex = antiAliasingComboBox->findText(QString::number(aaValue));
if (aaIndex != -1)
antiAliasingComboBox->setCurrentIndex(aaIndex);
int width = mEngineSettings.getInt("resolution x", "Video");
int height = mEngineSettings.getInt("resolution y", "Video");
int width = Settings::Manager::getInt("resolution x", "Video");
int height = Settings::Manager::getInt("resolution y", "Video");
QString resolution = QString::number(width) + QString(" x ") + QString::number(height);
screenComboBox->setCurrentIndex(mEngineSettings.getInt("screen", "Video"));
screenComboBox->setCurrentIndex(Settings::Manager::getInt("screen", "Video"));
int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith);
@ -125,40 +125,49 @@ bool Launcher::GraphicsPage::loadSettings()
customHeightSpinBox->setValue(height);
}
float fpsLimit = mEngineSettings.getFloat("framerate limit", "Video");
float fpsLimit = Settings::Manager::getFloat("framerate limit", "Video");
if (fpsLimit != 0)
{
framerateLimitCheckBox->setCheckState(Qt::Checked);
framerateLimitSpinBox->setValue(fpsLimit);
}
if (mEngineSettings.getBool("actor shadows", "Shadows"))
// Lighting
int lightingMethod = 1;
if (Settings::Manager::getString("lighting method", "Shaders") == "legacy")
lightingMethod = 0;
else if (Settings::Manager::getString("lighting method", "Shaders") == "shaders")
lightingMethod = 2;
lightingMethodComboBox->setCurrentIndex(lightingMethod);
// Shadows
if (Settings::Manager::getBool("actor shadows", "Shadows"))
actorShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("player shadows", "Shadows"))
if (Settings::Manager::getBool("player shadows", "Shadows"))
playerShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("terrain shadows", "Shadows"))
if (Settings::Manager::getBool("terrain shadows", "Shadows"))
terrainShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("object shadows", "Shadows"))
if (Settings::Manager::getBool("object shadows", "Shadows"))
objectShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("enable indoor shadows", "Shadows"))
if (Settings::Manager::getBool("enable indoor shadows", "Shadows"))
indoorShadowsCheckBox->setCheckState(Qt::Checked);
shadowComputeSceneBoundsComboBox->setCurrentIndex(
shadowComputeSceneBoundsComboBox->findText(
QString(tr(mEngineSettings.getString("compute scene bounds", "Shadows").c_str()))));
QString(tr(Settings::Manager::getString("compute scene bounds", "Shadows").c_str()))));
int shadowDistLimit = mEngineSettings.getInt("maximum shadow map distance", "Shadows");
int shadowDistLimit = Settings::Manager::getInt("maximum shadow map distance", "Shadows");
if (shadowDistLimit > 0)
{
shadowDistanceCheckBox->setCheckState(Qt::Checked);
shadowDistanceSpinBox->setValue(shadowDistLimit);
}
float shadowFadeStart = mEngineSettings.getFloat("shadow fade start", "Shadows");
float shadowFadeStart = Settings::Manager::getFloat("shadow fade start", "Shadows");
if (shadowFadeStart != 0)
fadeStartSpinBox->setValue(shadowFadeStart);
int shadowRes = mEngineSettings.getInt("shadow map resolution", "Shadows");
int shadowRes = Settings::Manager::getInt("shadow map resolution", "Shadows");
int shadowResIndex = shadowResolutionComboBox->findText(QString::number(shadowRes));
if (shadowResIndex != -1)
shadowResolutionComboBox->setCurrentIndex(shadowResIndex);
@ -168,23 +177,25 @@ bool Launcher::GraphicsPage::loadSettings()
void Launcher::GraphicsPage::saveSettings()
{
// Visuals
// Ensure we only set the new settings if they changed. This is to avoid cluttering the
// user settings file (which by definition should only contain settings the user has touched)
bool cVSync = vSyncCheckBox->checkState();
if (cVSync != mEngineSettings.getBool("vsync", "Video"))
mEngineSettings.setBool("vsync", "Video", cVSync);
if (cVSync != Settings::Manager::getBool("vsync", "Video"))
Settings::Manager::setBool("vsync", "Video", cVSync);
bool cFullScreen = fullScreenCheckBox->checkState();
if (cFullScreen != mEngineSettings.getBool("fullscreen", "Video"))
mEngineSettings.setBool("fullscreen", "Video", cFullScreen);
if (cFullScreen != Settings::Manager::getBool("fullscreen", "Video"))
Settings::Manager::setBool("fullscreen", "Video", cFullScreen);
bool cWindowBorder = windowBorderCheckBox->checkState();
if (cWindowBorder != mEngineSettings.getBool("window border", "Video"))
mEngineSettings.setBool("window border", "Video", cWindowBorder);
if (cWindowBorder != Settings::Manager::getBool("window border", "Video"))
Settings::Manager::setBool("window border", "Video", cWindowBorder);
int cAAValue = antiAliasingComboBox->currentText().toInt();
if (cAAValue != mEngineSettings.getInt("antialiasing", "Video"))
mEngineSettings.setInt("antialiasing", "Video", cAAValue);
if (cAAValue != Settings::Manager::getInt("antialiasing", "Video"))
Settings::Manager::setInt("antialiasing", "Video", cAAValue);
int cWidth = 0;
int cHeight = 0;
@ -199,33 +210,38 @@ void Launcher::GraphicsPage::saveSettings()
cHeight = customHeightSpinBox->value();
}
if (cWidth != mEngineSettings.getInt("resolution x", "Video"))
mEngineSettings.setInt("resolution x", "Video", cWidth);
if (cWidth != Settings::Manager::getInt("resolution x", "Video"))
Settings::Manager::setInt("resolution x", "Video", cWidth);
if (cHeight != mEngineSettings.getInt("resolution y", "Video"))
mEngineSettings.setInt("resolution y", "Video", cHeight);
if (cHeight != Settings::Manager::getInt("resolution y", "Video"))
Settings::Manager::setInt("resolution y", "Video", cHeight);
int cScreen = screenComboBox->currentIndex();
if (cScreen != mEngineSettings.getInt("screen", "Video"))
mEngineSettings.setInt("screen", "Video", cScreen);
if (cScreen != Settings::Manager::getInt("screen", "Video"))
Settings::Manager::setInt("screen", "Video", cScreen);
if (framerateLimitCheckBox->checkState() != Qt::Unchecked)
{
float cFpsLimit = framerateLimitSpinBox->value();
if (cFpsLimit != mEngineSettings.getFloat("framerate limit", "Video"))
mEngineSettings.setFloat("framerate limit", "Video", cFpsLimit);
if (cFpsLimit != Settings::Manager::getFloat("framerate limit", "Video"))
Settings::Manager::setFloat("framerate limit", "Video", cFpsLimit);
}
else if (mEngineSettings.getFloat("framerate limit", "Video") != 0)
else if (Settings::Manager::getFloat("framerate limit", "Video") != 0)
{
mEngineSettings.setFloat("framerate limit", "Video", 0);
Settings::Manager::setFloat("framerate limit", "Video", 0);
}
// Lighting
static std::array<std::string, 3> lightingMethodMap = {"legacy", "shaders compatibility", "shaders"};
Settings::Manager::setString("lighting method", "Shaders", lightingMethodMap[lightingMethodComboBox->currentIndex()]);
// Shadows
int cShadowDist = shadowDistanceCheckBox->checkState() != Qt::Unchecked ? shadowDistanceSpinBox->value() : 0;
if (mEngineSettings.getInt("maximum shadow map distance", "Shadows") != cShadowDist)
mEngineSettings.setInt("maximum shadow map distance", "Shadows", cShadowDist);
if (Settings::Manager::getInt("maximum shadow map distance", "Shadows") != cShadowDist)
Settings::Manager::setInt("maximum shadow map distance", "Shadows", cShadowDist);
float cFadeStart = fadeStartSpinBox->value();
if (cShadowDist > 0 && mEngineSettings.getFloat("shadow fade start", "Shadows") != cFadeStart)
mEngineSettings.setFloat("shadow fade start", "Shadows", cFadeStart);
if (cShadowDist > 0 && Settings::Manager::getFloat("shadow fade start", "Shadows") != cFadeStart)
Settings::Manager::setFloat("shadow fade start", "Shadows", cFadeStart);
bool cActorShadows = actorShadowsCheckBox->checkState();
bool cObjectShadows = objectShadowsCheckBox->checkState();
@ -233,42 +249,42 @@ void Launcher::GraphicsPage::saveSettings()
bool cPlayerShadows = playerShadowsCheckBox->checkState();
if (cActorShadows || cObjectShadows || cTerrainShadows || cPlayerShadows)
{
if (!mEngineSettings.getBool("enable shadows", "Shadows"))
mEngineSettings.setBool("enable shadows", "Shadows", true);
if (mEngineSettings.getBool("actor shadows", "Shadows") != cActorShadows)
mEngineSettings.setBool("actor shadows", "Shadows", cActorShadows);
if (mEngineSettings.getBool("player shadows", "Shadows") != cPlayerShadows)
mEngineSettings.setBool("player shadows", "Shadows", cPlayerShadows);
if (mEngineSettings.getBool("object shadows", "Shadows") != cObjectShadows)
mEngineSettings.setBool("object shadows", "Shadows", cObjectShadows);
if (mEngineSettings.getBool("terrain shadows", "Shadows") != cTerrainShadows)
mEngineSettings.setBool("terrain shadows", "Shadows", cTerrainShadows);
if (!Settings::Manager::getBool("enable shadows", "Shadows"))
Settings::Manager::setBool("enable shadows", "Shadows", true);
if (Settings::Manager::getBool("actor shadows", "Shadows") != cActorShadows)
Settings::Manager::setBool("actor shadows", "Shadows", cActorShadows);
if (Settings::Manager::getBool("player shadows", "Shadows") != cPlayerShadows)
Settings::Manager::setBool("player shadows", "Shadows", cPlayerShadows);
if (Settings::Manager::getBool("object shadows", "Shadows") != cObjectShadows)
Settings::Manager::setBool("object shadows", "Shadows", cObjectShadows);
if (Settings::Manager::getBool("terrain shadows", "Shadows") != cTerrainShadows)
Settings::Manager::setBool("terrain shadows", "Shadows", cTerrainShadows);
}
else
{
if (mEngineSettings.getBool("enable shadows", "Shadows"))
mEngineSettings.setBool("enable shadows", "Shadows", false);
if (mEngineSettings.getBool("actor shadows", "Shadows"))
mEngineSettings.setBool("actor shadows", "Shadows", false);
if (mEngineSettings.getBool("player shadows", "Shadows"))
mEngineSettings.setBool("player shadows", "Shadows", false);
if (mEngineSettings.getBool("object shadows", "Shadows"))
mEngineSettings.setBool("object shadows", "Shadows", false);
if (mEngineSettings.getBool("terrain shadows", "Shadows"))
mEngineSettings.setBool("terrain shadows", "Shadows", false);
if (Settings::Manager::getBool("enable shadows", "Shadows"))
Settings::Manager::setBool("enable shadows", "Shadows", false);
if (Settings::Manager::getBool("actor shadows", "Shadows"))
Settings::Manager::setBool("actor shadows", "Shadows", false);
if (Settings::Manager::getBool("player shadows", "Shadows"))
Settings::Manager::setBool("player shadows", "Shadows", false);
if (Settings::Manager::getBool("object shadows", "Shadows"))
Settings::Manager::setBool("object shadows", "Shadows", false);
if (Settings::Manager::getBool("terrain shadows", "Shadows"))
Settings::Manager::setBool("terrain shadows", "Shadows", false);
}
bool cIndoorShadows = indoorShadowsCheckBox->checkState();
if (mEngineSettings.getBool("enable indoor shadows", "Shadows") != cIndoorShadows)
mEngineSettings.setBool("enable indoor shadows", "Shadows", cIndoorShadows);
if (Settings::Manager::getBool("enable indoor shadows", "Shadows") != cIndoorShadows)
Settings::Manager::setBool("enable indoor shadows", "Shadows", cIndoorShadows);
int cShadowRes = shadowResolutionComboBox->currentText().toInt();
if (cShadowRes != mEngineSettings.getInt("shadow map resolution", "Shadows"))
mEngineSettings.setInt("shadow map resolution", "Shadows", cShadowRes);
if (cShadowRes != Settings::Manager::getInt("shadow map resolution", "Shadows"))
Settings::Manager::setInt("shadow map resolution", "Shadows", cShadowRes);
auto cComputeSceneBounds = shadowComputeSceneBoundsComboBox->currentText().toStdString();
if (cComputeSceneBounds != mEngineSettings.getString("compute scene bounds", "Shadows"))
mEngineSettings.setString("compute scene bounds", "Shadows", cComputeSceneBounds);
if (cComputeSceneBounds != Settings::Manager::getString("compute scene bounds", "Shadows"))
Settings::Manager::setString("compute scene bounds", "Shadows", cComputeSceneBounds);
}
QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)

@ -1,8 +1,6 @@
#ifndef GRAPHICSPAGE_H
#define GRAPHICSPAGE_H
#include <QWidget>
#include "ui_graphicspage.h"
#include <components/settings/settings.hpp>
@ -20,7 +18,7 @@ namespace Launcher
Q_OBJECT
public:
GraphicsPage(Settings::Manager &engineSettings, QWidget *parent = nullptr);
explicit GraphicsPage(QWidget *parent = nullptr);
void saveSettings();
bool loadSettings();
@ -35,8 +33,6 @@ namespace Launcher
void slotShadowDistLimitToggled(bool checked);
private:
Settings::Manager &mEngineSettings;
QVector<QStringList> mResolutionsPerScreen;
static QStringList getAvailableResolutions(int screen);

@ -1,10 +1,8 @@
#include <iostream>
#include <QApplication>
#include <QTranslator>
#include <QTextCodec>
#include <QDir>
#include <QDebug>
#ifdef MAC_OS_X_VERSION_MIN_REQUIRED
#undef MAC_OS_X_VERSION_MIN_REQUIRED

@ -5,15 +5,12 @@
#include <QDate>
#include <QMessageBox>
#include <QPushButton>
#include <QFontDatabase>
#include <QInputDialog>
#include <QFileDialog>
#include <QCloseEvent>
#include <QTextCodec>
#include <QDebug>
#include "playpage.hpp"
#include "graphicspage.hpp"
#include "datafilespage.hpp"
@ -126,9 +123,9 @@ void Launcher::MainDialog::createPages()
mPlayPage = new PlayPage(this);
mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
mGraphicsPage = new GraphicsPage(mEngineSettings, this);
mGraphicsPage = new GraphicsPage(this);
mSettingsPage = new SettingsPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
mAdvancedPage = new AdvancedPage(mGameSettings, mEngineSettings, this);
mAdvancedPage = new AdvancedPage(mGameSettings, this);
// Set the combobox of the play page to imitate the combobox on the datafilespage
mPlayPage->setProfilesModel(mDataFilesPage->profilesModel());
@ -427,11 +424,11 @@ bool Launcher::MainDialog::setupGraphicsSettings()
mEngineSettings.clear();
// Create the settings manager and load default settings file
const std::string localDefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string();
const std::string globalDefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string();
const std::string localDefault = (mCfgMgr.getLocalPath() / "defaults.bin").string();
const std::string globalDefault = (mCfgMgr.getGlobalPath() / "defaults.bin").string();
std::string defaultPath;
// Prefer the settings-default.cfg in the current directory.
// Prefer the defaults.bin in the current directory.
if (boost::filesystem::exists(localDefault))
defaultPath = localDefault;
else if (boost::filesystem::exists(globalDefault))
@ -439,7 +436,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
// Something's very wrong if we can't find the file at all.
else {
cfgError(tr("Error reading OpenMW configuration file"),
tr("<br><b>Could not find settings-default.cfg</b><br><br> \
tr("<br><b>Could not find defaults.bin</b><br><br> \
The problem may be due to an incomplete installation of OpenMW.<br> \
Reinstalling OpenMW may resolve the problem."));
return false;
@ -450,7 +447,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
mEngineSettings.loadDefault(defaultPath);
}
catch (std::exception& e) {
std::string msg = std::string("<br><b>Error reading settings-default.cfg</b><br><br>") + e.what();
std::string msg = std::string("<br><b>Error reading defaults.bin</b><br><br>") + e.what();
cfgError(tr("Error reading OpenMW configuration file"), tr(msg.c_str()));
return false;
}

@ -1,8 +1,6 @@
#ifndef MAINDIALOG_H
#define MAINDIALOG_H
#include <QMainWindow>
#include <QProcess>
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>

@ -1,8 +1,6 @@
#ifndef PLAYPAGE_H
#define PLAYPAGE_H
#include <QWidget>
#include "ui_playpage.h"
class QComboBox;

@ -1,7 +1,6 @@
#include <signal.h>
#include <SDL.h>
#include <SDL_video.h>
bool initSDL()
{

@ -2,7 +2,6 @@
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>
#include <QDir>
#include <components/files/configurationmanager.hpp>

@ -1,9 +1,6 @@
#ifndef SETTINGSPAGE_HPP
#define SETTINGSPAGE_HPP
#include <QWidget>
#include <QProcess>
#include <components/process/processinvoker.hpp>
#include "ui_settingspage.h"

@ -1,7 +1,6 @@
#ifndef OPENMW_CELLNAMELOADER_H
#define OPENMW_CELLNAMELOADER_H
#include <QComboBox>
#include <QSet>
#include <QString>

@ -11,7 +11,6 @@
#define LINEEDIT_H
#include <QLineEdit>
#include <QStyle>
#include <QStylePainter>
#include <QToolButton>

@ -1,5 +1,4 @@
#include <QRegExpValidator>
#include <QLineEdit>
#include <QString>
#include <QApplication>
#include <QKeyEvent>

@ -676,7 +676,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::p
}
if(line[0] == '[') {
int pos = line.find(']');
int pos = static_cast<int>(line.find(']'));
if(pos < 2) {
std::cout << "Warning: ini file wrongly formatted (" << line << "). Line ignored." << std::endl;
continue;
@ -686,12 +686,12 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::p
continue;
}
int comment_pos = line.find(";");
int comment_pos = static_cast<int>(line.find(';'));
if(comment_pos > 0) {
line = line.substr(0,comment_pos);
}
int pos = line.find("=");
int pos = static_cast<int>(line.find('='));
if(pos < 1) {
continue;
}
@ -722,7 +722,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::p
while (std::getline(file, line)) {
// we cant say comment by only looking at first char anymore
int comment_pos = line.find("#");
int comment_pos = static_cast<int>(line.find('#'));
if(comment_pos > 0) {
line = line.substr(0,comment_pos);
}
@ -731,7 +731,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::p
continue;
}
int pos = line.find("=");
int pos = static_cast<int>(line.find('='));
if(pos < 1) {
continue;
}

@ -20,7 +20,7 @@ namespace bfs = boost::filesystem;
///See if the file has the named extension
bool hasExtension(std::string filename, std::string extensionToFind)
{
std::string extension = filename.substr(filename.find_last_of(".")+1);
std::string extension = filename.substr(filename.find_last_of('.')+1);
//Convert strings to lower case for comparison
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);

@ -89,7 +89,7 @@ opencs_units (view/render
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
previewwidget editmode instancemode instanceselectionmode instancemovemode
orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller
cellwater terraintexturemode actor terrainselection terrainshapemode brushdraw
cellwater terraintexturemode actor terrainselection terrainshapemode brushdraw commands
)
opencs_units_noqt (view/render
@ -158,7 +158,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
if(APPLE)
set (OPENCS_MAC_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns")
set (OPENCS_CFG "${OpenMW_BINARY_DIR}/openmw-cs.cfg")
set (OPENCS_CFG "${OpenMW_BINARY_DIR}/defaults-cs.bin")
set (OPENCS_DEFAULT_FILTERS_FILE "${OpenMW_BINARY_DIR}/resources/defaultfilters")
set (OPENCS_OPENMW_CFG "${OpenMW_BINARY_DIR}/openmw.cfg")
else()
@ -270,7 +270,7 @@ if (WIN32)
SET(INSTALL_SOURCE "${OpenMW_BINARY_DIR}")
endif ()
INSTALL(FILES "${INSTALL_SOURCE}/openmw-cs.cfg" DESTINATION ".")
INSTALL(FILES "${INSTALL_SOURCE}/defaults-cs.bin" DESTINATION ".")
endif()
if (MSVC)

@ -21,7 +21,7 @@ void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type,
{
std::vector<std::string>& list = mIds[type];
int size = list.size();
size_t size = list.size();
list.resize (size+ids.size());

@ -5,7 +5,6 @@
#include "../tools/reportmodel.hpp"
#include "document.hpp"
#include "state.hpp"
CSMDoc::Loader::Stage::Stage() : mFile (0), mRecordsLoaded (0), mRecordsLeft (false) {}

@ -7,7 +7,6 @@
#include "../world/universalid.hpp"
#include "state.hpp"
#include "stage.hpp"
void CSMDoc::Operation::prepareStages()

@ -83,6 +83,8 @@ void CSMDoc::Runner::start (bool delayed)
arguments <<
QString::fromUtf8 (("--data=\""+mProjectPath.parent_path().string()+"\"").c_str());
arguments << "--replace=content";
for (std::vector<std::string>::const_iterator iter (mContentFiles.begin());
iter!=mContentFiles.end(); ++iter)
{

@ -9,7 +9,7 @@ CSMFilter::NAryNode::NAryNode (const std::vector<std::shared_ptr<Node> >& nodes,
int CSMFilter::NAryNode::getSize() const
{
return mNodes.size();
return static_cast<int>(mNodes.size());
}
const CSMFilter::Node& CSMFilter::NAryNode::operator[] (int index) const

@ -178,7 +178,7 @@ namespace CSMPrefs
{
const int MaxKeys = 4; // A limitation of QKeySequence
size_t end = data.find(";");
size_t end = data.find(';');
size_t size = std::min(end, data.size());
std::string value = data.substr(0, size);
@ -191,7 +191,7 @@ namespace CSMPrefs
while (start < value.size())
{
end = data.find("+", start);
end = data.find('+', start);
end = std::min(end, value.size());
std::string name = value.substr(start, end - start);
@ -243,7 +243,7 @@ namespace CSMPrefs
void ShortcutManager::convertFromString(const std::string& data, int& modifier) const
{
size_t start = data.find(";") + 1;
size_t start = data.find(';') + 1;
start = std::min(start, data.size());
std::string name = data.substr(start);

@ -17,15 +17,15 @@ CSMPrefs::State *CSMPrefs::State::sThis = nullptr;
void CSMPrefs::State::load()
{
// default settings file
boost::filesystem::path local = mConfigurationManager.getLocalPath() / mConfigFile;
boost::filesystem::path global = mConfigurationManager.getGlobalPath() / mConfigFile;
boost::filesystem::path local = mConfigurationManager.getLocalPath() / mDefaultConfigFile;
boost::filesystem::path global = mConfigurationManager.getGlobalPath() / mDefaultConfigFile;
if (boost::filesystem::exists (local))
mSettings.loadDefault (local.string());
else if (boost::filesystem::exists (global))
mSettings.loadDefault (global.string());
else
throw std::runtime_error ("No default settings file found! Make sure the file \"openmw-cs.cfg\" was properly installed.");
throw std::runtime_error ("No default settings file found! Make sure the file \"" + mDefaultConfigFile + "\" was properly installed.");
// user settings file
boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile;
@ -641,7 +641,7 @@ void CSMPrefs::State::setDefault (const std::string& key, const std::string& def
}
CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager)
: mConfigFile ("openmw-cs.cfg"), mConfigurationManager (configurationManager),
: mConfigFile ("openmw-cs.cfg"), mDefaultConfigFile("defaults-cs.bin"), mConfigurationManager (configurationManager),
mCurrentCategory (mCategories.end())
{
if (sThis)

@ -48,6 +48,7 @@ namespace CSMPrefs
private:
const std::string mConfigFile;
const std::string mDefaultConfigFile;
const Files::ConfigurationManager& mConfigurationManager;
ShortcutManager mShortcutManager;
Settings::Manager mSettings;

@ -11,7 +11,7 @@ CSMTools::MandatoryIdStage::MandatoryIdStage (const CSMWorld::CollectionBase& id
int CSMTools::MandatoryIdStage::setup()
{
return mIds.size();
return static_cast<int>(mIds.size());
}
void CSMTools::MandatoryIdStage::perform (int stage, CSMDoc::Messages& messages)

@ -24,7 +24,7 @@ int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const
if (parent.isValid())
return 0;
return mRows.size();
return static_cast<int>(mRows.size());
}
int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const
@ -140,7 +140,7 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p
void CSMTools::ReportModel::add (const CSMDoc::Message& message)
{
beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
beginInsertRows (QModelIndex(), static_cast<int>(mRows.size()), static_cast<int>(mRows.size()));
mRows.push_back (message);
@ -176,7 +176,7 @@ void CSMTools::ReportModel::clear()
{
if (!mRows.empty())
{
beginRemoveRows (QModelIndex(), 0, mRows.size()-1);
beginRemoveRows (QModelIndex(), 0, static_cast<int>(mRows.size())-1);
mRows.clear();
endRemoveRows();
}

@ -270,7 +270,7 @@ void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector<int>& newO
if (!newOrder.empty())
if (mIdCollection->reorderRows (baseIndex, newOrder))
emit dataChanged (index (baseIndex, 0),
index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1));
index (baseIndex+static_cast<int>(newOrder.size())-1, mIdCollection->getColumns()-1));
}
std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row) const

@ -1,6 +1,5 @@
#include "refcollection.hpp"
#include <components/misc/stringops.hpp>
#include <components/esm/loadcell.hpp>
#include "ref.hpp"
@ -109,11 +108,13 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
Record<CellRef> record;
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
(base ? record.mBase : record.mModified) = ref;
const ESM::RefNum refNum = ref.mRefNum;
std::string refId = ref.mId;
(base ? record.mBase : record.mModified) = std::move(ref);
appendRecord (record);
cache.insert (std::make_pair (ref.mRefNum, ref.mId));
cache.emplace(refNum, std::move(refId));
}
else
{
@ -124,7 +125,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
Record<CellRef> record = getRecord (index);
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_Modified;
(base ? record.mBase : record.mModified) = ref;
(base ? record.mBase : record.mModified) = std::move(ref);
setRecord (index, record);
}

@ -20,13 +20,13 @@ void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char * const *
mFiles.clear();
mIndex.clear();
int baseSize = mBaseDirectory.size();
size_t baseSize = mBaseDirectory.size();
const std::map<std::string, VFS::File*>& index = vfs->getIndex();
for (std::map<std::string, VFS::File*>::const_iterator it = index.begin(); it != index.end(); ++it)
{
std::string filepath = it->first;
if (static_cast<int> (filepath.size())<baseSize+1 ||
if (filepath.size()<baseSize+1 ||
filepath.substr (0, baseSize)!=mBaseDirectory ||
(filepath[baseSize]!='/' && filepath[baseSize]!='\\'))
continue;
@ -60,7 +60,7 @@ void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char * const *
int CSMWorld::Resources::getSize() const
{
return mFiles.size();
return static_cast<int>(mFiles.size());
}
std::string CSMWorld::Resources::getId (int index) const

@ -30,7 +30,7 @@ void CSVDoc::Operations::setProgress (int current, int max, int type, int thread
return;
}
int oldCount = mOperations.size();
int oldCount = static_cast<int>(mOperations.size());
int newCount = oldCount + 1;
Operation *operation = new Operation (type, this);
@ -51,7 +51,7 @@ void CSVDoc::Operations::quitOperation (int type)
for (std::vector<Operation *>::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter)
if ((*iter)->getType()==type)
{
int oldCount = mOperations.size();
int oldCount = static_cast<int>(mOperations.size());
int newCount = oldCount - 1;
mLayout->removeItem ((*iter)->getLayout());

@ -749,7 +749,7 @@ void CSVDoc::View::infoAbout()
"<tr><td>%4</td><td><a href=\"https://openmw.org\">https://openmw.org</a></td></tr>"
"<tr><td>%5</td><td><a href=\"https://forum.openmw.org\">https://forum.openmw.org</a></td></tr>"
"<tr><td>%6</td><td><a href=\"https://gitlab.com/OpenMW/openmw/issues\">https://gitlab.com/OpenMW/openmw/issues</a></td></tr>"
"<tr><td>%7</td><td><a href=\"https://webchat.freenode.net/?channels=openmw&uio=OT10cnVlde\">irc://irc.freenode.net/#openmw</a></td></tr>"
"<tr><td>%7</td><td><a href=\"https://web.libera.chat/#openmw\">ircs://irc.libera.chat/#openmw</a></td></tr>"
"</table>"
"</p>")
.arg(versionInfo

@ -11,7 +11,6 @@
#include "../../model/doc/documentmanager.hpp"
#include "../../model/doc/document.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/universalid.hpp"
#include "../../model/world/idcompletionmanager.hpp"
#include "../../model/prefs/state.hpp"

@ -2,7 +2,6 @@
#include <osg/Group>
#include <osg/PositionAttitudeTransform>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/PrimitiveSet>
@ -13,15 +12,23 @@
#include "../../model/world/cellcoordinates.hpp"
const int CSVRender::CellBorder::CellSize = ESM::Land::REAL_SIZE;
const int CSVRender::CellBorder::VertexCount = (ESM::Land::LAND_SIZE * 4) - 3;
/*
The number of vertices per cell border is equal to the number of vertices per edge
minus the duplicated corner vertices. An additional vertex to close the loop is NOT needed.
*/
const int CSVRender::CellBorder::VertexCount = (ESM::Land::LAND_SIZE * 4) - 4;
CSVRender::CellBorder::CellBorder(osg::Group* cellNode, const CSMWorld::CellCoordinates& coords)
: mParentNode(cellNode)
{
mBorderGeometry = new osg::Geometry();
mBaseNode = new osg::PositionAttitudeTransform();
mBaseNode->setNodeMask(Mask_CellBorder);
mBaseNode->setPosition(osg::Vec3f(coords.getX() * CellSize, coords.getY() * CellSize, 10));
mBaseNode->addChild(mBorderGeometry);
mParentNode->addChild(mBaseNode);
}
@ -38,56 +45,59 @@ void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand)
if (!landData)
return;
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
mBaseNode->removeChild(mBorderGeometry);
mBorderGeometry = new osg::Geometry();
// Vertices
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array();
int x = 0, y = 0;
for (; x < ESM::Land::LAND_SIZE; ++x)
int x = 0;
int y = 0;
/*
Traverse the cell border counter-clockwise starting at the SW corner vertex (0, 0).
Each loop starts at a corner vertex and ends right before the next corner vertex.
*/
for (; x < ESM::Land::LAND_SIZE - 1; ++x)
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)]));
x = ESM::Land::LAND_SIZE - 1;
for (; y < ESM::Land::LAND_SIZE; ++y)
for (; y < ESM::Land::LAND_SIZE - 1; ++y)
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)]));
y = ESM::Land::LAND_SIZE - 1;
for (; x >= 0; --x)
for (; x > 0; --x)
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)]));
x = 0;
for (; y >= 0; --y)
for (; y > 0; --y)
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)]));
geometry->setVertexArray(vertices);
mBorderGeometry->setVertexArray(vertices);
// Color
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array();
colors->push_back(osg::Vec4f(0.f, 0.5f, 0.f, 1.f));
geometry->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET);
mBorderGeometry->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET);
// Primitive
osg::ref_ptr<osg::DrawElementsUShort> primitives =
new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP, VertexCount+1);
new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP, VertexCount + 1);
// Assign one primitive to each vertex.
for (size_t i = 0; i < VertexCount; ++i)
primitives->setElement(i, i);
// Assign the last primitive to the first vertex to close the loop.
primitives->setElement(VertexCount, 0);
geometry->addPrimitiveSet(primitives);
geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
mBorderGeometry->addPrimitiveSet(primitives);
mBorderGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
geode->addDrawable(geometry);
mBaseNode->addChild(geode);
mBaseNode->addChild(mBorderGeometry);
}
size_t CSVRender::CellBorder::landIndex(int x, int y)
{
return y * ESM::Land::LAND_SIZE + x;
return static_cast<size_t>(y) * ESM::Land::LAND_SIZE + x;
}
float CSVRender::CellBorder::scaleToWorld(int value)

@ -7,6 +7,7 @@
namespace osg
{
class Geometry;
class Group;
class PositionAttitudeTransform;
}
@ -47,7 +48,7 @@ namespace CSVRender
osg::Group* mParentNode;
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
osg::ref_ptr<osg::Geometry> mBorderGeometry;
};
}

@ -0,0 +1,44 @@
#include "commands.hpp"
#include <QPointer>
#include <components/debug/debuglog.hpp>
#include <components/esm/loadland.hpp>
#include "editmode.hpp"
#include "terrainselection.hpp"
#include "terrainshapemode.hpp"
#include "terraintexturemode.hpp"
#include "worldspacewidget.hpp"
CSVRender::DrawTerrainSelectionCommand::DrawTerrainSelectionCommand(WorldspaceWidget* worldspaceWidget, QUndoCommand* parent)
: mWorldspaceWidget(worldspaceWidget)
{ }
void CSVRender::DrawTerrainSelectionCommand::redo()
{
tryUpdate();
}
void CSVRender::DrawTerrainSelectionCommand::undo()
{
tryUpdate();
}
void CSVRender::DrawTerrainSelectionCommand::tryUpdate()
{
if (!mWorldspaceWidget)
{
Log(Debug::Verbose) << "Can't update terrain selection, no WorldspaceWidget found!";
return;
}
auto terrainMode = dynamic_cast<CSVRender::TerrainShapeMode*>(mWorldspaceWidget->getEditMode());
if (!terrainMode)
{
Log(Debug::Verbose) << "Can't update terrain selection in current EditMode";
return;
}
terrainMode->getTerrainSelection()->update();
}

@ -0,0 +1,42 @@
#ifndef CSV_RENDER_COMMANDS_HPP
#define CSV_RENDER_COMMANDS_HPP
#include <QPointer>
#include <QUndoCommand>
#include "worldspacewidget.hpp"
namespace CSVRender
{
class TerrainSelection;
/*
Current solution to force a redrawing of the terrain-selection grid
when undoing/redoing changes in the editor.
This only triggers a simple redraw of the grid, so only use it in
conjunction with actual data changes which deform the grid.
Please note that this command needs to be put onto the QUndoStack twice:
at the start and at the end of the related terrain manipulation.
This makes sure that the grid is always updated after all changes have
been undone or redone -- but it also means that the selection is redrawn
once at the beginning of either action. Future refinement may solve that.
*/
class DrawTerrainSelectionCommand : public QUndoCommand
{
private:
QPointer<WorldspaceWidget> mWorldspaceWidget;
public:
DrawTerrainSelectionCommand(WorldspaceWidget* worldspaceWidget, QUndoCommand* parent = nullptr);
void redo() override;
void undo() override;
void tryUpdate();
};
}
#endif

@ -3,7 +3,6 @@
#include <QMenu>
#include "../../model/prefs/shortcut.hpp"
#include "../../model/prefs/shortcuteventhandler.hpp"
#include "worldspacewidget.hpp"

@ -7,18 +7,14 @@
#include <QMouseEvent>
#include <QApplication>
#include <components/esm/loadland.hpp>
#include <components/misc/constants.hpp>
#include "../../model/prefs/shortcut.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/idtable.hpp"
#include "../widget/scenetooltoggle2.hpp"
#include "../widget/scenetoolmode.hpp"
#include "../widget/scenetooltoggle2.hpp"
#include "editmode.hpp"
#include "mask.hpp"

@ -9,8 +9,6 @@
#include "../../model/world/commands.hpp"
#include "../../model/world/commandmacro.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/idtree.hpp"
#include "../widget/scenetoolbar.hpp"

@ -26,7 +26,6 @@
#include "../../model/prefs/state.hpp"
#include "../../model/prefs/shortcut.hpp"
#include "../../model/prefs/shortcuteventhandler.hpp"
#include "lighting.hpp"
#include "mask.hpp"

@ -39,64 +39,23 @@ std::vector<std::pair<int, int>> CSVRender::TerrainSelection::getTerrainSelectio
void CSVRender::TerrainSelection::onlySelect(const std::vector<std::pair<int, int>> &localPositions)
{
mSelection = localPositions;
update();
}
void CSVRender::TerrainSelection::addSelect(const std::pair<int, int> &localPos)
void CSVRender::TerrainSelection::addSelect(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress)
{
if (std::find(mSelection.begin(), mSelection.end(), localPos) == mSelection.end())
{
mSelection.emplace_back(localPos);
update();
}
handleSelection(localPositions, toggleInProgress, SelectionMethod::AddSelect);
}
void CSVRender::TerrainSelection::toggleSelect(const std::vector<std::pair<int, int>> &localPositions, bool toggleInProgress)
void CSVRender::TerrainSelection::removeSelect(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress)
{
if (toggleInProgress)
{
for(auto const& localPos: localPositions)
{
auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos);
mDraggedOperationFlag = true;
if (iterTemp == mTemporarySelection.end())
{
auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
if (iter != mSelection.end())
{
mSelection.erase(iter);
}
else
{
mSelection.emplace_back(localPos);
}
}
handleSelection(localPositions, toggleInProgress, SelectionMethod::RemoveSelect);
}
mTemporarySelection.push_back(localPos);
}
}
else if (mDraggedOperationFlag == false)
{
for(auto const& localPos: localPositions)
{
const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
if (iter != mSelection.end())
{
mSelection.erase(iter);
}
else
{
mSelection.emplace_back(localPos);
}
}
}
else
{
mDraggedOperationFlag = false;
mTemporarySelection.clear();
}
update();
void CSVRender::TerrainSelection::toggleSelect(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress)
{
handleSelection(localPositions, toggleInProgress, SelectionMethod::ToggleSelect);
}
void CSVRender::TerrainSelection::activate()
@ -239,6 +198,100 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr<osg::V
}
}
void CSVRender::TerrainSelection::handleSelection(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress, SelectionMethod selectionMethod)
{
if (toggleInProgress)
{
for (auto const& localPos : localPositions)
{
auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos);
mDraggedOperationFlag = true;
if (iterTemp == mTemporarySelection.end())
{
auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
switch (selectionMethod)
{
case SelectionMethod::AddSelect:
if (iter == mSelection.end())
{
mSelection.emplace_back(localPos);
}
break;
case SelectionMethod::RemoveSelect:
if (iter != mSelection.end())
{
mSelection.erase(iter);
}
break;
case SelectionMethod::ToggleSelect:
if (iter == mSelection.end())
{
mSelection.emplace_back(localPos);
}
else
{
mSelection.erase(iter);
}
break;
default: break;
}
}
mTemporarySelection.push_back(localPos);
}
}
else if (mDraggedOperationFlag == false)
{
for (auto const& localPos : localPositions)
{
const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
switch (selectionMethod)
{
case SelectionMethod::AddSelect:
if (iter == mSelection.end())
{
mSelection.emplace_back(localPos);
}
break;
case SelectionMethod::RemoveSelect:
if (iter != mSelection.end())
{
mSelection.erase(iter);
}
break;
case SelectionMethod::ToggleSelect:
if (iter == mSelection.end())
{
mSelection.emplace_back(localPos);
}
else
{
mSelection.erase(iter);
}
break;
default: break;
}
}
}
else
{
mDraggedOperationFlag = false;
mTemporarySelection.clear();
}
update();
}
bool CSVRender::TerrainSelection::noCell(const std::string& cellId)
{
CSMDoc::Document& document = mWorldspaceWidget->getDocument();

@ -27,6 +27,14 @@ namespace CSVRender
Shape
};
enum class SelectionMethod
{
OnlySelect,
AddSelect,
RemoveSelect,
ToggleSelect
};
/// \brief Class handling the terrain selection data and rendering
class TerrainSelection
{
@ -36,7 +44,8 @@ namespace CSVRender
~TerrainSelection();
void onlySelect(const std::vector<std::pair<int, int>> &localPositions);
void addSelect(const std::pair<int, int> &localPos);
void addSelect(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress);
void removeSelect(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress);
void toggleSelect(const std::vector<std::pair<int, int>> &localPositions, bool toggleInProgress);
void activate();
@ -55,6 +64,8 @@ namespace CSVRender
private:
void handleSelection(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress, SelectionMethod selectionMethod);
bool noCell(const std::string& cellId);
bool noLand(const std::string& cellId);

@ -25,18 +25,16 @@
#include "../../model/doc/document.hpp"
#include "../../model/prefs/state.hpp"
#include "../../model/world/columnbase.hpp"
#include "../../model/world/commandmacro.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/idtree.hpp"
#include "../../model/world/land.hpp"
#include "../../model/world/resourcetable.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/universalid.hpp"
#include "brushdraw.hpp"
#include "commands.hpp"
#include "editmode.hpp"
#include "pagedworldspacewidget.hpp"
#include "mask.hpp"
@ -45,7 +43,7 @@
#include "worldspacewidget.hpp"
CSVRender::TerrainShapeMode::TerrainShapeMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent)
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-shape"}, Mask_Terrain | Mask_Reference, "Terrain land editing", parent),
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-shape"}, Mask_Terrain, "Terrain land editing", parent),
mParentNode(parentNode)
{
}
@ -288,6 +286,9 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges()
undoStack.beginMacro ("Edit shape and normal records");
// One command at the beginning of the macro for redrawing the terrain-selection grid when undoing the changes.
undoStack.push(new DrawTerrainSelectionCommand(&getWorldspaceWidget()));
for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells)
{
std::string cellId = CSMWorld::CellCoordinates::generateId(cellCoordinates.getX(), cellCoordinates.getY());
@ -356,6 +357,9 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges()
}
pushNormalsEditToCommand(landNormalsNew, document, landTable, cellId);
}
// One command at the end of the macro for redrawing the terrain-selection grid when redoing the changes.
undoStack.push(new DrawTerrainSelectionCommand(&getWorldspaceWidget()));
undoStack.endMacro();
clearTransientEdits();
}
@ -433,7 +437,9 @@ void CSVRender::TerrainShapeMode::editTerrainShapeGrid(const std::pair<int, int>
float smoothedByDistance = 0.0f;
if (mShapeEditTool == ShapeEditTool_Drag) smoothedByDistance = calculateBumpShape(distance, r, mTotalDiffY);
if (mShapeEditTool == ShapeEditTool_PaintToRaise || mShapeEditTool == ShapeEditTool_PaintToLower) smoothedByDistance = calculateBumpShape(distance, r, r + mShapeEditToolStrength);
if (distance <= r)
// Using floating-point radius here to prevent selecting too few vertices.
if (distance <= mBrushSize / 2.0f)
{
if (mShapeEditTool == ShapeEditTool_Drag) alterHeight(cellCoords, x, y, smoothedByDistance);
if (mShapeEditTool == ShapeEditTool_PaintToRaise || mShapeEditTool == ShapeEditTool_PaintToLower)
@ -1036,10 +1042,35 @@ void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int glob
return;
int selectionX = globalSelectionX;
int selectionY = globalSelectionY;
if (xIsAtCellBorder)
/*
The northern and eastern edges don't belong to the current cell.
If the corresponding adjacent cell is not loaded, some special handling is necessary to select border vertices.
*/
if (xIsAtCellBorder && yIsAtCellBorder)
{
/*
Handle the NW, NE, and SE corner vertices.
NW corner: (+1, -1) offset to reach current cell.
NE corner: (-1, -1) offset to reach current cell.
SE corner: (-1, +1) offset to reach current cell.
*/
if (isInCellSelection(globalSelectionX - 1, globalSelectionY - 1)
|| isInCellSelection(globalSelectionX + 1, globalSelectionY - 1)
|| isInCellSelection(globalSelectionX - 1, globalSelectionY + 1))
{
selections->emplace_back(globalSelectionX, globalSelectionY);
}
}
else if (xIsAtCellBorder)
{
selectionX--;
if (yIsAtCellBorder)
}
else if (yIsAtCellBorder)
{
selectionY--;
}
if (isInCellSelection(selectionX, selectionY))
selections->emplace_back(globalSelectionX, globalSelectionY);
}
@ -1074,8 +1105,11 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
{
int distanceX = abs(i - vertexCoords.first);
int distanceY = abs(j - vertexCoords.second);
int distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2)));
if (distance <= r) handleSelection(i, j, &selections);
float distance = sqrt(pow(distanceX, 2)+pow(distanceY, 2));
// Using floating-point radius here to prevent selecting too few vertices.
if (distance <= mBrushSize / 2.0f)
handleSelection(i, j, &selections);
}
}
}
@ -1092,9 +1126,21 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
}
}
if(selectMode == 0) mTerrainShapeSelection->onlySelect(selections);
if(selectMode == 1) mTerrainShapeSelection->toggleSelect(selections, dragOperation);
std::string selectAction;
if (selectMode == 0)
selectAction = CSMPrefs::get()["3D Scene Editing"]["primary-select-action"].toString();
else
selectAction = CSMPrefs::get()["3D Scene Editing"]["secondary-select-action"].toString();
if (selectAction == "Select only")
mTerrainShapeSelection->onlySelect(selections);
else if (selectAction == "Add to selection")
mTerrainShapeSelection->addSelect(selections, dragOperation);
else if (selectAction == "Remove from selection")
mTerrainShapeSelection->removeSelect(selections, dragOperation);
else if (selectAction == "Invert selection")
mTerrainShapeSelection->toggleSelect(selections, dragOperation);
}
void CSVRender::TerrainShapeMode::pushEditToCommand(const CSMWorld::LandHeightsColumn::DataType& newLandGrid, CSMDoc::Document& document,
@ -1398,6 +1444,11 @@ void CSVRender::TerrainShapeMode::mouseMoveEvent (QMouseEvent *event)
mBrushDraw->hide();
}
std::shared_ptr<CSVRender::TerrainSelection> CSVRender::TerrainShapeMode::getTerrainSelection()
{
return mTerrainShapeSelection;
}
void CSVRender::TerrainShapeMode::setBrushSize(int brushSize)
{
mBrushSize = brushSize;

@ -92,6 +92,8 @@ namespace CSVRender
void dragMoveEvent (QDragMoveEvent *event) override;
void mouseMoveEvent (QMouseEvent *event) override;
std::shared_ptr<TerrainSelection> getTerrainSelection();
private:
/// Remove duplicates and sort mAlteredCells, then limitAlteredHeights forward and reverse
@ -176,7 +178,7 @@ namespace CSVRender
int mDragMode = InteractionType_None;
osg::Group* mParentNode;
bool mIsEditing = false;
std::unique_ptr<TerrainSelection> mTerrainShapeSelection;
std::shared_ptr<TerrainSelection> mTerrainShapeSelection;
int mTotalDiffY = 0;
std::vector<CSMWorld::CellCoordinates> mAlteredCells;
osg::Vec3d mEditingPos;

@ -12,23 +12,17 @@
#include <osg/Group>
#include <components/esm/loadland.hpp>
#include "../widget/modebutton.hpp"
#include "../widget/scenetoolbar.hpp"
#include "../widget/scenetooltexturebrush.hpp"
#include "../../model/doc/document.hpp"
#include "../../model/prefs/state.hpp"
#include "../../model/world/columnbase.hpp"
#include "../../model/world/commandmacro.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/idtree.hpp"
#include "../../model/world/land.hpp"
#include "../../model/world/landtexture.hpp"
#include "../../model/world/resourcetable.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/universalid.hpp"
#include "../widget/brushshapes.hpp"
@ -332,7 +326,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex);
std::size_t hashlocation = mBrushTexture.find("#");
std::size_t hashlocation = mBrushTexture.find('#');
std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1);
int brushInt = stoi(mBrushTexture.substr (hashlocation+1))+1; // All indices are offset by +1
@ -718,6 +712,11 @@ void CSVRender::TerrainTextureMode::mouseMoveEvent (QMouseEvent *event)
mBrushDraw->hide();
}
std::shared_ptr<CSVRender::TerrainSelection> CSVRender::TerrainTextureMode::getTerrainSelection()
{
return mTerrainTextureSelection;
}
void CSVRender::TerrainTextureMode::setBrushSize(int brushSize)
{

@ -85,6 +85,8 @@ namespace CSVRender
void mouseMoveEvent (QMouseEvent *event) override;
std::shared_ptr<TerrainSelection> getTerrainSelection();
private:
/// \brief Handle brush mechanics, maths regarding worldspace hit etc.
void editTerrainTextureGrid (const WorldspaceHitResult& hit);
@ -115,7 +117,7 @@ namespace CSVRender
int mDragMode;
osg::Group* mParentNode;
bool mIsEditing;
std::unique_ptr<TerrainSelection> mTerrainTextureSelection;
std::shared_ptr<TerrainSelection> mTerrainTextureSelection;
const int cellSize {ESM::Land::REAL_SIZE};
const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE};

@ -12,7 +12,6 @@
#include "../../model/world/idtable.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../widget/scenetooltoggle.hpp"
#include "../widget/scenetooltoggle2.hpp"
#include "cameracontroller.hpp"

@ -17,7 +17,6 @@
#include "../../model/world/idtable.hpp"
#include "../../model/prefs/shortcut.hpp"
#include "../../model/prefs/shortcuteventhandler.hpp"
#include "../../model/prefs/state.hpp"
#include "../render/orbitcameramode.hpp"
@ -453,6 +452,11 @@ CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick (const QPo
return hit;
}
CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
{
return dynamic_cast<CSVRender::EditMode *> (mEditMode->getCurrent());
}
void CSVRender::WorldspaceWidget::abortDrag()
{
if (mDragging)
@ -698,11 +702,6 @@ void CSVRender::WorldspaceWidget::handleInteractionPress (const WorldspaceHitRes
editMode.primaryOpenPressed (hit);
}
CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
{
return dynamic_cast<CSVRender::EditMode *> (mEditMode->getCurrent());
}
void CSVRender::WorldspaceWidget::primaryOpen(bool activate)
{
handleInteraction(InteractionType_PrimaryOpen, activate);

@ -189,6 +189,8 @@ namespace CSVRender
/// Erase all overrides and restore the visual representation to its true state.
virtual void reset (unsigned int elementMask) = 0;
EditMode *getEditMode();
protected:
/// Visual elements in a scene
@ -215,8 +217,6 @@ namespace CSVRender
void settingChanged (const CSMPrefs::Setting *setting) override;
EditMode *getEditMode();
bool getSpeedMode();
private:

@ -30,7 +30,7 @@ void CSVWidget::SceneToolRun::updateIcon()
void CSVWidget::SceneToolRun::updatePanel()
{
mTable->setRowCount (mProfiles.size());
mTable->setRowCount (static_cast<int>(mProfiles.size()));
int i = 0;

@ -27,11 +27,6 @@
#include "../../model/doc/document.hpp"
#include "../../model/prefs/state.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/idcollection.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/landtexture.hpp"
#include "../../model/world/universalid.hpp"
CSVWidget::ShapeBrushSizeControls::ShapeBrushSizeControls(const QString &title, QWidget *parent)

@ -80,7 +80,7 @@ QRect CSVWidget::SceneToolToggle::getIconBox (int index) const
int y = index / xMax;
int x = index % xMax;
int total = mButtons.size();
int total = static_cast<int>(mButtons.size());
int actualYIcons = total/xMax;
@ -154,7 +154,7 @@ void CSVWidget::SceneToolToggle::addButton (const std::string& icon, unsigned in
desc.mMask = mask;
desc.mSmallIcon = smallIcon;
desc.mName = name;
desc.mIndex = mButtons.size();
desc.mIndex = static_cast<int>(mButtons.size());
mButtons.insert (std::make_pair (button, desc));

@ -99,7 +99,7 @@ void CSVWidget::SceneToolToggle2::addButton (unsigned int id, unsigned int mask,
desc.mButtonId = id;
desc.mMask = mask;
desc.mName = name;
desc.mIndex = mButtons.size();
desc.mIndex = static_cast<int>(mButtons.size());
mButtons.insert (std::make_pair (button, desc));

@ -3,8 +3,6 @@
#include <QPainter>
#include <QPushButton>
#include "../widget/coloreditor.hpp"
CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent)

@ -28,7 +28,6 @@
#include "../../model/world/columns.hpp"
#include "../../model/world/record.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/idtree.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/doc/document.hpp"

@ -42,7 +42,7 @@ QValidator::State CSVWorld::IdValidator::validate (QString& input, int& pos) con
if (!mNamespace.empty())
{
std::string namespace_ = input.left (mNamespace.size()).toUtf8().constData();
std::string namespace_ = input.left (static_cast<int>(mNamespace.size())).toUtf8().constData();
if (Misc::StringUtils::lowerCase (namespace_)!=mNamespace)
return QValidator::Invalid; // incorrect namespace

@ -15,7 +15,6 @@
#include "../render/pagedworldspacewidget.hpp"
#include "../render/unpagedworldspacewidget.hpp"
#include "../render/editmode.hpp"
#include "../widget/scenetoolbar.hpp"
#include "../widget/scenetoolmode.hpp"

@ -12,7 +12,6 @@
#include "../../model/doc/document.hpp"
#include "../../model/world/universalid.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/columnbase.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/prefs/state.hpp"

@ -184,7 +184,7 @@ if(APPLE)
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
configure_file("${OpenMW_BINARY_DIR}/settings-default.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY)
configure_file("${OpenMW_BINARY_DIR}/defaults.bin" ${BUNDLE_RESOURCES_DIR} COPYONLY)
configure_file("${OpenMW_BINARY_DIR}/openmw.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY)
configure_file("${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" ${BUNDLE_RESOURCES_DIR} COPYONLY)

@ -496,8 +496,8 @@ void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame)
std::string OMW::Engine::loadSettings (Settings::Manager & settings)
{
// Create the settings manager and load default settings file
const std::string localdefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string();
const std::string globaldefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string();
const std::string localdefault = (mCfgMgr.getLocalPath() / "defaults.bin").string();
const std::string globaldefault = (mCfgMgr.getGlobalPath() / "defaults.bin").string();
// prefer local
if (boost::filesystem::exists(localdefault))
@ -505,7 +505,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
else if (boost::filesystem::exists(globaldefault))
settings.loadDefault(globaldefault);
else
throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed.");
throw std::runtime_error ("No default settings file found! Make sure the file \"defaults.bin\" was properly installed.");
// load user settings if they exist
const std::string settingspath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string();
@ -1081,6 +1081,8 @@ void OMW::Engine::go()
// Save user settings
settings.saveUser(settingspath);
mViewer->stopThreading();
Log(Debug::Info) << "Quitting peacefully.";
}

@ -44,6 +44,10 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
desc.add_options()
("help", "print help message")
("version", "print version information and quit")
("replace", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "")
->multitoken()->composing(), "settings where the values from the current source should replace those from lower-priority sources instead of being appended")
("data", bpo::value<Files::EscapePathContainer>()->default_value(Files::EscapePathContainer(), "data")
->multitoken()->composing(), "set data directories (later directories have higher priority)")
@ -192,6 +196,15 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
Log(Debug::Error) << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting...";
return false;
}
std::set<std::string> contentDedupe;
for (const auto& contentFile : content)
{
if (!contentDedupe.insert(contentFile).second)
{
Log(Debug::Error) << "Content file specified more than once: " << contentFile << ". Aborting...";
return false;
}
}
for (auto& file : content)
{

@ -301,7 +301,7 @@ namespace MWBase
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
virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, osg::Vec3f vec, bool moveToActive) = 0;
virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, osg::Vec3f vec, bool moveToActive, bool ignoreCollisions) = 0;
///< @return an updated Ptr
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;

@ -26,7 +26,6 @@
#include "../mwworld/failedaction.hpp"
#include "../mwworld/customdata.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwphysics/physicssystem.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/localscripts.hpp"

@ -132,12 +132,14 @@ namespace MWClass
MWBase::Environment::get().getWorld()->getMaxActivationDistance())
{
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr);
if(animation)
{
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
int index = ESM::MagicEffect::effectStringToId("sEffectTelekinesis");
const ESM::MagicEffect *effect = store.get<ESM::MagicEffect>().find(index);
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
int index = ESM::MagicEffect::effectStringToId("sEffectTelekinesis");
const ESM::MagicEffect *effect = store.get<ESM::MagicEffect>().find(index);
animation->addSpellCastGlow(effect, 1); // 1 second glow to match the time taken for a door opening or closing
animation->addSpellCastGlow(effect, 1); // 1 second glow to match the time taken for a door opening or closing
}
}
const std::string keyId = ptr.getCellRef().getKey();

@ -36,7 +36,6 @@
#include "../mwworld/failedaction.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/customdata.hpp"
#include "../mwphysics/physicssystem.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/localscripts.hpp"

@ -343,7 +343,7 @@ namespace MWDialogue
if(!inJournal(topicId, answer->mId))
{
// Does this dialogue contains some actor-specific answer?
if (answer->mActor == mActor.getCellRef().getRefId())
if (Misc::StringUtils::ciEqual(answer->mActor, mActor.getCellRef().getRefId()))
flag |= MWBase::DialogueManager::TopicType::Specific;
}
else

@ -3,7 +3,6 @@
#include "../mwbase/journal.hpp"
#include "journalentry.hpp"
#include "quest.hpp"
namespace MWDialogue

@ -10,7 +10,6 @@
#include <stdint.h>
#include <components/settings/settings.hpp>
#include <components/widgets/widgets.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"

@ -9,6 +9,10 @@
#include <components/compiler/exception.hpp>
#include <components/compiler/extensions0.hpp>
#include <components/compiler/lineparser.hpp>
#include <components/compiler/scanner.hpp>
#include <components/compiler/locals.hpp>
#include <components/interpreter/interpreter.hpp>
#include "../mwscript/extensions.hpp"

@ -6,12 +6,8 @@
#include <vector>
#include <components/compiler/errorhandler.hpp>
#include <components/compiler/lineparser.hpp>
#include <components/compiler/scanner.hpp>
#include <components/compiler/locals.hpp>
#include <components/compiler/output.hpp>
#include <components/compiler/extensions.hpp>
#include <components/interpreter/interpreter.hpp>
#include "../mwscript/compilercontext.hpp"
#include "../mwscript/interpretercontext.hpp"

@ -12,7 +12,9 @@
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwmechanics/aipackage.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/summoning.hpp"
#include "../mwscript/interpretercontext.hpp"
@ -268,6 +270,23 @@ namespace MWGui
for (const auto& creature : creatureMap)
MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(ptr, creature.second);
creatureMap.clear();
// Check if we are a summon and inform our master we've bit the dust
for(const auto& package : creatureStats.getAiSequence())
{
if(package->followTargetThroughDoors() && !package->getTarget().isEmpty())
{
const auto& summoner = package->getTarget();
auto& summons = summoner.getClass().getCreatureStats(summoner).getSummonedCreatureMap();
auto it = std::find_if(summons.begin(), summons.end(), [&] (const auto& entry) { return entry.second == creatureStats.getActorId(); });
if(it != summons.end())
{
MWMechanics::purgeSummonEffect(summoner, *it);
summons.erase(it);
break;
}
}
}
}
MWBase::Environment::get().getWorld()->deleteObject(ptr);

@ -310,7 +310,7 @@ namespace MWGui
deleteLater();
for (Link* link : mLinks)
delete link;
for (auto link : mTopicLinks)
for (const auto& link : mTopicLinks)
delete link.second;
for (auto history : mHistoryContents)
delete history;

@ -2,7 +2,6 @@
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"

@ -5,9 +5,7 @@
#include <MyGUI_FactoryManager.h>
#include <MyGUI_Gui.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_TextBox.h>
#include <MyGUI_ScrollView.h>
#include <MyGUI_Button.h>
#include "../mwworld/class.hpp"

@ -278,7 +278,7 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex ()
mIndexPagesCount = 2;
}
unsigned char ch[2] = {0xd0, 0x90}; // CYRILLIC CAPITAL A is a 0xd090 in UTF-8
unsigned char ch[3] = {0xd0, 0x90, 0x00}; // CYRILLIC CAPITAL A is a 0xd090 in UTF-8
for (int i = 0; i < 32; ++i)
{

@ -12,7 +12,6 @@
#include "../mwbase/soundmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"

@ -26,8 +26,6 @@
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/inputmanager.hpp"
#include "../mwrender/vismask.hpp"
#include "backgroundimage.hpp"
namespace MWGui
@ -103,7 +101,7 @@ namespace MWGui
Log(Debug::Warning) << "Warning: no splash screens found!";
}
void LoadingScreen::setLabel(const std::string &label, bool important, bool center)
void LoadingScreen::setLabel(const std::string &label, bool important)
{
mImportantLabel = important;
@ -113,7 +111,7 @@ namespace MWGui
size.width = std::max(300, size.width);
mLoadingBox->setSize(size);
if (center)
if (MWBase::Environment::get().getWindowManager()->getMessagesCount() > 0)
mLoadingBox->setPosition(mMainWidget->getWidth()/2 - mLoadingBox->getWidth()/2, mMainWidget->getHeight()/2 - mLoadingBox->getHeight()/2);
else
mLoadingBox->setPosition(mMainWidget->getWidth()/2 - mLoadingBox->getWidth()/2, mMainWidget->getHeight() - mLoadingBox->getHeight() - 8);

@ -3,7 +3,6 @@
#include <memory>
#include <osg/Camera>
#include <osg/Timer>
#include <osg/ref_ptr>
@ -38,7 +37,7 @@ namespace MWGui
virtual ~LoadingScreen();
/// Overridden from Loading::Listener, see the Loading::Listener documentation for usage details
void setLabel (const std::string& label, bool important, bool center) override;
void setLabel (const std::string& label, bool important) override;
void loadingOn(bool visible=true) override;
void loadingOff() override;
void setProgressRange (size_t range) override;

@ -7,7 +7,6 @@
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/pickpocket.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwbase/environment.hpp"

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save