mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-29 16:06:44 +00:00
Add OpenMW commits up to 16 May 2020
# Conflicts: # CI/before_script.linux.sh # apps/openmw/mwbase/world.hpp # apps/openmw/mwinput/inputmanagerimp.cpp # apps/openmw/mwscript/globalscripts.cpp # apps/openmw/mwscript/interpretercontext.cpp # apps/openmw/mwworld/cellstore.cpp # apps/openmw/mwworld/cellstore.hpp # apps/openmw/mwworld/worldimp.cpp # apps/openmw/mwworld/worldimp.hpp # components/interpreter/context.hpp
This commit is contained in:
commit
62df188fd4
95 changed files with 4433 additions and 3243 deletions
|
@ -2,7 +2,10 @@
|
||||||
------
|
------
|
||||||
|
|
||||||
Bug #1952: Incorrect particle lighting
|
Bug #1952: Incorrect particle lighting
|
||||||
|
Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs
|
||||||
Bug #3676: NiParticleColorModifier isn't applied properly
|
Bug #3676: NiParticleColorModifier isn't applied properly
|
||||||
|
Bug #4774: Guards are ignorant of an invisible player that tries to attack them
|
||||||
|
Bug #5108: Savegame bloating due to inefficient fog textures format
|
||||||
Bug #5358: ForceGreeting always resets the dialogue window completely
|
Bug #5358: ForceGreeting always resets the dialogue window completely
|
||||||
Bug #5363: Enchantment autocalc not always 0/1
|
Bug #5363: Enchantment autocalc not always 0/1
|
||||||
Bug #5364: Script fails/stops if trying to startscript an unknown script
|
Bug #5364: Script fails/stops if trying to startscript an unknown script
|
||||||
|
@ -10,6 +13,8 @@
|
||||||
Bug #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures
|
Bug #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures
|
||||||
Bug #5370: Opening an unlocked but trapped door uses the key
|
Bug #5370: Opening an unlocked but trapped door uses the key
|
||||||
Bug #5400: Editor: Verifier checks race of non-skin bodyparts
|
Bug #5400: Editor: Verifier checks race of non-skin bodyparts
|
||||||
|
Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work
|
||||||
|
Bug #5416: Junk non-node records before the root node are not handled gracefully
|
||||||
Feature #5362: Show the soul gems' trapped soul in count dialog
|
Feature #5362: Show the soul gems' trapped soul in count dialog
|
||||||
|
|
||||||
0.46.0
|
0.46.0
|
||||||
|
|
|
@ -13,21 +13,28 @@ The OpenMW team is proud to announce the release of version 0.47.0! Grab it from
|
||||||
Check out the release video (***add link***) and the OpenMW-CS release video (***add link***) by the ***add flattering adjective*** Atahualpa, and see below for the full list of changes.
|
Check out the release video (***add link***) and the OpenMW-CS release video (***add link***) by the ***add flattering adjective*** Atahualpa, and see below for the full list of changes.
|
||||||
|
|
||||||
Known Issues:
|
Known Issues:
|
||||||
- There's currently no way to redirect the logging output to the command prompt on Windows Release builds -- this will be resolved in version 0.46.0
|
|
||||||
- To use generic Linux binaries, Qt4 and libpng12 must be installed on your system
|
- To use generic Linux binaries, Qt4 and libpng12 must be installed on your system
|
||||||
- On macOS, launching OpenMW from OpenMW-CS requires OpenMW.app and OpenMW-CS.app to be siblings
|
- On macOS, launching OpenMW from OpenMW-CS requires OpenMW.app and OpenMW-CS.app to be siblings
|
||||||
|
|
||||||
New Features:
|
New Features:
|
||||||
- ?
|
- Dialogue to split item stacks now displays the name of the trapped soul for stacks of soul gems (#5362)
|
||||||
|
|
||||||
New Editor Features:
|
New Editor Features:
|
||||||
- ?
|
- ?
|
||||||
|
|
||||||
Bug Fixes:
|
Bug Fixes:
|
||||||
- ?
|
- NiParticleColorModifier in NIF files is now properly handled which solves issues regarding particle effects, e.g., smoke and fire (#1952, #3676)
|
||||||
|
- Targetting non-unique actors in scripts is now supported (#2311)
|
||||||
|
- Guards no longer ignore attacks of invisible players but rather initiate dialogue and flee if the player resists being arrested (#4774)
|
||||||
|
- Changing the dialogue window without closing it no longer clears the dialogue history in order to allow, e.g., emulation of three-way dialogue via ForceGreeting (#5358)
|
||||||
|
- Scripts which try to start a non-existent global script now skip that step and continue execution instead of breaking (#5364)
|
||||||
|
- Selecting already equipped spells or magic items via hotkey no longer triggers the equip sound to play (#5367)
|
||||||
|
- 'Scale' argument in levelled creature lists is now taken into account when spawning creatures from such lists (#5369)
|
||||||
|
- Morrowind legacy madness: Using a key on a trapped door/container now only disarms the trap if the door/container is locked (#5370)
|
||||||
|
|
||||||
Editor Bug Fixes:
|
Editor Bug Fixes:
|
||||||
- ?
|
- Verifier no longer checks for alleged 'race' entries in clothing body parts (#5400)
|
||||||
|
|
||||||
Miscellaneous:
|
Miscellaneous:
|
||||||
- ?
|
- Prevent save-game bloating by using an appropriate fog texture format (#5108)
|
||||||
|
- Ensure that 'Enchantment autocalc" flag is treated as flag in OpenMW-CS and in our esm tools (#5363)
|
|
@ -33,7 +33,6 @@ ${ANALYZE} cmake .. \
|
||||||
-DBUILD_ESSIMPORTER=${BUILD_OPENMW_CS} \
|
-DBUILD_ESSIMPORTER=${BUILD_OPENMW_CS} \
|
||||||
-DBUILD_WIZARD=${BUILD_OPENMW_CS} \
|
-DBUILD_WIZARD=${BUILD_OPENMW_CS} \
|
||||||
-DBUILD_NIFTEST=${BUILD_OPENMW_CS} \
|
-DBUILD_NIFTEST=${BUILD_OPENMW_CS} \
|
||||||
-DBUILD_MYGUI_PLUGIN=${BUILD_OPENMW_CS} \
|
|
||||||
-DBUILD_OPENMW_MP=ON \
|
-DBUILD_OPENMW_MP=ON \
|
||||||
-DBUILD_BROWSER=ON \
|
-DBUILD_BROWSER=ON \
|
||||||
-DBUILD_MASTER=ON \
|
-DBUILD_MASTER=ON \
|
||||||
|
|
|
@ -36,6 +36,7 @@ PLATFORM=""
|
||||||
CONFIGURATION=""
|
CONFIGURATION=""
|
||||||
TEST_FRAMEWORK=""
|
TEST_FRAMEWORK=""
|
||||||
GOOGLE_INSTALL_ROOT=""
|
GOOGLE_INSTALL_ROOT=""
|
||||||
|
INSTALL_PREFIX="."
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
ARGSTR=$1
|
ARGSTR=$1
|
||||||
|
@ -83,9 +84,13 @@ while [ $# -gt 0 ]; do
|
||||||
t )
|
t )
|
||||||
TEST_FRAMEWORK=true ;;
|
TEST_FRAMEWORK=true ;;
|
||||||
|
|
||||||
|
i )
|
||||||
|
INSTALL_PREFIX=$(echo "$1" | sed 's;\\;/;g' | sed -E 's;/+;/;g')
|
||||||
|
shift ;;
|
||||||
|
|
||||||
h )
|
h )
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Usage: $0 [-cdehkpuvV]
|
Usage: $0 [-cdehkpuvVi]
|
||||||
Options:
|
Options:
|
||||||
-c <Release/Debug>
|
-c <Release/Debug>
|
||||||
Set the configuration, can also be set with environment variable CONFIGURATION.
|
Set the configuration, can also be set with environment variable CONFIGURATION.
|
||||||
|
@ -109,6 +114,8 @@ Options:
|
||||||
Produce NMake makefiles instead of a Visual Studio solution.
|
Produce NMake makefiles instead of a Visual Studio solution.
|
||||||
-V
|
-V
|
||||||
Run verbosely
|
Run verbosely
|
||||||
|
-i
|
||||||
|
CMake install prefix
|
||||||
EOF
|
EOF
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
|
@ -386,9 +393,9 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Bullet
|
# Bullet
|
||||||
download "Bullet 2.86" \
|
download "Bullet 2.87" \
|
||||||
"https://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
"https://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
||||||
"Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z"
|
"Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||||
|
|
||||||
# FFmpeg
|
# FFmpeg
|
||||||
download "FFmpeg 3.2.4" \
|
download "FFmpeg 3.2.4" \
|
||||||
|
@ -526,15 +533,15 @@ fi
|
||||||
cd $DEPS
|
cd $DEPS
|
||||||
echo
|
echo
|
||||||
# Bullet
|
# Bullet
|
||||||
printf "Bullet 2.86... "
|
printf "Bullet 2.87... "
|
||||||
{
|
{
|
||||||
cd $DEPS_INSTALL
|
cd $DEPS_INSTALL
|
||||||
if [ -d Bullet ]; then
|
if [ -d Bullet ]; then
|
||||||
printf -- "Exists. (No version checking) "
|
printf -- "Exists. (No version checking) "
|
||||||
elif [ -z $SKIP_EXTRACT ]; then
|
elif [ -z $SKIP_EXTRACT ]; then
|
||||||
rm -rf Bullet
|
rm -rf Bullet
|
||||||
eval 7z x -y "${DEPS}/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
eval 7z x -y "${DEPS}/Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||||
mv "Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}" Bullet
|
mv "Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}" Bullet
|
||||||
fi
|
fi
|
||||||
export BULLET_ROOT="$(real_pwd)/Bullet"
|
export BULLET_ROOT="$(real_pwd)/Bullet"
|
||||||
echo Done.
|
echo Done.
|
||||||
|
@ -759,8 +766,8 @@ echo
|
||||||
cd $DEPS_INSTALL/..
|
cd $DEPS_INSTALL/..
|
||||||
echo
|
echo
|
||||||
echo "Setting up OpenMW build..."
|
echo "Setting up OpenMW build..."
|
||||||
add_cmake_opts -DBUILD_MYGUI_PLUGIN=no \
|
add_cmake_opts -DOPENMW_MP_BUILD=on
|
||||||
-DOPENMW_MP_BUILD=on
|
add_cmake_opts -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}"
|
||||||
if [ ! -z $CI ]; then
|
if [ ! -z $CI ]; then
|
||||||
case $STEP in
|
case $STEP in
|
||||||
components )
|
components )
|
||||||
|
|
|
@ -19,6 +19,5 @@ cmake \
|
||||||
-D OPENMW_OSX_DEPLOYMENT=TRUE \
|
-D OPENMW_OSX_DEPLOYMENT=TRUE \
|
||||||
-D DESIRED_QT_VERSION=5 \
|
-D DESIRED_QT_VERSION=5 \
|
||||||
-D BUILD_ESMTOOL=FALSE \
|
-D BUILD_ESMTOOL=FALSE \
|
||||||
-D BUILD_MYGUI_PLUGIN=FALSE \
|
|
||||||
-G"Unix Makefiles" \
|
-G"Unix Makefiles" \
|
||||||
..
|
..
|
||||||
|
|
|
@ -8,7 +8,6 @@ option(BUILD_ESSIMPORTER "Build ESS (Morrowind save game) importer" ON)
|
||||||
option(BUILD_BSATOOL "Build BSA extractor" ON)
|
option(BUILD_BSATOOL "Build BSA extractor" ON)
|
||||||
option(BUILD_ESMTOOL "Build ESM inspector" ON)
|
option(BUILD_ESMTOOL "Build ESM inspector" ON)
|
||||||
option(BUILD_NIFTEST "Build nif file tester" ON)
|
option(BUILD_NIFTEST "Build nif file tester" ON)
|
||||||
option(BUILD_MYGUI_PLUGIN "Build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
|
|
||||||
option(BUILD_DOCS "Build documentation." OFF )
|
option(BUILD_DOCS "Build documentation." OFF )
|
||||||
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
||||||
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
|
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
|
||||||
|
@ -497,9 +496,6 @@ IF(NOT WIN32 AND NOT APPLE)
|
||||||
IF(BUILD_WIZARD)
|
IF(BUILD_WIZARD)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" )
|
||||||
ENDIF(BUILD_WIZARD)
|
ENDIF(BUILD_WIZARD)
|
||||||
#if(BUILD_MYGUI_PLUGIN)
|
|
||||||
# INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" )
|
|
||||||
#ENDIF(BUILD_MYGUI_PLUGIN)
|
|
||||||
|
|
||||||
# Install licenses
|
# Install licenses
|
||||||
INSTALL(FILES "files/mygui/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
|
INSTALL(FILES "files/mygui/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
|
||||||
|
@ -557,11 +553,6 @@ if(WIN32)
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/gamecontrollerdb.txt" DESTINATION "." CONFIGURATIONS Debug)
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/gamecontrollerdb.txt" DESTINATION "." CONFIGURATIONS Debug)
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/gamecontrollerdb.txt" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/gamecontrollerdb.txt" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
|
|
||||||
if(BUILD_MYGUI_PLUGIN)
|
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug)
|
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
|
||||||
ENDIF(BUILD_MYGUI_PLUGIN)
|
|
||||||
|
|
||||||
IF(DESIRED_QT_VERSION MATCHES 5)
|
IF(DESIRED_QT_VERSION MATCHES 5)
|
||||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Debug/platforms" DESTINATION "." CONFIGURATIONS Debug)
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Debug/platforms" DESTINATION "." CONFIGURATIONS Debug)
|
||||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
|
|
|
@ -25,7 +25,8 @@ add_openmw_dir (mwrender
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
inputmanagerimp
|
actions actionmanager bindingsmanager controllermanager controlswitch
|
||||||
|
inputmanagerimp mousemanager keyboardmanager sdlmappings sensormanager
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwgui
|
add_openmw_dir (mwgui
|
||||||
|
|
|
@ -137,7 +137,7 @@ bool OMW::Engine::frame(float frametime)
|
||||||
// When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug.
|
// When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug.
|
||||||
// If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2),
|
// If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2),
|
||||||
// and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21)
|
// and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21)
|
||||||
if (!mEnvironment.getInputManager()->isWindowVisible())
|
if (!mEnvironment.getWindowManager()->isWindowVisible())
|
||||||
{
|
{
|
||||||
mEnvironment.getSoundManager()->pausePlayback();
|
mEnvironment.getSoundManager()->pausePlayback();
|
||||||
/*
|
/*
|
||||||
|
@ -654,20 +654,20 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
else
|
else
|
||||||
gameControllerdb = ""; //if it doesn't exist, pass in an empty string
|
gameControllerdb = ""; //if it doesn't exist, pass in an empty string
|
||||||
|
|
||||||
MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, mScreenCaptureHandler, mScreenCaptureOperation, keybinderUser, keybinderUserExists, userGameControllerdb, gameControllerdb, mGrab);
|
|
||||||
mEnvironment.setInputManager (input);
|
|
||||||
|
|
||||||
std::string myguiResources = (mResDir / "mygui").string();
|
std::string myguiResources = (mResDir / "mygui").string();
|
||||||
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
|
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
|
||||||
guiRoot->setName("GUI Root");
|
guiRoot->setName("GUI Root");
|
||||||
guiRoot->setNodeMask(MWRender::Mask_GUI);
|
guiRoot->setNodeMask(MWRender::Mask_GUI);
|
||||||
rootNode->addChild(guiRoot);
|
rootNode->addChild(guiRoot);
|
||||||
MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mWorkQueue.get(),
|
MWGui::WindowManager* window = new MWGui::WindowManager(mWindow, mViewer, guiRoot, mResourceSystem.get(), mWorkQueue.get(),
|
||||||
mCfgMgr.getLogPath().string() + std::string("/"), myguiResources,
|
mCfgMgr.getLogPath().string() + std::string("/"), myguiResources,
|
||||||
mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts,
|
mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts,
|
||||||
Version::getOpenmwVersionDescription(mResDir.string()), mCfgMgr.getUserConfigPath().string());
|
Version::getOpenmwVersionDescription(mResDir.string()), mCfgMgr.getUserConfigPath().string());
|
||||||
mEnvironment.setWindowManager (window);
|
mEnvironment.setWindowManager (window);
|
||||||
|
|
||||||
|
MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, mScreenCaptureHandler, mScreenCaptureOperation, keybinderUser, keybinderUserExists, userGameControllerdb, gameControllerdb, mGrab);
|
||||||
|
mEnvironment.setInputManager (input);
|
||||||
|
|
||||||
// Create sound system
|
// Create sound system
|
||||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
|
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
|
||||||
|
|
||||||
|
@ -683,7 +683,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
mFileCollections, mContentFiles, mEncoder, mActivationDistanceOverride, mCellName,
|
mFileCollections, mContentFiles, mEncoder, mActivationDistanceOverride, mCellName,
|
||||||
mStartupScript, mResDir.string(), mCfgMgr.getUserDataPath().string()));
|
mStartupScript, mResDir.string(), mCfgMgr.getUserDataPath().string()));
|
||||||
mEnvironment.getWorld()->setupPlayer();
|
mEnvironment.getWorld()->setupPlayer();
|
||||||
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
|
||||||
|
|
||||||
window->setStore(mEnvironment.getWorld()->getStore());
|
window->setStore(mEnvironment.getWorld()->getStore());
|
||||||
window->initUI();
|
window->initUI();
|
||||||
|
|
|
@ -38,8 +38,6 @@ namespace MWBase
|
||||||
|
|
||||||
virtual ~InputManager() {}
|
virtual ~InputManager() {}
|
||||||
|
|
||||||
virtual bool isWindowVisible() = 0;
|
|
||||||
|
|
||||||
virtual void update(float dt, bool disableControls, bool disableEvents=false) = 0;
|
virtual void update(float dt, bool disableControls, bool disableEvents=false) = 0;
|
||||||
|
|
||||||
virtual void changeInputMode(bool guiMode) = 0;
|
virtual void changeInputMode(bool guiMode) = 0;
|
||||||
|
@ -47,6 +45,8 @@ namespace MWBase
|
||||||
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& changed) = 0;
|
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& changed) = 0;
|
||||||
|
|
||||||
virtual void setDragDrop(bool dragDrop) = 0;
|
virtual void setDragDrop(bool dragDrop) = 0;
|
||||||
|
virtual void setGamepadGuiCursorEnabled(bool enabled) = 0;
|
||||||
|
virtual void setAttemptJump(bool jumping) = 0;
|
||||||
|
|
||||||
virtual void toggleControlSwitch (const std::string& sw, bool value) = 0;
|
virtual void toggleControlSwitch (const std::string& sw, bool value) = 0;
|
||||||
virtual bool getControlSwitch (const std::string& sw) = 0;
|
virtual bool getControlSwitch (const std::string& sw) = 0;
|
||||||
|
@ -54,8 +54,6 @@ namespace MWBase
|
||||||
virtual std::string getActionDescription (int action) = 0;
|
virtual std::string getActionDescription (int action) = 0;
|
||||||
virtual std::string getActionKeyBindingName (int action) = 0;
|
virtual std::string getActionKeyBindingName (int action) = 0;
|
||||||
virtual std::string getActionControllerBindingName (int action) = 0;
|
virtual std::string getActionControllerBindingName (int action) = 0;
|
||||||
virtual std::string sdlControllerAxisToString(int axis) = 0;
|
|
||||||
virtual std::string sdlControllerButtonToString(int button) = 0;
|
|
||||||
///Actions available for binding to keyboard buttons
|
///Actions available for binding to keyboard buttons
|
||||||
virtual std::vector<int> getActionKeySorting() = 0;
|
virtual std::vector<int> getActionKeySorting() = 0;
|
||||||
///Actions available for binding to controller buttons
|
///Actions available for binding to controller buttons
|
||||||
|
@ -69,10 +67,15 @@ namespace MWBase
|
||||||
/// Returns if the last used input device was a joystick or a keyboard
|
/// Returns if the last used input device was a joystick or a keyboard
|
||||||
/// @return true if joystick, false otherwise
|
/// @return true if joystick, false otherwise
|
||||||
virtual bool joystickLastUsed() = 0;
|
virtual bool joystickLastUsed() = 0;
|
||||||
|
virtual void setJoystickLastUsed(bool enabled) = 0;
|
||||||
|
|
||||||
virtual int countSavedGameRecords() const = 0;
|
virtual int countSavedGameRecords() const = 0;
|
||||||
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress) = 0;
|
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress) = 0;
|
||||||
virtual void readRecord(ESM::ESMReader& reader, uint32_t type) = 0;
|
virtual void readRecord(ESM::ESMReader& reader, uint32_t type) = 0;
|
||||||
|
|
||||||
|
virtual void resetIdleTime() = 0;
|
||||||
|
|
||||||
|
virtual void executeAction(int action) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual ~ScriptManager() {}
|
virtual ~ScriptManager() {}
|
||||||
|
|
||||||
virtual void run (const std::string& name, Interpreter::Context& interpreterContext) = 0;
|
virtual bool run (const std::string& name, Interpreter::Context& interpreterContext) = 0;
|
||||||
///< Run the script with the given name (compile first, if not compiled yet)
|
///< Run the script with the given name (compile first, if not compiled yet)
|
||||||
|
|
||||||
virtual bool compile (const std::string& name) = 0;
|
virtual bool compile (const std::string& name) = 0;
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include "../mwgui/mode.hpp"
|
#include "../mwgui/mode.hpp"
|
||||||
|
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
namespace Loading
|
namespace Loading
|
||||||
{
|
{
|
||||||
class Listener;
|
class Listener;
|
||||||
|
@ -86,7 +88,7 @@ namespace SFO
|
||||||
namespace MWBase
|
namespace MWBase
|
||||||
{
|
{
|
||||||
/// \brief Interface for widnow manager (implemented in MWGui)
|
/// \brief Interface for widnow manager (implemented in MWGui)
|
||||||
class WindowManager
|
class WindowManager : public SDLUtil::WindowListener
|
||||||
{
|
{
|
||||||
WindowManager (const WindowManager&);
|
WindowManager (const WindowManager&);
|
||||||
///< not implemented
|
///< not implemented
|
||||||
|
@ -344,8 +346,6 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& changed) = 0;
|
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& changed) = 0;
|
||||||
|
|
||||||
virtual void windowResized(int x, int y) = 0;
|
|
||||||
|
|
||||||
virtual void executeInConsole (const std::string& path) = 0;
|
virtual void executeInConsole (const std::string& path) = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -446,6 +446,11 @@ namespace MWBase
|
||||||
|
|
||||||
virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text, bool repeat) = 0;
|
virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text, bool repeat) = 0;
|
||||||
virtual bool injectKeyRelease(MyGUI::KeyCode key) = 0;
|
virtual bool injectKeyRelease(MyGUI::KeyCode key) = 0;
|
||||||
|
|
||||||
|
virtual void windowVisibilityChange(bool visible) = 0;
|
||||||
|
virtual void windowResized(int x, int y) = 0;
|
||||||
|
virtual void windowClosed() = 0;
|
||||||
|
virtual bool isWindowVisible() = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -200,6 +200,8 @@ namespace MWBase
|
||||||
virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0;
|
virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0;
|
||||||
///< Search is limited to the active cells.
|
///< Search is limited to the active cells.
|
||||||
|
|
||||||
|
virtual MWWorld::Ptr searchPtrViaRefNum (const std::string& id, const ESM::RefNum& refNum) = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
|
|
@ -240,6 +240,7 @@ namespace MWGui
|
||||||
MyGUI::IntCoord(mx*mMapWidgetSize, my*mMapWidgetSize, mMapWidgetSize, mMapWidgetSize),
|
MyGUI::IntCoord(mx*mMapWidgetSize, my*mMapWidgetSize, mMapWidgetSize, mMapWidgetSize),
|
||||||
MyGUI::Align::Top | MyGUI::Align::Left);
|
MyGUI::Align::Top | MyGUI::Align::Left);
|
||||||
fog->setDepth(Local_FogLayer);
|
fog->setDepth(Local_FogLayer);
|
||||||
|
fog->setColour(MyGUI::Colour(0, 0, 0));
|
||||||
|
|
||||||
map->setNeedMouseFocus(false);
|
map->setNeedMouseFocus(false);
|
||||||
fog->setNeedMouseFocus(false);
|
fog->setNeedMouseFocus(false);
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include <components/sdlutil/sdlcursormanager.hpp>
|
#include <components/sdlutil/sdlcursormanager.hpp>
|
||||||
|
#include <components/sdlutil/sdlvideowrapper.hpp>
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
@ -139,7 +140,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
WindowManager::WindowManager(
|
WindowManager::WindowManager(
|
||||||
osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||||
const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage,
|
const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage,
|
||||||
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, const std::string& userDataPath)
|
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, const std::string& userDataPath)
|
||||||
: mOldUpdateMask(0)
|
: mOldUpdateMask(0)
|
||||||
|
@ -208,6 +209,7 @@ namespace MWGui
|
||||||
, mEncoding(encoding)
|
, mEncoding(encoding)
|
||||||
, mFontHeight(16)
|
, mFontHeight(16)
|
||||||
, mVersionDescription(versionDescription)
|
, mVersionDescription(versionDescription)
|
||||||
|
, mWindowVisible(true)
|
||||||
{
|
{
|
||||||
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
||||||
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(), uiScale);
|
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(), uiScale);
|
||||||
|
@ -300,6 +302,10 @@ namespace MWGui
|
||||||
MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested);
|
MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested);
|
||||||
|
|
||||||
mShowOwned = Settings::Manager::getInt("show owned", "Game");
|
mShowOwned = Settings::Manager::getInt("show owned", "Game");
|
||||||
|
|
||||||
|
mVideoWrapper = new SDLUtil::VideoWrapper(window, viewer);
|
||||||
|
mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"),
|
||||||
|
Settings::Manager::getFloat("contrast", "Video"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::loadFontDelegate(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version)
|
void WindowManager::loadFontDelegate(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version)
|
||||||
|
@ -674,6 +680,7 @@ namespace MWGui
|
||||||
|
|
||||||
mGuiPlatform->shutdown();
|
mGuiPlatform->shutdown();
|
||||||
delete mGuiPlatform;
|
delete mGuiPlatform;
|
||||||
|
delete mVideoWrapper;
|
||||||
}
|
}
|
||||||
catch(const MyGUI::Exception& e)
|
catch(const MyGUI::Exception& e)
|
||||||
{
|
{
|
||||||
|
@ -946,7 +953,7 @@ namespace MWGui
|
||||||
mMessageBoxManager->onFrame(dt);
|
mMessageBoxManager->onFrame(dt);
|
||||||
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
||||||
|
|
||||||
if (!MWBase::Environment::get().getInputManager()->isWindowVisible())
|
if (!mWindowVisible)
|
||||||
OpenThreads::Thread::microSleep(5000);
|
OpenThreads::Thread::microSleep(5000);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1312,6 +1319,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI"));
|
mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI"));
|
||||||
|
|
||||||
|
bool changeRes = false;
|
||||||
for (const auto& setting : changed)
|
for (const auto& setting : changed)
|
||||||
{
|
{
|
||||||
if (setting.first == "HUD" && setting.second == "crosshair")
|
if (setting.first == "HUD" && setting.second == "crosshair")
|
||||||
|
@ -1320,11 +1328,38 @@ namespace MWGui
|
||||||
mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI");
|
mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI");
|
||||||
else if (setting.first == "GUI" && setting.second == "menu transparency")
|
else if (setting.first == "GUI" && setting.second == "menu transparency")
|
||||||
setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI"));
|
setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI"));
|
||||||
|
else if (setting.first == "Video" && (
|
||||||
|
setting.second == "resolution x"
|
||||||
|
|| setting.second == "resolution y"
|
||||||
|
|| setting.second == "fullscreen"
|
||||||
|
|| setting.second == "window border"))
|
||||||
|
changeRes = true;
|
||||||
|
|
||||||
|
else if (setting.first == "Video" && setting.second == "vsync")
|
||||||
|
mVideoWrapper->setSyncToVBlank(Settings::Manager::getBool("vsync", "Video"));
|
||||||
|
else if (setting.first == "Video" && (setting.second == "gamma" || setting.second == "contrast"))
|
||||||
|
mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"),
|
||||||
|
Settings::Manager::getFloat("contrast", "Video"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changeRes)
|
||||||
|
{
|
||||||
|
mVideoWrapper->setVideoMode(Settings::Manager::getInt("resolution x", "Video"),
|
||||||
|
Settings::Manager::getInt("resolution y", "Video"),
|
||||||
|
Settings::Manager::getBool("fullscreen", "Video"),
|
||||||
|
Settings::Manager::getBool("window border", "Video"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::windowResized(int x, int y)
|
void WindowManager::windowResized(int x, int y)
|
||||||
{
|
{
|
||||||
|
// Note: this is a side effect of resolution change or window resize.
|
||||||
|
// There is no need to track these changes.
|
||||||
|
Settings::Manager::setInt("resolution x", "Video", x);
|
||||||
|
Settings::Manager::setInt("resolution y", "Video", y);
|
||||||
|
Settings::Manager::resetPendingChange("resolution x", "Video");
|
||||||
|
Settings::Manager::resetPendingChange("resolution y", "Video");
|
||||||
|
|
||||||
mGuiPlatform->getRenderManagerPtr()->setViewSize(x, y);
|
mGuiPlatform->getRenderManagerPtr()->setViewSize(x, y);
|
||||||
|
|
||||||
// scaled size
|
// scaled size
|
||||||
|
@ -1354,9 +1389,27 @@ namespace MWGui
|
||||||
for (WindowBase* window : mWindows)
|
for (WindowBase* window : mWindows)
|
||||||
window->onResChange(x, y);
|
window->onResChange(x, y);
|
||||||
|
|
||||||
|
// We should reload TrueType fonts to fit new resolution
|
||||||
|
loadUserFonts();
|
||||||
|
|
||||||
// TODO: check if any windows are now off-screen and move them back if so
|
// TODO: check if any windows are now off-screen and move them back if so
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WindowManager::isWindowVisible()
|
||||||
|
{
|
||||||
|
return mWindowVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::windowVisibilityChange(bool visible)
|
||||||
|
{
|
||||||
|
mWindowVisible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::windowClosed()
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getStateManager()->requestQuit();
|
||||||
|
}
|
||||||
|
|
||||||
void WindowManager::onCursorChange(const std::string &name)
|
void WindowManager::onCursorChange(const std::string &name)
|
||||||
{
|
{
|
||||||
mCursorManager->cursorChanged(name);
|
mCursorManager->cursorChanged(name);
|
||||||
|
@ -2054,7 +2107,7 @@ namespace MWGui
|
||||||
|
|
||||||
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
MWBase::Environment::get().getInputManager()->update(dt, true, false);
|
||||||
|
|
||||||
if (!MWBase::Environment::get().getInputManager()->isWindowVisible())
|
if (!mWindowVisible)
|
||||||
{
|
{
|
||||||
mVideoWidget->pause();
|
mVideoWidget->pause();
|
||||||
OpenThreads::Thread::microSleep(5000);
|
OpenThreads::Thread::microSleep(5000);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/to_utf8/to_utf8.hpp>
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
|
@ -70,6 +71,7 @@ namespace SceneUtil
|
||||||
namespace SDLUtil
|
namespace SDLUtil
|
||||||
{
|
{
|
||||||
class SDLCursorManager;
|
class SDLCursorManager;
|
||||||
|
class VideoWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace osgMyGUI
|
namespace osgMyGUI
|
||||||
|
@ -124,13 +126,14 @@ namespace MWGui
|
||||||
class JailScreen;
|
class JailScreen;
|
||||||
class KeyboardNavigation;
|
class KeyboardNavigation;
|
||||||
|
|
||||||
class WindowManager : public MWBase::WindowManager
|
class WindowManager :
|
||||||
|
public MWBase::WindowManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::pair<std::string, int> Faction;
|
typedef std::pair<std::string, int> Faction;
|
||||||
typedef std::vector<Faction> FactionList;
|
typedef std::vector<Faction> FactionList;
|
||||||
|
|
||||||
WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
WindowManager(SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||||
const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage,
|
const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage,
|
||||||
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, const std::string& localPath);
|
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, const std::string& localPath);
|
||||||
virtual ~WindowManager();
|
virtual ~WindowManager();
|
||||||
|
@ -372,7 +375,10 @@ namespace MWGui
|
||||||
|
|
||||||
virtual void processChangedSettings(const Settings::CategorySettingVector& changed);
|
virtual void processChangedSettings(const Settings::CategorySettingVector& changed);
|
||||||
|
|
||||||
|
virtual void windowVisibilityChange(bool visible);
|
||||||
virtual void windowResized(int x, int y);
|
virtual void windowResized(int x, int y);
|
||||||
|
virtual void windowClosed();
|
||||||
|
virtual bool isWindowVisible();
|
||||||
|
|
||||||
virtual void executeInConsole (const std::string& path);
|
virtual void executeInConsole (const std::string& path);
|
||||||
|
|
||||||
|
@ -626,10 +632,14 @@ namespace MWGui
|
||||||
|
|
||||||
std::string mVersionDescription;
|
std::string mVersionDescription;
|
||||||
|
|
||||||
|
bool mWindowVisible;
|
||||||
|
|
||||||
MWGui::TextColours mTextColours;
|
MWGui::TextColours mTextColours;
|
||||||
|
|
||||||
std::unique_ptr<KeyboardNavigation> mKeyboardNavigation;
|
std::unique_ptr<KeyboardNavigation> mKeyboardNavigation;
|
||||||
|
|
||||||
|
SDLUtil::VideoWrapper* mVideoWrapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property.
|
* Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property.
|
||||||
* Supported syntax:
|
* Supported syntax:
|
||||||
|
|
665
apps/openmw/mwinput/actionmanager.cpp
Normal file
665
apps/openmw/mwinput/actionmanager.cpp
Normal file
|
@ -0,0 +1,665 @@
|
||||||
|
#include "actionmanager.hpp"
|
||||||
|
|
||||||
|
#include <MyGUI_InputManager.h>
|
||||||
|
|
||||||
|
#include <SDL_keyboard.h>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Include additional headers for multiplayer purposes
|
||||||
|
*/
|
||||||
|
#include "../mwmp/Main.hpp"
|
||||||
|
#include "../mwmp/LocalPlayer.hpp"
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
|
||||||
|
#include "actions.hpp"
|
||||||
|
#include "bindingsmanager.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
const float ZOOM_SCALE = 120.f; /// Used for scrolling camera in and out
|
||||||
|
|
||||||
|
ActionManager::ActionManager(BindingsManager* bindingsManager,
|
||||||
|
osgViewer::ScreenCaptureHandler::CaptureOperation* screenCaptureOperation,
|
||||||
|
osg::ref_ptr<osgViewer::Viewer> viewer,
|
||||||
|
osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler)
|
||||||
|
: mBindingsManager(bindingsManager)
|
||||||
|
, mViewer(viewer)
|
||||||
|
, mScreenCaptureHandler(screenCaptureHandler)
|
||||||
|
, mScreenCaptureOperation(screenCaptureOperation)
|
||||||
|
, mAlwaysRunActive(Settings::Manager::getBool("always run", "Input"))
|
||||||
|
, mSneaking(false)
|
||||||
|
, mAttemptJump(false)
|
||||||
|
, mOverencumberedMessageDelay(0.f)
|
||||||
|
, mPreviewPOVDelay(0.f)
|
||||||
|
, mTimeIdle(0.f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::update(float dt, bool triedToMove)
|
||||||
|
{
|
||||||
|
// Disable movement in Gui mode
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()
|
||||||
|
|| MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)
|
||||||
|
{
|
||||||
|
mAttemptJump = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure player movement according to keyboard input. Actual movement will
|
||||||
|
// be done in the physics system.
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
{
|
||||||
|
bool alwaysRunAllowed = false;
|
||||||
|
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
|
||||||
|
if (mBindingsManager->actionIsActive(A_MoveLeft) != mBindingsManager->actionIsActive(A_MoveRight))
|
||||||
|
{
|
||||||
|
alwaysRunAllowed = true;
|
||||||
|
triedToMove = true;
|
||||||
|
player.setLeftRight(mBindingsManager->actionIsActive(A_MoveRight) ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBindingsManager->actionIsActive(A_MoveForward) != mBindingsManager->actionIsActive(A_MoveBackward))
|
||||||
|
{
|
||||||
|
alwaysRunAllowed = true;
|
||||||
|
triedToMove = true;
|
||||||
|
player.setAutoMove (false);
|
||||||
|
player.setForwardBackward(mBindingsManager->actionIsActive(A_MoveForward) ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getAutoMove())
|
||||||
|
{
|
||||||
|
alwaysRunAllowed = true;
|
||||||
|
triedToMove = true;
|
||||||
|
player.setForwardBackward (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mAttemptJump && MWBase::Environment::get().getInputManager()->getControlSwitch("playerjumping"))
|
||||||
|
{
|
||||||
|
player.setUpDown(1);
|
||||||
|
triedToMove = true;
|
||||||
|
mOverencumberedMessageDelay = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if player tried to start moving, but can't (due to being overencumbered), display a notification.
|
||||||
|
if (triedToMove)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||||
|
mOverencumberedMessageDelay -= dt;
|
||||||
|
if (playerPtr.getClass().getEncumbrance(playerPtr) > playerPtr.getClass().getCapacity(playerPtr))
|
||||||
|
{
|
||||||
|
player.setAutoMove (false);
|
||||||
|
if (mOverencumberedMessageDelay <= 0)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage59}");
|
||||||
|
mOverencumberedMessageDelay = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch"))
|
||||||
|
{
|
||||||
|
if (mBindingsManager->actionIsActive(A_TogglePOV))
|
||||||
|
{
|
||||||
|
if (mPreviewPOVDelay <= 0.5 &&
|
||||||
|
(mPreviewPOVDelay += dt) > 0.5)
|
||||||
|
{
|
||||||
|
mPreviewPOVDelay = 1.f;
|
||||||
|
MWBase::Environment::get().getWorld()->togglePreviewMode(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//disable preview mode
|
||||||
|
MWBase::Environment::get().getWorld()->togglePreviewMode(false);
|
||||||
|
if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.5)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->togglePOV();
|
||||||
|
}
|
||||||
|
mPreviewPOVDelay = 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triedToMove)
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
|
||||||
|
static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input");
|
||||||
|
if (!isToggleSneak)
|
||||||
|
{
|
||||||
|
if(!MWBase::Environment::get().getInputManager()->joystickLastUsed())
|
||||||
|
player.setSneak(mBindingsManager->actionIsActive(A_Sneak));
|
||||||
|
}
|
||||||
|
|
||||||
|
float xAxis = mBindingsManager->getActionValue(A_MoveLeftRight);
|
||||||
|
float yAxis = mBindingsManager->getActionValue(A_MoveForwardBackward);
|
||||||
|
bool isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25;
|
||||||
|
if ((mAlwaysRunActive && alwaysRunAllowed) || isRunning)
|
||||||
|
player.setRunState(!mBindingsManager->actionIsActive(A_Run));
|
||||||
|
else
|
||||||
|
player.setRunState(mBindingsManager->actionIsActive(A_Run));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBindingsManager->actionIsActive(A_MoveForward) ||
|
||||||
|
mBindingsManager->actionIsActive(A_MoveBackward) ||
|
||||||
|
mBindingsManager->actionIsActive(A_MoveLeft) ||
|
||||||
|
mBindingsManager->actionIsActive(A_MoveRight) ||
|
||||||
|
mBindingsManager->actionIsActive(A_Jump) ||
|
||||||
|
mBindingsManager->actionIsActive(A_Sneak) ||
|
||||||
|
mBindingsManager->actionIsActive(A_TogglePOV) ||
|
||||||
|
mBindingsManager->actionIsActive(A_ZoomIn) ||
|
||||||
|
mBindingsManager->actionIsActive(A_ZoomOut))
|
||||||
|
{
|
||||||
|
resetIdleTime();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateIdleTime(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
mAttemptJump = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::resetIdleTime()
|
||||||
|
{
|
||||||
|
if (mTimeIdle < 0)
|
||||||
|
MWBase::Environment::get().getWorld()->toggleVanityMode(false);
|
||||||
|
mTimeIdle = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::updateIdleTime(float dt)
|
||||||
|
{
|
||||||
|
static const float vanityDelay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
|
.find("fVanityDelay")->mValue.getFloat();
|
||||||
|
if (mTimeIdle >= 0.f)
|
||||||
|
mTimeIdle += dt;
|
||||||
|
if (mTimeIdle > vanityDelay)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->toggleVanityMode(true);
|
||||||
|
mTimeIdle = -1.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::executeAction(int action)
|
||||||
|
{
|
||||||
|
// trigger action activated
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case A_GameMenu:
|
||||||
|
toggleMainMenu ();
|
||||||
|
break;
|
||||||
|
case A_Screenshot:
|
||||||
|
screenshot();
|
||||||
|
break;
|
||||||
|
case A_Inventory:
|
||||||
|
toggleInventory ();
|
||||||
|
break;
|
||||||
|
case A_Console:
|
||||||
|
toggleConsole ();
|
||||||
|
break;
|
||||||
|
case A_Activate:
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
activate();
|
||||||
|
break;
|
||||||
|
case A_MoveLeft:
|
||||||
|
case A_MoveRight:
|
||||||
|
case A_MoveForward:
|
||||||
|
case A_MoveBackward:
|
||||||
|
handleGuiArrowKey(action);
|
||||||
|
break;
|
||||||
|
case A_Journal:
|
||||||
|
toggleJournal();
|
||||||
|
break;
|
||||||
|
case A_AutoMove:
|
||||||
|
toggleAutoMove();
|
||||||
|
break;
|
||||||
|
case A_AlwaysRun:
|
||||||
|
toggleWalking();
|
||||||
|
break;
|
||||||
|
case A_ToggleWeapon:
|
||||||
|
toggleWeapon();
|
||||||
|
break;
|
||||||
|
case A_Rest:
|
||||||
|
rest();
|
||||||
|
break;
|
||||||
|
case A_ToggleSpell:
|
||||||
|
toggleSpell();
|
||||||
|
break;
|
||||||
|
case A_QuickKey1:
|
||||||
|
quickKey(1);
|
||||||
|
break;
|
||||||
|
case A_QuickKey2:
|
||||||
|
quickKey(2);
|
||||||
|
break;
|
||||||
|
case A_QuickKey3:
|
||||||
|
quickKey(3);
|
||||||
|
break;
|
||||||
|
case A_QuickKey4:
|
||||||
|
quickKey(4);
|
||||||
|
break;
|
||||||
|
case A_QuickKey5:
|
||||||
|
quickKey(5);
|
||||||
|
break;
|
||||||
|
case A_QuickKey6:
|
||||||
|
quickKey(6);
|
||||||
|
break;
|
||||||
|
case A_QuickKey7:
|
||||||
|
quickKey(7);
|
||||||
|
break;
|
||||||
|
case A_QuickKey8:
|
||||||
|
quickKey(8);
|
||||||
|
break;
|
||||||
|
case A_QuickKey9:
|
||||||
|
quickKey(9);
|
||||||
|
break;
|
||||||
|
case A_QuickKey10:
|
||||||
|
quickKey(10);
|
||||||
|
break;
|
||||||
|
case A_QuickKeysMenu:
|
||||||
|
showQuickKeysMenu();
|
||||||
|
break;
|
||||||
|
case A_ToggleHUD:
|
||||||
|
MWBase::Environment::get().getWindowManager()->toggleHud();
|
||||||
|
break;
|
||||||
|
case A_ToggleDebug:
|
||||||
|
MWBase::Environment::get().getWindowManager()->toggleDebugWindow();
|
||||||
|
break;
|
||||||
|
case A_ZoomIn:
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch") && MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols") && !MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
MWBase::Environment::get().getWorld()->setCameraDistance(ZOOM_SCALE, true, true);
|
||||||
|
break;
|
||||||
|
case A_ZoomOut:
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch") && MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols") && !MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
MWBase::Environment::get().getWorld()->setCameraDistance(-ZOOM_SCALE, true, true);
|
||||||
|
break;
|
||||||
|
case A_QuickSave:
|
||||||
|
quickSave();
|
||||||
|
break;
|
||||||
|
case A_QuickLoad:
|
||||||
|
quickLoad();
|
||||||
|
break;
|
||||||
|
case A_CycleSpellLeft:
|
||||||
|
if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic))
|
||||||
|
MWBase::Environment::get().getWindowManager()->cycleSpell(false);
|
||||||
|
break;
|
||||||
|
case A_CycleSpellRight:
|
||||||
|
if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic))
|
||||||
|
MWBase::Environment::get().getWindowManager()->cycleSpell(true);
|
||||||
|
break;
|
||||||
|
case A_CycleWeaponLeft:
|
||||||
|
if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
|
||||||
|
MWBase::Environment::get().getWindowManager()->cycleWeapon(false);
|
||||||
|
break;
|
||||||
|
case A_CycleWeaponRight:
|
||||||
|
if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
|
||||||
|
MWBase::Environment::get().getWindowManager()->cycleWeapon(true);
|
||||||
|
break;
|
||||||
|
case A_Sneak:
|
||||||
|
static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input");
|
||||||
|
if (isToggleSneak)
|
||||||
|
{
|
||||||
|
toggleSneaking();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActionManager::checkAllowedToUseItems() const
|
||||||
|
{
|
||||||
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
|
if (player.getClass().getNpcStats(player).isWerewolf())
|
||||||
|
{
|
||||||
|
// Cannot use items or spells while in werewolf form
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::screenshot()
|
||||||
|
{
|
||||||
|
bool regularScreenshot = true;
|
||||||
|
|
||||||
|
std::string settingStr;
|
||||||
|
|
||||||
|
settingStr = Settings::Manager::getString("screenshot type","Video");
|
||||||
|
regularScreenshot = settingStr.size() == 0 || settingStr.compare("regular") == 0;
|
||||||
|
|
||||||
|
if (regularScreenshot)
|
||||||
|
{
|
||||||
|
mScreenCaptureHandler->setFramesToCapture(1);
|
||||||
|
mScreenCaptureHandler->captureNextFrame(*mViewer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Image> screenshot (new osg::Image);
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWorld()->screenshot360(screenshot.get(), settingStr))
|
||||||
|
{
|
||||||
|
(*mScreenCaptureOperation) (*(screenshot.get()), 0);
|
||||||
|
// FIXME: mScreenCaptureHandler->getCaptureOperation() causes crash for some reason
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleMainMenu()
|
||||||
|
{
|
||||||
|
if (MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->exitCurrentModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->toggleConsole();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||||
|
}
|
||||||
|
else //Close current GUI
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleSpell()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
||||||
|
|
||||||
|
// Not allowed before the magic window is accessible
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playermagic") || !MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!checkAllowedToUseItems())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Not allowed if no spell selected
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
MWWorld::InventoryStore& inventory = player.getPlayer().getClass().getInventoryStore(player.getPlayer());
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->getSelectedSpell().empty() &&
|
||||||
|
inventory.getSelectedEnchantItem() == inventory.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(player.getPlayer()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWMechanics::DrawState_ state = player.getDrawState();
|
||||||
|
if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing)
|
||||||
|
player.setDrawState(MWMechanics::DrawState_Spell);
|
||||||
|
else
|
||||||
|
player.setDrawState(MWMechanics::DrawState_Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::quickLoad()
|
||||||
|
{
|
||||||
|
if (!MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
MWBase::Environment::get().getStateManager()->quickLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::quickSave()
|
||||||
|
{
|
||||||
|
if (!MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
MWBase::Environment::get().getStateManager()->quickSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleWeapon()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
||||||
|
|
||||||
|
// Not allowed before the inventory window is accessible
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playerfighting") || !MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
// We want to interrupt animation only if attack is preparing, but still is not triggered
|
||||||
|
// Otherwise we will get a "speedshooting" exploit, when player can skip reload animation by hitting "Toggle Weapon" key twice
|
||||||
|
if (MWBase::Environment::get().getMechanicsManager()->isAttackPreparing(player.getPlayer()))
|
||||||
|
player.setAttackingOrSpell(false);
|
||||||
|
else if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(player.getPlayer()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWMechanics::DrawState_ state = player.getDrawState();
|
||||||
|
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
|
||||||
|
player.setDrawState(MWMechanics::DrawState_Weapon);
|
||||||
|
else
|
||||||
|
player.setDrawState(MWMechanics::DrawState_Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::rest()
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!MWBase::Environment::get().getWindowManager()->getRestEnabled() || MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Ignore attempts to rest if the player has not logged in on the server yet
|
||||||
|
|
||||||
|
Set LocalPlayer's isUsingBed to be able to distinguish bed use from regular rest
|
||||||
|
menu use
|
||||||
|
*/
|
||||||
|
if (!mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||||
|
return;
|
||||||
|
|
||||||
|
mwmp::Main::get().getLocalPlayer()->isUsingBed = false;
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Rest); //Open rest GUI
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleInventory()
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Ignore attempts to open inventory if the player has not logged in on the server yet
|
||||||
|
*/
|
||||||
|
if (!mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Toggle between game mode and inventory mode
|
||||||
|
if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Inventory);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode();
|
||||||
|
if(mode == MWGui::GM_Inventory || mode == MWGui::GM_Container)
|
||||||
|
MWBase::Environment::get().getWindowManager()->popGuiMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// .. but don't touch any other mode, except container.
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleConsole()
|
||||||
|
{
|
||||||
|
if (MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
If a player's console is disabled by the server, go no further
|
||||||
|
*/
|
||||||
|
if (!mwmp::Main::get().getLocalPlayer()->consoleAllowed)
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->toggleConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleJournal()
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
return;
|
||||||
|
if (MyGUI::InputManager::getInstance ().isModalAny())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Journal
|
||||||
|
&& MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_MainMenu
|
||||||
|
&& MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Settings
|
||||||
|
&& MWBase::Environment::get().getWindowManager ()->getJournalAllowed())
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal);
|
||||||
|
}
|
||||||
|
else if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Journal))
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Journal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::quickKey (int index)
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols") || !MWBase::Environment::get().getInputManager()->getControlSwitch("playerfighting") || !MWBase::Environment::get().getInputManager()->getControlSwitch("playermagic"))
|
||||||
|
return;
|
||||||
|
if (!checkAllowedToUseItems())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")!=-1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
MWBase::Environment::get().getWindowManager()->activateQuickKey (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::showQuickKeysMenu()
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getWindowManager()->isGuiMode ()
|
||||||
|
&& MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1)
|
||||||
|
{
|
||||||
|
if (!checkAllowedToUseItems())
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_QuickKeysMenu);
|
||||||
|
}
|
||||||
|
else if (MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_QuickKeysMenu)
|
||||||
|
{
|
||||||
|
while (MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
{ //Handle any open Modal windows
|
||||||
|
MWBase::Environment::get().getWindowManager()->exitCurrentModal();
|
||||||
|
}
|
||||||
|
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); //And handle the actual main window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::activate()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
{
|
||||||
|
bool joystickUsed = MWBase::Environment::get().getInputManager()->joystickLastUsed();
|
||||||
|
if (!SDL_IsTextInputActive() && !mBindingsManager->isLeftOrRightButton(A_Activate, joystickUsed))
|
||||||
|
MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0, false);
|
||||||
|
}
|
||||||
|
else if (MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleAutoMove()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.setAutoMove (!player.getAutoMove());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleWalking()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode() || SDL_IsTextInputActive()) return;
|
||||||
|
mAlwaysRunActive = !mAlwaysRunActive;
|
||||||
|
|
||||||
|
Settings::Manager::setBool("always run", "Input", mAlwaysRunActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleSneaking()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols")) return;
|
||||||
|
mSneaking = !mSneaking;
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.setSneak(mSneaking);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::handleGuiArrowKey(int action)
|
||||||
|
{
|
||||||
|
bool joystickUsed = MWBase::Environment::get().getInputManager()->joystickLastUsed();
|
||||||
|
// This is currently keyboard-specific code
|
||||||
|
// TODO: see if GUI controls can be refactored into a single function
|
||||||
|
if (joystickUsed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (SDL_IsTextInputActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mBindingsManager->isLeftOrRightButton(action, joystickUsed))
|
||||||
|
return;
|
||||||
|
|
||||||
|
MyGUI::KeyCode key;
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case A_MoveLeft:
|
||||||
|
key = MyGUI::KeyCode::ArrowLeft;
|
||||||
|
break;
|
||||||
|
case A_MoveRight:
|
||||||
|
key = MyGUI::KeyCode::ArrowRight;
|
||||||
|
break;
|
||||||
|
case A_MoveForward:
|
||||||
|
key = MyGUI::KeyCode::ArrowUp;
|
||||||
|
break;
|
||||||
|
case A_MoveBackward:
|
||||||
|
default:
|
||||||
|
key = MyGUI::KeyCode::ArrowDown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false);
|
||||||
|
}
|
||||||
|
}
|
78
apps/openmw/mwinput/actionmanager.hpp
Normal file
78
apps/openmw/mwinput/actionmanager.hpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#ifndef MWINPUT_ACTIONMANAGER_H
|
||||||
|
#define MWINPUT_ACTIONMANAGER_H
|
||||||
|
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
#include <osgViewer/ViewerEventHandlers>
|
||||||
|
|
||||||
|
namespace osgViewer
|
||||||
|
{
|
||||||
|
class Viewer;
|
||||||
|
class ScreenCaptureHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class BindingsManager;
|
||||||
|
|
||||||
|
class ActionManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ActionManager(BindingsManager* bindingsManager,
|
||||||
|
osgViewer::ScreenCaptureHandler::CaptureOperation* screenCaptureOperation,
|
||||||
|
osg::ref_ptr<osgViewer::Viewer> viewer,
|
||||||
|
osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler);
|
||||||
|
|
||||||
|
void update(float dt, bool triedToMove);
|
||||||
|
|
||||||
|
void executeAction(int action);
|
||||||
|
|
||||||
|
bool checkAllowedToUseItems() const;
|
||||||
|
|
||||||
|
void toggleMainMenu();
|
||||||
|
void toggleSpell();
|
||||||
|
void toggleWeapon();
|
||||||
|
void toggleInventory();
|
||||||
|
void toggleConsole();
|
||||||
|
void screenshot();
|
||||||
|
void toggleJournal();
|
||||||
|
void activate();
|
||||||
|
void toggleWalking();
|
||||||
|
void toggleSneaking();
|
||||||
|
void toggleAutoMove();
|
||||||
|
void rest();
|
||||||
|
void quickLoad();
|
||||||
|
void quickSave();
|
||||||
|
|
||||||
|
void quickKey (int index);
|
||||||
|
void showQuickKeysMenu();
|
||||||
|
|
||||||
|
void resetIdleTime();
|
||||||
|
|
||||||
|
bool isAlwaysRunActive() const { return mAlwaysRunActive; };
|
||||||
|
bool isSneaking() const { return mSneaking; };
|
||||||
|
|
||||||
|
void setAttemptJump(bool enabled) { mAttemptJump = enabled; }
|
||||||
|
|
||||||
|
float getPreviewDelay() const { return mPreviewPOVDelay; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handleGuiArrowKey(int action);
|
||||||
|
|
||||||
|
void updateIdleTime(float dt);
|
||||||
|
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
|
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
||||||
|
osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler;
|
||||||
|
osgViewer::ScreenCaptureHandler::CaptureOperation* mScreenCaptureOperation;
|
||||||
|
|
||||||
|
bool mAlwaysRunActive;
|
||||||
|
bool mSneaking;
|
||||||
|
bool mAttemptJump;
|
||||||
|
|
||||||
|
float mOverencumberedMessageDelay;
|
||||||
|
float mPreviewPOVDelay;
|
||||||
|
float mTimeIdle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
79
apps/openmw/mwinput/actions.hpp
Normal file
79
apps/openmw/mwinput/actions.hpp
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#ifndef MWINPUT_ACTIONS_H
|
||||||
|
#define MWINPUT_ACTIONS_H
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
enum Actions
|
||||||
|
{
|
||||||
|
// please add new actions at the bottom, in order to preserve the channel IDs in the key configuration files
|
||||||
|
|
||||||
|
A_GameMenu,
|
||||||
|
|
||||||
|
A_Unused,
|
||||||
|
|
||||||
|
A_Screenshot, // Take a screenshot
|
||||||
|
|
||||||
|
A_Inventory, // Toggle inventory screen
|
||||||
|
|
||||||
|
A_Console, // Toggle console screen
|
||||||
|
|
||||||
|
A_MoveLeft, // Move player left / right
|
||||||
|
A_MoveRight,
|
||||||
|
A_MoveForward, // Forward / Backward
|
||||||
|
A_MoveBackward,
|
||||||
|
|
||||||
|
A_Activate,
|
||||||
|
|
||||||
|
A_Use, //Use weapon, spell, etc.
|
||||||
|
A_Jump,
|
||||||
|
A_AutoMove, //Toggle Auto-move forward
|
||||||
|
A_Rest, //Rest
|
||||||
|
A_Journal, //Journal
|
||||||
|
A_Weapon, //Draw/Sheath weapon
|
||||||
|
A_Spell, //Ready/Unready Casting
|
||||||
|
A_Run, //Run when held
|
||||||
|
A_CycleSpellLeft, //cycling through spells
|
||||||
|
A_CycleSpellRight,
|
||||||
|
A_CycleWeaponLeft, //Cycling through weapons
|
||||||
|
A_CycleWeaponRight,
|
||||||
|
A_ToggleSneak, //Toggles Sneak
|
||||||
|
A_AlwaysRun, //Toggle Walking/Running
|
||||||
|
A_Sneak,
|
||||||
|
|
||||||
|
A_QuickSave,
|
||||||
|
A_QuickLoad,
|
||||||
|
A_QuickMenu,
|
||||||
|
A_ToggleWeapon,
|
||||||
|
A_ToggleSpell,
|
||||||
|
|
||||||
|
A_TogglePOV,
|
||||||
|
|
||||||
|
A_QuickKey1,
|
||||||
|
A_QuickKey2,
|
||||||
|
A_QuickKey3,
|
||||||
|
A_QuickKey4,
|
||||||
|
A_QuickKey5,
|
||||||
|
A_QuickKey6,
|
||||||
|
A_QuickKey7,
|
||||||
|
A_QuickKey8,
|
||||||
|
A_QuickKey9,
|
||||||
|
A_QuickKey10,
|
||||||
|
|
||||||
|
A_QuickKeysMenu,
|
||||||
|
|
||||||
|
A_ToggleHUD,
|
||||||
|
|
||||||
|
A_ToggleDebug,
|
||||||
|
|
||||||
|
A_LookUpDown, //Joystick look
|
||||||
|
A_LookLeftRight,
|
||||||
|
A_MoveForwardBackward,
|
||||||
|
A_MoveLeftRight,
|
||||||
|
|
||||||
|
A_ZoomIn,
|
||||||
|
A_ZoomOut,
|
||||||
|
|
||||||
|
A_Last // Marker for the last item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
746
apps/openmw/mwinput/bindingsmanager.cpp
Normal file
746
apps/openmw/mwinput/bindingsmanager.cpp
Normal file
|
@ -0,0 +1,746 @@
|
||||||
|
#include "bindingsmanager.hpp"
|
||||||
|
|
||||||
|
#include <MyGUI_EditBox.h>
|
||||||
|
|
||||||
|
#include <extern/oics/ICSChannelListener.h>
|
||||||
|
#include <extern/oics/ICSInputControlSystem.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Include additional headers for multiplayer purposes
|
||||||
|
*/
|
||||||
|
#include "../mwmp/Main.hpp"
|
||||||
|
#include "../mwmp/GUIController.hpp"
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
#include "actions.hpp"
|
||||||
|
#include "sdlmappings.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
static const int sFakeDeviceId = 1; //As we only support one controller at a time, use a fake deviceID so we don't lose bindings when switching controllers
|
||||||
|
|
||||||
|
void clearAllKeyBindings(ICS::InputControlSystem* inputBinder, ICS::Control* control)
|
||||||
|
{
|
||||||
|
// right now we don't really need multiple bindings for the same action, so remove all others first
|
||||||
|
if (inputBinder->getKeyBinding(control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN)
|
||||||
|
inputBinder->removeKeyBinding(inputBinder->getKeyBinding(control, ICS::Control::INCREASE));
|
||||||
|
if (inputBinder->getMouseButtonBinding(control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS)
|
||||||
|
inputBinder->removeMouseButtonBinding(inputBinder->getMouseButtonBinding(control, ICS::Control::INCREASE));
|
||||||
|
if (inputBinder->getMouseWheelBinding(control, ICS::Control::INCREASE) != ICS::InputControlSystem::MouseWheelClick::UNASSIGNED)
|
||||||
|
inputBinder->removeMouseWheelBinding(inputBinder->getMouseWheelBinding(control, ICS::Control::INCREASE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearAllControllerBindings(ICS::InputControlSystem* inputBinder, ICS::Control* control)
|
||||||
|
{
|
||||||
|
// right now we don't really need multiple bindings for the same action, so remove all others first
|
||||||
|
if (inputBinder->getJoystickAxisBinding(control, sFakeDeviceId, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN)
|
||||||
|
inputBinder->removeJoystickAxisBinding(sFakeDeviceId, inputBinder->getJoystickAxisBinding(control, sFakeDeviceId, ICS::Control::INCREASE));
|
||||||
|
if (inputBinder->getJoystickButtonBinding(control, sFakeDeviceId, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS)
|
||||||
|
inputBinder->removeJoystickButtonBinding(sFakeDeviceId, inputBinder->getJoystickButtonBinding(control, sFakeDeviceId, ICS::Control::INCREASE));
|
||||||
|
}
|
||||||
|
|
||||||
|
class InputControlSystem : public ICS::InputControlSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InputControlSystem(const std::string& bindingsFile)
|
||||||
|
: ICS::InputControlSystem(bindingsFile, true, nullptr, nullptr, A_Last)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BindingsListener :
|
||||||
|
public ICS::ChannelListener,
|
||||||
|
public ICS::DetectingBindingListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BindingsListener(ICS::InputControlSystem* inputBinder, BindingsManager* bindingsManager)
|
||||||
|
: mInputBinder(inputBinder)
|
||||||
|
, mBindingsManager(bindingsManager)
|
||||||
|
, mDetectingKeyboard(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~BindingsListener() = default;
|
||||||
|
|
||||||
|
virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue)
|
||||||
|
{
|
||||||
|
int action = channel->getNumber();
|
||||||
|
mBindingsManager->actionValueChanged(action, currentValue, previousValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void keyBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
||||||
|
, SDL_Scancode key, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
//Disallow binding escape key
|
||||||
|
if (key==SDL_SCANCODE_ESCAPE)
|
||||||
|
{
|
||||||
|
//Stop binding if esc pressed
|
||||||
|
mInputBinder->cancelDetectingBindingState();
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disallow binding reserved keys
|
||||||
|
if (key == SDL_SCANCODE_F3 || key == SDL_SCANCODE_F4 || key == SDL_SCANCODE_F10)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifndef __APPLE__
|
||||||
|
// Disallow binding Windows/Meta keys
|
||||||
|
if (key == SDL_SCANCODE_LGUI || key == SDL_SCANCODE_RGUI)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!mDetectingKeyboard)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearAllKeyBindings(mInputBinder, control);
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
ICS::DetectingBindingListener::keyBindingDetected(ICS, control, key, direction);
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
||||||
|
, ICS::InputControlSystem::NamedAxis axis, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
// we don't want mouse movement bindings
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
||||||
|
, unsigned int button, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
if (!mDetectingKeyboard)
|
||||||
|
return;
|
||||||
|
clearAllKeyBindings(mInputBinder, control);
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
ICS::DetectingBindingListener::mouseButtonBindingDetected(ICS, control, button, direction);
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mouseWheelBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
||||||
|
, ICS::InputControlSystem::MouseWheelClick click, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
if (!mDetectingKeyboard)
|
||||||
|
return;
|
||||||
|
clearAllKeyBindings(mInputBinder, control);
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
ICS::DetectingBindingListener::mouseWheelBindingDetected(ICS, control, click, direction);
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control
|
||||||
|
, int axis, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
//only allow binding to the trigers
|
||||||
|
if (axis != SDL_CONTROLLER_AXIS_TRIGGERLEFT && axis != SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
|
||||||
|
return;
|
||||||
|
if (mDetectingKeyboard)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearAllControllerBindings(mInputBinder, control);
|
||||||
|
control->setValue(0.5f); //axis bindings must start at 0.5
|
||||||
|
control->setInitialValue(0.5f);
|
||||||
|
ICS::DetectingBindingListener::joystickAxisBindingDetected(ICS, deviceID, control, axis, direction);
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control
|
||||||
|
, unsigned int button, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
if (mDetectingKeyboard)
|
||||||
|
return;
|
||||||
|
clearAllControllerBindings(mInputBinder,control);
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, deviceID, control, button, direction);
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDetectingKeyboard(bool detecting)
|
||||||
|
{
|
||||||
|
mDetectingKeyboard = detecting;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ICS::InputControlSystem* mInputBinder;
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
|
bool mDetectingKeyboard;
|
||||||
|
};
|
||||||
|
|
||||||
|
BindingsManager::BindingsManager(const std::string& userFile, bool userFileExists)
|
||||||
|
: mUserFile(userFile)
|
||||||
|
, mDragDrop(false)
|
||||||
|
{
|
||||||
|
std::string file = userFileExists ? userFile : "";
|
||||||
|
mInputBinder = new InputControlSystem(file);
|
||||||
|
mListener = new BindingsListener(mInputBinder, this);
|
||||||
|
mInputBinder->setDetectingBindingListener(mListener);
|
||||||
|
|
||||||
|
loadKeyDefaults();
|
||||||
|
loadControllerDefaults();
|
||||||
|
|
||||||
|
for (int i = 0; i < A_Last; ++i)
|
||||||
|
{
|
||||||
|
mInputBinder->getChannel(i)->addListener(mListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::setDragDrop(bool dragDrop)
|
||||||
|
{
|
||||||
|
mDragDrop = dragDrop;
|
||||||
|
}
|
||||||
|
|
||||||
|
BindingsManager::~BindingsManager()
|
||||||
|
{
|
||||||
|
mInputBinder->save(mUserFile);
|
||||||
|
delete mInputBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::update(float dt)
|
||||||
|
{
|
||||||
|
// update values of channels (as a result of pressed keys)
|
||||||
|
mInputBinder->update(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BindingsManager::isLeftOrRightButton(int action, bool joystick) const
|
||||||
|
{
|
||||||
|
int mouseBinding = mInputBinder->getMouseButtonBinding(mInputBinder->getControl(action), ICS::Control::INCREASE);
|
||||||
|
if (mouseBinding != ICS_MAX_DEVICE_BUTTONS)
|
||||||
|
return true;
|
||||||
|
int buttonBinding = mInputBinder->getJoystickButtonBinding(mInputBinder->getControl(action), sFakeDeviceId, ICS::Control::INCREASE);
|
||||||
|
if (joystick && (buttonBinding == 0 || buttonBinding == 1))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::setPlayerControlsEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
int playerChannels[] = {A_AutoMove, A_AlwaysRun, A_ToggleWeapon,
|
||||||
|
A_ToggleSpell, A_Rest, A_QuickKey1, A_QuickKey2,
|
||||||
|
A_QuickKey3, A_QuickKey4, A_QuickKey5, A_QuickKey6,
|
||||||
|
A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10,
|
||||||
|
A_Use, A_Journal};
|
||||||
|
|
||||||
|
for(int pc : playerChannels)
|
||||||
|
{
|
||||||
|
mInputBinder->getChannel(pc)->setEnabled(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float BindingsManager::getActionValue (int id) const
|
||||||
|
{
|
||||||
|
return mInputBinder->getChannel(id)->getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BindingsManager::actionIsActive (int id) const
|
||||||
|
{
|
||||||
|
return getActionValue(id) == 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::loadKeyDefaults (bool force)
|
||||||
|
{
|
||||||
|
// using hardcoded key defaults is inevitable, if we want the configuration files to stay valid
|
||||||
|
// across different versions of OpenMW (in the case where another input action is added)
|
||||||
|
std::map<int, SDL_Scancode> defaultKeyBindings;
|
||||||
|
|
||||||
|
//Gets the Keyvalue from the Scancode; gives the button in the same place reguardless of keyboard format
|
||||||
|
defaultKeyBindings[A_Activate] = SDL_SCANCODE_SPACE;
|
||||||
|
defaultKeyBindings[A_MoveBackward] = SDL_SCANCODE_S;
|
||||||
|
defaultKeyBindings[A_MoveForward] = SDL_SCANCODE_W;
|
||||||
|
defaultKeyBindings[A_MoveLeft] = SDL_SCANCODE_A;
|
||||||
|
defaultKeyBindings[A_MoveRight] = SDL_SCANCODE_D;
|
||||||
|
defaultKeyBindings[A_ToggleWeapon] = SDL_SCANCODE_F;
|
||||||
|
defaultKeyBindings[A_ToggleSpell] = SDL_SCANCODE_R;
|
||||||
|
defaultKeyBindings[A_CycleSpellLeft] = SDL_SCANCODE_MINUS;
|
||||||
|
defaultKeyBindings[A_CycleSpellRight] = SDL_SCANCODE_EQUALS;
|
||||||
|
defaultKeyBindings[A_CycleWeaponLeft] = SDL_SCANCODE_LEFTBRACKET;
|
||||||
|
defaultKeyBindings[A_CycleWeaponRight] = SDL_SCANCODE_RIGHTBRACKET;
|
||||||
|
|
||||||
|
defaultKeyBindings[A_QuickKeysMenu] = SDL_SCANCODE_F1;
|
||||||
|
defaultKeyBindings[A_Console] = SDL_SCANCODE_GRAVE;
|
||||||
|
defaultKeyBindings[A_Run] = SDL_SCANCODE_LSHIFT;
|
||||||
|
defaultKeyBindings[A_Sneak] = SDL_SCANCODE_LCTRL;
|
||||||
|
defaultKeyBindings[A_AutoMove] = SDL_SCANCODE_Q;
|
||||||
|
defaultKeyBindings[A_Jump] = SDL_SCANCODE_E;
|
||||||
|
defaultKeyBindings[A_Journal] = SDL_SCANCODE_J;
|
||||||
|
defaultKeyBindings[A_Rest] = SDL_SCANCODE_T;
|
||||||
|
defaultKeyBindings[A_GameMenu] = SDL_SCANCODE_ESCAPE;
|
||||||
|
defaultKeyBindings[A_TogglePOV] = SDL_SCANCODE_TAB;
|
||||||
|
defaultKeyBindings[A_QuickKey1] = SDL_SCANCODE_1;
|
||||||
|
defaultKeyBindings[A_QuickKey2] = SDL_SCANCODE_2;
|
||||||
|
defaultKeyBindings[A_QuickKey3] = SDL_SCANCODE_3;
|
||||||
|
defaultKeyBindings[A_QuickKey4] = SDL_SCANCODE_4;
|
||||||
|
defaultKeyBindings[A_QuickKey5] = SDL_SCANCODE_5;
|
||||||
|
defaultKeyBindings[A_QuickKey6] = SDL_SCANCODE_6;
|
||||||
|
defaultKeyBindings[A_QuickKey7] = SDL_SCANCODE_7;
|
||||||
|
defaultKeyBindings[A_QuickKey8] = SDL_SCANCODE_8;
|
||||||
|
defaultKeyBindings[A_QuickKey9] = SDL_SCANCODE_9;
|
||||||
|
defaultKeyBindings[A_QuickKey10] = SDL_SCANCODE_0;
|
||||||
|
defaultKeyBindings[A_Screenshot] = SDL_SCANCODE_F12;
|
||||||
|
defaultKeyBindings[A_ToggleHUD] = SDL_SCANCODE_F11;
|
||||||
|
defaultKeyBindings[A_ToggleDebug] = SDL_SCANCODE_F10;
|
||||||
|
defaultKeyBindings[A_AlwaysRun] = SDL_SCANCODE_CAPSLOCK;
|
||||||
|
defaultKeyBindings[A_QuickSave] = SDL_SCANCODE_F5;
|
||||||
|
defaultKeyBindings[A_QuickLoad] = SDL_SCANCODE_F9;
|
||||||
|
|
||||||
|
std::map<int, int> defaultMouseButtonBindings;
|
||||||
|
defaultMouseButtonBindings[A_Inventory] = SDL_BUTTON_RIGHT;
|
||||||
|
defaultMouseButtonBindings[A_Use] = SDL_BUTTON_LEFT;
|
||||||
|
|
||||||
|
std::map<int, ICS::InputControlSystem::MouseWheelClick> defaultMouseWheelBindings;
|
||||||
|
defaultMouseWheelBindings[A_ZoomIn] = ICS::InputControlSystem::MouseWheelClick::UP;
|
||||||
|
defaultMouseWheelBindings[A_ZoomOut] = ICS::InputControlSystem::MouseWheelClick::DOWN;
|
||||||
|
|
||||||
|
for (int i = 0; i < A_Last; ++i)
|
||||||
|
{
|
||||||
|
ICS::Control* control;
|
||||||
|
bool controlExists = mInputBinder->getChannel(i)->getControlsCount() != 0;
|
||||||
|
if (!controlExists)
|
||||||
|
{
|
||||||
|
control = new ICS::Control(std::to_string(i), false, true, 0, ICS::ICS_MAX, ICS::ICS_MAX);
|
||||||
|
mInputBinder->addControl(control);
|
||||||
|
control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
control = mInputBinder->getChannel(i)->getAttachedControls().front().control;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!controlExists || force ||
|
||||||
|
(mInputBinder->getKeyBinding(control, ICS::Control::INCREASE) == SDL_SCANCODE_UNKNOWN
|
||||||
|
&& mInputBinder->getMouseButtonBinding(control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS
|
||||||
|
&& mInputBinder->getMouseWheelBinding(control, ICS::Control::INCREASE) == ICS::InputControlSystem::MouseWheelClick::UNASSIGNED))
|
||||||
|
{
|
||||||
|
clearAllKeyBindings(mInputBinder, control);
|
||||||
|
|
||||||
|
if (defaultKeyBindings.find(i) != defaultKeyBindings.end()
|
||||||
|
&& (force || !mInputBinder->isKeyBound(defaultKeyBindings[i])))
|
||||||
|
{
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
mInputBinder->addKeyBinding(control, defaultKeyBindings[i], ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end()
|
||||||
|
&& (force || !mInputBinder->isMouseButtonBound(defaultMouseButtonBindings[i])))
|
||||||
|
{
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
mInputBinder->addMouseButtonBinding(control, defaultMouseButtonBindings[i], ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
else if (defaultMouseWheelBindings.find(i) != defaultMouseWheelBindings.end()
|
||||||
|
&& (force || !mInputBinder->isMouseWheelBound(defaultMouseWheelBindings[i])))
|
||||||
|
{
|
||||||
|
control->setInitialValue(0.f);
|
||||||
|
mInputBinder->addMouseWheelBinding(control, defaultMouseWheelBindings[i], ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == A_LookLeftRight && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_4) && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_6))
|
||||||
|
{
|
||||||
|
mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_6, ICS::Control::INCREASE);
|
||||||
|
mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_4, ICS::Control::DECREASE);
|
||||||
|
}
|
||||||
|
if (i == A_LookUpDown && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_8) && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_2))
|
||||||
|
{
|
||||||
|
mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_2, ICS::Control::INCREASE);
|
||||||
|
mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_8, ICS::Control::DECREASE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::loadControllerDefaults(bool force)
|
||||||
|
{
|
||||||
|
// using hardcoded key defaults is inevitable, if we want the configuration files to stay valid
|
||||||
|
// across different versions of OpenMW (in the case where another input action is added)
|
||||||
|
std::map<int, int> defaultButtonBindings;
|
||||||
|
|
||||||
|
defaultButtonBindings[A_Activate] = SDL_CONTROLLER_BUTTON_A;
|
||||||
|
defaultButtonBindings[A_ToggleWeapon] = SDL_CONTROLLER_BUTTON_X;
|
||||||
|
defaultButtonBindings[A_ToggleSpell] = SDL_CONTROLLER_BUTTON_Y;
|
||||||
|
//defaultButtonBindings[A_QuickButtonsMenu] = SDL_GetButtonFromScancode(SDL_SCANCODE_F1); // Need to implement, should be ToggleSpell(5) AND Wait(9)
|
||||||
|
defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_LEFTSTICK;
|
||||||
|
defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||||
|
defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||||
|
defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
||||||
|
defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B;
|
||||||
|
defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START;
|
||||||
|
defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE;
|
||||||
|
defaultButtonBindings[A_MoveForward] = SDL_CONTROLLER_BUTTON_DPAD_UP;
|
||||||
|
defaultButtonBindings[A_MoveLeft] = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
|
||||||
|
defaultButtonBindings[A_MoveBackward] = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
|
||||||
|
defaultButtonBindings[A_MoveRight] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
|
||||||
|
|
||||||
|
std::map<int, int> defaultAxisBindings;
|
||||||
|
defaultAxisBindings[A_MoveForwardBackward] = SDL_CONTROLLER_AXIS_LEFTY;
|
||||||
|
defaultAxisBindings[A_MoveLeftRight] = SDL_CONTROLLER_AXIS_LEFTX;
|
||||||
|
defaultAxisBindings[A_LookUpDown] = SDL_CONTROLLER_AXIS_RIGHTY;
|
||||||
|
defaultAxisBindings[A_LookLeftRight] = SDL_CONTROLLER_AXIS_RIGHTX;
|
||||||
|
defaultAxisBindings[A_Use] = SDL_CONTROLLER_AXIS_TRIGGERRIGHT;
|
||||||
|
defaultAxisBindings[A_Jump] = SDL_CONTROLLER_AXIS_TRIGGERLEFT;
|
||||||
|
|
||||||
|
for (int i = 0; i < A_Last; i++)
|
||||||
|
{
|
||||||
|
ICS::Control* control;
|
||||||
|
bool controlExists = mInputBinder->getChannel(i)->getControlsCount() != 0;
|
||||||
|
if (!controlExists)
|
||||||
|
{
|
||||||
|
float initial;
|
||||||
|
if (defaultAxisBindings.find(i) == defaultAxisBindings.end())
|
||||||
|
initial = 0.0f;
|
||||||
|
else initial = 0.5f;
|
||||||
|
control = new ICS::Control(std::to_string(i), false, true, initial, ICS::ICS_MAX, ICS::ICS_MAX);
|
||||||
|
mInputBinder->addControl(control);
|
||||||
|
control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
control = mInputBinder->getChannel(i)->getAttachedControls().front().control;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!controlExists || force || (mInputBinder->getJoystickAxisBinding(control, sFakeDeviceId, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED &&
|
||||||
|
mInputBinder->getJoystickButtonBinding(control, sFakeDeviceId, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS))
|
||||||
|
{
|
||||||
|
clearAllControllerBindings(mInputBinder, control);
|
||||||
|
|
||||||
|
if (defaultButtonBindings.find(i) != defaultButtonBindings.end()
|
||||||
|
&& (force || !mInputBinder->isJoystickButtonBound(sFakeDeviceId, defaultButtonBindings[i])))
|
||||||
|
{
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
mInputBinder->addJoystickButtonBinding(control, sFakeDeviceId, defaultButtonBindings[i], ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
else if (defaultAxisBindings.find(i) != defaultAxisBindings.end() && (force || !mInputBinder->isJoystickAxisBound(sFakeDeviceId, defaultAxisBindings[i])))
|
||||||
|
{
|
||||||
|
control->setValue(0.5f);
|
||||||
|
control->setInitialValue(0.5f);
|
||||||
|
mInputBinder->addJoystickAxisBinding(control, sFakeDeviceId, defaultAxisBindings[i], ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BindingsManager::getActionDescription(int action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case A_Screenshot:
|
||||||
|
return "Screenshot";
|
||||||
|
case A_ZoomIn:
|
||||||
|
return "Zoom In";
|
||||||
|
case A_ZoomOut:
|
||||||
|
return "Zoom Out";
|
||||||
|
case A_ToggleHUD:
|
||||||
|
return "Toggle HUD";
|
||||||
|
case A_Use:
|
||||||
|
return "#{sUse}";
|
||||||
|
case A_Activate:
|
||||||
|
return "#{sActivate}";
|
||||||
|
case A_MoveBackward:
|
||||||
|
return "#{sBack}";
|
||||||
|
case A_MoveForward:
|
||||||
|
return "#{sForward}";
|
||||||
|
case A_MoveLeft:
|
||||||
|
return "#{sLeft}";
|
||||||
|
case A_MoveRight:
|
||||||
|
return "#{sRight}";
|
||||||
|
case A_ToggleWeapon:
|
||||||
|
return "#{sReady_Weapon}";
|
||||||
|
case A_ToggleSpell:
|
||||||
|
return "#{sReady_Magic}";
|
||||||
|
case A_CycleSpellLeft:
|
||||||
|
return "#{sPrevSpell}";
|
||||||
|
case A_CycleSpellRight:
|
||||||
|
return "#{sNextSpell}";
|
||||||
|
case A_CycleWeaponLeft:
|
||||||
|
return "#{sPrevWeapon}";
|
||||||
|
case A_CycleWeaponRight:
|
||||||
|
return "#{sNextWeapon}";
|
||||||
|
case A_Console:
|
||||||
|
return "#{sConsoleTitle}";
|
||||||
|
case A_Run:
|
||||||
|
return "#{sRun}";
|
||||||
|
case A_Sneak:
|
||||||
|
return "#{sCrouch_Sneak}";
|
||||||
|
case A_AutoMove:
|
||||||
|
return "#{sAuto_Run}";
|
||||||
|
case A_Jump:
|
||||||
|
return "#{sJump}";
|
||||||
|
case A_Journal:
|
||||||
|
return "#{sJournal}";
|
||||||
|
case A_Rest:
|
||||||
|
return "#{sRestKey}";
|
||||||
|
case A_Inventory:
|
||||||
|
return "#{sInventory}";
|
||||||
|
case A_TogglePOV:
|
||||||
|
return "#{sTogglePOVCmd}";
|
||||||
|
case A_QuickKeysMenu:
|
||||||
|
return "#{sQuickMenu}";
|
||||||
|
case A_QuickKey1:
|
||||||
|
return "#{sQuick1Cmd}";
|
||||||
|
case A_QuickKey2:
|
||||||
|
return "#{sQuick2Cmd}";
|
||||||
|
case A_QuickKey3:
|
||||||
|
return "#{sQuick3Cmd}";
|
||||||
|
case A_QuickKey4:
|
||||||
|
return "#{sQuick4Cmd}";
|
||||||
|
case A_QuickKey5:
|
||||||
|
return "#{sQuick5Cmd}";
|
||||||
|
case A_QuickKey6:
|
||||||
|
return "#{sQuick6Cmd}";
|
||||||
|
case A_QuickKey7:
|
||||||
|
return "#{sQuick7Cmd}";
|
||||||
|
case A_QuickKey8:
|
||||||
|
return "#{sQuick8Cmd}";
|
||||||
|
case A_QuickKey9:
|
||||||
|
return "#{sQuick9Cmd}";
|
||||||
|
case A_QuickKey10:
|
||||||
|
return "#{sQuick10Cmd}";
|
||||||
|
case A_AlwaysRun:
|
||||||
|
return "#{sAlways_Run}";
|
||||||
|
case A_QuickSave:
|
||||||
|
return "#{sQuickSaveCmd}";
|
||||||
|
case A_QuickLoad:
|
||||||
|
return "#{sQuickLoadCmd}";
|
||||||
|
default:
|
||||||
|
return std::string(); // not configurable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BindingsManager::getActionKeyBindingName(int action)
|
||||||
|
{
|
||||||
|
if (mInputBinder->getChannel(action)->getControlsCount() == 0)
|
||||||
|
return "#{sNone}";
|
||||||
|
|
||||||
|
ICS::Control* c = mInputBinder->getChannel(action)->getAttachedControls().front().control;
|
||||||
|
|
||||||
|
SDL_Scancode key = mInputBinder->getKeyBinding(c, ICS::Control::INCREASE);
|
||||||
|
unsigned int mouse = mInputBinder->getMouseButtonBinding(c, ICS::Control::INCREASE);
|
||||||
|
ICS::InputControlSystem::MouseWheelClick wheel = mInputBinder->getMouseWheelBinding(c, ICS::Control::INCREASE);
|
||||||
|
if (key != SDL_SCANCODE_UNKNOWN)
|
||||||
|
return MyGUI::TextIterator::toTagsString(mInputBinder->scancodeToString(key));
|
||||||
|
else if (mouse != ICS_MAX_DEVICE_BUTTONS)
|
||||||
|
return "#{sMouse} " + std::to_string(mouse);
|
||||||
|
else if (wheel != ICS::InputControlSystem::MouseWheelClick::UNASSIGNED)
|
||||||
|
switch (wheel)
|
||||||
|
{
|
||||||
|
case ICS::InputControlSystem::MouseWheelClick::UP:
|
||||||
|
return "Mouse Wheel Up";
|
||||||
|
case ICS::InputControlSystem::MouseWheelClick::DOWN:
|
||||||
|
return "Mouse Wheel Down";
|
||||||
|
case ICS::InputControlSystem::MouseWheelClick::RIGHT:
|
||||||
|
return "Mouse Wheel Right";
|
||||||
|
case ICS::InputControlSystem::MouseWheelClick::LEFT:
|
||||||
|
return "Mouse Wheel Left";
|
||||||
|
default:
|
||||||
|
return "#{sNone}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "#{sNone}";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BindingsManager::getActionControllerBindingName(int action)
|
||||||
|
{
|
||||||
|
if (mInputBinder->getChannel(action)->getControlsCount() == 0)
|
||||||
|
return "#{sNone}";
|
||||||
|
|
||||||
|
ICS::Control* c = mInputBinder->getChannel(action)->getAttachedControls().front().control;
|
||||||
|
|
||||||
|
if (mInputBinder->getJoystickAxisBinding(c, sFakeDeviceId, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED)
|
||||||
|
return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding(c, sFakeDeviceId, ICS::Control::INCREASE));
|
||||||
|
else if (mInputBinder->getJoystickButtonBinding(c, sFakeDeviceId, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS)
|
||||||
|
return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding(c, sFakeDeviceId, ICS::Control::INCREASE));
|
||||||
|
else
|
||||||
|
return "#{sNone}";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> BindingsManager::getActionKeySorting()
|
||||||
|
{
|
||||||
|
static const std::vector<int> actions
|
||||||
|
{
|
||||||
|
A_MoveForward, A_MoveBackward, A_MoveLeft, A_MoveRight, A_TogglePOV, A_ZoomIn, A_ZoomOut,
|
||||||
|
A_Run, A_AlwaysRun, A_Sneak, A_Activate, A_Use, A_ToggleWeapon, A_ToggleSpell,
|
||||||
|
A_CycleSpellLeft, A_CycleSpellRight, A_CycleWeaponLeft, A_CycleWeaponRight, A_AutoMove,
|
||||||
|
A_Jump, A_Inventory, A_Journal, A_Rest, A_Console, A_QuickSave, A_QuickLoad,
|
||||||
|
A_ToggleHUD, A_Screenshot, A_QuickKeysMenu, A_QuickKey1, A_QuickKey2, A_QuickKey3,
|
||||||
|
A_QuickKey4, A_QuickKey5, A_QuickKey6, A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10
|
||||||
|
};
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
std::vector<int> BindingsManager::getActionControllerSorting()
|
||||||
|
{
|
||||||
|
static const std::vector<int> actions
|
||||||
|
{
|
||||||
|
A_TogglePOV, A_ZoomIn, A_ZoomOut, A_Sneak, A_Activate, A_Use, A_ToggleWeapon, A_ToggleSpell,
|
||||||
|
A_AutoMove, A_Jump, A_Inventory, A_Journal, A_Rest, A_QuickSave, A_QuickLoad, A_ToggleHUD,
|
||||||
|
A_Screenshot, A_QuickKeysMenu, A_QuickKey1, A_QuickKey2, A_QuickKey3, A_QuickKey4,
|
||||||
|
A_QuickKey5, A_QuickKey6, A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10,
|
||||||
|
A_CycleSpellLeft, A_CycleSpellRight, A_CycleWeaponLeft, A_CycleWeaponRight
|
||||||
|
};
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::enableDetectingBindingMode(int action, bool keyboard)
|
||||||
|
{
|
||||||
|
mListener->setDetectingKeyboard(keyboard);
|
||||||
|
ICS::Control* c = mInputBinder->getChannel(action)->getAttachedControls().front().control;
|
||||||
|
mInputBinder->enableDetectingBindingState(c, ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BindingsManager::isDetectingBindingState() const
|
||||||
|
{
|
||||||
|
return mInputBinder->detectingBindingState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::mousePressed(const SDL_MouseButtonEvent &arg, int deviceID)
|
||||||
|
{
|
||||||
|
mInputBinder->mousePressed(arg, deviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::mouseReleased(const SDL_MouseButtonEvent &arg, int deviceID)
|
||||||
|
{
|
||||||
|
mInputBinder->mouseReleased(arg, deviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::mouseMoved(const SDLUtil::MouseMotionEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->mouseMoved(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::mouseWheelMoved(const SDL_MouseWheelEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->mouseWheelMoved(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::keyPressed(const SDL_KeyboardEvent &arg)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Pass the pressed key to the multiplayer-specific GUI controller
|
||||||
|
*/
|
||||||
|
mwmp::Main::get().getGUIController()->pressedKey(arg.keysym.scancode);
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
mInputBinder->keyPressed(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::keyReleased(const SDL_KeyboardEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->keyReleased(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->controllerAdded(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->controllerRemoved(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::controllerButtonPressed(int deviceID, const SDL_ControllerButtonEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->buttonPressed(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::controllerButtonReleased(int deviceID, const SDL_ControllerButtonEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->buttonReleased(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::controllerAxisMoved(int deviceID, const SDL_ControllerAxisEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->axisMoved(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Scancode BindingsManager::getKeyBinding(int actionId)
|
||||||
|
{
|
||||||
|
return mInputBinder->getKeyBinding(mInputBinder->getControl(actionId), ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::actionValueChanged(int action, float currentValue, float previousValue)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
|
||||||
|
if (mDragDrop && action != A_GameMenu && action != A_Inventory)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((previousValue == 1 || previousValue == 0) && (currentValue==1 || currentValue==0))
|
||||||
|
{
|
||||||
|
//Is a normal button press, so don't change it at all
|
||||||
|
}
|
||||||
|
//Otherwise only trigger button presses as they go through specific points
|
||||||
|
else if (previousValue >= 0.8 && currentValue < 0.8)
|
||||||
|
{
|
||||||
|
currentValue = 0.0;
|
||||||
|
previousValue = 1.0;
|
||||||
|
}
|
||||||
|
else if (previousValue <= 0.6 && currentValue > 0.6)
|
||||||
|
{
|
||||||
|
currentValue = 1.0;
|
||||||
|
previousValue = 0.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//If it's not switching between those values, ignore the channel change.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
{
|
||||||
|
bool joystickUsed = MWBase::Environment::get().getInputManager()->joystickLastUsed();
|
||||||
|
if (action == A_Use)
|
||||||
|
{
|
||||||
|
if (joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon))
|
||||||
|
action = A_CycleWeaponRight;
|
||||||
|
|
||||||
|
else if (joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell))
|
||||||
|
action = A_CycleSpellRight;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Prevent players from starting attacks while in the persuasion submenu in dialogue
|
||||||
|
*/
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue))
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
MWMechanics::DrawState_ state = player.getDrawState();
|
||||||
|
player.setAttackingOrSpell(currentValue != 0 && state != MWMechanics::DrawState_Nothing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (action == A_Jump)
|
||||||
|
{
|
||||||
|
if (joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon))
|
||||||
|
action = A_CycleWeaponLeft;
|
||||||
|
|
||||||
|
else if (joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell))
|
||||||
|
action = A_CycleSpellLeft;
|
||||||
|
|
||||||
|
else
|
||||||
|
MWBase::Environment::get().getInputManager()->setAttemptJump(currentValue == 1.0 && previousValue == 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentValue == 1)
|
||||||
|
MWBase::Environment::get().getInputManager()->executeAction(action);
|
||||||
|
}
|
||||||
|
}
|
73
apps/openmw/mwinput/bindingsmanager.hpp
Normal file
73
apps/openmw/mwinput/bindingsmanager.hpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#ifndef MWINPUT_MWBINDINGSMANAGER_H
|
||||||
|
#define MWINPUT_MWBINDINGSMANAGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class BindingsListener;
|
||||||
|
class InputControlSystem;
|
||||||
|
|
||||||
|
class BindingsManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BindingsManager(const std::string& userFile, bool userFileExists);
|
||||||
|
|
||||||
|
virtual ~BindingsManager();
|
||||||
|
|
||||||
|
std::string getActionDescription (int action);
|
||||||
|
std::string getActionKeyBindingName (int action);
|
||||||
|
std::string getActionControllerBindingName (int action);
|
||||||
|
std::vector<int> getActionKeySorting();
|
||||||
|
std::vector<int> getActionControllerSorting();
|
||||||
|
|
||||||
|
void enableDetectingBindingMode (int action, bool keyboard);
|
||||||
|
bool isDetectingBindingState() const;
|
||||||
|
|
||||||
|
void loadKeyDefaults(bool force = false);
|
||||||
|
void loadControllerDefaults(bool force = false);
|
||||||
|
|
||||||
|
void setDragDrop(bool dragDrop);
|
||||||
|
|
||||||
|
void update(float dt);
|
||||||
|
|
||||||
|
void setPlayerControlsEnabled(bool enabled);
|
||||||
|
|
||||||
|
bool isLeftOrRightButton(int action, bool joystick) const;
|
||||||
|
|
||||||
|
bool actionIsActive(int id) const;
|
||||||
|
float getActionValue(int id) const;
|
||||||
|
|
||||||
|
void mousePressed(const SDL_MouseButtonEvent &evt, int deviceID);
|
||||||
|
void mouseReleased(const SDL_MouseButtonEvent &arg, int deviceID);
|
||||||
|
void mouseMoved(const SDLUtil::MouseMotionEvent &arg);
|
||||||
|
void mouseWheelMoved(const SDL_MouseWheelEvent &arg);
|
||||||
|
|
||||||
|
void keyPressed(const SDL_KeyboardEvent &arg);
|
||||||
|
void keyReleased(const SDL_KeyboardEvent &arg);
|
||||||
|
|
||||||
|
void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg);
|
||||||
|
void controllerRemoved(const SDL_ControllerDeviceEvent &arg);
|
||||||
|
void controllerButtonPressed(int deviceID, const SDL_ControllerButtonEvent &arg);
|
||||||
|
void controllerButtonReleased(int deviceID, const SDL_ControllerButtonEvent &arg);
|
||||||
|
void controllerAxisMoved(int deviceID, const SDL_ControllerAxisEvent &arg);
|
||||||
|
|
||||||
|
SDL_Scancode getKeyBinding(int actionId);
|
||||||
|
|
||||||
|
void actionValueChanged(int action, float currentValue, float previousValue);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupSDLKeyMappings();
|
||||||
|
|
||||||
|
InputControlSystem* mInputBinder;
|
||||||
|
BindingsListener* mListener;
|
||||||
|
|
||||||
|
std::string mUserFile;
|
||||||
|
|
||||||
|
bool mDragDrop;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
400
apps/openmw/mwinput/controllermanager.cpp
Normal file
400
apps/openmw/mwinput/controllermanager.cpp
Normal file
|
@ -0,0 +1,400 @@
|
||||||
|
#include "controllermanager.hpp"
|
||||||
|
|
||||||
|
#include <MyGUI_Button.h>
|
||||||
|
#include <MyGUI_InputManager.h>
|
||||||
|
#include <MyGUI_Widget.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
#include "actions.hpp"
|
||||||
|
#include "actionmanager.hpp"
|
||||||
|
#include "bindingsmanager.hpp"
|
||||||
|
#include "mousemanager.hpp"
|
||||||
|
#include "sdlmappings.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
ControllerManager::ControllerManager(BindingsManager* bindingsManager,
|
||||||
|
ActionManager* actionManager,
|
||||||
|
MouseManager* mouseManager,
|
||||||
|
const std::string& userControllerBindingsFile,
|
||||||
|
const std::string& controllerBindingsFile)
|
||||||
|
: mBindingsManager(bindingsManager)
|
||||||
|
, mActionManager(actionManager)
|
||||||
|
, mMouseManager(mouseManager)
|
||||||
|
, mJoystickEnabled (Settings::Manager::getBool("enable controller", "Input"))
|
||||||
|
, mGamepadCursorSpeed(Settings::Manager::getFloat("gamepad cursor speed", "Input"))
|
||||||
|
, mInvUiScalingFactor(1.f)
|
||||||
|
, mSneakToggleShortcutTimer(0.f)
|
||||||
|
, mGamepadZoom(0)
|
||||||
|
, mGamepadGuiCursorEnabled(true)
|
||||||
|
, mControlsDisabled(false)
|
||||||
|
, mJoystickLastUsed(false)
|
||||||
|
, mSneakGamepadShortcut(false)
|
||||||
|
, mGamepadPreviewMode(false)
|
||||||
|
{
|
||||||
|
if (!controllerBindingsFile.empty())
|
||||||
|
{
|
||||||
|
SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userControllerBindingsFile.empty())
|
||||||
|
{
|
||||||
|
SDL_GameControllerAddMappingsFromFile(userControllerBindingsFile.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open all presently connected sticks
|
||||||
|
int numSticks = SDL_NumJoysticks();
|
||||||
|
for (int i = 0; i < numSticks; i++)
|
||||||
|
{
|
||||||
|
if (SDL_IsGameController(i))
|
||||||
|
{
|
||||||
|
SDL_ControllerDeviceEvent evt;
|
||||||
|
evt.which = i;
|
||||||
|
static const int fakeDeviceID = 1;
|
||||||
|
controllerAdded(fakeDeviceID, evt);
|
||||||
|
Log(Debug::Info) << "Detected game controller: " << SDL_GameControllerNameForIndex(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Info) << "Detected unusable controller: " << SDL_JoystickNameForIndex(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
||||||
|
if (uiScale != 0.f)
|
||||||
|
mInvUiScalingFactor = 1.f / uiScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||||
|
{
|
||||||
|
for (const auto& setting : changed)
|
||||||
|
{
|
||||||
|
if (setting.first == "Input" && setting.second == "enable controller")
|
||||||
|
mJoystickEnabled = Settings::Manager::getBool("enable controller", "Input");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControllerManager::update(float dt, bool disableControls)
|
||||||
|
{
|
||||||
|
mControlsDisabled = disableControls;
|
||||||
|
mGamepadPreviewMode = mActionManager->getPreviewDelay() == 1.f;
|
||||||
|
|
||||||
|
if (mGuiCursorEnabled && !(mJoystickLastUsed && !mGamepadGuiCursorEnabled))
|
||||||
|
{
|
||||||
|
float xAxis = mBindingsManager->getActionValue(A_MoveLeftRight) * 2.0f - 1.0f;
|
||||||
|
float yAxis = mBindingsManager->getActionValue(A_MoveForwardBackward) * 2.0f - 1.0f;
|
||||||
|
float zAxis = mBindingsManager->getActionValue(A_LookUpDown) * 2.0f - 1.0f;
|
||||||
|
|
||||||
|
xAxis *= (1.5f - mBindingsManager->getActionValue(A_Use));
|
||||||
|
yAxis *= (1.5f - mBindingsManager->getActionValue(A_Use));
|
||||||
|
|
||||||
|
// We keep track of our own mouse position, so that moving the mouse while in
|
||||||
|
// game mode does not move the position of the GUI cursor
|
||||||
|
float xMove = xAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
|
||||||
|
float yMove = yAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
|
||||||
|
if (xMove != 0 || yMove != 0 || zAxis != 0)
|
||||||
|
{
|
||||||
|
int mouseWheelMove = static_cast<int>(-zAxis * dt * 1500.0f);
|
||||||
|
|
||||||
|
mMouseManager->injectMouseMove(xMove, yMove, mouseWheelMove);
|
||||||
|
mMouseManager->warpMouse();
|
||||||
|
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable movement in Gui mode
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()
|
||||||
|
|| MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)
|
||||||
|
{
|
||||||
|
mGamepadZoom = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
bool triedToMove = false;
|
||||||
|
|
||||||
|
// Configure player movement according to controller input. Actual movement will
|
||||||
|
// be done in the physics system.
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
{
|
||||||
|
float xAxis = mBindingsManager->getActionValue(A_MoveLeftRight);
|
||||||
|
float yAxis = mBindingsManager->getActionValue(A_MoveForwardBackward);
|
||||||
|
if (xAxis != 0.5)
|
||||||
|
{
|
||||||
|
triedToMove = true;
|
||||||
|
player.setLeftRight((xAxis - 0.5f) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yAxis != 0.5)
|
||||||
|
{
|
||||||
|
triedToMove = true;
|
||||||
|
player.setAutoMove (false);
|
||||||
|
player.setForwardBackward((0.5f - yAxis) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triedToMove)
|
||||||
|
{
|
||||||
|
mJoystickLastUsed = true;
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input");
|
||||||
|
if (!isToggleSneak)
|
||||||
|
{
|
||||||
|
if (mJoystickLastUsed)
|
||||||
|
{
|
||||||
|
if (mBindingsManager->actionIsActive(A_Sneak))
|
||||||
|
{
|
||||||
|
if (mSneakToggleShortcutTimer) // New Sneak Button Press
|
||||||
|
{
|
||||||
|
if (mSneakToggleShortcutTimer <= 0.3f)
|
||||||
|
{
|
||||||
|
mSneakGamepadShortcut = true;
|
||||||
|
mActionManager->toggleSneaking();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mSneakGamepadShortcut = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mActionManager->isSneaking())
|
||||||
|
mActionManager->toggleSneaking();
|
||||||
|
mSneakToggleShortcutTimer = 0.f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!mSneakGamepadShortcut && mActionManager->isSneaking())
|
||||||
|
mActionManager->toggleSneaking();
|
||||||
|
if (mSneakToggleShortcutTimer <= 0.3f)
|
||||||
|
mSneakToggleShortcutTimer += dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
player.setSneak(mBindingsManager->actionIsActive(A_Sneak));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch"))
|
||||||
|
{
|
||||||
|
if (!mBindingsManager->actionIsActive(A_TogglePOV))
|
||||||
|
mGamepadZoom = 0;
|
||||||
|
|
||||||
|
if (mGamepadZoom)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->changeVanityModeScale(mGamepadZoom);
|
||||||
|
MWBase::Environment::get().getWorld()->setCameraDistance(mGamepadZoom, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return triedToMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg)
|
||||||
|
{
|
||||||
|
if (!mJoystickEnabled || mBindingsManager->isDetectingBindingState())
|
||||||
|
return;
|
||||||
|
|
||||||
|
mJoystickLastUsed = true;
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
{
|
||||||
|
if (gamepadToGuiControl(arg))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mGamepadGuiCursorEnabled)
|
||||||
|
{
|
||||||
|
// Temporary mouse binding until keyboard controls are available:
|
||||||
|
if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click.
|
||||||
|
{
|
||||||
|
bool mousePressSuccess = mMouseManager->injectMouseButtonPress(SDL_BUTTON_LEFT);
|
||||||
|
if (MyGUI::InputManager::getInstance().getMouseFocusWidget())
|
||||||
|
{
|
||||||
|
MyGUI::Button* b = MyGUI::InputManager::getInstance().getMouseFocusWidget()->castType<MyGUI::Button>(false);
|
||||||
|
if (b && b->getEnabled())
|
||||||
|
MWBase::Environment::get().getWindowManager()->playSound("Menu Click");
|
||||||
|
}
|
||||||
|
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!mousePressSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(true);
|
||||||
|
|
||||||
|
//esc, to leave initial movie screen
|
||||||
|
auto kc = sdlKeyToMyGUI(SDLK_ESCAPE);
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyPress(kc, 0));
|
||||||
|
|
||||||
|
if (!mControlsDisabled)
|
||||||
|
mBindingsManager->controllerButtonPressed(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg)
|
||||||
|
{
|
||||||
|
if (mBindingsManager->isDetectingBindingState())
|
||||||
|
{
|
||||||
|
mBindingsManager->controllerButtonReleased(deviceID, arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mJoystickEnabled || mControlsDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mJoystickLastUsed = true;
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
{
|
||||||
|
if (mGamepadGuiCursorEnabled)
|
||||||
|
{
|
||||||
|
// Temporary mouse binding until keyboard controls are available:
|
||||||
|
if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click.
|
||||||
|
{
|
||||||
|
bool mousePressSuccess = mMouseManager->injectMouseButtonRelease(SDL_BUTTON_LEFT);
|
||||||
|
if (mBindingsManager->isDetectingBindingState()) // If the player just triggered binding, don't let button release bind.
|
||||||
|
return;
|
||||||
|
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!mousePressSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(true);
|
||||||
|
|
||||||
|
//esc, to leave initial movie screen
|
||||||
|
auto kc = sdlKeyToMyGUI(SDLK_ESCAPE);
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(kc));
|
||||||
|
|
||||||
|
mBindingsManager->controllerButtonReleased(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg)
|
||||||
|
{
|
||||||
|
if (!mJoystickEnabled || mControlsDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mJoystickLastUsed = true;
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
{
|
||||||
|
gamepadToGuiControl(arg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mGamepadPreviewMode && arg.value) // Preview Mode Gamepad Zooming
|
||||||
|
{
|
||||||
|
if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
|
||||||
|
{
|
||||||
|
mGamepadZoom = arg.value * 0.85f / 1000.f;
|
||||||
|
return; // Do not propagate event.
|
||||||
|
}
|
||||||
|
else if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT)
|
||||||
|
{
|
||||||
|
mGamepadZoom = -arg.value * 0.85f / 1000.f;
|
||||||
|
return; // Do not propagate event.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mBindingsManager->controllerAxisMoved(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg)
|
||||||
|
{
|
||||||
|
mBindingsManager->controllerAdded(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg)
|
||||||
|
{
|
||||||
|
mBindingsManager->controllerRemoved(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControllerManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg)
|
||||||
|
{
|
||||||
|
// Presumption of GUI mode will be removed in the future.
|
||||||
|
// MyGUI KeyCodes *may* change.
|
||||||
|
MyGUI::KeyCode key = MyGUI::KeyCode::None;
|
||||||
|
switch (arg.button)
|
||||||
|
{
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_UP:
|
||||||
|
key = MyGUI::KeyCode::ArrowUp;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
||||||
|
key = MyGUI::KeyCode::ArrowRight;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
||||||
|
key = MyGUI::KeyCode::ArrowDown;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
||||||
|
key = MyGUI::KeyCode::ArrowLeft;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_A:
|
||||||
|
// If we are using the joystick as a GUI mouse, A must be handled via mouse.
|
||||||
|
if (mGamepadGuiCursorEnabled)
|
||||||
|
return false;
|
||||||
|
key = MyGUI::KeyCode::Space;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_B:
|
||||||
|
if (MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
MWBase::Environment::get().getWindowManager()->exitCurrentModal();
|
||||||
|
else
|
||||||
|
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
|
||||||
|
return true;
|
||||||
|
case SDL_CONTROLLER_BUTTON_X:
|
||||||
|
key = MyGUI::KeyCode::Semicolon;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_Y:
|
||||||
|
key = MyGUI::KeyCode::Apostrophe;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
|
||||||
|
key = MyGUI::KeyCode::Period;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
|
||||||
|
key = MyGUI::KeyCode::Slash;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
|
||||||
|
mGamepadGuiCursorEnabled = !mGamepadGuiCursorEnabled;
|
||||||
|
MWBase::Environment::get().getWindowManager()->setCursorActive(mGamepadGuiCursorEnabled);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some keys will work even when Text Input windows/modals are in focus.
|
||||||
|
if (SDL_IsTextInputActive())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControllerManager::gamepadToGuiControl(const SDL_ControllerAxisEvent &arg)
|
||||||
|
{
|
||||||
|
switch (arg.axis)
|
||||||
|
{
|
||||||
|
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
|
||||||
|
if (arg.value == 32767) // Treat like a button.
|
||||||
|
MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Minus, 0, false);
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
|
||||||
|
if (arg.value == 32767) // Treat like a button.
|
||||||
|
MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Equals, 0, false);
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_LEFTX:
|
||||||
|
case SDL_CONTROLLER_AXIS_LEFTY:
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTX:
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTY:
|
||||||
|
// If we are using the joystick as a GUI mouse, process mouse movement elsewhere.
|
||||||
|
if (mGamepadGuiCursorEnabled)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
66
apps/openmw/mwinput/controllermanager.hpp
Normal file
66
apps/openmw/mwinput/controllermanager.hpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef MWINPUT_MWCONTROLLERMANAGER_H
|
||||||
|
#define MWINPUT_MWCONTROLLERMANAGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class ActionManager;
|
||||||
|
class BindingsManager;
|
||||||
|
class MouseManager;
|
||||||
|
|
||||||
|
class ControllerManager : public SDLUtil::ControllerListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ControllerManager(BindingsManager* bindingsManager,
|
||||||
|
ActionManager* actionManager,
|
||||||
|
MouseManager* mouseManager,
|
||||||
|
const std::string& userControllerBindingsFile,
|
||||||
|
const std::string& controllerBindingsFile);
|
||||||
|
|
||||||
|
virtual ~ControllerManager() = default;
|
||||||
|
|
||||||
|
bool update(float dt, bool disableControls);
|
||||||
|
|
||||||
|
virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg);
|
||||||
|
virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg);
|
||||||
|
virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg);
|
||||||
|
virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg);
|
||||||
|
virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg);
|
||||||
|
|
||||||
|
void processChangedSettings(const Settings::CategorySettingVector& changed);
|
||||||
|
|
||||||
|
void setJoystickLastUsed(bool enabled) { mJoystickLastUsed = enabled; }
|
||||||
|
bool joystickLastUsed() { return mJoystickLastUsed; }
|
||||||
|
|
||||||
|
void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; }
|
||||||
|
|
||||||
|
void setGamepadGuiCursorEnabled(bool enabled) { mGamepadGuiCursorEnabled = enabled; }
|
||||||
|
bool gamepadGuiCursorEnabled() { return mGamepadGuiCursorEnabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Return true if GUI consumes input.
|
||||||
|
bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg);
|
||||||
|
bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg);
|
||||||
|
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
|
ActionManager* mActionManager;
|
||||||
|
MouseManager* mMouseManager;
|
||||||
|
|
||||||
|
bool mJoystickEnabled;
|
||||||
|
float mGamepadCursorSpeed;
|
||||||
|
float mInvUiScalingFactor;
|
||||||
|
float mSneakToggleShortcutTimer;
|
||||||
|
float mGamepadZoom;
|
||||||
|
bool mGamepadGuiCursorEnabled;
|
||||||
|
bool mControlsDisabled;
|
||||||
|
bool mJoystickLastUsed;
|
||||||
|
bool mGuiCursorEnabled;
|
||||||
|
bool mSneakGamepadShortcut;
|
||||||
|
bool mGamepadPreviewMode;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
99
apps/openmw/mwinput/controlswitch.cpp
Normal file
99
apps/openmw/mwinput/controlswitch.cpp
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
#include "controlswitch.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/controlsstate.hpp>
|
||||||
|
|
||||||
|
#include <components/loadinglistener/loadinglistener.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
ControlSwitch::ControlSwitch()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlSwitch::clear()
|
||||||
|
{
|
||||||
|
mSwitches["playercontrols"] = true;
|
||||||
|
mSwitches["playerfighting"] = true;
|
||||||
|
mSwitches["playerjumping"] = true;
|
||||||
|
mSwitches["playerlooking"] = true;
|
||||||
|
mSwitches["playermagic"] = true;
|
||||||
|
mSwitches["playerviewswitch"] = true;
|
||||||
|
mSwitches["vanitymode"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControlSwitch::get(const std::string& key)
|
||||||
|
{
|
||||||
|
return mSwitches[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlSwitch::set(const std::string& key, bool value)
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
|
||||||
|
/// \note 7 switches at all, if-else is relevant
|
||||||
|
if (key == "playercontrols" && !value)
|
||||||
|
{
|
||||||
|
player.setLeftRight(0);
|
||||||
|
player.setForwardBackward(0);
|
||||||
|
player.setAutoMove(false);
|
||||||
|
player.setUpDown(0);
|
||||||
|
}
|
||||||
|
else if (key == "playerjumping" && !value)
|
||||||
|
{
|
||||||
|
/// \fixme maybe crouching at this time
|
||||||
|
player.setUpDown(0);
|
||||||
|
}
|
||||||
|
else if (key == "vanitymode")
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->allowVanityMode(value);
|
||||||
|
}
|
||||||
|
else if (key == "playerlooking" && !value)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->rotateObject(player.getPlayer(), 0.f, 0.f, 0.f);
|
||||||
|
}
|
||||||
|
mSwitches[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlSwitch::write(ESM::ESMWriter& writer, Loading::Listener& /*progress*/)
|
||||||
|
{
|
||||||
|
ESM::ControlsState controls;
|
||||||
|
controls.mViewSwitchDisabled = !mSwitches["playerviewswitch"];
|
||||||
|
controls.mControlsDisabled = !mSwitches["playercontrols"];
|
||||||
|
controls.mJumpingDisabled = !mSwitches["playerjumping"];
|
||||||
|
controls.mLookingDisabled = !mSwitches["playerlooking"];
|
||||||
|
controls.mVanityModeDisabled = !mSwitches["vanitymode"];
|
||||||
|
controls.mWeaponDrawingDisabled = !mSwitches["playerfighting"];
|
||||||
|
controls.mSpellDrawingDisabled = !mSwitches["playermagic"];
|
||||||
|
|
||||||
|
writer.startRecord (ESM::REC_INPU);
|
||||||
|
controls.save(writer);
|
||||||
|
writer.endRecord (ESM::REC_INPU);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlSwitch::readRecord(ESM::ESMReader& reader, uint32_t type)
|
||||||
|
{
|
||||||
|
ESM::ControlsState controls;
|
||||||
|
controls.load(reader);
|
||||||
|
|
||||||
|
set("playerviewswitch", !controls.mViewSwitchDisabled);
|
||||||
|
set("playercontrols", !controls.mControlsDisabled);
|
||||||
|
set("playerjumping", !controls.mJumpingDisabled);
|
||||||
|
set("playerlooking", !controls.mLookingDisabled);
|
||||||
|
set("vanitymode", !controls.mVanityModeDisabled);
|
||||||
|
set("playerfighting", !controls.mWeaponDrawingDisabled);
|
||||||
|
set("playermagic", !controls.mSpellDrawingDisabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ControlSwitch::countSavedGameRecords() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
38
apps/openmw/mwinput/controlswitch.hpp
Normal file
38
apps/openmw/mwinput/controlswitch.hpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef MWINPUT_CONTROLSWITCH_H
|
||||||
|
#define MWINPUT_CONTROLSWITCH_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
struct ControlsState;
|
||||||
|
class ESMReader;
|
||||||
|
class ESMWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Loading
|
||||||
|
{
|
||||||
|
class Listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class ControlSwitch
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ControlSwitch();
|
||||||
|
|
||||||
|
bool get(const std::string& key);
|
||||||
|
void set(const std::string& key, bool value);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void write(ESM::ESMWriter& writer, Loading::Listener& progress);
|
||||||
|
void readRecord(ESM::ESMReader& reader, uint32_t type);
|
||||||
|
int countSavedGameRecords() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, bool> mSwitches;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -1,22 +1,18 @@
|
||||||
#ifndef MWINPUT_MWINPUTMANAGERIMP_H
|
#ifndef MWINPUT_MWINPUTMANAGERIMP_H
|
||||||
#define MWINPUT_MWINPUTMANAGERIMP_H
|
#define MWINPUT_MWINPUTMANAGERIMP_H
|
||||||
|
|
||||||
#include "../mwgui/mode.hpp"
|
|
||||||
|
|
||||||
#include <SDL_sensor.h>
|
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
#include <osgViewer/ViewerEventHandlers>
|
#include <osgViewer/ViewerEventHandlers>
|
||||||
|
|
||||||
#include <extern/oics/ICSChannelListener.h>
|
|
||||||
#include <extern/oics/ICSInputControlSystem.h>
|
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/files/configurationmanager.hpp>
|
|
||||||
#include <components/sdlutil/events.hpp>
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
#include "../mwbase/inputmanager.hpp"
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
|
||||||
|
#include "../mwgui/mode.hpp"
|
||||||
|
|
||||||
|
#include "actions.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class Player;
|
class Player;
|
||||||
|
@ -27,51 +23,27 @@ namespace MWBase
|
||||||
class WindowManager;
|
class WindowManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ICS
|
|
||||||
{
|
|
||||||
class InputControlSystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MyGUI
|
|
||||||
{
|
|
||||||
struct MouseButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Files
|
|
||||||
{
|
|
||||||
struct ConfigurationManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace SDLUtil
|
namespace SDLUtil
|
||||||
{
|
{
|
||||||
class InputWrapper;
|
class InputWrapper;
|
||||||
class VideoWrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace osgViewer
|
|
||||||
{
|
|
||||||
class Viewer;
|
|
||||||
class ScreenCaptureHandler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
|
|
||||||
namespace MWInput
|
namespace MWInput
|
||||||
{
|
{
|
||||||
const float ZOOM_SCALE = 120.f; /// Used for scrolling camera in and out
|
class ControlSwitch;
|
||||||
|
class ActionManager;
|
||||||
|
class BindingsManager;
|
||||||
|
class ControllerManager;
|
||||||
|
class KeyboardManager;
|
||||||
|
class MouseManager;
|
||||||
|
class SensorManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Class that handles all input and key bindings for OpenMW.
|
* @brief Class that provides a high-level API for game input
|
||||||
*/
|
*/
|
||||||
class InputManager :
|
class InputManager : public MWBase::InputManager
|
||||||
public MWBase::InputManager,
|
|
||||||
public SDLUtil::KeyListener,
|
|
||||||
public SDLUtil::MouseListener,
|
|
||||||
public SDLUtil::SensorListener,
|
|
||||||
public SDLUtil::WindowListener,
|
|
||||||
public SDLUtil::ControllerListener,
|
|
||||||
public ICS::ChannelListener,
|
|
||||||
public ICS::DetectingBindingListener
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InputManager(
|
InputManager(
|
||||||
|
@ -85,20 +57,18 @@ namespace MWInput
|
||||||
|
|
||||||
virtual ~InputManager();
|
virtual ~InputManager();
|
||||||
|
|
||||||
virtual bool isWindowVisible();
|
|
||||||
|
|
||||||
/// Clear all savegame-specific data
|
/// Clear all savegame-specific data
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
|
|
||||||
virtual void update(float dt, bool disableControls=false, bool disableEvents=false);
|
virtual void update(float dt, bool disableControls=false, bool disableEvents=false);
|
||||||
|
|
||||||
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
|
|
||||||
|
|
||||||
virtual void changeInputMode(bool guiMode);
|
virtual void changeInputMode(bool guiMode);
|
||||||
|
|
||||||
virtual void processChangedSettings(const Settings::CategorySettingVector& changed);
|
virtual void processChangedSettings(const Settings::CategorySettingVector& changed);
|
||||||
|
|
||||||
virtual void setDragDrop(bool dragDrop);
|
virtual void setDragDrop(bool dragDrop);
|
||||||
|
virtual void setGamepadGuiCursorEnabled(bool enabled);
|
||||||
|
virtual void setAttemptJump(bool jumping);
|
||||||
|
|
||||||
virtual void toggleControlSwitch (const std::string& sw, bool value);
|
virtual void toggleControlSwitch (const std::string& sw, bool value);
|
||||||
virtual bool getControlSwitch (const std::string& sw);
|
virtual bool getControlSwitch (const std::string& sw);
|
||||||
|
@ -113,264 +83,42 @@ namespace MWInput
|
||||||
virtual void resetToDefaultKeyBindings();
|
virtual void resetToDefaultKeyBindings();
|
||||||
virtual void resetToDefaultControllerBindings();
|
virtual void resetToDefaultControllerBindings();
|
||||||
|
|
||||||
virtual bool joystickLastUsed() {return mJoystickLastUsed;}
|
virtual void setJoystickLastUsed(bool enabled);
|
||||||
|
virtual bool joystickLastUsed();
|
||||||
public:
|
|
||||||
virtual void keyPressed(const SDL_KeyboardEvent &arg );
|
|
||||||
virtual void keyReleased( const SDL_KeyboardEvent &arg );
|
|
||||||
virtual void textInput (const SDL_TextInputEvent &arg);
|
|
||||||
|
|
||||||
virtual void mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id );
|
|
||||||
virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id );
|
|
||||||
virtual void mouseMoved( const SDLUtil::MouseMotionEvent &arg );
|
|
||||||
|
|
||||||
virtual void mouseWheelMoved( const SDL_MouseWheelEvent &arg);
|
|
||||||
|
|
||||||
virtual void sensorUpdated(const SDL_SensorEvent &arg);
|
|
||||||
virtual void displayOrientationChanged();
|
|
||||||
|
|
||||||
virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg);
|
|
||||||
virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg);
|
|
||||||
virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg);
|
|
||||||
virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg);
|
|
||||||
virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg);
|
|
||||||
|
|
||||||
virtual void windowVisibilityChange( bool visible );
|
|
||||||
virtual void windowFocusChange( bool have_focus );
|
|
||||||
virtual void windowResized (int x, int y);
|
|
||||||
virtual void windowClosed ();
|
|
||||||
|
|
||||||
virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue);
|
|
||||||
|
|
||||||
virtual void keyBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
|
||||||
, SDL_Scancode key, ICS::Control::ControlChangingDirection direction);
|
|
||||||
|
|
||||||
virtual void mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
|
||||||
, ICS::InputControlSystem::NamedAxis axis, ICS::Control::ControlChangingDirection direction);
|
|
||||||
|
|
||||||
virtual void mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
|
||||||
, unsigned int button, ICS::Control::ControlChangingDirection direction);
|
|
||||||
|
|
||||||
virtual void mouseWheelBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
|
||||||
, ICS::InputControlSystem::MouseWheelClick click, ICS::Control::ControlChangingDirection direction);
|
|
||||||
|
|
||||||
virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control
|
|
||||||
, int axis, ICS::Control::ControlChangingDirection direction);
|
|
||||||
|
|
||||||
virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control
|
|
||||||
, unsigned int button, ICS::Control::ControlChangingDirection direction);
|
|
||||||
|
|
||||||
void clearAllKeyBindings (ICS::Control* control);
|
|
||||||
void clearAllControllerBindings (ICS::Control* control);
|
|
||||||
|
|
||||||
virtual int countSavedGameRecords() const;
|
virtual int countSavedGameRecords() const;
|
||||||
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress);
|
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress);
|
||||||
virtual void readRecord(ESM::ESMReader& reader, uint32_t type);
|
virtual void readRecord(ESM::ESMReader& reader, uint32_t type);
|
||||||
|
|
||||||
private:
|
virtual void resetIdleTime();
|
||||||
enum GyroscopeAxis
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
X = 1,
|
|
||||||
Y = 2,
|
|
||||||
Z = 3,
|
|
||||||
Minus_X = -1,
|
|
||||||
Minus_Y = -2,
|
|
||||||
Minus_Z = -3
|
|
||||||
};
|
|
||||||
|
|
||||||
SDL_Window* mWindow;
|
virtual void executeAction(int action);
|
||||||
bool mWindowVisible;
|
|
||||||
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
|
||||||
osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler;
|
|
||||||
osgViewer::ScreenCaptureHandler::CaptureOperation *mScreenCaptureOperation;
|
|
||||||
|
|
||||||
bool mJoystickLastUsed;
|
|
||||||
MWWorld::Player* mPlayer;
|
|
||||||
|
|
||||||
ICS::InputControlSystem* mInputBinder;
|
|
||||||
|
|
||||||
SDLUtil::InputWrapper* mInputManager;
|
|
||||||
SDLUtil::VideoWrapper* mVideoWrapper;
|
|
||||||
|
|
||||||
std::string mUserFile;
|
|
||||||
|
|
||||||
bool mDragDrop;
|
|
||||||
|
|
||||||
bool mGrabCursor;
|
|
||||||
|
|
||||||
bool mInvertX;
|
|
||||||
bool mInvertY;
|
|
||||||
|
|
||||||
bool mControlsDisabled;
|
|
||||||
bool mJoystickEnabled;
|
|
||||||
|
|
||||||
float mCameraSensitivity;
|
|
||||||
float mCameraYMultiplier;
|
|
||||||
float mPreviewPOVDelay;
|
|
||||||
float mTimeIdle;
|
|
||||||
|
|
||||||
bool mMouseLookEnabled;
|
|
||||||
bool mGuiCursorEnabled;
|
|
||||||
bool mGamepadGuiCursorEnabled;
|
|
||||||
|
|
||||||
bool mDetectingKeyboard;
|
|
||||||
|
|
||||||
float mOverencumberedMessageDelay;
|
|
||||||
|
|
||||||
float mGuiCursorX;
|
|
||||||
float mGuiCursorY;
|
|
||||||
int mMouseWheel;
|
|
||||||
float mGamepadZoom;
|
|
||||||
bool mUserFileExists;
|
|
||||||
bool mAlwaysRunActive;
|
|
||||||
bool mSneakToggles;
|
|
||||||
float mSneakToggleShortcutTimer;
|
|
||||||
bool mSneakGamepadShortcut;
|
|
||||||
bool mSneaking;
|
|
||||||
bool mAttemptJump;
|
|
||||||
|
|
||||||
std::map<std::string, bool> mControlSwitch;
|
|
||||||
|
|
||||||
float mInvUiScalingFactor;
|
|
||||||
float mGamepadCursorSpeed;
|
|
||||||
|
|
||||||
float mGyroXSpeed;
|
|
||||||
float mGyroYSpeed;
|
|
||||||
float mGyroUpdateTimer;
|
|
||||||
|
|
||||||
float mGyroHSensitivity;
|
|
||||||
float mGyroVSensitivity;
|
|
||||||
GyroscopeAxis mGyroHAxis;
|
|
||||||
GyroscopeAxis mGyroVAxis;
|
|
||||||
float mGyroInputThreshold;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void convertMousePosForMyGUI(int& x, int& y);
|
void convertMousePosForMyGUI(int& x, int& y);
|
||||||
|
|
||||||
MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button);
|
|
||||||
|
|
||||||
virtual std::string sdlControllerAxisToString(int axis);
|
|
||||||
virtual std::string sdlControllerButtonToString(int button);
|
|
||||||
|
|
||||||
void resetIdleTime();
|
|
||||||
void updateIdleTime(float dt);
|
|
||||||
|
|
||||||
void setPlayerControlsEnabled(bool enabled);
|
|
||||||
void handleGuiArrowKey(int action);
|
void handleGuiArrowKey(int action);
|
||||||
// Return true if GUI consumes input.
|
|
||||||
bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg);
|
|
||||||
bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg);
|
|
||||||
|
|
||||||
void updateCursorMode();
|
void updateCursorMode();
|
||||||
void updateSensors();
|
|
||||||
void correctGyroscopeAxes();
|
|
||||||
GyroscopeAxis mapGyroscopeAxis(const std::string& axis);
|
|
||||||
|
|
||||||
bool checkAllowedToUseItems() const;
|
void quickKey(int index);
|
||||||
|
|
||||||
float getGyroAxisSpeed(GyroscopeAxis axis, const SDL_SensorEvent &arg) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void toggleMainMenu();
|
|
||||||
void toggleSpell();
|
|
||||||
void toggleWeapon();
|
|
||||||
void toggleInventory();
|
|
||||||
void toggleConsole();
|
|
||||||
void screenshot();
|
|
||||||
void toggleJournal();
|
|
||||||
void activate();
|
|
||||||
void toggleWalking();
|
|
||||||
void toggleSneaking();
|
|
||||||
void toggleAutoMove();
|
|
||||||
void rest();
|
|
||||||
void quickLoad();
|
|
||||||
void quickSave();
|
|
||||||
|
|
||||||
void quickKey (int index);
|
|
||||||
void showQuickKeysMenu();
|
void showQuickKeysMenu();
|
||||||
|
|
||||||
bool actionIsActive (int id);
|
|
||||||
|
|
||||||
void loadKeyDefaults(bool force = false);
|
void loadKeyDefaults(bool force = false);
|
||||||
void loadControllerDefaults(bool force = false);
|
void loadControllerDefaults(bool force = false);
|
||||||
|
|
||||||
int mFakeDeviceID; //As we only support one controller at a time, use a fake deviceID so we don't lose bindings when switching controllers
|
SDLUtil::InputWrapper* mInputWrapper;
|
||||||
SDL_Sensor* mGyroscope;
|
|
||||||
|
|
||||||
private:
|
bool mGrabCursor;
|
||||||
enum Actions
|
|
||||||
{
|
|
||||||
// please add new actions at the bottom, in order to preserve the channel IDs in the key configuration files
|
|
||||||
|
|
||||||
A_GameMenu,
|
ControlSwitch* mControlSwitch;
|
||||||
|
|
||||||
A_Unused,
|
ActionManager* mActionManager;
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
A_Screenshot, // Take a screenshot
|
ControllerManager* mControllerManager;
|
||||||
|
KeyboardManager* mKeyboardManager;
|
||||||
A_Inventory, // Toggle inventory screen
|
MouseManager* mMouseManager;
|
||||||
|
SensorManager* mSensorManager;
|
||||||
A_Console, // Toggle console screen
|
|
||||||
|
|
||||||
A_MoveLeft, // Move player left / right
|
|
||||||
A_MoveRight,
|
|
||||||
A_MoveForward, // Forward / Backward
|
|
||||||
A_MoveBackward,
|
|
||||||
|
|
||||||
A_Activate,
|
|
||||||
|
|
||||||
A_Use, //Use weapon, spell, etc.
|
|
||||||
A_Jump,
|
|
||||||
A_AutoMove, //Toggle Auto-move forward
|
|
||||||
A_Rest, //Rest
|
|
||||||
A_Journal, //Journal
|
|
||||||
A_Weapon, //Draw/Sheath weapon
|
|
||||||
A_Spell, //Ready/Unready Casting
|
|
||||||
A_Run, //Run when held
|
|
||||||
A_CycleSpellLeft, //cycling through spells
|
|
||||||
A_CycleSpellRight,
|
|
||||||
A_CycleWeaponLeft, //Cycling through weapons
|
|
||||||
A_CycleWeaponRight,
|
|
||||||
A_ToggleSneak, //Toggles Sneak
|
|
||||||
A_AlwaysRun, //Toggle Walking/Running
|
|
||||||
A_Sneak,
|
|
||||||
|
|
||||||
A_QuickSave,
|
|
||||||
A_QuickLoad,
|
|
||||||
A_QuickMenu,
|
|
||||||
A_ToggleWeapon,
|
|
||||||
A_ToggleSpell,
|
|
||||||
|
|
||||||
A_TogglePOV,
|
|
||||||
|
|
||||||
A_QuickKey1,
|
|
||||||
A_QuickKey2,
|
|
||||||
A_QuickKey3,
|
|
||||||
A_QuickKey4,
|
|
||||||
A_QuickKey5,
|
|
||||||
A_QuickKey6,
|
|
||||||
A_QuickKey7,
|
|
||||||
A_QuickKey8,
|
|
||||||
A_QuickKey9,
|
|
||||||
A_QuickKey10,
|
|
||||||
|
|
||||||
A_QuickKeysMenu,
|
|
||||||
|
|
||||||
A_ToggleHUD,
|
|
||||||
|
|
||||||
A_ToggleDebug,
|
|
||||||
|
|
||||||
A_LookUpDown, //Joystick look
|
|
||||||
A_LookLeftRight,
|
|
||||||
A_MoveForwardBackward,
|
|
||||||
A_MoveLeftRight,
|
|
||||||
|
|
||||||
A_ZoomIn,
|
|
||||||
A_ZoomOut,
|
|
||||||
|
|
||||||
A_Last // Marker for the last item
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
71
apps/openmw/mwinput/keyboardmanager.cpp
Normal file
71
apps/openmw/mwinput/keyboardmanager.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "keyboardmanager.hpp"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
#include <MyGUI_InputManager.h>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
#include "actions.hpp"
|
||||||
|
#include "bindingsmanager.hpp"
|
||||||
|
#include "sdlmappings.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
KeyboardManager::KeyboardManager(BindingsManager* bindingsManager)
|
||||||
|
: mBindingsManager(bindingsManager)
|
||||||
|
, mControlsDisabled(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardManager::textInput(const SDL_TextInputEvent &arg)
|
||||||
|
{
|
||||||
|
MyGUI::UString ustring(&arg.text[0]);
|
||||||
|
MyGUI::UString::utf32string utf32string = ustring.asUTF32();
|
||||||
|
for (MyGUI::UString::utf32string::const_iterator it = utf32string.begin(); it != utf32string.end(); ++it)
|
||||||
|
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardManager::keyPressed(const SDL_KeyboardEvent &arg)
|
||||||
|
{
|
||||||
|
// HACK: to make default keybinding for the console work without printing an extra "^" upon closing
|
||||||
|
// This assumes that SDL_TextInput events always come *after* the key event
|
||||||
|
// (which is somewhat reasonable, and hopefully true for all SDL platforms)
|
||||||
|
auto kc = sdlKeyToMyGUI(arg.keysym.sym);
|
||||||
|
if (mBindingsManager->getKeyBinding(A_Console) == arg.keysym.scancode
|
||||||
|
&& MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||||
|
SDL_StopTextInput();
|
||||||
|
|
||||||
|
bool consumed = false;
|
||||||
|
if (kc != MyGUI::KeyCode::None && !mBindingsManager->isDetectingBindingState())
|
||||||
|
{
|
||||||
|
consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(kc, 0, arg.repeat);
|
||||||
|
if (SDL_IsTextInputActive() && // Little trick to check if key is printable
|
||||||
|
(!(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)))
|
||||||
|
consumed = true;
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!consumed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.repeat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mControlsDisabled && !consumed)
|
||||||
|
mBindingsManager->keyPressed(arg);
|
||||||
|
|
||||||
|
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardManager::keyReleased(const SDL_KeyboardEvent &arg)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||||
|
auto kc = sdlKeyToMyGUI(arg.keysym.sym);
|
||||||
|
|
||||||
|
if (!mBindingsManager->isDetectingBindingState())
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(kc));
|
||||||
|
mBindingsManager->keyReleased(arg);
|
||||||
|
}
|
||||||
|
}
|
30
apps/openmw/mwinput/keyboardmanager.hpp
Normal file
30
apps/openmw/mwinput/keyboardmanager.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef MWINPUT_MWKEYBOARDMANAGER_H
|
||||||
|
#define MWINPUT_MWKEYBOARDMANAGER_H
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class BindingsManager;
|
||||||
|
|
||||||
|
class KeyboardManager : public SDLUtil::KeyListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KeyboardManager(BindingsManager* bindingsManager);
|
||||||
|
|
||||||
|
virtual ~KeyboardManager() = default;
|
||||||
|
|
||||||
|
virtual void textInput(const SDL_TextInputEvent &arg);
|
||||||
|
virtual void keyPressed(const SDL_KeyboardEvent &arg);
|
||||||
|
virtual void keyReleased(const SDL_KeyboardEvent &arg);
|
||||||
|
|
||||||
|
void setControlsDisabled(bool disabled) { mControlsDisabled = disabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
|
|
||||||
|
bool mControlsDisabled;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
227
apps/openmw/mwinput/mousemanager.cpp
Normal file
227
apps/openmw/mwinput/mousemanager.cpp
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
#include "mousemanager.hpp"
|
||||||
|
|
||||||
|
#include <MyGUI_Button.h>
|
||||||
|
#include <MyGUI_InputManager.h>
|
||||||
|
#include <MyGUI_RenderManager.h>
|
||||||
|
#include <MyGUI_Widget.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
#include <components/sdlutil/sdlinputwrapper.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
#include "actions.hpp"
|
||||||
|
#include "bindingsmanager.hpp"
|
||||||
|
#include "sdlmappings.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
MouseManager::MouseManager(BindingsManager* bindingsManager, SDLUtil::InputWrapper* inputWrapper, SDL_Window* window)
|
||||||
|
: mInvertX(Settings::Manager::getBool("invert x axis", "Input"))
|
||||||
|
, mInvertY(Settings::Manager::getBool("invert y axis", "Input"))
|
||||||
|
, mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input"))
|
||||||
|
, mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input"))
|
||||||
|
, mBindingsManager(bindingsManager)
|
||||||
|
, mInputWrapper(inputWrapper)
|
||||||
|
, mInvUiScalingFactor(1.f)
|
||||||
|
, mGuiCursorX(0)
|
||||||
|
, mGuiCursorY(0)
|
||||||
|
, mMouseWheel(0)
|
||||||
|
, mMouseLookEnabled(false)
|
||||||
|
, mControlsDisabled(false)
|
||||||
|
, mGuiCursorEnabled(true)
|
||||||
|
{
|
||||||
|
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
||||||
|
if (uiScale != 0.f)
|
||||||
|
mInvUiScalingFactor = 1.f / uiScale;
|
||||||
|
|
||||||
|
int w,h;
|
||||||
|
SDL_GetWindowSize(window, &w, &h);
|
||||||
|
|
||||||
|
mGuiCursorX = mInvUiScalingFactor * w / 2.f;
|
||||||
|
mGuiCursorY = mInvUiScalingFactor * h / 2.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||||
|
{
|
||||||
|
for (const auto& setting : changed)
|
||||||
|
{
|
||||||
|
if (setting.first == "Input" && setting.second == "invert x axis")
|
||||||
|
mInvertX = Settings::Manager::getBool("invert x axis", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "invert y axis")
|
||||||
|
mInvertY = Settings::Manager::getBool("invert y axis", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "camera sensitivity")
|
||||||
|
mCameraSensitivity = Settings::Manager::getFloat("camera sensitivity", "Input");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::mouseMoved(const SDLUtil::MouseMotionEvent &arg)
|
||||||
|
{
|
||||||
|
mBindingsManager->mouseMoved(arg);
|
||||||
|
|
||||||
|
MWBase::InputManager* input = MWBase::Environment::get().getInputManager();
|
||||||
|
input->setJoystickLastUsed(false);
|
||||||
|
input->resetIdleTime();
|
||||||
|
|
||||||
|
if (mGuiCursorEnabled)
|
||||||
|
{
|
||||||
|
input->setGamepadGuiCursorEnabled(true);
|
||||||
|
|
||||||
|
// We keep track of our own mouse position, so that moving the mouse while in
|
||||||
|
// game mode does not move the position of the GUI cursor
|
||||||
|
mGuiCursorX = static_cast<float>(arg.x) * mInvUiScalingFactor;
|
||||||
|
mGuiCursorY = static_cast<float>(arg.y) * mInvUiScalingFactor;
|
||||||
|
|
||||||
|
mMouseWheel = static_cast<int>(arg.z);
|
||||||
|
|
||||||
|
MyGUI::InputManager::getInstance().injectMouseMove(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), mMouseWheel);
|
||||||
|
// FIXME: inject twice to force updating focused widget states (tooltips) resulting from changing the viewport by scroll wheel
|
||||||
|
MyGUI::InputManager::getInstance().injectMouseMove(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), mMouseWheel);
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mMouseLookEnabled && !mControlsDisabled)
|
||||||
|
{
|
||||||
|
float x = arg.xrel * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f;
|
||||||
|
float y = arg.yrel * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f;
|
||||||
|
|
||||||
|
float rot[3];
|
||||||
|
rot[0] = -y;
|
||||||
|
rot[1] = 0.0f;
|
||||||
|
rot[2] = -x;
|
||||||
|
|
||||||
|
// Only actually turn player when we're not in vanity mode
|
||||||
|
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && input->getControlSwitch("playerlooking"))
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.yaw(x);
|
||||||
|
player.pitch(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.zrel && input->getControlSwitch("playerviewswitch") && input->getControlSwitch("playercontrols")) //Check to make sure you are allowed to zoomout and there is a change
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->changeVanityModeScale(static_cast<float>(arg.zrel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::mouseReleased(const SDL_MouseButtonEvent &arg, Uint8 id)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||||
|
|
||||||
|
if (mBindingsManager->isDetectingBindingState())
|
||||||
|
{
|
||||||
|
mBindingsManager->mouseReleased(arg, id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||||
|
guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI(id)) && guiMode;
|
||||||
|
|
||||||
|
if (mBindingsManager->isDetectingBindingState())
|
||||||
|
return; // don't allow same mouseup to bind as initiated bind
|
||||||
|
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!guiMode);
|
||||||
|
mBindingsManager->mouseReleased(arg, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::mouseWheelMoved(const SDL_MouseWheelEvent &arg)
|
||||||
|
{
|
||||||
|
if (mBindingsManager->isDetectingBindingState() || !mControlsDisabled)
|
||||||
|
mBindingsManager->mouseWheelMoved(arg);
|
||||||
|
|
||||||
|
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::mousePressed(const SDL_MouseButtonEvent &arg, Uint8 id)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||||
|
bool guiMode = false;
|
||||||
|
|
||||||
|
if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events
|
||||||
|
{
|
||||||
|
guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||||
|
guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI(id)) && guiMode;
|
||||||
|
if (MyGUI::InputManager::getInstance().getMouseFocusWidget () != 0)
|
||||||
|
{
|
||||||
|
MyGUI::Button* b = MyGUI::InputManager::getInstance().getMouseFocusWidget()->castType<MyGUI::Button>(false);
|
||||||
|
if (b && b->getEnabled() && id == SDL_BUTTON_LEFT)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->playSound("Menu Click");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!guiMode);
|
||||||
|
|
||||||
|
// Don't trigger any mouse bindings while in settings menu, otherwise rebinding controls becomes impossible
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Settings)
|
||||||
|
mBindingsManager->mousePressed(arg, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::update(float dt, bool disableControls)
|
||||||
|
{
|
||||||
|
mControlsDisabled = disableControls;
|
||||||
|
|
||||||
|
if (!mMouseLookEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float xAxis = mBindingsManager->getActionValue(A_LookLeftRight) * 2.0f - 1.0f;
|
||||||
|
float yAxis = mBindingsManager->getActionValue(A_LookUpDown) * 2.0f - 1.0f;
|
||||||
|
if (xAxis == 0 && yAxis == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float rot[3];
|
||||||
|
rot[0] = yAxis * dt * 1000.0f * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f;
|
||||||
|
rot[1] = 0.0f;
|
||||||
|
rot[2] = xAxis * dt * 1000.0f * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f;
|
||||||
|
|
||||||
|
// Only actually turn player when we're not in vanity mode
|
||||||
|
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.yaw(rot[2]);
|
||||||
|
player.pitch(rot[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MouseManager::injectMouseButtonPress(Uint8 button)
|
||||||
|
{
|
||||||
|
return MyGUI::InputManager::getInstance().injectMousePress(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MouseManager::injectMouseButtonRelease(Uint8 button)
|
||||||
|
{
|
||||||
|
return MyGUI::InputManager::getInstance().injectMousePress(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::injectMouseMove(int xMove, int yMove, int mouseWheelMove)
|
||||||
|
{
|
||||||
|
mGuiCursorX += xMove;
|
||||||
|
mGuiCursorY += yMove;
|
||||||
|
mMouseWheel += mouseWheelMove;
|
||||||
|
|
||||||
|
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
|
mGuiCursorX = std::max(0.f, std::min(mGuiCursorX, float(viewSize.width - 1)));
|
||||||
|
mGuiCursorY = std::max(0.f, std::min(mGuiCursorY, float(viewSize.height - 1)));
|
||||||
|
|
||||||
|
MyGUI::InputManager::getInstance().injectMouseMove(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), mMouseWheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::warpMouse()
|
||||||
|
{
|
||||||
|
mInputWrapper->warpMouse(static_cast<int>(mGuiCursorX / mInvUiScalingFactor), static_cast<int>(mGuiCursorY / mInvUiScalingFactor));
|
||||||
|
}
|
||||||
|
}
|
58
apps/openmw/mwinput/mousemanager.hpp
Normal file
58
apps/openmw/mwinput/mousemanager.hpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef MWINPUT_MWMOUSEMANAGER_H
|
||||||
|
#define MWINPUT_MWMOUSEMANAGER_H
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
|
namespace SDLUtil
|
||||||
|
{
|
||||||
|
class InputWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class BindingsManager;
|
||||||
|
|
||||||
|
class MouseManager : public SDLUtil::MouseListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MouseManager(BindingsManager* bindingsManager, SDLUtil::InputWrapper* inputWrapper, SDL_Window* window);
|
||||||
|
|
||||||
|
virtual ~MouseManager() = default;
|
||||||
|
|
||||||
|
void update(float dt, bool disableControls);
|
||||||
|
|
||||||
|
virtual void mouseMoved(const SDLUtil::MouseMotionEvent &arg);
|
||||||
|
virtual void mousePressed(const SDL_MouseButtonEvent &arg, Uint8 id);
|
||||||
|
virtual void mouseReleased(const SDL_MouseButtonEvent &arg, Uint8 id);
|
||||||
|
virtual void mouseWheelMoved(const SDL_MouseWheelEvent &arg);
|
||||||
|
|
||||||
|
void processChangedSettings(const Settings::CategorySettingVector& changed);
|
||||||
|
|
||||||
|
bool injectMouseButtonPress(Uint8 button);
|
||||||
|
bool injectMouseButtonRelease(Uint8 button);
|
||||||
|
void injectMouseMove(int xMove, int yMove, int mouseWheelMove);
|
||||||
|
void warpMouse();
|
||||||
|
|
||||||
|
void setMouseLookEnabled(bool enabled) { mMouseLookEnabled = enabled; }
|
||||||
|
void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mInvertX;
|
||||||
|
bool mInvertY;
|
||||||
|
float mCameraSensitivity;
|
||||||
|
float mCameraYMultiplier;
|
||||||
|
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
|
SDLUtil::InputWrapper* mInputWrapper;
|
||||||
|
float mInvUiScalingFactor;
|
||||||
|
|
||||||
|
float mGuiCursorX;
|
||||||
|
float mGuiCursorY;
|
||||||
|
int mMouseWheel;
|
||||||
|
bool mMouseLookEnabled;
|
||||||
|
bool mControlsDisabled;
|
||||||
|
bool mGuiCursorEnabled;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
218
apps/openmw/mwinput/sdlmappings.cpp
Normal file
218
apps/openmw/mwinput/sdlmappings.cpp
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
#include "sdlmappings.hpp"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <MyGUI_MouseButton.h>
|
||||||
|
|
||||||
|
#include <SDL_gamecontroller.h>
|
||||||
|
#include <SDL_mouse.h>
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
std::string sdlControllerButtonToString(int button)
|
||||||
|
{
|
||||||
|
switch(button)
|
||||||
|
{
|
||||||
|
case SDL_CONTROLLER_BUTTON_A:
|
||||||
|
return "A Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_B:
|
||||||
|
return "B Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_BACK:
|
||||||
|
return "Back Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
||||||
|
return "DPad Down";
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
||||||
|
return "DPad Left";
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
||||||
|
return "DPad Right";
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_UP:
|
||||||
|
return "DPad Up";
|
||||||
|
case SDL_CONTROLLER_BUTTON_GUIDE:
|
||||||
|
return "Guide Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
|
||||||
|
return "Left Shoulder";
|
||||||
|
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
|
||||||
|
return "Left Stick Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
|
||||||
|
return "Right Shoulder";
|
||||||
|
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
|
||||||
|
return "Right Stick Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_START:
|
||||||
|
return "Start Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_X:
|
||||||
|
return "X Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_Y:
|
||||||
|
return "Y Button";
|
||||||
|
default:
|
||||||
|
return "Button " + std::to_string(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sdlControllerAxisToString(int axis)
|
||||||
|
{
|
||||||
|
switch(axis)
|
||||||
|
{
|
||||||
|
case SDL_CONTROLLER_AXIS_LEFTX:
|
||||||
|
return "Left Stick X";
|
||||||
|
case SDL_CONTROLLER_AXIS_LEFTY:
|
||||||
|
return "Left Stick Y";
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTX:
|
||||||
|
return "Right Stick X";
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTY:
|
||||||
|
return "Right Stick Y";
|
||||||
|
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
|
||||||
|
return "Left Trigger";
|
||||||
|
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
|
||||||
|
return "Right Trigger";
|
||||||
|
default:
|
||||||
|
return "Axis " + std::to_string(axis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button)
|
||||||
|
{
|
||||||
|
//The right button is the second button, according to MyGUI
|
||||||
|
if(button == SDL_BUTTON_RIGHT)
|
||||||
|
button = SDL_BUTTON_MIDDLE;
|
||||||
|
else if(button == SDL_BUTTON_MIDDLE)
|
||||||
|
button = SDL_BUTTON_RIGHT;
|
||||||
|
|
||||||
|
//MyGUI's buttons are 0 indexed
|
||||||
|
return MyGUI::MouseButton::Enum(button - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initKeyMap(std::map<SDL_Keycode, MyGUI::KeyCode>& keyMap)
|
||||||
|
{
|
||||||
|
keyMap[SDLK_UNKNOWN] = MyGUI::KeyCode::None;
|
||||||
|
keyMap[SDLK_ESCAPE] = MyGUI::KeyCode::Escape;
|
||||||
|
keyMap[SDLK_1] = MyGUI::KeyCode::One;
|
||||||
|
keyMap[SDLK_2] = MyGUI::KeyCode::Two;
|
||||||
|
keyMap[SDLK_3] = MyGUI::KeyCode::Three;
|
||||||
|
keyMap[SDLK_4] = MyGUI::KeyCode::Four;
|
||||||
|
keyMap[SDLK_5] = MyGUI::KeyCode::Five;
|
||||||
|
keyMap[SDLK_6] = MyGUI::KeyCode::Six;
|
||||||
|
keyMap[SDLK_7] = MyGUI::KeyCode::Seven;
|
||||||
|
keyMap[SDLK_8] = MyGUI::KeyCode::Eight;
|
||||||
|
keyMap[SDLK_9] = MyGUI::KeyCode::Nine;
|
||||||
|
keyMap[SDLK_0] = MyGUI::KeyCode::Zero;
|
||||||
|
keyMap[SDLK_MINUS] = MyGUI::KeyCode::Minus;
|
||||||
|
keyMap[SDLK_EQUALS] = MyGUI::KeyCode::Equals;
|
||||||
|
keyMap[SDLK_BACKSPACE] = MyGUI::KeyCode::Backspace;
|
||||||
|
keyMap[SDLK_TAB] = MyGUI::KeyCode::Tab;
|
||||||
|
keyMap[SDLK_q] = MyGUI::KeyCode::Q;
|
||||||
|
keyMap[SDLK_w] = MyGUI::KeyCode::W;
|
||||||
|
keyMap[SDLK_e] = MyGUI::KeyCode::E;
|
||||||
|
keyMap[SDLK_r] = MyGUI::KeyCode::R;
|
||||||
|
keyMap[SDLK_t] = MyGUI::KeyCode::T;
|
||||||
|
keyMap[SDLK_y] = MyGUI::KeyCode::Y;
|
||||||
|
keyMap[SDLK_u] = MyGUI::KeyCode::U;
|
||||||
|
keyMap[SDLK_i] = MyGUI::KeyCode::I;
|
||||||
|
keyMap[SDLK_o] = MyGUI::KeyCode::O;
|
||||||
|
keyMap[SDLK_p] = MyGUI::KeyCode::P;
|
||||||
|
keyMap[SDLK_RETURN] = MyGUI::KeyCode::Return;
|
||||||
|
keyMap[SDLK_a] = MyGUI::KeyCode::A;
|
||||||
|
keyMap[SDLK_s] = MyGUI::KeyCode::S;
|
||||||
|
keyMap[SDLK_d] = MyGUI::KeyCode::D;
|
||||||
|
keyMap[SDLK_f] = MyGUI::KeyCode::F;
|
||||||
|
keyMap[SDLK_g] = MyGUI::KeyCode::G;
|
||||||
|
keyMap[SDLK_h] = MyGUI::KeyCode::H;
|
||||||
|
keyMap[SDLK_j] = MyGUI::KeyCode::J;
|
||||||
|
keyMap[SDLK_k] = MyGUI::KeyCode::K;
|
||||||
|
keyMap[SDLK_l] = MyGUI::KeyCode::L;
|
||||||
|
keyMap[SDLK_SEMICOLON] = MyGUI::KeyCode::Semicolon;
|
||||||
|
keyMap[SDLK_QUOTE] = MyGUI::KeyCode::Apostrophe;
|
||||||
|
keyMap[SDLK_BACKQUOTE] = MyGUI::KeyCode::Grave;
|
||||||
|
keyMap[SDLK_LSHIFT] = MyGUI::KeyCode::LeftShift;
|
||||||
|
keyMap[SDLK_BACKSLASH] = MyGUI::KeyCode::Backslash;
|
||||||
|
keyMap[SDLK_z] = MyGUI::KeyCode::Z;
|
||||||
|
keyMap[SDLK_x] = MyGUI::KeyCode::X;
|
||||||
|
keyMap[SDLK_c] = MyGUI::KeyCode::C;
|
||||||
|
keyMap[SDLK_v] = MyGUI::KeyCode::V;
|
||||||
|
keyMap[SDLK_b] = MyGUI::KeyCode::B;
|
||||||
|
keyMap[SDLK_n] = MyGUI::KeyCode::N;
|
||||||
|
keyMap[SDLK_m] = MyGUI::KeyCode::M;
|
||||||
|
keyMap[SDLK_COMMA] = MyGUI::KeyCode::Comma;
|
||||||
|
keyMap[SDLK_PERIOD] = MyGUI::KeyCode::Period;
|
||||||
|
keyMap[SDLK_SLASH] = MyGUI::KeyCode::Slash;
|
||||||
|
keyMap[SDLK_RSHIFT] = MyGUI::KeyCode::RightShift;
|
||||||
|
keyMap[SDLK_KP_MULTIPLY] = MyGUI::KeyCode::Multiply;
|
||||||
|
keyMap[SDLK_LALT] = MyGUI::KeyCode::LeftAlt;
|
||||||
|
keyMap[SDLK_SPACE] = MyGUI::KeyCode::Space;
|
||||||
|
keyMap[SDLK_CAPSLOCK] = MyGUI::KeyCode::Capital;
|
||||||
|
keyMap[SDLK_F1] = MyGUI::KeyCode::F1;
|
||||||
|
keyMap[SDLK_F2] = MyGUI::KeyCode::F2;
|
||||||
|
keyMap[SDLK_F3] = MyGUI::KeyCode::F3;
|
||||||
|
keyMap[SDLK_F4] = MyGUI::KeyCode::F4;
|
||||||
|
keyMap[SDLK_F5] = MyGUI::KeyCode::F5;
|
||||||
|
keyMap[SDLK_F6] = MyGUI::KeyCode::F6;
|
||||||
|
keyMap[SDLK_F7] = MyGUI::KeyCode::F7;
|
||||||
|
keyMap[SDLK_F8] = MyGUI::KeyCode::F8;
|
||||||
|
keyMap[SDLK_F9] = MyGUI::KeyCode::F9;
|
||||||
|
keyMap[SDLK_F10] = MyGUI::KeyCode::F10;
|
||||||
|
keyMap[SDLK_NUMLOCKCLEAR] = MyGUI::KeyCode::NumLock;
|
||||||
|
keyMap[SDLK_SCROLLLOCK] = MyGUI::KeyCode::ScrollLock;
|
||||||
|
keyMap[SDLK_KP_7] = MyGUI::KeyCode::Numpad7;
|
||||||
|
keyMap[SDLK_KP_8] = MyGUI::KeyCode::Numpad8;
|
||||||
|
keyMap[SDLK_KP_9] = MyGUI::KeyCode::Numpad9;
|
||||||
|
keyMap[SDLK_KP_MINUS] = MyGUI::KeyCode::Subtract;
|
||||||
|
keyMap[SDLK_KP_4] = MyGUI::KeyCode::Numpad4;
|
||||||
|
keyMap[SDLK_KP_5] = MyGUI::KeyCode::Numpad5;
|
||||||
|
keyMap[SDLK_KP_6] = MyGUI::KeyCode::Numpad6;
|
||||||
|
keyMap[SDLK_KP_PLUS] = MyGUI::KeyCode::Add;
|
||||||
|
keyMap[SDLK_KP_1] = MyGUI::KeyCode::Numpad1;
|
||||||
|
keyMap[SDLK_KP_2] = MyGUI::KeyCode::Numpad2;
|
||||||
|
keyMap[SDLK_KP_3] = MyGUI::KeyCode::Numpad3;
|
||||||
|
keyMap[SDLK_KP_0] = MyGUI::KeyCode::Numpad0;
|
||||||
|
keyMap[SDLK_KP_PERIOD] = MyGUI::KeyCode::Decimal;
|
||||||
|
keyMap[SDLK_F11] = MyGUI::KeyCode::F11;
|
||||||
|
keyMap[SDLK_F12] = MyGUI::KeyCode::F12;
|
||||||
|
keyMap[SDLK_F13] = MyGUI::KeyCode::F13;
|
||||||
|
keyMap[SDLK_F14] = MyGUI::KeyCode::F14;
|
||||||
|
keyMap[SDLK_F15] = MyGUI::KeyCode::F15;
|
||||||
|
keyMap[SDLK_KP_EQUALS] = MyGUI::KeyCode::NumpadEquals;
|
||||||
|
keyMap[SDLK_COLON] = MyGUI::KeyCode::Colon;
|
||||||
|
keyMap[SDLK_KP_ENTER] = MyGUI::KeyCode::NumpadEnter;
|
||||||
|
keyMap[SDLK_KP_DIVIDE] = MyGUI::KeyCode::Divide;
|
||||||
|
keyMap[SDLK_SYSREQ] = MyGUI::KeyCode::SysRq;
|
||||||
|
keyMap[SDLK_RALT] = MyGUI::KeyCode::RightAlt;
|
||||||
|
keyMap[SDLK_HOME] = MyGUI::KeyCode::Home;
|
||||||
|
keyMap[SDLK_UP] = MyGUI::KeyCode::ArrowUp;
|
||||||
|
keyMap[SDLK_PAGEUP] = MyGUI::KeyCode::PageUp;
|
||||||
|
keyMap[SDLK_LEFT] = MyGUI::KeyCode::ArrowLeft;
|
||||||
|
keyMap[SDLK_RIGHT] = MyGUI::KeyCode::ArrowRight;
|
||||||
|
keyMap[SDLK_END] = MyGUI::KeyCode::End;
|
||||||
|
keyMap[SDLK_DOWN] = MyGUI::KeyCode::ArrowDown;
|
||||||
|
keyMap[SDLK_PAGEDOWN] = MyGUI::KeyCode::PageDown;
|
||||||
|
keyMap[SDLK_INSERT] = MyGUI::KeyCode::Insert;
|
||||||
|
keyMap[SDLK_DELETE] = MyGUI::KeyCode::Delete;
|
||||||
|
keyMap[SDLK_APPLICATION] = MyGUI::KeyCode::AppMenu;
|
||||||
|
|
||||||
|
//The function of the Ctrl and Meta keys are switched on macOS compared to other platforms.
|
||||||
|
//For instance] = Cmd+C versus Ctrl+C to copy from the system clipboard
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
keyMap[SDLK_LGUI] = MyGUI::KeyCode::LeftControl;
|
||||||
|
keyMap[SDLK_RGUI] = MyGUI::KeyCode::RightControl;
|
||||||
|
keyMap[SDLK_LCTRL] = MyGUI::KeyCode::LeftWindows;
|
||||||
|
keyMap[SDLK_RCTRL] = MyGUI::KeyCode::RightWindows;
|
||||||
|
#else
|
||||||
|
keyMap[SDLK_LGUI] = MyGUI::KeyCode::LeftWindows;
|
||||||
|
keyMap[SDLK_RGUI] = MyGUI::KeyCode::RightWindows;
|
||||||
|
keyMap[SDLK_LCTRL] = MyGUI::KeyCode::LeftControl;
|
||||||
|
keyMap[SDLK_RCTRL] = MyGUI::KeyCode::RightControl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MyGUI::KeyCode sdlKeyToMyGUI(SDL_Keycode code)
|
||||||
|
{
|
||||||
|
static std::map<SDL_Keycode, MyGUI::KeyCode> keyMap;
|
||||||
|
if (keyMap.empty())
|
||||||
|
initKeyMap(keyMap);
|
||||||
|
|
||||||
|
MyGUI::KeyCode kc = MyGUI::KeyCode::None;
|
||||||
|
auto foundKey = keyMap.find(code);
|
||||||
|
if (foundKey != keyMap.end())
|
||||||
|
kc = foundKey->second;
|
||||||
|
|
||||||
|
return kc;
|
||||||
|
}
|
||||||
|
}
|
25
apps/openmw/mwinput/sdlmappings.hpp
Normal file
25
apps/openmw/mwinput/sdlmappings.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef MWINPUT_SDLMAPPINGS_H
|
||||||
|
#define MWINPUT_SDLMAPPINGS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <MyGUI_KeyCode.h>
|
||||||
|
|
||||||
|
#include <SDL_keycode.h>
|
||||||
|
|
||||||
|
namespace MyGUI
|
||||||
|
{
|
||||||
|
struct MouseButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
std::string sdlControllerButtonToString(int button);
|
||||||
|
|
||||||
|
std::string sdlControllerAxisToString(int axis);
|
||||||
|
|
||||||
|
MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button);
|
||||||
|
|
||||||
|
MyGUI::KeyCode sdlKeyToMyGUI(SDL_Keycode code);
|
||||||
|
}
|
||||||
|
#endif
|
267
apps/openmw/mwinput/sensormanager.cpp
Normal file
267
apps/openmw/mwinput/sensormanager.cpp
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
#include "sensormanager.hpp"
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
SensorManager::SensorManager()
|
||||||
|
: mInvertX(Settings::Manager::getBool("invert x axis", "Input"))
|
||||||
|
, mInvertY(Settings::Manager::getBool("invert y axis", "Input"))
|
||||||
|
, mGyroXSpeed(0.f)
|
||||||
|
, mGyroYSpeed(0.f)
|
||||||
|
, mGyroUpdateTimer(0.f)
|
||||||
|
, mGyroHSensitivity(Settings::Manager::getFloat("gyro horizontal sensitivity", "Input"))
|
||||||
|
, mGyroVSensitivity(Settings::Manager::getFloat("gyro vertical sensitivity", "Input"))
|
||||||
|
, mGyroHAxis(GyroscopeAxis::Minus_X)
|
||||||
|
, mGyroVAxis(GyroscopeAxis::Y)
|
||||||
|
, mGyroInputThreshold(Settings::Manager::getFloat("gyro input threshold", "Input"))
|
||||||
|
, mGyroscope(nullptr)
|
||||||
|
, mGuiCursorEnabled(true)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::init()
|
||||||
|
{
|
||||||
|
correctGyroscopeAxes();
|
||||||
|
updateSensors();
|
||||||
|
}
|
||||||
|
|
||||||
|
SensorManager::~SensorManager()
|
||||||
|
{
|
||||||
|
if (mGyroscope != nullptr)
|
||||||
|
{
|
||||||
|
SDL_SensorClose(mGyroscope);
|
||||||
|
mGyroscope = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SensorManager::GyroscopeAxis SensorManager::mapGyroscopeAxis(const std::string& axis)
|
||||||
|
{
|
||||||
|
if (axis == "x")
|
||||||
|
return GyroscopeAxis::X;
|
||||||
|
else if (axis == "y")
|
||||||
|
return GyroscopeAxis::Y;
|
||||||
|
else if (axis == "z")
|
||||||
|
return GyroscopeAxis::Z;
|
||||||
|
else if (axis == "-x")
|
||||||
|
return GyroscopeAxis::Minus_X;
|
||||||
|
else if (axis == "-y")
|
||||||
|
return GyroscopeAxis::Minus_Y;
|
||||||
|
else if (axis == "-z")
|
||||||
|
return GyroscopeAxis::Minus_Z;
|
||||||
|
|
||||||
|
return GyroscopeAxis::Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::correctGyroscopeAxes()
|
||||||
|
{
|
||||||
|
if (!Settings::Manager::getBool("enable gyroscope", "Input"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Treat setting from config as axes for landscape mode.
|
||||||
|
// If the device does not support orientation change, do nothing.
|
||||||
|
// Note: in is unclear how to correct axes for devices with non-standart Z axis direction.
|
||||||
|
mGyroHAxis = mapGyroscopeAxis(Settings::Manager::getString("gyro horizontal axis", "Input"));
|
||||||
|
mGyroVAxis = mapGyroscopeAxis(Settings::Manager::getString("gyro vertical axis", "Input"));
|
||||||
|
|
||||||
|
SDL_DisplayOrientation currentOrientation = SDL_GetDisplayOrientation(Settings::Manager::getInt("screen", "Video"));
|
||||||
|
switch (currentOrientation)
|
||||||
|
{
|
||||||
|
case SDL_ORIENTATION_UNKNOWN:
|
||||||
|
return;
|
||||||
|
case SDL_ORIENTATION_LANDSCAPE:
|
||||||
|
break;
|
||||||
|
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
|
||||||
|
{
|
||||||
|
mGyroHAxis = GyroscopeAxis(-mGyroHAxis);
|
||||||
|
mGyroVAxis = GyroscopeAxis(-mGyroVAxis);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_ORIENTATION_PORTRAIT:
|
||||||
|
{
|
||||||
|
GyroscopeAxis oldVAxis = mGyroVAxis;
|
||||||
|
mGyroVAxis = mGyroHAxis;
|
||||||
|
mGyroHAxis = GyroscopeAxis(-oldVAxis);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_ORIENTATION_PORTRAIT_FLIPPED:
|
||||||
|
{
|
||||||
|
GyroscopeAxis oldVAxis = mGyroVAxis;
|
||||||
|
mGyroVAxis = GyroscopeAxis(-mGyroHAxis);
|
||||||
|
mGyroHAxis = oldVAxis;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::updateSensors()
|
||||||
|
{
|
||||||
|
if (Settings::Manager::getBool("enable gyroscope", "Input"))
|
||||||
|
{
|
||||||
|
int numSensors = SDL_NumSensors();
|
||||||
|
for (int i = 0; i < numSensors; ++i)
|
||||||
|
{
|
||||||
|
if (SDL_SensorGetDeviceType(i) == SDL_SENSOR_GYRO)
|
||||||
|
{
|
||||||
|
// It is unclear how to handle several enabled gyroscopes, so use the first one.
|
||||||
|
// Note: Android registers some gyroscope as two separate sensors, for non-wake-up mode and for wake-up mode.
|
||||||
|
if (mGyroscope != nullptr)
|
||||||
|
{
|
||||||
|
SDL_SensorClose(mGyroscope);
|
||||||
|
mGyroscope = nullptr;
|
||||||
|
mGyroXSpeed = mGyroYSpeed = 0.f;
|
||||||
|
mGyroUpdateTimer = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: SDL2 does not provide a way to configure a sensor update frequency so far.
|
||||||
|
SDL_Sensor *sensor = SDL_SensorOpen(i);
|
||||||
|
if (sensor == nullptr)
|
||||||
|
Log(Debug::Error) << "Couldn't open sensor " << SDL_SensorGetDeviceName(i) << ": " << SDL_GetError();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mGyroscope = sensor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mGyroscope != nullptr)
|
||||||
|
{
|
||||||
|
SDL_SensorClose(mGyroscope);
|
||||||
|
mGyroscope = nullptr;
|
||||||
|
mGyroXSpeed = mGyroYSpeed = 0.f;
|
||||||
|
mGyroUpdateTimer = 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||||
|
{
|
||||||
|
for (const auto& setting : changed)
|
||||||
|
{
|
||||||
|
if (setting.first == "Input" && setting.second == "invert x axis")
|
||||||
|
mInvertX = Settings::Manager::getBool("invert x axis", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "invert y axis")
|
||||||
|
mInvertY = Settings::Manager::getBool("invert y axis", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "gyro horizontal sensitivity")
|
||||||
|
mGyroHSensitivity = Settings::Manager::getFloat("gyro horizontal sensitivity", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "gyro vertical sensitivity")
|
||||||
|
mGyroVSensitivity = Settings::Manager::getFloat("gyro vertical sensitivity", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "enable gyroscope")
|
||||||
|
init();
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "gyro horizontal axis")
|
||||||
|
correctGyroscopeAxes();
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "gyro vertical axis")
|
||||||
|
correctGyroscopeAxes();
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "gyro input threshold")
|
||||||
|
mGyroInputThreshold = Settings::Manager::getFloat("gyro input threshold", "Input");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float SensorManager::getGyroAxisSpeed(GyroscopeAxis axis, const SDL_SensorEvent &arg) const
|
||||||
|
{
|
||||||
|
switch (axis)
|
||||||
|
{
|
||||||
|
case GyroscopeAxis::X:
|
||||||
|
case GyroscopeAxis::Y:
|
||||||
|
case GyroscopeAxis::Z:
|
||||||
|
return std::abs(arg.data[0]) >= mGyroInputThreshold ? arg.data[axis-1] : 0.f;
|
||||||
|
case GyroscopeAxis::Minus_X:
|
||||||
|
case GyroscopeAxis::Minus_Y:
|
||||||
|
case GyroscopeAxis::Minus_Z:
|
||||||
|
return std::abs(arg.data[0]) >= mGyroInputThreshold ? -arg.data[std::abs(axis)-1] : 0.f;
|
||||||
|
default:
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::displayOrientationChanged()
|
||||||
|
{
|
||||||
|
correctGyroscopeAxes();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::sensorUpdated(const SDL_SensorEvent &arg)
|
||||||
|
{
|
||||||
|
if (!Settings::Manager::getBool("enable gyroscope", "Input"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
SDL_Sensor *sensor = SDL_SensorFromInstanceID(arg.which);
|
||||||
|
if (!sensor)
|
||||||
|
{
|
||||||
|
Log(Debug::Info) << "Couldn't get sensor for sensor event";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (SDL_SensorGetType(sensor))
|
||||||
|
{
|
||||||
|
case SDL_SENSOR_ACCEL:
|
||||||
|
break;
|
||||||
|
case SDL_SENSOR_GYRO:
|
||||||
|
{
|
||||||
|
mGyroXSpeed = getGyroAxisSpeed(mGyroHAxis, arg);
|
||||||
|
mGyroYSpeed = getGyroAxisSpeed(mGyroVAxis, arg);
|
||||||
|
mGyroUpdateTimer = 0.f;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::update(float dt)
|
||||||
|
{
|
||||||
|
if (mGyroXSpeed == 0.f && mGyroYSpeed == 0.f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mGyroUpdateTimer > 0.5f)
|
||||||
|
{
|
||||||
|
// More than half of second passed since the last gyroscope update.
|
||||||
|
// A device more likely was disconnected or switched to the sleep mode.
|
||||||
|
// Reset current rotation speed and wait for update.
|
||||||
|
mGyroXSpeed = 0.f;
|
||||||
|
mGyroYSpeed = 0.f;
|
||||||
|
mGyroUpdateTimer = 0.f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mGyroUpdateTimer += dt;
|
||||||
|
|
||||||
|
if (!mGuiCursorEnabled)
|
||||||
|
{
|
||||||
|
float rot[3];
|
||||||
|
rot[0] = mGyroYSpeed * dt * mGyroVSensitivity * 4 * (mInvertY ? -1 : 1);
|
||||||
|
rot[1] = 0.0f;
|
||||||
|
rot[2] = mGyroXSpeed * dt * mGyroHSensitivity * 4 * (mInvertX ? -1 : 1);
|
||||||
|
|
||||||
|
// Only actually turn player when we're not in vanity mode
|
||||||
|
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && MWBase::Environment::get().getInputManager()->getControlSwitch("playerlooking"))
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.yaw(rot[2]);
|
||||||
|
player.pitch(rot[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
apps/openmw/mwinput/sensormanager.hpp
Normal file
73
apps/openmw/mwinput/sensormanager.hpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#ifndef MWINPUT_MWSENSORMANAGER_H
|
||||||
|
#define MWINPUT_MWSENSORMANAGER_H
|
||||||
|
|
||||||
|
#include <SDL_sensor.h>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
|
namespace SDLUtil
|
||||||
|
{
|
||||||
|
class InputWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
class Player;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class SensorManager : public SDLUtil::SensorListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SensorManager();
|
||||||
|
|
||||||
|
virtual ~SensorManager();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
void update(float dt);
|
||||||
|
|
||||||
|
virtual void sensorUpdated(const SDL_SensorEvent &arg);
|
||||||
|
virtual void displayOrientationChanged();
|
||||||
|
void processChangedSettings(const Settings::CategorySettingVector& changed);
|
||||||
|
|
||||||
|
void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum GyroscopeAxis
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
X = 1,
|
||||||
|
Y = 2,
|
||||||
|
Z = 3,
|
||||||
|
Minus_X = -1,
|
||||||
|
Minus_Y = -2,
|
||||||
|
Minus_Z = -3
|
||||||
|
};
|
||||||
|
|
||||||
|
void updateSensors();
|
||||||
|
void correctGyroscopeAxes();
|
||||||
|
GyroscopeAxis mapGyroscopeAxis(const std::string& axis);
|
||||||
|
float getGyroAxisSpeed(GyroscopeAxis axis, const SDL_SensorEvent &arg) const;
|
||||||
|
|
||||||
|
bool mInvertX;
|
||||||
|
bool mInvertY;
|
||||||
|
|
||||||
|
float mGyroXSpeed;
|
||||||
|
float mGyroYSpeed;
|
||||||
|
float mGyroUpdateTimer;
|
||||||
|
|
||||||
|
float mGyroHSensitivity;
|
||||||
|
float mGyroVSensitivity;
|
||||||
|
GyroscopeAxis mGyroHAxis;
|
||||||
|
GyroscopeAxis mGyroVAxis;
|
||||||
|
float mGyroInputThreshold;
|
||||||
|
|
||||||
|
SDL_Sensor* mGyroscope;
|
||||||
|
|
||||||
|
bool mGuiCursorEnabled;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -3,6 +3,7 @@
|
||||||
#include <components/esm/aisequence.hpp>
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
@ -55,8 +56,9 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
||||||
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
|
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (isTargetMagicallyHidden(target))
|
if (!MWBase::Environment::get().getWorld()->getLOS(target, actor)
|
||||||
return true;
|
|| !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(target, actor))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (target.getClass().getCreatureStats(target).isDead())
|
if (target.getClass().getCreatureStats(target).isDead())
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -276,8 +276,7 @@ namespace MWMechanics
|
||||||
completeManualWalking(actor, storage);
|
completeManualWalking(actor, storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
AiWanderStorage::WanderState& wanderState = storage.mState;
|
if (storage.mState == AiWanderStorage::Wander_MoveNow && storage.mCanWanderAlongPathGrid)
|
||||||
if ((wanderState == AiWanderStorage::Wander_MoveNow) && storage.mCanWanderAlongPathGrid)
|
|
||||||
{
|
{
|
||||||
// Construct a new path if there isn't one
|
// Construct a new path if there isn't one
|
||||||
if(!mPathFinder.isPathConstructed())
|
if(!mPathFinder.isPathConstructed())
|
||||||
|
@ -293,8 +292,10 @@ namespace MWMechanics
|
||||||
completeManualWalking(actor, storage);
|
completeManualWalking(actor, storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wanderState == AiWanderStorage::Wander_Walking
|
if (storage.mIsWanderingManually
|
||||||
&& (isDestinationHidden(actor, mPathFinder.getPath().back())
|
&& storage.mState == AiWanderStorage::Wander_Walking
|
||||||
|
&& (mPathFinder.getPathSize() == 0
|
||||||
|
|| isDestinationHidden(actor, mPathFinder.getPath().back())
|
||||||
|| isAreaOccupiedByOtherActor(actor, mPathFinder.getPath().back())))
|
|| isAreaOccupiedByOtherActor(actor, mPathFinder.getPath().back())))
|
||||||
completeManualWalking(actor, storage);
|
completeManualWalking(actor, storage);
|
||||||
|
|
||||||
|
|
|
@ -2481,8 +2481,12 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||||
}
|
}
|
||||||
else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed)
|
else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed)
|
||||||
{
|
{
|
||||||
float speedmult = speed / mMovementAnimSpeed;
|
// Vanilla caps the played animation speed.
|
||||||
mAnimation->adjustSpeedMult(mCurrentMovement, speedmult);
|
const float maxSpeedMult = 10.f;
|
||||||
|
const float speedMult = speed / mMovementAnimSpeed;
|
||||||
|
mAnimation->adjustSpeedMult(mCurrentMovement, std::min(maxSpeedMult, speedMult));
|
||||||
|
// Make sure the actual speed is the "expected" speed even though the animation is slower
|
||||||
|
scale *= std::max(1.f, speedMult / maxSpeedMult);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mSkipAnim)
|
if (!mSkipAnim)
|
||||||
|
|
|
@ -101,6 +101,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap, bool checkMagicka)
|
float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap, bool checkMagicka)
|
||||||
{
|
{
|
||||||
|
// NB: Base chance is calculated here because the effective school pointer must be filled
|
||||||
|
float baseChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool);
|
||||||
|
|
||||||
bool godmode = actor == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
bool godmode = actor == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
||||||
|
|
||||||
CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
@ -124,7 +127,7 @@ namespace MWMechanics
|
||||||
return 100;
|
return 100;
|
||||||
|
|
||||||
float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude();
|
float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude();
|
||||||
float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus;
|
float castChance = baseChance + castBonus;
|
||||||
castChance *= stats.getFatigueTerm();
|
castChance *= stats.getFatigueTerm();
|
||||||
|
|
||||||
return std::max(0.f, cap ? std::min(100.f, castChance) : castChance);
|
return std::max(0.f, cap ? std::min(100.f, castChance) : castChance);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <components/openmw-mp/Version.hpp>
|
#include <components/openmw-mp/Version.hpp>
|
||||||
|
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
#include <components/files/configurationmanager.hpp>
|
||||||
#include <components/files/escape.hpp>
|
#include <components/files/escape.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
|
@ -7,12 +7,48 @@
|
||||||
|
|
||||||
#include <LinearMath/btTransform.h>
|
#include <LinearMath/btTransform.h>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
auto makeHeights(const T* heights, float sqrtVerts)
|
||||||
|
-> std::enable_if_t<std::is_same<btScalar, T>::value, std::vector<btScalar>>
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
auto makeHeights(const T* heights, float sqrtVerts)
|
||||||
|
-> std::enable_if_t<!std::is_same<btScalar, T>::value, std::vector<btScalar>>
|
||||||
|
{
|
||||||
|
return std::vector<btScalar>(heights, heights + static_cast<std::ptrdiff_t>(sqrtVerts * sqrtVerts));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
auto getHeights(const T* floatHeights, const std::vector<btScalar>&)
|
||||||
|
-> std::enable_if_t<std::is_same<btScalar, T>::value, const btScalar*>
|
||||||
|
{
|
||||||
|
return floatHeights;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
auto getHeights(const T*, const std::vector<btScalar>& btScalarHeights)
|
||||||
|
-> std::enable_if_t<!std::is_same<btScalar, T>::value, const btScalar*>
|
||||||
|
{
|
||||||
|
return btScalarHeights.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWPhysics
|
namespace MWPhysics
|
||||||
{
|
{
|
||||||
HeightField::HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject)
|
HeightField::HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject)
|
||||||
|
: mHeights(makeHeights(heights, sqrtVerts))
|
||||||
{
|
{
|
||||||
mShape = new btHeightfieldTerrainShape(
|
mShape = new btHeightfieldTerrainShape(
|
||||||
sqrtVerts, sqrtVerts, heights, 1,
|
sqrtVerts, sqrtVerts,
|
||||||
|
getHeights(heights, mHeights),
|
||||||
|
1,
|
||||||
minH, maxH, 2,
|
minH, maxH, 2,
|
||||||
PHY_FLOAT, false
|
PHY_FLOAT, false
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
|
||||||
|
#include <LinearMath/btScalar.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class btCollisionObject;
|
class btCollisionObject;
|
||||||
class btHeightfieldTerrainShape;
|
class btHeightfieldTerrainShape;
|
||||||
|
|
||||||
|
@ -27,6 +31,7 @@ namespace MWPhysics
|
||||||
btHeightfieldTerrainShape* mShape;
|
btHeightfieldTerrainShape* mShape;
|
||||||
btCollisionObject* mCollisionObject;
|
btCollisionObject* mCollisionObject;
|
||||||
osg::ref_ptr<const osg::Object> mHoldObject;
|
osg::ref_ptr<const osg::Object> mHoldObject;
|
||||||
|
std::vector<btScalar> mHeights;
|
||||||
|
|
||||||
void operator=(const HeightField&);
|
void operator=(const HeightField&);
|
||||||
HeightField(const HeightField&);
|
HeightField(const HeightField&);
|
||||||
|
|
|
@ -181,6 +181,10 @@ osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, f
|
||||||
camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object | Mask_Static);
|
camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object | Mask_Static);
|
||||||
camera->setNodeMask(Mask_RenderToTexture);
|
camera->setNodeMask(Mask_RenderToTexture);
|
||||||
|
|
||||||
|
// Disable small feature culling, it's not going to be reliable for this camera
|
||||||
|
osg::Camera::CullingMode cullingMode = (osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING) & ~(osg::CullStack::SMALL_FEATURE_CULLING);
|
||||||
|
camera->setCullingMode(cullingMode);
|
||||||
|
|
||||||
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
|
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
|
||||||
stateset->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), osg::StateAttribute::OVERRIDE);
|
stateset->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), osg::StateAttribute::OVERRIDE);
|
||||||
|
|
||||||
|
@ -693,12 +697,10 @@ void LocalMap::MapSegment::loadFogOfWar(const ESM::FogTexture &esm)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: deprecate tga and use raw data instead
|
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
||||||
|
|
||||||
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("tga");
|
|
||||||
if (!readerwriter)
|
if (!readerwriter)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Error: Unable to load fog, can't find a tga ReaderWriter" ;
|
Log(Debug::Error) << "Error: Unable to load fog, can't find a png ReaderWriter" ;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -727,10 +729,10 @@ void LocalMap::MapSegment::saveFogOfWar(ESM::FogTexture &fog) const
|
||||||
|
|
||||||
std::ostringstream ostream;
|
std::ostringstream ostream;
|
||||||
|
|
||||||
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("tga");
|
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
||||||
if (!readerwriter)
|
if (!readerwriter)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Error: Unable to write fog, can't find a tga ReaderWriter";
|
Log(Debug::Error) << "Error: Unable to write fog, can't find a png ReaderWriter";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,81 +5,169 @@
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/globalscript.hpp>
|
#include <components/esm/globalscript.hpp>
|
||||||
|
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/scriptmanager.hpp"
|
#include "../mwbase/scriptmanager.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
|
||||||
#include "interpretercontext.hpp"
|
#include "interpretercontext.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct ScriptCreatingVisitor : public boost::static_visitor<ESM::GlobalScript>
|
||||||
|
{
|
||||||
|
ESM::GlobalScript operator()(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
ESM::GlobalScript script;
|
||||||
|
script.mTargetRef.unset();
|
||||||
|
if (!ptr.isEmpty())
|
||||||
|
{
|
||||||
|
if (ptr.getCellRef().hasContentFile())
|
||||||
|
{
|
||||||
|
script.mTargetId = ptr.getCellRef().getRefId();
|
||||||
|
script.mTargetRef = ptr.getCellRef().getRefNum();
|
||||||
|
}
|
||||||
|
else if (MWBase::Environment::get().getWorld()->getPlayerPtr() == ptr)
|
||||||
|
script.mTargetId = ptr.getCellRef().getRefId();
|
||||||
|
}
|
||||||
|
return script;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM::GlobalScript operator()(const std::pair<ESM::RefNum, std::string> &pair) const
|
||||||
|
{
|
||||||
|
ESM::GlobalScript script;
|
||||||
|
script.mTargetId = pair.second;
|
||||||
|
script.mTargetRef = pair.first;
|
||||||
|
return script;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PtrGettingVisitor : public boost::static_visitor<const MWWorld::Ptr*>
|
||||||
|
{
|
||||||
|
const MWWorld::Ptr* operator()(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
return &ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MWWorld::Ptr* operator()(const std::pair<ESM::RefNum, std::string> &pair) const
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PtrResolvingVisitor : public boost::static_visitor<MWWorld::Ptr>
|
||||||
|
{
|
||||||
|
MWWorld::Ptr operator()(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Ptr operator()(const std::pair<ESM::RefNum, std::string> &pair) const
|
||||||
|
{
|
||||||
|
if (pair.second.empty())
|
||||||
|
return MWWorld::Ptr();
|
||||||
|
else if(pair.first.hasContentFile())
|
||||||
|
return MWBase::Environment::get().getWorld()->searchPtrViaRefNum(pair.second, pair.first);
|
||||||
|
return MWBase::Environment::get().getWorld()->searchPtr(pair.second, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MatchPtrVisitor : public boost::static_visitor<bool>
|
||||||
|
{
|
||||||
|
const MWWorld::Ptr& mPtr;
|
||||||
|
public:
|
||||||
|
MatchPtrVisitor(const MWWorld::Ptr& ptr) : mPtr(ptr) {}
|
||||||
|
|
||||||
|
bool operator()(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
return ptr == mPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(const std::pair<ESM::RefNum, std::string> &pair) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWScript
|
namespace MWScript
|
||||||
{
|
{
|
||||||
GlobalScriptDesc::GlobalScriptDesc() : mRunning (false) {}
|
GlobalScriptDesc::GlobalScriptDesc() : mRunning (false) {}
|
||||||
|
|
||||||
|
const MWWorld::Ptr* GlobalScriptDesc::getPtrIfPresent() const
|
||||||
|
{
|
||||||
|
return boost::apply_visitor(PtrGettingVisitor(), mTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Ptr GlobalScriptDesc::getPtr()
|
||||||
|
{
|
||||||
|
MWWorld::Ptr ptr = boost::apply_visitor(PtrResolvingVisitor(), mTarget);
|
||||||
|
mTarget = ptr;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GlobalScripts::GlobalScripts (const MWWorld::ESMStore& store)
|
GlobalScripts::GlobalScripts (const MWWorld::ESMStore& store)
|
||||||
: mStore (store)
|
: mStore (store)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void GlobalScripts::addScript (const std::string& name, const std::string& targetId)
|
void GlobalScripts::addScript (const std::string& name, const MWWorld::Ptr& target)
|
||||||
{
|
{
|
||||||
std::map<std::string, GlobalScriptDesc>::iterator iter =
|
const auto iter = mScripts.find (::Misc::StringUtils::lowerCase (name));
|
||||||
mScripts.find (::Misc::StringUtils::lowerCase (name));
|
|
||||||
|
|
||||||
if (iter==mScripts.end())
|
if (iter==mScripts.end())
|
||||||
{
|
{
|
||||||
if (const ESM::Script *script = mStore.get<ESM::Script>().search(name))
|
if (const ESM::Script *script = mStore.get<ESM::Script>().search(name))
|
||||||
{
|
{
|
||||||
GlobalScriptDesc desc;
|
auto desc = std::make_shared<GlobalScriptDesc>();
|
||||||
desc.mRunning = true;
|
MWWorld::Ptr ptr = target;
|
||||||
desc.mLocals.configure (*script);
|
desc->mTarget = ptr;
|
||||||
desc.mId = targetId;
|
desc->mRunning = true;
|
||||||
|
desc->mLocals.configure (*script);
|
||||||
mScripts.insert (std::make_pair (name, desc));
|
mScripts.insert (std::make_pair(name, desc));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Failed to add global script " << name << ": script record not found";
|
Log(Debug::Error) << "Failed to add global script " << name << ": script record not found";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!iter->second.mRunning)
|
else if (!iter->second->mRunning)
|
||||||
{
|
{
|
||||||
iter->second.mRunning = true;
|
iter->second->mRunning = true;
|
||||||
iter->second.mId = targetId;
|
MWWorld::Ptr ptr = target;
|
||||||
|
iter->second->mTarget = ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalScripts::removeScript (const std::string& name)
|
void GlobalScripts::removeScript (const std::string& name)
|
||||||
{
|
{
|
||||||
std::map<std::string, GlobalScriptDesc>::iterator iter =
|
const auto iter = mScripts.find (::Misc::StringUtils::lowerCase (name));
|
||||||
mScripts.find (::Misc::StringUtils::lowerCase (name));
|
|
||||||
|
|
||||||
if (iter!=mScripts.end())
|
if (iter!=mScripts.end())
|
||||||
iter->second.mRunning = false;
|
iter->second->mRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GlobalScripts::isRunning (const std::string& name) const
|
bool GlobalScripts::isRunning (const std::string& name) const
|
||||||
{
|
{
|
||||||
std::map<std::string, GlobalScriptDesc>::const_iterator iter =
|
const auto iter = mScripts.find (::Misc::StringUtils::lowerCase (name));
|
||||||
mScripts.find (::Misc::StringUtils::lowerCase (name));
|
|
||||||
|
|
||||||
if (iter==mScripts.end())
|
if (iter==mScripts.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return iter->second.mRunning;
|
return iter->second->mRunning;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalScripts::run()
|
void GlobalScripts::run()
|
||||||
{
|
{
|
||||||
for (std::map<std::string, GlobalScriptDesc>::iterator iter (mScripts.begin());
|
for (const auto& script : mScripts)
|
||||||
iter!=mScripts.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
if (iter->second.mRunning)
|
if (script.second->mRunning)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr;
|
MWScript::InterpreterContext context(script.second);
|
||||||
|
|
||||||
MWScript::InterpreterContext interpreterContext (
|
|
||||||
&iter->second.mLocals, MWWorld::Ptr(), iter->second.mId);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
@ -88,12 +176,13 @@ namespace MWScript
|
||||||
so that packets sent by the Interpreter can have their
|
so that packets sent by the Interpreter can have their
|
||||||
origin determined by serverside scripts
|
origin determined by serverside scripts
|
||||||
*/
|
*/
|
||||||
interpreterContext.setContextType(Interpreter::Context::SCRIPT_GLOBAL);
|
context.setContextType(Interpreter::Context::SCRIPT_GLOBAL);
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MWBase::Environment::get().getScriptManager()->run (iter->first, interpreterContext);
|
if (!MWBase::Environment::get().getScriptManager()->run(script.first, context))
|
||||||
|
script.second->mRunning = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,18 +230,15 @@ namespace MWScript
|
||||||
|
|
||||||
void GlobalScripts::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
|
void GlobalScripts::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
|
||||||
{
|
{
|
||||||
for (std::map<std::string, GlobalScriptDesc>::const_iterator iter (mScripts.begin());
|
for (const auto& iter : mScripts)
|
||||||
iter!=mScripts.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
ESM::GlobalScript script;
|
ESM::GlobalScript script = boost::apply_visitor (ScriptCreatingVisitor(), iter.second->mTarget);
|
||||||
|
|
||||||
script.mId = iter->first;
|
script.mId = iter.first;
|
||||||
|
|
||||||
iter->second.mLocals.write (script.mLocals, iter->first);
|
iter.second->mLocals.write (script.mLocals, iter.first);
|
||||||
|
|
||||||
script.mRunning = iter->second.mRunning ? 1 : 0;
|
script.mRunning = iter.second->mRunning ? 1 : 0;
|
||||||
|
|
||||||
script.mTargetId = iter->second.mId;
|
|
||||||
|
|
||||||
writer.startRecord (ESM::REC_GSCR);
|
writer.startRecord (ESM::REC_GSCR);
|
||||||
script.save (writer);
|
script.save (writer);
|
||||||
|
@ -167,8 +253,7 @@ namespace MWScript
|
||||||
ESM::GlobalScript script;
|
ESM::GlobalScript script;
|
||||||
script.load (reader);
|
script.load (reader);
|
||||||
|
|
||||||
std::map<std::string, GlobalScriptDesc>::iterator iter =
|
auto iter = mScripts.find (script.mId);
|
||||||
mScripts.find (script.mId);
|
|
||||||
|
|
||||||
if (iter==mScripts.end())
|
if (iter==mScripts.end())
|
||||||
{
|
{
|
||||||
|
@ -176,8 +261,12 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
GlobalScriptDesc desc;
|
auto desc = std::make_shared<GlobalScriptDesc>();
|
||||||
desc.mLocals.configure (*scriptRecord);
|
if (!script.mTargetId.empty())
|
||||||
|
{
|
||||||
|
desc->mTarget = std::make_pair(script.mTargetRef, script.mTargetId);
|
||||||
|
}
|
||||||
|
desc->mLocals.configure (*scriptRecord);
|
||||||
|
|
||||||
iter = mScripts.insert (std::make_pair (script.mId, desc)).first;
|
iter = mScripts.insert (std::make_pair (script.mId, desc)).first;
|
||||||
}
|
}
|
||||||
|
@ -194,9 +283,8 @@ namespace MWScript
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
iter->second.mRunning = script.mRunning!=0;
|
iter->second->mRunning = script.mRunning!=0;
|
||||||
iter->second.mLocals.read (script.mLocals, script.mId);
|
iter->second->mLocals.read (script.mLocals, script.mId);
|
||||||
iter->second.mId = script.mTargetId;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -207,18 +295,28 @@ namespace MWScript
|
||||||
Locals& GlobalScripts::getLocals (const std::string& name)
|
Locals& GlobalScripts::getLocals (const std::string& name)
|
||||||
{
|
{
|
||||||
std::string name2 = ::Misc::StringUtils::lowerCase (name);
|
std::string name2 = ::Misc::StringUtils::lowerCase (name);
|
||||||
std::map<std::string, GlobalScriptDesc>::iterator iter = mScripts.find (name2);
|
auto iter = mScripts.find (name2);
|
||||||
|
|
||||||
if (iter==mScripts.end())
|
if (iter==mScripts.end())
|
||||||
{
|
{
|
||||||
const ESM::Script *script = mStore.get<ESM::Script>().find (name);
|
const ESM::Script *script = mStore.get<ESM::Script>().find (name);
|
||||||
|
|
||||||
GlobalScriptDesc desc;
|
auto desc = std::make_shared<GlobalScriptDesc>();
|
||||||
desc.mLocals.configure (*script);
|
desc->mLocals.configure (*script);
|
||||||
|
|
||||||
iter = mScripts.insert (std::make_pair (name2, desc)).first;
|
iter = mScripts.insert (std::make_pair (name2, desc)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
return iter->second.mLocals;
|
return iter->second->mLocals;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalScripts::updatePtrs(const MWWorld::Ptr& base, const MWWorld::Ptr& updated)
|
||||||
|
{
|
||||||
|
MatchPtrVisitor visitor(base);
|
||||||
|
for (const auto& script : mScripts)
|
||||||
|
{
|
||||||
|
if (boost::apply_visitor (visitor, script.second->mTarget))
|
||||||
|
script.second->mTarget = updated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
#ifndef GAME_SCRIPT_GLOBALSCRIPTS_H
|
#ifndef GAME_SCRIPT_GLOBALSCRIPTS_H
|
||||||
#define GAME_SCRIPT_GLOBALSCRIPTS_H
|
#define GAME_SCRIPT_GLOBALSCRIPTS_H
|
||||||
|
|
||||||
|
#include <boost/variant/variant.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "locals.hpp"
|
#include "locals.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
class ESMWriter;
|
class ESMWriter;
|
||||||
class ESMReader;
|
class ESMReader;
|
||||||
|
struct RefNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Loading
|
namespace Loading
|
||||||
|
@ -30,21 +37,25 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
bool mRunning;
|
bool mRunning;
|
||||||
Locals mLocals;
|
Locals mLocals;
|
||||||
std::string mId; // ID used to start targeted script (empty if not a targeted script)
|
boost::variant<MWWorld::Ptr, std::pair<ESM::RefNum, std::string> > mTarget; // Used to start targeted script
|
||||||
|
|
||||||
GlobalScriptDesc();
|
GlobalScriptDesc();
|
||||||
|
|
||||||
|
const MWWorld::Ptr* getPtrIfPresent() const; // Returns a Ptr if one has been resolved
|
||||||
|
|
||||||
|
MWWorld::Ptr getPtr(); // Resolves mTarget to a Ptr and caches the (potentially empty) result
|
||||||
};
|
};
|
||||||
|
|
||||||
class GlobalScripts
|
class GlobalScripts
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore& mStore;
|
const MWWorld::ESMStore& mStore;
|
||||||
std::map<std::string, GlobalScriptDesc> mScripts;
|
std::map<std::string, std::shared_ptr<GlobalScriptDesc> > mScripts;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GlobalScripts (const MWWorld::ESMStore& store);
|
GlobalScripts (const MWWorld::ESMStore& store);
|
||||||
|
|
||||||
void addScript (const std::string& name, const std::string& targetId = "");
|
void addScript (const std::string& name, const MWWorld::Ptr& target = MWWorld::Ptr());
|
||||||
|
|
||||||
void removeScript (const std::string& name);
|
void removeScript (const std::string& name);
|
||||||
|
|
||||||
|
@ -70,6 +81,9 @@ namespace MWScript
|
||||||
Locals& getLocals (const std::string& name);
|
Locals& getLocals (const std::string& name);
|
||||||
///< If the script \a name has not been added as a global script yet, it is added
|
///< If the script \a name has not been added as a global script yet, it is added
|
||||||
/// automatically, but is not set to running state.
|
/// automatically, but is not set to running state.
|
||||||
|
|
||||||
|
void updatePtrs(const MWWorld::Ptr& base, const MWWorld::Ptr& updated);
|
||||||
|
///< Update the Ptrs stored in mTarget. Should be called after the reference has been moved to a new cell.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "interpretercontext.hpp"
|
#include "interpretercontext.hpp"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <stdexcept>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <components/compiler/locals.hpp>
|
#include <components/compiler/locals.hpp>
|
||||||
|
@ -43,26 +42,6 @@
|
||||||
|
|
||||||
namespace MWScript
|
namespace MWScript
|
||||||
{
|
{
|
||||||
MWWorld::Ptr InterpreterContext::getReferenceImp (
|
|
||||||
const std::string& id, bool activeOnly, bool doThrow)
|
|
||||||
{
|
|
||||||
if (!id.empty())
|
|
||||||
{
|
|
||||||
return MWBase::Environment::get().getWorld()->getPtr (id, activeOnly);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (mReference.isEmpty() && !mTargetId.empty())
|
|
||||||
mReference =
|
|
||||||
MWBase::Environment::get().getWorld()->searchPtr (mTargetId, false);
|
|
||||||
|
|
||||||
if (mReference.isEmpty() && doThrow)
|
|
||||||
throw std::runtime_error ("no implicit reference");
|
|
||||||
|
|
||||||
return mReference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
@ -90,12 +69,11 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (mReference.isEmpty() && !mTargetId.empty())
|
if (mReference.isEmpty() && mGlobalScriptDesc)
|
||||||
mReference =
|
mReference = mGlobalScriptDesc->getPtr();
|
||||||
MWBase::Environment::get().getWorld()->searchPtr (mTargetId, false);
|
|
||||||
|
|
||||||
if (mReference.isEmpty() && doThrow)
|
if (mReference.isEmpty() && doThrow)
|
||||||
throw std::runtime_error ("no implicit reference");
|
throw MissingImplicitRefError();
|
||||||
|
|
||||||
return mReference;
|
return mReference;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +91,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr ptr = getReferenceImp (id, false);
|
const MWWorld::Ptr ptr = getReferenceImp (id, false);
|
||||||
|
|
||||||
id = ptr.getClass().getScript (ptr);
|
id = ptr.getClass().getScript (ptr);
|
||||||
|
|
||||||
ptr.getRefData().setLocals (
|
ptr.getRefData().setLocals (
|
||||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id));
|
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id));
|
||||||
|
@ -142,6 +120,8 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MissingImplicitRefError::MissingImplicitRefError() : std::runtime_error("no implicit reference") {}
|
||||||
|
|
||||||
int InterpreterContext::findLocalVariableIndex (const std::string& scriptId,
|
int InterpreterContext::findLocalVariableIndex (const std::string& scriptId,
|
||||||
const std::string& name, char type) const
|
const std::string& name, char type) const
|
||||||
{
|
{
|
||||||
|
@ -167,27 +147,21 @@ namespace MWScript
|
||||||
throw std::runtime_error (stream.str().c_str());
|
throw std::runtime_error (stream.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InterpreterContext::InterpreterContext (MWScript::Locals *locals, const MWWorld::Ptr& reference)
|
||||||
|
: mLocals (locals), mReference (reference)
|
||||||
|
{}
|
||||||
|
|
||||||
InterpreterContext::InterpreterContext (
|
InterpreterContext::InterpreterContext (std::shared_ptr<GlobalScriptDesc> globalScriptDesc)
|
||||||
MWScript::Locals *locals, const MWWorld::Ptr& reference, const std::string& targetId)
|
: mLocals (&(globalScriptDesc->mLocals))
|
||||||
: mLocals (locals), mReference (reference), mTargetId (targetId)
|
|
||||||
{
|
{
|
||||||
// If we run on a reference (local script, dialogue script or console with object
|
const MWWorld::Ptr* ptr = globalScriptDesc->getPtrIfPresent();
|
||||||
// selected), store the ID of that reference store it so it can be inherited by
|
// A nullptr here signifies that the script's target has not yet been resolved after loading the game.
|
||||||
// targeted scripts started from this one.
|
// Script targets are lazily resolved to MWWorld::Ptrs (which can, upon resolution, be empty)
|
||||||
if (targetId.empty() && !reference.isEmpty())
|
// because scripts started through dialogue often don't use their implicit target.
|
||||||
mTargetId = reference.getCellRef().getRefId();
|
if (ptr)
|
||||||
|
mReference = *ptr;
|
||||||
/*
|
else
|
||||||
Start of tes3mp addition
|
mGlobalScriptDesc = globalScriptDesc;
|
||||||
|
|
||||||
Boolean used to check whether value change packets should be sent for the
|
|
||||||
script being processed by the InterpreterContext
|
|
||||||
*/
|
|
||||||
sendPackets = false;
|
|
||||||
/*
|
|
||||||
End of tes3mp addition
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int InterpreterContext::getLocalShort (int index) const
|
int InterpreterContext::getLocalShort (int index) const
|
||||||
|
@ -660,7 +634,12 @@ namespace MWScript
|
||||||
|
|
||||||
void InterpreterContext::startScript (const std::string& name, const std::string& targetId)
|
void InterpreterContext::startScript (const std::string& name, const std::string& targetId)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name, targetId);
|
MWWorld::Ptr target;
|
||||||
|
if (targetId.empty())
|
||||||
|
target = getReference(false);
|
||||||
|
else
|
||||||
|
target = getReferenceImp(targetId);
|
||||||
|
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterpreterContext::stopScript (const std::string& name)
|
void InterpreterContext::stopScript (const std::string& name)
|
||||||
|
@ -672,12 +651,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
// NOTE: id may be empty, indicating an implicit reference
|
// NOTE: id may be empty, indicating an implicit reference
|
||||||
|
|
||||||
MWWorld::Ptr ref2;
|
MWWorld::Ptr ref2 = getReferenceImp(id);
|
||||||
|
|
||||||
if (id.empty())
|
|
||||||
ref2 = getReferenceImp();
|
|
||||||
else
|
|
||||||
ref2 = MWBase::Environment::get().getWorld()->getPtr(id, false);
|
|
||||||
|
|
||||||
if (ref2.getContainerStore()) // is the object contained?
|
if (ref2.getContainerStore()) // is the object contained?
|
||||||
{
|
{
|
||||||
|
@ -901,11 +875,6 @@ namespace MWScript
|
||||||
return getReferenceImp ("", true, required);
|
return getReferenceImp ("", true, required);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string InterpreterContext::getTargetId() const
|
|
||||||
{
|
|
||||||
return mTargetId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InterpreterContext::updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated)
|
void InterpreterContext::updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated)
|
||||||
{
|
{
|
||||||
if (!mReference.isEmpty() && base == mReference)
|
if (!mReference.isEmpty() && base == mReference)
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
#ifndef GAME_SCRIPT_INTERPRETERCONTEXT_H
|
#ifndef GAME_SCRIPT_INTERPRETERCONTEXT_H
|
||||||
#define GAME_SCRIPT_INTERPRETERCONTEXT_H
|
#define GAME_SCRIPT_INTERPRETERCONTEXT_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <components/interpreter/context.hpp>
|
#include <components/interpreter/context.hpp>
|
||||||
|
|
||||||
|
#include "globalscripts.hpp"
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
|
@ -19,17 +24,17 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
class Locals;
|
class Locals;
|
||||||
|
|
||||||
|
class MissingImplicitRefError : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MissingImplicitRefError();
|
||||||
|
};
|
||||||
|
|
||||||
class InterpreterContext : public Interpreter::Context
|
class InterpreterContext : public Interpreter::Context
|
||||||
{
|
{
|
||||||
Locals *mLocals;
|
Locals *mLocals;
|
||||||
mutable MWWorld::Ptr mReference;
|
mutable MWWorld::Ptr mReference;
|
||||||
|
std::shared_ptr<GlobalScriptDesc> mGlobalScriptDesc;
|
||||||
std::string mTargetId;
|
|
||||||
|
|
||||||
/// If \a id is empty, a reference the script is run from is returned or in case
|
|
||||||
/// of a non-local script the reference derived from the target ID.
|
|
||||||
MWWorld::Ptr getReferenceImp (const std::string& id = "", bool activeOnly = false,
|
|
||||||
bool doThrow=true);
|
|
||||||
|
|
||||||
/// If \a id is empty, a reference the script is run from is returned or in case
|
/// If \a id is empty, a reference the script is run from is returned or in case
|
||||||
/// of a non-local script the reference derived from the target ID.
|
/// of a non-local script the reference derived from the target ID.
|
||||||
|
@ -47,17 +52,18 @@ namespace MWScript
|
||||||
char type) const;
|
char type) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
InterpreterContext (std::shared_ptr<GlobalScriptDesc> globalScriptDesc);
|
||||||
|
|
||||||
InterpreterContext (MWScript::Locals *locals, const MWWorld::Ptr& reference,
|
InterpreterContext (MWScript::Locals *locals, const MWWorld::Ptr& reference);
|
||||||
const std::string& targetId = "");
|
|
||||||
///< The ownership of \a locals is not transferred. 0-pointer allowed.
|
///< The ownership of \a locals is not transferred. 0-pointer allowed.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
Useful boolean for setting whether scripts send packets
|
Useful boolean for setting whether scripts send packets, set to false by default
|
||||||
|
to avoid massive packet spam
|
||||||
*/
|
*/
|
||||||
bool sendPackets;
|
bool sendPackets = false;
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
@ -177,8 +183,6 @@ namespace MWScript
|
||||||
|
|
||||||
void updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated);
|
void updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated);
|
||||||
///< Update the Ptr stored in mReference, if there is one stored there. Should be called after the reference has been moved to a new cell.
|
///< Update the Ptr stored in mReference, if there is one stored there. Should be called after the reference has been moved to a new cell.
|
||||||
|
|
||||||
virtual std::string getTargetId() const;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
#include "extensions.hpp"
|
#include "extensions.hpp"
|
||||||
|
#include "interpretercontext.hpp"
|
||||||
|
|
||||||
namespace MWScript
|
namespace MWScript
|
||||||
{
|
{
|
||||||
|
@ -88,7 +89,7 @@ namespace MWScript
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext)
|
bool ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext)
|
||||||
{
|
{
|
||||||
// compile script
|
// compile script
|
||||||
ScriptCollection::iterator iter = mScripts.find (name);
|
ScriptCollection::iterator iter = mScripts.find (name);
|
||||||
|
@ -100,7 +101,7 @@ namespace MWScript
|
||||||
// failed -> ignore script from now on.
|
// failed -> ignore script from now on.
|
||||||
std::vector<Interpreter::Type_Code> empty;
|
std::vector<Interpreter::Type_Code> empty;
|
||||||
mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals())));
|
mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals())));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
iter = mScripts.find (name);
|
iter = mScripts.find (name);
|
||||||
|
@ -118,14 +119,19 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
|
|
||||||
mInterpreter.run (&iter->second.first[0], iter->second.first.size(), interpreterContext);
|
mInterpreter.run (&iter->second.first[0], iter->second.first.size(), interpreterContext);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (const MissingImplicitRefError& e)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Execution of script " << name << " failed: " << e.what();
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Execution of script " << name << " failed:";
|
Log(Debug::Error) << "Execution of script " << name << " failed: " << e.what();
|
||||||
Log(Debug::Error) << e.what();
|
|
||||||
|
|
||||||
iter->second.first.clear(); // don't execute again.
|
iter->second.first.clear(); // don't execute again.
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int, int> ScriptManager::compileAll()
|
std::pair<int, int> ScriptManager::compileAll()
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace MWScript
|
||||||
Compiler::Context& compilerContext, int warningsMode,
|
Compiler::Context& compilerContext, int warningsMode,
|
||||||
const std::vector<std::string>& scriptBlacklist);
|
const std::vector<std::string>& scriptBlacklist);
|
||||||
|
|
||||||
virtual void run (const std::string& name, Interpreter::Context& interpreterContext);
|
virtual bool run (const std::string& name, Interpreter::Context& interpreterContext);
|
||||||
///< Run the script with the given name (compile first, if not compiled yet)
|
///< Run the script with the given name (compile first, if not compiled yet)
|
||||||
|
|
||||||
virtual bool compile (const std::string& name);
|
virtual bool compile (const std::string& name);
|
||||||
|
|
|
@ -144,6 +144,7 @@ void MWState::StateManager::newGame (bool bypass)
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Log(Debug::Info) << "Starting a new game";
|
||||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup();
|
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup();
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->startNewGame (bypass);
|
MWBase::Environment::get().getWorld()->startNewGame (bypass);
|
||||||
|
@ -220,6 +221,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
||||||
profile.mTimePlayed = mTimePlayed;
|
profile.mTimePlayed = mTimePlayed;
|
||||||
profile.mDescription = description;
|
profile.mDescription = description;
|
||||||
|
|
||||||
|
Log(Debug::Info) << "Making a screenshot for saved game '" << description << "'";;
|
||||||
writeScreenshot(profile.mScreenshot);
|
writeScreenshot(profile.mScreenshot);
|
||||||
|
|
||||||
if (!slot)
|
if (!slot)
|
||||||
|
@ -230,6 +232,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
||||||
// Make sure the animation state held by references is up to date before saving the game.
|
// Make sure the animation state held by references is up to date before saving the game.
|
||||||
MWBase::Environment::get().getMechanicsManager()->persistAnimationStates();
|
MWBase::Environment::get().getMechanicsManager()->persistAnimationStates();
|
||||||
|
|
||||||
|
Log(Debug::Info) << "Writing saved game '" << description << "' for character '" << profile.mPlayerName << "'";
|
||||||
|
|
||||||
// Write to a memory stream first. If there is an exception during the save process, we don't want to trash the
|
// Write to a memory stream first. If there is an exception during the save process, we don't want to trash the
|
||||||
// existing save file we are overwriting.
|
// existing save file we are overwriting.
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
|
@ -324,6 +328,16 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
||||||
|
|
||||||
void MWState::StateManager::quickSave (std::string name)
|
void MWState::StateManager::quickSave (std::string name)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
Start of tes3mp change (major)
|
||||||
|
|
||||||
|
It should not be possible to quicksave the game in multiplayer, so it has been disabled
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
End of tes3mp change (major)
|
||||||
|
*/
|
||||||
|
|
||||||
if (!(mState==State_Running &&
|
if (!(mState==State_Running &&
|
||||||
MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1 // char gen
|
MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1 // char gen
|
||||||
&& MWBase::Environment::get().getWindowManager()->isSavingAllowed()))
|
&& MWBase::Environment::get().getWindowManager()->isSavingAllowed()))
|
||||||
|
@ -380,6 +394,8 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
|
||||||
{
|
{
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
|
Log(Debug::Info) << "Reading save file " << boost::filesystem::path(filepath).filename().string();
|
||||||
|
|
||||||
ESM::ESMReader reader;
|
ESM::ESMReader reader;
|
||||||
reader.open (filepath);
|
reader.open (filepath);
|
||||||
|
|
||||||
|
@ -418,6 +434,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mTimePlayed = profile.mTimePlayed;
|
mTimePlayed = profile.mTimePlayed;
|
||||||
|
Log(Debug::Info) << "Loading saved game '" << profile.mDescription << "' for character '" << profile.mPlayerName << "'";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -526,6 +543,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Cell no longer exists (i.e. changed game files), choose a default cell
|
// Cell no longer exists (i.e. changed game files), choose a default cell
|
||||||
|
Log(Debug::Warning) << "Warning: Player character's cell no longer exists, changing to the default cell";
|
||||||
MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(0,0);
|
MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(0,0);
|
||||||
float x,y;
|
float x,y;
|
||||||
MWBase::Environment::get().getWorld()->indexToPosition(0,0,x,y,false);
|
MWBase::Environment::get().getWorld()->indexToPosition(0,0,x,y,false);
|
||||||
|
@ -565,6 +583,16 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
|
||||||
|
|
||||||
void MWState::StateManager::quickLoad()
|
void MWState::StateManager::quickLoad()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
Start of tes3mp change (major)
|
||||||
|
|
||||||
|
It should not be possible to quickload the game in multiplayer, so it has been disabled
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
End of tes3mp change (major)
|
||||||
|
*/
|
||||||
|
|
||||||
if (Character* currentCharacter = getCurrentCharacter ())
|
if (Character* currentCharacter = getCurrentCharacter ())
|
||||||
{
|
{
|
||||||
if (currentCharacter->begin() == currentCharacter->end())
|
if (currentCharacter->begin() == currentCharacter->end())
|
||||||
|
@ -628,7 +656,7 @@ bool MWState::StateManager::verifyProfile(const ESM::SavedGame& profile) const
|
||||||
if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), *it)
|
if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), *it)
|
||||||
== selectedContentFiles.end())
|
== selectedContentFiles.end())
|
||||||
{
|
{
|
||||||
Log(Debug::Warning) << "Warning: Savegame dependency " << *it << " is missing.";
|
Log(Debug::Warning) << "Warning: Saved game dependency " << *it << " is missing.";
|
||||||
notFound = true;
|
notFound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/defs.hpp>
|
#include <components/esm/defs.hpp>
|
||||||
#include <components/esm/cellstate.hpp>
|
#include <components/esm/cellstate.hpp>
|
||||||
|
#include <components/esm/cellref.hpp>
|
||||||
#include <components/loadinglistener/loadinglistener.hpp>
|
#include <components/loadinglistener/loadinglistener.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
@ -291,6 +292,37 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
|
||||||
return Ptr();
|
return Ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& id, const ESM::RefNum& refNum)
|
||||||
|
{
|
||||||
|
for (auto& pair : mInteriors)
|
||||||
|
{
|
||||||
|
Ptr ptr = getPtr(pair.second, id, refNum);
|
||||||
|
if (!ptr.isEmpty())
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
for (auto& pair : mExteriors)
|
||||||
|
{
|
||||||
|
Ptr ptr = getPtr(pair.second, id, refNum);
|
||||||
|
if (!ptr.isEmpty())
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
return Ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Ptr MWWorld::Cells::getPtr(CellStore& cellStore, const std::string& id, const ESM::RefNum& refNum)
|
||||||
|
{
|
||||||
|
if (cellStore.getState() == CellStore::State_Unloaded)
|
||||||
|
cellStore.preload();
|
||||||
|
if (cellStore.getState() == CellStore::State_Preloaded)
|
||||||
|
{
|
||||||
|
if (cellStore.hasId(id))
|
||||||
|
cellStore.load();
|
||||||
|
else
|
||||||
|
return Ptr();
|
||||||
|
}
|
||||||
|
return cellStore.searchViaRefNum(refNum);
|
||||||
|
}
|
||||||
|
|
||||||
void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<MWWorld::Ptr> &out)
|
void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<MWWorld::Ptr> &out)
|
||||||
{
|
{
|
||||||
const MWWorld::Store<ESM::Cell> &cells = mStore.get<ESM::Cell>();
|
const MWWorld::Store<ESM::Cell> &cells = mStore.get<ESM::Cell>();
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace ESM
|
||||||
class ESMWriter;
|
class ESMWriter;
|
||||||
struct CellId;
|
struct CellId;
|
||||||
struct Cell;
|
struct Cell;
|
||||||
|
struct RefNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Loading
|
namespace Loading
|
||||||
|
@ -41,6 +42,8 @@ namespace MWWorld
|
||||||
|
|
||||||
Ptr getPtrAndCache (const std::string& name, CellStore& cellStore);
|
Ptr getPtrAndCache (const std::string& name, CellStore& cellStore);
|
||||||
|
|
||||||
|
Ptr getPtr(CellStore& cellStore, const std::string& id, const ESM::RefNum& refNum);
|
||||||
|
|
||||||
void writeCell (ESM::ESMWriter& writer, CellStore& cell) const;
|
void writeCell (ESM::ESMWriter& writer, CellStore& cell) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -73,6 +76,8 @@ namespace MWWorld
|
||||||
/// @note name must be lower case
|
/// @note name must be lower case
|
||||||
Ptr getPtr (const std::string& name);
|
Ptr getPtr (const std::string& name);
|
||||||
|
|
||||||
|
Ptr getPtr(const std::string& id, const ESM::RefNum& refNum);
|
||||||
|
|
||||||
void rest (double hours);
|
void rest (double hours);
|
||||||
void recharge (float duration);
|
void recharge (float duration);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <components/esm/cellstate.hpp>
|
#include <components/esm/cellstate.hpp>
|
||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
|
#include <components/esm/cellref.hpp>
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/objectstate.hpp>
|
#include <components/esm/objectstate.hpp>
|
||||||
|
@ -509,19 +510,47 @@ namespace MWWorld
|
||||||
return Ptr();
|
return Ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RefNumSearchVisitor
|
||||||
|
{
|
||||||
|
const ESM::RefNum& mRefNum;
|
||||||
|
public:
|
||||||
|
RefNumSearchVisitor(const ESM::RefNum& refNum) : mRefNum(refNum) {}
|
||||||
|
|
||||||
|
Ptr mFound;
|
||||||
|
|
||||||
|
bool operator()(const Ptr& ptr)
|
||||||
|
{
|
||||||
|
if (ptr.getCellRef().getRefNum() == mRefNum)
|
||||||
|
{
|
||||||
|
mFound = ptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ptr CellStore::searchViaRefNum(const ESM::RefNum& refNum)
|
||||||
|
{
|
||||||
|
RefNumSearchVisitor searchVisitor(refNum);
|
||||||
|
forEach(searchVisitor);
|
||||||
|
return searchVisitor.mFound;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
A custom type of search visitor used to find objects by their reference numbers
|
A custom type of search visitor used to find objects by their reference numbers
|
||||||
*/
|
*/
|
||||||
template <typename PtrType>
|
class SearchExactVisitor
|
||||||
struct SearchExactVisitor
|
|
||||||
{
|
{
|
||||||
PtrType mFound;
|
const unsigned int mRefNumToFind;
|
||||||
unsigned int mRefNumToFind;
|
const unsigned int mMpNumToFind;
|
||||||
unsigned int mMpNumToFind;
|
public:
|
||||||
|
SearchExactVisitor(const unsigned int refNum, const unsigned int mpNum) : mRefNumToFind(refNum), mMpNumToFind(mpNum) {}
|
||||||
|
|
||||||
bool operator()(const PtrType& ptr)
|
Ptr mFound;
|
||||||
|
|
||||||
|
bool operator()(const Ptr& ptr)
|
||||||
{
|
{
|
||||||
if (ptr.getCellRef().getRefNum().mIndex == mRefNumToFind && ptr.getCellRef().getMpNum() == mMpNumToFind)
|
if (ptr.getCellRef().getRefNum().mIndex == mRefNumToFind && ptr.getCellRef().getMpNum() == mMpNumToFind)
|
||||||
{
|
{
|
||||||
|
@ -540,15 +569,13 @@ namespace MWWorld
|
||||||
|
|
||||||
Allow the searching of objects by their reference numbers
|
Allow the searching of objects by their reference numbers
|
||||||
*/
|
*/
|
||||||
Ptr CellStore::searchExact (unsigned int refNum, unsigned int mpNum)
|
Ptr CellStore::searchExact (const unsigned int refNum, const unsigned int mpNum)
|
||||||
{
|
{
|
||||||
// Ensure that all objects searched for have a valid reference number
|
// Ensure that all objects searched for have a valid reference number
|
||||||
if (refNum == 0 && mpNum == 0)
|
if (refNum == 0 && mpNum == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SearchExactVisitor<MWWorld::Ptr> searchVisitor;
|
SearchExactVisitor searchVisitor(refNum, mpNum);
|
||||||
searchVisitor.mRefNumToFind = refNum;
|
|
||||||
searchVisitor.mMpNumToFind = mpNum;
|
|
||||||
forEach(searchVisitor);
|
forEach(searchVisitor);
|
||||||
return searchVisitor.mFound;
|
return searchVisitor.mFound;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ namespace ESM
|
||||||
struct CellState;
|
struct CellState;
|
||||||
struct FogState;
|
struct FogState;
|
||||||
struct CellId;
|
struct CellId;
|
||||||
|
struct RefNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
@ -242,6 +243,11 @@ namespace MWWorld
|
||||||
Ptr searchViaActorId (int id);
|
Ptr searchViaActorId (int id);
|
||||||
///< Will return an empty Ptr if cell is not loaded.
|
///< Will return an empty Ptr if cell is not loaded.
|
||||||
|
|
||||||
|
Ptr searchViaRefNum (const ESM::RefNum& refNum);
|
||||||
|
///< Will return an empty Ptr if cell is not loaded. Does not check references in
|
||||||
|
/// containers.
|
||||||
|
/// @note Triggers CellStore hasState flag.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
|
#include <components/esm/cellref.hpp>
|
||||||
|
|
||||||
#include <components/misc/constants.hpp>
|
#include <components/misc/constants.hpp>
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
@ -796,6 +797,11 @@ namespace MWWorld
|
||||||
return mWorldScene->searchPtrViaActorId (actorId);
|
return mWorldScene->searchPtrViaActorId (actorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ptr World::searchPtrViaRefNum (const std::string& id, const ESM::RefNum& refNum)
|
||||||
|
{
|
||||||
|
return mCells.getPtr (id, refNum);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
@ -1477,6 +1483,7 @@ namespace MWWorld
|
||||||
mRendering->updatePtr(ptr, newPtr);
|
mRendering->updatePtr(ptr, newPtr);
|
||||||
MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr);
|
MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr);
|
||||||
mPhysics->updatePtr(ptr, newPtr);
|
mPhysics->updatePtr(ptr, newPtr);
|
||||||
|
MWBase::Environment::get().getScriptManager()->getGlobalScripts().updatePtrs(ptr, newPtr);
|
||||||
|
|
||||||
MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager();
|
MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager();
|
||||||
mechMgr->updateCell(ptr, newPtr);
|
mechMgr->updateCell(ptr, newPtr);
|
||||||
|
|
|
@ -316,6 +316,8 @@ namespace MWWorld
|
||||||
Ptr searchPtrViaActorId (int actorId) override;
|
Ptr searchPtrViaActorId (int actorId) override;
|
||||||
///< Search is limited to the active cells.
|
///< Search is limited to the active cells.
|
||||||
|
|
||||||
|
Ptr searchPtrViaRefNum (const std::string& id, const ESM::RefNum& refNum) override;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
|
|
@ -20,22 +20,62 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct Wrapper {
|
||||||
|
const T& mValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Range>
|
||||||
|
inline testing::Message& writeRange(testing::Message& message, const Range& range)
|
||||||
|
{
|
||||||
|
message << "{\n";
|
||||||
|
for (const auto& v : range)
|
||||||
|
message << Wrapper<typename std::decay<decltype(v)>::type> {v} << ",\n";
|
||||||
|
return message << "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace testing
|
namespace testing
|
||||||
{
|
{
|
||||||
|
template <>
|
||||||
|
inline testing::Message& Message::operator <<(const osg::Vec3f& value)
|
||||||
|
{
|
||||||
|
return (*this) << "osg::Vec3f(" << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.x()
|
||||||
|
<< ", " << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.y()
|
||||||
|
<< ", " << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.z()
|
||||||
|
<< ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline testing::Message& Message::operator <<(const Wrapper<osg::Vec3f>& value)
|
||||||
|
{
|
||||||
|
return (*this) << value.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline testing::Message& Message::operator <<(const Wrapper<float>& value)
|
||||||
|
{
|
||||||
|
return (*this) << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.mValue;
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline testing::Message& Message::operator <<(const std::deque<osg::Vec3f>& value)
|
inline testing::Message& Message::operator <<(const std::deque<osg::Vec3f>& value)
|
||||||
{
|
{
|
||||||
(*this) << "{\n";
|
return writeRange(*this, value);
|
||||||
for (const auto& v : value)
|
}
|
||||||
{
|
|
||||||
std::ostringstream stream;
|
template <>
|
||||||
stream << "osg::Vec3f("
|
inline testing::Message& Message::operator <<(const std::vector<osg::Vec3f>& value)
|
||||||
<< std::setprecision(std::numeric_limits<float>::max_exponent10) << v.x() << ", "
|
{
|
||||||
<< std::setprecision(std::numeric_limits<float>::max_exponent10) << v.y() << ", "
|
return writeRange(*this, value);
|
||||||
<< std::setprecision(std::numeric_limits<float>::max_exponent10) << v.z() << ")";
|
}
|
||||||
(*this) << stream.str() << ",\n";
|
|
||||||
}
|
template <>
|
||||||
return (*this) << "}";
|
inline testing::Message& Message::operator <<(const std::vector<float>& value)
|
||||||
|
{
|
||||||
|
return writeRange(*this, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -363,11 +363,11 @@ namespace
|
||||||
AreaType_ground
|
AreaType_ground
|
||||||
);
|
);
|
||||||
const auto recastMesh = builder.create(mGeneration, mRevision);
|
const auto recastMesh = builder.create(mGeneration, mRevision);
|
||||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
EXPECT_THAT(recastMesh->getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
|
||||||
1.41421353816986083984375, 0, 1.1920928955078125e-07,
|
1.41421353816986083984375, 0, 1.1920928955078125e-07,
|
||||||
-1.41421353816986083984375, 0, -1.1920928955078125e-07,
|
-1.41421353816986083984375, 0, -1.1920928955078125e-07,
|
||||||
1.1920928955078125e-07, 0, -1.41421353816986083984375,
|
1.1920928955078125e-07, 0, -1.41421353816986083984375,
|
||||||
}));
|
})));
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -30,6 +32,34 @@ namespace
|
||||||
shape.processAllTriangles(&callback, aabbMin, aabbMax);
|
shape.processAllTriangles(&callback, aabbMin, aabbMax);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isNear(btScalar lhs, btScalar rhs)
|
||||||
|
{
|
||||||
|
return std::abs(lhs - rhs) <= 1e-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNear(const btVector3& lhs, const btVector3& rhs)
|
||||||
|
{
|
||||||
|
return std::equal(
|
||||||
|
static_cast<const btScalar*>(lhs),
|
||||||
|
static_cast<const btScalar*>(lhs) + 3,
|
||||||
|
static_cast<const btScalar*>(rhs),
|
||||||
|
[] (btScalar lhs, btScalar rhs) { return isNear(lhs, rhs); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNear(const btMatrix3x3& lhs, const btMatrix3x3& rhs)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
if (!isNear(lhs[i], rhs[i]))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNear(const btTransform& lhs, const btTransform& rhs)
|
||||||
|
{
|
||||||
|
return isNear(lhs.getOrigin(), rhs.getOrigin()) && isNear(lhs.getBasis(), rhs.getBasis());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::ostream& operator <<(std::ostream& stream, const btVector3& value)
|
static std::ostream& operator <<(std::ostream& stream, const btVector3& value)
|
||||||
|
@ -157,7 +187,7 @@ static bool operator ==(const btCompoundShape& lhs, const btCompoundShape& rhs)
|
||||||
for (int i = 0; i < lhs.getNumChildShapes(); ++i)
|
for (int i = 0; i < lhs.getNumChildShapes(); ++i)
|
||||||
{
|
{
|
||||||
if (!compareObjects(lhs.getChildShape(i), rhs.getChildShape(i))
|
if (!compareObjects(lhs.getChildShape(i), rhs.getChildShape(i))
|
||||||
|| !(lhs.getChildTransform(i) == rhs.getChildTransform(i)))
|
|| !isNear(lhs.getChildTransform(i), rhs.getChildTransform(i)))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -165,13 +195,13 @@ static bool operator ==(const btCompoundShape& lhs, const btCompoundShape& rhs)
|
||||||
|
|
||||||
static bool operator ==(const btBoxShape& lhs, const btBoxShape& rhs)
|
static bool operator ==(const btBoxShape& lhs, const btBoxShape& rhs)
|
||||||
{
|
{
|
||||||
return lhs.getLocalScaling() == rhs.getLocalScaling()
|
return isNear(lhs.getLocalScaling(), rhs.getLocalScaling())
|
||||||
&& lhs.getHalfExtentsWithoutMargin() == rhs.getHalfExtentsWithoutMargin();
|
&& lhs.getHalfExtentsWithoutMargin() == rhs.getHalfExtentsWithoutMargin();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool operator ==(const btBvhTriangleMeshShape& lhs, const btBvhTriangleMeshShape& rhs)
|
static bool operator ==(const btBvhTriangleMeshShape& lhs, const btBvhTriangleMeshShape& rhs)
|
||||||
{
|
{
|
||||||
return lhs.getLocalScaling() == rhs.getLocalScaling()
|
return isNear(lhs.getLocalScaling(), rhs.getLocalScaling())
|
||||||
&& lhs.usesQuantizedAabbCompression() == rhs.usesQuantizedAabbCompression()
|
&& lhs.usesQuantizedAabbCompression() == rhs.usesQuantizedAabbCompression()
|
||||||
&& lhs.getOwnsBvh() == rhs.getOwnsBvh()
|
&& lhs.getOwnsBvh() == rhs.getOwnsBvh()
|
||||||
&& getTriangles(lhs) == getTriangles(rhs);
|
&& getTriangles(lhs) == getTriangles(rhs);
|
||||||
|
@ -349,19 +379,6 @@ namespace
|
||||||
EXPECT_EQ(*result, expected);
|
EXPECT_EQ(*result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestBulletNifLoader, for_root_not_nif_node_should_return_default)
|
|
||||||
{
|
|
||||||
StrictMock<RecordMock> record;
|
|
||||||
|
|
||||||
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
|
|
||||||
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&record));
|
|
||||||
const auto result = mLoader.load(mNifFile);
|
|
||||||
|
|
||||||
Resource::BulletShape expected;
|
|
||||||
|
|
||||||
EXPECT_EQ(*result, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TestBulletNifLoader, for_default_root_nif_node_should_return_default)
|
TEST_F(TestBulletNifLoader, for_default_root_nif_node_should_return_default)
|
||||||
{
|
{
|
||||||
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
|
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
|
||||||
|
|
|
@ -30,8 +30,8 @@ configuration:
|
||||||
clone_depth: 1
|
clone_depth: 1
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
- C:\projects\openmw\deps\Bullet-2.86-msvc2015-win32.7z
|
- C:\projects\openmw\deps\Bullet-2.87-msvc2015-win32.7z
|
||||||
- C:\projects\openmw\deps\Bullet-2.86-msvc2015-win64.7z
|
- C:\projects\openmw\deps\Bullet-2.87-msvc2015-win64.7z
|
||||||
- C:\projects\openmw\deps\MyGUI-3.2.2-msvc2015-win32.7z
|
- C:\projects\openmw\deps\MyGUI-3.2.2-msvc2015-win32.7z
|
||||||
- C:\projects\openmw\deps\MyGUI-3.2.2-msvc2015-win64.7z
|
- C:\projects\openmw\deps\MyGUI-3.2.2-msvc2015-win64.7z
|
||||||
- C:\projects\openmw\deps\OSG-3.4.1-scrawl-msvc2015-win32.7z
|
- C:\projects\openmw\deps\OSG-3.4.1-scrawl-msvc2015-win32.7z
|
||||||
|
@ -50,15 +50,16 @@ install:
|
||||||
|
|
||||||
before_build:
|
before_build:
|
||||||
- cmd: git submodule update --init --recursive
|
- cmd: git submodule update --init --recursive
|
||||||
- cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -c %configuration% -p %PLATFORM% -v %msvc% -V
|
- cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -c %configuration% -p %PLATFORM% -v %msvc% -V -i %APPVEYOR_BUILD_FOLDER%\install
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- cmd: if %PLATFORM%==Win32 set build=MSVC%msvc%_32
|
- cmd: if %PLATFORM%==Win32 set build=MSVC%msvc%_32
|
||||||
- cmd: if %PLATFORM%==x64 set build=MSVC%msvc%_64
|
- cmd: if %PLATFORM%==x64 set build=MSVC%msvc%_64
|
||||||
- cmd: msbuild %build%\OpenMW.sln /t:Build /p:Configuration=%configuration% /m:2 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
- cmd: msbuild %build%\OpenMW.sln /t:Build /p:Configuration=%configuration% /m:2 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||||
|
- cmd: cmake --install %build% --config %configuration%
|
||||||
|
|
||||||
after_build:
|
after_build:
|
||||||
- cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_%platform%_%appveyor_pull_request_number%_%appveyor_pull_request_head_commit%.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\%configuration%\ -xr"!*.pdb"
|
- cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_%platform%_%appveyor_pull_request_number%_%appveyor_pull_request_head_commit%.zip %APPVEYOR_BUILD_FOLDER%\install -xr"!*.pdb"
|
||||||
#- cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_%platform%_%appveyor_pull_request_number%_%appveyor_pull_request_head_commit%_pdb.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\%configuration%\*.pdb
|
#- cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_%platform%_%appveyor_pull_request_number%_%appveyor_pull_request_head_commit%_pdb.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\%configuration%\*.pdb
|
||||||
|
|
||||||
test: off
|
test: off
|
||||||
|
|
|
@ -143,7 +143,7 @@ add_component_dir (fontloader
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (sdlutil
|
add_component_dir (sdlutil
|
||||||
sdlgraphicswindow imagetosurface sdlinputwrapper sdlvideowrapper OISCompat events sdlcursormanager
|
sdlgraphicswindow imagetosurface sdlinputwrapper sdlvideowrapper events sdlcursormanager
|
||||||
)
|
)
|
||||||
ENDIF(BUILD_OPENMW OR BUILD_OPENCS)
|
ENDIF(BUILD_OPENMW OR BUILD_OPENCS)
|
||||||
|
|
||||||
|
|
|
@ -163,15 +163,15 @@ namespace DetourNavigator
|
||||||
|
|
||||||
transformBoundingBox(transform, aabbMin, aabbMax);
|
transformBoundingBox(transform, aabbMin, aabbMax);
|
||||||
|
|
||||||
aabbMin.setX(std::max(mBounds.mMin.x(), aabbMin.x()));
|
aabbMin.setX(std::max(static_cast<btScalar>(mBounds.mMin.x()), aabbMin.x()));
|
||||||
aabbMin.setX(std::min(mBounds.mMax.x(), aabbMin.x()));
|
aabbMin.setX(std::min(static_cast<btScalar>(mBounds.mMax.x()), aabbMin.x()));
|
||||||
aabbMin.setY(std::max(mBounds.mMin.y(), aabbMin.y()));
|
aabbMin.setY(std::max(static_cast<btScalar>(mBounds.mMin.y()), aabbMin.y()));
|
||||||
aabbMin.setY(std::min(mBounds.mMax.y(), aabbMin.y()));
|
aabbMin.setY(std::min(static_cast<btScalar>(mBounds.mMax.y()), aabbMin.y()));
|
||||||
|
|
||||||
aabbMax.setX(std::max(mBounds.mMin.x(), aabbMax.x()));
|
aabbMax.setX(std::max(static_cast<btScalar>(mBounds.mMin.x()), aabbMax.x()));
|
||||||
aabbMax.setX(std::min(mBounds.mMax.x(), aabbMax.x()));
|
aabbMax.setX(std::min(static_cast<btScalar>(mBounds.mMax.x()), aabbMax.x()));
|
||||||
aabbMax.setY(std::max(mBounds.mMin.y(), aabbMax.y()));
|
aabbMax.setY(std::max(static_cast<btScalar>(mBounds.mMin.y()), aabbMax.y()));
|
||||||
aabbMax.setY(std::min(mBounds.mMax.y(), aabbMax.y()));
|
aabbMax.setY(std::min(static_cast<btScalar>(mBounds.mMax.y()), aabbMax.y()));
|
||||||
|
|
||||||
transformBoundingBox(transform.inverse(), aabbMin, aabbMax);
|
transformBoundingBox(transform.inverse(), aabbMin, aabbMax);
|
||||||
|
|
||||||
|
|
|
@ -17,53 +17,60 @@ void ESM::CreatureStats::load (ESMReader &esm)
|
||||||
mTradeTime.mHour = 0;
|
mTradeTime.mHour = 0;
|
||||||
esm.getHNOT (mTradeTime, "TIME");
|
esm.getHNOT (mTradeTime, "TIME");
|
||||||
|
|
||||||
|
int flags = 0;
|
||||||
mDead = false;
|
mDead = false;
|
||||||
esm.getHNOT (mDead, "DEAD");
|
|
||||||
|
|
||||||
mDeathAnimationFinished = false;
|
mDeathAnimationFinished = false;
|
||||||
esm.getHNOT (mDeathAnimationFinished, "DFNT");
|
|
||||||
|
|
||||||
if (esm.getFormat() < 3 && mDead)
|
|
||||||
mDeathAnimationFinished = true;
|
|
||||||
|
|
||||||
mDied = false;
|
mDied = false;
|
||||||
esm.getHNOT (mDied, "DIED");
|
|
||||||
|
|
||||||
mMurdered = false;
|
mMurdered = false;
|
||||||
esm.getHNOT (mMurdered, "MURD");
|
|
||||||
|
|
||||||
if (esm.isNextSub("FRHT"))
|
|
||||||
esm.skipHSub(); // Friendly hits, no longer used
|
|
||||||
|
|
||||||
mTalkedTo = false;
|
mTalkedTo = false;
|
||||||
esm.getHNOT (mTalkedTo, "TALK");
|
|
||||||
|
|
||||||
mAlarmed = false;
|
mAlarmed = false;
|
||||||
esm.getHNOT (mAlarmed, "ALRM");
|
|
||||||
|
|
||||||
mAttacked = false;
|
mAttacked = false;
|
||||||
esm.getHNOT (mAttacked, "ATKD");
|
|
||||||
|
|
||||||
if (esm.isNextSub("HOST"))
|
|
||||||
esm.skipHSub(); // Hostile, no longer used
|
|
||||||
|
|
||||||
if (esm.isNextSub("ATCK"))
|
|
||||||
esm.skipHSub(); // attackingOrSpell, no longer used
|
|
||||||
|
|
||||||
mKnockdown = false;
|
mKnockdown = false;
|
||||||
esm.getHNOT (mKnockdown, "KNCK");
|
|
||||||
|
|
||||||
mKnockdownOneFrame = false;
|
mKnockdownOneFrame = false;
|
||||||
esm.getHNOT (mKnockdownOneFrame, "KNC1");
|
|
||||||
|
|
||||||
mKnockdownOverOneFrame = false;
|
mKnockdownOverOneFrame = false;
|
||||||
esm.getHNOT (mKnockdownOverOneFrame, "KNCO");
|
|
||||||
|
|
||||||
mHitRecovery = false;
|
mHitRecovery = false;
|
||||||
esm.getHNOT (mHitRecovery, "HITR");
|
|
||||||
|
|
||||||
mBlock = false;
|
mBlock = false;
|
||||||
esm.getHNOT (mBlock, "BLCK");
|
mRecalcDynamicStats = false;
|
||||||
|
if (esm.getFormat() < 8)
|
||||||
|
{
|
||||||
|
esm.getHNOT (mDead, "DEAD");
|
||||||
|
esm.getHNOT (mDeathAnimationFinished, "DFNT");
|
||||||
|
if (esm.getFormat() < 3 && mDead)
|
||||||
|
mDeathAnimationFinished = true;
|
||||||
|
esm.getHNOT (mDied, "DIED");
|
||||||
|
esm.getHNOT (mMurdered, "MURD");
|
||||||
|
if (esm.isNextSub("FRHT"))
|
||||||
|
esm.skipHSub(); // Friendly hits, no longer used
|
||||||
|
esm.getHNOT (mTalkedTo, "TALK");
|
||||||
|
esm.getHNOT (mAlarmed, "ALRM");
|
||||||
|
esm.getHNOT (mAttacked, "ATKD");
|
||||||
|
if (esm.isNextSub("HOST"))
|
||||||
|
esm.skipHSub(); // Hostile, no longer used
|
||||||
|
if (esm.isNextSub("ATCK"))
|
||||||
|
esm.skipHSub(); // attackingOrSpell, no longer used
|
||||||
|
esm.getHNOT (mKnockdown, "KNCK");
|
||||||
|
esm.getHNOT (mKnockdownOneFrame, "KNC1");
|
||||||
|
esm.getHNOT (mKnockdownOverOneFrame, "KNCO");
|
||||||
|
esm.getHNOT (mHitRecovery, "HITR");
|
||||||
|
esm.getHNOT (mBlock, "BLCK");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
esm.getHNOT(flags, "AFLG");
|
||||||
|
mDead = flags & Dead;
|
||||||
|
mDeathAnimationFinished = flags & DeathAnimationFinished;
|
||||||
|
mDied = flags & Died;
|
||||||
|
mMurdered = flags & Murdered;
|
||||||
|
mTalkedTo = flags & TalkedTo;
|
||||||
|
mAlarmed = flags & Alarmed;
|
||||||
|
mAttacked = flags & Attacked;
|
||||||
|
mKnockdown = flags & Knockdown;
|
||||||
|
mKnockdownOneFrame = flags & KnockdownOneFrame;
|
||||||
|
mKnockdownOverOneFrame = flags & KnockdownOverOneFrame;
|
||||||
|
mHitRecovery = flags & HitRecovery;
|
||||||
|
mBlock = flags & Block;
|
||||||
|
mRecalcDynamicStats = flags & RecalcDynamicStats;
|
||||||
|
}
|
||||||
|
|
||||||
mMovementFlags = 0;
|
mMovementFlags = 0;
|
||||||
esm.getHNOT (mMovementFlags, "MOVE");
|
esm.getHNOT (mMovementFlags, "MOVE");
|
||||||
|
@ -78,8 +85,8 @@ void ESM::CreatureStats::load (ESMReader &esm)
|
||||||
|
|
||||||
mLastHitAttemptObject = esm.getHNOString ("LHAT");
|
mLastHitAttemptObject = esm.getHNOString ("LHAT");
|
||||||
|
|
||||||
mRecalcDynamicStats = false;
|
if (esm.getFormat() < 8)
|
||||||
esm.getHNOT (mRecalcDynamicStats, "CALC");
|
esm.getHNOT (mRecalcDynamicStats, "CALC");
|
||||||
|
|
||||||
mDrawState = 0;
|
mDrawState = 0;
|
||||||
esm.getHNOT (mDrawState, "DRAW");
|
esm.getHNOT (mDrawState, "DRAW");
|
||||||
|
@ -90,9 +97,6 @@ void ESM::CreatureStats::load (ESMReader &esm)
|
||||||
mActorId = -1;
|
mActorId = -1;
|
||||||
esm.getHNOT (mActorId, "ACID");
|
esm.getHNOT (mActorId, "ACID");
|
||||||
|
|
||||||
//mHitAttemptActorId = -1;
|
|
||||||
//esm.getHNOT(mHitAttemptActorId, "HAID");
|
|
||||||
|
|
||||||
mDeathAnimation = -1;
|
mDeathAnimation = -1;
|
||||||
esm.getHNOT (mDeathAnimation, "DANM");
|
esm.getHNOT (mDeathAnimation, "DANM");
|
||||||
|
|
||||||
|
@ -134,7 +138,6 @@ void ESM::CreatureStats::load (ESMReader &esm)
|
||||||
|
|
||||||
void ESM::CreatureStats::save (ESMWriter &esm) const
|
void ESM::CreatureStats::save (ESMWriter &esm) const
|
||||||
{
|
{
|
||||||
|
|
||||||
for (int i=0; i<8; ++i)
|
for (int i=0; i<8; ++i)
|
||||||
mAttributes[i].save (esm);
|
mAttributes[i].save (esm);
|
||||||
|
|
||||||
|
@ -147,41 +150,23 @@ void ESM::CreatureStats::save (ESMWriter &esm) const
|
||||||
if (mTradeTime.mDay != 0 || mTradeTime.mHour != 0)
|
if (mTradeTime.mDay != 0 || mTradeTime.mHour != 0)
|
||||||
esm.writeHNT ("TIME", mTradeTime);
|
esm.writeHNT ("TIME", mTradeTime);
|
||||||
|
|
||||||
if (mDead)
|
int flags = 0;
|
||||||
esm.writeHNT ("DEAD", mDead);
|
if (mDead) flags |= Dead;
|
||||||
|
if (mDeathAnimationFinished) flags |= DeathAnimationFinished;
|
||||||
|
if (mDied) flags |= Died;
|
||||||
|
if (mMurdered) flags |= Murdered;
|
||||||
|
if (mTalkedTo) flags |= TalkedTo;
|
||||||
|
if (mAlarmed) flags |= Alarmed;
|
||||||
|
if (mAttacked) flags |= Attacked;
|
||||||
|
if (mKnockdown) flags |= Knockdown;
|
||||||
|
if (mKnockdownOneFrame) flags |= KnockdownOneFrame;
|
||||||
|
if (mKnockdownOverOneFrame) flags |= KnockdownOverOneFrame;
|
||||||
|
if (mHitRecovery) flags |= HitRecovery;
|
||||||
|
if (mBlock) flags |= Block;
|
||||||
|
if (mRecalcDynamicStats) flags |= RecalcDynamicStats;
|
||||||
|
|
||||||
if (mDeathAnimationFinished)
|
if (flags)
|
||||||
esm.writeHNT ("DFNT", mDeathAnimationFinished);
|
esm.writeHNT ("AFLG", flags);
|
||||||
|
|
||||||
if (mDied)
|
|
||||||
esm.writeHNT ("DIED", mDied);
|
|
||||||
|
|
||||||
if (mMurdered)
|
|
||||||
esm.writeHNT ("MURD", mMurdered);
|
|
||||||
|
|
||||||
if (mTalkedTo)
|
|
||||||
esm.writeHNT ("TALK", mTalkedTo);
|
|
||||||
|
|
||||||
if (mAlarmed)
|
|
||||||
esm.writeHNT ("ALRM", mAlarmed);
|
|
||||||
|
|
||||||
if (mAttacked)
|
|
||||||
esm.writeHNT ("ATKD", mAttacked);
|
|
||||||
|
|
||||||
if (mKnockdown)
|
|
||||||
esm.writeHNT ("KNCK", mKnockdown);
|
|
||||||
|
|
||||||
if (mKnockdownOneFrame)
|
|
||||||
esm.writeHNT ("KNC1", mKnockdownOneFrame);
|
|
||||||
|
|
||||||
if (mKnockdownOverOneFrame)
|
|
||||||
esm.writeHNT ("KNCO", mKnockdownOverOneFrame);
|
|
||||||
|
|
||||||
if (mHitRecovery)
|
|
||||||
esm.writeHNT ("HITR", mHitRecovery);
|
|
||||||
|
|
||||||
if (mBlock)
|
|
||||||
esm.writeHNT ("BLCK", mBlock);
|
|
||||||
|
|
||||||
if (mMovementFlags)
|
if (mMovementFlags)
|
||||||
esm.writeHNT ("MOVE", mMovementFlags);
|
esm.writeHNT ("MOVE", mMovementFlags);
|
||||||
|
@ -195,9 +180,6 @@ void ESM::CreatureStats::save (ESMWriter &esm) const
|
||||||
if (!mLastHitAttemptObject.empty())
|
if (!mLastHitAttemptObject.empty())
|
||||||
esm.writeHNString ("LHAT", mLastHitAttemptObject);
|
esm.writeHNString ("LHAT", mLastHitAttemptObject);
|
||||||
|
|
||||||
if (mRecalcDynamicStats)
|
|
||||||
esm.writeHNT ("CALC", mRecalcDynamicStats);
|
|
||||||
|
|
||||||
if (mDrawState)
|
if (mDrawState)
|
||||||
esm.writeHNT ("DRAW", mDrawState);
|
esm.writeHNT ("DRAW", mDrawState);
|
||||||
|
|
||||||
|
@ -207,13 +189,10 @@ void ESM::CreatureStats::save (ESMWriter &esm) const
|
||||||
if (mActorId != -1)
|
if (mActorId != -1)
|
||||||
esm.writeHNT ("ACID", mActorId);
|
esm.writeHNT ("ACID", mActorId);
|
||||||
|
|
||||||
//if (mHitAttemptActorId != -1)
|
|
||||||
// esm.writeHNT("HAID", mHitAttemptActorId);
|
|
||||||
|
|
||||||
if (mDeathAnimation != -1)
|
if (mDeathAnimation != -1)
|
||||||
esm.writeHNT ("DANM", mDeathAnimation);
|
esm.writeHNT ("DANM", mDeathAnimation);
|
||||||
|
|
||||||
if (mTimeOfDeath.mHour != 0 && mTimeOfDeath.mDay != 0)
|
if (mTimeOfDeath.mHour != 0 || mTimeOfDeath.mDay != 0)
|
||||||
esm.writeHNT ("DTIM", mTimeOfDeath);
|
esm.writeHNT ("DTIM", mTimeOfDeath);
|
||||||
|
|
||||||
mSpells.save(esm);
|
mSpells.save(esm);
|
||||||
|
@ -247,7 +226,6 @@ void ESM::CreatureStats::blank()
|
||||||
mTradeTime.mDay = 0;
|
mTradeTime.mDay = 0;
|
||||||
mGoldPool = 0;
|
mGoldPool = 0;
|
||||||
mActorId = -1;
|
mActorId = -1;
|
||||||
//mHitAttemptActorId = -1;
|
|
||||||
mHasAiSettings = false;
|
mHasAiSettings = false;
|
||||||
mDead = false;
|
mDead = false;
|
||||||
mDeathAnimationFinished = false;
|
mDeathAnimationFinished = false;
|
||||||
|
|
|
@ -40,6 +40,22 @@ namespace ESM
|
||||||
int mActorId;
|
int mActorId;
|
||||||
//int mHitAttemptActorId;
|
//int mHitAttemptActorId;
|
||||||
|
|
||||||
|
enum Flags
|
||||||
|
{
|
||||||
|
Dead = 0x0001,
|
||||||
|
DeathAnimationFinished = 0x0002,
|
||||||
|
Died = 0x0004,
|
||||||
|
Murdered = 0x0008,
|
||||||
|
TalkedTo = 0x0010,
|
||||||
|
Alarmed = 0x0020,
|
||||||
|
Attacked = 0x0040,
|
||||||
|
Knockdown = 0x0080,
|
||||||
|
KnockdownOneFrame = 0x0100,
|
||||||
|
KnockdownOverOneFrame = 0x0200,
|
||||||
|
HitRecovery = 0x0400,
|
||||||
|
Block = 0x0800,
|
||||||
|
RecalcDynamicStats = 0x1000
|
||||||
|
};
|
||||||
bool mDead;
|
bool mDead;
|
||||||
bool mDeathAnimationFinished;
|
bool mDeathAnimationFinished;
|
||||||
bool mDied;
|
bool mDied;
|
||||||
|
|
|
@ -3,10 +3,60 @@
|
||||||
#include "esmreader.hpp"
|
#include "esmreader.hpp"
|
||||||
#include "esmwriter.hpp"
|
#include "esmwriter.hpp"
|
||||||
|
|
||||||
|
#include <osgDB/ReadFile>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
#include <components/files/memorystream.hpp>
|
||||||
|
|
||||||
|
#include "savedgame.hpp"
|
||||||
|
|
||||||
|
void convertFogOfWar(std::vector<char>& imageData)
|
||||||
|
{
|
||||||
|
if (imageData.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
osgDB::ReaderWriter* tgaReader = osgDB::Registry::instance()->getReaderWriterForExtension("tga");
|
||||||
|
if (!tgaReader)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Error: Unable to load fog, can't find a tga ReaderWriter";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Files::IMemStream in(&imageData[0], imageData.size());
|
||||||
|
|
||||||
|
osgDB::ReaderWriter::ReadResult result = tgaReader->readImage(in);
|
||||||
|
if (!result.success())
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Error: Failed to read fog: " << result.message() << " code " << result.status();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
osgDB::ReaderWriter* pngWriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
||||||
|
if (!pngWriter)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Error: Unable to write fog, can't find a png ReaderWriter";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream ostream;
|
||||||
|
osgDB::ReaderWriter::WriteResult png = pngWriter->writeImage(*result.getImage(), ostream);
|
||||||
|
if (!png.success())
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Error: Unable to write fog: " << png.message() << " code " << png.status();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string str = ostream.str();
|
||||||
|
imageData = std::vector<char>(str.begin(), str.end());
|
||||||
|
}
|
||||||
|
|
||||||
void ESM::FogState::load (ESMReader &esm)
|
void ESM::FogState::load (ESMReader &esm)
|
||||||
{
|
{
|
||||||
esm.getHNOT(mBounds, "BOUN");
|
esm.getHNOT(mBounds, "BOUN");
|
||||||
esm.getHNOT(mNorthMarkerAngle, "ANGL");
|
esm.getHNOT(mNorthMarkerAngle, "ANGL");
|
||||||
|
int dataFormat = esm.getFormat();
|
||||||
while (esm.isNextSub("FTEX"))
|
while (esm.isNextSub("FTEX"))
|
||||||
{
|
{
|
||||||
esm.getSubHeader();
|
esm.getSubHeader();
|
||||||
|
@ -18,6 +68,10 @@ void ESM::FogState::load (ESMReader &esm)
|
||||||
size_t imageSize = esm.getSubSize()-sizeof(int)*2;
|
size_t imageSize = esm.getSubSize()-sizeof(int)*2;
|
||||||
tex.mImageData.resize(imageSize);
|
tex.mImageData.resize(imageSize);
|
||||||
esm.getExact(&tex.mImageData[0], imageSize);
|
esm.getExact(&tex.mImageData[0], imageSize);
|
||||||
|
|
||||||
|
if (dataFormat < 7)
|
||||||
|
convertFogOfWar(tex.mImageData);
|
||||||
|
|
||||||
mFogTextures.push_back(tex);
|
mFogTextures.push_back(tex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,11 @@ void ESM::GlobalScript::load (ESMReader &esm)
|
||||||
mRunning = 0;
|
mRunning = 0;
|
||||||
esm.getHNOT (mRunning, "RUN_");
|
esm.getHNOT (mRunning, "RUN_");
|
||||||
|
|
||||||
mTargetId = esm.getHNOString ("TARG");
|
mTargetRef.unset();
|
||||||
|
if (esm.peekNextSub("TARG"))
|
||||||
|
mTargetId = esm.getHNString ("TARG");
|
||||||
|
if (esm.peekNextSub("FRMR"))
|
||||||
|
mTargetRef.load(esm, true, "FRMR");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESM::GlobalScript::save (ESMWriter &esm) const
|
void ESM::GlobalScript::save (ESMWriter &esm) const
|
||||||
|
@ -24,5 +28,10 @@ void ESM::GlobalScript::save (ESMWriter &esm) const
|
||||||
if (mRunning)
|
if (mRunning)
|
||||||
esm.writeHNT ("RUN_", mRunning);
|
esm.writeHNT ("RUN_", mRunning);
|
||||||
|
|
||||||
esm.writeHNOString ("TARG", mTargetId);
|
if (!mTargetId.empty())
|
||||||
|
{
|
||||||
|
esm.writeHNOString ("TARG", mTargetId);
|
||||||
|
if (mTargetRef.hasContentFile())
|
||||||
|
mTargetRef.save (esm, true, "FRMR");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define OPENMW_ESM_GLOBALSCRIPT_H
|
#define OPENMW_ESM_GLOBALSCRIPT_H
|
||||||
|
|
||||||
#include "locals.hpp"
|
#include "locals.hpp"
|
||||||
|
#include "cellref.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -16,6 +17,7 @@ namespace ESM
|
||||||
Locals mLocals;
|
Locals mLocals;
|
||||||
int mRunning;
|
int mRunning;
|
||||||
std::string mTargetId; // for targeted scripts
|
std::string mTargetId; // for targeted scripts
|
||||||
|
RefNum mTargetRef;
|
||||||
|
|
||||||
void load (ESMReader &esm);
|
void load (ESMReader &esm);
|
||||||
void save (ESMWriter &esm) const;
|
void save (ESMWriter &esm) const;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
void ESM::InventoryState::load (ESMReader &esm)
|
void ESM::InventoryState::load (ESMReader &esm)
|
||||||
{
|
{
|
||||||
|
// obsolete
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while (esm.isNextSub ("IOBJ"))
|
while (esm.isNextSub ("IOBJ"))
|
||||||
{
|
{
|
||||||
|
@ -31,6 +32,22 @@ void ESM::InventoryState::load (ESMReader &esm)
|
||||||
|
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int itemsCount = 0;
|
||||||
|
esm.getHNOT(itemsCount, "ICNT");
|
||||||
|
for (int i = 0; i < itemsCount; i++)
|
||||||
|
{
|
||||||
|
ObjectState state;
|
||||||
|
|
||||||
|
state.mRef.loadId(esm, true);
|
||||||
|
state.load (esm);
|
||||||
|
|
||||||
|
if (state.mCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mItems.push_back (state);
|
||||||
|
}
|
||||||
|
|
||||||
//Next item is Levelled item
|
//Next item is Levelled item
|
||||||
while (esm.isNextSub("LEVM"))
|
while (esm.isNextSub("LEVM"))
|
||||||
{
|
{
|
||||||
|
@ -72,18 +89,35 @@ void ESM::InventoryState::load (ESMReader &esm)
|
||||||
mEquipmentSlots[equipIndex] = slot;
|
mEquipmentSlots[equipIndex] = slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (esm.isNextSub("EQIP"))
|
||||||
|
{
|
||||||
|
esm.getSubHeader();
|
||||||
|
int slotsCount = 0;
|
||||||
|
esm.getT(slotsCount);
|
||||||
|
for (int i = 0; i < slotsCount; i++)
|
||||||
|
{
|
||||||
|
int equipIndex;
|
||||||
|
esm.getT(equipIndex);
|
||||||
|
int slot;
|
||||||
|
esm.getT(slot);
|
||||||
|
mEquipmentSlots[equipIndex] = slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mSelectedEnchantItem = -1;
|
mSelectedEnchantItem = -1;
|
||||||
esm.getHNOT(mSelectedEnchantItem, "SELE");
|
esm.getHNOT(mSelectedEnchantItem, "SELE");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESM::InventoryState::save (ESMWriter &esm) const
|
void ESM::InventoryState::save (ESMWriter &esm) const
|
||||||
{
|
{
|
||||||
for (std::vector<ObjectState>::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter)
|
int itemsCount = static_cast<int>(mItems.size());
|
||||||
|
if (itemsCount > 0)
|
||||||
{
|
{
|
||||||
int unused = 0;
|
esm.writeHNT ("ICNT", itemsCount);
|
||||||
esm.writeHNT ("IOBJ", unused);
|
for (const ObjectState& state : mItems)
|
||||||
|
{
|
||||||
iter->save (esm, true);
|
state.save (esm, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::map<std::pair<std::string, std::string>, int>::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it)
|
for (std::map<std::pair<std::string, std::string>, int>::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it)
|
||||||
|
@ -105,12 +139,17 @@ void ESM::InventoryState::save (ESMWriter &esm) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::map<int, int>::const_iterator it = mEquipmentSlots.begin(); it != mEquipmentSlots.end(); ++it)
|
int slotsCount = static_cast<int>(mEquipmentSlots.size());
|
||||||
|
if (slotsCount > 0)
|
||||||
{
|
{
|
||||||
esm.startSubRecord("EQUI");
|
esm.startSubRecord("EQIP");
|
||||||
esm.writeT(it->first);
|
esm.writeT(slotsCount);
|
||||||
esm.writeT(it->second);
|
for (std::map<int, int>::const_iterator it = mEquipmentSlots.begin(); it != mEquipmentSlots.end(); ++it)
|
||||||
esm.endRecord("EQUI");
|
{
|
||||||
|
esm.writeT(it->first);
|
||||||
|
esm.writeT(it->second);
|
||||||
|
}
|
||||||
|
esm.endRecord("EQIP");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSelectedEnchantItem != -1)
|
if (mSelectedEnchantItem != -1)
|
||||||
|
|
|
@ -210,13 +210,15 @@ namespace ESM
|
||||||
std::string Cell::getDescription() const
|
std::string Cell::getDescription() const
|
||||||
{
|
{
|
||||||
if (mData.mFlags & Interior)
|
if (mData.mFlags & Interior)
|
||||||
{
|
|
||||||
return mName;
|
return mName;
|
||||||
}
|
|
||||||
else
|
std::string cellGrid = "(" + std::to_string(mData.mX) + ", " + std::to_string(mData.mY) + ")";
|
||||||
{
|
if (!mName.empty())
|
||||||
return std::to_string(mData.mX) + ", " + std::to_string(mData.mY);
|
return mName + ' ' + cellGrid;
|
||||||
}
|
// FIXME: should use sDefaultCellname GMST instead, but it's not available in this scope
|
||||||
|
std::string region = !mRegion.empty() ? mRegion : "Wilderness";
|
||||||
|
|
||||||
|
return region + ' ' + cellGrid;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool &isDeleted, bool ignoreMoves, MovedCellRef *mref)
|
bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool &isDeleted, bool ignoreMoves, MovedCellRef *mref)
|
||||||
|
|
|
@ -35,7 +35,7 @@ void ESM::NpcStats::load (ESMReader &esm)
|
||||||
mSkills[i].load (esm);
|
mSkills[i].load (esm);
|
||||||
|
|
||||||
mWerewolfDeprecatedData = false;
|
mWerewolfDeprecatedData = false;
|
||||||
if (esm.peekNextSub("STBA"))
|
if (esm.getFormat() < 8 && esm.peekNextSub("STBA"))
|
||||||
{
|
{
|
||||||
// we have deprecated werewolf skills, stored interleaved
|
// we have deprecated werewolf skills, stored interleaved
|
||||||
// Load into one big vector, then remove every 2nd value
|
// Load into one big vector, then remove every 2nd value
|
||||||
|
@ -95,7 +95,9 @@ void ESM::NpcStats::load (ESMReader &esm)
|
||||||
mLevelProgress = 0;
|
mLevelProgress = 0;
|
||||||
esm.getHNOT (mLevelProgress, "LPRO");
|
esm.getHNOT (mLevelProgress, "LPRO");
|
||||||
|
|
||||||
esm.getHNT (mSkillIncrease, "INCR");
|
for (int i = 0; i < 8; ++i)
|
||||||
|
mSkillIncrease[i] = 0;
|
||||||
|
esm.getHNOT (mSkillIncrease, "INCR");
|
||||||
|
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
mSpecIncreases[i] = 0;
|
mSpecIncreases[i] = 0;
|
||||||
|
@ -160,8 +162,21 @@ void ESM::NpcStats::save (ESMWriter &esm) const
|
||||||
if (mLevelProgress)
|
if (mLevelProgress)
|
||||||
esm.writeHNT ("LPRO", mLevelProgress);
|
esm.writeHNT ("LPRO", mLevelProgress);
|
||||||
|
|
||||||
esm.writeHNT ("INCR", mSkillIncrease);
|
bool saveSkillIncreases = false;
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
if (mSkillIncrease[i] != 0)
|
||||||
|
{
|
||||||
|
saveSkillIncreases = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (saveSkillIncreases)
|
||||||
|
esm.writeHNT ("INCR", mSkillIncrease);
|
||||||
|
|
||||||
|
if (mSpecIncreases[0] != 0 ||
|
||||||
|
mSpecIncreases[1] != 0 ||
|
||||||
|
mSpecIncreases[2] != 0)
|
||||||
esm.writeHNT ("SPEC", mSpecIncreases);
|
esm.writeHNT ("SPEC", mSpecIncreases);
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator iter (mUsedIds.begin()); iter!=mUsedIds.end();
|
for (std::vector<std::string>::const_iterator iter (mUsedIds.begin()); iter!=mUsedIds.end();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
|
|
||||||
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
|
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
|
||||||
int ESM::SavedGame::sCurrentFormat = 5;
|
int ESM::SavedGame::sCurrentFormat = 8;
|
||||||
|
|
||||||
void ESM::SavedGame::load (ESMReader &esm)
|
void ESM::SavedGame::load (ESMReader &esm)
|
||||||
{
|
{
|
||||||
|
|
|
@ -125,8 +125,6 @@ namespace Interpreter
|
||||||
virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global)
|
virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global)
|
||||||
= 0;
|
= 0;
|
||||||
|
|
||||||
virtual std::string getTargetId() const = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace Interpreter
|
||||||
{
|
{
|
||||||
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
runtime.getContext().startScript (name, runtime.getContext().getTargetId());
|
runtime.getContext().startScript (name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -123,12 +123,10 @@ namespace Nif
|
||||||
{
|
{
|
||||||
Controller::read(nif);
|
Controller::read(nif);
|
||||||
|
|
||||||
/*
|
bankDir = nif->getInt();
|
||||||
int = 1
|
maxBankAngle = nif->getFloat();
|
||||||
2xfloat
|
smoothing = nif->getFloat();
|
||||||
short = 0 or 1
|
followAxis = nif->getShort();
|
||||||
*/
|
|
||||||
nif->skip(14);
|
|
||||||
posData.read(nif);
|
posData.read(nif);
|
||||||
floatData.read(nif);
|
floatData.read(nif);
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,20 @@ public:
|
||||||
NiPosDataPtr posData;
|
NiPosDataPtr posData;
|
||||||
NiFloatDataPtr floatData;
|
NiFloatDataPtr floatData;
|
||||||
|
|
||||||
|
enum Flags
|
||||||
|
{
|
||||||
|
Flag_OpenCurve = 0x020,
|
||||||
|
Flag_AllowFlip = 0x040,
|
||||||
|
Flag_Bank = 0x080,
|
||||||
|
Flag_ConstVelocity = 0x100,
|
||||||
|
Flag_Follow = 0x200,
|
||||||
|
Flag_FlipFollowAxis = 0x400
|
||||||
|
};
|
||||||
|
|
||||||
|
int bankDir;
|
||||||
|
float maxBankAngle, smoothing;
|
||||||
|
short followAxis;
|
||||||
|
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
void post(NIFFile *nif);
|
void post(NIFFile *nif);
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,7 +31,7 @@ void NiSkinInstance::post(NIFFile *nif)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeData::read(NIFStream *nif)
|
void NiGeometryData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
int verts = nif->getUShort();
|
int verts = nif->getUShort();
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ void ShapeData::read(NIFStream *nif)
|
||||||
|
|
||||||
void NiTriShapeData::read(NIFStream *nif)
|
void NiTriShapeData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
ShapeData::read(nif);
|
NiGeometryData::read(nif);
|
||||||
|
|
||||||
/*int tris =*/ nif->getUShort();
|
/*int tris =*/ nif->getUShort();
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ void NiTriShapeData::read(NIFStream *nif)
|
||||||
|
|
||||||
void NiTriStripsData::read(NIFStream *nif)
|
void NiTriStripsData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
ShapeData::read(nif);
|
NiGeometryData::read(nif);
|
||||||
|
|
||||||
// Every strip with n points defines n-2 triangles, so this should be unnecessary.
|
// Every strip with n points defines n-2 triangles, so this should be unnecessary.
|
||||||
/*int tris =*/ nif->getUShort();
|
/*int tris =*/ nif->getUShort();
|
||||||
|
@ -112,7 +112,7 @@ void NiTriStripsData::read(NIFStream *nif)
|
||||||
|
|
||||||
void NiAutoNormalParticlesData::read(NIFStream *nif)
|
void NiAutoNormalParticlesData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
ShapeData::read(nif);
|
NiGeometryData::read(nif);
|
||||||
|
|
||||||
// Should always match the number of vertices
|
// Should always match the number of vertices
|
||||||
numParticles = nif->getUShort();
|
numParticles = nif->getUShort();
|
||||||
|
@ -163,11 +163,8 @@ void NiPixelData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
fmt = (Format)nif->getUInt();
|
fmt = (Format)nif->getUInt();
|
||||||
|
|
||||||
rmask = nif->getUInt(); // usually 0xff
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
gmask = nif->getUInt(); // usually 0xff00
|
colorMask[i] = nif->getUInt();
|
||||||
bmask = nif->getUInt(); // usually 0xff0000
|
|
||||||
amask = nif->getUInt(); // usually 0xff000000 or zero
|
|
||||||
|
|
||||||
bpp = nif->getUInt();
|
bpp = nif->getUInt();
|
||||||
|
|
||||||
// 8 bytes of "Old Fast Compare". Whatever that means.
|
// 8 bytes of "Old Fast Compare". Whatever that means.
|
||||||
|
@ -190,10 +187,9 @@ void NiPixelData::read(NIFStream *nif)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the data
|
// Read the data
|
||||||
unsigned int dataSize = nif->getUInt();
|
unsigned int numPixels = nif->getUInt();
|
||||||
data.reserve(dataSize);
|
if (numPixels)
|
||||||
for (unsigned i=0; i<dataSize; ++i)
|
nif->getUChars(data, numPixels);
|
||||||
data.push_back((unsigned char)nif->getChar());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NiPixelData::post(NIFFile *nif)
|
void NiPixelData::post(NIFFile *nif)
|
||||||
|
@ -225,7 +221,7 @@ void NiSkinData::read(NIFStream *nif)
|
||||||
trafo.scale = nif->getFloat();
|
trafo.scale = nif->getFloat();
|
||||||
|
|
||||||
int boneNum = nif->getInt();
|
int boneNum = nif->getInt();
|
||||||
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW && nif->getVersion() <= NIFFile::NIFVersion::VER_GAMEBRYO)
|
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW && nif->getVersion() <= NIFStream::generateVersion(10,1,0,0))
|
||||||
nif->skip(4); // NiSkinPartition link
|
nif->skip(4); // NiSkinPartition link
|
||||||
|
|
||||||
bones.resize(boneNum);
|
bones.resize(boneNum);
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace Nif
|
||||||
{
|
{
|
||||||
|
|
||||||
// Common ancestor for several data classes
|
// Common ancestor for several data classes
|
||||||
class ShapeData : public Record
|
class NiGeometryData : public Record
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<osg::Vec3f> vertices, normals;
|
std::vector<osg::Vec3f> vertices, normals;
|
||||||
|
@ -44,7 +44,7 @@ public:
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
class NiTriShapeData : public ShapeData
|
class NiTriShapeData : public NiGeometryData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Triangles, three vertex indices per triangle
|
// Triangles, three vertex indices per triangle
|
||||||
|
@ -53,7 +53,7 @@ public:
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
class NiTriStripsData : public ShapeData
|
class NiTriStripsData : public NiGeometryData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Triangle strips, series of vertex indices.
|
// Triangle strips, series of vertex indices.
|
||||||
|
@ -62,7 +62,7 @@ public:
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
class NiAutoNormalParticlesData : public ShapeData
|
class NiAutoNormalParticlesData : public NiGeometryData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int numParticles;
|
int numParticles;
|
||||||
|
@ -124,7 +124,8 @@ public:
|
||||||
};
|
};
|
||||||
Format fmt;
|
Format fmt;
|
||||||
|
|
||||||
unsigned int rmask, gmask, bmask, amask, bpp;
|
unsigned int colorMask[4];
|
||||||
|
unsigned int bpp;
|
||||||
|
|
||||||
NiPalettePtr palette;
|
NiPalettePtr palette;
|
||||||
unsigned int numberOfMipmaps;
|
unsigned int numberOfMipmaps;
|
||||||
|
|
|
@ -144,7 +144,7 @@ void NIFFile::parse(Files::IStreamPtr stream)
|
||||||
ver = nif.getUInt();
|
ver = nif.getUInt();
|
||||||
// 4.0.0.0 is an older, practically identical version of the format.
|
// 4.0.0.0 is an older, practically identical version of the format.
|
||||||
// It's not used by Morrowind assets but Morrowind supports it.
|
// It's not used by Morrowind assets but Morrowind supports it.
|
||||||
if(ver != nif.generateVersion(4,0,0,0) && ver != VER_MW)
|
if(ver != NIFStream::generateVersion(4,0,0,0) && ver != VER_MW)
|
||||||
fail("Unsupported NIF version: " + printVersion(ver));
|
fail("Unsupported NIF version: " + printVersion(ver));
|
||||||
// Number of records
|
// Number of records
|
||||||
size_t recNum = nif.getInt();
|
size_t recNum = nif.getInt();
|
||||||
|
|
|
@ -79,11 +79,7 @@ public:
|
||||||
enum NIFVersion
|
enum NIFVersion
|
||||||
{
|
{
|
||||||
VER_MW = 0x04000002, // 4.0.0.2. Main Morrowind NIF version.
|
VER_MW = 0x04000002, // 4.0.0.2. Main Morrowind NIF version.
|
||||||
VER_CI = 0x04020200, // 4.2.2.0. Main Culpa Innata NIF version, also used in Civ4.
|
|
||||||
VER_ZT2 = 0x0A000100, // 10.0.1.0. Main Zoo Tycoon 2 NIF version, also used in Oblivion and Civ4.
|
|
||||||
VER_OB_OLD = 0x0A000102, // 10.0.1.2. Main older Oblivion NIF version.
|
VER_OB_OLD = 0x0A000102, // 10.0.1.2. Main older Oblivion NIF version.
|
||||||
VER_GAMEBRYO = 0x0A010000, // 10.1.0.0. Lots of games use it. The first version that has Gamebryo File Format header.
|
|
||||||
VER_CIV4 = 0x14000004, // 20.0.0.4. Main Civilization IV NIF version.
|
|
||||||
VER_OB = 0x14000005, // 20.0.0.5. Main Oblivion NIF version.
|
VER_OB = 0x14000005, // 20.0.0.5. Main Oblivion NIF version.
|
||||||
VER_BGS = 0x14020007 // 20.2.0.7. Main Fallout 3/4/76/New Vegas and Skyrim/SkyrimSE NIF version.
|
VER_BGS = 0x14020007 // 20.2.0.7. Main Fallout 3/4/76/New Vegas and Skyrim/SkyrimSE NIF version.
|
||||||
};
|
};
|
||||||
|
|
|
@ -200,6 +200,18 @@ public:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getChars(std::vector<char> &vec, size_t size)
|
||||||
|
{
|
||||||
|
vec.resize(size);
|
||||||
|
readLittleEndianDynamicBufferOfType<char,char>(inp, vec.data(), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getUChars(std::vector<unsigned char> &vec, size_t size)
|
||||||
|
{
|
||||||
|
vec.resize(size);
|
||||||
|
readLittleEndianDynamicBufferOfType<unsigned char,unsigned char>(inp, vec.data(), size);
|
||||||
|
}
|
||||||
|
|
||||||
void getUShorts(std::vector<unsigned short> &vec, size_t size)
|
void getUShorts(std::vector<unsigned short> &vec, size_t size)
|
||||||
{
|
{
|
||||||
vec.resize(size);
|
vec.resize(size);
|
||||||
|
|
|
@ -128,7 +128,12 @@ struct NiNode : Node
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NiTriShape : Node
|
struct NiGeometry : Node
|
||||||
|
{
|
||||||
|
NiSkinInstancePtr skin;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NiTriShape : NiGeometry
|
||||||
{
|
{
|
||||||
/* Possible flags:
|
/* Possible flags:
|
||||||
0x40 - mesh has no vertex normals ?
|
0x40 - mesh has no vertex normals ?
|
||||||
|
@ -138,7 +143,6 @@ struct NiTriShape : Node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NiTriShapeDataPtr data;
|
NiTriShapeDataPtr data;
|
||||||
NiSkinInstancePtr skin;
|
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
|
@ -157,10 +161,9 @@ struct NiTriShape : Node
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NiTriStrips : Node
|
struct NiTriStrips : NiGeometry
|
||||||
{
|
{
|
||||||
NiTriStripsDataPtr data;
|
NiTriStripsDataPtr data;
|
||||||
NiSkinInstancePtr skin;
|
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
|
@ -285,7 +288,7 @@ struct NiLODNode : public NiSwitchNode
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
NiSwitchNode::read(nif);
|
NiSwitchNode::read(nif);
|
||||||
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW && nif->getVersion() <= NIFFile::NIFVersion::VER_ZT2)
|
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW && nif->getVersion() <= NIFStream::generateVersion(10,0,1,0))
|
||||||
lodCenter = nif->getVector3();
|
lodCenter = nif->getVector3();
|
||||||
unsigned int numLodLevels = nif->getUInt();
|
unsigned int numLodLevels = nif->getUInt();
|
||||||
for (unsigned int i=0; i<numLodLevels; ++i)
|
for (unsigned int i=0; i<numLodLevels; ++i)
|
||||||
|
|
|
@ -132,23 +132,21 @@ osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::File& nif)
|
||||||
mStaticMesh.reset();
|
mStaticMesh.reset();
|
||||||
mAvoidStaticMesh.reset();
|
mAvoidStaticMesh.reset();
|
||||||
|
|
||||||
if (nif.numRoots() < 1)
|
Nif::Node* node = nullptr;
|
||||||
|
const size_t numRoots = nif.numRoots();
|
||||||
|
for (size_t i = 0; i < numRoots; ++i)
|
||||||
|
{
|
||||||
|
Nif::Record* r = nif.getRoot(i);
|
||||||
|
assert(r != nullptr);
|
||||||
|
if ((node = dynamic_cast<Nif::Node*>(r)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!node)
|
||||||
{
|
{
|
||||||
warn("Found no root nodes in NIF.");
|
warn("Found no root nodes in NIF.");
|
||||||
return mShape;
|
return mShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
Nif::Record *r = nif.getRoot(0);
|
|
||||||
assert(r != nullptr);
|
|
||||||
|
|
||||||
Nif::Node *node = dynamic_cast<Nif::Node*>(r);
|
|
||||||
if (node == nullptr)
|
|
||||||
{
|
|
||||||
warn("First root in file was not a node, but a " +
|
|
||||||
r->recName + ". Skipping file.");
|
|
||||||
return mShape;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (findBoundingBox(node))
|
if (findBoundingBox(node))
|
||||||
{
|
{
|
||||||
std::unique_ptr<btCompoundShape> compound (new btCompoundShape);
|
std::unique_ptr<btCompoundShape> compound (new btCompoundShape);
|
||||||
|
|
|
@ -521,4 +521,50 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv
|
||||||
traverse(node, nv);
|
traverse(node, nv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PathController::PathController(const PathController ©, const osg::CopyOp ©op)
|
||||||
|
: osg::NodeCallback(copy, copyop)
|
||||||
|
, Controller(copy)
|
||||||
|
, mPath(copy.mPath)
|
||||||
|
, mPercent(copy.mPercent)
|
||||||
|
, mFlags(copy.mFlags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PathController::PathController(const Nif::NiPathController* ctrl)
|
||||||
|
: mPath(ctrl->posData->mKeyList, osg::Vec3f())
|
||||||
|
, mPercent(ctrl->floatData->mKeyList, 1.f)
|
||||||
|
, mFlags(ctrl->flags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
float PathController::getPercent(float time) const
|
||||||
|
{
|
||||||
|
float percent = mPercent.interpKey(time);
|
||||||
|
if (percent < 0.f)
|
||||||
|
percent = std::fmod(percent, 1.f) + 1.f;
|
||||||
|
else if (percent > 1.f)
|
||||||
|
percent = std::fmod(percent, 1.f);
|
||||||
|
return percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathController::operator() (osg::Node* node, osg::NodeVisitor* nv)
|
||||||
|
{
|
||||||
|
if (mPath.empty() || mPercent.empty() || !hasInput())
|
||||||
|
{
|
||||||
|
traverse(node, nv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::MatrixTransform* trans = static_cast<osg::MatrixTransform*>(node);
|
||||||
|
osg::Matrix mat = trans->getMatrix();
|
||||||
|
|
||||||
|
float time = getInputValue(nv);
|
||||||
|
float percent = getPercent(time);
|
||||||
|
osg::Vec3f pos(mPath.interpKey(percent));
|
||||||
|
mat.setTrans(pos);
|
||||||
|
trans->setMatrix(mat);
|
||||||
|
|
||||||
|
traverse(node, nv);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -342,6 +342,25 @@ namespace NifOsg
|
||||||
float mEmitStop;
|
float mEmitStop;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PathController : public osg::NodeCallback, public SceneUtil::Controller
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PathController(const Nif::NiPathController* ctrl);
|
||||||
|
PathController() = default;
|
||||||
|
PathController(const PathController& copy, const osg::CopyOp& copyop);
|
||||||
|
|
||||||
|
META_Object(NifOsg, PathController)
|
||||||
|
|
||||||
|
virtual void operator() (osg::Node*, osg::NodeVisitor*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vec3Interpolator mPath;
|
||||||
|
FloatInterpolator mPercent;
|
||||||
|
int mFlags{0};
|
||||||
|
|
||||||
|
float getPercent(float time) const;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -247,22 +247,24 @@ namespace NifOsg
|
||||||
|
|
||||||
static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target)
|
static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target)
|
||||||
{
|
{
|
||||||
if(nif->numRoots() < 1)
|
const Nif::NiSequenceStreamHelper *seq = nullptr;
|
||||||
|
const size_t numRoots = nif->numRoots();
|
||||||
|
for (size_t i = 0; i < numRoots; ++i)
|
||||||
{
|
{
|
||||||
nif->warn("Found no root nodes");
|
const Nif::Record *r = nif->getRoot(i);
|
||||||
return;
|
assert(r != nullptr);
|
||||||
|
if (r->recType == Nif::RC_NiSequenceStreamHelper)
|
||||||
|
{
|
||||||
|
seq = static_cast<const Nif::NiSequenceStreamHelper*>(r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Nif::Record *r = nif->getRoot(0);
|
if (!seq)
|
||||||
assert(r != nullptr);
|
|
||||||
|
|
||||||
if(r->recType != Nif::RC_NiSequenceStreamHelper)
|
|
||||||
{
|
{
|
||||||
nif->warn("First root was not a NiSequenceStreamHelper, but a "+
|
nif->warn("Found no NiSequenceStreamHelper root record");
|
||||||
r->recName+".");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const Nif::NiSequenceStreamHelper *seq = static_cast<const Nif::NiSequenceStreamHelper*>(r);
|
|
||||||
|
|
||||||
Nif::ExtraPtr extra = seq->extra;
|
Nif::ExtraPtr extra = seq->extra;
|
||||||
if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData)
|
if(extra.empty() || extra->recType != Nif::RC_NiTextKeyExtraData)
|
||||||
|
@ -303,15 +305,17 @@ namespace NifOsg
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> load(Nif::NIFFilePtr nif, Resource::ImageManager* imageManager)
|
osg::ref_ptr<osg::Node> load(Nif::NIFFilePtr nif, Resource::ImageManager* imageManager)
|
||||||
{
|
{
|
||||||
if (nif->numRoots() < 1)
|
const Nif::Node* nifNode = nullptr;
|
||||||
|
const size_t numRoots = nif->numRoots();
|
||||||
|
for (size_t i = 0; i < numRoots; ++i)
|
||||||
|
{
|
||||||
|
const Nif::Record* r = nif->getRoot(i);
|
||||||
|
if ((nifNode = dynamic_cast<const Nif::Node*>(r)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!nifNode)
|
||||||
nif->fail("Found no root nodes");
|
nif->fail("Found no root nodes");
|
||||||
|
|
||||||
const Nif::Record* r = nif->getRoot(0);
|
|
||||||
|
|
||||||
const Nif::Node* nifNode = dynamic_cast<const Nif::Node*>(r);
|
|
||||||
if (nifNode == nullptr)
|
|
||||||
nif->fail("First root was not a node, but a " + r->recName);
|
|
||||||
|
|
||||||
osg::ref_ptr<TextKeyMapHolder> textkeys (new TextKeyMapHolder);
|
osg::ref_ptr<TextKeyMapHolder> textkeys (new TextKeyMapHolder);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> created = handleNode(nifNode, nullptr, imageManager, std::vector<unsigned int>(), 0, false, false, false, &textkeys->mTextKeys);
|
osg::ref_ptr<osg::Node> created = handleNode(nifNode, nullptr, imageManager, std::vector<unsigned int>(), 0, false, false, false, &textkeys->mTextKeys);
|
||||||
|
@ -612,7 +616,7 @@ namespace NifOsg
|
||||||
bool hasVisController = false;
|
bool hasVisController = false;
|
||||||
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
|
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
|
||||||
{
|
{
|
||||||
if (hasVisController |= (ctrl->recType == Nif::RC_NiVisController))
|
if ((hasVisController |= (ctrl->recType == Nif::RC_NiVisController)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,11 +649,7 @@ namespace NifOsg
|
||||||
const bool isMarker = hasMarkers && !nodeName.compare(0, markerName.size(), markerName);
|
const bool isMarker = hasMarkers && !nodeName.compare(0, markerName.size(), markerName);
|
||||||
if (!isMarker && nodeName.compare(0, shadowName.size(), shadowName) && nodeName.compare(0, shadowName2.size(), shadowName2))
|
if (!isMarker && nodeName.compare(0, shadowName.size(), shadowName) && nodeName.compare(0, shadowName2.size(), shadowName2))
|
||||||
{
|
{
|
||||||
Nif::NiSkinInstancePtr skin;
|
Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin;
|
||||||
if (nifNode->recType == Nif::RC_NiTriShape)
|
|
||||||
skin = static_cast<const Nif::NiTriShape*>(nifNode)->skin;
|
|
||||||
else // if (nifNode->recType == Nif::RC_NiTriStrips)
|
|
||||||
skin = static_cast<const Nif::NiTriStrips*>(nifNode)->skin;
|
|
||||||
|
|
||||||
if (skin.empty())
|
if (skin.empty())
|
||||||
handleTriShape(nifNode, node, composite, boundTextures, animflags);
|
handleTriShape(nifNode, node, composite, boundTextures, animflags);
|
||||||
|
@ -752,6 +752,17 @@ namespace NifOsg
|
||||||
node->addUpdateCallback(callback);
|
node->addUpdateCallback(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (ctrl->recType == Nif::RC_NiPathController)
|
||||||
|
{
|
||||||
|
const Nif::NiPathController *path = static_cast<const Nif::NiPathController*>(ctrl.getPtr());
|
||||||
|
if (!path->posData.empty() && !path->floatData.empty())
|
||||||
|
{
|
||||||
|
osg::ref_ptr<PathController> callback(new PathController(path));
|
||||||
|
|
||||||
|
setupController(path, callback, animflags);
|
||||||
|
node->addUpdateCallback(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (ctrl->recType == Nif::RC_NiVisController)
|
else if (ctrl->recType == Nif::RC_NiVisController)
|
||||||
{
|
{
|
||||||
handleVisController(static_cast<const Nif::NiVisController*>(ctrl.getPtr()), node, animflags);
|
handleVisController(static_cast<const Nif::NiVisController*>(ctrl.getPtr()), node, animflags);
|
||||||
|
@ -780,6 +791,17 @@ namespace NifOsg
|
||||||
transformNode->addUpdateCallback(callback);
|
transformNode->addUpdateCallback(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (ctrl->recType == Nif::RC_NiPathController)
|
||||||
|
{
|
||||||
|
const Nif::NiPathController *path = static_cast<const Nif::NiPathController*>(ctrl.getPtr());
|
||||||
|
if (!path->posData.empty() && !path->floatData.empty())
|
||||||
|
{
|
||||||
|
osg::ref_ptr<PathController> callback(new PathController(path));
|
||||||
|
|
||||||
|
setupController(path, callback, animflags);
|
||||||
|
transformNode->addUpdateCallback(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (ctrl->recType == Nif::RC_NiVisController)
|
else if (ctrl->recType == Nif::RC_NiVisController)
|
||||||
{
|
{
|
||||||
handleVisController(static_cast<const Nif::NiVisController*>(ctrl.getPtr()), transformNode, animflags);
|
handleVisController(static_cast<const Nif::NiVisController*>(ctrl.getPtr()), transformNode, animflags);
|
||||||
|
@ -1268,12 +1290,7 @@ namespace NifOsg
|
||||||
// Assign bone weights
|
// Assign bone weights
|
||||||
osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> map (new SceneUtil::RigGeometry::InfluenceMap);
|
osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> map (new SceneUtil::RigGeometry::InfluenceMap);
|
||||||
|
|
||||||
Nif::NiSkinInstancePtr skinPtr;
|
const Nif::NiSkinInstance *skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin.getPtr();
|
||||||
if (nifNode->recType == Nif::RC_NiTriShape)
|
|
||||||
skinPtr = static_cast<const Nif::NiTriShape*>(nifNode)->skin;
|
|
||||||
else
|
|
||||||
skinPtr = static_cast<const Nif::NiTriStrips*>(nifNode)->skin;
|
|
||||||
const Nif::NiSkinInstance *skin = skinPtr.getPtr();
|
|
||||||
const Nif::NiSkinData *data = skin->data.getPtr();
|
const Nif::NiSkinData *data = skin->data.getPtr();
|
||||||
const Nif::NodeList &bones = skin->bones;
|
const Nif::NodeList &bones = skin->bones;
|
||||||
for(size_t i = 0;i < bones.length();i++)
|
for(size_t i = 0;i < bones.length();i++)
|
||||||
|
|
|
@ -45,23 +45,24 @@ namespace SceneUtil
|
||||||
|
|
||||||
virtual void apply(osg::Drawable& drawable)
|
virtual void apply(osg::Drawable& drawable)
|
||||||
{
|
{
|
||||||
std::string lowerName = Misc::StringUtils::lowerCase(drawable.getName());
|
if (!filterMatches(drawable.getName()))
|
||||||
if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0)
|
return;
|
||||||
|| (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0))
|
|
||||||
|
osg::Node* node = &drawable;
|
||||||
|
while (node->getNumParents())
|
||||||
{
|
{
|
||||||
osg::Node* node = &drawable;
|
osg::Group* parent = node->getParent(0);
|
||||||
while (node && node->getNumParents() && !node->getStateSet())
|
if (!parent || !filterMatches(parent->getName()))
|
||||||
node = node->getParent(0);
|
break;
|
||||||
if (node)
|
node = parent;
|
||||||
mToCopy.push_back(node);
|
|
||||||
}
|
}
|
||||||
|
mToCopy.emplace(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void doCopy()
|
void doCopy()
|
||||||
{
|
{
|
||||||
for (std::vector<osg::ref_ptr<osg::Node> >::iterator it = mToCopy.begin(); it != mToCopy.end(); ++it)
|
for (const osg::ref_ptr<osg::Node>& node : mToCopy)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Node> node = *it;
|
|
||||||
if (node->getNumParents() > 1)
|
if (node->getNumParents() > 1)
|
||||||
Log(Debug::Error) << "Error CopyRigVisitor: node has multiple parents";
|
Log(Debug::Error) << "Error CopyRigVisitor: node has multiple parents";
|
||||||
while (node->getNumParents())
|
while (node->getNumParents())
|
||||||
|
@ -73,8 +74,16 @@ namespace SceneUtil
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::vector<osg::ref_ptr<osg::Node> > NodeVector;
|
|
||||||
NodeVector mToCopy;
|
bool filterMatches(const std::string& name) const
|
||||||
|
{
|
||||||
|
std::string lowerName = Misc::StringUtils::lowerCase(name);
|
||||||
|
return (lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0)
|
||||||
|
|| (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
using NodeSet = std::set<osg::ref_ptr<osg::Node>>;
|
||||||
|
NodeSet mToCopy;
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> mParent;
|
osg::ref_ptr<osg::Group> mParent;
|
||||||
std::string mFilter;
|
std::string mFilter;
|
||||||
|
|
|
@ -1,159 +0,0 @@
|
||||||
#ifndef OIS_SDL_COMPAT_H
|
|
||||||
#define OIS_SDL_COMPAT_H
|
|
||||||
|
|
||||||
#include <SDL_events.h>
|
|
||||||
#include <SDL_types.h>
|
|
||||||
|
|
||||||
namespace OIS
|
|
||||||
{
|
|
||||||
//! Keyboard scan codes
|
|
||||||
enum KeyCode
|
|
||||||
{
|
|
||||||
KC_UNASSIGNED = 0x00,
|
|
||||||
KC_ESCAPE = 0x01,
|
|
||||||
KC_1 = 0x02,
|
|
||||||
KC_2 = 0x03,
|
|
||||||
KC_3 = 0x04,
|
|
||||||
KC_4 = 0x05,
|
|
||||||
KC_5 = 0x06,
|
|
||||||
KC_6 = 0x07,
|
|
||||||
KC_7 = 0x08,
|
|
||||||
KC_8 = 0x09,
|
|
||||||
KC_9 = 0x0A,
|
|
||||||
KC_0 = 0x0B,
|
|
||||||
KC_MINUS = 0x0C, // - on main keyboard
|
|
||||||
KC_EQUALS = 0x0D,
|
|
||||||
KC_BACK = 0x0E, // backspace
|
|
||||||
KC_TAB = 0x0F,
|
|
||||||
KC_Q = 0x10,
|
|
||||||
KC_W = 0x11,
|
|
||||||
KC_E = 0x12,
|
|
||||||
KC_R = 0x13,
|
|
||||||
KC_T = 0x14,
|
|
||||||
KC_Y = 0x15,
|
|
||||||
KC_U = 0x16,
|
|
||||||
KC_I = 0x17,
|
|
||||||
KC_O = 0x18,
|
|
||||||
KC_P = 0x19,
|
|
||||||
KC_LBRACKET = 0x1A,
|
|
||||||
KC_RBRACKET = 0x1B,
|
|
||||||
KC_RETURN = 0x1C, // Enter on main keyboard
|
|
||||||
KC_LCONTROL = 0x1D,
|
|
||||||
KC_A = 0x1E,
|
|
||||||
KC_S = 0x1F,
|
|
||||||
KC_D = 0x20,
|
|
||||||
KC_F = 0x21,
|
|
||||||
KC_G = 0x22,
|
|
||||||
KC_H = 0x23,
|
|
||||||
KC_J = 0x24,
|
|
||||||
KC_K = 0x25,
|
|
||||||
KC_L = 0x26,
|
|
||||||
KC_SEMICOLON = 0x27,
|
|
||||||
KC_APOSTROPHE = 0x28,
|
|
||||||
KC_GRAVE = 0x29, // accent
|
|
||||||
KC_LSHIFT = 0x2A,
|
|
||||||
KC_BACKSLASH = 0x2B,
|
|
||||||
KC_Z = 0x2C,
|
|
||||||
KC_X = 0x2D,
|
|
||||||
KC_C = 0x2E,
|
|
||||||
KC_V = 0x2F,
|
|
||||||
KC_B = 0x30,
|
|
||||||
KC_N = 0x31,
|
|
||||||
KC_M = 0x32,
|
|
||||||
KC_COMMA = 0x33,
|
|
||||||
KC_PERIOD = 0x34, // . on main keyboard
|
|
||||||
KC_SLASH = 0x35, // / on main keyboard
|
|
||||||
KC_RSHIFT = 0x36,
|
|
||||||
KC_MULTIPLY = 0x37, // * on numeric keypad
|
|
||||||
KC_LMENU = 0x38, // left Alt
|
|
||||||
KC_SPACE = 0x39,
|
|
||||||
KC_CAPITAL = 0x3A,
|
|
||||||
KC_F1 = 0x3B,
|
|
||||||
KC_F2 = 0x3C,
|
|
||||||
KC_F3 = 0x3D,
|
|
||||||
KC_F4 = 0x3E,
|
|
||||||
KC_F5 = 0x3F,
|
|
||||||
KC_F6 = 0x40,
|
|
||||||
KC_F7 = 0x41,
|
|
||||||
KC_F8 = 0x42,
|
|
||||||
KC_F9 = 0x43,
|
|
||||||
KC_F10 = 0x44,
|
|
||||||
KC_NUMLOCK = 0x45,
|
|
||||||
KC_SCROLL = 0x46, // Scroll Lock
|
|
||||||
KC_NUMPAD7 = 0x47,
|
|
||||||
KC_NUMPAD8 = 0x48,
|
|
||||||
KC_NUMPAD9 = 0x49,
|
|
||||||
KC_SUBTRACT = 0x4A, // - on numeric keypad
|
|
||||||
KC_NUMPAD4 = 0x4B,
|
|
||||||
KC_NUMPAD5 = 0x4C,
|
|
||||||
KC_NUMPAD6 = 0x4D,
|
|
||||||
KC_ADD = 0x4E, // + on numeric keypad
|
|
||||||
KC_NUMPAD1 = 0x4F,
|
|
||||||
KC_NUMPAD2 = 0x50,
|
|
||||||
KC_NUMPAD3 = 0x51,
|
|
||||||
KC_NUMPAD0 = 0x52,
|
|
||||||
KC_DECIMAL = 0x53, // . on numeric keypad
|
|
||||||
KC_OEM_102 = 0x56, // < > | on UK/Germany keyboards
|
|
||||||
KC_F11 = 0x57,
|
|
||||||
KC_F12 = 0x58,
|
|
||||||
KC_F13 = 0x64, // (NEC PC98)
|
|
||||||
KC_F14 = 0x65, // (NEC PC98)
|
|
||||||
KC_F15 = 0x66, // (NEC PC98)
|
|
||||||
KC_KANA = 0x70, // (Japanese keyboard)
|
|
||||||
KC_ABNT_C1 = 0x73, // / ? on Portugese (Brazilian) keyboards
|
|
||||||
KC_CONVERT = 0x79, // (Japanese keyboard)
|
|
||||||
KC_NOCONVERT = 0x7B, // (Japanese keyboard)
|
|
||||||
KC_YEN = 0x7D, // (Japanese keyboard)
|
|
||||||
KC_ABNT_C2 = 0x7E, // Numpad . on Portugese (Brazilian) keyboards
|
|
||||||
KC_NUMPADEQUALS= 0x8D, // = on numeric keypad (NEC PC98)
|
|
||||||
KC_PREVTRACK = 0x90, // Previous Track (KC_CIRCUMFLEX on Japanese keyboard)
|
|
||||||
KC_AT = 0x91, // (NEC PC98)
|
|
||||||
KC_COLON = 0x92, // (NEC PC98)
|
|
||||||
KC_UNDERLINE = 0x93, // (NEC PC98)
|
|
||||||
KC_KANJI = 0x94, // (Japanese keyboard)
|
|
||||||
KC_STOP = 0x95, // (NEC PC98)
|
|
||||||
KC_AX = 0x96, // (Japan AX)
|
|
||||||
KC_UNLABELED = 0x97, // (J3100)
|
|
||||||
KC_NEXTTRACK = 0x99, // Next Track
|
|
||||||
KC_NUMPADENTER = 0x9C, // Enter on numeric keypad
|
|
||||||
KC_RCONTROL = 0x9D,
|
|
||||||
KC_MUTE = 0xA0, // Mute
|
|
||||||
KC_CALCULATOR = 0xA1, // Calculator
|
|
||||||
KC_PLAYPAUSE = 0xA2, // Play / Pause
|
|
||||||
KC_MEDIASTOP = 0xA4, // Media Stop
|
|
||||||
KC_VOLUMEDOWN = 0xAE, // Volume -
|
|
||||||
KC_VOLUMEUP = 0xB0, // Volume +
|
|
||||||
KC_WEBHOME = 0xB2, // Web home
|
|
||||||
KC_NUMPADCOMMA = 0xB3, // , on numeric keypad (NEC PC98)
|
|
||||||
KC_DIVIDE = 0xB5, // / on numeric keypad
|
|
||||||
KC_SYSRQ = 0xB7,
|
|
||||||
KC_RMENU = 0xB8, // right Alt
|
|
||||||
KC_PAUSE = 0xC5, // Pause
|
|
||||||
KC_HOME = 0xC7, // Home on arrow keypad
|
|
||||||
KC_UP = 0xC8, // UpArrow on arrow keypad
|
|
||||||
KC_PGUP = 0xC9, // PgUp on arrow keypad
|
|
||||||
KC_LEFT = 0xCB, // LeftArrow on arrow keypad
|
|
||||||
KC_RIGHT = 0xCD, // RightArrow on arrow keypad
|
|
||||||
KC_END = 0xCF, // End on arrow keypad
|
|
||||||
KC_DOWN = 0xD0, // DownArrow on arrow keypad
|
|
||||||
KC_PGDOWN = 0xD1, // PgDn on arrow keypad
|
|
||||||
KC_INSERT = 0xD2, // Insert on arrow keypad
|
|
||||||
KC_DELETE = 0xD3, // Delete on arrow keypad
|
|
||||||
KC_LWIN = 0xDB, // Left Windows key
|
|
||||||
KC_RWIN = 0xDC, // Right Windows key
|
|
||||||
KC_APPS = 0xDD, // AppMenu key
|
|
||||||
KC_POWER = 0xDE, // System Power
|
|
||||||
KC_SLEEP = 0xDF, // System Sleep
|
|
||||||
KC_WAKE = 0xE3, // System Wake
|
|
||||||
KC_WEBSEARCH = 0xE5, // Web Search
|
|
||||||
KC_WEBFAVORITES= 0xE6, // Web Favorites
|
|
||||||
KC_WEBREFRESH = 0xE7, // Web Refresh
|
|
||||||
KC_WEBSTOP = 0xE8, // Web Stop
|
|
||||||
KC_WEBFORWARD = 0xE9, // Web Forward
|
|
||||||
KC_WEBBACK = 0xEA, // Web Back
|
|
||||||
KC_MYCOMPUTER = 0xEB, // My Computer
|
|
||||||
KC_MAIL = 0xEC, // Mail
|
|
||||||
KC_MEDIASELECT = 0xED // Media Select
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -79,9 +79,6 @@ public:
|
||||||
/** @remarks The window's visibility changed */
|
/** @remarks The window's visibility changed */
|
||||||
virtual void windowVisibilityChange( bool visible ) {}
|
virtual void windowVisibilityChange( bool visible ) {}
|
||||||
|
|
||||||
/** @remarks The window got / lost input focus */
|
|
||||||
virtual void windowFocusChange( bool have_focus ) {}
|
|
||||||
|
|
||||||
virtual void windowClosed () {}
|
virtual void windowClosed () {}
|
||||||
|
|
||||||
virtual void windowResized (int x, int y) {}
|
virtual void windowResized (int x, int y) {}
|
||||||
|
|
|
@ -33,8 +33,6 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> v
|
||||||
mWindowHasFocus(true),
|
mWindowHasFocus(true),
|
||||||
mMouseInWindow(true)
|
mMouseInWindow(true)
|
||||||
{
|
{
|
||||||
_setupOISKeys();
|
|
||||||
|
|
||||||
Uint32 flags = SDL_GetWindowFlags(mSDLWindow);
|
Uint32 flags = SDL_GetWindowFlags(mSDLWindow);
|
||||||
mWindowHasFocus = (flags & SDL_WINDOW_INPUT_FOCUS);
|
mWindowHasFocus = (flags & SDL_WINDOW_INPUT_FOCUS);
|
||||||
mMouseInWindow = (flags & SDL_WINDOW_MOUSE_FOCUS);
|
mMouseInWindow = (flags & SDL_WINDOW_MOUSE_FOCUS);
|
||||||
|
@ -231,15 +229,10 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> v
|
||||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||||
mWindowHasFocus = true;
|
mWindowHasFocus = true;
|
||||||
updateMouseSettings();
|
updateMouseSettings();
|
||||||
if (mWindowListener)
|
|
||||||
mWindowListener->windowFocusChange(true);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||||
mWindowHasFocus = false;
|
mWindowHasFocus = false;
|
||||||
updateMouseSettings();
|
updateMouseSettings();
|
||||||
if (mWindowListener)
|
|
||||||
mWindowListener->windowFocusChange(false);
|
|
||||||
break;
|
break;
|
||||||
case SDL_WINDOWEVENT_CLOSE:
|
case SDL_WINDOWEVENT_CLOSE:
|
||||||
break;
|
break;
|
||||||
|
@ -402,139 +395,4 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> v
|
||||||
|
|
||||||
return pack_evt;
|
return pack_evt;
|
||||||
}
|
}
|
||||||
|
|
||||||
OIS::KeyCode InputWrapper::sdl2OISKeyCode(SDL_Keycode code)
|
|
||||||
{
|
|
||||||
OIS::KeyCode kc = OIS::KC_UNASSIGNED;
|
|
||||||
|
|
||||||
KeyMap::const_iterator ois_equiv = mKeyMap.find(code);
|
|
||||||
|
|
||||||
if(ois_equiv != mKeyMap.end())
|
|
||||||
kc = ois_equiv->second;
|
|
||||||
|
|
||||||
return kc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputWrapper::_setupOISKeys()
|
|
||||||
{
|
|
||||||
//lifted from OIS's SDLKeyboard.cpp
|
|
||||||
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_UNKNOWN, OIS::KC_UNASSIGNED));
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_ESCAPE, OIS::KC_ESCAPE) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_1, OIS::KC_1) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_2, OIS::KC_2) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_3, OIS::KC_3) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_4, OIS::KC_4) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_5, OIS::KC_5) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_6, OIS::KC_6) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_7, OIS::KC_7) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_8, OIS::KC_8) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_9, OIS::KC_9) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_0, OIS::KC_0) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_MINUS, OIS::KC_MINUS) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_EQUALS, OIS::KC_EQUALS) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_BACKSPACE, OIS::KC_BACK) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_TAB, OIS::KC_TAB) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_q, OIS::KC_Q) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_w, OIS::KC_W) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_e, OIS::KC_E) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_r, OIS::KC_R) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_t, OIS::KC_T) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_y, OIS::KC_Y) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_u, OIS::KC_U) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_i, OIS::KC_I) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_o, OIS::KC_O) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_p, OIS::KC_P) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_RETURN, OIS::KC_RETURN) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_a, OIS::KC_A) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_s, OIS::KC_S) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_d, OIS::KC_D) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_f, OIS::KC_F) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_g, OIS::KC_G) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_h, OIS::KC_H) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_j, OIS::KC_J) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_k, OIS::KC_K) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_l, OIS::KC_L) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_SEMICOLON, OIS::KC_SEMICOLON) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_COLON, OIS::KC_COLON) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_QUOTE, OIS::KC_APOSTROPHE) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_BACKQUOTE, OIS::KC_GRAVE) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_LSHIFT, OIS::KC_LSHIFT) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_BACKSLASH, OIS::KC_BACKSLASH) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_SLASH, OIS::KC_SLASH) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_z, OIS::KC_Z) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_x, OIS::KC_X) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_c, OIS::KC_C) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_v, OIS::KC_V) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_b, OIS::KC_B) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_n, OIS::KC_N) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_m, OIS::KC_M) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_COMMA, OIS::KC_COMMA) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_PERIOD, OIS::KC_PERIOD));
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_RSHIFT, OIS::KC_RSHIFT));
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_MULTIPLY, OIS::KC_MULTIPLY) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_LALT, OIS::KC_LMENU) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_SPACE, OIS::KC_SPACE));
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_CAPSLOCK, OIS::KC_CAPITAL) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F1, OIS::KC_F1) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F2, OIS::KC_F2) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F3, OIS::KC_F3) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F4, OIS::KC_F4) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F5, OIS::KC_F5) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F6, OIS::KC_F6) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F7, OIS::KC_F7) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F8, OIS::KC_F8) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F9, OIS::KC_F9) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F10, OIS::KC_F10) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_NUMLOCKCLEAR, OIS::KC_NUMLOCK) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_SCROLLLOCK, OIS::KC_SCROLL));
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_7, OIS::KC_NUMPAD7) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_8, OIS::KC_NUMPAD8) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_9, OIS::KC_NUMPAD9) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_MINUS, OIS::KC_SUBTRACT) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_4, OIS::KC_NUMPAD4) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_5, OIS::KC_NUMPAD5) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_6, OIS::KC_NUMPAD6) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_PLUS, OIS::KC_ADD) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_1, OIS::KC_NUMPAD1) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_2, OIS::KC_NUMPAD2) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_3, OIS::KC_NUMPAD3) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_0, OIS::KC_NUMPAD0) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_PERIOD, OIS::KC_DECIMAL) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F11, OIS::KC_F11) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F12, OIS::KC_F12) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F13, OIS::KC_F13) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F14, OIS::KC_F14) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_F15, OIS::KC_F15) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_EQUALS, OIS::KC_NUMPADEQUALS) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_DIVIDE, OIS::KC_DIVIDE) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_SYSREQ, OIS::KC_SYSRQ) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_RALT, OIS::KC_RMENU) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_HOME, OIS::KC_HOME) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_UP, OIS::KC_UP) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_PAGEUP, OIS::KC_PGUP) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_LEFT, OIS::KC_LEFT) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_RIGHT, OIS::KC_RIGHT) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_END, OIS::KC_END) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_DOWN, OIS::KC_DOWN) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_PAGEDOWN, OIS::KC_PGDOWN) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_INSERT, OIS::KC_INSERT) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_DELETE, OIS::KC_DELETE) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_KP_ENTER, OIS::KC_NUMPADENTER) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_APPLICATION, OIS::KC_APPS) );
|
|
||||||
|
|
||||||
//The function of the Ctrl and Meta keys are switched on macOS compared to other platforms.
|
|
||||||
//For instance, Cmd+C versus Ctrl+C to copy from the system clipboard
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_LGUI, OIS::KC_LCONTROL) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_RGUI, OIS::KC_RCONTROL) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LWIN));
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_RCTRL, OIS::KC_RWIN) );
|
|
||||||
#else
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_LGUI, OIS::KC_LWIN) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_RGUI, OIS::KC_RWIN) );
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LCONTROL));
|
|
||||||
mKeyMap.insert( KeyMap::value_type(SDLK_RCTRL, OIS::KC_RCONTROL) );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include <SDL_events.h>
|
#include <SDL_events.h>
|
||||||
#include <SDL_version.h>
|
#include <SDL_version.h>
|
||||||
|
|
||||||
#include "OISCompat.hpp"
|
|
||||||
#include "events.hpp"
|
#include "events.hpp"
|
||||||
|
|
||||||
namespace osgViewer
|
namespace osgViewer
|
||||||
|
@ -40,8 +39,6 @@ namespace SDLUtil
|
||||||
bool getMouseRelative() { return mMouseRelative; }
|
bool getMouseRelative() { return mMouseRelative; }
|
||||||
void setGrabPointer(bool grab);
|
void setGrabPointer(bool grab);
|
||||||
|
|
||||||
OIS::KeyCode sdl2OISKeyCode(SDL_Keycode code);
|
|
||||||
|
|
||||||
void warpMouse(int x, int y);
|
void warpMouse(int x, int y);
|
||||||
|
|
||||||
void updateMouseSettings();
|
void updateMouseSettings();
|
||||||
|
@ -53,8 +50,6 @@ namespace SDLUtil
|
||||||
void _wrapMousePointer(const SDL_MouseMotionEvent &evt);
|
void _wrapMousePointer(const SDL_MouseMotionEvent &evt);
|
||||||
MouseMotionEvent _packageMouseMotion(const SDL_Event& evt);
|
MouseMotionEvent _packageMouseMotion(const SDL_Event& evt);
|
||||||
|
|
||||||
void _setupOISKeys();
|
|
||||||
|
|
||||||
SDL_Window* mSDLWindow;
|
SDL_Window* mSDLWindow;
|
||||||
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
||||||
|
|
||||||
|
@ -64,9 +59,6 @@ namespace SDLUtil
|
||||||
WindowListener* mWindowListener;
|
WindowListener* mWindowListener;
|
||||||
ControllerListener* mConListener;
|
ControllerListener* mConListener;
|
||||||
|
|
||||||
typedef std::map<SDL_Keycode, OIS::KeyCode> KeyMap;
|
|
||||||
KeyMap mKeyMap;
|
|
||||||
|
|
||||||
Uint16 mWarpX;
|
Uint16 mWarpX;
|
||||||
Uint16 mWarpY;
|
Uint16 mWarpY;
|
||||||
bool mWarpCompensate;
|
bool mWarpCompensate;
|
||||||
|
|
|
@ -263,15 +263,21 @@ namespace Shader
|
||||||
case osg::Material::OFF:
|
case osg::Material::OFF:
|
||||||
colorMode = 0;
|
colorMode = 0;
|
||||||
break;
|
break;
|
||||||
case GL_AMBIENT:
|
case osg::Material::EMISSION:
|
||||||
colorMode = 3;
|
colorMode = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case GL_AMBIENT_AND_DIFFUSE:
|
case osg::Material::AMBIENT_AND_DIFFUSE:
|
||||||
colorMode = 2;
|
colorMode = 2;
|
||||||
break;
|
break;
|
||||||
case GL_EMISSION:
|
case osg::Material::AMBIENT:
|
||||||
colorMode = 1;
|
colorMode = 3;
|
||||||
|
break;
|
||||||
|
case osg::Material::DIFFUSE:
|
||||||
|
colorMode = 4;
|
||||||
|
break;
|
||||||
|
case osg::Material::SPECULAR:
|
||||||
|
colorMode = 5;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,13 @@
|
||||||
|
|
||||||
uniform int colorMode;
|
uniform int colorMode;
|
||||||
|
|
||||||
|
const int ColorMode_None = 0;
|
||||||
|
const int ColorMode_Emission = 1;
|
||||||
|
const int ColorMode_AmbientAndDiffuse = 2;
|
||||||
|
const int ColorMode_Ambient = 3;
|
||||||
|
const int ColorMode_Diffuse = 4;
|
||||||
|
const int ColorMode_Specular = 5;
|
||||||
|
|
||||||
void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient)
|
void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient)
|
||||||
{
|
{
|
||||||
vec3 lightDir;
|
vec3 lightDir;
|
||||||
|
@ -22,22 +29,25 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing
|
||||||
vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadowDiffuse)
|
vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadowDiffuse)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
vec4 diffuse;
|
vec4 diffuse = gl_FrontMaterial.diffuse;
|
||||||
vec3 ambient;
|
vec3 ambient = gl_FrontMaterial.ambient.xyz;
|
||||||
if (colorMode == 3)
|
vec3 emission = gl_FrontMaterial.emission.xyz;
|
||||||
{
|
if (colorMode == ColorMode_AmbientAndDiffuse)
|
||||||
diffuse = gl_FrontMaterial.diffuse;
|
|
||||||
ambient = vertexColor.xyz;
|
|
||||||
}
|
|
||||||
else if (colorMode == 2)
|
|
||||||
{
|
{
|
||||||
diffuse = vertexColor;
|
diffuse = vertexColor;
|
||||||
ambient = vertexColor.xyz;
|
ambient = vertexColor.xyz;
|
||||||
}
|
}
|
||||||
else
|
else if (colorMode == ColorMode_Ambient)
|
||||||
{
|
{
|
||||||
diffuse = gl_FrontMaterial.diffuse;
|
ambient = vertexColor.xyz;
|
||||||
ambient = gl_FrontMaterial.ambient.xyz;
|
}
|
||||||
|
else if (colorMode == ColorMode_Diffuse)
|
||||||
|
{
|
||||||
|
diffuse = vertexColor;
|
||||||
|
}
|
||||||
|
else if (colorMode == ColorMode_Emission)
|
||||||
|
{
|
||||||
|
emission = vertexColor.xyz;
|
||||||
}
|
}
|
||||||
vec4 lightResult = vec4(0.0, 0.0, 0.0, diffuse.a);
|
vec4 lightResult = vec4(0.0, 0.0, 0.0, diffuse.a);
|
||||||
|
|
||||||
|
@ -55,12 +65,7 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow
|
||||||
lightResult.xyz += ambientLight + diffuseLight;
|
lightResult.xyz += ambientLight + diffuseLight;
|
||||||
}
|
}
|
||||||
|
|
||||||
lightResult.xyz += gl_LightModel.ambient.xyz * ambient;
|
lightResult.xyz += gl_LightModel.ambient.xyz * ambient + emission;
|
||||||
|
|
||||||
if (colorMode == 1)
|
|
||||||
lightResult.xyz += vertexColor.xyz;
|
|
||||||
else
|
|
||||||
lightResult.xyz += gl_FrontMaterial.emission.xyz;
|
|
||||||
|
|
||||||
#if @clamp
|
#if @clamp
|
||||||
lightResult = clamp(lightResult, vec4(0.0), vec4(1.0));
|
lightResult = clamp(lightResult, vec4(0.0), vec4(1.0));
|
||||||
|
|
|
@ -59,9 +59,8 @@ varying float linearDepth;
|
||||||
#if !PER_PIXEL_LIGHTING
|
#if !PER_PIXEL_LIGHTING
|
||||||
centroid varying vec4 lighting;
|
centroid varying vec4 lighting;
|
||||||
centroid varying vec3 shadowDiffuseLighting;
|
centroid varying vec3 shadowDiffuseLighting;
|
||||||
#else
|
|
||||||
centroid varying vec4 passColor;
|
|
||||||
#endif
|
#endif
|
||||||
|
centroid varying vec4 passColor;
|
||||||
varying vec3 passViewPos;
|
varying vec3 passViewPos;
|
||||||
varying vec3 passNormal;
|
varying vec3 passNormal;
|
||||||
|
|
||||||
|
@ -178,6 +177,8 @@ void main()
|
||||||
#else
|
#else
|
||||||
float shininess = gl_FrontMaterial.shininess;
|
float shininess = gl_FrontMaterial.shininess;
|
||||||
vec3 matSpec = gl_FrontMaterial.specular.xyz;
|
vec3 matSpec = gl_FrontMaterial.specular.xyz;
|
||||||
|
if (colorMode == ColorMode_Specular)
|
||||||
|
matSpec = passColor.xyz;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gl_FragData[0].xyz += getSpecular(normalize(viewNormal), normalize(passViewPos.xyz), shininess, matSpec) * shadowing;
|
gl_FragData[0].xyz += getSpecular(normalize(viewNormal), normalize(passViewPos.xyz), shininess, matSpec) * shadowing;
|
||||||
|
|
|
@ -45,9 +45,8 @@ varying float linearDepth;
|
||||||
#if !PER_PIXEL_LIGHTING
|
#if !PER_PIXEL_LIGHTING
|
||||||
centroid varying vec4 lighting;
|
centroid varying vec4 lighting;
|
||||||
centroid varying vec3 shadowDiffuseLighting;
|
centroid varying vec3 shadowDiffuseLighting;
|
||||||
#else
|
|
||||||
centroid varying vec4 passColor;
|
|
||||||
#endif
|
#endif
|
||||||
|
centroid varying vec4 passColor;
|
||||||
varying vec3 passViewPos;
|
varying vec3 passViewPos;
|
||||||
varying vec3 passNormal;
|
varying vec3 passNormal;
|
||||||
|
|
||||||
|
@ -108,9 +107,8 @@ void main(void)
|
||||||
|
|
||||||
#if !PER_PIXEL_LIGHTING
|
#if !PER_PIXEL_LIGHTING
|
||||||
lighting = doLighting(viewPos.xyz, viewNormal, gl_Color, shadowDiffuseLighting);
|
lighting = doLighting(viewPos.xyz, viewNormal, gl_Color, shadowDiffuseLighting);
|
||||||
#else
|
|
||||||
passColor = gl_Color;
|
|
||||||
#endif
|
#endif
|
||||||
|
passColor = gl_Color;
|
||||||
passViewPos = viewPos.xyz;
|
passViewPos = viewPos.xyz;
|
||||||
passNormal = gl_Normal.xyz;
|
passNormal = gl_Normal.xyz;
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,8 @@ varying float linearDepth;
|
||||||
#if !PER_PIXEL_LIGHTING
|
#if !PER_PIXEL_LIGHTING
|
||||||
centroid varying vec4 lighting;
|
centroid varying vec4 lighting;
|
||||||
centroid varying vec3 shadowDiffuseLighting;
|
centroid varying vec3 shadowDiffuseLighting;
|
||||||
#else
|
|
||||||
centroid varying vec4 passColor;
|
|
||||||
#endif
|
#endif
|
||||||
|
centroid varying vec4 passColor;
|
||||||
varying vec3 passViewPos;
|
varying vec3 passViewPos;
|
||||||
varying vec3 passNormal;
|
varying vec3 passNormal;
|
||||||
|
|
||||||
|
@ -83,10 +82,12 @@ void main()
|
||||||
|
|
||||||
#if @specularMap
|
#if @specularMap
|
||||||
float shininess = 128.0; // TODO: make configurable
|
float shininess = 128.0; // TODO: make configurable
|
||||||
vec3 matSpec = vec3(diffuseTex.a, diffuseTex.a, diffuseTex.a);
|
vec3 matSpec = vec3(diffuseTex.a);
|
||||||
#else
|
#else
|
||||||
float shininess = gl_FrontMaterial.shininess;
|
float shininess = gl_FrontMaterial.shininess;
|
||||||
vec3 matSpec = gl_FrontMaterial.specular.xyz;
|
vec3 matSpec = gl_FrontMaterial.specular.xyz;
|
||||||
|
if (colorMode == ColorMode_Specular)
|
||||||
|
matSpec = passColor.xyz;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gl_FragData[0].xyz += getSpecular(normalize(viewNormal), normalize(passViewPos), shininess, matSpec) * shadowing;
|
gl_FragData[0].xyz += getSpecular(normalize(viewNormal), normalize(passViewPos), shininess, matSpec) * shadowing;
|
||||||
|
|
|
@ -9,9 +9,8 @@ varying float linearDepth;
|
||||||
#if !PER_PIXEL_LIGHTING
|
#if !PER_PIXEL_LIGHTING
|
||||||
centroid varying vec4 lighting;
|
centroid varying vec4 lighting;
|
||||||
centroid varying vec3 shadowDiffuseLighting;
|
centroid varying vec3 shadowDiffuseLighting;
|
||||||
#else
|
|
||||||
centroid varying vec4 passColor;
|
|
||||||
#endif
|
#endif
|
||||||
|
centroid varying vec4 passColor;
|
||||||
varying vec3 passViewPos;
|
varying vec3 passViewPos;
|
||||||
varying vec3 passNormal;
|
varying vec3 passNormal;
|
||||||
|
|
||||||
|
@ -32,9 +31,8 @@ void main(void)
|
||||||
|
|
||||||
#if !PER_PIXEL_LIGHTING
|
#if !PER_PIXEL_LIGHTING
|
||||||
lighting = doLighting(viewPos.xyz, viewNormal, gl_Color, shadowDiffuseLighting);
|
lighting = doLighting(viewPos.xyz, viewNormal, gl_Color, shadowDiffuseLighting);
|
||||||
#else
|
|
||||||
passColor = gl_Color;
|
|
||||||
#endif
|
#endif
|
||||||
|
passColor = gl_Color;
|
||||||
passNormal = gl_Normal.xyz;
|
passNormal = gl_Normal.xyz;
|
||||||
passViewPos = viewPos.xyz;
|
passViewPos = viewPos.xyz;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue