forked from teamnwah/openmw-tes3coop
Merge pull request #360 from TES3MP/0.6.1-openmw-updates while resolving conflicts
This commit is contained in:
commit
cac2c6c1e8
415 changed files with 11318 additions and 4626 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -26,6 +26,7 @@ Doxygen
|
||||||
.settings
|
.settings
|
||||||
.directory
|
.directory
|
||||||
.idea
|
.idea
|
||||||
|
cmake-build-*
|
||||||
files/windows/*.aps
|
files/windows/*.aps
|
||||||
cmake-build-*
|
cmake-build-*
|
||||||
## qt-creator
|
## qt-creator
|
||||||
|
|
|
@ -24,7 +24,7 @@ addons:
|
||||||
- llvm-toolchain-precise-3.6
|
- llvm-toolchain-precise-3.6
|
||||||
packages: [
|
packages: [
|
||||||
# Dev
|
# Dev
|
||||||
clang-3.6, libunshield-dev, libtinyxml-dev,
|
cmake, clang-3.6, libunshield-dev, libtinyxml-dev,
|
||||||
g++-6,
|
g++-6,
|
||||||
# Tests
|
# Tests
|
||||||
libgtest-dev, google-mock,
|
libgtest-dev, google-mock,
|
||||||
|
@ -43,7 +43,7 @@ addons:
|
||||||
name: "TES3MP/openmw-tes3mp"
|
name: "TES3MP/openmw-tes3mp"
|
||||||
description: "<Your project description here>"
|
description: "<Your project description here>"
|
||||||
notification_email: stas5978@gmail.com
|
notification_email: stas5978@gmail.com
|
||||||
build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE"
|
build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_MWINIIMPORTER=FALSE -DBUILD_LAUNCHER=FALSE"
|
||||||
build_command: "make -j3"
|
build_command: "make -j3"
|
||||||
branch_pattern: coverity_scan
|
branch_pattern: coverity_scan
|
||||||
matrix:
|
matrix:
|
||||||
|
|
|
@ -34,11 +34,13 @@ Programmers
|
||||||
Ben Shealy (bentsherman)
|
Ben Shealy (bentsherman)
|
||||||
Bret Curtis (psi29a)
|
Bret Curtis (psi29a)
|
||||||
Britt Mathis (galdor557)
|
Britt Mathis (galdor557)
|
||||||
|
Capostrophic
|
||||||
cc9cii
|
cc9cii
|
||||||
Chris Boyce (slothlife)
|
Chris Boyce (slothlife)
|
||||||
Chris Robinson (KittyCat)
|
Chris Robinson (KittyCat)
|
||||||
Cory F. Cohen (cfcohen)
|
Cory F. Cohen (cfcohen)
|
||||||
Cris Mihalache (Mirceam)
|
Cris Mihalache (Mirceam)
|
||||||
|
crussell187
|
||||||
darkf
|
darkf
|
||||||
devnexen
|
devnexen
|
||||||
Dieho
|
Dieho
|
||||||
|
@ -86,6 +88,7 @@ Programmers
|
||||||
lazydev
|
lazydev
|
||||||
Leon Krieg (lkrieg)
|
Leon Krieg (lkrieg)
|
||||||
Leon Saunders (emoose)
|
Leon Saunders (emoose)
|
||||||
|
Łukasz Gołębiewski (lukago)
|
||||||
logzero
|
logzero
|
||||||
lohikaarme
|
lohikaarme
|
||||||
Lukasz Gromanowski (lgro)
|
Lukasz Gromanowski (lgro)
|
||||||
|
@ -104,6 +107,7 @@ Programmers
|
||||||
Michael Papageorgiou (werdanith)
|
Michael Papageorgiou (werdanith)
|
||||||
Michał Bień (Glorf)
|
Michał Bień (Glorf)
|
||||||
Michał Moroz (dragonee)
|
Michał Moroz (dragonee)
|
||||||
|
Miloslav Číž (drummyfish)
|
||||||
Miroslav Puda (pakanek)
|
Miroslav Puda (pakanek)
|
||||||
MiroslavR
|
MiroslavR
|
||||||
Mitchell Schwitzer (schwitzerm)
|
Mitchell Schwitzer (schwitzerm)
|
||||||
|
@ -125,6 +129,7 @@ Programmers
|
||||||
Radu-Marius Popovici (rpopovici)
|
Radu-Marius Popovici (rpopovici)
|
||||||
Rafael Moura (dhustkoder)
|
Rafael Moura (dhustkoder)
|
||||||
rdimesio
|
rdimesio
|
||||||
|
rexelion
|
||||||
riothamus
|
riothamus
|
||||||
Rob Cutmore (rcutmore)
|
Rob Cutmore (rcutmore)
|
||||||
Robert MacGregor (Ragora)
|
Robert MacGregor (Ragora)
|
||||||
|
@ -148,6 +153,7 @@ Programmers
|
||||||
Sylvain Thesnieres (Garvek)
|
Sylvain Thesnieres (Garvek)
|
||||||
t6
|
t6
|
||||||
terrorfisch
|
terrorfisch
|
||||||
|
thegriglat
|
||||||
Thomas Luppi (Digmaster)
|
Thomas Luppi (Digmaster)
|
||||||
Will Herrmann (Thunderforge)
|
Will Herrmann (Thunderforge)
|
||||||
Tom Mason (wheybags)
|
Tom Mason (wheybags)
|
||||||
|
|
137
CHANGELOG.md
137
CHANGELOG.md
|
@ -1,3 +1,140 @@
|
||||||
|
0.43.0
|
||||||
|
------
|
||||||
|
|
||||||
|
Bug #815: Different settings cause inconsistent underwater visibility
|
||||||
|
Bug #1452: autosave is not executed when waiting
|
||||||
|
Bug #1555: Closing containers with spacebar doesn't work after touching an item
|
||||||
|
Bug #1692: Can't close container when item is "held"
|
||||||
|
Bug #2405: Maximum distance for guards attacking hostile creatures is incorrect
|
||||||
|
Bug #2445: Spellcasting can be interrupted
|
||||||
|
Bug #2489: Keeping map open not persisted between saves
|
||||||
|
Bug #2594: 1st person view uses wrong body texture with Better bodies
|
||||||
|
Bug #2628: enablestatreviewmenu command doen't read race, class and sign values from current game
|
||||||
|
Bug #2639: Attacking flag isn't reset upon reloading
|
||||||
|
Bug #2698: Snow and rain VFX move with the player
|
||||||
|
Bug #2704: Some creature swim animations not being used
|
||||||
|
Bug #2789: Potential risk of misunderstanding using the colored "owned" crosshair feature
|
||||||
|
Bug #3045: Settings containing '#' cannot be loaded
|
||||||
|
Bug #3097: Drop() doesn't work when an item is held (with the mouse)
|
||||||
|
Bug #3110: GetDetected doesn't work without a reference
|
||||||
|
Bug #3126: Framerate nosedives when adjusting dialogue window size
|
||||||
|
Bug #3243: Ampersand in configuration files isn't escaped automatically
|
||||||
|
Bug #3365: Wrong water reflection along banks
|
||||||
|
Bug #3441: Golden saint always dispelling soul trap / spell priority issue
|
||||||
|
Bug #3528: Disposing of corpses breaks quests
|
||||||
|
Bug #3531: No FPS limit when playing bink videos even though "framerate limit" is set in settings.cfg
|
||||||
|
Bug #3647: Multi-effect spells play audio louder than in Vanilla
|
||||||
|
Bug #3656: NPCs forget where their place in the world is
|
||||||
|
Bug #3665: Music transitions are too abrupt
|
||||||
|
Bug #3679: Spell cast effect should disappear after using rest command
|
||||||
|
Bug #3684: Merchants do not restock empty soul gems if they acquire filled ones.
|
||||||
|
Bug #3694: Wrong magicka bonus applied on character creation
|
||||||
|
Bug #3706: Guards don't try to arrest the player if attacked
|
||||||
|
Bug #3709: Editor: Camera is not positioned correctly on mode switches related to orbital mode
|
||||||
|
Bug #3720: Death counter not cleaned of non-existing IDs when loading a game
|
||||||
|
Bug #3744: "Greater/lesser or equal" operators are not parsed when their signs are swapped
|
||||||
|
Bug #3749: Yagrum Bagarn moves to different position on encountering
|
||||||
|
Bug #3766: DisableLevitation does not remove visuals of preexisting effect
|
||||||
|
Bug #3787: Script commands in result box for voiced dialogue are ignored
|
||||||
|
Bug #3793: OpenMW tries to animate animated references even when they are disabled
|
||||||
|
Bug #3794: Default sound buffer size is too small for mods
|
||||||
|
Bug #3796: Mod 'Undress for me' doesn't work: NPCs re-equip everything
|
||||||
|
Bug #3798: tgm command behaviour differs from vanilla
|
||||||
|
Bug #3804: [Mod] Animated Morrowind: some animations do not loop correctly
|
||||||
|
Bug #3805: Slight enchant miscalculation
|
||||||
|
Bug #3826: Rendering problems with an image in a letter
|
||||||
|
Bug #3833: [Mod] Windows Glow: windows textures are much darker than in original game
|
||||||
|
Bug #3835: Bodyparts with multiple NiTriShapes are not handled correctly
|
||||||
|
Bug #3839: InventoryStore::purgeEffect() removes only first effect with argument ID
|
||||||
|
Bug #3843: Wrong jumping fatigue loss calculations
|
||||||
|
Bug #3850: Boethiah's voice is distorted underwater
|
||||||
|
Bug #3851: NPCs and player say things while underwater
|
||||||
|
Bug #3864: Crash when exiting to Khartag point from Ilunibi
|
||||||
|
Bug #3878: Swapping soul gems while enchanting allows constant effect enchantments using any soul gem
|
||||||
|
Bug #3879: Dialogue option: Go to jail, persists beyond quickload
|
||||||
|
Bug #3891: Journal displays empty entries
|
||||||
|
Bug #3892: Empty space before dialogue entry display
|
||||||
|
Bug #3898: (mod) PositionCell in dialogue results closes dialogue window
|
||||||
|
Bug #3906: "Could not find Data Files location" dialog can appear multiple times
|
||||||
|
Bug #3908: [Wizard] User gets stuck if they cancel out of installing from a CD
|
||||||
|
Bug #3909: Morrowind Content Language dropdown is the only element on the right half of the Settings window
|
||||||
|
Bug #3910: Launcher window can be resized so that it cuts off the scroll
|
||||||
|
Bug #3915: NC text key on nifs doesn't work
|
||||||
|
Bug #3919: Closing inventory while cursor hovers over spell (or other magic menu item) produces left click sound
|
||||||
|
Bug #3922: Combat AI should avoid enemy hits when casts Self-ranged spells
|
||||||
|
Bug #3934: [macOS] Copy/Paste from system clipboard uses Control key instead of Command key
|
||||||
|
Bug #3935: Incorrect attack strength for AI actors
|
||||||
|
Bug #3937: Combat AI: enchanted weapons have too high rating
|
||||||
|
Bug #3942: UI sounds are distorted underwater
|
||||||
|
Bug #3943: CPU/GPU usage should stop when the game is minimised
|
||||||
|
Bug #3944: Attempting to sell stolen items back to their owner does not remove them from your inventory
|
||||||
|
Bug #3955: Player's avatar rendering issues
|
||||||
|
Bug #3956: EditEffectDialog: Cancel button does not update a Range button and an Area slider properly
|
||||||
|
Bug #3957: Weird bodypart rendering if a node has reserved name
|
||||||
|
Bug #3960: Clothes with high cost (> 32768) are not handled properly
|
||||||
|
Bug #3963: When on edge of being burdened the condition doesn't lower as you run.
|
||||||
|
Bug #3971: Editor: Incorrect colour field in cell table
|
||||||
|
Bug #3974: Journal page turning doesn't produce sounds
|
||||||
|
Bug #3978: Instant opening and closing happens when using a Controller with Menus/Containers
|
||||||
|
Bug #3981: Lagging when spells are cast, especially noticeable on new landmasses such as Tamriel Rebuilt
|
||||||
|
Bug #3982: Down sounds instead of Up ones are played when trading
|
||||||
|
Bug #3987: NPCs attack after some taunting with no "Goodbye"
|
||||||
|
Bug #3991: Journal can still be opened at main menu
|
||||||
|
Bug #3995: Dispel cancels every temporary magic effect
|
||||||
|
Bug #4002: Build broken on OpenBSD with clang
|
||||||
|
Bug #4003: Reduce Render Area of Inventory Doll to Fit Within Border
|
||||||
|
Bug #4004: Manis Virmaulese attacks without saying anything
|
||||||
|
Bug #4010: AiWander: "return to the spawn position" feature does not work properly
|
||||||
|
Bug #4016: Closing menus with spacebar will still send certain assigned actions through afterwards
|
||||||
|
Bug #4017: GetPCRunning and GetPCSneaking should check that the PC is actually moving
|
||||||
|
Bug #4024: Poor music track distribution
|
||||||
|
Bug #4025: Custom spell with copy-pasted name always sorts to top of spell list
|
||||||
|
Bug #4027: Editor: OpenMW-CS misreports its own name as "OpenCS", under Mac OS
|
||||||
|
Bug #4033: Archers don't attack if the arrows have run out and there is no other weapon
|
||||||
|
Bug #4037: Editor: New greetings do not work in-game.
|
||||||
|
Bug #4049: Reloading a saved game while falling prevents damage
|
||||||
|
Bug #4056: Draw animation should not be played when player equips a new weapon
|
||||||
|
Bug #4074: Editor: Merging of LAND/LTEX records
|
||||||
|
Bug #4076: Disposition bar is not updated when "goodbye" selected in dialogue
|
||||||
|
Bug #4079: Alchemy skill increases do not take effect until next batch
|
||||||
|
Bug #4093: GetResistFire, getResistFrost and getResistShock doesn't work as in vanilla
|
||||||
|
Bug #4094: Level-up messages for levels past 20 are hardcoded not to be used
|
||||||
|
Bug #4095: Error in framelistener when take all items from a dead corpse
|
||||||
|
Bug #4096: Messagebox with the "%0.f" format should use 0 digit precision
|
||||||
|
Bug #4104: Cycling through weapons does not skip broken ones
|
||||||
|
Bug #4105: birthsign generation menu does not show full details
|
||||||
|
Bug #4107: Editor: Left pane in Preferences window is too narrow
|
||||||
|
Bug #4112: Inventory sort order is inconsistent
|
||||||
|
Bug #4113: 'Resolution not supported in fullscreen' message is inconvenient
|
||||||
|
Bug #4131: Pickpocketing behaviour is different from vanilla
|
||||||
|
Bug #4155: NPCs don't equip a second ring in some cases
|
||||||
|
Bug #4156: Snow doesn't create water ripples
|
||||||
|
Bug #4165: NPCs autoequip new clothing with the same price
|
||||||
|
Feature #452: Rain-induced water ripples
|
||||||
|
Feature #824: Fading for doors and teleport commands
|
||||||
|
Feature #933: Editor: LTEX record table
|
||||||
|
Feature #936: Editor: LAND record table
|
||||||
|
Feature #1374: AI: Resurface to breathe
|
||||||
|
Feature #2320: ess-Importer: convert projectiles
|
||||||
|
Feature #2509: Editor: highlighting occurrences of a word in a script
|
||||||
|
Feature #2748: Editor: Should use one resource manager per document
|
||||||
|
Feature #2834: Have openMW's UI remember what menu items were 'pinned' across boots.
|
||||||
|
Feature #2923: Option to show the damage of the arrows through tooltip.
|
||||||
|
Feature #3099: Disabling inventory while dragging an item forces you to drop it
|
||||||
|
Feature #3274: Editor: Script Editor - Shortcuts and context menu options for commenting code out and uncommenting code respectively
|
||||||
|
Feature #3275: Editor: User Settings- Add an option to reset settings to their default status (per category / all)
|
||||||
|
Feature #3400: Add keyboard shortcuts for menus
|
||||||
|
Feature #3492: Show success rate while enchanting
|
||||||
|
Feature #3530: Editor: Reload data files
|
||||||
|
Feature #3682: Editor: Default key binding reset
|
||||||
|
Feature #3921: Combat AI: aggro priorities
|
||||||
|
Feature #3941: Allow starting at an unnamed exterior cell with --start
|
||||||
|
Feature #3952: Add Visual Studio 2017 support
|
||||||
|
Feature #3953: Combat AI: use "WhenUsed" enchantments
|
||||||
|
Feature #4082: Leave the stack of ingredients or potions grabbed after using an ingredient/potion
|
||||||
|
Task #2258: Windows installer: launch OpenMW tickbox
|
||||||
|
Task #4152: The Windows CI script is moving files around that CMake should be dealing with
|
||||||
|
|
||||||
0.42.0
|
0.42.0
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
@ -6,5 +6,5 @@ brew outdated cmake || brew upgrade cmake
|
||||||
brew outdated pkgconfig || brew upgrade pkgconfig
|
brew outdated pkgconfig || brew upgrade pkgconfig
|
||||||
brew install $macos_qt_formula
|
brew install $macos_qt_formula
|
||||||
|
|
||||||
curl https://downloads.openmw.org/osx/dependencies/openmw-deps-5e144e2.zip -o ~/openmw-deps.zip
|
curl https://downloads.openmw.org/osx/dependencies/openmw-deps-c40905f.zip -o ~/openmw-deps.zip
|
||||||
unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null
|
unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null
|
||||||
|
|
|
@ -320,9 +320,9 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
||||||
"ffmpeg-3.2.4-dev-win${BITS}.zip"
|
"ffmpeg-3.2.4-dev-win${BITS}.zip"
|
||||||
|
|
||||||
# MyGUI
|
# MyGUI
|
||||||
download "MyGUI 3.2.3-git" \
|
download "MyGUI 3.2.2" \
|
||||||
"http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
"http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
||||||
"MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z"
|
"MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||||
|
|
||||||
# OpenAL
|
# OpenAL
|
||||||
download "OpenAL-Soft 1.17.2" \
|
download "OpenAL-Soft 1.17.2" \
|
||||||
|
@ -330,9 +330,9 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
||||||
"OpenAL-Soft-1.17.2.zip"
|
"OpenAL-Soft-1.17.2.zip"
|
||||||
|
|
||||||
# OSG
|
# OSG
|
||||||
download "OpenSceneGraph 3.4.0-scrawl" \
|
download "OpenSceneGraph 3.4.1-scrawl" \
|
||||||
"http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
"http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
||||||
"OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z"
|
"OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||||
|
|
||||||
# Qt
|
# Qt
|
||||||
if [ -z $APPVEYOR ]; then
|
if [ -z $APPVEYOR ]; then
|
||||||
|
@ -350,9 +350,9 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# SDL2
|
# SDL2
|
||||||
download "SDL 2.0.4" \
|
download "SDL 2.0.7" \
|
||||||
"https://www.libsdl.org/release/SDL2-devel-2.0.4-VC.zip" \
|
"https://www.libsdl.org/release/SDL2-devel-2.0.7-VC.zip" \
|
||||||
"SDL2-2.0.4.zip"
|
"SDL2-2.0.7.zip"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd .. #/..
|
cd .. #/..
|
||||||
|
@ -474,20 +474,20 @@ cd $DEPS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# MyGUI
|
# MyGUI
|
||||||
printf "MyGUI 3.2.3-git... "
|
printf "MyGUI 3.2.2... "
|
||||||
{
|
{
|
||||||
cd $DEPS_INSTALL
|
cd $DEPS_INSTALL
|
||||||
|
|
||||||
if [ -d MyGUI ] && \
|
if [ -d MyGUI ] && \
|
||||||
grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
||||||
grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
||||||
grep "MYGUI_VERSION_PATCH 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null
|
grep "MYGUI_VERSION_PATCH 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null
|
||||||
then
|
then
|
||||||
printf "Exists. "
|
printf "Exists. "
|
||||||
elif [ -z $SKIP_EXTRACT ]; then
|
elif [ -z $SKIP_EXTRACT ]; then
|
||||||
rm -rf MyGUI
|
rm -rf MyGUI
|
||||||
eval 7z x -y "${DEPS}/MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
eval 7z x -y "${DEPS}/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||||
mv "MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}" MyGUI
|
mv "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}" MyGUI
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export MYGUI_HOME="$(real_pwd)/MyGUI"
|
export MYGUI_HOME="$(real_pwd)/MyGUI"
|
||||||
|
@ -527,20 +527,20 @@ cd $DEPS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# OSG
|
# OSG
|
||||||
printf "OSG 3.4.0-scrawl... "
|
printf "OSG 3.4.1-scrawl... "
|
||||||
{
|
{
|
||||||
cd $DEPS_INSTALL
|
cd $DEPS_INSTALL
|
||||||
|
|
||||||
if [ -d OSG ] && \
|
if [ -d OSG ] && \
|
||||||
grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \
|
grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \
|
||||||
grep "OPENSCENEGRAPH_MINOR_VERSION 4" OSG/include/osg/Version > /dev/null && \
|
grep "OPENSCENEGRAPH_MINOR_VERSION 4" OSG/include/osg/Version > /dev/null && \
|
||||||
grep "OPENSCENEGRAPH_PATCH_VERSION 0" OSG/include/osg/Version > /dev/null
|
grep "OPENSCENEGRAPH_PATCH_VERSION 1" OSG/include/osg/Version > /dev/null
|
||||||
then
|
then
|
||||||
printf "Exists. "
|
printf "Exists. "
|
||||||
elif [ -z $SKIP_EXTRACT ]; then
|
elif [ -z $SKIP_EXTRACT ]; then
|
||||||
rm -rf OSG
|
rm -rf OSG
|
||||||
eval 7z x -y "${DEPS}/OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
eval 7z x -y "${DEPS}/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||||
mv "OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG
|
mv "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OSG_SDK="$(real_pwd)/OSG"
|
OSG_SDK="$(real_pwd)/OSG"
|
||||||
|
@ -556,8 +556,8 @@ printf "OSG 3.4.0-scrawl... "
|
||||||
add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \
|
add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \
|
||||||
"$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll
|
"$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll
|
||||||
|
|
||||||
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll
|
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll
|
||||||
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll
|
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
}
|
}
|
||||||
|
@ -632,18 +632,18 @@ cd $DEPS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# SDL2
|
# SDL2
|
||||||
printf "SDL 2.0.4... "
|
printf "SDL 2.0.7... "
|
||||||
{
|
{
|
||||||
if [ -d SDL2-2.0.4 ]; then
|
if [ -d SDL2-2.0.7 ]; then
|
||||||
printf "Exists. "
|
printf "Exists. "
|
||||||
elif [ -z $SKIP_EXTRACT ]; then
|
elif [ -z $SKIP_EXTRACT ]; then
|
||||||
rm -rf SDL2-2.0.4
|
rm -rf SDL2-2.0.7
|
||||||
eval 7z x -y SDL2-2.0.4.zip $STRIP
|
eval 7z x -y SDL2-2.0.7.zip $STRIP
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export SDL2DIR="$(real_pwd)/SDL2-2.0.4"
|
export SDL2DIR="$(real_pwd)/SDL2-2.0.7"
|
||||||
|
|
||||||
add_runtime_dlls "$(pwd)/SDL2-2.0.4/lib/x${ARCHSUFFIX}/SDL2.dll"
|
add_runtime_dlls "$(pwd)/SDL2-2.0.7/lib/x${ARCHSUFFIX}/SDL2.dll"
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
}
|
}
|
||||||
|
@ -717,10 +717,10 @@ if [ -z $CI ]; then
|
||||||
echo
|
echo
|
||||||
|
|
||||||
echo "- OSG Plugin DLLs..."
|
echo "- OSG Plugin DLLs..."
|
||||||
mkdir -p $BUILD_CONFIG/osgPlugins-3.4.0
|
mkdir -p $BUILD_CONFIG/osgPlugins-3.4.1
|
||||||
for DLL in $OSG_PLUGINS; do
|
for DLL in $OSG_PLUGINS; do
|
||||||
echo " $(basename $DLL)."
|
echo " $(basename $DLL)."
|
||||||
cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.0
|
cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.1
|
||||||
done
|
done
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
@ -750,19 +750,4 @@ if [ -z $VERBOSE ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z $CI ]; then
|
|
||||||
echo "- Copying Runtime Resources/Config Files"
|
|
||||||
echo " gamecontrollerdb.txt"
|
|
||||||
cp gamecontrollerdb.txt $BUILD_CONFIG/gamecontrollerdb.txt
|
|
||||||
echo " openmw.cfg"
|
|
||||||
cp openmw.cfg.install $BUILD_CONFIG/openmw.cfg
|
|
||||||
echo " openmw-cs.cfg"
|
|
||||||
cp openmw-cs.cfg $BUILD_CONFIG/openmw-cs.cfg
|
|
||||||
echo " settings-default.cfg"
|
|
||||||
cp settings-default.cfg $BUILD_CONFIG/settings-default.cfg
|
|
||||||
echo " resources/"
|
|
||||||
cp -r resources $BUILD_CONFIG/resources
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit $RET
|
exit $RET
|
||||||
|
|
144
CMakeLists.txt
144
CMakeLists.txt
|
@ -1,3 +1,35 @@
|
||||||
|
# Apps and tools
|
||||||
|
option(BUILD_OPENMW "build OpenMW" ON)
|
||||||
|
option(BUILD_OPENMW_MP "build OpenMW-MP" ON)
|
||||||
|
option(BUILD_MASTER "build tes3mp master server" OFF)
|
||||||
|
option(BUILD_BSATOOL "build BSA extractor" ON)
|
||||||
|
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
||||||
|
option(BUILD_LAUNCHER "build Launcher" ON)
|
||||||
|
option(BUILD_BROWSER "build tes3mp Server Browser" ON)
|
||||||
|
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
|
||||||
|
option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON)
|
||||||
|
option(BUILD_OPENCS "build OpenMW Construction Set" ON)
|
||||||
|
option(BUILD_WIZARD "build Installation Wizard" ON)
|
||||||
|
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
||||||
|
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
|
||||||
|
option(BUILD_NIFTEST "build nif file tester" OFF)
|
||||||
|
option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
|
||||||
|
option(BUILD_DOCS "build documentation." OFF )
|
||||||
|
|
||||||
|
if (NOT BUILD_LAUNCHER AND NOT BUILD_BROWSER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD)
|
||||||
|
set(USE_QT FALSE)
|
||||||
|
else()
|
||||||
|
set(USE_QT TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (USE_QT)
|
||||||
|
set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)")
|
||||||
|
set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# set the minimum required version across the board
|
||||||
|
cmake_minimum_required(VERSION 3.1.0)
|
||||||
|
|
||||||
project(OpenMW)
|
project(OpenMW)
|
||||||
|
|
||||||
# If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them.
|
# If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them.
|
||||||
|
@ -25,7 +57,7 @@ endif()
|
||||||
message(STATUS "Configuring OpenMW...")
|
message(STATUS "Configuring OpenMW...")
|
||||||
|
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 42)
|
set(OPENMW_VERSION_MINOR 43)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
|
@ -59,24 +91,6 @@ option(QT_STATIC "Link static build of QT into the binaries" FALSE)
|
||||||
|
|
||||||
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
|
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
|
||||||
|
|
||||||
# Apps and tools
|
|
||||||
option(BUILD_OPENMW "build OpenMW" ON)
|
|
||||||
option(BUILD_OPENMW_MP "build OpenMW-MP" ON)
|
|
||||||
option(BUILD_MASTER "build tes3mp master server" OFF)
|
|
||||||
option(BUILD_BSATOOL "build BSA extractor" ON)
|
|
||||||
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
|
||||||
option(BUILD_LAUNCHER "build Launcher" ON)
|
|
||||||
option(BUILD_BROWSER "build tes3mp Server Browser" ON)
|
|
||||||
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
|
|
||||||
option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON)
|
|
||||||
option(BUILD_OPENCS "build OpenMW Construction Set" ON)
|
|
||||||
option(BUILD_WIZARD "build Installation Wizard" ON)
|
|
||||||
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
|
||||||
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
|
|
||||||
option(BUILD_NIFTEST "build nif file tester" OFF)
|
|
||||||
option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
|
|
||||||
option(BUILD_DOCS "build documentation." OFF )
|
|
||||||
|
|
||||||
# what is necessary to build documentation
|
# what is necessary to build documentation
|
||||||
IF( BUILD_DOCS )
|
IF( BUILD_DOCS )
|
||||||
# Builds the documentation.
|
# Builds the documentation.
|
||||||
|
@ -126,16 +140,8 @@ endif()
|
||||||
find_package(RakNet REQUIRED)
|
find_package(RakNet REQUIRED)
|
||||||
include_directories(${RakNet_INCLUDES})
|
include_directories(${RakNet_INCLUDES})
|
||||||
|
|
||||||
if (NOT BUILD_LAUNCHER AND NOT BUILD_BROWSER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD)
|
|
||||||
set(USE_QT FALSE)
|
|
||||||
else()
|
|
||||||
set(USE_QT TRUE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
if (USE_QT)
|
if (USE_QT)
|
||||||
set(DESIRED_QT_VERSION 5 CACHE STRING "The QT version OpenMW should use (4 or 5)")
|
|
||||||
set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5)
|
|
||||||
message(STATUS "Using Qt${DESIRED_QT_VERSION}")
|
message(STATUS "Using Qt${DESIRED_QT_VERSION}")
|
||||||
|
|
||||||
if (DESIRED_QT_VERSION MATCHES 4)
|
if (DESIRED_QT_VERSION MATCHES 4)
|
||||||
|
@ -150,17 +156,6 @@ if (USE_QT)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
|
||||||
# OS X build process relies on this fix: https://github.com/Kitware/CMake/commit/3df5147043d83aa09acd5c9ce31d5c602efb99db
|
|
||||||
cmake_minimum_required(VERSION 3.1.0)
|
|
||||||
elseif (USE_QT AND DESIRED_QT_VERSION MATCHES 5)
|
|
||||||
# 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows.
|
|
||||||
cmake_minimum_required(VERSION 2.8.11)
|
|
||||||
else()
|
|
||||||
# We probably support older versions than this.
|
|
||||||
cmake_minimum_required(VERSION 2.6)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
IF(BUILD_OPENMW OR BUILD_OPENCS)
|
IF(BUILD_OPENMW OR BUILD_OPENCS)
|
||||||
# Sound setup
|
# Sound setup
|
||||||
find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE)
|
find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE)
|
||||||
|
@ -323,33 +318,34 @@ endif (APPLE)
|
||||||
|
|
||||||
# Other files
|
# Other files
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp-client-default.cfg
|
configure_resource_file(${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp-client-default.cfg
|
||||||
"${OpenMW_BINARY_DIR}/tes3mp-client-default.cfg")
|
"${OpenMW_BINARY_DIR}" "tes3mp-client-default.cfg")
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp-server-default.cfg
|
configure_resource_file(${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp-server-default.cfg
|
||||||
"${OpenMW_BINARY_DIR}/tes3mp-server-default.cfg")
|
"${OpenMW_BINARY_DIR}" "tes3mp-server-default.cfg")
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
|
configure_resource_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
|
||||||
"${OpenMW_BINARY_DIR}/settings-default.cfg")
|
"${OpenMW_BINARY_DIR}" "settings-default.cfg")
|
||||||
|
|
||||||
if (NOT APPLE)
|
if (NOT APPLE)
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
|
configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
|
||||||
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
"${OpenMW_BINARY_DIR}" "openmw.cfg")
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||||
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
|
"${OpenMW_BINARY_DIR}" "openmw.cfg.install")
|
||||||
else ()
|
else ()
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||||
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
|
configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
|
||||||
"${OpenMW_BINARY_DIR}/openmw-cs.cfg")
|
"${OpenMW_BINARY_DIR}" "openmw-cs.cfg")
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
|
# 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.
|
||||||
"${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY)
|
copy_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
|
||||||
|
"${OpenMW_BINARY_DIR}" "resources/defaultfilters")
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt
|
configure_resource_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt
|
||||||
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt")
|
"${OpenMW_BINARY_DIR}" "gamecontrollerdb.txt")
|
||||||
|
|
||||||
if (NOT WIN32 AND NOT APPLE)
|
if (NOT WIN32 AND NOT APPLE)
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
|
||||||
|
@ -363,6 +359,7 @@ if (NOT WIN32 AND NOT APPLE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# CXX Compiler settings
|
# CXX Compiler settings
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wundef -Wno-unused-parameter -std=c++11 -pedantic -Wno-long-long")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wundef -Wno-unused-parameter -std=c++11 -pedantic -Wno-long-long")
|
||||||
add_definitions( -DBOOST_NO_CXX11_SCOPED_ENUMS=ON )
|
add_definitions( -DBOOST_NO_CXX11_SCOPED_ENUMS=ON )
|
||||||
|
@ -398,13 +395,16 @@ IF(NOT WIN32 AND NOT APPLE)
|
||||||
|
|
||||||
# Install binaries
|
# Install binaries
|
||||||
IF(BUILD_OPENMW)
|
IF(BUILD_OPENMW)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/tes3mp" DESTINATION "${BINDIR}" )
|
||||||
ENDIF(BUILD_OPENMW)
|
ENDIF(BUILD_OPENMW)
|
||||||
|
IF(BUILD_OPENMW_MP)
|
||||||
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/tes3mp-server" DESTINATION "${BINDIR}")
|
||||||
|
ENDIF(BUILD_OPENMW_MP)
|
||||||
IF(BUILD_LAUNCHER)
|
IF(BUILD_LAUNCHER)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" )
|
||||||
ENDIF(BUILD_LAUNCHER)
|
ENDIF(BUILD_LAUNCHER)
|
||||||
IF(BUILD_BROWSER)
|
IF(BUILD_BROWSER)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-browser" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/tes3mp-browser" DESTINATION "${BINDIR}" )
|
||||||
ENDIF(BUILD_BROWSER)
|
ENDIF(BUILD_BROWSER)
|
||||||
IF(BUILD_BSATOOL)
|
IF(BUILD_BSATOOL)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" )
|
||||||
|
@ -432,7 +432,7 @@ IF(NOT WIN32 AND NOT APPLE)
|
||||||
#ENDIF(BUILD_MYGUI_PLUGIN)
|
#ENDIF(BUILD_MYGUI_PLUGIN)
|
||||||
|
|
||||||
# Install licenses
|
# Install licenses
|
||||||
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
|
INSTALL(FILES "files/mygui/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
|
||||||
|
|
||||||
# Install icon and desktop file
|
# Install icon and desktop file
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw")
|
||||||
|
@ -452,10 +452,11 @@ IF(NOT WIN32 AND NOT APPLE)
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||||
|
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client-default" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-client.cfg" COMPONENT "openmw")
|
#INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-client.cfg" COMPONENT "openmw")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server-default" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw-mp")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw-mp")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-server.cfg" COMPONENT "openmw-mp")
|
#INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-server.cfg" COMPONENT "openmw-mp")
|
||||||
|
#They both do not exist
|
||||||
|
|
||||||
IF(BUILD_OPENCS)
|
IF(BUILD_OPENCS)
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs")
|
||||||
|
@ -471,16 +472,20 @@ if(WIN32)
|
||||||
FILE(GLOB dll_files_release "${OpenMW_BINARY_DIR}/Release/*.dll")
|
FILE(GLOB dll_files_release "${OpenMW_BINARY_DIR}/Release/*.dll")
|
||||||
INSTALL(FILES ${dll_files_debug} DESTINATION "." CONFIGURATIONS Debug)
|
INSTALL(FILES ${dll_files_debug} DESTINATION "." CONFIGURATIONS Debug)
|
||||||
INSTALL(FILES ${dll_files_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
INSTALL(FILES ${dll_files_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg" CONFIGURATIONS Debug)
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg" CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt")
|
INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt")
|
||||||
INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt")
|
INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt")
|
||||||
|
INSTALL(FILES "${OpenMW_SOURCE_DIR}/LICENSE" DESTINATION "." RENAME "LICENSE.txt")
|
||||||
INSTALL(FILES
|
INSTALL(FILES
|
||||||
"${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt"
|
"${OpenMW_SOURCE_DIR}/files/mygui/DejaVu Font License.txt"
|
||||||
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
|
|
||||||
"${OpenMW_BINARY_DIR}/settings-default.cfg"
|
|
||||||
"${OpenMW_BINARY_DIR}/tes3mp-client-default.cfg"
|
|
||||||
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
|
|
||||||
DESTINATION ".")
|
DESTINATION ".")
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/settings-default.cfg" DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/settings-default.cfg" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/tes3mp-client-default.cfg" DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/tes3mp-client-default.cfg" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/gamecontrollerdb.txt" DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/gamecontrollerdb.txt" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
|
|
||||||
if(BUILD_MYGUI_PLUGIN)
|
if(BUILD_MYGUI_PLUGIN)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug)
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
@ -492,7 +497,9 @@ if(WIN32)
|
||||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Debug/resources" DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/resources" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
|
|
||||||
FILE(GLOB plugin_dir_debug "${OpenMW_BINARY_DIR}/Debug/osgPlugins-*")
|
FILE(GLOB plugin_dir_debug "${OpenMW_BINARY_DIR}/Debug/osgPlugins-*")
|
||||||
FILE(GLOB plugin_dir_release "${OpenMW_BINARY_DIR}/Release/osgPlugins-*")
|
FILE(GLOB plugin_dir_release "${OpenMW_BINARY_DIR}/Release/osgPlugins-*")
|
||||||
INSTALL(DIRECTORY ${plugin_dir_debug} DESTINATION "." CONFIGURATIONS Debug)
|
INSTALL(DIRECTORY ${plugin_dir_debug} DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
@ -530,6 +537,7 @@ if(WIN32)
|
||||||
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
|
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
|
||||||
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
|
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
|
||||||
SET(CPACK_NSIS_INSTALLED_ICON_NAME "openmw-launcher.exe")
|
SET(CPACK_NSIS_INSTALLED_ICON_NAME "openmw-launcher.exe")
|
||||||
|
SET(CPACK_NSIS_MUI_FINISHPAGE_RUN "openmw-launcher.exe")
|
||||||
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp.ico")
|
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp.ico")
|
||||||
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp.ico")
|
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp.ico")
|
||||||
SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
|
SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
|
||||||
|
|
|
@ -33,6 +33,7 @@ Furthermore, we advise to:
|
||||||
* Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title.
|
* Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title.
|
||||||
* If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards).
|
* If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards).
|
||||||
* Make sure each of your changes has a clear objective. Unnecessary changes may lead to merge conflicts, clutter the commit history and slow down review. Code formatting 'fixes' should be avoided, unless you were already changing that particular line anyway.
|
* Make sure each of your changes has a clear objective. Unnecessary changes may lead to merge conflicts, clutter the commit history and slow down review. Code formatting 'fixes' should be avoided, unless you were already changing that particular line anyway.
|
||||||
|
* Reference the bug / feature ticket(s) in your commit message (e.g. 'Bug #123') to make it easier to keep track of what we changed for what reason. Our bugtracker will show those commits next to the ticket. If your commit message includes 'Fixes #123', that bug/feature will automatically be set to 'Closed' when your commit is merged.
|
||||||
|
|
||||||
Guidelines for original engine "fixes"
|
Guidelines for original engine "fixes"
|
||||||
=================================
|
=================================
|
||||||
|
|
|
@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
|
||||||
state the exclusion of warranty; and each file should have at least
|
state the exclusion of warranty; and each file should have at least
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
{one line to give the program's name and a brief idea of what it does.}
|
||||||
Copyright (C) <year> <name of author>
|
Copyright (C) {year} {name of author}
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
||||||
If the program does terminal interaction, make it output a short
|
If the program does terminal interaction, make it output a short
|
||||||
notice like this when it starts in an interactive mode:
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
{project} Copyright (C) {year} {fullname}
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions; type `show c' for details.
|
under certain conditions; type `show c' for details.
|
17
README.md
17
README.md
|
@ -3,13 +3,14 @@ TES3MP
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/TES3MP/openmw-tes3mp.svg?branch=master)](https://travis-ci.org/TES3MP/openmw-tes3mp)
|
[![Build Status](https://travis-ci.org/TES3MP/openmw-tes3mp.svg?branch=master)](https://travis-ci.org/TES3MP/openmw-tes3mp)
|
||||||
|
|
||||||
TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), a free and open source recreation of the popular Bethesda Softworks game "The Elder Scrolls III: Morrowind".
|
TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), a free and open source engine recreation of the popular Bethesda Softworks game "The Elder Scrolls III: Morrowind".
|
||||||
|
|
||||||
* Version: 0.6.2
|
* TES3MP version: 0.6.2
|
||||||
* License: GPLv3 (see docs/license/GPL3.txt for more information)
|
* OpenMW version: 0.43.0
|
||||||
|
* License: GPLv3 (see [LICENSE](https://github.com/TES3MP/openmw-tes3mp/blob/master/LICENSE) for more information)
|
||||||
|
|
||||||
Font Licenses:
|
Font Licenses:
|
||||||
* DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information)
|
* DejaVuLGCSansMono.ttf: custom (see [files/mygui/DejaVu Font License.txt](https://github.com/TES3MP/openmw-tes3mp/blob/master/files/mygui/DejaVu%20Font%20License.txt) for more information)
|
||||||
|
|
||||||
Project Status
|
Project Status
|
||||||
--------------
|
--------------
|
||||||
|
@ -18,24 +19,24 @@ Project Status
|
||||||
|
|
||||||
TES3MP is now playable in most respects. Player and NPC movement, animations, combat and spell casting are properly synchronized with small exceptions, as is picking up and dropping items in the world, using doors and levers, and adding and removing items from containers. Journal entries, faction stats and dialogue topics are also synchronized, allowing the majority of quests to work fine.
|
TES3MP is now playable in most respects. Player and NPC movement, animations, combat and spell casting are properly synchronized with small exceptions, as is picking up and dropping items in the world, using doors and levers, and adding and removing items from containers. Journal entries, faction stats and dialogue topics are also synchronized, allowing the majority of quests to work fine.
|
||||||
|
|
||||||
[Serverside Lua scripts](https://github.com/TES3MP/PluginExamples) are used to save and load the state of most of the aforementioned.
|
[Serverside Lua scripts](https://github.com/TES3MP/CoreScripts) are used to save and load the state of most of the aforementioned.
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Development has been relatively fast, but any contribution regarding [code](https://github.com/TES3MP/openmw-tes3mp/blob/master/CONTRIBUTING.md), documentation, bug hunting or video showcases is greatly appreciated.
|
Development has been relatively fast, but any contribution regarding [code](https://github.com/TES3MP/openmw-tes3mp/blob/master/CONTRIBUTING.md), documentation, bug hunting or video showcases is greatly appreciated.
|
||||||
|
|
||||||
Test sessions are often advertised in [our Steam group](https://steamcommunity.com/groups/mwmulti) or [our Discord server](https://discord.gg/H8zhhuk).
|
Test sessions are often advertised on [our Discord server](https://discord.gg/ECJk293) or in [our Steam group](https://steamcommunity.com/groups/mwmulti).
|
||||||
|
|
||||||
Feel free to contact the [team members](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-credits.md) for any questions you might have.
|
Feel free to contact the [team members](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-credits.md) for any questions you might have.
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
* [Quickstart guide](https://github.com/TES3MP/openmw-tes3mp/wiki/Quickstart-guide)
|
||||||
|
* [Steam group](https://steamcommunity.com/groups/mwmulti) and its [detailed FAQ](http://steamcommunity.com/groups/mwmulti/discussions/1/353916184342480541/)
|
||||||
* [TES3MP section on OpenMW forums](https://forum.openmw.org/viewforum.php?f=44)
|
* [TES3MP section on OpenMW forums](https://forum.openmw.org/viewforum.php?f=44)
|
||||||
* [Steam group](https://steamcommunity.com/groups/mwmulti)
|
|
||||||
* [Subreddit](https://www.reddit.com/r/tes3mp)
|
* [Subreddit](https://www.reddit.com/r/tes3mp)
|
||||||
* [Installation and build instructions](https://github.com/TES3MP/openmw-tes3mp/wiki/Installation-and-build-instructions)
|
|
||||||
* [Known issues and bug reports](https://github.com/TES3MP/openmw-tes3mp/issues)
|
* [Known issues and bug reports](https://github.com/TES3MP/openmw-tes3mp/issues)
|
||||||
|
|
||||||
Donations
|
Donations
|
||||||
|
|
|
@ -4,7 +4,7 @@ set(BSATOOL
|
||||||
source_group(apps\\bsatool FILES ${BSATOOL})
|
source_group(apps\\bsatool FILES ${BSATOOL})
|
||||||
|
|
||||||
# Main executable
|
# Main executable
|
||||||
add_executable(bsatool
|
openmw_add_executable(bsatool
|
||||||
${BSATOOL}
|
${BSATOOL}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ set(ESMTOOL
|
||||||
source_group(apps\\esmtool FILES ${ESMTOOL})
|
source_group(apps\\esmtool FILES ${ESMTOOL})
|
||||||
|
|
||||||
# Main executable
|
# Main executable
|
||||||
add_executable(esmtool
|
openmw_add_executable(esmtool
|
||||||
${ESMTOOL}
|
${ESMTOOL}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@ set(ESSIMPORTER_FILES
|
||||||
importjour.cpp
|
importjour.cpp
|
||||||
importscri.cpp
|
importscri.cpp
|
||||||
importscpt.cpp
|
importscpt.cpp
|
||||||
|
importproj.cpp
|
||||||
|
importsplm.cpp
|
||||||
importercontext.cpp
|
importercontext.cpp
|
||||||
converter.cpp
|
converter.cpp
|
||||||
convertacdt.cpp
|
convertacdt.cpp
|
||||||
|
@ -28,7 +30,7 @@ set(ESSIMPORTER_FILES
|
||||||
convertplayer.cpp
|
convertplayer.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(openmw-essimporter
|
openmw_add_executable(openmw-essimporter
|
||||||
${ESSIMPORTER_FILES}
|
${ESSIMPORTER_FILES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "converter.hpp"
|
#include "converter.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <osgDB/WriteFile>
|
#include <osgDB/WriteFile>
|
||||||
|
|
||||||
|
@ -53,6 +54,36 @@ namespace
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void splitIndexedRefId(const std::string& indexedRefId, int& refIndex, std::string& refId)
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << std::hex << indexedRefId.substr(indexedRefId.size()-8,8);
|
||||||
|
stream >> refIndex;
|
||||||
|
|
||||||
|
refId = indexedRefId.substr(0,indexedRefId.size()-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int convertActorId(const std::string& indexedRefId, ESSImport::Context& context)
|
||||||
|
{
|
||||||
|
if (isIndexedRefId(indexedRefId))
|
||||||
|
{
|
||||||
|
int refIndex;
|
||||||
|
std::string refId;
|
||||||
|
splitIndexedRefId(indexedRefId, refIndex, refId);
|
||||||
|
|
||||||
|
auto it = context.mActorIdMap.find(std::make_pair(refIndex, refId));
|
||||||
|
if (it == context.mActorIdMap.end())
|
||||||
|
return -1;
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
else if (indexedRefId == "PlayerSaveGame")
|
||||||
|
{
|
||||||
|
return context.mPlayer.mObject.mCreatureStats.mActorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ESSImport
|
namespace ESSImport
|
||||||
|
@ -322,12 +353,9 @@ namespace ESSImport
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::stringstream stream;
|
|
||||||
stream << std::hex << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8);
|
|
||||||
int refIndex;
|
int refIndex;
|
||||||
stream >> refIndex;
|
splitIndexedRefId(cellref.mIndexedRefId, refIndex, out.mRefID);
|
||||||
|
|
||||||
out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8);
|
|
||||||
std::string idLower = Misc::StringUtils::lowerCase(out.mRefID);
|
std::string idLower = Misc::StringUtils::lowerCase(out.mRefID);
|
||||||
|
|
||||||
std::map<std::pair<int, std::string>, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find(
|
std::map<std::pair<int, std::string>, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find(
|
||||||
|
@ -347,6 +375,10 @@ namespace ESSImport
|
||||||
convertNpcData(cellref, objstate.mNpcStats);
|
convertNpcData(cellref, objstate.mNpcStats);
|
||||||
convertNPCC(npccIt->second, objstate);
|
convertNPCC(npccIt->second, objstate);
|
||||||
convertCellRef(cellref, objstate);
|
convertCellRef(cellref, objstate);
|
||||||
|
|
||||||
|
objstate.mCreatureStats.mActorId = mContext->generateActorId();
|
||||||
|
mContext->mActorIdMap.insert(std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId));
|
||||||
|
|
||||||
esm.writeHNT ("OBJE", ESM::REC_NPC_);
|
esm.writeHNT ("OBJE", ESM::REC_NPC_);
|
||||||
objstate.save(esm);
|
objstate.save(esm);
|
||||||
continue;
|
continue;
|
||||||
|
@ -383,6 +415,10 @@ namespace ESSImport
|
||||||
convertACSC(cellref.mACSC, objstate.mCreatureStats);
|
convertACSC(cellref.mACSC, objstate.mCreatureStats);
|
||||||
convertCREC(crecIt->second, objstate);
|
convertCREC(crecIt->second, objstate);
|
||||||
convertCellRef(cellref, objstate);
|
convertCellRef(cellref, objstate);
|
||||||
|
|
||||||
|
objstate.mCreatureStats.mActorId = mContext->generateActorId();
|
||||||
|
mContext->mActorIdMap.insert(std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId));
|
||||||
|
|
||||||
esm.writeHNT ("OBJE", ESM::REC_CREA);
|
esm.writeHNT ("OBJE", ESM::REC_CREA);
|
||||||
objstate.save(esm);
|
objstate.save(esm);
|
||||||
continue;
|
continue;
|
||||||
|
@ -413,4 +449,73 @@ namespace ESSImport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConvertPROJ::read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
mProj.load(esm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertPROJ::write(ESM::ESMWriter& esm)
|
||||||
|
{
|
||||||
|
for (const PROJ::PNAM& pnam : mProj.mProjectiles)
|
||||||
|
{
|
||||||
|
if (!pnam.isMagic())
|
||||||
|
{
|
||||||
|
ESM::ProjectileState out;
|
||||||
|
convertBaseState(out, pnam);
|
||||||
|
|
||||||
|
out.mBowId = pnam.mBowId.toString();
|
||||||
|
out.mVelocity = pnam.mVelocity;
|
||||||
|
out.mAttackStrength = pnam.mAttackStrength;
|
||||||
|
|
||||||
|
esm.startRecord(ESM::REC_PROJ);
|
||||||
|
out.save(esm);
|
||||||
|
esm.endRecord(ESM::REC_PROJ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESM::MagicBoltState out;
|
||||||
|
convertBaseState(out, pnam);
|
||||||
|
|
||||||
|
auto it = std::find_if(mContext->mActiveSpells.begin(), mContext->mActiveSpells.end(),
|
||||||
|
[&pnam](const SPLM::ActiveSpell& spell) -> bool { return spell.mIndex == pnam.mSplmIndex; });
|
||||||
|
|
||||||
|
if (it == mContext->mActiveSpells.end())
|
||||||
|
{
|
||||||
|
std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (invalid spell link)" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.mSpellId = it->mSPDT.mId.toString();
|
||||||
|
out.mSpeed = pnam.mSpeed * 0.001f; // not sure where this factor comes from
|
||||||
|
|
||||||
|
esm.startRecord(ESM::REC_MPRJ);
|
||||||
|
out.save(esm);
|
||||||
|
esm.endRecord(ESM::REC_MPRJ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertPROJ::convertBaseState(ESM::BaseProjectileState& base, const PROJ::PNAM& pnam)
|
||||||
|
{
|
||||||
|
base.mId = pnam.mArrowId.toString();
|
||||||
|
base.mPosition = pnam.mPosition;
|
||||||
|
|
||||||
|
osg::Quat orient;
|
||||||
|
orient.makeRotate(osg::Vec3f(0,1,0), pnam.mVelocity);
|
||||||
|
base.mOrientation = orient;
|
||||||
|
|
||||||
|
base.mActorId = convertActorId(pnam.mActorId.toString(), *mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertSPLM::read(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
mSPLM.load(esm);
|
||||||
|
mContext->mActiveSpells = mSPLM.mActiveSpells;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertSPLM::write(ESM::ESMWriter& esm)
|
||||||
|
{
|
||||||
|
std::cerr << "Warning: Skipped active spell conversion (not implemented)" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <components/esm/globalscript.hpp>
|
#include <components/esm/globalscript.hpp>
|
||||||
#include <components/esm/queststate.hpp>
|
#include <components/esm/queststate.hpp>
|
||||||
#include <components/esm/stolenitems.hpp>
|
#include <components/esm/stolenitems.hpp>
|
||||||
|
#include <components/esm/projectilestate.hpp>
|
||||||
|
|
||||||
#include "importcrec.hpp"
|
#include "importcrec.hpp"
|
||||||
#include "importcntc.hpp"
|
#include "importcntc.hpp"
|
||||||
|
@ -35,6 +36,8 @@
|
||||||
#include "importques.hpp"
|
#include "importques.hpp"
|
||||||
#include "importjour.hpp"
|
#include "importjour.hpp"
|
||||||
#include "importscpt.hpp"
|
#include "importscpt.hpp"
|
||||||
|
#include "importproj.h"
|
||||||
|
#include "importsplm.h"
|
||||||
|
|
||||||
#include "convertacdt.hpp"
|
#include "convertacdt.hpp"
|
||||||
#include "convertnpcc.hpp"
|
#include "convertnpcc.hpp"
|
||||||
|
@ -593,6 +596,27 @@ private:
|
||||||
std::vector<ESM::GlobalScript> mScripts;
|
std::vector<ESM::GlobalScript> mScripts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Projectile converter
|
||||||
|
class ConvertPROJ : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual int getStage() override { return 2; }
|
||||||
|
virtual void read(ESM::ESMReader& esm) override;
|
||||||
|
virtual void write(ESM::ESMWriter& esm) override;
|
||||||
|
private:
|
||||||
|
void convertBaseState(ESM::BaseProjectileState& base, const PROJ::PNAM& pnam);
|
||||||
|
PROJ mProj;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertSPLM : public Converter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void read(ESM::ESMReader& esm) override;
|
||||||
|
virtual void write(ESM::ESMWriter& esm) override;
|
||||||
|
private:
|
||||||
|
SPLM mSPLM;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -271,6 +271,7 @@ namespace ESSImport
|
||||||
const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value;
|
const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value;
|
||||||
const unsigned int recGAME = ESM::FourCC<'G','A','M','E'>::value;
|
const unsigned int recGAME = ESM::FourCC<'G','A','M','E'>::value;
|
||||||
const unsigned int recJOUR = ESM::FourCC<'J','O','U','R'>::value;
|
const unsigned int recJOUR = ESM::FourCC<'J','O','U','R'>::value;
|
||||||
|
const unsigned int recSPLM = ESM::FourCC<'S','P','L','M'>::value;
|
||||||
|
|
||||||
std::map<unsigned int, std::shared_ptr<Converter> > converters;
|
std::map<unsigned int, std::shared_ptr<Converter> > converters;
|
||||||
converters[ESM::REC_GLOB] = std::shared_ptr<Converter>(new ConvertGlobal());
|
converters[ESM::REC_GLOB] = std::shared_ptr<Converter>(new ConvertGlobal());
|
||||||
|
@ -303,12 +304,13 @@ namespace ESSImport
|
||||||
converters[ESM::REC_QUES] = std::shared_ptr<Converter>(new ConvertQUES());
|
converters[ESM::REC_QUES] = std::shared_ptr<Converter>(new ConvertQUES());
|
||||||
converters[recJOUR ] = std::shared_ptr<Converter>(new ConvertJOUR());
|
converters[recJOUR ] = std::shared_ptr<Converter>(new ConvertJOUR());
|
||||||
converters[ESM::REC_SCPT] = std::shared_ptr<Converter>(new ConvertSCPT());
|
converters[ESM::REC_SCPT] = std::shared_ptr<Converter>(new ConvertSCPT());
|
||||||
|
converters[ESM::REC_PROJ] = std::shared_ptr<Converter>(new ConvertPROJ());
|
||||||
|
converters[recSPLM] = std::shared_ptr<Converter>(new ConvertSPLM());
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - REGN (weather in certain regions?)
|
// - REGN (weather in certain regions?)
|
||||||
// - VFXM
|
// - VFXM
|
||||||
// - SPLM (active spell effects)
|
// - SPLM (active spell effects)
|
||||||
// - PROJ (magic projectiles in air)
|
|
||||||
|
|
||||||
std::set<unsigned int> unknownRecords;
|
std::set<unsigned int> unknownRecords;
|
||||||
|
|
||||||
|
@ -420,6 +422,19 @@ namespace ESSImport
|
||||||
context.mPlayer.save(writer);
|
context.mPlayer.save(writer);
|
||||||
writer.endRecord(ESM::REC_PLAY);
|
writer.endRecord(ESM::REC_PLAY);
|
||||||
|
|
||||||
|
writer.startRecord(ESM::REC_ACTC);
|
||||||
|
writer.writeHNT("COUN", context.mNextActorId);
|
||||||
|
writer.endRecord(ESM::REC_ACTC);
|
||||||
|
|
||||||
|
// Stage 2 requires cell references to be written / actors IDs assigned
|
||||||
|
for (std::map<unsigned int, std::shared_ptr<Converter> >::const_iterator it = converters.begin();
|
||||||
|
it != converters.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->second->getStage() != 2)
|
||||||
|
continue;
|
||||||
|
it->second->write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
writer.startRecord (ESM::REC_DIAS);
|
writer.startRecord (ESM::REC_DIAS);
|
||||||
context.mDialogueState.save(writer);
|
context.mDialogueState.save(writer);
|
||||||
writer.endRecord(ESM::REC_DIAS);
|
writer.endRecord(ESM::REC_DIAS);
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include "importcrec.hpp"
|
#include "importcrec.hpp"
|
||||||
#include "importcntc.hpp"
|
#include "importcntc.hpp"
|
||||||
#include "importplayer.hpp"
|
#include "importplayer.hpp"
|
||||||
|
#include "importsplm.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,14 +48,20 @@ namespace ESSImport
|
||||||
std::map<std::pair<int, std::string>, NPCC> mNpcChanges;
|
std::map<std::pair<int, std::string>, NPCC> mNpcChanges;
|
||||||
std::map<std::pair<int, std::string>, CNTC> mContainerChanges;
|
std::map<std::pair<int, std::string>, CNTC> mContainerChanges;
|
||||||
|
|
||||||
|
std::map<std::pair<int, std::string>, int> mActorIdMap;
|
||||||
|
int mNextActorId;
|
||||||
|
|
||||||
std::map<std::string, ESM::Creature> mCreatures;
|
std::map<std::string, ESM::Creature> mCreatures;
|
||||||
std::map<std::string, ESM::NPC> mNpcs;
|
std::map<std::string, ESM::NPC> mNpcs;
|
||||||
|
|
||||||
|
std::vector<SPLM::ActiveSpell> mActiveSpells;
|
||||||
|
|
||||||
Context()
|
Context()
|
||||||
: mDay(0)
|
: mDay(0)
|
||||||
, mMonth(0)
|
, mMonth(0)
|
||||||
, mYear(0)
|
, mYear(0)
|
||||||
, mHour(0.f)
|
, mHour(0.f)
|
||||||
|
, mNextActorId(0)
|
||||||
{
|
{
|
||||||
mPlayer.mAutoMove = 0;
|
mPlayer.mAutoMove = 0;
|
||||||
ESM::CellId playerCellId;
|
ESM::CellId playerCellId;
|
||||||
|
@ -67,16 +73,23 @@ namespace ESSImport
|
||||||
= mPlayer.mLastKnownExteriorPosition[2]
|
= mPlayer.mLastKnownExteriorPosition[2]
|
||||||
= 0.0f;
|
= 0.0f;
|
||||||
mPlayer.mHasMark = 0;
|
mPlayer.mHasMark = 0;
|
||||||
mPlayer.mCurrentCrimeId = 0; // TODO
|
mPlayer.mCurrentCrimeId = -1; // TODO
|
||||||
|
mPlayer.mPaidCrimeId = -1;
|
||||||
mPlayer.mObject.blank();
|
mPlayer.mObject.blank();
|
||||||
mPlayer.mObject.mEnabled = true;
|
mPlayer.mObject.mEnabled = true;
|
||||||
mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame
|
mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame
|
||||||
|
mPlayer.mObject.mCreatureStats.mActorId = generateActorId();
|
||||||
|
|
||||||
mGlobalMapState.mBounds.mMinX = 0;
|
mGlobalMapState.mBounds.mMinX = 0;
|
||||||
mGlobalMapState.mBounds.mMaxX = 0;
|
mGlobalMapState.mBounds.mMaxX = 0;
|
||||||
mGlobalMapState.mBounds.mMinY = 0;
|
mGlobalMapState.mBounds.mMinY = 0;
|
||||||
mGlobalMapState.mBounds.mMaxY = 0;
|
mGlobalMapState.mBounds.mMaxY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int generateActorId()
|
||||||
|
{
|
||||||
|
return mNextActorId++;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
18
apps/essimporter/importproj.cpp
Normal file
18
apps/essimporter/importproj.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "importproj.h"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void ESSImport::PROJ::load(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
while (esm.isNextSub("PNAM"))
|
||||||
|
{
|
||||||
|
PNAM pnam;
|
||||||
|
esm.getHT(pnam);
|
||||||
|
mProjectiles.push_back(pnam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
47
apps/essimporter/importproj.h
Normal file
47
apps/essimporter/importproj.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTPROJ_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTPROJ_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <components/esm/esmcommon.hpp>
|
||||||
|
#include <components/esm/util.hpp>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
struct PROJ
|
||||||
|
{
|
||||||
|
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
struct PNAM // 184 bytes
|
||||||
|
{
|
||||||
|
float mAttackStrength;
|
||||||
|
float mSpeed;
|
||||||
|
unsigned char mUnknown[4*2];
|
||||||
|
float mFlightTime;
|
||||||
|
int mSplmIndex; // reference to a SPLM record (0 for ballistic projectiles)
|
||||||
|
unsigned char mUnknown2[4];
|
||||||
|
ESM::Vector3 mVelocity;
|
||||||
|
ESM::Vector3 mPosition;
|
||||||
|
unsigned char mUnknown3[4*9];
|
||||||
|
ESM::NAME32 mActorId; // indexed refID (with the exception of "PlayerSaveGame")
|
||||||
|
ESM::NAME32 mArrowId;
|
||||||
|
ESM::NAME32 mBowId;
|
||||||
|
|
||||||
|
bool isMagic() const { return mSplmIndex != 0; }
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
std::vector<PNAM> mProjectiles;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
43
apps/essimporter/importsplm.cpp
Normal file
43
apps/essimporter/importsplm.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include "importsplm.h"
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
void SPLM::load(ESM::ESMReader& esm)
|
||||||
|
{
|
||||||
|
while (esm.isNextSub("NAME"))
|
||||||
|
{
|
||||||
|
ActiveSpell spell;
|
||||||
|
esm.getHT(spell.mIndex);
|
||||||
|
esm.getHNT(spell.mSPDT, "SPDT");
|
||||||
|
spell.mTarget = esm.getHNOString("TNAM");
|
||||||
|
|
||||||
|
while (esm.isNextSub("NPDT"))
|
||||||
|
{
|
||||||
|
ActiveEffect effect;
|
||||||
|
esm.getHT(effect.mNPDT);
|
||||||
|
|
||||||
|
// Effect-specific subrecords can follow:
|
||||||
|
// - INAM for disintegration and bound effects
|
||||||
|
// - CNAM for summoning and command effects
|
||||||
|
// - VNAM for vampirism
|
||||||
|
// NOTE: There can be multiple INAMs per effect.
|
||||||
|
// TODO: Needs more research.
|
||||||
|
|
||||||
|
esm.skipHSubUntil("NAM0"); // sentinel
|
||||||
|
esm.getSubName();
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
|
spell.mActiveEffects.push_back(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char xnam; // sentinel
|
||||||
|
esm.getHNT(xnam, "XNAM");
|
||||||
|
|
||||||
|
mActiveSpells.push_back(spell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
81
apps/essimporter/importsplm.h
Normal file
81
apps/essimporter/importsplm.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#ifndef OPENMW_ESSIMPORT_IMPORTSPLM_H
|
||||||
|
#define OPENMW_ESSIMPORT_IMPORTSPLM_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <components/esm/esmcommon.hpp>
|
||||||
|
#include <components/esm/util.hpp>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESSImport
|
||||||
|
{
|
||||||
|
|
||||||
|
struct SPLM
|
||||||
|
{
|
||||||
|
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
struct SPDT // 160 bytes
|
||||||
|
{
|
||||||
|
int mType; // 1 = spell, 2 = enchantment, 3 = potion
|
||||||
|
ESM::NAME32 mId; // base ID of a spell/enchantment/potion
|
||||||
|
unsigned char mUnknown[4*4];
|
||||||
|
ESM::NAME32 mCasterId;
|
||||||
|
ESM::NAME32 mSourceId; // empty for spells
|
||||||
|
unsigned char mUnknown2[4*11];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NPDT // 56 bytes
|
||||||
|
{
|
||||||
|
ESM::NAME32 mAffectedActorId;
|
||||||
|
unsigned char mUnknown[4*2];
|
||||||
|
int mMagnitude;
|
||||||
|
float mSecondsActive;
|
||||||
|
unsigned char mUnknown2[4*2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct INAM // 40 bytes
|
||||||
|
{
|
||||||
|
int mUnknown;
|
||||||
|
unsigned char mUnknown2;
|
||||||
|
ESM::FIXED_STRING<35> mItemId; // disintegrated item / bound item / item to re-equip after expiration
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CNAM // 36 bytes
|
||||||
|
{
|
||||||
|
int mUnknown; // seems to always be 0
|
||||||
|
ESM::NAME32 mSummonedOrCommandedActor[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VNAM // 4 bytes
|
||||||
|
{
|
||||||
|
int mUnknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
struct ActiveEffect
|
||||||
|
{
|
||||||
|
NPDT mNPDT;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ActiveSpell
|
||||||
|
{
|
||||||
|
int mIndex;
|
||||||
|
SPDT mSPDT;
|
||||||
|
std::string mTarget;
|
||||||
|
std::vector<ActiveEffect> mActiveEffects;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<ActiveSpell> mActiveSpells;
|
||||||
|
|
||||||
|
void load(ESM::ESMReader& esm);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -78,7 +78,7 @@ if(NOT WIN32)
|
||||||
endif(NOT WIN32)
|
endif(NOT WIN32)
|
||||||
|
|
||||||
# Main executable
|
# Main executable
|
||||||
add_executable(openmw-launcher
|
openmw_add_executable(openmw-launcher
|
||||||
${GUI_TYPE}
|
${GUI_TYPE}
|
||||||
${LAUNCHER}
|
${LAUNCHER}
|
||||||
${LAUNCHER_HEADER}
|
${LAUNCHER_HEADER}
|
||||||
|
|
|
@ -9,7 +9,7 @@ set(MWINIIMPORT_HEADER
|
||||||
|
|
||||||
source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER})
|
source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER})
|
||||||
|
|
||||||
add_executable(openmw-iniimporter
|
openmw_add_executable(openmw-iniimporter
|
||||||
${MWINIIMPORT}
|
${MWINIIMPORT}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ set(NIFTEST
|
||||||
source_group(components\\nif\\tests FILES ${NIFTEST})
|
source_group(components\\nif\\tests FILES ${NIFTEST})
|
||||||
|
|
||||||
# Main executable
|
# Main executable
|
||||||
add_executable(niftest
|
openmw_add_executable(niftest
|
||||||
${NIFTEST}
|
${NIFTEST}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc
|
||||||
|
|
||||||
|
|
||||||
opencs_units (model/world
|
opencs_units (model/world
|
||||||
idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel
|
idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel landtexturetableproxymodel
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ opencs_units (view/world
|
||||||
cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview
|
cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview
|
||||||
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
||||||
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
|
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
|
||||||
bodypartcreator
|
bodypartcreator landtexturecreator landcreator
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/world
|
opencs_units_noqt (view/world
|
||||||
|
@ -174,7 +174,7 @@ else()
|
||||||
set (OPENCS_OPENMW_CFG "")
|
set (OPENCS_OPENMW_CFG "")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
add_executable(openmw-cs
|
openmw_add_executable(openmw-cs
|
||||||
MACOSX_BUNDLE
|
MACOSX_BUNDLE
|
||||||
${OPENCS_SRC}
|
${OPENCS_SRC}
|
||||||
${OPENCS_UI_HDR}
|
${OPENCS_UI_HDR}
|
||||||
|
@ -252,7 +252,8 @@ endif()
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY})
|
target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY})
|
||||||
INSTALL(TARGETS openmw-cs RUNTIME DESTINATION ".")
|
INSTALL(TARGETS openmw-cs RUNTIME DESTINATION ".")
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/openmw-cs.cfg" DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/openmw-cs.cfg" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
|
|
@ -90,16 +90,16 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
|
||||||
boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options");
|
boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options");
|
||||||
|
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken()->composing())
|
("data", boost::program_options::value<Files::EscapePathContainer>()->default_value(Files::EscapePathContainer(), "data")->multitoken()->composing())
|
||||||
("data-local", boost::program_options::value<std::string>()->default_value(""))
|
("data-local", boost::program_options::value<Files::EscapeHashString>()->default_value(""))
|
||||||
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
|
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
|
||||||
("encoding", boost::program_options::value<std::string>()->default_value("win1252"))
|
("encoding", boost::program_options::value<Files::EscapeHashString>()->default_value("win1252"))
|
||||||
("resources", boost::program_options::value<std::string>()->default_value("resources"))
|
("resources", boost::program_options::value<Files::EscapeHashString>()->default_value("resources"))
|
||||||
("fallback-archive", boost::program_options::value<std::vector<std::string> >()->
|
("fallback-archive", boost::program_options::value<Files::EscapeStringVector>()->
|
||||||
default_value(std::vector<std::string>(), "fallback-archive")->multitoken())
|
default_value(Files::EscapeStringVector(), "fallback-archive")->multitoken())
|
||||||
("fallback", boost::program_options::value<FallbackMap>()->default_value(FallbackMap(), "")
|
("fallback", boost::program_options::value<FallbackMap>()->default_value(FallbackMap(), "")
|
||||||
->multitoken()->composing(), "fallback values")
|
->multitoken()->composing(), "fallback values")
|
||||||
("script-blacklist", boost::program_options::value<std::vector<std::string> >()->default_value(std::vector<std::string>(), "")
|
("script-blacklist", boost::program_options::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "")
|
||||||
->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)")
|
->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)")
|
||||||
("script-blacklist-use", boost::program_options::value<bool>()->implicit_value(true)
|
("script-blacklist-use", boost::program_options::value<bool>()->implicit_value(true)
|
||||||
->default_value(true), "enable script blacklisting");
|
->default_value(true), "enable script blacklisting");
|
||||||
|
@ -109,25 +109,29 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
|
||||||
mCfgMgr.readConfiguration(variables, desc, quiet);
|
mCfgMgr.readConfiguration(variables, desc, quiet);
|
||||||
|
|
||||||
mDocumentManager.setEncoding (
|
mDocumentManager.setEncoding (
|
||||||
ToUTF8::calculateEncoding (variables["encoding"].as<std::string>()));
|
ToUTF8::calculateEncoding (variables["encoding"].as<Files::EscapeHashString>().toStdString()));
|
||||||
|
|
||||||
mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>());
|
mDocumentManager.setResourceDir (mResources = variables["resources"].as<Files::EscapeHashString>().toStdString());
|
||||||
|
|
||||||
mDocumentManager.setFallbackMap (variables["fallback"].as<FallbackMap>().mMap);
|
mDocumentManager.setFallbackMap (variables["fallback"].as<FallbackMap>().mMap);
|
||||||
|
|
||||||
if (variables["script-blacklist-use"].as<bool>())
|
if (variables["script-blacklist-use"].as<bool>())
|
||||||
mDocumentManager.setBlacklistedScripts (
|
mDocumentManager.setBlacklistedScripts (
|
||||||
variables["script-blacklist"].as<std::vector<std::string> >());
|
variables["script-blacklist"].as<Files::EscapeStringVector>().toStdStringVector());
|
||||||
|
|
||||||
mFsStrict = variables["fs-strict"].as<bool>();
|
mFsStrict = variables["fs-strict"].as<bool>();
|
||||||
|
|
||||||
Files::PathContainer dataDirs, dataLocal;
|
Files::PathContainer dataDirs, dataLocal;
|
||||||
if (!variables["data"].empty()) {
|
if (!variables["data"].empty()) {
|
||||||
dataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
|
dataDirs = Files::PathContainer(Files::EscapePath::toPathContainer(variables["data"].as<Files::EscapePathContainer>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string local = variables["data-local"].as<std::string>();
|
std::string local = variables["data-local"].as<Files::EscapeHashString>().toStdString();
|
||||||
if (!local.empty()) {
|
if (!local.empty())
|
||||||
|
{
|
||||||
|
if (local.front() == '\"')
|
||||||
|
local = local.substr(1, local.length() - 2);
|
||||||
|
|
||||||
dataLocal.push_back(Files::PathContainer::value_type(local));
|
dataLocal.push_back(Files::PathContainer::value_type(local));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +161,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
|
||||||
mFileDialog.addFiles(path);
|
mFileDialog.addFiles(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair (dataDirs, variables["fallback-archive"].as<std::vector<std::string> >());
|
return std::make_pair (dataDirs, variables["fallback-archive"].as<Files::EscapeStringVector>().toStdStringVector());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CS::Editor::createGame()
|
void CS::Editor::createGame()
|
||||||
|
|
|
@ -288,7 +288,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
||||||
if (mContentFiles.empty())
|
if (mContentFiles.empty())
|
||||||
throw std::runtime_error ("Empty content file sequence");
|
throw std::runtime_error ("Empty content file sequence");
|
||||||
|
|
||||||
if (!boost::filesystem::exists (mProjectPath))
|
if (mNew || !boost::filesystem::exists (mProjectPath))
|
||||||
{
|
{
|
||||||
boost::filesystem::path customFiltersPath (configuration.getUserDataPath());
|
boost::filesystem::path customFiltersPath (configuration.getUserDataPath());
|
||||||
customFiltersPath /= "defaultfilters";
|
customFiltersPath /= "defaultfilters";
|
||||||
|
|
|
@ -132,7 +132,7 @@ namespace CSMPrefs
|
||||||
if (mods && i == 0)
|
if (mods && i == 0)
|
||||||
{
|
{
|
||||||
if (mods & Qt::ControlModifier)
|
if (mods & Qt::ControlModifier)
|
||||||
result.append("Ctl+");
|
result.append("Ctrl+");
|
||||||
if (mods & Qt::ShiftModifier)
|
if (mods & Qt::ShiftModifier)
|
||||||
result.append("Shift+");
|
result.append("Shift+");
|
||||||
if (mods & Qt::AltModifier)
|
if (mods & Qt::AltModifier)
|
||||||
|
@ -196,7 +196,7 @@ namespace CSMPrefs
|
||||||
|
|
||||||
std::string name = value.substr(start, end - start);
|
std::string name = value.substr(start, end - start);
|
||||||
|
|
||||||
if (name == "Ctl")
|
if (name == "Ctrl")
|
||||||
{
|
{
|
||||||
mods |= Qt::ControlModifier;
|
mods |= Qt::ControlModifier;
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,18 +169,25 @@ void CSMPrefs::State::declare()
|
||||||
"list go to the first/last item");
|
"list go to the first/last item");
|
||||||
|
|
||||||
declareCategory ("3D Scene Input");
|
declareCategory ("3D Scene Input");
|
||||||
|
|
||||||
|
declareDouble ("navi-wheel-factor", "Camera Zoom Sensitivity", 8).setRange(-100.0, 100.0);
|
||||||
|
declareDouble ("s-navi-sensitivity", "Secondary Camera Movement Sensitivity", 50.0).setRange(-1000.0, 1000.0);
|
||||||
|
declareSeparator();
|
||||||
|
|
||||||
declareDouble ("p-navi-free-sensitivity", "Free Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0);
|
declareDouble ("p-navi-free-sensitivity", "Free Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0);
|
||||||
declareBool ("p-navi-free-invert", "Invert Free Camera Mouse Input", false);
|
declareBool ("p-navi-free-invert", "Invert Free Camera Mouse Input", false);
|
||||||
declareDouble ("p-navi-orbit-sensitivity", "Orbit Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0);
|
|
||||||
declareBool ("p-navi-orbit-invert", "Invert Orbit Camera Mouse Input", false);
|
|
||||||
declareDouble ("s-navi-sensitivity", "Secondary Camera Movement Sensitivity", 50.0).setRange(-1000.0, 1000.0);
|
|
||||||
declareDouble ("navi-wheel-factor", "Camera Zoom Sensitivity", 8).setRange(-100.0, 100.0);
|
|
||||||
declareDouble ("navi-free-lin-speed", "Free Camera Linear Speed", 1000.0).setRange(1.0, 10000.0);
|
declareDouble ("navi-free-lin-speed", "Free Camera Linear Speed", 1000.0).setRange(1.0, 10000.0);
|
||||||
declareDouble ("navi-free-rot-speed", "Free Camera Rotational Speed", 3.14 / 2).setRange(0.001, 6.28);
|
declareDouble ("navi-free-rot-speed", "Free Camera Rotational Speed", 3.14 / 2).setRange(0.001, 6.28);
|
||||||
declareDouble ("navi-free-speed-mult", "Free Camera Speed Multiplier (from Modifier)", 8).setRange(0.001, 1000.0);
|
declareDouble ("navi-free-speed-mult", "Free Camera Speed Multiplier (from Modifier)", 8).setRange(0.001, 1000.0);
|
||||||
|
declareSeparator();
|
||||||
|
|
||||||
|
declareDouble ("p-navi-orbit-sensitivity", "Orbit Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0);
|
||||||
|
declareBool ("p-navi-orbit-invert", "Invert Orbit Camera Mouse Input", false);
|
||||||
declareDouble ("navi-orbit-rot-speed", "Orbital Camera Rotational Speed", 3.14 / 4).setRange(0.001, 6.28);
|
declareDouble ("navi-orbit-rot-speed", "Orbital Camera Rotational Speed", 3.14 / 4).setRange(0.001, 6.28);
|
||||||
declareDouble ("navi-orbit-speed-mult", "Orbital Camera Speed Multiplier (from Modifier)", 4).setRange(0.001, 1000.0);
|
declareDouble ("navi-orbit-speed-mult", "Orbital Camera Speed Multiplier (from Modifier)", 4).setRange(0.001, 1000.0);
|
||||||
|
declareBool ("navi-orbit-const-roll", "Keep camera roll constant for orbital camera", true);
|
||||||
declareSeparator();
|
declareSeparator();
|
||||||
|
|
||||||
declareBool ("context-select", "Context Sensitive Selection", false);
|
declareBool ("context-select", "Context Sensitive Selection", false);
|
||||||
declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0).
|
declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0).
|
||||||
setRange (0.001, 100.0);
|
setRange (0.001, 100.0);
|
||||||
|
@ -192,6 +199,14 @@ void CSMPrefs::State::declare()
|
||||||
setRange (0.001, 100.0);
|
setRange (0.001, 100.0);
|
||||||
declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1);
|
declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1);
|
||||||
|
|
||||||
|
declareCategory ("Rendering");
|
||||||
|
declareInt ("camera-fov", "Camera FOV", 90).setRange(10, 170);
|
||||||
|
declareBool ("camera-ortho", "Orthographic projection for camera", false);
|
||||||
|
declareInt ("camera-ortho-size", "Orthographic projection size parameter", 100).
|
||||||
|
setTooltip("Size of the orthographic frustum, greater value will allow the camera to see more of the world.").
|
||||||
|
setRange(10, 10000);
|
||||||
|
declareDouble ("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0,1);
|
||||||
|
|
||||||
declareCategory ("Tooltips");
|
declareCategory ("Tooltips");
|
||||||
declareBool ("scene", "Show Tooltips in 3D scenes", true);
|
declareBool ("scene", "Show Tooltips in 3D scenes", true);
|
||||||
declareBool ("scene-hide-basic", "Hide basic 3D scenes tooltips", false);
|
declareBool ("scene-hide-basic", "Hide basic 3D scenes tooltips", false);
|
||||||
|
@ -240,6 +255,8 @@ void CSMPrefs::State::declare()
|
||||||
declareShortcut ("document-world-cells", "Open Cell List", QKeySequence());
|
declareShortcut ("document-world-cells", "Open Cell List", QKeySequence());
|
||||||
declareShortcut ("document-world-referencables", "Open Object List", QKeySequence());
|
declareShortcut ("document-world-referencables", "Open Object List", QKeySequence());
|
||||||
declareShortcut ("document-world-references", "Open Instance List", QKeySequence());
|
declareShortcut ("document-world-references", "Open Instance List", QKeySequence());
|
||||||
|
declareShortcut ("document-world-lands", "Open Lands List", QKeySequence());
|
||||||
|
declareShortcut ("document-world-landtextures", "Open Land Textures List", QKeySequence());
|
||||||
declareShortcut ("document-world-pathgrid", "Open Pathgrid List", QKeySequence());
|
declareShortcut ("document-world-pathgrid", "Open Pathgrid List", QKeySequence());
|
||||||
declareShortcut ("document-world-regionmap", "Open Region Map", QKeySequence());
|
declareShortcut ("document-world-regionmap", "Open Region Map", QKeySequence());
|
||||||
declareShortcut ("document-mechanics-globals", "Open Global List", QKeySequence());
|
declareShortcut ("document-mechanics-globals", "Open Global List", QKeySequence());
|
||||||
|
@ -276,6 +293,7 @@ void CSMPrefs::State::declare()
|
||||||
declareShortcut ("table-edit", "Edit Record", QKeySequence());
|
declareShortcut ("table-edit", "Edit Record", QKeySequence());
|
||||||
declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A));
|
declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A));
|
||||||
declareShortcut ("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D));
|
declareShortcut ("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D));
|
||||||
|
declareShortcut ("touch-record", "Touch Record", QKeySequence());
|
||||||
declareShortcut ("table-revert", "Revert Record", QKeySequence());
|
declareShortcut ("table-revert", "Revert Record", QKeySequence());
|
||||||
declareShortcut ("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete));
|
declareShortcut ("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete));
|
||||||
declareShortcut ("table-moveup", "Move Record Up", QKeySequence());
|
declareShortcut ("table-moveup", "Move Record Up", QKeySequence());
|
||||||
|
|
|
@ -38,9 +38,10 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr
|
||||||
appendStage (new MergeRefIdsStage (mState));
|
appendStage (new MergeRefIdsStage (mState));
|
||||||
appendStage (new MergeReferencesStage (mState));
|
appendStage (new MergeReferencesStage (mState));
|
||||||
appendStage (new MergeReferencesStage (mState));
|
appendStage (new MergeReferencesStage (mState));
|
||||||
appendStage (new ListLandTexturesMergeStage (mState));
|
appendStage (new PopulateLandTexturesMergeStage (mState));
|
||||||
appendStage (new MergeLandTexturesStage (mState));
|
|
||||||
appendStage (new MergeLandStage (mState));
|
appendStage (new MergeLandStage (mState));
|
||||||
|
appendStage (new FixLandsAndLandTexturesMergeStage (mState));
|
||||||
|
appendStage (new CleanupLandTexturesMergeStage (mState));
|
||||||
|
|
||||||
appendStage (new FinishMergedDocumentStage (mState, encoding));
|
appendStage (new FinishMergedDocumentStage (mState, encoding));
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
#include "mergestate.hpp"
|
#include "mergestate.hpp"
|
||||||
|
|
||||||
#include "../doc/document.hpp"
|
#include "../doc/document.hpp"
|
||||||
|
#include "../world/commands.hpp"
|
||||||
#include "../world/data.hpp"
|
#include "../world/data.hpp"
|
||||||
|
#include "../world/idtable.hpp"
|
||||||
|
|
||||||
|
|
||||||
CSMTools::StartMergeStage::StartMergeStage (MergeState& state)
|
CSMTools::StartMergeStage::StartMergeStage (MergeState& state)
|
||||||
|
@ -109,102 +111,32 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state)
|
CSMTools::PopulateLandTexturesMergeStage::PopulateLandTexturesMergeStage (MergeState& state)
|
||||||
: mState (state)
|
: mState (state)
|
||||||
{}
|
|
||||||
|
|
||||||
int CSMTools::ListLandTexturesMergeStage::setup()
|
|
||||||
{
|
{
|
||||||
return mState.mSource.getData().getLand().getSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
|
int CSMTools::PopulateLandTexturesMergeStage::setup()
|
||||||
{
|
{
|
||||||
const CSMWorld::Record<CSMWorld::Land>& record =
|
|
||||||
mState.mSource.getData().getLand().getRecord (stage);
|
|
||||||
|
|
||||||
if (!record.isDeleted())
|
|
||||||
{
|
|
||||||
const CSMWorld::Land& land = record.get();
|
|
||||||
|
|
||||||
// make sure record is loaded
|
|
||||||
land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
|
|
||||||
ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX);
|
|
||||||
|
|
||||||
if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX))
|
|
||||||
{
|
|
||||||
// list texture indices
|
|
||||||
std::pair<uint16_t, int> key;
|
|
||||||
key.second = land.mPlugin;
|
|
||||||
|
|
||||||
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i)
|
|
||||||
{
|
|
||||||
key.first = data->mTextures[i];
|
|
||||||
|
|
||||||
mState.mTextureIndices[key] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state)
|
|
||||||
: mState (state), mNext (mState.mTextureIndices.end())
|
|
||||||
{}
|
|
||||||
|
|
||||||
int CSMTools::MergeLandTexturesStage::setup()
|
|
||||||
{
|
|
||||||
// Should use the size of mState.mTextureIndices instead, but that is not available at this
|
|
||||||
// point. Unless there are any errors in the land and land texture records this will not
|
|
||||||
// make a difference.
|
|
||||||
return mState.mSource.getData().getLandTextures().getSize();
|
return mState.mSource.getData().getLandTextures().getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages)
|
void CSMTools::PopulateLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
{
|
{
|
||||||
if (stage==0)
|
const CSMWorld::Record<CSMWorld::LandTexture>& record =
|
||||||
mNext = mState.mTextureIndices.begin();
|
mState.mSource.getData().getLandTextures().getRecord (stage);
|
||||||
|
|
||||||
bool found = false;
|
if (!record.isDeleted())
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
if (mNext==mState.mTextureIndices.end())
|
mState.mTarget->getData().getLandTextures().appendRecord(record);
|
||||||
return;
|
|
||||||
|
|
||||||
mNext->second = stage+1;
|
|
||||||
|
|
||||||
std::ostringstream stream;
|
|
||||||
stream << mNext->first.first-1 << "_" << mNext->first.second;
|
|
||||||
|
|
||||||
int index = mState.mSource.getData().getLandTextures().searchId (stream.str());
|
|
||||||
|
|
||||||
if (index!=-1)
|
|
||||||
{
|
|
||||||
CSMWorld::LandTexture texture =
|
|
||||||
mState.mSource.getData().getLandTextures().getRecord (index).get();
|
|
||||||
|
|
||||||
stream.clear();
|
|
||||||
stream << mNext->second-1 << "_0";
|
|
||||||
|
|
||||||
texture.mIndex = mNext->second-1;
|
|
||||||
texture.mId = stream.str();
|
|
||||||
|
|
||||||
CSMWorld::Record<CSMWorld::LandTexture> newRecord (
|
|
||||||
CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture);
|
|
||||||
|
|
||||||
mState.mTarget->getData().getLandTextures().appendRecord (newRecord);
|
|
||||||
|
|
||||||
found = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++mNext;
|
|
||||||
}
|
|
||||||
while (!found);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {}
|
CSMTools::MergeLandStage::MergeLandStage (MergeState& state)
|
||||||
|
: mState (state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int CSMTools::MergeLandStage::setup()
|
int CSMTools::MergeLandStage::setup()
|
||||||
{
|
{
|
||||||
|
@ -218,40 +150,66 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
|
|
||||||
if (!record.isDeleted())
|
if (!record.isDeleted())
|
||||||
{
|
{
|
||||||
const CSMWorld::Land& land = record.get();
|
mState.mTarget->getData().getLand().appendRecord (record);
|
||||||
|
}
|
||||||
land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
|
}
|
||||||
ESM::Land::DATA_VTEX);
|
|
||||||
|
|
||||||
CSMWorld::Land newLand (land);
|
CSMTools::FixLandsAndLandTexturesMergeStage::FixLandsAndLandTexturesMergeStage (MergeState& state)
|
||||||
|
: mState (state)
|
||||||
newLand.mPlugin = 0;
|
{
|
||||||
|
}
|
||||||
if (land.mDataTypes & ESM::Land::DATA_VTEX)
|
|
||||||
{
|
int CSMTools::FixLandsAndLandTexturesMergeStage::setup()
|
||||||
// adjust land texture references
|
{
|
||||||
if (ESM::Land::LandData *data = newLand.getLandData())
|
// We will have no more than the source
|
||||||
{
|
return mState.mSource.getData().getLand().getSize();
|
||||||
std::pair<uint16_t, int> key;
|
}
|
||||||
key.second = land.mPlugin;
|
|
||||||
|
void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i)
|
{
|
||||||
{
|
if (stage < mState.mTarget->getData().getLand().getSize())
|
||||||
key.first = data->mTextures[i];
|
{
|
||||||
std::map<std::pair<uint16_t, int>, int>::const_iterator iter =
|
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&>(
|
||||||
mState.mTextureIndices.find (key);
|
*mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_Lands));
|
||||||
|
|
||||||
if (iter!=mState.mTextureIndices.end())
|
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&>(
|
||||||
data->mTextures[i] = iter->second;
|
*mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures));
|
||||||
else
|
|
||||||
data->mTextures[i] = 0;
|
std::string id = mState.mTarget->getData().getLand().getId(stage);
|
||||||
}
|
|
||||||
}
|
CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id);
|
||||||
}
|
cmd.redo();
|
||||||
|
|
||||||
CSMWorld::Record<CSMWorld::Land> newRecord (
|
// Get rid of base data
|
||||||
CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand);
|
const CSMWorld::Record<CSMWorld::Land>& oldRecord =
|
||||||
|
mState.mTarget->getData().getLand().getRecord (stage);
|
||||||
mState.mTarget->getData().getLand().appendRecord (newRecord);
|
|
||||||
|
CSMWorld::Record<CSMWorld::Land> newRecord(CSMWorld::RecordBase::State_ModifiedOnly,
|
||||||
|
nullptr, &oldRecord.get());
|
||||||
|
|
||||||
|
mState.mTarget->getData().getLand().setRecord(stage, newRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMTools::CleanupLandTexturesMergeStage::CleanupLandTexturesMergeStage (MergeState& state)
|
||||||
|
: mState (state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSMTools::CleanupLandTexturesMergeStage::setup()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMTools::CleanupLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
|
{
|
||||||
|
auto& landTextures = mState.mTarget->getData().getLandTextures();
|
||||||
|
for (int i = 0; i < landTextures.getSize(); )
|
||||||
|
{
|
||||||
|
if (!landTextures.getRecord(i).isModified())
|
||||||
|
landTextures.removeRows(i, 1);
|
||||||
|
else
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,29 +116,14 @@ namespace CSMTools
|
||||||
///< Messages resulting from this stage will be appended to \a messages.
|
///< Messages resulting from this stage will be appended to \a messages.
|
||||||
};
|
};
|
||||||
|
|
||||||
class ListLandTexturesMergeStage : public CSMDoc::Stage
|
/// Adds all land texture records that could potentially be referenced when merging
|
||||||
|
class PopulateLandTexturesMergeStage : public CSMDoc::Stage
|
||||||
{
|
{
|
||||||
MergeState& mState;
|
MergeState& mState;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ListLandTexturesMergeStage (MergeState& state);
|
PopulateLandTexturesMergeStage (MergeState& state);
|
||||||
|
|
||||||
virtual int setup();
|
|
||||||
///< \return number of steps
|
|
||||||
|
|
||||||
virtual void perform (int stage, CSMDoc::Messages& messages);
|
|
||||||
///< Messages resulting from this stage will be appended to \a messages.
|
|
||||||
};
|
|
||||||
|
|
||||||
class MergeLandTexturesStage : public CSMDoc::Stage
|
|
||||||
{
|
|
||||||
MergeState& mState;
|
|
||||||
std::map<std::pair<uint16_t, int>, int>::iterator mNext;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
MergeLandTexturesStage (MergeState& state);
|
|
||||||
|
|
||||||
virtual int setup();
|
virtual int setup();
|
||||||
///< \return number of steps
|
///< \return number of steps
|
||||||
|
@ -161,6 +146,40 @@ namespace CSMTools
|
||||||
virtual void perform (int stage, CSMDoc::Messages& messages);
|
virtual void perform (int stage, CSMDoc::Messages& messages);
|
||||||
///< Messages resulting from this stage will be appended to \a messages.
|
///< Messages resulting from this stage will be appended to \a messages.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// During this stage, the complex process of combining LandTextures from
|
||||||
|
/// potentially multiple plugins is undertaken.
|
||||||
|
class FixLandsAndLandTexturesMergeStage : public CSMDoc::Stage
|
||||||
|
{
|
||||||
|
MergeState& mState;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
FixLandsAndLandTexturesMergeStage (MergeState& state);
|
||||||
|
|
||||||
|
virtual int setup();
|
||||||
|
///< \return number of steps
|
||||||
|
|
||||||
|
virtual void perform (int stage, CSMDoc::Messages& messages);
|
||||||
|
///< Messages resulting from this stage will be appended to \a messages.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Removes base LandTexture records. This gets rid of the base records previously
|
||||||
|
/// needed in FixLandsAndLandTexturesMergeStage.
|
||||||
|
class CleanupLandTexturesMergeStage : public CSMDoc::Stage
|
||||||
|
{
|
||||||
|
MergeState& mState;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CleanupLandTexturesMergeStage (MergeState& state);
|
||||||
|
|
||||||
|
virtual int setup();
|
||||||
|
///< \return number of steps
|
||||||
|
|
||||||
|
virtual void perform (int stage, CSMDoc::Messages& messages);
|
||||||
|
///< Messages resulting from this stage will be appended to \a messages.
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
@ -13,8 +14,9 @@
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "columnbase.hpp"
|
#include "columnbase.hpp"
|
||||||
|
|
||||||
#include "collectionbase.hpp"
|
#include "collectionbase.hpp"
|
||||||
|
#include "land.hpp"
|
||||||
|
#include "landtexture.hpp"
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
|
@ -22,15 +24,14 @@ namespace CSMWorld
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
struct IdAccessor
|
struct IdAccessor
|
||||||
{
|
{
|
||||||
std::string& getId (ESXRecordT& record);
|
void setId(ESXRecordT& record, const std::string& id) const;
|
||||||
|
|
||||||
const std::string getId (const ESXRecordT& record) const;
|
const std::string getId (const ESXRecordT& record) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
std::string& IdAccessor<ESXRecordT>::getId (ESXRecordT& record)
|
void IdAccessor<ESXRecordT>::setId(ESXRecordT& record, const std::string& id) const
|
||||||
{
|
{
|
||||||
return record.mId;
|
record.mId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
|
@ -39,6 +40,39 @@ namespace CSMWorld
|
||||||
return record.mId;
|
return record.mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void IdAccessor<Land>::setId (Land& record, const std::string& id) const
|
||||||
|
{
|
||||||
|
int x=0, y=0;
|
||||||
|
|
||||||
|
Land::parseUniqueRecordId(id, x, y);
|
||||||
|
record.mX = x;
|
||||||
|
record.mY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void IdAccessor<LandTexture>::setId (LandTexture& record, const std::string& id) const
|
||||||
|
{
|
||||||
|
int plugin = 0;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
LandTexture::parseUniqueRecordId(id, plugin, index);
|
||||||
|
record.mPluginIndex = plugin;
|
||||||
|
record.mIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline const std::string IdAccessor<Land>::getId (const Land& record) const
|
||||||
|
{
|
||||||
|
return Land::createUniqueRecordId(record.mX, record.mY);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline const std::string IdAccessor<LandTexture>::getId (const LandTexture& record) const
|
||||||
|
{
|
||||||
|
return LandTexture::createUniqueRecordId(record.mPluginIndex, record.mIndex);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Single-type record collection
|
/// \brief Single-type record collection
|
||||||
template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
|
template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
|
||||||
class Collection : public CollectionBase
|
class Collection : public CollectionBase
|
||||||
|
@ -69,6 +103,13 @@ namespace CSMWorld
|
||||||
///
|
///
|
||||||
/// \return Success?
|
/// \return Success?
|
||||||
|
|
||||||
|
int cloneRecordImp (const std::string& origin, const std::string& dest,
|
||||||
|
UniversalId::Type type);
|
||||||
|
///< Returns the index of the clone.
|
||||||
|
|
||||||
|
int touchRecordImp (const std::string& id);
|
||||||
|
///< Returns the index of the record on success, -1 on failure.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Collection();
|
Collection();
|
||||||
|
@ -108,6 +149,10 @@ namespace CSMWorld
|
||||||
const std::string& destination,
|
const std::string& destination,
|
||||||
const UniversalId::Type type);
|
const UniversalId::Type type);
|
||||||
|
|
||||||
|
virtual bool touchRecord(const std::string& id);
|
||||||
|
///< Change the state of a record from base to modified, if it is not already.
|
||||||
|
/// \return True if the record was changed.
|
||||||
|
|
||||||
virtual int searchId (const std::string& id) const;
|
virtual int searchId (const std::string& id) const;
|
||||||
////< Search record with \a id.
|
////< Search record with \a id.
|
||||||
/// \return index of record (if found) or -1 (not found)
|
/// \return index of record (if found) or -1 (not found)
|
||||||
|
@ -206,16 +251,71 @@ namespace CSMWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
|
int Collection<ESXRecordT, IdAccessorT>::cloneRecordImp(const std::string& origin,
|
||||||
const std::string& destination,
|
const std::string& destination, UniversalId::Type type)
|
||||||
const UniversalId::Type type)
|
|
||||||
{
|
{
|
||||||
Record<ESXRecordT> copy;
|
Record<ESXRecordT> copy;
|
||||||
copy.mModified = getRecord(origin).get();
|
copy.mModified = getRecord(origin).get();
|
||||||
copy.mState = RecordBase::State_ModifiedOnly;
|
copy.mState = RecordBase::State_ModifiedOnly;
|
||||||
copy.get().mId = destination;
|
IdAccessorT().setId(copy.get(), destination);
|
||||||
|
|
||||||
|
int index = getAppendIndex(destination, type);
|
||||||
insertRecord(copy, getAppendIndex(destination, type));
|
insertRecord(copy, getAppendIndex(destination, type));
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
|
int Collection<ESXRecordT, IdAccessorT>::touchRecordImp(const std::string& id)
|
||||||
|
{
|
||||||
|
int index = getIndex(id);
|
||||||
|
Record<ESXRecordT>& record = mRecords.at(index);
|
||||||
|
if (record.isDeleted())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("attempt to touch deleted record");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!record.isModified())
|
||||||
|
{
|
||||||
|
record.setModified(record.get());
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
|
void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination, const UniversalId::Type type)
|
||||||
|
{
|
||||||
|
cloneRecordImp(origin, destination, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void Collection<Land, IdAccessor<Land> >::cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination, const UniversalId::Type type)
|
||||||
|
{
|
||||||
|
int index = cloneRecordImp(origin, destination, type);
|
||||||
|
mRecords.at(index).get().mPlugin = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
|
bool Collection<ESXRecordT, IdAccessorT>::touchRecord(const std::string& id)
|
||||||
|
{
|
||||||
|
return touchRecordImp(id) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool Collection<Land, IdAccessor<Land> >::touchRecord(const std::string& id)
|
||||||
|
{
|
||||||
|
int index = touchRecordImp(id);
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
mRecords.at(index).get().mPlugin = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
|
@ -366,7 +466,7 @@ namespace CSMWorld
|
||||||
UniversalId::Type type)
|
UniversalId::Type type)
|
||||||
{
|
{
|
||||||
ESXRecordT record;
|
ESXRecordT record;
|
||||||
IdAccessorT().getId (record) = id;
|
IdAccessorT().setId(record, id);
|
||||||
record.blank();
|
record.blank();
|
||||||
|
|
||||||
Record<ESXRecordT> record2;
|
Record<ESXRecordT> record2;
|
||||||
|
|
|
@ -78,6 +78,8 @@ namespace CSMWorld
|
||||||
const std::string& destination,
|
const std::string& destination,
|
||||||
const UniversalId::Type type) = 0;
|
const UniversalId::Type type) = 0;
|
||||||
|
|
||||||
|
virtual bool touchRecord(const std::string& id) = 0;
|
||||||
|
|
||||||
virtual const RecordBase& getRecord (const std::string& id) const = 0;
|
virtual const RecordBase& getRecord (const std::string& id) const = 0;
|
||||||
|
|
||||||
virtual const RecordBase& getRecord (int index) const = 0;
|
virtual const RecordBase& getRecord (int index) const = 0;
|
||||||
|
|
|
@ -1,28 +1,341 @@
|
||||||
#include "columnimp.hpp"
|
#include "columnimp.hpp"
|
||||||
|
|
||||||
CSMWorld::BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn<ESM::BodyPart> *meshType)
|
#include <stdexcept>
|
||||||
: mMeshType(meshType)
|
#include <QVector>
|
||||||
{}
|
|
||||||
|
|
||||||
QVariant CSMWorld::BodyPartRaceColumn::get(const Record<ESM::BodyPart> &record) const
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
|
/* LandTextureNicknameColumn */
|
||||||
|
LandTextureNicknameColumn::LandTextureNicknameColumn()
|
||||||
|
: Column<LandTexture>(Columns::ColumnId_TextureNickname, ColumnBase::Display_String)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LandTextureNicknameColumn::get(const Record<LandTexture>& record) const
|
||||||
|
{
|
||||||
|
return QString::fromUtf8(record.get().mId.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandTextureNicknameColumn::set(Record<LandTexture>& record, const QVariant& data)
|
||||||
|
{
|
||||||
|
LandTexture copy = record.get();
|
||||||
|
copy.mId = data.toString().toUtf8().constData();
|
||||||
|
record.setModified(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LandTextureNicknameColumn::isEditable() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LandTextureIndexColumn */
|
||||||
|
LandTextureIndexColumn::LandTextureIndexColumn()
|
||||||
|
: Column<LandTexture>(Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LandTextureIndexColumn::get(const Record<LandTexture>& record) const
|
||||||
|
{
|
||||||
|
return record.get().mIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LandTextureIndexColumn::isEditable() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LandPluginIndexColumn */
|
||||||
|
LandPluginIndexColumn::LandPluginIndexColumn()
|
||||||
|
: Column<Land>(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LandPluginIndexColumn::get(const Record<Land>& record) const
|
||||||
|
{
|
||||||
|
return record.get().mPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LandPluginIndexColumn::isEditable() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LandTexturePluginIndexColumn */
|
||||||
|
LandTexturePluginIndexColumn::LandTexturePluginIndexColumn()
|
||||||
|
: Column<LandTexture>(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LandTexturePluginIndexColumn::get(const Record<LandTexture>& record) const
|
||||||
|
{
|
||||||
|
return record.get().mPluginIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LandTexturePluginIndexColumn::isEditable() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LandMapLodColumn */
|
||||||
|
LandMapLodColumn::LandMapLodColumn()
|
||||||
|
: Column<Land>(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LandMapLodColumn::get(const Record<Land>& record) const
|
||||||
|
{
|
||||||
|
const int Size = Land::LAND_GLOBAL_MAP_LOD_SIZE;
|
||||||
|
const Land& land = record.get();
|
||||||
|
|
||||||
|
DataType values(Size, 0);
|
||||||
|
|
||||||
|
if (land.isDataLoaded(Land::DATA_WNAM))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Size; ++i)
|
||||||
|
values[i] = land.mWnam[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant variant;
|
||||||
|
variant.setValue(values);
|
||||||
|
return variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandMapLodColumn::set(Record<Land>& record, const QVariant& data)
|
||||||
|
{
|
||||||
|
DataType values = data.value<DataType>();
|
||||||
|
|
||||||
|
if (values.size() != Land::LAND_GLOBAL_MAP_LOD_SIZE)
|
||||||
|
throw std::runtime_error("invalid land map LOD data");
|
||||||
|
|
||||||
|
Land copy = record.get();
|
||||||
|
copy.add(Land::DATA_WNAM);
|
||||||
|
|
||||||
|
for (int i = 0; i < values.size(); ++i)
|
||||||
|
{
|
||||||
|
copy.mWnam[i] = values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
record.setModified(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LandMapLodColumn::isEditable() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LandNormalsColumn */
|
||||||
|
LandNormalsColumn::LandNormalsColumn()
|
||||||
|
: Column<Land>(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LandNormalsColumn::get(const Record<Land>& record) const
|
||||||
|
{
|
||||||
|
const int Size = Land::LAND_NUM_VERTS * 3;
|
||||||
|
const Land& land = record.get();
|
||||||
|
|
||||||
|
DataType values(Size, 0);
|
||||||
|
|
||||||
|
if (land.isDataLoaded(Land::DATA_VNML))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Size; ++i)
|
||||||
|
values[i] = land.getLandData()->mNormals[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant variant;
|
||||||
|
variant.setValue(values);
|
||||||
|
return variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandNormalsColumn::set(Record<Land>& record, const QVariant& data)
|
||||||
|
{
|
||||||
|
DataType values = data.value<DataType>();
|
||||||
|
|
||||||
|
if (values.size() != Land::LAND_NUM_VERTS * 3)
|
||||||
|
throw std::runtime_error("invalid land normals data");
|
||||||
|
|
||||||
|
Land copy = record.get();
|
||||||
|
copy.add(Land::DATA_VNML);
|
||||||
|
|
||||||
|
for (int i = 0; i < values.size(); ++i)
|
||||||
|
{
|
||||||
|
copy.getLandData()->mNormals[i] = values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
record.setModified(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LandNormalsColumn::isEditable() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LandHeightsColumn */
|
||||||
|
LandHeightsColumn::LandHeightsColumn()
|
||||||
|
: Column<Land>(Columns::ColumnId_LandHeightsIndex, ColumnBase::Display_String, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LandHeightsColumn::get(const Record<Land>& record) const
|
||||||
|
{
|
||||||
|
const int Size = Land::LAND_NUM_VERTS;
|
||||||
|
const Land& land = record.get();
|
||||||
|
|
||||||
|
DataType values(Size, 0);
|
||||||
|
|
||||||
|
if (land.isDataLoaded(Land::DATA_VHGT))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Size; ++i)
|
||||||
|
values[i] = land.getLandData()->mHeights[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant variant;
|
||||||
|
variant.setValue(values);
|
||||||
|
return variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandHeightsColumn::set(Record<Land>& record, const QVariant& data)
|
||||||
|
{
|
||||||
|
DataType values = data.value<DataType>();
|
||||||
|
|
||||||
|
if (values.size() != Land::LAND_NUM_VERTS)
|
||||||
|
throw std::runtime_error("invalid land heights data");
|
||||||
|
|
||||||
|
Land copy = record.get();
|
||||||
|
copy.add(Land::DATA_VHGT);
|
||||||
|
|
||||||
|
for (int i = 0; i < values.size(); ++i)
|
||||||
|
{
|
||||||
|
copy.getLandData()->mHeights[i] = values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
record.setModified(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LandHeightsColumn::isEditable() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LandColoursColumn */
|
||||||
|
LandColoursColumn::LandColoursColumn()
|
||||||
|
: Column<Land>(Columns::ColumnId_LandColoursIndex, ColumnBase::Display_String, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LandColoursColumn::get(const Record<Land>& record) const
|
||||||
|
{
|
||||||
|
const int Size = Land::LAND_NUM_VERTS * 3;
|
||||||
|
const Land& land = record.get();
|
||||||
|
|
||||||
|
DataType values(Size, 0);
|
||||||
|
|
||||||
|
if (land.isDataLoaded(Land::DATA_VCLR))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Size; ++i)
|
||||||
|
values[i] = land.getLandData()->mColours[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant variant;
|
||||||
|
variant.setValue(values);
|
||||||
|
return variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandColoursColumn::set(Record<Land>& record, const QVariant& data)
|
||||||
|
{
|
||||||
|
DataType values = data.value<DataType>();
|
||||||
|
|
||||||
|
if (values.size() != Land::LAND_NUM_VERTS * 3)
|
||||||
|
throw std::runtime_error("invalid land colours data");
|
||||||
|
|
||||||
|
Land copy = record.get();
|
||||||
|
copy.add(Land::DATA_VCLR);
|
||||||
|
|
||||||
|
for (int i = 0; i < values.size(); ++i)
|
||||||
|
{
|
||||||
|
copy.getLandData()->mColours[i] = values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
record.setModified(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LandColoursColumn::isEditable() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LandTexturesColumn */
|
||||||
|
LandTexturesColumn::LandTexturesColumn()
|
||||||
|
: Column<Land>(Columns::ColumnId_LandTexturesIndex, ColumnBase::Display_String, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LandTexturesColumn::get(const Record<Land>& record) const
|
||||||
|
{
|
||||||
|
const int Size = Land::LAND_NUM_TEXTURES;
|
||||||
|
const Land& land = record.get();
|
||||||
|
|
||||||
|
DataType values(Size, 0);
|
||||||
|
|
||||||
|
if (land.isDataLoaded(Land::DATA_VTEX))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Size; ++i)
|
||||||
|
values[i] = land.getLandData()->mTextures[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant variant;
|
||||||
|
variant.setValue(values);
|
||||||
|
return variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandTexturesColumn::set(Record<Land>& record, const QVariant& data)
|
||||||
|
{
|
||||||
|
DataType values = data.value<DataType>();
|
||||||
|
|
||||||
|
if (values.size() != Land::LAND_NUM_TEXTURES)
|
||||||
|
throw std::runtime_error("invalid land textures data");
|
||||||
|
|
||||||
|
Land copy = record.get();
|
||||||
|
copy.add(Land::DATA_VTEX);
|
||||||
|
|
||||||
|
for (int i = 0; i < values.size(); ++i)
|
||||||
|
{
|
||||||
|
copy.getLandData()->mTextures[i] = values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
record.setModified(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LandTexturesColumn::isEditable() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BodyPartRaceColumn */
|
||||||
|
BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn<ESM::BodyPart> *meshType)
|
||||||
|
: mMeshType(meshType)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QVariant BodyPartRaceColumn::get(const Record<ESM::BodyPart> &record) const
|
||||||
|
{
|
||||||
if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin)
|
if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin)
|
||||||
{
|
{
|
||||||
return QString::fromUtf8(record.get().mRace.c_str());
|
return QString::fromUtf8(record.get().mRace.c_str());
|
||||||
}
|
}
|
||||||
return QVariant(QVariant::UserType);
|
return QVariant(QVariant::UserType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::BodyPartRaceColumn::set(Record<ESM::BodyPart> &record, const QVariant &data)
|
void BodyPartRaceColumn::set(Record<ESM::BodyPart> &record, const QVariant &data)
|
||||||
{
|
{
|
||||||
ESM::BodyPart record2 = record.get();
|
ESM::BodyPart record2 = record.get();
|
||||||
|
|
||||||
record2.mRace = data.toString().toUtf8().constData();
|
record2.mRace = data.toString().toUtf8().constData();
|
||||||
|
|
||||||
record.setModified(record2);
|
record.setModified(record2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSMWorld::BodyPartRaceColumn::isEditable() const
|
bool BodyPartRaceColumn::isEditable() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
#define CSM_WOLRD_COLUMNIMP_H
|
#define CSM_WOLRD_COLUMNIMP_H
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
#include <components/esm/loadbody.hpp>
|
#include <components/esm/loadbody.hpp>
|
||||||
#include <components/esm/loadskil.hpp>
|
#include <components/esm/loadskil.hpp>
|
||||||
|
@ -15,6 +17,9 @@
|
||||||
#include "columns.hpp"
|
#include "columns.hpp"
|
||||||
#include "info.hpp"
|
#include "info.hpp"
|
||||||
|
|
||||||
|
#include "land.hpp"
|
||||||
|
#include "landtexture.hpp"
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
/// \note Shares ID with VarValueColumn. A table can not have both.
|
/// \note Shares ID with VarValueColumn. A table can not have both.
|
||||||
|
@ -60,6 +65,20 @@ namespace CSMWorld
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline QVariant StringIdColumn<Land>::get(const Record<Land>& record) const
|
||||||
|
{
|
||||||
|
const Land& land = record.get();
|
||||||
|
return QString::fromUtf8(Land::createUniqueRecordId(land.mX, land.mY).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline QVariant StringIdColumn<LandTexture>::get(const Record<LandTexture>& record) const
|
||||||
|
{
|
||||||
|
const LandTexture& ltex = record.get();
|
||||||
|
return QString::fromUtf8(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
struct RecordStateColumn : public Column<ESXRecordT>
|
struct RecordStateColumn : public Column<ESXRecordT>
|
||||||
{
|
{
|
||||||
|
@ -673,32 +692,23 @@ namespace CSMWorld
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \todo QColor is a GUI class and should not be in model. Need to think of an alternative
|
|
||||||
/// solution.
|
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
struct MapColourColumn : public Column<ESXRecordT>
|
struct MapColourColumn : public Column<ESXRecordT>
|
||||||
{
|
{
|
||||||
/// \todo Replace Display_Integer with something that displays the colour value more directly.
|
|
||||||
MapColourColumn()
|
MapColourColumn()
|
||||||
: Column<ESXRecordT> (Columns::ColumnId_MapColour, ColumnBase::Display_Colour)
|
: Column<ESXRecordT> (Columns::ColumnId_MapColour, ColumnBase::Display_Colour)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||||
{
|
{
|
||||||
int colour = record.get().mMapColor;
|
return record.get().mMapColor;
|
||||||
|
|
||||||
return QColor (colour & 0xff, (colour>>8) & 0xff, (colour>>16) & 0xff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||||
{
|
{
|
||||||
ESXRecordT record2 = record.get();
|
ESXRecordT copy = record.get();
|
||||||
|
copy.mMapColor = data.toInt();
|
||||||
QColor colour = data.value<QColor>();
|
record.setModified (copy);
|
||||||
|
|
||||||
record2.mMapColor = (colour.blue() << 16) | (colour.green() << 8) | colour.red();
|
|
||||||
|
|
||||||
record.setModified (record2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool isEditable() const
|
virtual bool isEditable() const
|
||||||
|
@ -2418,6 +2428,94 @@ namespace CSMWorld
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LandTextureNicknameColumn : public Column<LandTexture>
|
||||||
|
{
|
||||||
|
LandTextureNicknameColumn();
|
||||||
|
|
||||||
|
QVariant get(const Record<LandTexture>& record) const override;
|
||||||
|
void set(Record<LandTexture>& record, const QVariant& data) override;
|
||||||
|
bool isEditable() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LandTextureIndexColumn : public Column<LandTexture>
|
||||||
|
{
|
||||||
|
LandTextureIndexColumn();
|
||||||
|
|
||||||
|
QVariant get(const Record<LandTexture>& record) const override;
|
||||||
|
bool isEditable() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LandPluginIndexColumn : public Column<Land>
|
||||||
|
{
|
||||||
|
LandPluginIndexColumn();
|
||||||
|
|
||||||
|
QVariant get(const Record<Land>& record) const override;
|
||||||
|
bool isEditable() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LandTexturePluginIndexColumn : public Column<LandTexture>
|
||||||
|
{
|
||||||
|
LandTexturePluginIndexColumn();
|
||||||
|
|
||||||
|
QVariant get(const Record<LandTexture>& record) const override;
|
||||||
|
bool isEditable() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LandMapLodColumn : public Column<Land>
|
||||||
|
{
|
||||||
|
using DataType = QVector<signed char>;
|
||||||
|
|
||||||
|
LandMapLodColumn();
|
||||||
|
|
||||||
|
QVariant get(const Record<Land>& record) const override;
|
||||||
|
void set(Record<Land>& record, const QVariant& data) override;
|
||||||
|
bool isEditable() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LandNormalsColumn : public Column<Land>
|
||||||
|
{
|
||||||
|
using DataType = QVector<signed char>;
|
||||||
|
|
||||||
|
LandNormalsColumn();
|
||||||
|
|
||||||
|
QVariant get(const Record<Land>& record) const override;
|
||||||
|
void set(Record<Land>& record, const QVariant& data) override;
|
||||||
|
bool isEditable() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LandHeightsColumn : public Column<Land>
|
||||||
|
{
|
||||||
|
using DataType = QVector<float>;
|
||||||
|
|
||||||
|
LandHeightsColumn();
|
||||||
|
|
||||||
|
QVariant get(const Record<Land>& record) const override;
|
||||||
|
void set(Record<Land>& record, const QVariant& data) override;
|
||||||
|
bool isEditable() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LandColoursColumn : public Column<Land>
|
||||||
|
{
|
||||||
|
using DataType = QVector<unsigned char>;
|
||||||
|
|
||||||
|
LandColoursColumn();
|
||||||
|
|
||||||
|
QVariant get(const Record<Land>& record) const override;
|
||||||
|
void set(Record<Land>& record, const QVariant& data) override;
|
||||||
|
bool isEditable() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LandTexturesColumn : public Column<Land>
|
||||||
|
{
|
||||||
|
using DataType = QVector<uint16_t>;
|
||||||
|
|
||||||
|
LandTexturesColumn();
|
||||||
|
|
||||||
|
QVariant get(const Record<Land>& record) const override;
|
||||||
|
void set(Record<Land>& record, const QVariant& data) override;
|
||||||
|
bool isEditable() const override;
|
||||||
|
};
|
||||||
|
|
||||||
struct BodyPartRaceColumn : public RaceColumn<ESM::BodyPart>
|
struct BodyPartRaceColumn : public RaceColumn<ESM::BodyPart>
|
||||||
{
|
{
|
||||||
const MeshTypeColumn<ESM::BodyPart> *mMeshType;
|
const MeshTypeColumn<ESM::BodyPart> *mMeshType;
|
||||||
|
@ -2430,4 +2528,11 @@ namespace CSMWorld
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is required to access the type as a QVariant.
|
||||||
|
Q_DECLARE_METATYPE(CSMWorld::LandMapLodColumn::DataType)
|
||||||
|
//Q_DECLARE_METATYPE(CSMWorld::LandNormalsColumn::DataType) // Same as LandMapLodColumn::DataType
|
||||||
|
Q_DECLARE_METATYPE(CSMWorld::LandHeightsColumn::DataType)
|
||||||
|
Q_DECLARE_METATYPE(CSMWorld::LandColoursColumn::DataType)
|
||||||
|
Q_DECLARE_METATYPE(CSMWorld::LandTexturesColumn::DataType)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -330,6 +330,14 @@ namespace CSMWorld
|
||||||
{ ColumnId_WeatherChance, "Percent Chance" },
|
{ ColumnId_WeatherChance, "Percent Chance" },
|
||||||
|
|
||||||
{ ColumnId_Text, "Text" },
|
{ ColumnId_Text, "Text" },
|
||||||
|
{ ColumnId_TextureNickname, "Texture Nickname" },
|
||||||
|
{ ColumnId_PluginIndex, "Plugin Index" },
|
||||||
|
{ ColumnId_TextureIndex, "Texture Index" },
|
||||||
|
{ ColumnId_LandMapLodIndex, "Land map height LOD" },
|
||||||
|
{ ColumnId_LandNormalsIndex, "Land normals" },
|
||||||
|
{ ColumnId_LandHeightsIndex, "Land heights" },
|
||||||
|
{ ColumnId_LandColoursIndex, "Land colors" },
|
||||||
|
{ ColumnId_LandTexturesIndex, "Land textures" },
|
||||||
|
|
||||||
{ ColumnId_UseValue1, "Use value 1" },
|
{ ColumnId_UseValue1, "Use value 1" },
|
||||||
{ ColumnId_UseValue2, "Use value 2" },
|
{ ColumnId_UseValue2, "Use value 2" },
|
||||||
|
|
|
@ -329,6 +329,15 @@ namespace CSMWorld
|
||||||
|
|
||||||
ColumnId_Text = 297,
|
ColumnId_Text = 297,
|
||||||
|
|
||||||
|
ColumnId_TextureNickname = 298,
|
||||||
|
ColumnId_PluginIndex = 299,
|
||||||
|
ColumnId_TextureIndex = 300,
|
||||||
|
ColumnId_LandMapLodIndex = 301,
|
||||||
|
ColumnId_LandNormalsIndex = 302,
|
||||||
|
ColumnId_LandHeightsIndex = 303,
|
||||||
|
ColumnId_LandColoursIndex = 304,
|
||||||
|
ColumnId_LandTexturesIndex = 305,
|
||||||
|
|
||||||
// Allocated to a separate value range, so we don't get a collision should we ever need
|
// Allocated to a separate value range, so we don't get a collision should we ever need
|
||||||
// to extend the number of use values.
|
// to extend the number of use values.
|
||||||
ColumnId_UseValue1 = 0x10000,
|
ColumnId_UseValue1 = 0x10000,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
@ -15,6 +16,175 @@
|
||||||
#include "nestedtablewrapper.hpp"
|
#include "nestedtablewrapper.hpp"
|
||||||
#include "pathgrid.hpp"
|
#include "pathgrid.hpp"
|
||||||
|
|
||||||
|
CSMWorld::TouchCommand::TouchCommand(IdTable& table, const std::string& id, QUndoCommand* parent)
|
||||||
|
: QUndoCommand(parent)
|
||||||
|
, mTable(table)
|
||||||
|
, mId(id)
|
||||||
|
, mOld(nullptr)
|
||||||
|
, mChanged(false)
|
||||||
|
{
|
||||||
|
setText(("Touch " + mId).c_str());
|
||||||
|
mOld.reset(mTable.getRecord(mId).clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::TouchCommand::redo()
|
||||||
|
{
|
||||||
|
mChanged = mTable.touchRecord(mId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::TouchCommand::undo()
|
||||||
|
{
|
||||||
|
if (mChanged)
|
||||||
|
{
|
||||||
|
mTable.setRecord(mId, *mOld);
|
||||||
|
mChanged = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::ImportLandTexturesCommand::ImportLandTexturesCommand(IdTable& landTable,
|
||||||
|
IdTable& ltexTable, QUndoCommand* parent)
|
||||||
|
: QUndoCommand(parent)
|
||||||
|
, mLands(landTable)
|
||||||
|
, mLtexs(ltexTable)
|
||||||
|
, mOldState(0)
|
||||||
|
{
|
||||||
|
setText("Copy land textures to current plugin");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::ImportLandTexturesCommand::redo()
|
||||||
|
{
|
||||||
|
int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex);
|
||||||
|
int oldPlugin = mLands.data(mLands.getModelIndex(getOriginId(), pluginColumn)).toInt();
|
||||||
|
|
||||||
|
// Original data
|
||||||
|
int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex);
|
||||||
|
mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).value<DataType>();
|
||||||
|
|
||||||
|
// Need to make a copy so the old values can be looked up
|
||||||
|
DataType copy(mOld);
|
||||||
|
|
||||||
|
// Perform touch/copy/etc...
|
||||||
|
onRedo();
|
||||||
|
|
||||||
|
// Find all indices used
|
||||||
|
std::unordered_set<int> texIndices;
|
||||||
|
for (int i = 0; i < mOld.size(); ++i)
|
||||||
|
{
|
||||||
|
// All indices are offset by 1 for a default texture
|
||||||
|
if (mOld[i] > 0)
|
||||||
|
texIndices.insert(mOld[i] - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> oldTextures;
|
||||||
|
for (int index : texIndices)
|
||||||
|
{
|
||||||
|
oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import the textures, replace old values
|
||||||
|
LandTextureIdTable::ImportResults results = dynamic_cast<LandTextureIdTable&>(mLtexs).importTextures(oldTextures);
|
||||||
|
mCreatedTextures = std::move(results.createdRecords);
|
||||||
|
for (const auto& it : results.recordMapping)
|
||||||
|
{
|
||||||
|
int plugin = 0, newIndex = 0, oldIndex = 0;
|
||||||
|
LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex);
|
||||||
|
LandTexture::parseUniqueRecordId(it.second, plugin, newIndex);
|
||||||
|
|
||||||
|
if (newIndex != oldIndex)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i)
|
||||||
|
{
|
||||||
|
// All indices are offset by 1 for a default texture
|
||||||
|
if (mOld[i] == oldIndex + 1)
|
||||||
|
copy[i] = newIndex + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply modification
|
||||||
|
int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification);
|
||||||
|
mOldState = mLands.data(mLands.getModelIndex(getDestinationId(), stateColumn)).toInt();
|
||||||
|
|
||||||
|
QVariant variant;
|
||||||
|
variant.setValue(copy);
|
||||||
|
mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::ImportLandTexturesCommand::undo()
|
||||||
|
{
|
||||||
|
// Restore to previous
|
||||||
|
int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex);
|
||||||
|
QVariant variant;
|
||||||
|
variant.setValue(mOld);
|
||||||
|
mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), variant);
|
||||||
|
|
||||||
|
int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification);
|
||||||
|
mLands.setData(mLands.getModelIndex(getDestinationId(), stateColumn), mOldState);
|
||||||
|
|
||||||
|
// Undo copy/touch/etc...
|
||||||
|
onUndo();
|
||||||
|
|
||||||
|
for (const std::string& id : mCreatedTextures)
|
||||||
|
{
|
||||||
|
int row = mLtexs.getModelIndex(id, 0).row();
|
||||||
|
mLtexs.removeRows(row, 1);
|
||||||
|
}
|
||||||
|
mCreatedTextures.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::CopyLandTexturesCommand::CopyLandTexturesCommand(IdTable& landTable, IdTable& ltexTable,
|
||||||
|
const std::string& origin, const std::string& dest, QUndoCommand* parent)
|
||||||
|
: ImportLandTexturesCommand(landTable, ltexTable, parent)
|
||||||
|
, mOriginId(origin)
|
||||||
|
, mDestId(dest)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& CSMWorld::CopyLandTexturesCommand::getOriginId() const
|
||||||
|
{
|
||||||
|
return mOriginId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& CSMWorld::CopyLandTexturesCommand::getDestinationId() const
|
||||||
|
{
|
||||||
|
return mDestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTable,
|
||||||
|
const std::string& id, QUndoCommand* parent)
|
||||||
|
: ImportLandTexturesCommand(landTable, ltexTable, parent)
|
||||||
|
, mId(id)
|
||||||
|
, mOld(nullptr)
|
||||||
|
, mChanged(false)
|
||||||
|
{
|
||||||
|
setText(("Touch " + mId).c_str());
|
||||||
|
mOld.reset(mLands.getRecord(mId).clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& CSMWorld::TouchLandCommand::getOriginId() const
|
||||||
|
{
|
||||||
|
return mId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& CSMWorld::TouchLandCommand::getDestinationId() const
|
||||||
|
{
|
||||||
|
return mId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::TouchLandCommand::onRedo()
|
||||||
|
{
|
||||||
|
mChanged = mLands.touchRecord(mId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::TouchLandCommand::onUndo()
|
||||||
|
{
|
||||||
|
if (mChanged)
|
||||||
|
{
|
||||||
|
mLands.setRecord(mId, *mOld);
|
||||||
|
mChanged = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
|
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
|
||||||
const QVariant& new_, QUndoCommand* parent)
|
const QVariant& new_, QUndoCommand* parent)
|
||||||
: QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly)
|
: QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly)
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QUndoCommand>
|
#include <QUndoCommand>
|
||||||
#include <QModelIndex>
|
#include <QModelIndex>
|
||||||
|
|
||||||
|
#include "columnimp.hpp"
|
||||||
#include "universalid.hpp"
|
#include "universalid.hpp"
|
||||||
#include "nestedtablewrapper.hpp"
|
#include "nestedtablewrapper.hpp"
|
||||||
|
|
||||||
|
@ -24,6 +26,106 @@ namespace CSMWorld
|
||||||
struct RecordBase;
|
struct RecordBase;
|
||||||
struct NestedTableWrapperBase;
|
struct NestedTableWrapperBase;
|
||||||
|
|
||||||
|
class TouchCommand : public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
TouchCommand(IdTable& model, const std::string& id, QUndoCommand* parent=nullptr);
|
||||||
|
|
||||||
|
void redo() override;
|
||||||
|
void undo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
IdTable& mTable;
|
||||||
|
std::string mId;
|
||||||
|
std::unique_ptr<RecordBase> mOld;
|
||||||
|
|
||||||
|
bool mChanged;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Adds LandTexture records and modifies texture indices as needed.
|
||||||
|
///
|
||||||
|
/// LandTexture records are different from other types of records, because
|
||||||
|
/// they only effect the current plugin. Thus, when modifying or copying
|
||||||
|
/// a Land record, all of the LandTexture records referenced need to be
|
||||||
|
/// added to the current plugin. Since these newly added LandTextures could
|
||||||
|
/// have indices that conflict with pre-existing LandTextures in the current
|
||||||
|
/// plugin, the indices might have to be changed, both for the newly added
|
||||||
|
/// LandRecord and within the Land record.
|
||||||
|
class ImportLandTexturesCommand : public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ImportLandTexturesCommand(IdTable& landTable, IdTable& ltexTable,
|
||||||
|
QUndoCommand* parent);
|
||||||
|
|
||||||
|
void redo() override;
|
||||||
|
void undo() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
using DataType = LandTexturesColumn::DataType;
|
||||||
|
|
||||||
|
virtual const std::string& getOriginId() const = 0;
|
||||||
|
virtual const std::string& getDestinationId() const = 0;
|
||||||
|
|
||||||
|
virtual void onRedo() = 0;
|
||||||
|
virtual void onUndo() = 0;
|
||||||
|
|
||||||
|
IdTable& mLands;
|
||||||
|
IdTable& mLtexs;
|
||||||
|
DataType mOld;
|
||||||
|
int mOldState;
|
||||||
|
std::vector<std::string> mCreatedTextures;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief This command is used to fix LandTexture records and texture
|
||||||
|
/// indices after cloning a Land. See ImportLandTexturesCommand for
|
||||||
|
/// details.
|
||||||
|
class CopyLandTexturesCommand : public ImportLandTexturesCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CopyLandTexturesCommand(IdTable& landTable, IdTable& ltexTable, const std::string& origin,
|
||||||
|
const std::string& dest, QUndoCommand* parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const std::string& getOriginId() const override;
|
||||||
|
const std::string& getDestinationId() const override;
|
||||||
|
|
||||||
|
void onRedo() override {}
|
||||||
|
void onUndo() override {}
|
||||||
|
|
||||||
|
std::string mOriginId;
|
||||||
|
std::string mDestId;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief This command brings a land record into the current plugin, adding
|
||||||
|
/// LandTexture records and modifying texture indices as needed.
|
||||||
|
/// \note See ImportLandTextures for more details.
|
||||||
|
class TouchLandCommand : public ImportLandTexturesCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
TouchLandCommand(IdTable& landTable, IdTable& ltexTable,
|
||||||
|
const std::string& id, QUndoCommand* parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const std::string& getOriginId() const override;
|
||||||
|
const std::string& getDestinationId() const override;
|
||||||
|
|
||||||
|
void onRedo() override;
|
||||||
|
void onUndo() override;
|
||||||
|
|
||||||
|
std::string mId;
|
||||||
|
std::unique_ptr<RecordBase> mOld;
|
||||||
|
|
||||||
|
bool mChanged;
|
||||||
|
};
|
||||||
|
|
||||||
class ModifyCommand : public QUndoCommand
|
class ModifyCommand : public QUndoCommand
|
||||||
{
|
{
|
||||||
QAbstractItemModel *mModel;
|
QAbstractItemModel *mModel;
|
||||||
|
|
|
@ -412,6 +412,24 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
||||||
Columns::ColumnId_NegativeLight, ESM::MagicEffect::NegativeLight));
|
Columns::ColumnId_NegativeLight, ESM::MagicEffect::NegativeLight));
|
||||||
mMagicEffects.addColumn (new DescriptionColumn<ESM::MagicEffect>);
|
mMagicEffects.addColumn (new DescriptionColumn<ESM::MagicEffect>);
|
||||||
|
|
||||||
|
mLand.addColumn (new StringIdColumn<Land>);
|
||||||
|
mLand.addColumn (new RecordStateColumn<Land>);
|
||||||
|
mLand.addColumn (new FixedRecordTypeColumn<Land>(UniversalId::Type_Land));
|
||||||
|
mLand.addColumn (new LandPluginIndexColumn);
|
||||||
|
mLand.addColumn (new LandMapLodColumn);
|
||||||
|
mLand.addColumn (new LandNormalsColumn);
|
||||||
|
mLand.addColumn (new LandHeightsColumn);
|
||||||
|
mLand.addColumn (new LandColoursColumn);
|
||||||
|
mLand.addColumn (new LandTexturesColumn);
|
||||||
|
|
||||||
|
mLandTextures.addColumn (new StringIdColumn<LandTexture>(true));
|
||||||
|
mLandTextures.addColumn (new RecordStateColumn<LandTexture>);
|
||||||
|
mLandTextures.addColumn (new FixedRecordTypeColumn<LandTexture>(UniversalId::Type_LandTexture));
|
||||||
|
mLandTextures.addColumn (new LandTextureNicknameColumn);
|
||||||
|
mLandTextures.addColumn (new LandTexturePluginIndexColumn);
|
||||||
|
mLandTextures.addColumn (new LandTextureIndexColumn);
|
||||||
|
mLandTextures.addColumn (new TextureColumn<LandTexture>);
|
||||||
|
|
||||||
mPathgrids.addColumn (new StringIdColumn<Pathgrid>);
|
mPathgrids.addColumn (new StringIdColumn<Pathgrid>);
|
||||||
mPathgrids.addColumn (new RecordStateColumn<Pathgrid>);
|
mPathgrids.addColumn (new RecordStateColumn<Pathgrid>);
|
||||||
mPathgrids.addColumn (new FixedRecordTypeColumn<Pathgrid> (UniversalId::Type_Pathgrid));
|
mPathgrids.addColumn (new FixedRecordTypeColumn<Pathgrid> (UniversalId::Type_Pathgrid));
|
||||||
|
@ -531,6 +549,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
||||||
addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart);
|
addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart);
|
||||||
addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen);
|
addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen);
|
||||||
addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect);
|
addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect);
|
||||||
|
addModel (new IdTable (&mLand, IdTable::Feature_AllowTouch), UniversalId::Type_Land);
|
||||||
|
addModel (new LandTextureIdTable (&mLandTextures), UniversalId::Type_LandTexture);
|
||||||
addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid);
|
addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid);
|
||||||
addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript);
|
addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript);
|
||||||
addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview),
|
addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview),
|
||||||
|
@ -993,19 +1013,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
||||||
|
|
||||||
case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break;
|
case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break;
|
||||||
|
|
||||||
case ESM::REC_LAND:
|
case ESM::REC_LAND: mLand.load(*mReader, mBase); break;
|
||||||
{
|
|
||||||
int index = mLand.load(*mReader, mBase);
|
|
||||||
|
|
||||||
// Load all land data for now. A future optimisation may only load non-base data
|
|
||||||
// if a suitable mechanism for avoiding race conditions can be established.
|
|
||||||
if (index!=-1/* && !mBase*/)
|
|
||||||
mLand.getRecord (index).get().loadData (
|
|
||||||
ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR |
|
|
||||||
ESM::Land::DATA_VTEX);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ESM::REC_CELL:
|
case ESM::REC_CELL:
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
#include "collection.hpp"
|
#include "collection.hpp"
|
||||||
|
#include "land.hpp"
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
|
@ -39,6 +40,22 @@ namespace CSMWorld
|
||||||
record.load (reader, isDeleted);
|
record.load (reader, isDeleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void IdCollection<Land, IdAccessor<Land> >::loadRecord (Land& record,
|
||||||
|
ESM::ESMReader& reader, bool& isDeleted)
|
||||||
|
{
|
||||||
|
record.load (reader, isDeleted);
|
||||||
|
|
||||||
|
// Load all land data for now. A future optimisation may only load non-base data
|
||||||
|
// if a suitable mechanism for avoiding race conditions can be established.
|
||||||
|
int flags = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
|
||||||
|
ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX;
|
||||||
|
record.loadData (flags);
|
||||||
|
|
||||||
|
// Prevent data from being reloaded.
|
||||||
|
record.mContext.filename.clear();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
int IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base)
|
int IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
#include "idtable.hpp"
|
#include "idtable.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <map>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
|
|
||||||
#include "collectionbase.hpp"
|
#include "collectionbase.hpp"
|
||||||
#include "columnbase.hpp"
|
#include "columnbase.hpp"
|
||||||
|
#include "landtexture.hpp"
|
||||||
|
|
||||||
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features)
|
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features)
|
||||||
: IdTableBase (features), mIdCollection (idCollection)
|
: IdTableBase (features), mIdCollection (idCollection)
|
||||||
|
@ -179,6 +185,26 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin,
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CSMWorld::IdTable::touchRecord(const std::string& id)
|
||||||
|
{
|
||||||
|
bool changed = mIdCollection->touchRecord(id);
|
||||||
|
|
||||||
|
int row = mIdCollection->getIndex(id);
|
||||||
|
int column = mIdCollection->searchColumnIndex(Columns::ColumnId_RecordType);
|
||||||
|
if (changed && column != -1)
|
||||||
|
{
|
||||||
|
QModelIndex modelIndex = index(row, column);
|
||||||
|
emit dataChanged(modelIndex, modelIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CSMWorld::IdTable::getId(int row) const
|
||||||
|
{
|
||||||
|
return mIdCollection->getId(row);
|
||||||
|
}
|
||||||
|
|
||||||
///This method can return only indexes to the top level table cells
|
///This method can return only indexes to the top level table cells
|
||||||
QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const
|
QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const
|
||||||
{
|
{
|
||||||
|
@ -281,3 +307,72 @@ CSMWorld::CollectionBase *CSMWorld::IdTable::idCollection() const
|
||||||
{
|
{
|
||||||
return mIdCollection;
|
return mIdCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSMWorld::LandTextureIdTable::LandTextureIdTable(CollectionBase* idCollection, unsigned int features)
|
||||||
|
: IdTable(idCollection, features)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::importTextures(const std::vector<std::string>& ids)
|
||||||
|
{
|
||||||
|
ImportResults results;
|
||||||
|
|
||||||
|
// Map existing textures to ids
|
||||||
|
std::map<std::string, std::string> reverseLookupMap;
|
||||||
|
for (int i = 0; i < idCollection()->getSize(); ++i)
|
||||||
|
{
|
||||||
|
auto& record = static_cast<const Record<LandTexture>&>(idCollection()->getRecord(i));
|
||||||
|
std::string texture = record.get().mTexture;
|
||||||
|
std::transform(texture.begin(), texture.end(), texture.begin(), tolower);
|
||||||
|
if (record.isModified())
|
||||||
|
reverseLookupMap.emplace(texture, idCollection()->getId(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const std::string& id : ids)
|
||||||
|
{
|
||||||
|
int plugin, index;
|
||||||
|
|
||||||
|
LandTexture::parseUniqueRecordId(id, plugin, index);
|
||||||
|
int oldRow = idCollection()->searchId(id);
|
||||||
|
|
||||||
|
// If it does not exist or it is in the current plugin, it can be skipped.
|
||||||
|
if (oldRow < 0 || plugin == 0)
|
||||||
|
{
|
||||||
|
results.recordMapping.push_back(std::make_pair(id, id));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a pre-existing record
|
||||||
|
auto& record = static_cast<const Record<LandTexture>&>(idCollection()->getRecord(oldRow));
|
||||||
|
std::string texture = record.get().mTexture;
|
||||||
|
std::transform(texture.begin(), texture.end(), texture.begin(), tolower);
|
||||||
|
auto searchIt = reverseLookupMap.find(texture);
|
||||||
|
if (searchIt != reverseLookupMap.end())
|
||||||
|
{
|
||||||
|
results.recordMapping.push_back(std::make_pair(id, searchIt->second));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate until an unused index or found, or the index has completely wrapped around.
|
||||||
|
int startIndex = index;
|
||||||
|
do {
|
||||||
|
std::string newId = LandTexture::createUniqueRecordId(0, index);
|
||||||
|
int newRow = idCollection()->searchId(newId);
|
||||||
|
|
||||||
|
if (newRow < 0)
|
||||||
|
{
|
||||||
|
// Id not taken, clone it
|
||||||
|
cloneRecord(id, newId, UniversalId::Type_LandTexture);
|
||||||
|
results.createdRecords.push_back(newId);
|
||||||
|
results.recordMapping.push_back(std::make_pair(id, newId));
|
||||||
|
reverseLookupMap.emplace(texture, newId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t MaxIndex = std::numeric_limits<uint16_t>::max() - 1;
|
||||||
|
index = (index + 1) % MaxIndex;
|
||||||
|
} while (index != startIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
|
@ -61,6 +61,11 @@ namespace CSMWorld
|
||||||
const std::string& destination,
|
const std::string& destination,
|
||||||
UniversalId::Type type = UniversalId::Type_None);
|
UniversalId::Type type = UniversalId::Type_None);
|
||||||
|
|
||||||
|
bool touchRecord(const std::string& id);
|
||||||
|
///< Will change the record state to modified, if it is not already.
|
||||||
|
|
||||||
|
std::string getId(int row) const;
|
||||||
|
|
||||||
virtual QModelIndex getModelIndex (const std::string& id, int column) const;
|
virtual QModelIndex getModelIndex (const std::string& id, int column) const;
|
||||||
|
|
||||||
void setRecord (const std::string& id, const RecordBase& record,
|
void setRecord (const std::string& id, const RecordBase& record,
|
||||||
|
@ -93,6 +98,29 @@ namespace CSMWorld
|
||||||
|
|
||||||
virtual CollectionBase *idCollection() const;
|
virtual CollectionBase *idCollection() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// An IdTable customized to handle the more unique needs of LandTextureId's which behave
|
||||||
|
/// differently from other records. The major difference is that base records cannot be
|
||||||
|
/// modified.
|
||||||
|
class LandTextureIdTable : public IdTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct ImportResults
|
||||||
|
{
|
||||||
|
using StringPair = std::pair<std::string,std::string>;
|
||||||
|
|
||||||
|
/// The newly added records
|
||||||
|
std::vector<std::string> createdRecords;
|
||||||
|
/// The 1st string is the original id, the 2nd is the mapped id
|
||||||
|
std::vector<StringPair> recordMapping;
|
||||||
|
};
|
||||||
|
|
||||||
|
LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0);
|
||||||
|
|
||||||
|
/// Finds and maps/recreates the specified ids.
|
||||||
|
ImportResults importTextures(const std::vector<std::string>& ids);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,7 +32,9 @@ namespace CSMWorld
|
||||||
Feature_Preview = 8,
|
Feature_Preview = 8,
|
||||||
|
|
||||||
/// Table can not be modified through ordinary means.
|
/// Table can not be modified through ordinary means.
|
||||||
Feature_Constant = 16
|
Feature_Constant = 16,
|
||||||
|
|
||||||
|
Feature_AllowTouch = 32
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,15 +1,30 @@
|
||||||
#include "land.hpp"
|
#include "land.hpp"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
void Land::load(ESM::ESMReader &esm, bool &isDeleted)
|
void Land::load(ESM::ESMReader &esm, bool &isDeleted)
|
||||||
{
|
{
|
||||||
ESM::Land::load(esm, isDeleted);
|
ESM::Land::load(esm, isDeleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Land::createUniqueRecordId(int x, int y)
|
||||||
|
{
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
stream << "#" << mX << " " << mY;
|
stream << "#" << x << " " << y;
|
||||||
mId = stream.str();
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Land::parseUniqueRecordId(const std::string& id, int& x, int& y)
|
||||||
|
{
|
||||||
|
size_t mid = id.find(' ');
|
||||||
|
|
||||||
|
if (mid == std::string::npos || id[0] != '#')
|
||||||
|
throw std::runtime_error("Invalid Land ID");
|
||||||
|
|
||||||
|
x = std::stoi(id.substr(1, mid - 1));
|
||||||
|
y = std::stoi(id.substr(mid + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,11 @@ namespace CSMWorld
|
||||||
/// \todo Add worldspace support to the Land record.
|
/// \todo Add worldspace support to the Land record.
|
||||||
struct Land : public ESM::Land
|
struct Land : public ESM::Land
|
||||||
{
|
{
|
||||||
std::string mId;
|
|
||||||
|
|
||||||
/// Loads the metadata and ID
|
/// Loads the metadata and ID
|
||||||
void load (ESM::ESMReader &esm, bool &isDeleted);
|
void load (ESM::ESMReader &esm, bool &isDeleted);
|
||||||
|
|
||||||
|
static std::string createUniqueRecordId(int x, int y);
|
||||||
|
static void parseUniqueRecordId(const std::string& id, int& x, int& y);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#include "landtexture.hpp"
|
#include "landtexture.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
|
@ -11,4 +14,21 @@ namespace CSMWorld
|
||||||
mPluginIndex = esm.getIndex();
|
mPluginIndex = esm.getIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string LandTexture::createUniqueRecordId(int plugin, int index)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << 'L' << plugin << '#' << index;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandTexture::parseUniqueRecordId(const std::string& id, int& plugin, int& index)
|
||||||
|
{
|
||||||
|
size_t middle = id.find('#');
|
||||||
|
|
||||||
|
if (middle == std::string::npos || id[0] != 'L')
|
||||||
|
throw std::runtime_error("Invalid LandTexture ID");
|
||||||
|
|
||||||
|
plugin = std::stoi(id.substr(1,middle-1));
|
||||||
|
index = std::stoi(id.substr(middle+1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,11 @@ namespace CSMWorld
|
||||||
int mPluginIndex;
|
int mPluginIndex;
|
||||||
|
|
||||||
void load (ESM::ESMReader &esm, bool &isDeleted);
|
void load (ESM::ESMReader &esm, bool &isDeleted);
|
||||||
|
|
||||||
|
/// Returns a string identifier that will be unique to any LandTexture.
|
||||||
|
static std::string createUniqueRecordId(int plugin, int index);
|
||||||
|
/// Deconstructs a unique string identifier into plugin and index.
|
||||||
|
static void parseUniqueRecordId(const std::string& id, int& plugin, int& index);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
21
apps/opencs/model/world/landtexturetableproxymodel.cpp
Normal file
21
apps/opencs/model/world/landtexturetableproxymodel.cpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#include "landtexturetableproxymodel.hpp"
|
||||||
|
|
||||||
|
#include "idtable.hpp"
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
LandTextureTableProxyModel::LandTextureTableProxyModel(QObject* parent)
|
||||||
|
: IdTableProxyModel(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LandTextureTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const
|
||||||
|
{
|
||||||
|
int columnIndex = mSourceModel->findColumnIndex(Columns::ColumnId_Modification);
|
||||||
|
QModelIndex index = mSourceModel->index(sourceRow, columnIndex);
|
||||||
|
if (mSourceModel->data(index).toInt() != RecordBase::State_ModifiedOnly)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return IdTableProxyModel::filterAcceptsRow(sourceRow, sourceParent);
|
||||||
|
}
|
||||||
|
}
|
22
apps/opencs/model/world/landtexturetableproxymodel.hpp
Normal file
22
apps/opencs/model/world/landtexturetableproxymodel.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef CSM_WORLD_LANDTEXTURETABLEPROXYMODEL_H
|
||||||
|
#define CSM_WORLD_LANDTEXTURETABLEPROXYMODEL_H
|
||||||
|
|
||||||
|
#include "idtableproxymodel.hpp"
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
/// \brief Removes base records from filtered results.
|
||||||
|
class LandTextureTableProxyModel : public IdTableProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
LandTextureTableProxyModel(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -813,6 +813,12 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin,
|
||||||
mData.insertRecord(*newRecord, type, destination);
|
mData.insertRecord(*newRecord, type, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CSMWorld::RefIdCollection::touchRecord(const std::string& id)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("RefIdCollection::touchRecord is unimplemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
|
void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
|
||||||
UniversalId::Type type)
|
UniversalId::Type type)
|
||||||
{
|
{
|
||||||
|
|
|
@ -80,6 +80,8 @@ namespace CSMWorld
|
||||||
const std::string& destination,
|
const std::string& destination,
|
||||||
const UniversalId::Type type);
|
const UniversalId::Type type);
|
||||||
|
|
||||||
|
virtual bool touchRecord(const std::string& id);
|
||||||
|
|
||||||
virtual void appendBlankRecord (const std::string& id, UniversalId::Type type);
|
virtual void appendBlankRecord (const std::string& id, UniversalId::Type type);
|
||||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ namespace
|
||||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", 0 },
|
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", 0 },
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 },
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 },
|
||||||
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands", 0 },
|
||||||
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_LandTextures, "LandTextures", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 },
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 },
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 },
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 },
|
||||||
|
@ -118,6 +120,8 @@ namespace
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 },
|
||||||
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", 0 },
|
||||||
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "LandTexture", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 },
|
||||||
|
|
|
@ -126,6 +126,10 @@ namespace CSMWorld
|
||||||
Type_SoundGen,
|
Type_SoundGen,
|
||||||
Type_MagicEffects,
|
Type_MagicEffects,
|
||||||
Type_MagicEffect,
|
Type_MagicEffect,
|
||||||
|
Type_Lands,
|
||||||
|
Type_Land,
|
||||||
|
Type_LandTextures,
|
||||||
|
Type_LandTexture,
|
||||||
Type_Pathgrids,
|
Type_Pathgrids,
|
||||||
Type_Pathgrid,
|
Type_Pathgrid,
|
||||||
Type_StartScripts,
|
Type_StartScripts,
|
||||||
|
|
|
@ -172,6 +172,16 @@ void CSVDoc::View::setupWorldMenu()
|
||||||
setupShortcut("document-world-references", references);
|
setupShortcut("document-world-references", references);
|
||||||
world->addAction (references);
|
world->addAction (references);
|
||||||
|
|
||||||
|
QAction *lands = new QAction (tr ("Lands"), this);
|
||||||
|
connect (lands, SIGNAL (triggered()), this, SLOT (addLandsSubView()));
|
||||||
|
setupShortcut("document-world-lands", lands);
|
||||||
|
world->addAction (lands);
|
||||||
|
|
||||||
|
QAction *landTextures = new QAction (tr ("Land Textures"), this);
|
||||||
|
connect (landTextures, SIGNAL (triggered()), this, SLOT (addLandTexturesSubView()));
|
||||||
|
setupShortcut("document-world-landtextures", landTextures);
|
||||||
|
world->addAction (landTextures);
|
||||||
|
|
||||||
QAction *grid = new QAction (tr ("Pathgrid"), this);
|
QAction *grid = new QAction (tr ("Pathgrid"), this);
|
||||||
connect (grid, SIGNAL (triggered()), this, SLOT (addPathgridSubView()));
|
connect (grid, SIGNAL (triggered()), this, SLOT (addPathgridSubView()));
|
||||||
setupShortcut("document-world-pathgrid", grid);
|
setupShortcut("document-world-pathgrid", grid);
|
||||||
|
@ -876,6 +886,16 @@ void CSVDoc::View::addRunLogSubView()
|
||||||
addSubView (CSMWorld::UniversalId::Type_RunLog);
|
addSubView (CSMWorld::UniversalId::Type_RunLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVDoc::View::addLandsSubView()
|
||||||
|
{
|
||||||
|
addSubView (CSMWorld::UniversalId::Type_Lands);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVDoc::View::addLandTexturesSubView()
|
||||||
|
{
|
||||||
|
addSubView (CSMWorld::UniversalId::Type_LandTextures);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVDoc::View::addPathgridSubView()
|
void CSVDoc::View::addPathgridSubView()
|
||||||
{
|
{
|
||||||
addSubView (CSMWorld::UniversalId::Type_Pathgrids);
|
addSubView (CSMWorld::UniversalId::Type_Pathgrids);
|
||||||
|
|
|
@ -224,6 +224,10 @@ namespace CSVDoc
|
||||||
|
|
||||||
void addRunLogSubView();
|
void addRunLogSubView();
|
||||||
|
|
||||||
|
void addLandsSubView();
|
||||||
|
|
||||||
|
void addLandTexturesSubView();
|
||||||
|
|
||||||
void addPathgridSubView();
|
void addPathgridSubView();
|
||||||
|
|
||||||
void addStartScriptsSubView();
|
void addStartScriptsSubView();
|
||||||
|
|
|
@ -24,7 +24,7 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main)
|
||||||
|
|
||||||
main->addWidget (list);
|
main->addWidget (list);
|
||||||
|
|
||||||
QFontMetrics metrics (QApplication::font());
|
QFontMetrics metrics (QApplication::font(list));
|
||||||
|
|
||||||
int maxWidth = 1;
|
int maxWidth = 1;
|
||||||
|
|
||||||
|
@ -84,7 +84,6 @@ CSVPrefs::Dialogue::~Dialogue()
|
||||||
void CSVPrefs::Dialogue::closeEvent (QCloseEvent *event)
|
void CSVPrefs::Dialogue::closeEvent (QCloseEvent *event)
|
||||||
{
|
{
|
||||||
QMainWindow::closeEvent (event);
|
QMainWindow::closeEvent (event);
|
||||||
|
|
||||||
CSMPrefs::State::get().save();
|
CSMPrefs::State::get().save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -669,15 +669,24 @@ namespace CSVRender
|
||||||
mInitialized = true;
|
mInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OrbitCameraController::setConstRoll(bool enabled)
|
||||||
|
{
|
||||||
|
mConstRoll = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
void OrbitCameraController::rotateHorizontal(double value)
|
void OrbitCameraController::rotateHorizontal(double value)
|
||||||
{
|
{
|
||||||
osg::Vec3d eye, center, up;
|
osg::Vec3d eye, center, up;
|
||||||
getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
||||||
|
osg::Vec3d absoluteUp = osg::Vec3(0,0,1);
|
||||||
|
|
||||||
osg::Quat rotation = osg::Quat(value, up);
|
osg::Quat rotation = osg::Quat(value, mConstRoll ? absoluteUp : up);
|
||||||
osg::Vec3d oldOffset = eye - mCenter;
|
osg::Vec3d oldOffset = eye - mCenter;
|
||||||
osg::Vec3d newOffset = rotation * oldOffset;
|
osg::Vec3d newOffset = rotation * oldOffset;
|
||||||
|
|
||||||
|
if (mConstRoll)
|
||||||
|
up = rotation * up;
|
||||||
|
|
||||||
getCamera()->setViewMatrixAsLookAt(mCenter + newOffset, mCenter, up);
|
getCamera()->setViewMatrixAsLookAt(mCenter + newOffset, mCenter, up);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,10 +696,15 @@ namespace CSVRender
|
||||||
getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
||||||
|
|
||||||
osg::Vec3d forward = center - eye;
|
osg::Vec3d forward = center - eye;
|
||||||
osg::Quat rotation = osg::Quat(value, up ^ forward);
|
osg::Vec3d axis = up ^ forward;
|
||||||
|
|
||||||
|
osg::Quat rotation = osg::Quat(value,axis);
|
||||||
osg::Vec3d oldOffset = eye - mCenter;
|
osg::Vec3d oldOffset = eye - mCenter;
|
||||||
osg::Vec3d newOffset = rotation * oldOffset;
|
osg::Vec3d newOffset = rotation * oldOffset;
|
||||||
|
|
||||||
|
if (mConstRoll)
|
||||||
|
up = rotation * up;
|
||||||
|
|
||||||
getCamera()->setViewMatrixAsLookAt(mCenter + newOffset, mCenter, up);
|
getCamera()->setViewMatrixAsLookAt(mCenter + newOffset, mCenter, up);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,8 @@ namespace CSVRender
|
||||||
/// \brief Flag controller to be re-initialized.
|
/// \brief Flag controller to be re-initialized.
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
void setConstRoll(bool enable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
@ -181,6 +183,8 @@ namespace CSVRender
|
||||||
double mOrbitSpeed;
|
double mOrbitSpeed;
|
||||||
double mOrbitSpeedMult;
|
double mOrbitSpeedMult;
|
||||||
|
|
||||||
|
bool mConstRoll;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void naviPrimary(bool active);
|
void naviPrimary(bool active);
|
||||||
|
|
|
@ -26,6 +26,33 @@
|
||||||
#include "terrainstorage.hpp"
|
#include "terrainstorage.hpp"
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class CellNodeContainer : public osg::Referenced
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CellNodeContainer(Cell* cell) : mCell(cell) {}
|
||||||
|
|
||||||
|
Cell* getCell(){ return mCell; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Cell* mCell;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CellNodeCallback : public osg::NodeCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||||
|
{
|
||||||
|
CellNodeContainer* container = static_cast<CellNodeContainer*>(node->getUserData());
|
||||||
|
container->getCell()->updateLand();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
bool CSVRender::Cell::removeObject (const std::string& id)
|
bool CSVRender::Cell::removeObject (const std::string& id)
|
||||||
{
|
{
|
||||||
std::map<std::string, Object *>::iterator iter =
|
std::map<std::string, Object *>::iterator iter =
|
||||||
|
@ -75,10 +102,69 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::updateLand()
|
||||||
|
{
|
||||||
|
if (!mUpdateLand || mLandDeleted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mUpdateLand = false;
|
||||||
|
|
||||||
|
// Cell is deleted
|
||||||
|
if (mDeleted)
|
||||||
|
{
|
||||||
|
unloadLand();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup land if available
|
||||||
|
const CSMWorld::IdCollection<CSMWorld::Land>& land = mData.getLand();
|
||||||
|
int landIndex = land.searchId(mId);
|
||||||
|
if (landIndex != -1 && !land.getRecord(mId).isDeleted())
|
||||||
|
{
|
||||||
|
const ESM::Land& esmLand = land.getRecord(mId).get();
|
||||||
|
|
||||||
|
if (esmLand.getLandData (ESM::Land::DATA_VHGT))
|
||||||
|
{
|
||||||
|
if (mTerrain)
|
||||||
|
{
|
||||||
|
mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY());
|
||||||
|
mTerrain->clearAssociatedCaches();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode,
|
||||||
|
mData.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain));
|
||||||
|
}
|
||||||
|
|
||||||
|
mTerrain->loadCell(esmLand.mX, esmLand.mY);
|
||||||
|
|
||||||
|
if (!mCellBorder)
|
||||||
|
mCellBorder.reset(new CellBorder(mCellNode, mCoordinates));
|
||||||
|
|
||||||
|
mCellBorder->buildShape(esmLand);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No land data
|
||||||
|
mLandDeleted = true;
|
||||||
|
unloadLand();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::unloadLand()
|
||||||
|
{
|
||||||
|
if (mTerrain)
|
||||||
|
mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY());
|
||||||
|
|
||||||
|
if (mCellBorder)
|
||||||
|
mCellBorder.reset();
|
||||||
|
}
|
||||||
|
|
||||||
CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id,
|
CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id,
|
||||||
bool deleted)
|
bool deleted)
|
||||||
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0),
|
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0),
|
||||||
mSubModeElementMask (0)
|
mSubModeElementMask (0), mUpdateLand(true), mLandDeleted(false)
|
||||||
{
|
{
|
||||||
std::pair<CSMWorld::CellCoordinates, bool> result = CSMWorld::CellCoordinates::fromId (id);
|
std::pair<CSMWorld::CellCoordinates, bool> result = CSMWorld::CellCoordinates::fromId (id);
|
||||||
|
|
||||||
|
@ -86,6 +172,8 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st
|
||||||
mCoordinates = result.first;
|
mCoordinates = result.first;
|
||||||
|
|
||||||
mCellNode = new osg::Group;
|
mCellNode = new osg::Group;
|
||||||
|
mCellNode->setUserData(new CellNodeContainer(this));
|
||||||
|
mCellNode->setUpdateCallback(new CellNodeCallback);
|
||||||
rootNode->addChild(mCellNode);
|
rootNode->addChild(mCellNode);
|
||||||
|
|
||||||
setCellMarker();
|
setCellMarker();
|
||||||
|
@ -99,22 +187,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st
|
||||||
|
|
||||||
addObjects (0, rows-1);
|
addObjects (0, rows-1);
|
||||||
|
|
||||||
const CSMWorld::IdCollection<CSMWorld::Land>& land = mData.getLand();
|
updateLand();
|
||||||
int landIndex = land.searchId(mId);
|
|
||||||
if (landIndex != -1)
|
|
||||||
{
|
|
||||||
const ESM::Land& esmLand = land.getRecord(mId).get();
|
|
||||||
|
|
||||||
if (esmLand.getLandData (ESM::Land::DATA_VHGT))
|
|
||||||
{
|
|
||||||
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, data.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain));
|
|
||||||
mTerrain->loadCell(esmLand.mX,
|
|
||||||
esmLand.mY);
|
|
||||||
|
|
||||||
mCellBorder.reset(new CellBorder(mCellNode, mCoordinates));
|
|
||||||
mCellBorder->buildShape(esmLand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates));
|
mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates));
|
||||||
mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates));
|
mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates));
|
||||||
|
@ -285,6 +358,38 @@ void CSVRender::Cell::pathgridRemoved()
|
||||||
mPathgrid->removeGeometry();
|
mPathgrid->removeGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
mUpdateLand = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
mLandDeleted = true;
|
||||||
|
unloadLand();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
mUpdateLand = true;
|
||||||
|
mLandDeleted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
mUpdateLand = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
mUpdateLand = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
mUpdateLand = true;
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::Cell::reloadAssets()
|
void CSVRender::Cell::reloadAssets()
|
||||||
{
|
{
|
||||||
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
|
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
|
||||||
|
|
|
@ -57,6 +57,7 @@ namespace CSVRender
|
||||||
bool mDeleted;
|
bool mDeleted;
|
||||||
int mSubMode;
|
int mSubMode;
|
||||||
unsigned int mSubModeElementMask;
|
unsigned int mSubModeElementMask;
|
||||||
|
bool mUpdateLand, mLandDeleted;
|
||||||
|
|
||||||
/// Ignored if cell does not have an object with the given ID.
|
/// Ignored if cell does not have an object with the given ID.
|
||||||
///
|
///
|
||||||
|
@ -72,6 +73,9 @@ namespace CSVRender
|
||||||
/// \return Have any objects been added?
|
/// \return Have any objects been added?
|
||||||
bool addObjects (int start, int end);
|
bool addObjects (int start, int end);
|
||||||
|
|
||||||
|
void updateLand();
|
||||||
|
void unloadLand();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Selection
|
enum Selection
|
||||||
|
@ -118,6 +122,18 @@ namespace CSVRender
|
||||||
|
|
||||||
void pathgridRemoved();
|
void pathgridRemoved();
|
||||||
|
|
||||||
|
void landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
|
||||||
|
void landAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void landAdded (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
|
||||||
|
void landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void landTextureAdded (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
void reloadAssets();
|
void reloadAssets();
|
||||||
|
|
||||||
void setSelection (int elementMask, Selection mode);
|
void setSelection (int elementMask, Selection mode);
|
||||||
|
@ -145,6 +161,8 @@ namespace CSVRender
|
||||||
/// Erase all overrides and restore the visual representation of the cell to its
|
/// Erase all overrides and restore the visual representation of the cell to its
|
||||||
/// true state.
|
/// true state.
|
||||||
void reset (unsigned int elementMask);
|
void reset (unsigned int elementMask);
|
||||||
|
|
||||||
|
friend class CellNodeCallback;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <osg/Depth>
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
#include <osg/PositionAttitudeTransform>
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
#include "../../model/world/universalid.hpp"
|
#include "../../model/world/universalid.hpp"
|
||||||
#include "../../model/world/commandmacro.hpp"
|
#include "../../model/world/commandmacro.hpp"
|
||||||
#include "../../model/world/cellcoordinates.hpp"
|
#include "../../model/world/cellcoordinates.hpp"
|
||||||
|
#include "../../model/prefs/state.hpp"
|
||||||
|
|
||||||
#include <components/resource/scenemanager.hpp>
|
#include <components/resource/scenemanager.hpp>
|
||||||
#include <components/sceneutil/lightutil.hpp>
|
#include <components/sceneutil/lightutil.hpp>
|
||||||
|
@ -220,7 +222,7 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeMoveOrScaleMarker (int axis)
|
||||||
|
|
||||||
for (int i=0; i<2; ++i)
|
for (int i=0; i<2; ++i)
|
||||||
{
|
{
|
||||||
float length = i ? shaftLength : 0;
|
float length = i ? shaftLength : MarkerShaftWidth;
|
||||||
|
|
||||||
vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, -MarkerShaftWidth/2, length, axis));
|
vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, -MarkerShaftWidth/2, length, axis));
|
||||||
vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, MarkerShaftWidth/2, length, axis));
|
vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, MarkerShaftWidth/2, length, axis));
|
||||||
|
@ -285,15 +287,15 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeMoveOrScaleMarker (int axis)
|
||||||
|
|
||||||
for (int i=0; i<8; ++i)
|
for (int i=0; i<8; ++i)
|
||||||
colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f,
|
colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f,
|
||||||
axis==2 ? 1.0f : 0.2f, 1.0f));
|
axis==2 ? 1.0f : 0.2f, mMarkerTransparency));
|
||||||
|
|
||||||
for (int i=8; i<8+4+1; ++i)
|
for (int i=8; i<8+4+1; ++i)
|
||||||
colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.0f, axis==1 ? 1.0f : 0.0f,
|
colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.0f, axis==1 ? 1.0f : 0.0f,
|
||||||
axis==2 ? 1.0f : 0.0f, 1.0f));
|
axis==2 ? 1.0f : 0.0f, mMarkerTransparency));
|
||||||
|
|
||||||
geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX);
|
geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX);
|
||||||
|
|
||||||
geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF);
|
setupCommonMarkerState(geometry);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
||||||
geode->addDrawable (geometry);
|
geode->addDrawable (geometry);
|
||||||
|
@ -305,11 +307,11 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
{
|
{
|
||||||
const float Pi = 3.14159265f;
|
const float Pi = 3.14159265f;
|
||||||
|
|
||||||
const float InnerRadius = mBaseNode->getBound().radius();
|
const float InnerRadius = std::max(MarkerShaftBaseLength, mBaseNode->getBound().radius());
|
||||||
const float OuterRadius = InnerRadius + MarkerShaftWidth;
|
const float OuterRadius = InnerRadius + MarkerShaftWidth;
|
||||||
|
|
||||||
const float SegmentDistance = 100.f;
|
const float SegmentDistance = 100.f;
|
||||||
const size_t SegmentCount = std::min(64, std::max(8, (int)(OuterRadius * 2 * Pi / SegmentDistance)));
|
const size_t SegmentCount = std::min(64, std::max(24, (int)(OuterRadius * 2 * Pi / SegmentDistance)));
|
||||||
const size_t VerticesPerSegment = 4;
|
const size_t VerticesPerSegment = 4;
|
||||||
const size_t IndicesPerSegment = 24;
|
const size_t IndicesPerSegment = 24;
|
||||||
|
|
||||||
|
@ -334,6 +336,9 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
osg::ref_ptr<osg::DrawElementsUShort> primitives = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES,
|
osg::ref_ptr<osg::DrawElementsUShort> primitives = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES,
|
||||||
IndexCount);
|
IndexCount);
|
||||||
|
|
||||||
|
// prevent some depth collision issues from overlaps
|
||||||
|
osg::Vec3f offset = getMarkerPosition(0, MarkerShaftWidth/4, 0, axis);
|
||||||
|
|
||||||
for (size_t i = 0; i < SegmentCount; ++i)
|
for (size_t i = 0; i < SegmentCount; ++i)
|
||||||
{
|
{
|
||||||
size_t index = i * VerticesPerSegment;
|
size_t index = i * VerticesPerSegment;
|
||||||
|
@ -344,13 +349,17 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
float outerX = OuterRadius * std::cos(i * Angle);
|
float outerX = OuterRadius * std::cos(i * Angle);
|
||||||
float outerY = OuterRadius * std::sin(i * Angle);
|
float outerY = OuterRadius * std::sin(i * Angle);
|
||||||
|
|
||||||
vertices->at(index++) = getMarkerPosition(innerX, innerY, MarkerShaftWidth / 2, axis);
|
vertices->at(index++) = getMarkerPosition(innerX, innerY, MarkerShaftWidth / 2, axis) + offset;
|
||||||
vertices->at(index++) = getMarkerPosition(innerX, innerY, -MarkerShaftWidth / 2, axis);
|
vertices->at(index++) = getMarkerPosition(innerX, innerY, -MarkerShaftWidth / 2, axis) + offset;
|
||||||
vertices->at(index++) = getMarkerPosition(outerX, outerY, MarkerShaftWidth / 2, axis);
|
vertices->at(index++) = getMarkerPosition(outerX, outerY, MarkerShaftWidth / 2, axis) + offset;
|
||||||
vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis);
|
vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis) + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
colors->at(0) = osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f, axis==2 ? 1.0f : 0.2f, 1.0f);
|
colors->at(0) = osg::Vec4f (
|
||||||
|
axis==0 ? 1.0f : 0.2f,
|
||||||
|
axis==1 ? 1.0f : 0.2f,
|
||||||
|
axis==2 ? 1.0f : 0.2f,
|
||||||
|
mMarkerTransparency);
|
||||||
|
|
||||||
for (size_t i = 0; i < SegmentCount; ++i)
|
for (size_t i = 0; i < SegmentCount; ++i)
|
||||||
{
|
{
|
||||||
|
@ -374,7 +383,7 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
geometry->setColorArray(colors, osg::Array::BIND_OVERALL);
|
geometry->setColorArray(colors, osg::Array::BIND_OVERALL);
|
||||||
geometry->addPrimitiveSet(primitives);
|
geometry->addPrimitiveSet(primitives);
|
||||||
|
|
||||||
geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF);
|
setupCommonMarkerState(geometry);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
|
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
|
||||||
geode->addDrawable (geometry);
|
geode->addDrawable (geometry);
|
||||||
|
@ -382,6 +391,15 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
return geode;
|
return geode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::Object::setupCommonMarkerState(osg::ref_ptr<osg::Geometry> geometry)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::StateSet> state = geometry->getOrCreateStateSet();
|
||||||
|
state->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||||
|
state->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||||
|
}
|
||||||
|
|
||||||
osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis)
|
osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis)
|
||||||
{
|
{
|
||||||
switch (axis)
|
switch (axis)
|
||||||
|
@ -399,7 +417,7 @@ osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int
|
||||||
CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
|
CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
|
||||||
const std::string& id, bool referenceable, bool forceBaseToZero)
|
const std::string& id, bool referenceable, bool forceBaseToZero)
|
||||||
: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero),
|
: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero),
|
||||||
mScaleOverride (1), mOverrideFlags (0), mSubMode (-1)
|
mScaleOverride (1), mOverrideFlags (0), mSubMode (-1), mMarkerTransparency(0.5f)
|
||||||
{
|
{
|
||||||
mRootNode = new osg::PositionAttitudeTransform;
|
mRootNode = new osg::PositionAttitudeTransform;
|
||||||
|
|
||||||
|
@ -453,6 +471,7 @@ void CSVRender::Object::setSelected(bool selected)
|
||||||
else
|
else
|
||||||
mRootNode->addChild(mBaseNode);
|
mRootNode->addChild(mBaseNode);
|
||||||
|
|
||||||
|
mMarkerTransparency = CSMPrefs::get()["Rendering"]["object-marker-alpha"].toDouble();
|
||||||
updateMarker();
|
updateMarker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,6 +648,12 @@ void CSVRender::Object::setScale (float scale)
|
||||||
adjustTransform();
|
adjustTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::Object::setMarkerTransparency(float value)
|
||||||
|
{
|
||||||
|
mMarkerTransparency = value;
|
||||||
|
updateMarker();
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::Object::apply (CSMWorld::CommandMacro& commands)
|
void CSVRender::Object::apply (CSMWorld::CommandMacro& commands)
|
||||||
{
|
{
|
||||||
const CSMWorld::RefCollection& collection = mData.getReferences();
|
const CSMWorld::RefCollection& collection = mData.getReferences();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
#include <osg/Geometry>
|
||||||
#include <osg/Referenced>
|
#include <osg/Referenced>
|
||||||
|
|
||||||
#include <components/esm/defs.hpp>
|
#include <components/esm/defs.hpp>
|
||||||
|
@ -96,6 +97,7 @@ namespace CSVRender
|
||||||
int mOverrideFlags;
|
int mOverrideFlags;
|
||||||
osg::ref_ptr<osg::Node> mMarker[3];
|
osg::ref_ptr<osg::Node> mMarker[3];
|
||||||
int mSubMode;
|
int mSubMode;
|
||||||
|
float mMarkerTransparency;
|
||||||
|
|
||||||
/// Not implemented
|
/// Not implemented
|
||||||
Object (const Object&);
|
Object (const Object&);
|
||||||
|
@ -121,6 +123,9 @@ namespace CSVRender
|
||||||
osg::ref_ptr<osg::Node> makeMoveOrScaleMarker (int axis);
|
osg::ref_ptr<osg::Node> makeMoveOrScaleMarker (int axis);
|
||||||
osg::ref_ptr<osg::Node> makeRotateMarker (int axis);
|
osg::ref_ptr<osg::Node> makeRotateMarker (int axis);
|
||||||
|
|
||||||
|
/// Sets up a stateset with properties common to all marker types.
|
||||||
|
void setupCommonMarkerState(osg::ref_ptr<osg::Geometry> geometry);
|
||||||
|
|
||||||
osg::Vec3f getMarkerPosition (float x, float y, float z, int axis);
|
osg::Vec3f getMarkerPosition (float x, float y, float z, int axis);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -179,6 +184,8 @@ namespace CSVRender
|
||||||
/// Set override scale
|
/// Set override scale
|
||||||
void setScale (float scale);
|
void setScale (float scale);
|
||||||
|
|
||||||
|
void setMarkerTransparency(float value);
|
||||||
|
|
||||||
/// Apply override changes via command and end edit mode
|
/// Apply override changes via command and end edit mode
|
||||||
void apply (CSMWorld::CommandMacro& commands);
|
void apply (CSMWorld::CommandMacro& commands);
|
||||||
|
|
||||||
|
|
|
@ -351,6 +351,72 @@ void CSVRender::PagedWorldspaceWidget::pathgridAdded(const QModelIndex& parent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
for (int r = topLeft.row(); r <= bottomRight.row(); ++r)
|
||||||
|
{
|
||||||
|
std::string id = mDocument.getData().getLand().getId(r);
|
||||||
|
|
||||||
|
auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first);
|
||||||
|
if (cellIt != mCells.end())
|
||||||
|
{
|
||||||
|
cellIt->second->landDataChanged(topLeft, bottomRight);
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::landAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
for (int r = start; r <= end; ++r)
|
||||||
|
{
|
||||||
|
std::string id = mDocument.getData().getLand().getId(r);
|
||||||
|
|
||||||
|
auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first);
|
||||||
|
if (cellIt != mCells.end())
|
||||||
|
{
|
||||||
|
cellIt->second->landAboutToBeRemoved(parent, start, end);
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::landAdded (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
for (int r = start; r <= end; ++r)
|
||||||
|
{
|
||||||
|
std::string id = mDocument.getData().getLand().getId(r);
|
||||||
|
|
||||||
|
auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first);
|
||||||
|
if (cellIt != mCells.end())
|
||||||
|
{
|
||||||
|
cellIt->second->landAdded(parent, start, end);
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::landTextureDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
for (auto cellIt : mCells)
|
||||||
|
cellIt.second->landTextureChanged(topLeft, bottomRight);
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
for (auto cellIt : mCells)
|
||||||
|
cellIt.second->landTextureAboutToBeRemoved(parent, start, end);
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::landTextureAdded (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
for (auto cellIt : mCells)
|
||||||
|
cellIt.second->landTextureAdded(parent, start, end);
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
|
std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
|
||||||
{
|
{
|
||||||
|
@ -475,6 +541,24 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc
|
||||||
connect (&document.getData(), SIGNAL (assetTablesChanged ()),
|
connect (&document.getData(), SIGNAL (assetTablesChanged ()),
|
||||||
this, SLOT (assetTablesChanged ()));
|
this, SLOT (assetTablesChanged ()));
|
||||||
|
|
||||||
|
QAbstractItemModel *lands = document.getData().getTableModel (CSMWorld::UniversalId::Type_Lands);
|
||||||
|
|
||||||
|
connect (lands, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||||
|
this, SLOT (landDataChanged (const QModelIndex&, const QModelIndex&)));
|
||||||
|
connect (lands, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
|
this, SLOT (landAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
|
connect (lands, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||||
|
this, SLOT (landAdded (const QModelIndex&, int, int)));
|
||||||
|
|
||||||
|
QAbstractItemModel *ltexs = document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures);
|
||||||
|
|
||||||
|
connect (ltexs, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||||
|
this, SLOT (landTextureDataChanged (const QModelIndex&, const QModelIndex&)));
|
||||||
|
connect (ltexs, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
|
this, SLOT (landTextureAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
|
connect (ltexs, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||||
|
this, SLOT (landTextureAdded (const QModelIndex&, int, int)));
|
||||||
|
|
||||||
// Shortcuts
|
// Shortcuts
|
||||||
CSMPrefs::Shortcut* loadCameraCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-cell", this);
|
CSMPrefs::Shortcut* loadCameraCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-cell", this);
|
||||||
connect(loadCameraCellShortcut, SIGNAL(activated()), this, SLOT(loadCameraCell()));
|
connect(loadCameraCellShortcut, SIGNAL(activated()), this, SLOT(loadCameraCell()));
|
||||||
|
|
|
@ -155,6 +155,14 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual void cellAdded (const QModelIndex& index, int start, int end);
|
virtual void cellAdded (const QModelIndex& index, int start, int end);
|
||||||
|
|
||||||
|
virtual void landDataChanged (const QModelIndex& topLeft, const QModelIndex& botomRight);
|
||||||
|
virtual void landAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
virtual void landAdded (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
virtual void landTextureDataChanged (const QModelIndex& topLeft, const QModelIndex& botomRight);
|
||||||
|
virtual void landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
virtual void landTextureAdded (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
void assetTablesChanged ();
|
void assetTablesChanged ();
|
||||||
|
|
||||||
void loadCameraCell();
|
void loadCameraCell();
|
||||||
|
|
|
@ -56,6 +56,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f)
|
||||||
traits->vsync = false;
|
traits->vsync = false;
|
||||||
|
|
||||||
mView = new osgViewer::View;
|
mView = new osgViewer::View;
|
||||||
|
updateCameraParameters( traits->width / static_cast<double>(traits->height) );
|
||||||
|
|
||||||
osg::ref_ptr<osgQt::GraphicsWindowQt> window = new osgQt::GraphicsWindowQt(traits.get());
|
osg::ref_ptr<osgQt::GraphicsWindowQt> window = new osgQt::GraphicsWindowQt(traits.get());
|
||||||
QLayout* layout = new QHBoxLayout(this);
|
QLayout* layout = new QHBoxLayout(this);
|
||||||
|
@ -66,7 +67,6 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f)
|
||||||
mView->getCamera()->setGraphicsContext(window);
|
mView->getCamera()->setGraphicsContext(window);
|
||||||
mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) );
|
mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) );
|
||||||
mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
|
mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
|
||||||
mView->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 1.0f, 10000.0f );
|
|
||||||
|
|
||||||
SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager;
|
SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager;
|
||||||
lightMgr->setStartLight(1);
|
lightMgr->setStartLight(1);
|
||||||
|
@ -188,6 +188,8 @@ SceneWidget::SceneWidget(std::shared_ptr<Resource::ResourceSystem> resourceSyste
|
||||||
|
|
||||||
mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain);
|
mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain);
|
||||||
|
|
||||||
|
mOrbitCamControl->setConstRoll( CSMPrefs::get()["3D Scene Input"]["navi-orbit-const-roll"].isTrue() );
|
||||||
|
|
||||||
// we handle lighting manually
|
// we handle lighting manually
|
||||||
mView->setLightingMode(osgViewer::View::NO_LIGHT);
|
mView->setLightingMode(osgViewer::View::NO_LIGHT);
|
||||||
|
|
||||||
|
@ -370,6 +372,40 @@ void SceneWidget::settingChanged (const CSMPrefs::Setting *setting)
|
||||||
{
|
{
|
||||||
mOrbitCamControl->setOrbitSpeedMultiplier(setting->toDouble());
|
mOrbitCamControl->setOrbitSpeedMultiplier(setting->toDouble());
|
||||||
}
|
}
|
||||||
|
else if (*setting=="3D Scene Input/navi-orbit-const-roll")
|
||||||
|
{
|
||||||
|
mOrbitCamControl->setConstRoll(setting->isTrue());
|
||||||
|
}
|
||||||
|
else if (*setting=="Rendering/camera-fov" ||
|
||||||
|
*setting=="Rendering/camera-ortho" ||
|
||||||
|
*setting=="Rendering/camera-ortho-size")
|
||||||
|
{
|
||||||
|
updateCameraParameters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderWidget::updateCameraParameters(double overrideAspect)
|
||||||
|
{
|
||||||
|
const float nearDist = 1.0;
|
||||||
|
const float farDist = 1000.0;
|
||||||
|
|
||||||
|
if (CSMPrefs::get()["Rendering"]["camera-ortho"].isTrue())
|
||||||
|
{
|
||||||
|
const float size = CSMPrefs::get()["Rendering"]["camera-ortho-size"].toInt();
|
||||||
|
const float aspect = overrideAspect >= 0.0 ? overrideAspect : (width() / static_cast<double>(height()));
|
||||||
|
const float halfH = size * 10.0;
|
||||||
|
const float halfW = halfH * aspect;
|
||||||
|
|
||||||
|
mView->getCamera()->setProjectionMatrixAsOrtho(
|
||||||
|
-halfW, halfW, -halfH, halfH, nearDist, farDist);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mView->getCamera()->setProjectionMatrixAsPerspective(
|
||||||
|
CSMPrefs::get()["Rendering"]["camera-fov"].toInt(),
|
||||||
|
static_cast<double>(width())/static_cast<double>(height()),
|
||||||
|
nearDist, farDist);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneWidget::selectNavigationMode (const std::string& mode)
|
void SceneWidget::selectNavigationMode (const std::string& mode)
|
||||||
|
|
|
@ -64,6 +64,8 @@ namespace CSVRender
|
||||||
osg::ref_ptr<osgViewer::View> mView;
|
osg::ref_ptr<osgViewer::View> mView;
|
||||||
osg::ref_ptr<osg::Group> mRootNode;
|
osg::ref_ptr<osg::Group> mRootNode;
|
||||||
|
|
||||||
|
void updateCameraParameters(double overrideAspect = -1.0);
|
||||||
|
|
||||||
QTimer mTimer;
|
QTimer mTimer;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#include "terrainstorage.hpp"
|
#include "terrainstorage.hpp"
|
||||||
|
|
||||||
|
#include "../../model/world/land.hpp"
|
||||||
|
#include "../../model/world/landtexture.hpp"
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -11,12 +14,9 @@ namespace CSVRender
|
||||||
|
|
||||||
osg::ref_ptr<const ESMTerrain::LandObject> TerrainStorage::getLand(int cellX, int cellY)
|
osg::ref_ptr<const ESMTerrain::LandObject> TerrainStorage::getLand(int cellX, int cellY)
|
||||||
{
|
{
|
||||||
std::ostringstream stream;
|
|
||||||
stream << "#" << cellX << " " << cellY;
|
|
||||||
|
|
||||||
// The cell isn't guaranteed to have Land. This is because the terrain implementation
|
// The cell isn't guaranteed to have Land. This is because the terrain implementation
|
||||||
// has to wrap the vertices of the last row and column to the next cell, which may be a nonexisting cell
|
// has to wrap the vertices of the last row and column to the next cell, which may be a nonexisting cell
|
||||||
int index = mData.getLand().searchId(stream.str());
|
int index = mData.getLand().searchId(CSMWorld::Land::createUniqueRecordId(cellX, cellY));
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -26,16 +26,11 @@ namespace CSVRender
|
||||||
|
|
||||||
const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin)
|
const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin)
|
||||||
{
|
{
|
||||||
int numRecords = mData.getLandTextures().getSize();
|
int row = mData.getLandTextures().searchId(CSMWorld::LandTexture::createUniqueRecordId(plugin, index));
|
||||||
|
if (row == -1)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
for (int i=0; i<numRecords; ++i)
|
return &mData.getLandTextures().getRecord(row).get();
|
||||||
{
|
|
||||||
const CSMWorld::LandTexture* ltex = &mData.getLandTextures().getRecord(i).get();
|
|
||||||
if (ltex->mIndex == index && ltex->mPluginIndex == plugin)
|
|
||||||
return ltex;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY)
|
void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY)
|
||||||
|
|
|
@ -51,6 +51,7 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
|
||||||
, mToolTipPos (-1, -1)
|
, mToolTipPos (-1, -1)
|
||||||
, mShowToolTips(false)
|
, mShowToolTips(false)
|
||||||
, mToolTipDelay(0)
|
, mToolTipDelay(0)
|
||||||
|
, mInConstructor(true)
|
||||||
{
|
{
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
||||||
|
@ -114,6 +115,8 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
|
||||||
|
|
||||||
CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this);
|
CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this);
|
||||||
connect(abortShortcut, SIGNAL(activated()), this, SLOT(abortDrag()));
|
connect(abortShortcut, SIGNAL(activated()), this, SLOT(abortDrag()));
|
||||||
|
|
||||||
|
mInConstructor = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVRender::WorldspaceWidget::~WorldspaceWidget ()
|
CSVRender::WorldspaceWidget::~WorldspaceWidget ()
|
||||||
|
@ -128,6 +131,17 @@ void CSVRender::WorldspaceWidget::settingChanged (const CSMPrefs::Setting *setti
|
||||||
mDragWheelFactor = setting->toDouble();
|
mDragWheelFactor = setting->toDouble();
|
||||||
else if (*setting=="3D Scene Input/drag-shift-factor")
|
else if (*setting=="3D Scene Input/drag-shift-factor")
|
||||||
mDragShiftFactor = setting->toDouble();
|
mDragShiftFactor = setting->toDouble();
|
||||||
|
else if (*setting=="Rendering/object-marker-alpha" && !mInConstructor)
|
||||||
|
{
|
||||||
|
float alpha = setting->toDouble();
|
||||||
|
// getSelection is virtual, thus this can not be called from the constructor
|
||||||
|
auto selection = getSelection(Mask_Reference);
|
||||||
|
for (osg::ref_ptr<TagBase> tag : selection)
|
||||||
|
{
|
||||||
|
if (auto objTag = dynamic_cast<ObjectTag*>(tag.get()))
|
||||||
|
objTag->mObject->setMarkerTransparency(alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (*setting=="Tooltips/scene-delay")
|
else if (*setting=="Tooltips/scene-delay")
|
||||||
mToolTipDelay = setting->toInt();
|
mToolTipDelay = setting->toInt();
|
||||||
else if (*setting=="Tooltips/scene")
|
else if (*setting=="Tooltips/scene")
|
||||||
|
|
|
@ -65,6 +65,7 @@ namespace CSVRender
|
||||||
QPoint mToolTipPos;
|
QPoint mToolTipPos;
|
||||||
bool mShowToolTips;
|
bool mShowToolTips;
|
||||||
int mToolTipDelay;
|
int mToolTipDelay;
|
||||||
|
bool mInConstructor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,15 @@ void CSVWorld::ColorDelegate::paint(QPainter *painter,
|
||||||
const QStyleOptionViewItem &option,
|
const QStyleOptionViewItem &option,
|
||||||
const QModelIndex &index) const
|
const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
|
int colorInt = index.data().toInt();
|
||||||
|
QColor color(colorInt & 0xff, (colorInt >> 8) & 0xff, (colorInt >> 16) & 0xff);
|
||||||
|
|
||||||
QRect coloredRect(option.rect.x() + qRound(option.rect.width() / 4.0),
|
QRect coloredRect(option.rect.x() + qRound(option.rect.width() / 4.0),
|
||||||
option.rect.y() + qRound(option.rect.height() / 4.0),
|
option.rect.y() + qRound(option.rect.height() / 4.0),
|
||||||
option.rect.width() / 2,
|
option.rect.width() / 2,
|
||||||
option.rect.height() / 2);
|
option.rect.height() / 2);
|
||||||
painter->save();
|
painter->save();
|
||||||
painter->fillRect(coloredRect, index.data().value<QColor>());
|
painter->fillRect(coloredRect, color);
|
||||||
painter->setPen(Qt::black);
|
painter->setPen(Qt::black);
|
||||||
painter->drawRect(coloredRect);
|
painter->drawRect(coloredRect);
|
||||||
painter->restore();
|
painter->restore();
|
||||||
|
|
|
@ -31,6 +31,9 @@ namespace CSVWorld
|
||||||
virtual void cloneMode(const std::string& originId,
|
virtual void cloneMode(const std::string& originId,
|
||||||
const CSMWorld::UniversalId::Type type) = 0;
|
const CSMWorld::UniversalId::Type type) = 0;
|
||||||
|
|
||||||
|
/// Touches a record, if the creator supports it.
|
||||||
|
virtual void touch(const std::vector<CSMWorld::UniversalId>& ids) = 0;
|
||||||
|
|
||||||
virtual void setEditLock (bool locked) = 0;
|
virtual void setEditLock (bool locked) = 0;
|
||||||
|
|
||||||
virtual void toggleWidgets(bool active = true) = 0;
|
virtual void toggleWidgets(bool active = true) = 0;
|
||||||
|
|
|
@ -51,6 +51,11 @@ std::string CSVWorld::GenericCreator::getId() const
|
||||||
return mId->text().toUtf8().constData();
|
return mId->text().toUtf8().constData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CSVWorld::GenericCreator::getClonedId() const
|
||||||
|
{
|
||||||
|
return mClonedId;
|
||||||
|
}
|
||||||
|
|
||||||
std::string CSVWorld::GenericCreator::getIdValidatorResult() const
|
std::string CSVWorld::GenericCreator::getIdValidatorResult() const
|
||||||
{
|
{
|
||||||
std::string errors;
|
std::string errors;
|
||||||
|
@ -254,6 +259,22 @@ void CSVWorld::GenericCreator::cloneMode(const std::string& originId,
|
||||||
mClonedType = type;
|
mClonedType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::GenericCreator::touch(const std::vector<CSMWorld::UniversalId>& ids)
|
||||||
|
{
|
||||||
|
// Combine multiple touch commands into one "macro" command
|
||||||
|
mUndoStack.beginMacro("Touch Records");
|
||||||
|
|
||||||
|
CSMWorld::IdTable& table = dynamic_cast<CSMWorld::IdTable&>(*mData.getTableModel(mListId));
|
||||||
|
for (const CSMWorld::UniversalId& uid : ids)
|
||||||
|
{
|
||||||
|
CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId());
|
||||||
|
mUndoStack.push(touchCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
mUndoStack.endMacro();
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::GenericCreator::toggleWidgets(bool active)
|
void CSVWorld::GenericCreator::toggleWidgets(bool active)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,8 @@ namespace CSVWorld
|
||||||
|
|
||||||
virtual std::string getId() const;
|
virtual std::string getId() const;
|
||||||
|
|
||||||
|
std::string getClonedId() const;
|
||||||
|
|
||||||
virtual std::string getIdValidatorResult() const;
|
virtual std::string getIdValidatorResult() const;
|
||||||
|
|
||||||
/// Allow subclasses to add additional data to \a command.
|
/// Allow subclasses to add additional data to \a command.
|
||||||
|
@ -103,6 +105,8 @@ namespace CSVWorld
|
||||||
virtual void cloneMode(const std::string& originId,
|
virtual void cloneMode(const std::string& originId,
|
||||||
const CSMWorld::UniversalId::Type type);
|
const CSMWorld::UniversalId::Type type);
|
||||||
|
|
||||||
|
virtual void touch(const std::vector<CSMWorld::UniversalId>& ids);
|
||||||
|
|
||||||
virtual std::string getErrors() const;
|
virtual std::string getErrors() const;
|
||||||
///< Return formatted error descriptions for the current state of the creator. if an empty
|
///< Return formatted error descriptions for the current state of the creator. if an empty
|
||||||
/// string is returned, there is no error.
|
/// string is returned, there is no error.
|
||||||
|
|
120
apps/opencs/view/world/landcreator.cpp
Normal file
120
apps/opencs/view/world/landcreator.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
#include "landcreator.hpp"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QSpinBox>
|
||||||
|
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/land.hpp"
|
||||||
|
|
||||||
|
namespace CSVWorld
|
||||||
|
{
|
||||||
|
LandCreator::LandCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id)
|
||||||
|
: GenericCreator(data, undoStack, id)
|
||||||
|
, mXLabel(nullptr)
|
||||||
|
, mYLabel(nullptr)
|
||||||
|
, mX(nullptr)
|
||||||
|
, mY(nullptr)
|
||||||
|
{
|
||||||
|
const int MaxInt = std::numeric_limits<int>::max();
|
||||||
|
const int MinInt = std::numeric_limits<int>::min();
|
||||||
|
|
||||||
|
setManualEditing(false);
|
||||||
|
|
||||||
|
mXLabel = new QLabel("X: ");
|
||||||
|
mX = new QSpinBox();
|
||||||
|
mX->setMinimum(MinInt);
|
||||||
|
mX->setMaximum(MaxInt);
|
||||||
|
insertBeforeButtons(mXLabel, false);
|
||||||
|
insertBeforeButtons(mX, true);
|
||||||
|
|
||||||
|
mYLabel = new QLabel("Y: ");
|
||||||
|
mY = new QSpinBox();
|
||||||
|
mY->setMinimum(MinInt);
|
||||||
|
mY->setMaximum(MaxInt);
|
||||||
|
insertBeforeButtons(mYLabel, false);
|
||||||
|
insertBeforeButtons(mY, true);
|
||||||
|
|
||||||
|
connect (mX, SIGNAL(valueChanged(int)), this, SLOT(coordChanged(int)));
|
||||||
|
connect (mY, SIGNAL(valueChanged(int)), this, SLOT(coordChanged(int)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type)
|
||||||
|
{
|
||||||
|
GenericCreator::cloneMode(originId, type);
|
||||||
|
|
||||||
|
int x = 0, y = 0;
|
||||||
|
CSMWorld::Land::parseUniqueRecordId(originId, x, y);
|
||||||
|
|
||||||
|
mX->setValue(x);
|
||||||
|
mY->setValue(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandCreator::touch(const std::vector<CSMWorld::UniversalId>& ids)
|
||||||
|
{
|
||||||
|
// Combine multiple touch commands into one "macro" command
|
||||||
|
getUndoStack().beginMacro("Touch records");
|
||||||
|
|
||||||
|
CSMWorld::IdTable& lands = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands));
|
||||||
|
CSMWorld::IdTable& ltexs = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures));
|
||||||
|
for (const CSMWorld::UniversalId& uid : ids)
|
||||||
|
{
|
||||||
|
CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId());
|
||||||
|
getUndoStack().push(touchCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
getUndoStack().endMacro();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandCreator::focus()
|
||||||
|
{
|
||||||
|
mX->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandCreator::reset()
|
||||||
|
{
|
||||||
|
GenericCreator::reset();
|
||||||
|
mX->setValue(0);
|
||||||
|
mY->setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LandCreator::getErrors() const
|
||||||
|
{
|
||||||
|
if (getData().getLand().searchId(getId()) >= 0)
|
||||||
|
return "A land with that name already exists.";
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LandCreator::getId() const
|
||||||
|
{
|
||||||
|
return CSMWorld::Land::createUniqueRecordId(mX->value(), mY->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandCreator::pushCommand(std::unique_ptr<CSMWorld::CreateCommand> command, const std::string& id)
|
||||||
|
{
|
||||||
|
if (mCloneMode)
|
||||||
|
{
|
||||||
|
CSMWorld::IdTable& lands = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands));
|
||||||
|
CSMWorld::IdTable& ltexs = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures));
|
||||||
|
|
||||||
|
getUndoStack().beginMacro(("Clone " + id).c_str());
|
||||||
|
getUndoStack().push(command.release());
|
||||||
|
|
||||||
|
CSMWorld::CopyLandTexturesCommand* ltexCopy = new CSMWorld::CopyLandTexturesCommand(lands, ltexs, getClonedId(), getId());
|
||||||
|
getUndoStack().push(ltexCopy);
|
||||||
|
|
||||||
|
getUndoStack().endMacro();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
getUndoStack().push (command.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandCreator::coordChanged(int value)
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
47
apps/opencs/view/world/landcreator.hpp
Normal file
47
apps/opencs/view/world/landcreator.hpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef CSV_WORLD_LANDCREATOR_H
|
||||||
|
#define CSV_WORLD_LANDCREATOR_H
|
||||||
|
|
||||||
|
#include "genericcreator.hpp"
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
class QSpinBox;
|
||||||
|
|
||||||
|
namespace CSVWorld
|
||||||
|
{
|
||||||
|
class LandCreator : public GenericCreator
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QLabel* mXLabel;
|
||||||
|
QLabel* mYLabel;
|
||||||
|
QSpinBox* mX;
|
||||||
|
QSpinBox* mY;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
LandCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id);
|
||||||
|
|
||||||
|
void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override;
|
||||||
|
|
||||||
|
void touch(const std::vector<CSMWorld::UniversalId>& ids) override;
|
||||||
|
|
||||||
|
void focus() override;
|
||||||
|
|
||||||
|
void reset() override;
|
||||||
|
|
||||||
|
std::string getErrors() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
std::string getId() const override;
|
||||||
|
|
||||||
|
void pushCommand(std::unique_ptr<CSMWorld::CreateCommand> command,
|
||||||
|
const std::string& id) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void coordChanged(int value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
101
apps/opencs/view/world/landtexturecreator.cpp
Normal file
101
apps/opencs/view/world/landtexturecreator.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
#include "landtexturecreator.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QSpinBox>
|
||||||
|
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/landtexture.hpp"
|
||||||
|
|
||||||
|
namespace CSVWorld
|
||||||
|
{
|
||||||
|
LandTextureCreator::LandTextureCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id)
|
||||||
|
: GenericCreator(data, undoStack, id)
|
||||||
|
{
|
||||||
|
// One index is reserved for a default texture
|
||||||
|
const size_t MaxIndex = std::numeric_limits<uint16_t>::max() - 1;
|
||||||
|
|
||||||
|
setManualEditing(false);
|
||||||
|
|
||||||
|
QLabel* nameLabel = new QLabel("Name");
|
||||||
|
insertBeforeButtons(nameLabel, false);
|
||||||
|
|
||||||
|
mNameEdit = new QLineEdit(this);
|
||||||
|
insertBeforeButtons(mNameEdit, true);
|
||||||
|
|
||||||
|
QLabel* indexLabel = new QLabel("Index");
|
||||||
|
insertBeforeButtons(indexLabel, false);
|
||||||
|
|
||||||
|
mIndexBox = new QSpinBox(this);
|
||||||
|
mIndexBox->setMinimum(0);
|
||||||
|
mIndexBox->setMaximum(MaxIndex);
|
||||||
|
insertBeforeButtons(mIndexBox, true);
|
||||||
|
|
||||||
|
connect(mNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)));
|
||||||
|
connect(mIndexBox, SIGNAL(valueChanged(int)), this, SLOT(indexChanged(int)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandTextureCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type)
|
||||||
|
{
|
||||||
|
GenericCreator::cloneMode(originId, type);
|
||||||
|
|
||||||
|
CSMWorld::IdTable& table = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(getCollectionId()));
|
||||||
|
|
||||||
|
int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureNickname);
|
||||||
|
mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString()));
|
||||||
|
|
||||||
|
column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex);
|
||||||
|
mIndexBox->setValue((table.data(table.getModelIndex(originId, column)).toInt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandTextureCreator::focus()
|
||||||
|
{
|
||||||
|
mIndexBox->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandTextureCreator::reset()
|
||||||
|
{
|
||||||
|
GenericCreator::reset();
|
||||||
|
mNameEdit->setText("");
|
||||||
|
mIndexBox->setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LandTextureCreator::getErrors() const
|
||||||
|
{
|
||||||
|
if (getData().getLandTextures().searchId(getId()) >= 0)
|
||||||
|
{
|
||||||
|
return "Index is already in use";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandTextureCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const
|
||||||
|
{
|
||||||
|
GenericCreator::configureCreateCommand(command);
|
||||||
|
|
||||||
|
CSMWorld::IdTable& table = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(getCollectionId()));
|
||||||
|
int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureNickname);
|
||||||
|
command.addValue(column, mName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LandTextureCreator::getId() const
|
||||||
|
{
|
||||||
|
return CSMWorld::LandTexture::createUniqueRecordId(0, mIndexBox->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandTextureCreator::nameChanged(const QString& value)
|
||||||
|
{
|
||||||
|
mName = value.toUtf8().constData();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandTextureCreator::indexChanged(int value)
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
49
apps/opencs/view/world/landtexturecreator.hpp
Normal file
49
apps/opencs/view/world/landtexturecreator.hpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#ifndef CSV_WORLD_LANDTEXTURECREATOR_H
|
||||||
|
#define CSV_WORLD_LANDTEXTURECREATOR_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "genericcreator.hpp"
|
||||||
|
|
||||||
|
class QLineEdit;
|
||||||
|
class QSpinBox;
|
||||||
|
|
||||||
|
namespace CSVWorld
|
||||||
|
{
|
||||||
|
class LandTextureCreator : public GenericCreator
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
LandTextureCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id);
|
||||||
|
|
||||||
|
void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override;
|
||||||
|
|
||||||
|
void focus() override;
|
||||||
|
|
||||||
|
void reset() override;
|
||||||
|
|
||||||
|
std::string getErrors() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void configureCreateCommand(CSMWorld::CreateCommand& command) const override;
|
||||||
|
|
||||||
|
std::string getId() const override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void nameChanged(const QString& val);
|
||||||
|
void indexChanged(int val);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QLineEdit* mNameEdit;
|
||||||
|
QSpinBox* mIndexBox;
|
||||||
|
|
||||||
|
std::string mName;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -18,6 +18,8 @@
|
||||||
#include "pathgridcreator.hpp"
|
#include "pathgridcreator.hpp"
|
||||||
#include "previewsubview.hpp"
|
#include "previewsubview.hpp"
|
||||||
#include "bodypartcreator.hpp"
|
#include "bodypartcreator.hpp"
|
||||||
|
#include "landcreator.hpp"
|
||||||
|
#include "landtexturecreator.hpp"
|
||||||
|
|
||||||
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||||
{
|
{
|
||||||
|
@ -81,6 +83,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||||
manager.add (CSMWorld::UniversalId::Type_Pathgrids,
|
manager.add (CSMWorld::UniversalId::Type_Pathgrids,
|
||||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, PathgridCreatorFactory>);
|
new CSVDoc::SubViewFactoryWithCreator<TableSubView, PathgridCreatorFactory>);
|
||||||
|
|
||||||
|
manager.add (CSMWorld::UniversalId::Type_Lands,
|
||||||
|
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandCreator> >);
|
||||||
|
|
||||||
|
manager.add (CSMWorld::UniversalId::Type_LandTextures,
|
||||||
|
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandTextureCreator> >);
|
||||||
|
|
||||||
manager.add (CSMWorld::UniversalId::Type_Globals,
|
manager.add (CSMWorld::UniversalId::Type_Globals,
|
||||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GlobalCreator> >);
|
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GlobalCreator> >);
|
||||||
|
|
||||||
|
@ -181,6 +189,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||||
manager.add (CSMWorld::UniversalId::Type_Pathgrid,
|
manager.add (CSMWorld::UniversalId::Type_Pathgrid,
|
||||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, PathgridCreatorFactory> (false));
|
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, PathgridCreatorFactory> (false));
|
||||||
|
|
||||||
|
manager.add (CSMWorld::UniversalId::Type_Land,
|
||||||
|
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandCreator> >(false));
|
||||||
|
|
||||||
|
manager.add (CSMWorld::UniversalId::Type_LandTexture,
|
||||||
|
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandTextureCreator> >(false));
|
||||||
|
|
||||||
manager.add (CSMWorld::UniversalId::Type_DebugProfile,
|
manager.add (CSMWorld::UniversalId::Type_DebugProfile,
|
||||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false));
|
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false));
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "../../model/world/idtableproxymodel.hpp"
|
#include "../../model/world/idtableproxymodel.hpp"
|
||||||
#include "../../model/world/idtablebase.hpp"
|
#include "../../model/world/idtablebase.hpp"
|
||||||
#include "../../model/world/idtable.hpp"
|
#include "../../model/world/idtable.hpp"
|
||||||
|
#include "../../model/world/landtexturetableproxymodel.hpp"
|
||||||
#include "../../model/world/record.hpp"
|
#include "../../model/world/record.hpp"
|
||||||
#include "../../model/world/columns.hpp"
|
#include "../../model/world/columns.hpp"
|
||||||
#include "../../model/world/commanddispatcher.hpp"
|
#include "../../model/world/commanddispatcher.hpp"
|
||||||
|
@ -60,6 +61,9 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
||||||
menu.addAction(mCloneAction);
|
menu.addAction(mCloneAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mTouchAction)
|
||||||
|
menu.addAction (mTouchAction);
|
||||||
|
|
||||||
if (mCreateAction)
|
if (mCreateAction)
|
||||||
menu.addAction (mCreateAction);
|
menu.addAction (mCreateAction);
|
||||||
|
|
||||||
|
@ -226,17 +230,22 @@ void CSVWorld::Table::mouseDoubleClickEvent (QMouseEvent *event)
|
||||||
|
|
||||||
CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
|
CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
|
||||||
bool createAndDelete, bool sorting, CSMDoc::Document& document)
|
bool createAndDelete, bool sorting, CSMDoc::Document& document)
|
||||||
: DragRecordTable(document), mCreateAction (0),
|
: DragRecordTable(document), mCreateAction (nullptr), mCloneAction(nullptr), mTouchAction(nullptr),
|
||||||
mCloneAction(0), mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false)
|
mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false)
|
||||||
{
|
{
|
||||||
mModel = &dynamic_cast<CSMWorld::IdTableBase&> (*mDocument.getData().getTableModel (id));
|
mModel = &dynamic_cast<CSMWorld::IdTableBase&> (*mDocument.getData().getTableModel (id));
|
||||||
|
|
||||||
bool isInfoTable = id.getType() == CSMWorld::UniversalId::Type_TopicInfos ||
|
bool isInfoTable = id.getType() == CSMWorld::UniversalId::Type_TopicInfos ||
|
||||||
id.getType() == CSMWorld::UniversalId::Type_JournalInfos;
|
id.getType() == CSMWorld::UniversalId::Type_JournalInfos;
|
||||||
|
bool isLtexTable = (id.getType() == CSMWorld::UniversalId::Type_LandTextures);
|
||||||
if (isInfoTable)
|
if (isInfoTable)
|
||||||
{
|
{
|
||||||
mProxyModel = new CSMWorld::InfoTableProxyModel(id.getType(), this);
|
mProxyModel = new CSMWorld::InfoTableProxyModel(id.getType(), this);
|
||||||
}
|
}
|
||||||
|
else if (isLtexTable)
|
||||||
|
{
|
||||||
|
mProxyModel = new CSMWorld::LandTextureTableProxyModel (this);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mProxyModel = new CSMWorld::IdTableProxyModel (this);
|
mProxyModel = new CSMWorld::IdTableProxyModel (this);
|
||||||
|
@ -302,6 +311,15 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
|
||||||
cloneShortcut->associateAction(mCloneAction);
|
cloneShortcut->associateAction(mCloneAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch)
|
||||||
|
{
|
||||||
|
mTouchAction = new QAction(tr("Touch Record"), this);
|
||||||
|
connect(mTouchAction, SIGNAL(triggered()), this, SLOT(touchRecord()));
|
||||||
|
addAction(mTouchAction);
|
||||||
|
CSMPrefs::Shortcut* touchShortcut = new CSMPrefs::Shortcut("table-touch", this);
|
||||||
|
touchShortcut->associateAction(mTouchAction);
|
||||||
|
}
|
||||||
|
|
||||||
mRevertAction = new QAction (tr ("Revert Record"), this);
|
mRevertAction = new QAction (tr ("Revert Record"), this);
|
||||||
connect (mRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeRevert()));
|
connect (mRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeRevert()));
|
||||||
addAction (mRevertAction);
|
addAction (mRevertAction);
|
||||||
|
@ -442,6 +460,22 @@ void CSVWorld::Table::cloneRecord()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::Table::touchRecord()
|
||||||
|
{
|
||||||
|
if (!mEditLock && mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch)
|
||||||
|
{
|
||||||
|
std::vector<CSMWorld::UniversalId> touchIds;
|
||||||
|
|
||||||
|
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||||
|
for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it)
|
||||||
|
{
|
||||||
|
touchIds.push_back(getUniversalId(it->row()));
|
||||||
|
}
|
||||||
|
|
||||||
|
emit touchRequest(touchIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::Table::moveUpRecord()
|
void CSVWorld::Table::moveUpRecord()
|
||||||
{
|
{
|
||||||
if (mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant))
|
if (mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant))
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace CSVWorld
|
||||||
QAction *mEditAction;
|
QAction *mEditAction;
|
||||||
QAction *mCreateAction;
|
QAction *mCreateAction;
|
||||||
QAction *mCloneAction;
|
QAction *mCloneAction;
|
||||||
|
QAction *mTouchAction;
|
||||||
QAction *mRevertAction;
|
QAction *mRevertAction;
|
||||||
QAction *mDeleteAction;
|
QAction *mDeleteAction;
|
||||||
QAction *mMoveUpAction;
|
QAction *mMoveUpAction;
|
||||||
|
@ -115,6 +116,8 @@ namespace CSVWorld
|
||||||
|
|
||||||
void cloneRequest(const CSMWorld::UniversalId&);
|
void cloneRequest(const CSMWorld::UniversalId&);
|
||||||
|
|
||||||
|
void touchRequest(const std::vector<CSMWorld::UniversalId>& ids);
|
||||||
|
|
||||||
void closeRequest();
|
void closeRequest();
|
||||||
|
|
||||||
void extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds);
|
void extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds);
|
||||||
|
@ -129,6 +132,8 @@ namespace CSVWorld
|
||||||
|
|
||||||
void cloneRecord();
|
void cloneRecord();
|
||||||
|
|
||||||
|
void touchRecord();
|
||||||
|
|
||||||
void moveUpRecord();
|
void moveUpRecord();
|
||||||
|
|
||||||
void moveDownRecord();
|
void moveDownRecord();
|
||||||
|
|
|
@ -249,6 +249,11 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id,
|
||||||
mCreator->focus();
|
mCreator->focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::TableBottomBox::touchRequest(const std::vector<CSMWorld::UniversalId>& ids)
|
||||||
|
{
|
||||||
|
mCreator->touch(ids);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::TableBottomBox::extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds)
|
void CSVWorld::TableBottomBox::extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds)
|
||||||
{
|
{
|
||||||
extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete, selectedIds);
|
extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete, selectedIds);
|
||||||
|
|
|
@ -102,6 +102,7 @@ namespace CSVWorld
|
||||||
void createRequest();
|
void createRequest();
|
||||||
void cloneRequest(const std::string& id,
|
void cloneRequest(const std::string& id,
|
||||||
const CSMWorld::UniversalId::Type type);
|
const CSMWorld::UniversalId::Type type);
|
||||||
|
void touchRequest(const std::vector<CSMWorld::UniversalId>&);
|
||||||
|
|
||||||
void extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds);
|
void extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds);
|
||||||
void extendedRevertConfigRequest(const std::vector<std::string> &selectedIds);
|
void extendedRevertConfigRequest(const std::vector<std::string> &selectedIds);
|
||||||
|
|
|
@ -69,6 +69,9 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
||||||
connect (this, SIGNAL(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)),
|
connect (this, SIGNAL(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)),
|
||||||
mBottom, SLOT(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)));
|
mBottom, SLOT(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)));
|
||||||
|
|
||||||
|
connect (mTable, SIGNAL(touchRequest(const std::vector<CSMWorld::UniversalId>&)),
|
||||||
|
mBottom, SLOT(touchRequest(const std::vector<CSMWorld::UniversalId>&)));
|
||||||
|
|
||||||
connect (mTable, SIGNAL(extendedDeleteConfigRequest(const std::vector<std::string> &)),
|
connect (mTable, SIGNAL(extendedDeleteConfigRequest(const std::vector<std::string> &)),
|
||||||
mBottom, SLOT(extendedDeleteConfigRequest(const std::vector<std::string> &)));
|
mBottom, SLOT(extendedDeleteConfigRequest(const std::vector<std::string> &)));
|
||||||
connect (mTable, SIGNAL(extendedRevertConfigRequest(const std::vector<std::string> &)),
|
connect (mTable, SIGNAL(extendedRevertConfigRequest(const std::vector<std::string> &)),
|
||||||
|
|
|
@ -1,26 +1,29 @@
|
||||||
#include <RakPeerInterface.h>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
#include <boost/iostreams/concepts.hpp>
|
||||||
|
#include <boost/iostreams/stream_buffer.hpp>
|
||||||
|
|
||||||
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
#include <components/files/escape.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/version/version.hpp>
|
||||||
|
|
||||||
|
#include <components/openmw-mp/Log.hpp>
|
||||||
|
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||||
|
#include <components/openmw-mp/Version.hpp>
|
||||||
|
|
||||||
#include <BitStream.h>
|
#include <BitStream.h>
|
||||||
|
#include <MessageIdentifiers.h>
|
||||||
|
#include <RakPeer.h>
|
||||||
|
#include <RakPeerInterface.h>
|
||||||
|
|
||||||
#include "Player.hpp"
|
#include "Player.hpp"
|
||||||
#include "Networking.hpp"
|
#include "Networking.hpp"
|
||||||
#include "MasterClient.hpp"
|
#include "MasterClient.hpp"
|
||||||
#include <RakPeer.h>
|
|
||||||
#include <MessageIdentifiers.h>
|
|
||||||
#include <components/openmw-mp/Log.hpp>
|
|
||||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
|
||||||
#include <apps/openmw-mp/Script/Script.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <components/files/configurationmanager.hpp>
|
|
||||||
#include <components/settings/settings.hpp>
|
|
||||||
#include <boost/iostreams/concepts.hpp>
|
|
||||||
#include <boost/iostreams/stream_buffer.hpp>
|
|
||||||
#include <boost/filesystem/fstream.hpp>
|
|
||||||
#include <components/openmw-mp/Version.hpp>
|
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
|
||||||
#include "MasterClient.hpp"
|
#include <apps/openmw-mp/Script/Script.hpp>
|
||||||
|
|
||||||
#include <components/version/version.hpp>
|
|
||||||
#include <components/files/escape.hpp>
|
|
||||||
|
|
||||||
#ifdef ENABLE_BREAKPAD
|
#ifdef ENABLE_BREAKPAD
|
||||||
#include <handler/exception_handler.h>
|
#include <handler/exception_handler.h>
|
||||||
|
@ -29,41 +32,6 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace mwmp;
|
using namespace mwmp;
|
||||||
|
|
||||||
void printVersion(string version, Version::Version ver, int protocol)
|
|
||||||
{
|
|
||||||
cout << "TES3:MP dedicated server " << version;
|
|
||||||
cout << " (";
|
|
||||||
#if defined(_WIN32)
|
|
||||||
cout << "Windows";
|
|
||||||
#elif defined(__linux)
|
|
||||||
cout << "Linux";
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
cout << "OS X";
|
|
||||||
#else
|
|
||||||
cout << "Unknown OS";
|
|
||||||
#endif
|
|
||||||
cout << " ";
|
|
||||||
#ifdef __x86_64__
|
|
||||||
cout << "64-bit";
|
|
||||||
#elif defined(__i386__) || defined(_M_I86)
|
|
||||||
cout << "32-bit";
|
|
||||||
#elif defined(__ARM_ARCH)
|
|
||||||
cout << "ARMv" << __ARM_ARCH << " ";
|
|
||||||
#ifdef __aarch64__
|
|
||||||
cout << "64-bit";
|
|
||||||
#else
|
|
||||||
cout << "32-bit";
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
cout << "Unknown architecture";
|
|
||||||
#endif
|
|
||||||
cout << ")" << endl;
|
|
||||||
cout << "Protocol version: " << protocol << endl;
|
|
||||||
cout << "Commit hash: " << ver.mCommitHash.substr(0, 10) << endl;
|
|
||||||
|
|
||||||
cout << "------------------------------------------------------------" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_BREAKPAD
|
#ifdef ENABLE_BREAKPAD
|
||||||
google_breakpad::ExceptionHandler *pHandler = 0;
|
google_breakpad::ExceptionHandler *pHandler = 0;
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
@ -230,9 +198,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
vector<string> plugins (Utils::split(mgr.getString("plugins", "Plugins"), ','));
|
vector<string> plugins (Utils::split(mgr.getString("plugins", "Plugins"), ','));
|
||||||
|
|
||||||
|
Utils::printVersion("TES3MP dedicated server", TES3MP_VERSION, version.mCommitHash, TES3MP_PROTO_VERSION);
|
||||||
printVersion(TES3MP_VERSION, version, TES3MP_PROTO_VERSION);
|
|
||||||
|
|
||||||
|
|
||||||
setenv("AMXFILE", moddir.c_str(), 1);
|
setenv("AMXFILE", moddir.c_str(), 1);
|
||||||
setenv("MOD_DIR", moddir.c_str(), 1); // hack for lua
|
setenv("MOD_DIR", moddir.c_str(), 1); // hack for lua
|
||||||
|
|
|
@ -42,7 +42,7 @@ add_openmw_dir (mwgui
|
||||||
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
||||||
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
||||||
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
|
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
|
||||||
draganddrop timeadvancer jailscreen itemchargeview
|
draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwdialogue
|
add_openmw_dir (mwdialogue
|
||||||
|
@ -57,7 +57,8 @@ add_openmw_dir (mwscript
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwsound
|
add_openmw_dir (mwsound
|
||||||
soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output loudness movieaudiofactory
|
soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output
|
||||||
|
loudness movieaudiofactory alext efx efx-presets
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwworld
|
add_openmw_dir (mwworld
|
||||||
|
@ -131,7 +132,7 @@ add_openmw_dir (mwmp/processors/world BaseObjectProcessor ProcessorConsoleComman
|
||||||
# Main executable
|
# Main executable
|
||||||
|
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID)
|
||||||
add_executable(tes3mp
|
openmw_add_executable(tes3mp
|
||||||
${OPENMW_FILES}
|
${OPENMW_FILES}
|
||||||
${GAME} ${GAME_HEADER}
|
${GAME} ${GAME_HEADER}
|
||||||
${APPLE_BUNDLE_RESOURCES}
|
${APPLE_BUNDLE_RESOURCES}
|
||||||
|
|
|
@ -108,12 +108,14 @@ void OMW::Engine::executeLocalScripts()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OMW::Engine::frame(float frametime)
|
bool OMW::Engine::frame(float frametime)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mStartTick = mViewer->getStartTick();
|
mStartTick = mViewer->getStartTick();
|
||||||
|
|
||||||
|
mEnvironment.setFrameDuration(frametime);
|
||||||
|
|
||||||
// update input
|
// update input
|
||||||
mEnvironment.getInputManager()->update(frametime, false);
|
mEnvironment.getInputManager()->update(frametime, false);
|
||||||
|
|
||||||
|
@ -127,7 +129,7 @@ void OMW::Engine::frame(float frametime)
|
||||||
The game cannot be paused in multiplayer, so prevent that from happening even here
|
The game cannot be paused in multiplayer, so prevent that from happening even here
|
||||||
*/
|
*/
|
||||||
//if (!mEnvironment.getInputManager()->isWindowVisible())
|
//if (!mEnvironment.getInputManager()->isWindowVisible())
|
||||||
// return;
|
// return false;
|
||||||
/*
|
/*
|
||||||
End of tes3mp change (major)
|
End of tes3mp change (major)
|
||||||
*/
|
*/
|
||||||
|
@ -240,11 +242,6 @@ void OMW::Engine::frame(float frametime)
|
||||||
|
|
||||||
// update GUI
|
// update GUI
|
||||||
mEnvironment.getWindowManager()->onFrame(frametime);
|
mEnvironment.getWindowManager()->onFrame(frametime);
|
||||||
if (mEnvironment.getStateManager()->getState()!=
|
|
||||||
MWBase::StateManager::State_NoGame)
|
|
||||||
{
|
|
||||||
mEnvironment.getWindowManager()->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
||||||
osg::Stats* stats = mViewer->getViewerStats();
|
osg::Stats* stats = mViewer->getViewerStats();
|
||||||
|
@ -271,8 +268,9 @@ void OMW::Engine::frame(float frametime)
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "Error in framelistener: " << e.what() << std::endl;
|
std::cerr << "Error in frame: " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
||||||
|
@ -831,6 +829,22 @@ void OMW::Engine::go()
|
||||||
frameTimer.setStartTick();
|
frameTimer.setStartTick();
|
||||||
dt = std::min(dt, 0.2);
|
dt = std::min(dt, 0.2);
|
||||||
|
|
||||||
|
mViewer->advance(simulationTime);
|
||||||
|
|
||||||
|
if (!frame(dt))
|
||||||
|
{
|
||||||
|
OpenThreads::Thread::microSleep(5000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mViewer->eventTraversal();
|
||||||
|
mViewer->updateTraversal();
|
||||||
|
|
||||||
|
mEnvironment.getWorld()->updateWindowManager();
|
||||||
|
|
||||||
|
mViewer->renderingTraversals();
|
||||||
|
|
||||||
bool guiActive = mEnvironment.getWindowManager()->isGuiMode();
|
bool guiActive = mEnvironment.getWindowManager()->isGuiMode();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -846,26 +860,6 @@ void OMW::Engine::go()
|
||||||
|
|
||||||
if (!guiActive)
|
if (!guiActive)
|
||||||
simulationTime += dt;
|
simulationTime += dt;
|
||||||
|
|
||||||
mViewer->advance(simulationTime);
|
|
||||||
|
|
||||||
mEnvironment.setFrameDuration(dt);
|
|
||||||
|
|
||||||
frame(dt);
|
|
||||||
|
|
||||||
if (!mEnvironment.getInputManager()->isWindowVisible())
|
|
||||||
{
|
|
||||||
OpenThreads::Thread::microSleep(5000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mViewer->eventTraversal();
|
|
||||||
mViewer->updateTraversal();
|
|
||||||
|
|
||||||
mEnvironment.getWorld()->updateWindowManager();
|
|
||||||
|
|
||||||
mViewer->renderingTraversals();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mEnvironment.limitFrameRate(frameTimer.time_s());
|
mEnvironment.limitFrameRate(frameTimer.time_s());
|
||||||
|
|
|
@ -118,7 +118,7 @@ namespace OMW
|
||||||
|
|
||||||
void executeLocalScripts();
|
void executeLocalScripts();
|
||||||
|
|
||||||
void frame (float dt);
|
bool frame (float dt);
|
||||||
|
|
||||||
/// Load settings from various files, returns the path to the user settings file
|
/// Load settings from various files, returns the path to the user settings file
|
||||||
std::string loadSettings (Settings::Manager & settings);
|
std::string loadSettings (Settings::Manager & settings);
|
||||||
|
|
|
@ -49,9 +49,11 @@ extern int is_debugger_attached(void);
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
Include the header of the logger added for multiplayer
|
Include additional headers for multiplayer purposes
|
||||||
*/
|
*/
|
||||||
#include <components/openmw-mp/Log.hpp>
|
#include <components/openmw-mp/Log.hpp>
|
||||||
|
#include <components/openmw-mp/Utils.hpp>
|
||||||
|
#include <components/openmw-mp/Version.hpp>
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
@ -207,7 +209,26 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
cfgMgr.readConfiguration(variables, desc);
|
cfgMgr.readConfiguration(variables, desc);
|
||||||
|
|
||||||
Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapeHashString>().toStdString());
|
Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapeHashString>().toStdString());
|
||||||
std::cout << v.describe() << std::endl;
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Print the multiplayer version first
|
||||||
|
*/
|
||||||
|
Utils::printVersion("TES3MP client", TES3MP_VERSION, v.mCommitHash, TES3MP_PROTO_VERSION);
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp change (minor)
|
||||||
|
|
||||||
|
Because there is no need to print the commit hash again, only print OpenMW's version
|
||||||
|
*/
|
||||||
|
std::cout << "OpenMW version " << v.mVersion << std::endl;
|
||||||
|
/*
|
||||||
|
End of tes3mp change (minor)
|
||||||
|
*/
|
||||||
|
|
||||||
engine.setGrabMouse(!variables["no-grab"].as<bool>());
|
engine.setGrabMouse(!variables["no-grab"].as<bool>());
|
||||||
|
|
||||||
|
@ -224,6 +245,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
std::string local(variables["data-local"].as<Files::EscapeHashString>().toStdString());
|
std::string local(variables["data-local"].as<Files::EscapeHashString>().toStdString());
|
||||||
if (!local.empty())
|
if (!local.empty())
|
||||||
{
|
{
|
||||||
|
if (local.front() == '\"')
|
||||||
|
local = local.substr(1, local.length() - 2);
|
||||||
|
|
||||||
dataDirs.push_back(Files::PathContainer::value_type(local));
|
dataDirs.push_back(Files::PathContainer::value_type(local));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#define GAME_MWBASE_DIALOGUEMANAGER_H
|
#define GAME_MWBASE_DIALOGUEMANAGER_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -34,6 +36,12 @@ namespace MWBase
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
class ResponseCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void addResponse(const std::string& title, const std::string& text) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
DialogueManager() {}
|
DialogueManager() {}
|
||||||
|
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
@ -42,7 +50,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual bool isInChoice() const = 0;
|
virtual bool isInChoice() const = 0;
|
||||||
|
|
||||||
virtual void startDialogue (const MWWorld::Ptr& actor) = 0;
|
virtual bool startDialogue (const MWWorld::Ptr& actor, ResponseCallback* callback) = 0;
|
||||||
|
|
||||||
virtual void addTopic (const std::string& topic) = 0;
|
virtual void addTopic (const std::string& topic) = 0;
|
||||||
|
|
||||||
|
@ -57,20 +65,24 @@ namespace MWBase
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
virtual void askQuestion (const std::string& question,int choice) = 0;
|
virtual void addChoice (const std::string& text,int choice) = 0;
|
||||||
|
virtual const std::vector<std::pair<std::string, int> >& getChoices() = 0;
|
||||||
|
|
||||||
|
virtual bool isGoodbye() = 0;
|
||||||
|
|
||||||
virtual void goodbye() = 0;
|
virtual void goodbye() = 0;
|
||||||
|
|
||||||
virtual void say(const MWWorld::Ptr &actor, const std::string &topic) = 0;
|
virtual void say(const MWWorld::Ptr &actor, const std::string &topic) = 0;
|
||||||
|
|
||||||
//calbacks for the GUI
|
virtual void keywordSelected (const std::string& keyword, ResponseCallback* callback) = 0;
|
||||||
virtual void keywordSelected (const std::string& keyword) = 0;
|
|
||||||
virtual void goodbyeSelected() = 0;
|
virtual void goodbyeSelected() = 0;
|
||||||
virtual void questionAnswered (int answer) = 0;
|
virtual void questionAnswered (int answer, ResponseCallback* callback) = 0;
|
||||||
|
|
||||||
virtual bool checkServiceRefused () = 0;
|
virtual std::list<std::string> getAvailableTopics() = 0;
|
||||||
|
|
||||||
virtual void persuade (int type) = 0;
|
virtual bool checkServiceRefused (ResponseCallback* callback) = 0;
|
||||||
|
|
||||||
|
virtual void persuade (int type, ResponseCallback* callback) = 0;
|
||||||
virtual int getTemporaryDispositionChange () const = 0;
|
virtual int getTemporaryDispositionChange () const = 0;
|
||||||
|
|
||||||
/// @note This change is temporary and gets discarded when dialogue ends.
|
/// @note This change is temporary and gets discarded when dialogue ends.
|
||||||
|
@ -98,7 +110,7 @@ namespace MWBase
|
||||||
|
|
||||||
Declare this method here so it can be used from outside of MWDialogue::DialogueManager
|
Declare this method here so it can be used from outside of MWDialogue::DialogueManager
|
||||||
*/
|
*/
|
||||||
virtual void updateTopics() = 0;
|
virtual void updateActorKnownTopics() = 0;
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -150,7 +150,7 @@ namespace MWBase
|
||||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||||
/// @param container The container the item is in; may be empty for an item in the world
|
/// @param container The container the item is in; may be empty for an item in the world
|
||||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
||||||
int count) = 0;
|
int count, bool alarm = true) = 0;
|
||||||
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
|
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
|
||||||
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0;
|
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0;
|
||||||
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
|
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
|
||||||
|
@ -201,6 +201,9 @@ namespace MWBase
|
||||||
virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
|
virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
|
||||||
virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects) = 0;
|
virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects) = 0;
|
||||||
|
|
||||||
|
/// Check if there are actors in selected range
|
||||||
|
virtual bool isAnyActorInRange(const osg::Vec3f &position, float radius) = 0;
|
||||||
|
|
||||||
///Returns the list of actors which are siding with the given actor in fights
|
///Returns the list of actors which are siding with the given actor in fights
|
||||||
/**ie AiFollow or AiEscort is active and the target is the actor **/
|
/**ie AiFollow or AiEscort is active and the target is the actor **/
|
||||||
virtual std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor) = 0;
|
virtual std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor) = 0;
|
||||||
|
@ -235,6 +238,10 @@ namespace MWBase
|
||||||
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0;
|
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0;
|
||||||
virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const = 0;
|
virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const = 0;
|
||||||
|
|
||||||
|
/// Check if the target actor was detected by an observer
|
||||||
|
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
||||||
|
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) = 0;
|
||||||
|
|
||||||
virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0;
|
virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0;
|
||||||
|
|
||||||
/// List the owners that the player has stolen this item from (the owner can be an NPC or a faction).
|
/// List the owners that the player has stolen this item from (the owner can be an NPC or a faction).
|
||||||
|
@ -244,7 +251,8 @@ namespace MWBase
|
||||||
/// Has the player stolen this item from the given owner?
|
/// Has the player stolen this item from the given owner?
|
||||||
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0;
|
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0;
|
||||||
|
|
||||||
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) = 0;
|
virtual bool isBoundItem(const MWWorld::Ptr& item) = 0;
|
||||||
|
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) = 0;
|
||||||
|
|
||||||
/// Turn actor into werewolf or normal form.
|
/// Turn actor into werewolf or normal form.
|
||||||
virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0;
|
virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0;
|
||||||
|
@ -256,7 +264,6 @@ namespace MWBase
|
||||||
virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0;
|
virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0;
|
||||||
|
|
||||||
virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0;
|
virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0;
|
||||||
|
|
||||||
virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr) = 0;
|
virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr) = 0;
|
||||||
virtual bool isRunning(const MWWorld::Ptr& ptr) = 0;
|
virtual bool isRunning(const MWWorld::Ptr& ptr) = 0;
|
||||||
virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0;
|
virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0;
|
||||||
|
|
|
@ -18,54 +18,59 @@ namespace MWSound
|
||||||
class Stream;
|
class Stream;
|
||||||
struct Sound_Decoder;
|
struct Sound_Decoder;
|
||||||
typedef std::shared_ptr<Sound_Decoder> DecoderPtr;
|
typedef std::shared_ptr<Sound_Decoder> DecoderPtr;
|
||||||
|
|
||||||
|
/* These must all fit together */
|
||||||
|
enum class PlayMode {
|
||||||
|
Normal = 0, /* non-looping, affected by environment */
|
||||||
|
Loop = 1<<0, /* Sound will continually loop until explicitly stopped */
|
||||||
|
NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */
|
||||||
|
RemoveAtDistance = 1<<2, /* (3D only) If the listener gets further than 2000 units away
|
||||||
|
* from the sound source, the sound is removed.
|
||||||
|
* This is weird stuff but apparently how vanilla works for sounds
|
||||||
|
* played by the PlayLoopSound family of script functions. Perhaps
|
||||||
|
* we can make this cut off a more subtle fade later, but have to
|
||||||
|
* be careful to not change the overall volume of areas by too
|
||||||
|
* much. */
|
||||||
|
NoPlayerLocal = 1<<3, /* (3D only) Don't play the sound local to the listener even if the
|
||||||
|
* player is making it. */
|
||||||
|
LoopNoEnv = Loop | NoEnv,
|
||||||
|
LoopRemoveAtDistance = Loop | RemoveAtDistance
|
||||||
|
};
|
||||||
|
enum class Type {
|
||||||
|
Sfx = 1<<4, /* Normal SFX sound */
|
||||||
|
Voice = 1<<5, /* Voice sound */
|
||||||
|
Foot = 1<<6, /* Footstep sound */
|
||||||
|
Music = 1<<7, /* Music track */
|
||||||
|
Movie = 1<<8, /* Movie audio track */
|
||||||
|
Mask = Sfx | Voice | Foot | Music | Movie
|
||||||
|
};
|
||||||
|
// Used for creating a type mask for SoundManager::pauseSounds and resumeSounds
|
||||||
|
inline int operator~(Type a) { return ~static_cast<int>(a); }
|
||||||
|
inline int operator&(Type a, Type b) { return static_cast<int>(a) & static_cast<int>(b); }
|
||||||
|
inline int operator&(int a, Type b) { return a & static_cast<int>(b); }
|
||||||
|
inline int operator|(Type a, Type b) { return static_cast<int>(a) | static_cast<int>(b); }
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWBase
|
namespace MWBase
|
||||||
{
|
{
|
||||||
typedef std::shared_ptr<MWSound::Sound> SoundPtr;
|
using Sound = MWSound::Sound;
|
||||||
typedef std::shared_ptr<MWSound::Stream> SoundStreamPtr;
|
using SoundStream = MWSound::Stream;
|
||||||
|
|
||||||
/// \brief Interface for sound manager (implemented in MWSound)
|
/// \brief Interface for sound manager (implemented in MWSound)
|
||||||
class SoundManager
|
class SoundManager
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
/* These must all fit together */
|
|
||||||
enum PlayMode {
|
|
||||||
Play_Normal = 0, /* non-looping, affected by environment */
|
|
||||||
Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */
|
|
||||||
Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */
|
|
||||||
Play_RemoveAtDistance = 1<<2, /* (3D only) If the listener gets further than 2000 units away
|
|
||||||
from the sound source, the sound is removed.
|
|
||||||
This is weird stuff but apparently how vanilla works for sounds
|
|
||||||
played by the PlayLoopSound family of script functions. Perhaps we
|
|
||||||
can make this cut off a more subtle fade later, but have to
|
|
||||||
be careful to not change the overall volume of areas by too much. */
|
|
||||||
Play_NoPlayerLocal = 1<<3, /* (3D only) Don't play the sound local to the listener even if the
|
|
||||||
player is making it. */
|
|
||||||
Play_LoopNoEnv = Play_Loop | Play_NoEnv,
|
|
||||||
Play_LoopRemoveAtDistance = Play_Loop | Play_RemoveAtDistance
|
|
||||||
};
|
|
||||||
enum PlayType {
|
|
||||||
Play_TypeSfx = 1<<4, /* Normal SFX sound */
|
|
||||||
Play_TypeVoice = 1<<5, /* Voice sound */
|
|
||||||
Play_TypeFoot = 1<<6, /* Footstep sound */
|
|
||||||
Play_TypeMusic = 1<<7, /* Music track */
|
|
||||||
Play_TypeMovie = 1<<8, /* Movie audio track */
|
|
||||||
Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeFoot|Play_TypeMusic|Play_TypeMovie
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
SoundManager (const SoundManager&);
|
SoundManager (const SoundManager&);
|
||||||
///< not implemented
|
///< not implemented
|
||||||
|
|
||||||
SoundManager& operator= (const SoundManager&);
|
SoundManager& operator= (const SoundManager&);
|
||||||
///< not implemented
|
///< not implemented
|
||||||
|
|
||||||
|
protected:
|
||||||
|
using PlayMode = MWSound::PlayMode;
|
||||||
|
using Type = MWSound::Type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SoundManager() {}
|
SoundManager() {}
|
||||||
|
|
||||||
virtual ~SoundManager() {}
|
virtual ~SoundManager() {}
|
||||||
|
|
||||||
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& settings) = 0;
|
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& settings) = 0;
|
||||||
|
@ -77,9 +82,6 @@ namespace MWBase
|
||||||
///< Play a soundifle
|
///< Play a soundifle
|
||||||
/// \param filename name of a sound file in "Music/" in the data directory.
|
/// \param filename name of a sound file in "Music/" in the data directory.
|
||||||
|
|
||||||
virtual void startRandomTitle() = 0;
|
|
||||||
///< Starts a random track from the current playlist
|
|
||||||
|
|
||||||
virtual bool isMusicPlaying() = 0;
|
virtual bool isMusicPlaying() = 0;
|
||||||
///< Returns true if music is playing
|
///< Returns true if music is playing
|
||||||
|
|
||||||
|
@ -106,34 +108,36 @@ namespace MWBase
|
||||||
/// and get an average loudness value (scale [0,1]) at the current time position.
|
/// and get an average loudness value (scale [0,1]) at the current time position.
|
||||||
/// If the actor is not saying anything, returns 0.
|
/// If the actor is not saying anything, returns 0.
|
||||||
|
|
||||||
virtual SoundStreamPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0;
|
virtual SoundStream *playTrack(const MWSound::DecoderPtr& decoder, Type type) = 0;
|
||||||
///< Play a 2D audio track, using a custom decoder
|
///< Play a 2D audio track, using a custom decoder. The caller is expected to call
|
||||||
|
/// stopTrack with the returned handle when done.
|
||||||
|
|
||||||
virtual void stopTrack(SoundStreamPtr stream) = 0;
|
virtual void stopTrack(SoundStream *stream) = 0;
|
||||||
///< Stop the given audio track from playing
|
///< Stop the given audio track from playing
|
||||||
|
|
||||||
virtual double getTrackTimeDelay(SoundStreamPtr stream) = 0;
|
virtual double getTrackTimeDelay(SoundStream *stream) = 0;
|
||||||
///< Retives the time delay, in seconds, of the audio track (must be a sound
|
///< Retives the time delay, in seconds, of the audio track (must be a sound
|
||||||
/// returned by \ref playTrack). Only intended to be called by the track
|
/// returned by \ref playTrack). Only intended to be called by the track
|
||||||
/// decoder's read method.
|
/// decoder's read method.
|
||||||
|
|
||||||
virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch,
|
virtual Sound *playSound(const std::string& soundId, float volume, float pitch,
|
||||||
PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal,
|
Type type=Type::Sfx, PlayMode mode=PlayMode::Normal,
|
||||||
float offset=0) = 0;
|
float offset=0) = 0;
|
||||||
///< Play a sound, independently of 3D-position
|
///< Play a sound, independently of 3D-position
|
||||||
///< @param offset Number of seconds into the sound to start playback.
|
///< @param offset Number of seconds into the sound to start playback.
|
||||||
|
|
||||||
virtual MWBase::SoundPtr playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId,
|
virtual Sound *playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId,
|
||||||
float volume, float pitch, PlayType type=Play_TypeSfx,
|
float volume, float pitch, Type type=Type::Sfx,
|
||||||
PlayMode mode=Play_Normal, float offset=0) = 0;
|
PlayMode mode=PlayMode::Normal, float offset=0) = 0;
|
||||||
///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified.
|
///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified.
|
||||||
///< @param offset Number of seconds into the sound to start playback.
|
///< @param offset Number of seconds into the sound to start playback.
|
||||||
|
|
||||||
virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId,
|
virtual Sound *playSound3D(const osg::Vec3f& initialPos, const std::string& soundId,
|
||||||
float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0;
|
float volume, float pitch, Type type=Type::Sfx,
|
||||||
|
PlayMode mode=PlayMode::Normal, float offset=0) = 0;
|
||||||
///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition.
|
///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition.
|
||||||
|
|
||||||
virtual void stopSound(SoundPtr sound) = 0;
|
virtual void stopSound(Sound *sound) = 0;
|
||||||
///< Stop the given sound from playing
|
///< Stop the given sound from playing
|
||||||
|
|
||||||
virtual void stopSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId) = 0;
|
virtual void stopSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId) = 0;
|
||||||
|
@ -158,10 +162,10 @@ namespace MWBase
|
||||||
///< Is the given sound currently playing on the given object?
|
///< Is the given sound currently playing on the given object?
|
||||||
/// If you want to check if sound played with playSound is playing, use empty Ptr
|
/// If you want to check if sound played with playSound is playing, use empty Ptr
|
||||||
|
|
||||||
virtual void pauseSounds(int types=Play_TypeMask) = 0;
|
virtual void pauseSounds(int types=static_cast<int>(Type::Mask)) = 0;
|
||||||
///< Pauses all currently playing sounds, including music.
|
///< Pauses all currently playing sounds, including music.
|
||||||
|
|
||||||
virtual void resumeSounds(int types=Play_TypeMask) = 0;
|
virtual void resumeSounds(int types=static_cast<int>(Type::Mask)) = 0;
|
||||||
///< Resumes all previously paused sounds.
|
///< Resumes all previously paused sounds.
|
||||||
|
|
||||||
virtual void update(float duration) = 0;
|
virtual void update(float duration) = 0;
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
#include <MyGUI_KeyCode.h>
|
||||||
|
|
||||||
#include "../mwgui/mode.hpp"
|
#include "../mwgui/mode.hpp"
|
||||||
|
|
||||||
namespace Loading
|
namespace Loading
|
||||||
|
@ -100,23 +102,17 @@ namespace MWBase
|
||||||
|
|
||||||
virtual ~WindowManager() {}
|
virtual ~WindowManager() {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Should be called each frame to update windows/gui elements.
|
|
||||||
* This could mean updating sizes of gui elements or opening
|
|
||||||
* new dialogs.
|
|
||||||
*/
|
|
||||||
virtual void update() = 0;
|
|
||||||
|
|
||||||
/// @note This method will block until the video finishes playing
|
/// @note This method will block until the video finishes playing
|
||||||
/// (and will continually update the window while doing so)
|
/// (and will continually update the window while doing so)
|
||||||
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
|
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
|
||||||
|
|
||||||
virtual void setNewGame(bool newgame) = 0;
|
virtual void setNewGame(bool newgame) = 0;
|
||||||
|
|
||||||
|
virtual void pushGuiMode (MWGui::GuiMode mode, const MWWorld::Ptr& arg) = 0;
|
||||||
virtual void pushGuiMode (MWGui::GuiMode mode) = 0;
|
virtual void pushGuiMode (MWGui::GuiMode mode) = 0;
|
||||||
virtual void popGuiMode() = 0;
|
virtual void popGuiMode(bool noSound=false) = 0;
|
||||||
|
|
||||||
virtual void removeGuiMode (MWGui::GuiMode mode) = 0;
|
virtual void removeGuiMode (MWGui::GuiMode mode, bool noSound=false) = 0;
|
||||||
///< can be anywhere in the stack
|
///< can be anywhere in the stack
|
||||||
|
|
||||||
virtual void goToJail(int days) = 0;
|
virtual void goToJail(int days) = 0;
|
||||||
|
@ -144,7 +140,6 @@ namespace MWBase
|
||||||
virtual bool isAllowed (MWGui::GuiWindow wnd) const = 0;
|
virtual bool isAllowed (MWGui::GuiWindow wnd) const = 0;
|
||||||
|
|
||||||
/// \todo investigate, if we really need to expose every single lousy UI element to the outside world
|
/// \todo investigate, if we really need to expose every single lousy UI element to the outside world
|
||||||
virtual MWGui::DialogueWindow* getDialogueWindow() = 0;
|
|
||||||
virtual MWGui::InventoryWindow* getInventoryWindow() = 0;
|
virtual MWGui::InventoryWindow* getInventoryWindow() = 0;
|
||||||
virtual MWGui::CountDialog* getCountDialog() = 0;
|
virtual MWGui::CountDialog* getCountDialog() = 0;
|
||||||
virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0;
|
virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0;
|
||||||
|
@ -195,6 +190,7 @@ namespace MWBase
|
||||||
virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0;
|
virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0;
|
||||||
|
|
||||||
virtual void setCursorVisible(bool visible) = 0;
|
virtual void setCursorVisible(bool visible) = 0;
|
||||||
|
virtual void setCursorActive(bool active) = 0;
|
||||||
virtual void getMousePosition(int &x, int &y) = 0;
|
virtual void getMousePosition(int &x, int &y) = 0;
|
||||||
virtual void getMousePosition(float &x, float &y) = 0;
|
virtual void getMousePosition(float &x, float &y) = 0;
|
||||||
virtual void setDragDrop(bool dragDrop) = 0;
|
virtual void setDragDrop(bool dragDrop) = 0;
|
||||||
|
@ -259,7 +255,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void showCrosshair(bool show) = 0;
|
virtual void showCrosshair(bool show) = 0;
|
||||||
virtual bool getSubtitlesEnabled() = 0;
|
virtual bool getSubtitlesEnabled() = 0;
|
||||||
virtual bool toggleGui() = 0;
|
virtual bool toggleHud() = 0;
|
||||||
|
|
||||||
virtual void disallowMouse() = 0;
|
virtual void disallowMouse() = 0;
|
||||||
virtual void allowMouse() = 0;
|
virtual void allowMouse() = 0;
|
||||||
|
@ -333,21 +329,6 @@ namespace MWBase
|
||||||
virtual bool getPlayerSleeping() = 0;
|
virtual bool getPlayerSleeping() = 0;
|
||||||
virtual void wakeUpPlayer() = 0;
|
virtual void wakeUpPlayer() = 0;
|
||||||
|
|
||||||
virtual void showCompanionWindow(MWWorld::Ptr actor) = 0;
|
|
||||||
virtual void startSpellMaking(MWWorld::Ptr actor) = 0;
|
|
||||||
virtual void startEnchanting(MWWorld::Ptr actor) = 0;
|
|
||||||
virtual void startRecharge(MWWorld::Ptr soulgem) = 0;
|
|
||||||
virtual void startSelfEnchanting(MWWorld::Ptr soulgem) = 0;
|
|
||||||
virtual void startTraining(MWWorld::Ptr actor) = 0;
|
|
||||||
virtual void startRepair(MWWorld::Ptr actor) = 0;
|
|
||||||
virtual void startRepairItem(MWWorld::Ptr item) = 0;
|
|
||||||
virtual void startTravel(const MWWorld::Ptr& actor) = 0;
|
|
||||||
virtual void startSpellBuying(const MWWorld::Ptr& actor) = 0;
|
|
||||||
virtual void startTrade(const MWWorld::Ptr& actor) = 0;
|
|
||||||
virtual void openContainer(const MWWorld::Ptr& container, bool loot) = 0;
|
|
||||||
virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton) = 0;
|
|
||||||
virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton) = 0;
|
|
||||||
|
|
||||||
virtual void showSoulgemDialog (MWWorld::Ptr item) = 0;
|
virtual void showSoulgemDialog (MWWorld::Ptr item) = 0;
|
||||||
|
|
||||||
virtual void changePointer (const std::string& name) = 0;
|
virtual void changePointer (const std::string& name) = 0;
|
||||||
|
@ -389,11 +370,11 @@ namespace MWBase
|
||||||
virtual void pinWindow (MWGui::GuiWindow window) = 0;
|
virtual void pinWindow (MWGui::GuiWindow window) = 0;
|
||||||
|
|
||||||
/// Fade the screen in, over \a time seconds
|
/// Fade the screen in, over \a time seconds
|
||||||
virtual void fadeScreenIn(const float time, bool clearQueue=true) = 0;
|
virtual void fadeScreenIn(const float time, bool clearQueue=true, float delay=0.f) = 0;
|
||||||
/// Fade the screen out to black, over \a time seconds
|
/// Fade the screen out to black, over \a time seconds
|
||||||
virtual void fadeScreenOut(const float time, bool clearQueue=true) = 0;
|
virtual void fadeScreenOut(const float time, bool clearQueue=true, float delay=0.f) = 0;
|
||||||
/// Fade the screen to a specified percentage of black, over \a time seconds
|
/// Fade the screen to a specified percentage of black, over \a time seconds
|
||||||
virtual void fadeScreenTo(const int percent, const float time, bool clearQueue=true) = 0;
|
virtual void fadeScreenTo(const int percent, const float time, bool clearQueue=true, float delay=0.f) = 0;
|
||||||
/// Darken the screen to a specified percentage
|
/// Darken the screen to a specified percentage
|
||||||
virtual void setBlindness(const int percent) = 0;
|
virtual void setBlindness(const int percent) = 0;
|
||||||
|
|
||||||
|
@ -411,7 +392,7 @@ namespace MWBase
|
||||||
|
|
||||||
// In WindowManager for now since there isn't a VFS singleton
|
// In WindowManager for now since there isn't a VFS singleton
|
||||||
virtual std::string correctIconPath(const std::string& path) = 0;
|
virtual std::string correctIconPath(const std::string& path) = 0;
|
||||||
virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0;
|
virtual std::string correctBookartPath(const std::string& path, int width, int height, bool* exists = nullptr) = 0;
|
||||||
virtual std::string correctTexturePath(const std::string& path) = 0;
|
virtual std::string correctTexturePath(const std::string& path) = 0;
|
||||||
virtual bool textureExists(const std::string& path) = 0;
|
virtual bool textureExists(const std::string& path) = 0;
|
||||||
|
|
||||||
|
@ -419,6 +400,8 @@ namespace MWBase
|
||||||
virtual void writeFog(MWWorld::CellStore* cell) = 0;
|
virtual void writeFog(MWWorld::CellStore* cell) = 0;
|
||||||
|
|
||||||
virtual const MWGui::TextColours& getTextColours() = 0;
|
virtual const MWGui::TextColours& getTextColours() = 0;
|
||||||
|
|
||||||
|
virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -522,8 +522,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual void launchMagicBolt (const std::string& spellId, bool stack, const ESM::EffectList& effects,
|
virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) = 0;
|
||||||
const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0;
|
|
||||||
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
||||||
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0;
|
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0;
|
||||||
|
|
||||||
|
|
|
@ -181,9 +181,7 @@ namespace MWClass
|
||||||
if(isTrapped)
|
if(isTrapped)
|
||||||
{
|
{
|
||||||
ptr.getCellRef().setTrap("");
|
ptr.getCellRef().setTrap("");
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr,
|
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Disarm Trap", 1.0f, 1.0f);
|
||||||
"Disarm Trap", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx,
|
|
||||||
MWBase::SoundManager::Play_Normal);
|
|
||||||
isTrapped = false;
|
isTrapped = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -567,11 +567,11 @@ namespace MWClass
|
||||||
|
|
||||||
// by default user can loot friendly actors during death animation
|
// by default user can loot friendly actors during death animation
|
||||||
if (canLoot && !stats.getAiSequence().isInCombat())
|
if (canLoot && !stats.getAiSequence().isInCombat())
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
|
||||||
|
|
||||||
// otherwise wait until death animation
|
// otherwise wait until death animation
|
||||||
if(stats.isDeathAnimationFinished())
|
if(stats.isDeathAnimationFinished())
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
|
||||||
|
|
||||||
// death animation is not finished, do nothing
|
// death animation is not finished, do nothing
|
||||||
return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
||||||
|
@ -580,6 +580,9 @@ namespace MWClass
|
||||||
if(stats.getAiSequence().isInCombat())
|
if(stats.getAiSequence().isInCombat())
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction(""));
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction(""));
|
||||||
|
|
||||||
|
if(stats.getKnockedDown())
|
||||||
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction(""));
|
||||||
|
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,9 +175,7 @@ namespace MWClass
|
||||||
if(isTrapped)
|
if(isTrapped)
|
||||||
{
|
{
|
||||||
ptr.getCellRef().setTrap("");
|
ptr.getCellRef().setTrap("");
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr,
|
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Disarm Trap", 1.0f, 1.0f);
|
||||||
"Disarm Trap", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx,
|
|
||||||
MWBase::SoundManager::Play_Normal);
|
|
||||||
isTrapped = false;
|
isTrapped = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -49,8 +49,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault))
|
if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault))
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0,
|
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0,
|
||||||
MWBase::SoundManager::Play_TypeSfx,
|
MWSound::Type::Sfx,
|
||||||
MWBase::SoundManager::Play_Loop);
|
MWSound::PlayMode::Loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Light::useAnim() const
|
bool Light::useAnim() const
|
||||||
|
|
|
@ -1008,11 +1008,11 @@ namespace MWClass
|
||||||
|
|
||||||
// by default user can loot friendly actors during death animation
|
// by default user can loot friendly actors during death animation
|
||||||
if (canLoot && !stats.getAiSequence().isInCombat())
|
if (canLoot && !stats.getAiSequence().isInCombat())
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
|
||||||
|
|
||||||
// otherwise wait until death animation
|
// otherwise wait until death animation
|
||||||
if(stats.isDeathAnimationFinished())
|
if(stats.isDeathAnimationFinished())
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
|
||||||
|
|
||||||
// death animation is not finished, do nothing
|
// death animation is not finished, do nothing
|
||||||
return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
||||||
|
@ -1265,6 +1265,15 @@ namespace MWClass
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr);
|
ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr);
|
||||||
|
|
||||||
|
// Take in account armor condition
|
||||||
|
const bool hasHealth = it->getClass().hasItemHealth(*it);
|
||||||
|
if (hasHealth)
|
||||||
|
{
|
||||||
|
int armorHealth = it->getClass().getItemHealth(*it);
|
||||||
|
int armorMaxHealth = it->getClass().getItemMaxHealth(*it);
|
||||||
|
ratings[i] *= (float(armorHealth) / armorMaxHealth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue