mirror of
https://github.com/OpenMW/openmw.git
synced 2025-12-13 08:13:06 +00:00
Merge from upstream master
This commit is contained in:
commit
f0ca3eabd3
461 changed files with 12819 additions and 5534 deletions
11
.editorconfig
Normal file
11
.editorconfig
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*.cpp]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.hpp]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -26,6 +26,8 @@ Doxygen
|
||||||
.settings
|
.settings
|
||||||
.directory
|
.directory
|
||||||
.idea
|
.idea
|
||||||
|
cmake-build-*
|
||||||
|
files/windows/*.aps
|
||||||
## qt-creator
|
## qt-creator
|
||||||
CMakeLists.txt.user*
|
CMakeLists.txt.user*
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ addons:
|
||||||
project:
|
project:
|
||||||
name: "OpenMW/openmw"
|
name: "OpenMW/openmw"
|
||||||
description: "<Your project description here>"
|
description: "<Your project description here>"
|
||||||
notification_email: scrawl@baseoftrash.de
|
notification_email: 720642+scrawl@users.noreply.github.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:
|
||||||
|
|
|
||||||
14
AUTHORS.md
14
AUTHORS.md
|
|
@ -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
|
||||||
|
|
@ -50,6 +52,7 @@ Programmers
|
||||||
Edmondo Tommasina (edmondo)
|
Edmondo Tommasina (edmondo)
|
||||||
Eduard Cot (trombonecot)
|
Eduard Cot (trombonecot)
|
||||||
Eli2
|
Eli2
|
||||||
|
elsid
|
||||||
Emanuel Guével (potatoesmaster)
|
Emanuel Guével (potatoesmaster)
|
||||||
eroen
|
eroen
|
||||||
escondida
|
escondida
|
||||||
|
|
@ -59,10 +62,11 @@ Programmers
|
||||||
Gašper Sedej
|
Gašper Sedej
|
||||||
gugus/gus
|
gugus/gus
|
||||||
Hallfaer Tuilinn
|
Hallfaer Tuilinn
|
||||||
|
Haoda Wang (h313)
|
||||||
hristoast
|
hristoast
|
||||||
Internecine
|
Internecine
|
||||||
Jacob Essex (Yacoby)
|
Jacob Essex (Yacoby)
|
||||||
Jannik Heller (scrawl)
|
Jake Westrip (16bitint)
|
||||||
Jason Hooks (jhooks)
|
Jason Hooks (jhooks)
|
||||||
jeaye
|
jeaye
|
||||||
Jeffrey Haines (Jyby)
|
Jeffrey Haines (Jyby)
|
||||||
|
|
@ -84,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)
|
||||||
|
|
@ -102,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)
|
||||||
|
|
@ -123,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)
|
||||||
|
|
@ -131,12 +138,14 @@ Programmers
|
||||||
Roman Proskuryakov (kpp)
|
Roman Proskuryakov (kpp)
|
||||||
Sandy Carter (bwrsandman)
|
Sandy Carter (bwrsandman)
|
||||||
Scott Howard
|
Scott Howard
|
||||||
|
scrawl
|
||||||
Sebastian Wick (swick)
|
Sebastian Wick (swick)
|
||||||
Sergey Shambir
|
Sergey Shambir
|
||||||
ShadowRadiance
|
ShadowRadiance
|
||||||
Siimacore
|
Siimacore
|
||||||
sir_herrbatka
|
sir_herrbatka
|
||||||
smbas
|
smbas
|
||||||
|
spycrab
|
||||||
Stefan Galowicz (bogglez)
|
Stefan Galowicz (bogglez)
|
||||||
Stanislav Bobrov (Jiub)
|
Stanislav Bobrov (Jiub)
|
||||||
stil-t
|
stil-t
|
||||||
|
|
@ -145,6 +154,7 @@ Programmers
|
||||||
t6
|
t6
|
||||||
terrorfisch
|
terrorfisch
|
||||||
Thomas Luppi (Digmaster)
|
Thomas Luppi (Digmaster)
|
||||||
|
Will Herrmann (Thunderforge)
|
||||||
Tom Mason (wheybags)
|
Tom Mason (wheybags)
|
||||||
Torben Leif Carrington (TorbenC)
|
Torben Leif Carrington (TorbenC)
|
||||||
viadanna
|
viadanna
|
||||||
|
|
|
||||||
79
CHANGELOG.md
79
CHANGELOG.md
|
|
@ -1,3 +1,82 @@
|
||||||
|
0.42.0
|
||||||
|
------
|
||||||
|
|
||||||
|
Bug #1956: Duplicate objects after loading the game, when a mod was edited
|
||||||
|
Bug #2100: Falling leaves in Vurt's Leafy West Gash II not rendered correctly
|
||||||
|
Bug #2116: Cant fit through some doorways pressed against staircases
|
||||||
|
Bug #2289: Some modal dialogs are not centered on the screen when the window resizes
|
||||||
|
Bug #2409: Softlock when pressing weapon/magic switch keys during chargen, afterwards switches weapons even though a text field is selected
|
||||||
|
Bug #2483: Previous/Next Weapon hotkeys triggered while typing the name of game save
|
||||||
|
Bug #2629: centeroncell, coc causes death / fall damage time to time when teleporting from high
|
||||||
|
Bug #2645: Cycling weapons is possible while console/pause menu is open
|
||||||
|
Bug #2678: Combat with water creatures do not end upon exiting water
|
||||||
|
Bug #2759: Light Problems in Therana's Chamber in Tel Branora
|
||||||
|
Bug #2771: unhandled sdl event of type 0x302
|
||||||
|
Bug #2777: (constant/on cast) disintegrate armor/weapon on self is seemingly not working
|
||||||
|
Bug #2838: Editor: '.' in a record name should be allowed
|
||||||
|
Bug #2909: NPCs appear floating when standing on a slope
|
||||||
|
Bug #3093: Controller movement cannot be used while mouse is moving
|
||||||
|
Bug #3134: Crash possible when using console with open container
|
||||||
|
Bug #3254: AI enemies hit between them.
|
||||||
|
Bug #3344: Editor: Verification results sorting by Type is not alphabetical.
|
||||||
|
Bug #3345: Editor: Cloned and added pathgrids are lost after reopen of saved omwgame file
|
||||||
|
Bug #3355: [MGSO] Physics maxing out in south cornerclub Balmora
|
||||||
|
Bug #3484: Editor: camera position is not set when changing cell via drag&drop
|
||||||
|
Bug #3508: Slowfall kills Jump momentum
|
||||||
|
Bug #3580: Crash: Error ElementBufferObject::remove BufferData<0> out of range
|
||||||
|
Bug #3581: NPCs wander too much
|
||||||
|
Bug #3601: Menu Titles not centered vertically
|
||||||
|
Bug #3607: [Mac OS] Beginning of NPC speech cut off (same issue as closed bug #3453)
|
||||||
|
Bug #3613: Can not map "next weapon" or "next spell" to controller
|
||||||
|
Bug #3617: Enchanted arrows don't explode when hitting the ground
|
||||||
|
Bug #3645: Unable to use steps in Vivec, Palace of Vivec
|
||||||
|
Bug #3650: Tamriel Rebuilt 16.09.1 – Hist Cuirass GND nif is rendered inside a Pink Box
|
||||||
|
Bug #3652: Item icon shadows get stuck in the alchemy GUI
|
||||||
|
Bug #3653: Incorrect swish sounds
|
||||||
|
Bug #3666: NPC collision should not be disabled until death animation has finished
|
||||||
|
Bug #3669: Editor: Text field was missing from book object editing dialogue
|
||||||
|
Bug #3670: Unhandled SDL event of type 0x304
|
||||||
|
Bug #3671: Incorrect local variable value after picking up bittercup
|
||||||
|
Bug #3686: Travelling followers doesn't increase travel fee
|
||||||
|
Bug #3689: Problematic greetings from Antares Big Mod that override the appropriate ones.
|
||||||
|
Bug #3690: Certain summoned creatures do not engage in combat with underwater creatures
|
||||||
|
Bug #3691: Enemies do not initiate combat with player followers on sight
|
||||||
|
Bug #3695: [Regression] Dispel does not always dispel spell effects in 0.41
|
||||||
|
Bug #3699: Crash on MWWorld::ProjectileManager::moveMagicBolts
|
||||||
|
Bug #3700: Climbing on rocks and mountains
|
||||||
|
Bug #3704: Creatures don't auto-equip their shields on creation
|
||||||
|
Bug #3705: AI combat engagement logic differs from vanilla
|
||||||
|
Bug #3707: Animation playing does some very odd things if pc comes in contact with the animated mesh
|
||||||
|
Bug #3712: [Mod] Freeze upon entering Adanumuran with mod Adanumuran Reclaimed
|
||||||
|
Bug #3713: [Regression] Cancelling dialogue or using travel with creatures throws a (possibly game-breaking) exception
|
||||||
|
Bug #3719: Dropped identification papers can't be picked up again
|
||||||
|
Bug #3722: Command spell doesn't bring enemies out of combat
|
||||||
|
Bug #3727: Using "Activate" mid-script-execution invalidates interpreter context
|
||||||
|
Bug #3746: Editor: Book records show attribute IDs instead of skill IDs for teached skills entry.
|
||||||
|
Bug #3755: Followers stop following after loading from savegame
|
||||||
|
Bug #3772: ModStat lowers attribute to 100 if it was greater
|
||||||
|
Bug #3781: Guns in Clean Hunter Rifles mod use crossbow sounds
|
||||||
|
Bug #3797: NPC and creature names don't show up in combat when RMB windows are displayed
|
||||||
|
Bug #3800: Wrong tooltip maximum width
|
||||||
|
Bug #3801: Drowning widget is bugged
|
||||||
|
Bug #3802: BarterOffer shouldn't limit pcMercantile
|
||||||
|
Bug #3813: Some fatal error
|
||||||
|
Bug #3816: Expression parser thinks the -> token is unexpected when a given explicit refID clashes with a journal ID
|
||||||
|
Bug #3822: Custom added creatures are not animated
|
||||||
|
Feature #451: Water sounds
|
||||||
|
Feature #2691: Light particles sometimes not shown in inventory character preview
|
||||||
|
Feature #3523: Light source on magic projectiles
|
||||||
|
Feature #3644: Nif NiSphericalCollider Unknown Record Type
|
||||||
|
Feature #3675: ess-Importer: convert mark location
|
||||||
|
Feature #3693: ess-Importer: convert last known exterior cell
|
||||||
|
Feature #3748: Editor: Replace "Scroll" check box in Book records with "Book Type" combo box.
|
||||||
|
Feature #3751: Editor: Replace "Xyz Blood" check boxes in NPC and Creature records with "Blood Type" combo box
|
||||||
|
Feature #3752: Editor: Replace emitter check boxes in Light records with "Emitter Type" combo box
|
||||||
|
Feature #3756: Editor: Replace "Female" check box in NPC records with "Gender" combo box
|
||||||
|
Feature #3757: Editor: Replace "Female" check box in BodyPart records with "Gender" combo box
|
||||||
|
Task #3092: const version of ContainerStoreIterator
|
||||||
|
Task #3795: /deps folder not in .gitignore
|
||||||
|
|
||||||
0.41.0
|
0.41.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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,4 @@ DATE=`date +'%d%m%Y'`
|
||||||
SHORT_COMMIT=`git rev-parse --short ${TRAVIS_COMMIT}`
|
SHORT_COMMIT=`git rev-parse --short ${TRAVIS_COMMIT}`
|
||||||
TARGET_FILENAME="OpenMW-${DATE}-${SHORT_COMMIT}.dmg"
|
TARGET_FILENAME="OpenMW-${DATE}-${SHORT_COMMIT}.dmg"
|
||||||
|
|
||||||
curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "ftp://s3.mydevil.net:21/nightly/${TARGET_FILENAME}"
|
curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "${OSX_FTP_URL}${TARGET_FILENAME}"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,32 @@
|
||||||
|
# Apps and tools
|
||||||
|
option(BUILD_OPENMW "build OpenMW" ON)
|
||||||
|
option(BUILD_BSATOOL "build BSA extractor" ON)
|
||||||
|
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
||||||
|
option(BUILD_LAUNCHER "build Launcher" 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_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 +54,7 @@ endif()
|
||||||
message(STATUS "Configuring OpenMW...")
|
message(STATUS "Configuring OpenMW...")
|
||||||
|
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 41)
|
set(OPENMW_VERSION_MINOR 42)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
|
|
@ -59,21 +88,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_BSATOOL "build BSA extractor" ON)
|
|
||||||
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
|
||||||
option(BUILD_LAUNCHER "build Launcher" 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.
|
||||||
|
|
@ -120,16 +134,8 @@ if (WIN32)
|
||||||
option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON)
|
option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT BUILD_LAUNCHER 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 4 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)
|
||||||
|
|
@ -144,17 +150,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()
|
|
||||||
|
|
||||||
# Sound setup
|
# Sound setup
|
||||||
find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE)
|
find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE)
|
||||||
# Required for building the FFmpeg headers
|
# Required for building the FFmpeg headers
|
||||||
|
|
@ -207,7 +202,7 @@ if(NOT HAVE_STDINT_H)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX)
|
find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX)
|
||||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
|
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
|
||||||
|
|
||||||
set(USED_OSG_PLUGINS
|
set(USED_OSG_PLUGINS
|
||||||
|
|
@ -310,27 +305,28 @@ endif (APPLE)
|
||||||
|
|
||||||
# Other files
|
# Other files
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -408,7 +404,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")
|
||||||
|
|
@ -442,9 +438,9 @@ if(WIN32)
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
||||||
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}/settings-default.cfg"
|
||||||
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
|
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
|
||||||
DESTINATION ".")
|
DESTINATION ".")
|
||||||
|
|
@ -494,6 +490,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/windows/openmw.ico")
|
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
|
||||||
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
|
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
|
||||||
SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
|
SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -7,13 +7,13 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind
|
||||||
|
|
||||||
OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set.
|
OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set.
|
||||||
|
|
||||||
* Version: 0.41.0
|
* Version: 0.42.0
|
||||||
* License: GPLv3 (see [docs/license/GPL3.txt](https://github.com/OpenMW/openmw/blob/master/docs/license/GPL3.txt) for more information)
|
* License: GPLv3 (see [LICENSE](https://github.com/OpenMW/openmw/blob/master/LICENSE) for more information)
|
||||||
* Website: http://www.openmw.org
|
* Website: http://www.openmw.org
|
||||||
* IRC: #openmw on irc.freenode.net
|
* IRC: #openmw on irc.freenode.net
|
||||||
|
|
||||||
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/OpenMW/openmw/blob/master/files/mygui/DejaVu%20Font%20License.txt) for more information)
|
||||||
|
|
||||||
Current Status
|
Current Status
|
||||||
--------------
|
--------------
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,10 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return setup() ? FirstRunDialogResultContinue : FirstRunDialogResultFailure;
|
if (!setup() || !setupGameData()) {
|
||||||
|
return FirstRunDialogResultFailure;
|
||||||
|
}
|
||||||
|
return FirstRunDialogResultContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::MainDialog::setVersionLabel()
|
void Launcher::MainDialog::setVersionLabel()
|
||||||
|
|
@ -344,6 +347,11 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Launcher::MainDialog::setupGameData()
|
||||||
|
{
|
||||||
QStringList dataDirs;
|
QStringList dataDirs;
|
||||||
|
|
||||||
// Check if the paths actually contain data files
|
// Check if the paths actually contain data files
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ namespace Launcher
|
||||||
bool setupLauncherSettings();
|
bool setupLauncherSettings();
|
||||||
bool setupGameSettings();
|
bool setupGameSettings();
|
||||||
bool setupGraphicsSettings();
|
bool setupGraphicsSettings();
|
||||||
|
bool setupGameData();
|
||||||
|
|
||||||
void setVersionLabel();
|
void setVersionLabel();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
@ -199,7 +199,7 @@ if(APPLE)
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
|
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
|
||||||
OUTPUT_NAME ${OPENCS_BUNDLE_NAME}
|
OUTPUT_NAME ${OPENCS_BUNDLE_NAME}
|
||||||
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
|
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
|
||||||
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
|
MACOSX_BUNDLE_BUNDLE_NAME "OpenMW-CS"
|
||||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
|
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
|
||||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION}
|
MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION}
|
||||||
MACOSX_BUNDLE_BUNDLE_VERSION ${OPENMW_VERSION}
|
MACOSX_BUNDLE_BUNDLE_VERSION ${OPENMW_VERSION}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include <components/vfs/manager.hpp>
|
|
||||||
#include <components/vfs/registerarchives.hpp>
|
|
||||||
|
|
||||||
#include <components/fallback/validate.hpp>
|
#include <components/fallback/validate.hpp>
|
||||||
|
|
||||||
#include <components/nifosg/nifloader.hpp>
|
#include <components/nifosg/nifloader.hpp>
|
||||||
|
|
@ -33,11 +30,7 @@ CS::Editor::Editor ()
|
||||||
|
|
||||||
NifOsg::Loader::setShowMarkers(true);
|
NifOsg::Loader::setShowMarkers(true);
|
||||||
|
|
||||||
mVFS.reset(new VFS::Manager(mFsStrict));
|
mDocumentManager.setFileData(mFsStrict, config.first, config.second);
|
||||||
|
|
||||||
VFS::registerArchives(mVFS.get(), Files::Collections(config.first, !mFsStrict), config.second, true);
|
|
||||||
|
|
||||||
mDocumentManager.setVFS(mVFS.get());
|
|
||||||
|
|
||||||
mNewGame.setLocalData (mLocal);
|
mNewGame.setLocalData (mLocal);
|
||||||
mFileDialog.setLocalData (mLocal);
|
mFileDialog.setLocalData (mLocal);
|
||||||
|
|
@ -97,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");
|
||||||
|
|
@ -116,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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,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()
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
#ifndef CS_EDITOR_H
|
#ifndef CS_EDITOR_H
|
||||||
#define CS_EDITOR_H
|
#define CS_EDITOR_H
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <boost/interprocess/sync/file_lock.hpp>
|
#include <boost/interprocess/sync/file_lock.hpp>
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
|
|
@ -30,11 +28,6 @@
|
||||||
|
|
||||||
#include "view/tools/merge.hpp"
|
#include "view/tools/merge.hpp"
|
||||||
|
|
||||||
namespace VFS
|
|
||||||
{
|
|
||||||
class Manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace CSMDoc
|
namespace CSMDoc
|
||||||
{
|
{
|
||||||
class Document;
|
class Document;
|
||||||
|
|
@ -46,9 +39,6 @@ namespace CS
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
// FIXME: should be moved to document, so we can have different resources for each opened project
|
|
||||||
std::unique_ptr<VFS::Manager> mVFS;
|
|
||||||
|
|
||||||
Files::ConfigurationManager mCfgMgr;
|
Files::ConfigurationManager mCfgMgr;
|
||||||
CSMPrefs::State mSettingsState;
|
CSMPrefs::State mSettingsState;
|
||||||
CSMDoc::DocumentManager mDocumentManager;
|
CSMDoc::DocumentManager mDocumentManager;
|
||||||
|
|
|
||||||
|
|
@ -269,13 +269,14 @@ void CSMDoc::Document::createBase()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration,
|
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
||||||
const std::vector< boost::filesystem::path >& files, bool new_,
|
const std::vector< boost::filesystem::path >& files,bool new_,
|
||||||
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
|
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
|
||||||
const Fallback::Map* fallback,
|
const Fallback::Map* fallback,
|
||||||
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
|
ToUTF8::FromType encoding,
|
||||||
const std::vector<std::string>& blacklistedScripts)
|
const std::vector<std::string>& blacklistedScripts,
|
||||||
: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager, fallback, resDir),
|
bool fsStrict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives)
|
||||||
|
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, fsStrict, dataPaths, archives, fallback, resDir),
|
||||||
mTools (*this, encoding),
|
mTools (*this, encoding),
|
||||||
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
||||||
(savePath.filename().string() + ".project")),
|
(savePath.filename().string() + ".project")),
|
||||||
|
|
@ -287,7 +288,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM
|
||||||
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";
|
||||||
|
|
@ -337,11 +338,6 @@ CSMDoc::Document::~Document()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const VFS::Manager *CSMDoc::Document::getVFS() const
|
|
||||||
{
|
|
||||||
return mVFS;
|
|
||||||
}
|
|
||||||
|
|
||||||
QUndoStack& CSMDoc::Document::getUndoStack()
|
QUndoStack& CSMDoc::Document::getUndoStack()
|
||||||
{
|
{
|
||||||
return mUndoStack;
|
return mUndoStack;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <components/files/multidircollection.hpp>
|
||||||
#include <components/to_utf8/to_utf8.hpp>
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
#include "../world/data.hpp"
|
#include "../world/data.hpp"
|
||||||
|
|
@ -59,7 +60,6 @@ namespace CSMDoc
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const VFS::Manager* mVFS;
|
|
||||||
boost::filesystem::path mSavePath;
|
boost::filesystem::path mSavePath;
|
||||||
std::vector<boost::filesystem::path> mContentFiles;
|
std::vector<boost::filesystem::path> mContentFiles;
|
||||||
bool mNew;
|
bool mNew;
|
||||||
|
|
@ -102,17 +102,15 @@ namespace CSMDoc
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration,
|
Document (const Files::ConfigurationManager& configuration,
|
||||||
const std::vector< boost::filesystem::path >& files, bool new_,
|
const std::vector< boost::filesystem::path >& files, bool new_,
|
||||||
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
|
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
|
||||||
const Fallback::Map* fallback,
|
const Fallback::Map* fallback, ToUTF8::FromType encoding,
|
||||||
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
|
const std::vector<std::string>& blacklistedScripts,
|
||||||
const std::vector<std::string>& blacklistedScripts);
|
bool fsStrict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives);
|
||||||
|
|
||||||
~Document();
|
~Document();
|
||||||
|
|
||||||
const VFS::Manager* getVFS() const;
|
|
||||||
|
|
||||||
QUndoStack& getUndoStack();
|
QUndoStack& getUndoStack();
|
||||||
|
|
||||||
int getState() const;
|
int getState() const;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
#include "document.hpp"
|
#include "document.hpp"
|
||||||
|
|
||||||
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
|
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
|
||||||
: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252), mVFS(NULL)
|
: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252)
|
||||||
{
|
{
|
||||||
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
|
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
|
||||||
|
|
||||||
|
|
@ -62,7 +62,7 @@ CSMDoc::Document *CSMDoc::DocumentManager::makeDocument (
|
||||||
const std::vector< boost::filesystem::path >& files,
|
const std::vector< boost::filesystem::path >& files,
|
||||||
const boost::filesystem::path& savePath, bool new_)
|
const boost::filesystem::path& savePath, bool new_)
|
||||||
{
|
{
|
||||||
return new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, &mFallbackMap, mEncoding, mResourcesManager, mBlacklistedScripts);
|
return new Document (mConfiguration, files, new_, savePath, mResDir, &mFallbackMap, mEncoding, mBlacklistedScripts, mFsStrict, mDataPaths, mArchives);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document)
|
void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document)
|
||||||
|
|
@ -127,8 +127,9 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std::
|
||||||
removeDocument (document);
|
removeDocument (document);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMDoc::DocumentManager::setVFS(const VFS::Manager *vfs)
|
void CSMDoc::DocumentManager::setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives)
|
||||||
{
|
{
|
||||||
mResourcesManager.setVFS(vfs);
|
mFsStrict = strict;
|
||||||
mVFS = vfs;
|
mDataPaths = dataPaths;
|
||||||
|
mArchives = archives;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,7 @@
|
||||||
|
|
||||||
#include <components/to_utf8/to_utf8.hpp>
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
#include <components/fallback/fallback.hpp>
|
#include <components/fallback/fallback.hpp>
|
||||||
|
#include <components/files/multidircollection.hpp>
|
||||||
#include "../world/resourcesmanager.hpp"
|
|
||||||
|
|
||||||
#include "loader.hpp"
|
#include "loader.hpp"
|
||||||
|
|
||||||
|
|
@ -39,9 +38,14 @@ namespace CSMDoc
|
||||||
QThread mLoaderThread;
|
QThread mLoaderThread;
|
||||||
Loader mLoader;
|
Loader mLoader;
|
||||||
ToUTF8::FromType mEncoding;
|
ToUTF8::FromType mEncoding;
|
||||||
CSMWorld::ResourcesManager mResourcesManager;
|
|
||||||
std::vector<std::string> mBlacklistedScripts;
|
std::vector<std::string> mBlacklistedScripts;
|
||||||
const VFS::Manager* mVFS;
|
|
||||||
|
boost::filesystem::path mResDir;
|
||||||
|
Fallback::Map mFallbackMap;
|
||||||
|
|
||||||
|
bool mFsStrict;
|
||||||
|
Files::PathContainer mDataPaths;
|
||||||
|
std::vector<std::string> mArchives;
|
||||||
|
|
||||||
DocumentManager (const DocumentManager&);
|
DocumentManager (const DocumentManager&);
|
||||||
DocumentManager& operator= (const DocumentManager&);
|
DocumentManager& operator= (const DocumentManager&);
|
||||||
|
|
@ -74,15 +78,11 @@ namespace CSMDoc
|
||||||
|
|
||||||
void setBlacklistedScripts (const std::vector<std::string>& scriptIds);
|
void setBlacklistedScripts (const std::vector<std::string>& scriptIds);
|
||||||
|
|
||||||
void setVFS(const VFS::Manager* vfs);
|
/// Sets the file data that gets passed to newly created documents.
|
||||||
|
void setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives);
|
||||||
|
|
||||||
bool isEmpty();
|
bool isEmpty();
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
boost::filesystem::path mResDir;
|
|
||||||
Fallback::Map mFallbackMap;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void documentLoaded (Document *document);
|
void documentLoaded (Document *document);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,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());
|
||||||
|
|
@ -259,6 +261,7 @@ void CSMPrefs::State::declare()
|
||||||
declareShortcut ("document-character-topicinfos", "Open Topic Info List", QKeySequence());
|
declareShortcut ("document-character-topicinfos", "Open Topic Info List", QKeySequence());
|
||||||
declareShortcut ("document-character-journalinfos", "Open Journal Info List", QKeySequence());
|
declareShortcut ("document-character-journalinfos", "Open Journal Info List", QKeySequence());
|
||||||
declareShortcut ("document-character-bodyparts", "Open Body Part List", QKeySequence());
|
declareShortcut ("document-character-bodyparts", "Open Body Part List", QKeySequence());
|
||||||
|
declareShortcut ("document-assets-reload", "Reload Assets", QKeySequence(Qt::Key_F5));
|
||||||
declareShortcut ("document-assets-sounds", "Open Sound Asset List", QKeySequence());
|
declareShortcut ("document-assets-sounds", "Open Sound Asset List", QKeySequence());
|
||||||
declareShortcut ("document-assets-soundgens", "Open Sound Generator List", QKeySequence());
|
declareShortcut ("document-assets-soundgens", "Open Sound Generator List", QKeySequence());
|
||||||
declareShortcut ("document-assets-meshes", "Open Mesh Asset List", QKeySequence());
|
declareShortcut ("document-assets-meshes", "Open Mesh Asset List", QKeySequence());
|
||||||
|
|
@ -275,6 +278,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);
|
||||||
|
|
||||||
insertRecord(copy, getAppendIndex(destination, type));
|
int index = 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
|
||||||
{
|
{
|
||||||
if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin)
|
/* LandTextureNicknameColumn */
|
||||||
|
LandTextureNicknameColumn::LandTextureNicknameColumn()
|
||||||
|
: Column<LandTexture>(Columns::ColumnId_TextureNickname, ColumnBase::Display_String)
|
||||||
{
|
{
|
||||||
return QString::fromUtf8(record.get().mRace.c_str());
|
|
||||||
}
|
}
|
||||||
return QVariant(QVariant::UserType);
|
|
||||||
}
|
QVariant LandTextureNicknameColumn::get(const Record<LandTexture>& record) const
|
||||||
|
{
|
||||||
void CSMWorld::BodyPartRaceColumn::set(Record<ESM::BodyPart> &record, const QVariant &data)
|
return QString::fromUtf8(record.get().mId.c_str());
|
||||||
{
|
}
|
||||||
ESM::BodyPart record2 = record.get();
|
|
||||||
|
void LandTextureNicknameColumn::set(Record<LandTexture>& record, const QVariant& data)
|
||||||
record2.mRace = data.toString().toUtf8().constData();
|
{
|
||||||
|
LandTexture copy = record.get();
|
||||||
record.setModified(record2);
|
copy.mId = data.toString().toUtf8().constData();
|
||||||
}
|
record.setModified(copy);
|
||||||
|
}
|
||||||
bool CSMWorld::BodyPartRaceColumn::isEditable() const
|
|
||||||
{
|
bool LandTextureNicknameColumn::isEditable() const
|
||||||
return true;
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return QString::fromUtf8(record.get().mRace.c_str());
|
||||||
|
}
|
||||||
|
return QVariant(QVariant::UserType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BodyPartRaceColumn::set(Record<ESM::BodyPart> &record, const QVariant &data)
|
||||||
|
{
|
||||||
|
ESM::BodyPart record2 = record.get();
|
||||||
|
|
||||||
|
record2.mRace = data.toString().toUtf8().constData();
|
||||||
|
|
||||||
|
record.setModified(record2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BodyPartRaceColumn::isEditable() const
|
||||||
|
{
|
||||||
|
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
|
||||||
|
|
@ -1499,9 +1509,9 @@ namespace CSMWorld
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
struct TopicColumn : public Column<ESXRecordT>
|
struct TopicColumn : public Column<ESXRecordT>
|
||||||
{
|
{
|
||||||
TopicColumn (bool journal)
|
TopicColumn (bool journal)
|
||||||
: Column<ESXRecordT> (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic,
|
: Column<ESXRecordT> (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic,
|
||||||
journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic)
|
journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||||
|
|
@ -1755,7 +1765,7 @@ namespace CSMWorld
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
struct GenderNpcColumn : public Column<ESXRecordT>
|
struct GenderNpcColumn : public Column<ESXRecordT>
|
||||||
{
|
{
|
||||||
|
|
@ -2198,8 +2208,8 @@ namespace CSMWorld
|
||||||
struct EffectTextureColumn : public Column<ESXRecordT>
|
struct EffectTextureColumn : public Column<ESXRecordT>
|
||||||
{
|
{
|
||||||
EffectTextureColumn (Columns::ColumnId columnId)
|
EffectTextureColumn (Columns::ColumnId columnId)
|
||||||
: Column<ESXRecordT> (columnId,
|
: Column<ESXRecordT> (columnId,
|
||||||
columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture
|
columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture
|
||||||
: ColumnBase::Display_Icon)
|
: ColumnBase::Display_Icon)
|
||||||
{
|
{
|
||||||
assert (this->mColumnId==Columns::ColumnId_Icon ||
|
assert (this->mColumnId==Columns::ColumnId_Icon ||
|
||||||
|
|
@ -2417,7 +2427,95 @@ namespace CSMWorld
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ namespace CSMWorld
|
||||||
{ ColumnId_Portable, "Portable" },
|
{ ColumnId_Portable, "Portable" },
|
||||||
{ ColumnId_NegativeLight, "Negative Light" },
|
{ ColumnId_NegativeLight, "Negative Light" },
|
||||||
{ ColumnId_EmitterType, "Emitter Type" },
|
{ ColumnId_EmitterType, "Emitter Type" },
|
||||||
|
|
||||||
{ ColumnId_Fire, "Fire" },
|
{ ColumnId_Fire, "Fire" },
|
||||||
{ ColumnId_OffByDefault, "Off by default" },
|
{ ColumnId_OffByDefault, "Off by default" },
|
||||||
{ ColumnId_IsKey, "Is Key" },
|
{ ColumnId_IsKey, "Is Key" },
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
#include <components/esm/cellref.hpp>
|
#include <components/esm/cellref.hpp>
|
||||||
|
|
||||||
#include <components/resource/scenemanager.hpp>
|
#include <components/resource/scenemanager.hpp>
|
||||||
|
#include <components/vfs/manager.hpp>
|
||||||
|
#include <components/vfs/registerarchives.hpp>
|
||||||
|
|
||||||
#include "idtable.hpp"
|
#include "idtable.hpp"
|
||||||
#include "idtree.hpp"
|
#include "idtree.hpp"
|
||||||
|
|
@ -61,11 +63,18 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir)
|
CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths,
|
||||||
|
const std::vector<std::string>& archives, const Fallback::Map* fallback, const boost::filesystem::path& resDir)
|
||||||
: mEncoder (encoding), mPathgrids (mCells), mRefs (mCells),
|
: mEncoder (encoding), mPathgrids (mCells), mRefs (mCells),
|
||||||
mResourcesManager (resourcesManager), mFallbackMap(fallback),
|
mFallbackMap(fallback), mReader (0), mDialogue (0), mReaderIndex(1),
|
||||||
mReader (0), mDialogue (0), mReaderIndex(1), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS()))
|
mFsStrict(fsStrict), mDataPaths(dataPaths), mArchives(archives)
|
||||||
{
|
{
|
||||||
|
mVFS.reset(new VFS::Manager(mFsStrict));
|
||||||
|
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true);
|
||||||
|
|
||||||
|
mResourcesManager.setVFS(mVFS.get());
|
||||||
|
mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get()));
|
||||||
|
|
||||||
mResourceSystem->getSceneManager()->setShaderPath((resDir / "shaders").string());
|
mResourceSystem->getSceneManager()->setShaderPath((resDir / "shaders").string());
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
@ -403,6 +412,24 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
||||||
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));
|
||||||
|
|
@ -522,6 +549,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
||||||
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),
|
||||||
|
|
@ -984,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:
|
||||||
{
|
{
|
||||||
|
|
@ -1215,6 +1232,43 @@ std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::Data::assetsChanged()
|
||||||
|
{
|
||||||
|
mVFS.get()->reset();
|
||||||
|
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true);
|
||||||
|
|
||||||
|
const UniversalId assetTableIds[] = {
|
||||||
|
UniversalId::Type_Meshes,
|
||||||
|
UniversalId::Type_Icons,
|
||||||
|
UniversalId::Type_Musics,
|
||||||
|
UniversalId::Type_SoundsRes,
|
||||||
|
UniversalId::Type_Textures,
|
||||||
|
UniversalId::Type_Videos
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t numAssetTables = sizeof(assetTableIds) / sizeof(UniversalId);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < numAssetTables; ++i)
|
||||||
|
{
|
||||||
|
ResourceTable* table = static_cast<ResourceTable*>(getTableModel(assetTableIds[i]));
|
||||||
|
table->beginReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger recreation
|
||||||
|
mResourcesManager.recreateResources();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < numAssetTables; ++i)
|
||||||
|
{
|
||||||
|
ResourceTable* table = static_cast<ResourceTable*>(getTableModel(assetTableIds[i]));
|
||||||
|
table->endReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get rid of potentially old cached assets
|
||||||
|
mResourceSystem->clearCache();
|
||||||
|
|
||||||
|
emit assetTablesChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
if (topLeft.column()<=0)
|
if (topLeft.column()<=0)
|
||||||
|
|
@ -1228,7 +1282,7 @@ void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end)
|
||||||
|
|
||||||
const VFS::Manager* CSMWorld::Data::getVFS() const
|
const VFS::Manager* CSMWorld::Data::getVFS() const
|
||||||
{
|
{
|
||||||
return mResourcesManager.getVFS();
|
return mVFS.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Fallback::Map* CSMWorld::Data::getFallbackMap() const
|
const Fallback::Map* CSMWorld::Data::getFallbackMap() const
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include <components/resource/resourcesystem.hpp>
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
|
||||||
|
#include <components/files/multidircollection.hpp>
|
||||||
#include <components/to_utf8/to_utf8.hpp>
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
#include "../doc/stage.hpp"
|
#include "../doc/stage.hpp"
|
||||||
|
|
@ -46,6 +47,7 @@
|
||||||
#include "infocollection.hpp"
|
#include "infocollection.hpp"
|
||||||
#include "nestedinfocollection.hpp"
|
#include "nestedinfocollection.hpp"
|
||||||
#include "pathgrid.hpp"
|
#include "pathgrid.hpp"
|
||||||
|
#include "resourcesmanager.hpp"
|
||||||
#include "metadata.hpp"
|
#include "metadata.hpp"
|
||||||
#ifndef Q_MOC_RUN
|
#ifndef Q_MOC_RUN
|
||||||
#include "subcellcollection.hpp"
|
#include "subcellcollection.hpp"
|
||||||
|
|
@ -108,7 +110,6 @@ namespace CSMWorld
|
||||||
RefCollection mRefs;
|
RefCollection mRefs;
|
||||||
IdCollection<ESM::Filter> mFilters;
|
IdCollection<ESM::Filter> mFilters;
|
||||||
Collection<MetaData> mMetaData;
|
Collection<MetaData> mMetaData;
|
||||||
const ResourcesManager& mResourcesManager;
|
|
||||||
const Fallback::Map* mFallbackMap;
|
const Fallback::Map* mFallbackMap;
|
||||||
std::vector<QAbstractItemModel *> mModels;
|
std::vector<QAbstractItemModel *> mModels;
|
||||||
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
|
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
|
||||||
|
|
@ -119,6 +120,11 @@ namespace CSMWorld
|
||||||
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
|
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
|
||||||
int mReaderIndex;
|
int mReaderIndex;
|
||||||
|
|
||||||
|
bool mFsStrict;
|
||||||
|
Files::PathContainer mDataPaths;
|
||||||
|
std::vector<std::string> mArchives;
|
||||||
|
std::unique_ptr<VFS::Manager> mVFS;
|
||||||
|
ResourcesManager mResourcesManager;
|
||||||
std::shared_ptr<Resource::ResourceSystem> mResourceSystem;
|
std::shared_ptr<Resource::ResourceSystem> mResourceSystem;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<ESM::ESMReader> > mReaders;
|
std::vector<std::shared_ptr<ESM::ESMReader> > mReaders;
|
||||||
|
|
@ -140,7 +146,9 @@ namespace CSMWorld
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir);
|
Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths,
|
||||||
|
const std::vector<std::string>& archives, const Fallback::Map* fallback,
|
||||||
|
const boost::filesystem::path& resDir);
|
||||||
|
|
||||||
virtual ~Data();
|
virtual ~Data();
|
||||||
|
|
||||||
|
|
@ -304,8 +312,12 @@ namespace CSMWorld
|
||||||
|
|
||||||
void idListChanged();
|
void idListChanged();
|
||||||
|
|
||||||
|
void assetTablesChanged();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
void assetsChanged();
|
||||||
|
|
||||||
void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
|
||||||
void rowsChanged (const QModelIndex& parent, int start, int end);
|
void rowsChanged (const QModelIndex& parent, int start, int end);
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
@ -61,7 +63,7 @@ namespace CSMWorld
|
||||||
virtual bool isDeleted (const std::string& id) const = 0;
|
virtual bool isDeleted (const std::string& id) const = 0;
|
||||||
|
|
||||||
virtual int getColumnId (int column) const = 0;
|
virtual int getColumnId (int column) const = 0;
|
||||||
|
|
||||||
unsigned int getFeatures() const;
|
unsigned int getFeatures() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,14 @@ CSMWorld::Resources::Resources (const VFS::Manager* vfs, const std::string& base
|
||||||
const char * const *extensions)
|
const char * const *extensions)
|
||||||
: mBaseDirectory (baseDirectory), mType (type)
|
: mBaseDirectory (baseDirectory), mType (type)
|
||||||
{
|
{
|
||||||
|
recreate(vfs, extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char * const *extensions)
|
||||||
|
{
|
||||||
|
mFiles.clear();
|
||||||
|
mIndex.clear();
|
||||||
|
|
||||||
int baseSize = mBaseDirectory.size();
|
int baseSize = mBaseDirectory.size();
|
||||||
|
|
||||||
const std::map<std::string, VFS::File*>& index = vfs->getIndex();
|
const std::map<std::string, VFS::File*>& index = vfs->getIndex();
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ namespace CSMWorld
|
||||||
Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type,
|
Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type,
|
||||||
const char * const *extensions = 0);
|
const char * const *extensions = 0);
|
||||||
|
|
||||||
|
void recreate(const VFS::Manager* vfs, const char * const *extensions = 0);
|
||||||
|
|
||||||
int getSize() const;
|
int getSize() const;
|
||||||
|
|
||||||
std::string getId (int index) const;
|
std::string getId (int index) const;
|
||||||
|
|
|
||||||
|
|
@ -14,21 +14,24 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources)
|
||||||
resources));
|
resources));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char * const * CSMWorld::ResourcesManager::getMeshExtensions()
|
||||||
|
{
|
||||||
|
// maybe we could go over the osgDB::Registry to list all supported node formats
|
||||||
|
static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 };
|
||||||
|
return sMeshTypes;
|
||||||
|
}
|
||||||
|
|
||||||
void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs)
|
void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs)
|
||||||
{
|
{
|
||||||
mVFS = vfs;
|
mVFS = vfs;
|
||||||
mResources.clear();
|
mResources.clear();
|
||||||
|
|
||||||
// maybe we could go over the osgDB::Registry to list all supported node formats
|
addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, getMeshExtensions()));
|
||||||
|
|
||||||
static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 };
|
|
||||||
|
|
||||||
addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes));
|
|
||||||
addResources (Resources (vfs, "icons", UniversalId::Type_Icon));
|
addResources (Resources (vfs, "icons", UniversalId::Type_Icon));
|
||||||
addResources (Resources (vfs, "music", UniversalId::Type_Music));
|
addResources (Resources (vfs, "music", UniversalId::Type_Music));
|
||||||
addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes));
|
addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes));
|
||||||
addResources (Resources (vfs, "textures", UniversalId::Type_Texture));
|
addResources (Resources (vfs, "textures", UniversalId::Type_Texture));
|
||||||
addResources (Resources (vfs, "videos", UniversalId::Type_Video));
|
addResources (Resources (vfs, "video", UniversalId::Type_Video));
|
||||||
}
|
}
|
||||||
|
|
||||||
const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const
|
const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const
|
||||||
|
|
@ -36,6 +39,18 @@ const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const
|
||||||
return mVFS;
|
return mVFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::ResourcesManager::recreateResources()
|
||||||
|
{
|
||||||
|
std::map<UniversalId::Type, Resources>::iterator it = mResources.begin();
|
||||||
|
for ( ; it != mResources.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->first == UniversalId::Type_Mesh)
|
||||||
|
it->second.recreate(mVFS, getMeshExtensions());
|
||||||
|
else
|
||||||
|
it->second.recreate(mVFS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const
|
const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const
|
||||||
{
|
{
|
||||||
std::map<UniversalId::Type, Resources>::const_iterator iter = mResources.find (type);
|
std::map<UniversalId::Type, Resources>::const_iterator iter = mResources.find (type);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
void addResources (const Resources& resources);
|
void addResources (const Resources& resources);
|
||||||
|
|
||||||
|
const char * const * getMeshExtensions();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ResourcesManager();
|
ResourcesManager();
|
||||||
|
|
@ -30,6 +32,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
void setVFS(const VFS::Manager* vfs);
|
void setVFS(const VFS::Manager* vfs);
|
||||||
|
|
||||||
|
void recreateResources();
|
||||||
|
|
||||||
const Resources& get (UniversalId::Type type) const;
|
const Resources& get (UniversalId::Type type) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,3 +154,13 @@ int CSMWorld::ResourceTable::getColumnId (int column) const
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::ResourceTable::beginReset()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::ResourceTable::endReset()
|
||||||
|
{
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,12 @@ namespace CSMWorld
|
||||||
/// Is \a id flagged as deleted?
|
/// Is \a id flagged as deleted?
|
||||||
virtual bool isDeleted (const std::string& id) const;
|
virtual bool isDeleted (const std::string& id) const;
|
||||||
|
|
||||||
virtual int getColumnId (int column) const;
|
virtual int getColumnId (int column) const;
|
||||||
|
|
||||||
|
/// Signal Qt that the data is about to change.
|
||||||
|
void beginReset();
|
||||||
|
/// Signal Qt that the data has been changed.
|
||||||
|
void endReset();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 },
|
||||||
|
|
@ -364,8 +368,8 @@ std::vector<CSMWorld::UniversalId::Type> CSMWorld::UniversalId::listTypes (int c
|
||||||
for (int i=0; sIndexArg[i].mName; ++i)
|
for (int i=0; sIndexArg[i].mName; ++i)
|
||||||
if (sIndexArg[i].mClass & classes)
|
if (sIndexArg[i].mClass & classes)
|
||||||
list.push_back (sIndexArg[i].mType);
|
list.push_back (sIndexArg[i].mType);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type)
|
CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -284,6 +294,13 @@ void CSVDoc::View::setupAssetsMenu()
|
||||||
{
|
{
|
||||||
QMenu *assets = menuBar()->addMenu (tr ("Assets"));
|
QMenu *assets = menuBar()->addMenu (tr ("Assets"));
|
||||||
|
|
||||||
|
QAction *reload = new QAction (tr ("Reload"), this);
|
||||||
|
connect (reload, SIGNAL (triggered()), &mDocument->getData(), SLOT (assetsChanged()));
|
||||||
|
setupShortcut("document-assets-reload", reload);
|
||||||
|
assets->addAction (reload);
|
||||||
|
|
||||||
|
assets->addSeparator();
|
||||||
|
|
||||||
QAction *sounds = new QAction (tr ("Sounds"), this);
|
QAction *sounds = new QAction (tr ("Sounds"), this);
|
||||||
connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView()));
|
connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView()));
|
||||||
setupShortcut("document-assets-sounds", sounds);
|
setupShortcut("document-assets-sounds", sounds);
|
||||||
|
|
@ -869,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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
@ -275,12 +348,64 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int
|
||||||
|
|
||||||
void CSVRender::Cell::pathgridModified()
|
void CSVRender::Cell::pathgridModified()
|
||||||
{
|
{
|
||||||
mPathgrid->recreateGeometry();
|
if (mPathgrid)
|
||||||
|
mPathgrid->recreateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::Cell::pathgridRemoved()
|
void CSVRender::Cell::pathgridRemoved()
|
||||||
{
|
{
|
||||||
mPathgrid->removeGeometry();
|
if (mPathgrid)
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
|
||||||
|
iter != mObjects.end(); ++iter)
|
||||||
|
{
|
||||||
|
iter->second->reloadAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTerrain)
|
||||||
|
{
|
||||||
|
mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY());
|
||||||
|
mTerrain->loadCell(mCoordinates.getX(), mCoordinates.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCellWater)
|
||||||
|
mCellWater->reloadAssets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::Cell::setSelection (int elementMask, Selection mode)
|
void CSVRender::Cell::setSelection (int elementMask, Selection mode)
|
||||||
|
|
@ -302,7 +427,7 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode)
|
||||||
iter->second->setSelected (selected);
|
iter->second->setSelected (selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (elementMask & Mask_Pathgrid)
|
if (mPathgrid && elementMask & Mask_Pathgrid)
|
||||||
{
|
{
|
||||||
// Only one pathgrid may be selected, so some operations will only have an effect
|
// Only one pathgrid may be selected, so some operations will only have an effect
|
||||||
// if the pathgrid is already focused
|
// if the pathgrid is already focused
|
||||||
|
|
@ -402,7 +527,7 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::Cell::getSelection (un
|
||||||
iter!=mObjects.end(); ++iter)
|
iter!=mObjects.end(); ++iter)
|
||||||
if (iter->second->getSelected())
|
if (iter->second->getSelected())
|
||||||
result.push_back (iter->second->getTag());
|
result.push_back (iter->second->getTag());
|
||||||
if (elementMask & Mask_Pathgrid)
|
if (mPathgrid && elementMask & Mask_Pathgrid)
|
||||||
if (mPathgrid->isSelected())
|
if (mPathgrid->isSelected())
|
||||||
result.push_back(mPathgrid->getTag());
|
result.push_back(mPathgrid->getTag());
|
||||||
|
|
||||||
|
|
@ -439,6 +564,6 @@ void CSVRender::Cell::reset (unsigned int elementMask)
|
||||||
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
|
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
|
||||||
iter!=mObjects.end(); ++iter)
|
iter!=mObjects.end(); ++iter)
|
||||||
iter->second->reset();
|
iter->second->reset();
|
||||||
if (elementMask & Mask_Pathgrid)
|
if (mPathgrid && elementMask & Mask_Pathgrid)
|
||||||
mPathgrid->resetIndicators();
|
mPathgrid->resetIndicators();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,20 @@ 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 setSelection (int elementMask, Selection mode);
|
void setSelection (int elementMask, Selection mode);
|
||||||
|
|
||||||
// Select everything that references the same ID as at least one of the elements
|
// Select everything that references the same ID as at least one of the elements
|
||||||
|
|
@ -143,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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,11 @@ namespace CSVRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CellWater::reloadAssets()
|
||||||
|
{
|
||||||
|
recreate();
|
||||||
|
}
|
||||||
|
|
||||||
void CellWater::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
void CellWater::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
const CSMWorld::Collection<CSMWorld::Cell>& cells = mData.getCells();
|
const CSMWorld::Collection<CSMWorld::Cell>& cells = mData.getCells();
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ namespace CSVRender
|
||||||
|
|
||||||
void updateCellData(const CSMWorld::Record<CSMWorld::Cell>& cellRecord);
|
void updateCellData(const CSMWorld::Record<CSMWorld::Cell>& cellRecord);
|
||||||
|
|
||||||
|
void reloadAssets();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
void cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
|
|
||||||
|
|
@ -532,6 +532,12 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::Object::reloadAssets()
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
updateMarker();
|
||||||
|
}
|
||||||
|
|
||||||
std::string CSVRender::Object::getReferenceId() const
|
std::string CSVRender::Object::getReferenceId() const
|
||||||
{
|
{
|
||||||
return mReferenceId;
|
return mReferenceId;
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,9 @@ namespace CSVRender
|
||||||
/// this object?
|
/// this object?
|
||||||
bool referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
bool referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
|
||||||
|
/// Reloads the underlying asset
|
||||||
|
void reloadAssets();
|
||||||
|
|
||||||
/// Returns an empty string if this is a refereceable-type object.
|
/// Returns an empty string if this is a refereceable-type object.
|
||||||
std::string getReferenceId() const;
|
std::string getReferenceId() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
@ -472,6 +538,27 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc
|
||||||
connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||||
this, SLOT (cellAdded (const QModelIndex&, int, int)));
|
this, SLOT (cellAdded (const QModelIndex&, int, int)));
|
||||||
|
|
||||||
|
connect (&document.getData(), SIGNAL (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()));
|
||||||
|
|
@ -520,7 +607,7 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
|
||||||
// Loop through all the coordinates to add them to selection
|
// Loop through all the coordinates to add them to selection
|
||||||
while (stream >> ignore1 >> ignore2 >> x >> y)
|
while (stream >> ignore1 >> ignore2 >> x >> y)
|
||||||
selection.add (CSMWorld::CellCoordinates (x, y));
|
selection.add (CSMWorld::CellCoordinates (x, y));
|
||||||
|
|
||||||
// Mark that camera needs setup
|
// Mark that camera needs setup
|
||||||
mCamPositionSet=false;
|
mCamPositionSet=false;
|
||||||
}
|
}
|
||||||
|
|
@ -763,6 +850,15 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::assetTablesChanged()
|
||||||
|
{
|
||||||
|
std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter = mCells.begin();
|
||||||
|
for ( ; iter != mCells.end(); ++iter)
|
||||||
|
{
|
||||||
|
iter->second->reloadAssets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::PagedWorldspaceWidget::loadCameraCell()
|
void CSVRender::PagedWorldspaceWidget::loadCameraCell()
|
||||||
{
|
{
|
||||||
addCellToSceneFromCamera(0, 0);
|
addCellToSceneFromCamera(0, 0);
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ namespace CSVRender
|
||||||
/// hint system.
|
/// hint system.
|
||||||
|
|
||||||
virtual ~PagedWorldspaceWidget();
|
virtual ~PagedWorldspaceWidget();
|
||||||
|
|
||||||
/// Decodes the the hint string to set of cell that are rendered.
|
/// Decodes the the hint string to set of cell that are rendered.
|
||||||
void useViewHint (const std::string& hint);
|
void useViewHint (const std::string& hint);
|
||||||
|
|
||||||
|
|
@ -155,6 +155,16 @@ 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 loadCameraCell();
|
void loadCameraCell();
|
||||||
|
|
||||||
void loadEastCell();
|
void loadEastCell();
|
||||||
|
|
|
||||||
|
|
@ -72,12 +72,15 @@ namespace CSVRender
|
||||||
}
|
}
|
||||||
else if (Cell* cell = getWorldspaceWidget().getCell (hitResult.worldPos))
|
else if (Cell* cell = getWorldspaceWidget().getCell (hitResult.worldPos))
|
||||||
{
|
{
|
||||||
// Add node
|
if (cell->getPathgrid())
|
||||||
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
|
{
|
||||||
QString description = "Add node";
|
// Add node
|
||||||
|
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
|
||||||
|
QString description = "Add node";
|
||||||
|
|
||||||
CSMWorld::CommandMacro macro(undoStack, description);
|
CSMWorld::CommandMacro macro(undoStack, description);
|
||||||
cell->getPathgrid()->applyPoint(macro, hitResult.worldPos);
|
cell->getPathgrid()->applyPoint(macro, hitResult.worldPos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,7 +208,7 @@ namespace CSVRender
|
||||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||||
|
|
||||||
Cell* cell = getWorldspaceWidget().getCell(hit.worldPos);
|
Cell* cell = getWorldspaceWidget().getCell(hit.worldPos);
|
||||||
if (cell)
|
if (cell && cell->getPathgrid())
|
||||||
{
|
{
|
||||||
PathgridTag* tag = 0;
|
PathgridTag* tag = 0;
|
||||||
if (hit.tag && (tag = dynamic_cast<PathgridTag*>(hit.tag.get())) && tag->getPathgrid()->getId() == mEdgeId)
|
if (hit.tag && (tag = dynamic_cast<PathgridTag*>(hit.tag.get())) && tag->getPathgrid()->getId() == mEdgeId)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
|
||||||
connect (referenceables, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
connect (referenceables, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
this, SLOT (referenceableAboutToBeRemoved (const QModelIndex&, int, int)));
|
this, SLOT (referenceableAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
|
|
||||||
|
connect (&mData, SIGNAL (assetTablesChanged ()),
|
||||||
|
this, SLOT (assetTablesChanged ()));
|
||||||
|
|
||||||
if (!referenceable)
|
if (!referenceable)
|
||||||
{
|
{
|
||||||
QAbstractItemModel *references =
|
QAbstractItemModel *references =
|
||||||
|
|
@ -119,3 +122,8 @@ void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& par
|
||||||
if (index.row()>=start && index.row()<=end)
|
if (index.row()>=start && index.row()<=end)
|
||||||
emit closeRequest();
|
emit closeRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::PreviewWidget::assetTablesChanged ()
|
||||||
|
{
|
||||||
|
mObject.reloadAssets();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ namespace CSVRender
|
||||||
void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
|
||||||
void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void assetTablesChanged ();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -221,8 +221,8 @@ SceneWidget::SceneWidget(std::shared_ptr<Resource::ResourceSystem> resourceSyste
|
||||||
|
|
||||||
SceneWidget::~SceneWidget()
|
SceneWidget::~SceneWidget()
|
||||||
{
|
{
|
||||||
// Since we're holding on to the scene templates past the existence of this graphics context, we'll need to manually release the created objects
|
// Since we're holding on to the resources past the existence of this graphics context, we'll need to manually release the created objects
|
||||||
mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
|
mResourceSystem->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneWidget::setLighting(Lighting *lighting)
|
void SceneWidget::setLighting(Lighting *lighting)
|
||||||
|
|
@ -393,6 +393,7 @@ void SceneWidget::selectNavigationMode (const std::string& mode)
|
||||||
mCurrentCamControl->setCamera(NULL);
|
mCurrentCamControl->setCamera(NULL);
|
||||||
mCurrentCamControl = mOrbitCamControl;
|
mCurrentCamControl = mOrbitCamControl;
|
||||||
mOrbitCamControl->setCamera(getCamera());
|
mOrbitCamControl->setCamera(getCamera());
|
||||||
|
mOrbitCamControl->reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,9 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string&
|
||||||
connect (mCellsModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
connect (mCellsModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
this, SLOT (cellRowsAboutToBeRemoved (const QModelIndex&, int, int)));
|
this, SLOT (cellRowsAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
|
|
||||||
|
connect (&document.getData(), SIGNAL (assetTablesChanged ()),
|
||||||
|
this, SLOT (assetTablesChanged ()));
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
|
||||||
mCell.reset (new Cell (document.getData(), mRootNode, mCellId));
|
mCell.reset (new Cell (document.getData(), mRootNode, mCellId));
|
||||||
|
|
@ -82,6 +85,12 @@ void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelI
|
||||||
emit closeRequest();
|
emit closeRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::UnpagedWorldspaceWidget::assetTablesChanged()
|
||||||
|
{
|
||||||
|
if (mCell)
|
||||||
|
mCell->reloadAssets();
|
||||||
|
}
|
||||||
|
|
||||||
bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& universalIdData, DropType type)
|
bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& universalIdData, DropType type)
|
||||||
{
|
{
|
||||||
if (WorldspaceWidget::handleDrop (universalIdData, type))
|
if (WorldspaceWidget::handleDrop (universalIdData, type))
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,8 @@ namespace CSVRender
|
||||||
|
|
||||||
void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void assetTablesChanged ();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void cellChanged(const CSMWorld::UniversalId& id);
|
void cellChanged(const CSMWorld::UniversalId& id);
|
||||||
|
|
|
||||||
|
|
@ -5,29 +5,32 @@
|
||||||
|
|
||||||
#include "../widget/coloreditor.hpp"
|
#include "../widget/coloreditor.hpp"
|
||||||
|
|
||||||
CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
|
CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
|
||||||
CSMDoc::Document& document,
|
CSMDoc::Document& document,
|
||||||
QObject *parent)
|
QObject *parent)
|
||||||
: CommandDelegate(dispatcher, document, parent)
|
: CommandDelegate(dispatcher, document, parent)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void CSVWorld::ColorDelegate::paint(QPainter *painter,
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
|
CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
|
||||||
CSMDoc::Document &document,
|
CSMDoc::Document &document,
|
||||||
QObject *parent) const
|
QObject *parent) const
|
||||||
{
|
{
|
||||||
return new ColorDelegate(dispatcher, document, parent);
|
return new ColorDelegate(dispatcher, document, parent);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,19 @@ std::string CSVWorld::InfoCreator::getId() const
|
||||||
|
|
||||||
void CSVWorld::InfoCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const
|
void CSVWorld::InfoCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const
|
||||||
{
|
{
|
||||||
int index =
|
CSMWorld::IdTable& table = dynamic_cast<CSMWorld::IdTable&> (*getData().getTableModel (getCollectionId()));
|
||||||
dynamic_cast<CSMWorld::IdTable&> (*getData().getTableModel (getCollectionId())).
|
|
||||||
findColumnIndex (
|
|
||||||
getCollectionId().getType()==CSMWorld::UniversalId::Type_TopicInfos ?
|
|
||||||
CSMWorld::Columns::ColumnId_Topic : CSMWorld::Columns::ColumnId_Journal);
|
|
||||||
|
|
||||||
command.addValue (index, mTopic->text());
|
if (getCollectionId() == CSMWorld::UniversalId::Type_TopicInfos)
|
||||||
|
{
|
||||||
|
command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Topic), mTopic->text());
|
||||||
|
command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Rank), -1);
|
||||||
|
command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Gender), -1);
|
||||||
|
command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_PcRank), -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Journal), mTopic->text());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||||
|
|
|
||||||
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();
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,9 @@ void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandCo
|
||||||
mExtendedConfigurator->setFocus();
|
mExtendedConfigurator->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory,
|
CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory,
|
||||||
CSMDoc::Document& document,
|
CSMDoc::Document& document,
|
||||||
const CSMWorld::UniversalId& id,
|
const CSMWorld::UniversalId& id,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None), mHasPosition(false), mRow(0), mColumn(0)
|
: QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None), mHasPosition(false), mRow(0), mColumn(0)
|
||||||
{
|
{
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue