mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-07-20 19:44:05 +00:00
GUI fixes. Animation fixes, i now understand movement accumulation better and was able to clean up some of the hacks with a better result. Lockpicks and probes now work. Haptics. Ready to be playtested.
This commit is contained in:
parent
cad6468518
commit
6474d703ae
27 changed files with 687 additions and 179 deletions
|
@ -65,6 +65,8 @@ namespace MWBase
|
||||||
virtual void enableDetectingBindingMode (int action, bool keyboard) = 0;
|
virtual void enableDetectingBindingMode (int action, bool keyboard) = 0;
|
||||||
virtual void resetToDefaultKeyBindings() = 0;
|
virtual void resetToDefaultKeyBindings() = 0;
|
||||||
virtual void resetToDefaultControllerBindings() = 0;
|
virtual void resetToDefaultControllerBindings() = 0;
|
||||||
|
virtual void applyHapticsLeftHand(float intensity) = 0;
|
||||||
|
virtual void applyHapticsRightHand(float intensity) = 0;
|
||||||
|
|
||||||
/// 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
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "../mwmechanics/difficultyscaling.hpp"
|
#include "../mwmechanics/difficultyscaling.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -329,11 +330,11 @@ namespace MWClass
|
||||||
|
|
||||||
MWMechanics::diseaseContact(victim, ptr);
|
MWMechanics::diseaseContact(victim, ptr);
|
||||||
|
|
||||||
victim.getClass().onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true);
|
victim.getClass().onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true, attackStrength);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) const
|
void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful, float hitStrength) const
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||||
|
|
||||||
|
@ -348,6 +349,8 @@ namespace MWClass
|
||||||
if (isMobile(ptr) && !attacker.isEmpty())
|
if (isMobile(ptr) && !attacker.isEmpty())
|
||||||
setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
|
setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
|
||||||
|
|
||||||
|
bool attackerIsPlayer = attacker == MWMechanics::getPlayer();
|
||||||
|
|
||||||
// Attacker and target store each other as hitattemptactor if they have no one stored yet
|
// Attacker and target store each other as hitattemptactor if they have no one stored yet
|
||||||
if (!attacker.isEmpty() && attacker.getClass().isActor())
|
if (!attacker.isEmpty() && attacker.getClass().isActor())
|
||||||
{
|
{
|
||||||
|
@ -355,20 +358,20 @@ namespace MWClass
|
||||||
// First handle the attacked actor
|
// First handle the attacked actor
|
||||||
if ((stats.getHitAttemptActorId() == -1)
|
if ((stats.getHitAttemptActorId() == -1)
|
||||||
&& (statsAttacker.getAiSequence().isInCombat(ptr)
|
&& (statsAttacker.getAiSequence().isInCombat(ptr)
|
||||||
|| attacker == MWMechanics::getPlayer()))
|
|| attackerIsPlayer))
|
||||||
stats.setHitAttemptActorId(statsAttacker.getActorId());
|
stats.setHitAttemptActorId(statsAttacker.getActorId());
|
||||||
|
|
||||||
// Next handle the attacking actor
|
// Next handle the attacking actor
|
||||||
if ((statsAttacker.getHitAttemptActorId() == -1)
|
if ((statsAttacker.getHitAttemptActorId() == -1)
|
||||||
&& (statsAttacker.getAiSequence().isInCombat(ptr)
|
&& (statsAttacker.getAiSequence().isInCombat(ptr)
|
||||||
|| attacker == MWMechanics::getPlayer()))
|
|| attackerIsPlayer))
|
||||||
statsAttacker.setHitAttemptActorId(stats.getActorId());
|
statsAttacker.setHitAttemptActorId(stats.getActorId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!object.isEmpty())
|
if (!object.isEmpty())
|
||||||
stats.setLastHitAttemptObject(object.getCellRef().getRefId());
|
stats.setLastHitAttemptObject(object.getCellRef().getRefId());
|
||||||
|
|
||||||
if (setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer())
|
if (setOnPcHitMe && !attacker.isEmpty() && attackerIsPlayer)
|
||||||
{
|
{
|
||||||
const std::string &script = ptr.get<ESM::Creature>()->mBase->mScript;
|
const std::string &script = ptr.get<ESM::Creature>()->mBase->mScript;
|
||||||
/* Set the OnPCHitMe script variable. The script is responsible for clearing it. */
|
/* Set the OnPCHitMe script variable. The script is responsible for clearing it. */
|
||||||
|
@ -379,7 +382,7 @@ namespace MWClass
|
||||||
if (!successful)
|
if (!successful)
|
||||||
{
|
{
|
||||||
// Missed
|
// Missed
|
||||||
if (!attacker.isEmpty() && attacker == MWMechanics::getPlayer())
|
if (!attacker.isEmpty() && attackerIsPlayer)
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "miss", 1.0f, 1.0f);
|
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "miss", 1.0f, 1.0f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -427,6 +430,16 @@ namespace MWClass
|
||||||
stats.setFatigue(fatigue);
|
stats.setFatigue(fatigue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(successful)
|
||||||
|
{
|
||||||
|
auto* inputManager = MWBase::Environment::get().getInputManager();
|
||||||
|
if (attackerIsPlayer && hitStrength > 0.f)
|
||||||
|
{
|
||||||
|
float hapticIntensity = std::max(0.25f, std::min(1.f, hitStrength));
|
||||||
|
inputManager->applyHapticsRightHand(hapticIntensity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Creature::activate (const MWWorld::Ptr& ptr,
|
std::shared_ptr<MWWorld::Action> Creature::activate (const MWWorld::Ptr& ptr,
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace MWClass
|
||||||
|
|
||||||
virtual bool hit(const MWWorld::Ptr& ptr, float attackStrength, int type, bool simulated) const;
|
virtual bool hit(const MWWorld::Ptr& ptr, float attackStrength, int type, bool simulated) const;
|
||||||
|
|
||||||
virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) const;
|
virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful, float hitStrength) const;
|
||||||
|
|
||||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||||
const MWWorld::Ptr& actor) const;
|
const MWWorld::Ptr& actor) const;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -670,15 +671,16 @@ namespace MWClass
|
||||||
|
|
||||||
MWMechanics::diseaseContact(victim, ptr);
|
MWMechanics::diseaseContact(victim, ptr);
|
||||||
|
|
||||||
othercls.onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true);
|
othercls.onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true, attackStrength);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Npc::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) const
|
void Npc::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful, float hitStrength) const
|
||||||
{
|
{
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||||
bool wasDead = stats.isDead();
|
bool wasDead = stats.isDead();
|
||||||
|
float rawDamage = damage;
|
||||||
|
|
||||||
// Note OnPcHitMe is not set for friendly hits.
|
// Note OnPcHitMe is not set for friendly hits.
|
||||||
bool setOnPcHitMe = true;
|
bool setOnPcHitMe = true;
|
||||||
|
@ -689,6 +691,8 @@ namespace MWClass
|
||||||
stats.setAttacked(true);
|
stats.setAttacked(true);
|
||||||
setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
|
setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
|
||||||
}
|
}
|
||||||
|
bool attackerIsPlayer = attacker == MWMechanics::getPlayer();
|
||||||
|
bool victimIsPlayer = ptr == MWMechanics::getPlayer();
|
||||||
|
|
||||||
// Attacker and target store each other as hitattemptactor if they have no one stored yet
|
// Attacker and target store each other as hitattemptactor if they have no one stored yet
|
||||||
if (!attacker.isEmpty() && attacker.getClass().isActor())
|
if (!attacker.isEmpty() && attacker.getClass().isActor())
|
||||||
|
@ -697,20 +701,20 @@ namespace MWClass
|
||||||
// First handle the attacked actor
|
// First handle the attacked actor
|
||||||
if ((stats.getHitAttemptActorId() == -1)
|
if ((stats.getHitAttemptActorId() == -1)
|
||||||
&& (statsAttacker.getAiSequence().isInCombat(ptr)
|
&& (statsAttacker.getAiSequence().isInCombat(ptr)
|
||||||
|| attacker == MWMechanics::getPlayer()))
|
|| attackerIsPlayer))
|
||||||
stats.setHitAttemptActorId(statsAttacker.getActorId());
|
stats.setHitAttemptActorId(statsAttacker.getActorId());
|
||||||
|
|
||||||
// Next handle the attacking actor
|
// Next handle the attacking actor
|
||||||
if ((statsAttacker.getHitAttemptActorId() == -1)
|
if ((statsAttacker.getHitAttemptActorId() == -1)
|
||||||
&& (statsAttacker.getAiSequence().isInCombat(ptr)
|
&& (statsAttacker.getAiSequence().isInCombat(ptr)
|
||||||
|| attacker == MWMechanics::getPlayer()))
|
|| attackerIsPlayer))
|
||||||
statsAttacker.setHitAttemptActorId(stats.getActorId());
|
statsAttacker.setHitAttemptActorId(stats.getActorId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!object.isEmpty())
|
if (!object.isEmpty())
|
||||||
stats.setLastHitAttemptObject(object.getCellRef().getRefId());
|
stats.setLastHitAttemptObject(object.getCellRef().getRefId());
|
||||||
|
|
||||||
if (setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer())
|
if (setOnPcHitMe && !attacker.isEmpty() && attackerIsPlayer)
|
||||||
{
|
{
|
||||||
const std::string &script = getScript(ptr);
|
const std::string &script = getScript(ptr);
|
||||||
/* Set the OnPCHitMe script variable. The script is responsible for clearing it. */
|
/* Set the OnPCHitMe script variable. The script is responsible for clearing it. */
|
||||||
|
@ -721,7 +725,7 @@ namespace MWClass
|
||||||
if (!successful)
|
if (!successful)
|
||||||
{
|
{
|
||||||
// Missed
|
// Missed
|
||||||
if (!attacker.isEmpty() && attacker == MWMechanics::getPlayer())
|
if (!attacker.isEmpty() && attackerIsPlayer)
|
||||||
sndMgr->playSound3D(ptr, "miss", 1.0f, 1.0f);
|
sndMgr->playSound3D(ptr, "miss", 1.0f, 1.0f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -736,7 +740,7 @@ namespace MWClass
|
||||||
if (damage < 0.001f)
|
if (damage < 0.001f)
|
||||||
damage = 0;
|
damage = 0;
|
||||||
|
|
||||||
bool godmode = ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
bool godmode = victimIsPlayer && MWBase::Environment::get().getWorld()->getGodModeState();
|
||||||
|
|
||||||
if (godmode)
|
if (godmode)
|
||||||
damage = 0;
|
damage = 0;
|
||||||
|
@ -860,6 +864,23 @@ namespace MWClass
|
||||||
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker);
|
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply haptics
|
||||||
|
if (successful)
|
||||||
|
{
|
||||||
|
auto* inputManager = MWBase::Environment::get().getInputManager();
|
||||||
|
if (victimIsPlayer)
|
||||||
|
{
|
||||||
|
float maxHealth = getCreatureStats(ptr).getHealth().getModified();
|
||||||
|
float hapticIntensity = std::max(0.25f, std::min(1.f, rawDamage / ( maxHealth / 4.f)));
|
||||||
|
inputManager->applyHapticsLeftHand(hapticIntensity);
|
||||||
|
}
|
||||||
|
else if (attackerIsPlayer && hitStrength > 0.f)
|
||||||
|
{
|
||||||
|
float hapticIntensity = std::max(0.25f, std::min(1.f, hitStrength));
|
||||||
|
inputManager->applyHapticsRightHand(hapticIntensity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Npc::activate (const MWWorld::Ptr& ptr,
|
std::shared_ptr<MWWorld::Action> Npc::activate (const MWWorld::Ptr& ptr,
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace MWClass
|
||||||
|
|
||||||
virtual bool hit(const MWWorld::Ptr& ptr, float attackStrength, int type, bool simulated) const;
|
virtual bool hit(const MWWorld::Ptr& ptr, float attackStrength, int type, bool simulated) const;
|
||||||
|
|
||||||
virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) const;
|
virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful, float hitStrength) const;
|
||||||
|
|
||||||
virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector<std::string>& models) const;
|
virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector<std::string>& models) const;
|
||||||
///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel().
|
///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel().
|
||||||
|
|
|
@ -30,7 +30,11 @@ namespace MWGui
|
||||||
std::string ToolTips::sSchoolNames[] = {"#{sSchoolAlteration}", "#{sSchoolConjuration}", "#{sSchoolDestruction}", "#{sSchoolIllusion}", "#{sSchoolMysticism}", "#{sSchoolRestoration}"};
|
std::string ToolTips::sSchoolNames[] = {"#{sSchoolAlteration}", "#{sSchoolConjuration}", "#{sSchoolDestruction}", "#{sSchoolIllusion}", "#{sSchoolMysticism}", "#{sSchoolRestoration}"};
|
||||||
|
|
||||||
ToolTips::ToolTips() :
|
ToolTips::ToolTips() :
|
||||||
|
#ifdef USE_OPENXR
|
||||||
|
Layout("openmw_tooltips_vr.layout")
|
||||||
|
#else
|
||||||
Layout("openmw_tooltips.layout")
|
Layout("openmw_tooltips.layout")
|
||||||
|
#endif
|
||||||
, mFocusToolTipX(0.0)
|
, mFocusToolTipX(0.0)
|
||||||
, mFocusToolTipY(0.0)
|
, mFocusToolTipY(0.0)
|
||||||
, mHorizontalScrollIndex(0)
|
, mHorizontalScrollIndex(0)
|
||||||
|
|
|
@ -1945,7 +1945,7 @@ namespace MWGui
|
||||||
// (Menu gets recreated next tick)
|
// (Menu gets recreated next tick)
|
||||||
if (xrMenuManager)
|
if (xrMenuManager)
|
||||||
{
|
{
|
||||||
xrMenuManager->showGUIs(false);
|
xrMenuManager->updateTracking();
|
||||||
xrMenuManager = nullptr;
|
xrMenuManager = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -239,6 +239,9 @@ namespace MWInput
|
||||||
|
|
||||||
bool checkAllowedToUseItems() const;
|
bool checkAllowedToUseItems() const;
|
||||||
|
|
||||||
|
void applyHapticsLeftHand(float intensity) override {};
|
||||||
|
void applyHapticsRightHand(float intensity) override {};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void toggleMainMenu();
|
void toggleMainMenu();
|
||||||
void toggleSpell();
|
void toggleSpell();
|
||||||
|
|
|
@ -49,6 +49,11 @@
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
#include "spellcasting.hpp"
|
#include "spellcasting.hpp"
|
||||||
|
|
||||||
|
#ifdef USE_OPENXR
|
||||||
|
#include "../mwvr/vrenvironment.hpp"
|
||||||
|
#include "../mwvr/vranimation.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -1582,9 +1587,14 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
{
|
{
|
||||||
MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
MWWorld::Ptr item = *weapon;
|
MWWorld::Ptr item = *weapon;
|
||||||
// TODO: this will only work for the player, and needs to be fixed if NPCs should ever use lockpicks/probes.
|
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject();
|
|
||||||
std::string resultMessage, resultSound;
|
std::string resultMessage, resultSound;
|
||||||
|
// TODO: this will only work for the player, and needs to be fixed if NPCs should ever use lockpicks/probes.
|
||||||
|
#ifdef USE_OPENXR
|
||||||
|
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
||||||
|
auto target = anim->getTarget("weapon bone");
|
||||||
|
#else
|
||||||
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject();
|
||||||
|
#endif
|
||||||
|
|
||||||
if(!target.isEmpty())
|
if(!target.isEmpty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -211,7 +211,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (Misc::Rng::roll0to99() >= getHitChance(attacker, victim, skillValue))
|
if (Misc::Rng::roll0to99() >= getHitChance(attacker, victim, skillValue))
|
||||||
{
|
{
|
||||||
victim.getClass().onHit(victim, damage, false, projectile, attacker, osg::Vec3f(), false);
|
victim.getClass().onHit(victim, damage, false, projectile, attacker, osg::Vec3f(), false, attackStrength);
|
||||||
MWMechanics::reduceWeaponCondition(damage, false, weapon, attacker);
|
MWMechanics::reduceWeaponCondition(damage, false, weapon, attacker);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ namespace MWMechanics
|
||||||
victim.getClass().getContainerStore(victim).add(projectile, 1, victim);
|
victim.getClass().getContainerStore(victim).add(projectile, 1, victim);
|
||||||
}
|
}
|
||||||
|
|
||||||
victim.getClass().onHit(victim, damage, true, projectile, attacker, hitPosition, true);
|
victim.getClass().onHit(victim, damage, true, projectile, attacker, hitPosition, true, attackStrength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1062,29 +1062,18 @@ namespace MWRender
|
||||||
return mNodeMap;
|
return mNodeMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In VR, only jump, walk, and run groups should accumulate movement.
|
|
||||||
static bool vrAccum(const std::string& groupname)
|
|
||||||
{
|
|
||||||
#ifdef USE_OPENXR
|
|
||||||
if (groupname.compare(0, 4, "jump"))
|
|
||||||
if (groupname.compare(0, 4, "walk"))
|
|
||||||
if (groupname.compare(0, 3, "run"))
|
|
||||||
if (groupname.compare(0, 4, "swim"))
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
(void)groupname;
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool vrOverride(const std::string& groupname, const std::string& bone)
|
static bool vrOverride(const std::string& groupname, const std::string& bone)
|
||||||
{
|
{
|
||||||
#ifdef USE_OPENXR
|
#ifdef USE_OPENXR
|
||||||
|
// TODO: It's difficult to design a good override system when
|
||||||
|
// I don't have a good understanding of the animation code. So for
|
||||||
|
// now i just block adding updates for nodes that should not be animated in VR.
|
||||||
|
|
||||||
// TODO: Some overrides cause NaN during cull.
|
// TODO: Some overrides cause NaN during cull.
|
||||||
// I believe this happens if an override causes a bone to never receive
|
// I believe this happens if an override causes a bone to never receive
|
||||||
// a valid matrix, but i'm not totally sure.
|
// a valid matrix, but i'm not totally sure.
|
||||||
|
|
||||||
// Add any bone+animation pair that is messing with Vr comfort here.
|
// Add any bone+groupname pair that is messing with Vr comfort here.
|
||||||
using Overrides = std::set<std::string>;
|
using Overrides = std::set<std::string>;
|
||||||
using GroupOverrides = std::map<std::string, Overrides>;
|
using GroupOverrides = std::map<std::string, Overrides>;
|
||||||
static GroupOverrides sVrOverrides =
|
static GroupOverrides sVrOverrides =
|
||||||
|
@ -1165,7 +1154,11 @@ namespace MWRender
|
||||||
mActiveControllers.insert(std::make_pair(node, it->second));
|
mActiveControllers.insert(std::make_pair(node, it->second));
|
||||||
|
|
||||||
if (blendMask == 0 && node == mAccumRoot
|
if (blendMask == 0 && node == mAccumRoot
|
||||||
&& (!isPlayer || vrAccum(active->first)))
|
#ifdef USE_OPENXR
|
||||||
|
// TODO: Little hack to keep certain animations from wobbling the camera in VR
|
||||||
|
&& (!isPlayer)
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
mAccumCtrl = it->second;
|
mAccumCtrl = it->second;
|
||||||
|
|
||||||
|
|
|
@ -442,7 +442,7 @@ public:
|
||||||
void disable(const std::string &groupname);
|
void disable(const std::string &groupname);
|
||||||
|
|
||||||
/** Retrieves the velocity (in units per second) that the animation will move. */
|
/** Retrieves the velocity (in units per second) that the animation will move. */
|
||||||
float getVelocity(const std::string &groupname) const;
|
virtual float getVelocity(const std::string &groupname) const;
|
||||||
|
|
||||||
virtual osg::Vec3f runAnimation(float duration);
|
virtual osg::Vec3f runAnimation(float duration);
|
||||||
|
|
||||||
|
|
|
@ -113,10 +113,8 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef USE_OPENXR
|
#ifdef USE_OPENXR
|
||||||
// In VR player rotation and weapon aim are unrelated.
|
// In VR weapon aim is taken from the real orientation of the weapon.
|
||||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
osg::Quat orient = MWVR::Environment::get().getPlayerAnimation()->getWeaponTransformMatrix().getRotate();
|
||||||
osg::Matrix worldMatrix = osg::computeLocalToWorld(anim->mWeaponDirectionTransform->getParentalNodePaths()[0]);
|
|
||||||
osg::Quat orient = worldMatrix.getRotate();
|
|
||||||
#else
|
#else
|
||||||
// The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's orientation dictates otherwise.
|
// The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's orientation dictates otherwise.
|
||||||
osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))
|
osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))
|
||||||
|
|
|
@ -127,8 +127,6 @@ public:
|
||||||
mOnActivate = changed && mActive;
|
mOnActivate = changed && mActive;
|
||||||
mOnDeactivate = changed && !mActive;
|
mOnDeactivate = changed && !mActive;
|
||||||
|
|
||||||
//if(openMWActionCode() == MWInput::InputManager::A_Journal)
|
|
||||||
Log(Debug::Verbose) << "Action[" << mXRAction.mName << "]: old=" << old << " shouldQueue=" << shouldQueue() << ", active=" << mActive << ", value=" << mValue << " onActivate=" << mOnActivate << ", mOnDeactivate=" << mOnDeactivate;
|
|
||||||
if (shouldQueue())
|
if (shouldQueue())
|
||||||
{
|
{
|
||||||
queue.push_back(this);
|
queue.push_back(this);
|
||||||
|
@ -287,6 +285,7 @@ struct OpenXRInput
|
||||||
{
|
{
|
||||||
A_XrFirst = MWInput::InputManager::A_Last,
|
A_XrFirst = MWInput::InputManager::A_Last,
|
||||||
A_ActivateTouch,
|
A_ActivateTouch,
|
||||||
|
A_RepositionMenu,
|
||||||
A_XrLast
|
A_XrLast
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -326,6 +325,11 @@ struct OpenXRInput
|
||||||
const Action* nextAction();
|
const Action* nextAction();
|
||||||
PoseSet getHandPoses(int64_t time, TrackedSpace space);
|
PoseSet getHandPoses(int64_t time, TrackedSpace space);
|
||||||
|
|
||||||
|
void applyHaptics(SubAction subAction, float intensity)
|
||||||
|
{
|
||||||
|
mHapticsAction.applyHaptics(subactionPath(subAction), intensity);
|
||||||
|
}
|
||||||
|
|
||||||
SubActionPaths mSubactionPath;
|
SubActionPaths mSubactionPath;
|
||||||
XrActionSet mActionSet = XR_NULL_HANDLE;
|
XrActionSet mActionSet = XR_NULL_HANDLE;
|
||||||
|
|
||||||
|
@ -345,6 +349,7 @@ struct OpenXRInput
|
||||||
ControllerActionPaths mTriggerValuePath;
|
ControllerActionPaths mTriggerValuePath;
|
||||||
|
|
||||||
ActionPtr mGameMenu;
|
ActionPtr mGameMenu;
|
||||||
|
ActionPtr mRepositionMenu;
|
||||||
ActionPtr mInventory;
|
ActionPtr mInventory;
|
||||||
ActionPtr mActivate;
|
ActionPtr mActivate;
|
||||||
ActionPtr mUse;
|
ActionPtr mUse;
|
||||||
|
@ -355,18 +360,19 @@ struct OpenXRInput
|
||||||
ActionPtr mCycleSpellRight;
|
ActionPtr mCycleSpellRight;
|
||||||
ActionPtr mCycleWeaponLeft;
|
ActionPtr mCycleWeaponLeft;
|
||||||
ActionPtr mCycleWeaponRight;
|
ActionPtr mCycleWeaponRight;
|
||||||
ActionPtr mToggleSneak;
|
ActionPtr mSneak;
|
||||||
ActionPtr mQuickMenu;
|
ActionPtr mQuickMenu;
|
||||||
ActionPtr mLookLeftRight;
|
ActionPtr mLookLeftRight;
|
||||||
ActionPtr mMoveForwardBackward;
|
ActionPtr mMoveForwardBackward;
|
||||||
ActionPtr mMoveLeftRight;
|
ActionPtr mMoveLeftRight;
|
||||||
ActionPtr mJournal;
|
ActionPtr mJournal;
|
||||||
//OpenXRAction_Delayed mQuickSave;
|
ActionPtr mQuickSave;
|
||||||
|
ActionPtr mRest;
|
||||||
// Needed to access all the actions that don't fit on the controllers
|
|
||||||
ActionPtr mQuickKeysMenu;
|
|
||||||
|
|
||||||
ActionPtr mActivateTouch;
|
ActionPtr mActivateTouch;
|
||||||
|
ActionPtr mAlwaysRun;
|
||||||
|
ActionPtr mAutoMove;
|
||||||
|
ActionPtr mToggleHUD;
|
||||||
|
ActionPtr mToggleDebug;
|
||||||
|
|
||||||
// Hand tracking
|
// Hand tracking
|
||||||
OpenXRAction mHandPoseAction;
|
OpenXRAction mHandPoseAction;
|
||||||
|
@ -480,6 +486,8 @@ bool OpenXRAction::getPose(XrPath subactionPath)
|
||||||
|
|
||||||
bool OpenXRAction::applyHaptics(XrPath subactionPath, float amplitude)
|
bool OpenXRAction::applyHaptics(XrPath subactionPath, float amplitude)
|
||||||
{
|
{
|
||||||
|
amplitude = std::max(0.f, std::min(1.f, amplitude));
|
||||||
|
|
||||||
auto* xr = Environment::get().getManager();
|
auto* xr = Environment::get().getManager();
|
||||||
XrHapticVibration vibration{ XR_TYPE_HAPTIC_VIBRATION };
|
XrHapticVibration vibration{ XR_TYPE_HAPTIC_VIBRATION };
|
||||||
vibration.amplitude = amplitude;
|
vibration.amplitude = amplitude;
|
||||||
|
@ -534,26 +542,31 @@ OpenXRInput::OpenXRInput()
|
||||||
, mAPath(generateControllerActionPaths("/input/a/click"))
|
, mAPath(generateControllerActionPaths("/input/a/click"))
|
||||||
, mBPath(generateControllerActionPaths("/input/b/click"))
|
, mBPath(generateControllerActionPaths("/input/b/click"))
|
||||||
, mTriggerValuePath(generateControllerActionPaths("/input/trigger/value"))
|
, mTriggerValuePath(generateControllerActionPaths("/input/trigger/value"))
|
||||||
, mGameMenu(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_GameMenu, "game_menu", "GameMenu", { })))
|
, mGameMenu(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_GameMenu, "game_menu", "Game Menu", { })))
|
||||||
|
, mRepositionMenu(std::move(createMWAction<ButtonLongPressAction>(A_RepositionMenu, "reposition_menu", "Reposition Menu", { })))
|
||||||
, mInventory(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_Inventory, "inventory", "Inventory", { })))
|
, mInventory(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_Inventory, "inventory", "Inventory", { })))
|
||||||
, mActivate(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_Activate, "activate", "Activate", { })))
|
, mActivate(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_Activate, "activate", "Activate", { })))
|
||||||
, mUse(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_Use, "use", "Use", { })))
|
, mUse(std::move(createMWAction<ButtonHoldAction>(MWInput::InputManager::A_Use, "use", "Use", { })))
|
||||||
, mJump(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_Jump, "jump", "Jump", { })))
|
, mJump(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_Jump, "jump", "Jump", { })))
|
||||||
, mToggleWeapon(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_ToggleWeapon, "weapon", "Weapon", { })))
|
, mToggleWeapon(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_ToggleWeapon, "weapon", "Weapon", { })))
|
||||||
, mToggleSpell(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_ToggleSpell, "spell", "Spell", { })))
|
, mToggleSpell(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_ToggleSpell, "spell", "Spell", { })))
|
||||||
, mCycleSpellLeft(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_CycleSpellLeft, "cycle_spell_left", "CycleSpellLeft", { })))
|
, mCycleSpellLeft(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_CycleSpellLeft, "cycle_spell_left", "Cycle Spell Left", { })))
|
||||||
, mCycleSpellRight(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_CycleSpellRight, "cycle_spell_right", "CycleSpellRight", { })))
|
, mCycleSpellRight(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_CycleSpellRight, "cycle_spell_right", "Cycle Spell Right", { })))
|
||||||
, mCycleWeaponLeft(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_CycleWeaponLeft, "cycle_weapon_left", "CycleWeaponLeft", { })))
|
, mCycleWeaponLeft(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_CycleWeaponLeft, "cycle_weapon_left", "Cycle Weapon Left", { })))
|
||||||
, mCycleWeaponRight(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_CycleWeaponRight, "cycle_weapon_right", "CycleWeaponRight", { })))
|
, mCycleWeaponRight(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_CycleWeaponRight, "cycle_weapon_right", "Cycle Weapon Right", { })))
|
||||||
, mToggleSneak(std::move(createMWAction<ButtonHoldAction>(MWInput::InputManager::A_ToggleSneak, "sneak", "Sneak", { })))
|
, mSneak(std::move(createMWAction<ButtonHoldAction>(MWInput::InputManager::A_Sneak, "sneak", "Sneak", { })))
|
||||||
, mQuickMenu(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_QuickMenu, "quick_menu", "QuickMenu", { })))
|
, mQuickMenu(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_QuickMenu, "quick_menu", "Quick Menu", { })))
|
||||||
, mLookLeftRight(std::move(createMWAction<AxisAction>(MWInput::InputManager::A_LookLeftRight, "look_left_right", "LookLeftRight", { })))
|
, mLookLeftRight(std::move(createMWAction<AxisAction>(MWInput::InputManager::A_LookLeftRight, "look_left_right", "Look Left Right", { })))
|
||||||
, mMoveForwardBackward(std::move(createMWAction<AxisAction>(MWInput::InputManager::A_MoveForwardBackward, "move_forward_backward", "MoveForwardBackward", { })))
|
, mMoveForwardBackward(std::move(createMWAction<AxisAction>(MWInput::InputManager::A_MoveForwardBackward, "move_forward_backward", "Move Forward Backward", { })))
|
||||||
, mMoveLeftRight(std::move(createMWAction<AxisAction>(MWInput::InputManager::A_MoveLeftRight, "move_left_right", "MoveLeftRight", { })))
|
, mMoveLeftRight(std::move(createMWAction<AxisAction>(MWInput::InputManager::A_MoveLeftRight, "move_left_right", "Move Left Right", { })))
|
||||||
, mJournal(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_Journal, "journal_book", "Journal Book", { })))
|
, mJournal(std::move(createMWAction<ButtonLongPressAction>(MWInput::InputManager::A_Journal, "journal_book", "Journal Book", { })))
|
||||||
//, mQuickSave(std::move(createMWAction<ButtonHoldAction>(MWInput::InputManager::A_QuickSave, "quick_save", "Quick Save", { })))
|
, mQuickSave(std::move(createMWAction<ButtonLongPressAction>(MWInput::InputManager::A_QuickSave, "quick_save", "Quick Save", { })))
|
||||||
, mQuickKeysMenu(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_QuickKeysMenu, "quick_keys_menu", "Quick Keys Menu", { })))
|
, mRest(std::move(createMWAction<ButtonLongPressAction>(MWInput::InputManager::A_Rest, "rest", "Rest", { })))
|
||||||
, mActivateTouch(std::move(createMWAction<AxisAction>(A_ActivateTouch, "activate_touched", "Activate Touch", { RIGHT_HAND })))
|
, mActivateTouch(std::move(createMWAction<AxisAction>(A_ActivateTouch, "activate_touched", "Activate Touch", { RIGHT_HAND })))
|
||||||
|
, mAlwaysRun(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_AlwaysRun, "always_run", "Always Run", { })))
|
||||||
|
, mAutoMove(std::move(createMWAction<ButtonPressAction>(MWInput::InputManager::A_AutoMove, "auto_move", "Auto Move", { })))
|
||||||
|
, mToggleHUD(std::move(createMWAction<ButtonLongPressAction>(MWInput::InputManager::A_ToggleHUD, "toggle_hud", "Toggle HUD", { })))
|
||||||
|
, mToggleDebug(std::move(createMWAction<ButtonLongPressAction>(MWInput::InputManager::A_ToggleDebug, "toggle_debug", "Toggle DEBUG", { })))
|
||||||
, mHandPoseAction(std::move(createXRAction(XR_ACTION_TYPE_POSE_INPUT, "hand_pose", "Hand Pose", { LEFT_HAND, RIGHT_HAND })))
|
, mHandPoseAction(std::move(createXRAction(XR_ACTION_TYPE_POSE_INPUT, "hand_pose", "Hand Pose", { LEFT_HAND, RIGHT_HAND })))
|
||||||
, mHapticsAction(std::move(createXRAction(XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_hand", "Vibrate Hand", { LEFT_HAND, RIGHT_HAND })))
|
, mHapticsAction(std::move(createXRAction(XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_hand", "Vibrate Hand", { LEFT_HAND, RIGHT_HAND })))
|
||||||
{
|
{
|
||||||
|
@ -562,6 +575,81 @@ OpenXRInput::OpenXRInput()
|
||||||
XrPath oculusTouchInteractionProfilePath;
|
XrPath oculusTouchInteractionProfilePath;
|
||||||
CHECK_XRCMD(
|
CHECK_XRCMD(
|
||||||
xrStringToPath(xr->impl().mInstance, "/interaction_profiles/oculus/touch_controller", &oculusTouchInteractionProfilePath));
|
xrStringToPath(xr->impl().mInstance, "/interaction_profiles/oculus/touch_controller", &oculusTouchInteractionProfilePath));
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Applicable actions not (yet) included
|
||||||
|
A_QuickKey1,
|
||||||
|
A_QuickKey2,
|
||||||
|
A_QuickKey3,
|
||||||
|
A_QuickKey4,
|
||||||
|
A_QuickKey5,
|
||||||
|
A_QuickKey6,
|
||||||
|
A_QuickKey7,
|
||||||
|
A_QuickKey8,
|
||||||
|
A_QuickKey9,
|
||||||
|
A_QuickKey10,
|
||||||
|
A_QuickKeysMenu,
|
||||||
|
A_QuickLoad,
|
||||||
|
A_CycleSpellLeft,
|
||||||
|
A_CycleSpellRight,
|
||||||
|
A_CycleWeaponLeft,
|
||||||
|
A_CycleWeaponRight,
|
||||||
|
A_Screenshot, // Generate a VR screenshot?
|
||||||
|
A_Console, // Currently awkward due to a lack of virtual keyboard, but should be included when that's in place
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Oculus Bindings:
|
||||||
|
L-Squeeze:
|
||||||
|
Hold: Sneak
|
||||||
|
|
||||||
|
R-Squeeze:
|
||||||
|
Hold: Enable Pointer
|
||||||
|
|
||||||
|
L-Trigger:
|
||||||
|
Press: Jump
|
||||||
|
|
||||||
|
R-Trigger:
|
||||||
|
IF POINTER:
|
||||||
|
Activate
|
||||||
|
ELSE:
|
||||||
|
Use
|
||||||
|
|
||||||
|
L-Thumbstick:
|
||||||
|
X-Axis: MoveForwardBackward
|
||||||
|
Y-Axis: MoveLeftRight
|
||||||
|
Button:
|
||||||
|
Press: AlwaysRun
|
||||||
|
Long: ToggleHUD
|
||||||
|
Touch:
|
||||||
|
|
||||||
|
R-Thumbstick:
|
||||||
|
X-Axis: LookLeftRight
|
||||||
|
Y-Axis:
|
||||||
|
Button:
|
||||||
|
Press: AutoMove
|
||||||
|
Long: ToggleDebug
|
||||||
|
Touch:
|
||||||
|
|
||||||
|
X:
|
||||||
|
Press: Toggle Spell
|
||||||
|
Long:
|
||||||
|
Y:
|
||||||
|
Press: Rest
|
||||||
|
Long: Quick Save
|
||||||
|
A:
|
||||||
|
Press: Toggle Weapon
|
||||||
|
Long:
|
||||||
|
B:
|
||||||
|
Press: Inventory
|
||||||
|
Long: Journal
|
||||||
|
|
||||||
|
Menu:
|
||||||
|
Press: GameMenun
|
||||||
|
Long: Reposition GUI
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
std::vector<XrActionSuggestedBinding> bindings{ {
|
std::vector<XrActionSuggestedBinding> bindings{ {
|
||||||
{mHandPoseAction, mPosePath[LEFT_HAND]},
|
{mHandPoseAction, mPosePath[LEFT_HAND]},
|
||||||
{mHandPoseAction, mPosePath[RIGHT_HAND]},
|
{mHandPoseAction, mPosePath[RIGHT_HAND]},
|
||||||
|
@ -574,16 +662,22 @@ OpenXRInput::OpenXRInput()
|
||||||
{*mUse, mTriggerValuePath[RIGHT_HAND]},
|
{*mUse, mTriggerValuePath[RIGHT_HAND]},
|
||||||
{*mJump, mTriggerValuePath[LEFT_HAND]},
|
{*mJump, mTriggerValuePath[LEFT_HAND]},
|
||||||
{*mToggleWeapon, mAPath[RIGHT_HAND]},
|
{*mToggleWeapon, mAPath[RIGHT_HAND]},
|
||||||
{*mToggleSpell, mAPath[RIGHT_HAND]},
|
{*mToggleSpell, mXPath[LEFT_HAND]},
|
||||||
{*mCycleSpellLeft, mThumbstickClickPath[LEFT_HAND]},
|
//{*mCycleSpellLeft, mThumbstickClickPath[LEFT_HAND]},
|
||||||
{*mCycleSpellRight, mThumbstickClickPath[RIGHT_HAND]},
|
//{*mCycleSpellRight, mThumbstickClickPath[RIGHT_HAND]},
|
||||||
{*mCycleWeaponLeft, mThumbstickClickPath[LEFT_HAND]},
|
//{*mCycleWeaponLeft, mThumbstickClickPath[LEFT_HAND]},
|
||||||
{*mCycleWeaponRight, mThumbstickClickPath[RIGHT_HAND]},
|
//{*mCycleWeaponRight, mThumbstickClickPath[RIGHT_HAND]},
|
||||||
{*mToggleSneak, mXPath[LEFT_HAND]},
|
{*mAlwaysRun, mThumbstickClickPath[LEFT_HAND]},
|
||||||
|
{*mAutoMove, mThumbstickClickPath[RIGHT_HAND]},
|
||||||
|
{*mToggleHUD, mThumbstickClickPath[LEFT_HAND]},
|
||||||
|
{*mToggleDebug, mThumbstickClickPath[RIGHT_HAND]},
|
||||||
|
{*mSneak, mSqueezeValuePath[LEFT_HAND]},
|
||||||
{*mInventory, mBPath[RIGHT_HAND]},
|
{*mInventory, mBPath[RIGHT_HAND]},
|
||||||
{*mJournal, mYPath[LEFT_HAND]},
|
{*mRest, mYPath[LEFT_HAND]},
|
||||||
//{*mQuickSave, mYPath[LEFT_HAND]},
|
{*mJournal, mBPath[RIGHT_HAND]},
|
||||||
|
{*mQuickSave, mYPath[LEFT_HAND]},
|
||||||
{*mGameMenu, mMenuClickPath[LEFT_HAND]},
|
{*mGameMenu, mMenuClickPath[LEFT_HAND]},
|
||||||
|
{*mRepositionMenu, mMenuClickPath[LEFT_HAND]},
|
||||||
{*mActivateTouch, mSqueezeValuePath[RIGHT_HAND]},
|
{*mActivateTouch, mSqueezeValuePath[RIGHT_HAND]},
|
||||||
} };
|
} };
|
||||||
XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
|
XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
|
||||||
|
@ -591,24 +685,6 @@ OpenXRInput::OpenXRInput()
|
||||||
suggestedBindings.suggestedBindings = bindings.data();
|
suggestedBindings.suggestedBindings = bindings.data();
|
||||||
suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
|
suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
|
||||||
CHECK_XRCMD(xrSuggestInteractionProfileBindings(xr->impl().mInstance, &suggestedBindings));
|
CHECK_XRCMD(xrSuggestInteractionProfileBindings(xr->impl().mInstance, &suggestedBindings));
|
||||||
|
|
||||||
/*
|
|
||||||
mActivate; // R-Squeeze
|
|
||||||
mUse; // R-Trigger
|
|
||||||
mJump; // L-Trigger. L-trigger has value, could use this to make measured jumps ?
|
|
||||||
mToggleWeapon; // A
|
|
||||||
mToggleSpell; // A + SpellModifier
|
|
||||||
mRun; // Based on movement thumbstick value ?
|
|
||||||
mCycleSpellLeft; // L-ThumbstickClick + SpellModifier
|
|
||||||
mCycleSpellRight; // R-ThumbstickClick + SpellModifier
|
|
||||||
mCycleWeaponLeft; // L-ThumbstickClick
|
|
||||||
mCycleWeaponRight; // R-ThumbstickClick
|
|
||||||
mToggleSneak; // X
|
|
||||||
mInventory; // B
|
|
||||||
mQuickMenu; // Y
|
|
||||||
mGameMenu; // Menu
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Set up action spaces
|
{ // Set up action spaces
|
||||||
|
@ -691,6 +767,7 @@ OpenXRInput::updateControls()
|
||||||
CHECK_XRCMD(xrSyncActions(xr->impl().mSession, &syncInfo));
|
CHECK_XRCMD(xrSyncActions(xr->impl().mSession, &syncInfo));
|
||||||
|
|
||||||
mGameMenu->updateAndQueue(mActionQueue);
|
mGameMenu->updateAndQueue(mActionQueue);
|
||||||
|
mRepositionMenu->updateAndQueue(mActionQueue);
|
||||||
mInventory->updateAndQueue(mActionQueue);
|
mInventory->updateAndQueue(mActionQueue);
|
||||||
mActivate->updateAndQueue(mActionQueue);
|
mActivate->updateAndQueue(mActionQueue);
|
||||||
mUse->updateAndQueue(mActionQueue);
|
mUse->updateAndQueue(mActionQueue);
|
||||||
|
@ -701,15 +778,28 @@ OpenXRInput::updateControls()
|
||||||
mCycleSpellRight->updateAndQueue(mActionQueue);
|
mCycleSpellRight->updateAndQueue(mActionQueue);
|
||||||
mCycleWeaponLeft->updateAndQueue(mActionQueue);
|
mCycleWeaponLeft->updateAndQueue(mActionQueue);
|
||||||
mCycleWeaponRight->updateAndQueue(mActionQueue);
|
mCycleWeaponRight->updateAndQueue(mActionQueue);
|
||||||
mToggleSneak->updateAndQueue(mActionQueue);
|
mSneak->updateAndQueue(mActionQueue);
|
||||||
mQuickMenu->updateAndQueue(mActionQueue);
|
mQuickMenu->updateAndQueue(mActionQueue);
|
||||||
mLookLeftRight->updateAndQueue(mActionQueue);
|
mLookLeftRight->updateAndQueue(mActionQueue);
|
||||||
mMoveForwardBackward->updateAndQueue(mActionQueue);
|
mMoveForwardBackward->updateAndQueue(mActionQueue);
|
||||||
mMoveLeftRight->updateAndQueue(mActionQueue);
|
mMoveLeftRight->updateAndQueue(mActionQueue);
|
||||||
mJournal->updateAndQueue(mActionQueue);
|
mJournal->updateAndQueue(mActionQueue);
|
||||||
//mQuickSave->updateAndQueue(mActionQueue);
|
mQuickSave->updateAndQueue(mActionQueue);
|
||||||
mQuickKeysMenu->updateAndQueue(mActionQueue);
|
mRest->updateAndQueue(mActionQueue);
|
||||||
mActivateTouch->updateAndQueue(mActionQueue);
|
mActivateTouch->updateAndQueue(mActionQueue);
|
||||||
|
mAlwaysRun->updateAndQueue(mActionQueue);
|
||||||
|
mAutoMove->updateAndQueue(mActionQueue);
|
||||||
|
mToggleHUD->updateAndQueue(mActionQueue);
|
||||||
|
mToggleDebug->updateAndQueue(mActionQueue);
|
||||||
|
|
||||||
|
//if (mActivateTouch->isActive())
|
||||||
|
//{
|
||||||
|
// mHapticsAction.applyHaptics(mSubactionPath[RIGHT_HAND], 0.5);
|
||||||
|
//}
|
||||||
|
//if (mSneak->isActive())
|
||||||
|
//{
|
||||||
|
// mHapticsAction.applyHaptics(mSubactionPath[LEFT_HAND], 0.5);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
XrPath OpenXRInput::generateXrPath(const std::string& path)
|
XrPath OpenXRInput::generateXrPath(const std::string& path)
|
||||||
|
@ -846,11 +936,11 @@ private:
|
||||||
{
|
{
|
||||||
injectMousePress(SDL_BUTTON_LEFT, onPress);
|
injectMousePress(SDL_BUTTON_LEFT, onPress);
|
||||||
}
|
}
|
||||||
//else if (onPress)
|
else if (onPress)
|
||||||
//{
|
{
|
||||||
// // Other actions should only happen on release;
|
// Other actions should only happen on release;
|
||||||
// return;
|
return;
|
||||||
//}
|
}
|
||||||
else if (dnd.mIsOnDragAndDrop)
|
else if (dnd.mIsOnDragAndDrop)
|
||||||
{
|
{
|
||||||
// Intersected with the world while drag and drop is active
|
// Intersected with the world while drag and drop is active
|
||||||
|
@ -879,6 +969,17 @@ private:
|
||||||
mouseReleased(arg, sdlButton);
|
mouseReleased(arg, sdlButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Configurable haptics: on/off + max intensity
|
||||||
|
void OpenXRInputManager::applyHapticsLeftHand(float intensity)
|
||||||
|
{
|
||||||
|
mXRInput->applyHaptics(OpenXRInput::LEFT_HAND, intensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenXRInputManager::applyHapticsRightHand(float intensity)
|
||||||
|
{
|
||||||
|
mXRInput->applyHaptics(OpenXRInput::RIGHT_HAND, intensity);
|
||||||
|
}
|
||||||
|
|
||||||
OpenXRInputManager::OpenXRInputManager(
|
OpenXRInputManager::OpenXRInputManager(
|
||||||
SDL_Window* window,
|
SDL_Window* window,
|
||||||
osg::ref_ptr<osgViewer::Viewer> viewer,
|
osg::ref_ptr<osgViewer::Viewer> viewer,
|
||||||
|
@ -903,7 +1004,7 @@ private:
|
||||||
{
|
{
|
||||||
// VR mode has no concept of these
|
// VR mode has no concept of these
|
||||||
mControlSwitch["vanitymode"] = false;
|
mControlSwitch["vanitymode"] = false;
|
||||||
mGuiCursorEnabled = false;
|
//mGuiCursorEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenXRInputManager::~OpenXRInputManager()
|
OpenXRInputManager::~OpenXRInputManager()
|
||||||
|
@ -913,7 +1014,7 @@ private:
|
||||||
void OpenXRInputManager::changeInputMode(bool mode)
|
void OpenXRInputManager::changeInputMode(bool mode)
|
||||||
{
|
{
|
||||||
// VR mode has no concept of these
|
// VR mode has no concept of these
|
||||||
mGuiCursorEnabled = false;
|
//mGuiCursorEnabled = false;
|
||||||
MWInput::InputManager::changeInputMode(mode);
|
MWInput::InputManager::changeInputMode(mode);
|
||||||
MWBase::Environment::get().getWindowManager()->showCrosshair(false);
|
MWBase::Environment::get().getWindowManager()->showCrosshair(false);
|
||||||
MWBase::Environment::get().getWindowManager()->setCursorVisible(false);
|
MWBase::Environment::get().getWindowManager()->setCursorVisible(false);
|
||||||
|
@ -927,10 +1028,13 @@ private:
|
||||||
mXRInput->updateControls();
|
mXRInput->updateControls();
|
||||||
|
|
||||||
auto* vrGuiManager = Environment::get().getGUIManager();
|
auto* vrGuiManager = Environment::get().getGUIManager();
|
||||||
vrGuiManager->updateFocus();
|
bool vrHasFocus = vrGuiManager->updateFocus();
|
||||||
auto guiCursor = vrGuiManager->guiCursor();
|
auto guiCursor = vrGuiManager->guiCursor();
|
||||||
mGuiCursorX = guiCursor.x();
|
if (vrHasFocus)
|
||||||
mGuiCursorY = guiCursor.y();
|
{
|
||||||
|
mGuiCursorX = guiCursor.x();
|
||||||
|
mGuiCursorY = guiCursor.y();
|
||||||
|
}
|
||||||
|
|
||||||
while (auto* action = mXRInput->nextAction())
|
while (auto* action = mXRInput->nextAction())
|
||||||
{
|
{
|
||||||
|
@ -942,9 +1046,6 @@ private:
|
||||||
MWInput::InputManager::update(dt, disableControls, disableEvents);
|
MWInput::InputManager::update(dt, disableControls, disableEvents);
|
||||||
|
|
||||||
bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||||
auto* xrGUIManager = Environment::get().getGUIManager();
|
|
||||||
if(xrGUIManager)
|
|
||||||
xrGUIManager->showGUIs(guiMode);
|
|
||||||
|
|
||||||
setPlayerControlsEnabled(!guiMode);
|
setPlayerControlsEnabled(!guiMode);
|
||||||
|
|
||||||
|
@ -981,6 +1082,14 @@ private:
|
||||||
case A_MoveForwardBackward:
|
case A_MoveForwardBackward:
|
||||||
mInputBinder->getChannel(A_MoveForwardBackward)->setValue(-action->value() / 2.f + 0.5f);
|
mInputBinder->getChannel(A_MoveForwardBackward)->setValue(-action->value() / 2.f + 0.5f);
|
||||||
break;
|
break;
|
||||||
|
case A_Sneak:
|
||||||
|
if(!mSneakToggles)
|
||||||
|
mInputBinder->getChannel(A_Sneak)->setValue(action->isActive() ? 1.f : 0.f);
|
||||||
|
break;
|
||||||
|
case A_Use:
|
||||||
|
if (!(mActivationIndication || MWBase::Environment::get().getWindowManager()->isGuiMode()))
|
||||||
|
mInputBinder->getChannel(A_Use)->setValue(action->value());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -992,10 +1101,6 @@ private:
|
||||||
{
|
{
|
||||||
case A_GameMenu:
|
case A_GameMenu:
|
||||||
toggleMainMenu();
|
toggleMainMenu();
|
||||||
// Explicitly request position update here so that the player can move the menu
|
|
||||||
// using the menu key when the menu can't be toggled.
|
|
||||||
// TODO: This should respond to a menu HODL instead
|
|
||||||
// xrGUIManager->updateTracking();
|
|
||||||
break;
|
break;
|
||||||
case A_Screenshot:
|
case A_Screenshot:
|
||||||
screenshot();
|
screenshot();
|
||||||
|
@ -1058,9 +1163,11 @@ private:
|
||||||
showQuickKeysMenu();
|
showQuickKeysMenu();
|
||||||
break;
|
break;
|
||||||
case A_ToggleHUD:
|
case A_ToggleHUD:
|
||||||
|
Log(Debug::Verbose) << "Toggle HUD";
|
||||||
MWBase::Environment::get().getWindowManager()->toggleHud();
|
MWBase::Environment::get().getWindowManager()->toggleHud();
|
||||||
break;
|
break;
|
||||||
case A_ToggleDebug:
|
case A_ToggleDebug:
|
||||||
|
Log(Debug::Verbose) << "Toggle Debug";
|
||||||
MWBase::Environment::get().getWindowManager()->toggleDebugWindow();
|
MWBase::Environment::get().getWindowManager()->toggleDebugWindow();
|
||||||
break;
|
break;
|
||||||
case A_QuickSave:
|
case A_QuickSave:
|
||||||
|
@ -1085,27 +1192,33 @@ private:
|
||||||
if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
|
if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
|
||||||
MWBase::Environment::get().getWindowManager()->cycleWeapon(true);
|
MWBase::Environment::get().getWindowManager()->cycleWeapon(true);
|
||||||
break;
|
break;
|
||||||
case A_ToggleSneak:
|
|
||||||
toggleSneaking();
|
|
||||||
break;
|
|
||||||
case A_Jump:
|
case A_Jump:
|
||||||
mAttemptJump = true;
|
mAttemptJump = true;
|
||||||
break;
|
break;
|
||||||
|
case OpenXRInput::A_RepositionMenu:
|
||||||
|
xrGUIManager->updateTracking();
|
||||||
|
break;
|
||||||
|
case A_Use:
|
||||||
|
if (mActivationIndication || MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
pointActivation(true);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A few actions need both activate and deactivate
|
// A few actions need to fire on deactivation
|
||||||
if (action->onDeactivate())
|
if (action->onDeactivate())
|
||||||
{
|
{
|
||||||
switch (action->openMWActionCode())
|
switch (action->openMWActionCode())
|
||||||
{
|
{
|
||||||
case A_Use:
|
case A_Use:
|
||||||
|
mInputBinder->getChannel(A_Use)->setValue(0.f);
|
||||||
if (mActivationIndication || MWBase::Environment::get().getWindowManager()->isGuiMode())
|
if (mActivationIndication || MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
pointActivation(action->onActivate());
|
pointActivation(false);
|
||||||
else
|
break;
|
||||||
mInputBinder->getChannel(A_Use)->setValue(action->isActive());
|
case A_Sneak:
|
||||||
|
if (mSneakToggles)
|
||||||
|
toggleSneaking();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -49,6 +49,9 @@ namespace MWVR
|
||||||
|
|
||||||
void injectMousePress(int sdlButton, bool onPress);
|
void injectMousePress(int sdlButton, bool onPress);
|
||||||
|
|
||||||
|
void applyHapticsLeftHand(float intensity) override;
|
||||||
|
void applyHapticsRightHand(float intensity) override;
|
||||||
|
|
||||||
std::unique_ptr<OpenXRInput> mXRInput;
|
std::unique_ptr<OpenXRInput> mXRInput;
|
||||||
std::unique_ptr<RealisticCombat::StateMachine> mRealisticCombat;
|
std::unique_ptr<RealisticCombat::StateMachine> mRealisticCombat;
|
||||||
Pose mPreviousHeadPose{};
|
Pose mPreviousHeadPose{};
|
||||||
|
|
|
@ -507,6 +507,8 @@ void VRAnimation::updateParts()
|
||||||
removeIndividualPart(ESM::PartReferenceType::PRT_RAnkle);
|
removeIndividualPart(ESM::PartReferenceType::PRT_RAnkle);
|
||||||
removeIndividualPart(ESM::PartReferenceType::PRT_LKnee);
|
removeIndividualPart(ESM::PartReferenceType::PRT_LKnee);
|
||||||
removeIndividualPart(ESM::PartReferenceType::PRT_RKnee);
|
removeIndividualPart(ESM::PartReferenceType::PRT_RKnee);
|
||||||
|
removeIndividualPart(ESM::PartReferenceType::PRT_LFoot);
|
||||||
|
removeIndividualPart(ESM::PartReferenceType::PRT_RFoot);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -613,6 +615,11 @@ osg::ref_ptr<osg::Geometry> VRAnimation::createPointerGeometry(void)
|
||||||
return geometry;
|
return geometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float VRAnimation::getVelocity(const std::string& groupname) const
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
osg::Vec3f VRAnimation::runAnimation(float timepassed)
|
osg::Vec3f VRAnimation::runAnimation(float timepassed)
|
||||||
{
|
{
|
||||||
return NpcAnimation::runAnimation(timepassed);
|
return NpcAnimation::runAnimation(timepassed);
|
||||||
|
@ -662,6 +669,13 @@ void VRAnimation::addControllers()
|
||||||
group->addChild(mModelOffset);
|
group->addChild(mModelOffset);
|
||||||
mModelOffset->addChild(mObjectRoot);
|
mModelOffset->addChild(mObjectRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto wb = mNodeMap.find("weapon bone");
|
||||||
|
if (wb != mNodeMap.end())
|
||||||
|
{
|
||||||
|
wb->second->removeChild(mWeaponPointerTransform);
|
||||||
|
wb->second->addChild(mWeaponPointerTransform);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void VRAnimation::enableHeadAnimation(bool)
|
void VRAnimation::enableHeadAnimation(bool)
|
||||||
{
|
{
|
||||||
|
@ -692,6 +706,23 @@ const MWRender::RayResult& VRAnimation::getPointerTarget() const
|
||||||
return mPointerTarget;
|
return mPointerTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MWWorld::Ptr VRAnimation::getTarget(const std::string& directorNode)
|
||||||
|
{
|
||||||
|
auto node = mNodeMap.find(directorNode);
|
||||||
|
auto* world = MWBase::Environment::get().getWorld();
|
||||||
|
MWRender::RayResult result{};
|
||||||
|
if (node != mNodeMap.end())
|
||||||
|
if (world)
|
||||||
|
world->getTargetObject(result, node->second);
|
||||||
|
return result.mHitObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Matrix VRAnimation::getWeaponTransformMatrix() const
|
||||||
|
{
|
||||||
|
return osg::computeLocalToWorld(mWeaponDirectionTransform->getParentalNodePaths()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
void VRAnimation::updatePointerTarget()
|
void VRAnimation::updatePointerTarget()
|
||||||
{
|
{
|
||||||
auto* world = MWBase::Environment::get().getWorld();
|
auto* world = MWBase::Environment::get().getWorld();
|
||||||
|
|
|
@ -63,9 +63,15 @@ public:
|
||||||
|
|
||||||
void updatePointerTarget();
|
void updatePointerTarget();
|
||||||
|
|
||||||
public:
|
MWWorld::Ptr getTarget(const std::string& directorNode);
|
||||||
|
|
||||||
|
osg::Matrix getWeaponTransformMatrix() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
static osg::ref_ptr<osg::Geometry> createPointerGeometry(void);
|
static osg::ref_ptr<osg::Geometry> createPointerGeometry(void);
|
||||||
|
|
||||||
|
float getVelocity(const std::string& groupname) const override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<OpenXRSession> mSession;
|
std::shared_ptr<OpenXRSession> mSession;
|
||||||
osg::ref_ptr<ForearmController> mForearmControllers[2];
|
osg::ref_ptr<ForearmController> mForearmControllers[2];
|
||||||
|
|
|
@ -134,11 +134,11 @@ private:
|
||||||
VRGUILayer::VRGUILayer(
|
VRGUILayer::VRGUILayer(
|
||||||
osg::ref_ptr<osg::Group> geometryRoot,
|
osg::ref_ptr<osg::Group> geometryRoot,
|
||||||
osg::ref_ptr<osg::Group> cameraRoot,
|
osg::ref_ptr<osg::Group> cameraRoot,
|
||||||
std::string filter,
|
std::string layerName,
|
||||||
LayerConfig config,
|
LayerConfig config,
|
||||||
VRGUIManager* parent)
|
VRGUIManager* parent)
|
||||||
: mConfig(config)
|
: mConfig(config)
|
||||||
, mFilter(filter)
|
, mLayerName(layerName)
|
||||||
, mGeometryRoot(geometryRoot)
|
, mGeometryRoot(geometryRoot)
|
||||||
, mCameraRoot(cameraRoot)
|
, mCameraRoot(cameraRoot)
|
||||||
{
|
{
|
||||||
|
@ -176,6 +176,9 @@ VRGUILayer::VRGUILayer(
|
||||||
mGeometry->setName("VRGUILayer");
|
mGeometry->setName("VRGUILayer");
|
||||||
|
|
||||||
// Create the camera that will render the menu texture
|
// Create the camera that will render the menu texture
|
||||||
|
std::string filter = mLayerName;
|
||||||
|
if (!mConfig.extraLayers.empty())
|
||||||
|
filter = filter + ";" + mConfig.extraLayers;
|
||||||
mGUICamera = new GUICamera(config.pixelResolution.x(), config.pixelResolution.y(), config.backgroundColor);
|
mGUICamera = new GUICamera(config.pixelResolution.x(), config.pixelResolution.y(), config.backgroundColor);
|
||||||
osgMyGUI::RenderManager& renderManager = static_cast<osgMyGUI::RenderManager&>(MyGUI::RenderManager::getInstance());
|
osgMyGUI::RenderManager& renderManager = static_cast<osgMyGUI::RenderManager&>(MyGUI::RenderManager::getInstance());
|
||||||
mMyGUICamera = renderManager.createGUICamera(osg::Camera::NESTED_RENDER, filter);
|
mMyGUICamera = renderManager.createGUICamera(osg::Camera::NESTED_RENDER, filter);
|
||||||
|
@ -201,8 +204,10 @@ VRGUILayer::VRGUILayer(
|
||||||
mCameraRoot->addChild(mGUICamera);
|
mCameraRoot->addChild(mGUICamera);
|
||||||
|
|
||||||
// Edit offset to account for priority
|
// Edit offset to account for priority
|
||||||
if(!mConfig.sideBySide)
|
if (!mConfig.sideBySide)
|
||||||
|
{
|
||||||
mConfig.offset.y() -= 0.001f * mConfig.priority;
|
mConfig.offset.y() -= 0.001f * mConfig.priority;
|
||||||
|
}
|
||||||
|
|
||||||
mTransform->addUpdateCallback(new LayerUpdateCallback(this));
|
mTransform->addUpdateCallback(new LayerUpdateCallback(this));
|
||||||
}
|
}
|
||||||
|
@ -302,7 +307,7 @@ void VRGUILayer::updateRect()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some widgets don't capture the full visual
|
// Some widgets don't capture the full visual
|
||||||
if (mFilter == "JournalBooks" || mFilter == "MessageBox" )
|
if (mLayerName == "JournalBooks" )
|
||||||
{
|
{
|
||||||
mRealRect.left = 0.f;
|
mRealRect.left = 0.f;
|
||||||
mRealRect.top = 0.f;
|
mRealRect.top = 0.f;
|
||||||
|
@ -310,7 +315,7 @@ void VRGUILayer::updateRect()
|
||||||
mRealRect.bottom = 1.f;
|
mRealRect.bottom = 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mFilter == "Notification")
|
if (mLayerName == "Notification")
|
||||||
{
|
{
|
||||||
// The latest widget for notification is always the top one
|
// The latest widget for notification is always the top one
|
||||||
// So we just have to stretch the rectangle to the bottom
|
// So we just have to stretch the rectangle to the bottom
|
||||||
|
@ -357,7 +362,7 @@ void VRGUILayer::update()
|
||||||
{
|
{
|
||||||
mTransform->setScale(osg::Vec3(w / res, 1.f, h / res));
|
mTransform->setScale(osg::Vec3(w / res, 1.f, h / res));
|
||||||
}
|
}
|
||||||
if (mFilter == "Notification")
|
if (mLayerName == "Notification")
|
||||||
{
|
{
|
||||||
auto viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
auto viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
h = (1.f - mRealRect.top) * viewSize.height;
|
h = (1.f - mRealRect.top) * viewSize.height;
|
||||||
|
@ -421,44 +426,28 @@ VRGUIManager::~VRGUIManager(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRGUIManager::showGUIs(bool show)
|
static const LayerConfig createDefaultConfig(int priority, bool background = true, SizingMode sizingMode = SizingMode::Auto)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const LayerConfig createDefaultConfig(int priority)
|
|
||||||
{
|
{
|
||||||
return LayerConfig{
|
return LayerConfig{
|
||||||
1,
|
priority,
|
||||||
false, // side-by-side
|
false, // side-by-side
|
||||||
osg::Vec4{0.f,0.f,0.f,.75f}, // background
|
background ? osg::Vec4{0.f,0.f,0.f,.75f} : osg::Vec4{}, // background
|
||||||
osg::Vec3(0.f,0.66f,-.25f), // offset
|
osg::Vec3(0.f,0.66f,-.25f), // offset
|
||||||
osg::Vec2(0.f,0.f), // center (model space)
|
osg::Vec2(0.f,0.f), // center (model space)
|
||||||
osg::Vec2(1.f, 1.f), // extent (meters)
|
osg::Vec2(1.f, 1.f), // extent (meters)
|
||||||
1024, // Spatial resolution (pixels per meter)
|
1024, // Spatial resolution (pixels per meter)
|
||||||
osg::Vec2i(2048,2048), // Texture resolution
|
osg::Vec2i(2048,2048), // Texture resolution
|
||||||
osg::Vec2(1,1),
|
osg::Vec2(1,1),
|
||||||
SizingMode::Auto,
|
sizingMode,
|
||||||
TrackingMode::Menu
|
TrackingMode::Menu,
|
||||||
|
"Popup"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
LayerConfig gDefaultConfig = createDefaultConfig(1);
|
LayerConfig gDefaultConfig = createDefaultConfig(1);
|
||||||
LayerConfig gJournalBooksConfig = LayerConfig
|
LayerConfig gJournalBooksConfig = createDefaultConfig(2, false, SizingMode::Fixed);
|
||||||
{
|
LayerConfig gDefaultWindowsConfig = createDefaultConfig(3, true);
|
||||||
2,
|
LayerConfig gMessageBoxConfig = createDefaultConfig(6, false, SizingMode::Auto);;
|
||||||
gDefaultConfig.sideBySide,
|
LayerConfig gNotificationConfig = createDefaultConfig(7, false, SizingMode::Fixed);;
|
||||||
osg::Vec4{}, // background
|
|
||||||
gDefaultConfig.offset,
|
|
||||||
gDefaultConfig.center,
|
|
||||||
gDefaultConfig.extent,
|
|
||||||
gDefaultConfig.spatialResolution,
|
|
||||||
gDefaultConfig.pixelResolution,
|
|
||||||
gDefaultConfig.myGUIViewSize,
|
|
||||||
SizingMode::Fixed,
|
|
||||||
gDefaultConfig.trackingMode
|
|
||||||
};
|
|
||||||
LayerConfig gDefaultWindowsConfig = createDefaultConfig(3);
|
|
||||||
LayerConfig gMessageBoxConfig = gJournalBooksConfig;
|
|
||||||
LayerConfig gNotificationConfig = gJournalBooksConfig;
|
|
||||||
|
|
||||||
static const float sSideBySideRadius = 1.f;
|
static const float sSideBySideRadius = 1.f;
|
||||||
static const float sSideBySideAzimuthInterval = -osg::PI_4;
|
static const float sSideBySideAzimuthInterval = -osg::PI_4;
|
||||||
|
@ -475,7 +464,8 @@ static const LayerConfig createSideBySideConfig(int priority)
|
||||||
gDefaultConfig.pixelResolution,
|
gDefaultConfig.pixelResolution,
|
||||||
osg::Vec2(0.70f, 0.70f),
|
osg::Vec2(0.70f, 0.70f),
|
||||||
SizingMode::Fixed,
|
SizingMode::Fixed,
|
||||||
gDefaultConfig.trackingMode
|
gDefaultConfig.trackingMode,
|
||||||
|
""
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -499,6 +489,7 @@ LayerConfig gStatusHUDConfig = LayerConfig
|
||||||
gDefaultConfig.myGUIViewSize,
|
gDefaultConfig.myGUIViewSize,
|
||||||
SizingMode::Auto,
|
SizingMode::Auto,
|
||||||
TrackingMode::HudLeftHand,
|
TrackingMode::HudLeftHand,
|
||||||
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
LayerConfig gPopupConfig = LayerConfig
|
LayerConfig gPopupConfig = LayerConfig
|
||||||
|
@ -514,6 +505,7 @@ LayerConfig gPopupConfig = LayerConfig
|
||||||
gDefaultConfig.myGUIViewSize,
|
gDefaultConfig.myGUIViewSize,
|
||||||
SizingMode::Auto,
|
SizingMode::Auto,
|
||||||
TrackingMode::HudRightHand,
|
TrackingMode::HudRightHand,
|
||||||
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -521,8 +513,7 @@ LayerConfig gPopupConfig = LayerConfig
|
||||||
static std::map<std::string, LayerConfig&> gLayerConfigs =
|
static std::map<std::string, LayerConfig&> gLayerConfigs =
|
||||||
{
|
{
|
||||||
{"StatusHUD", gStatusHUDConfig},
|
{"StatusHUD", gStatusHUDConfig},
|
||||||
//{"MinimapHUD", gMinimapHUDConfig},
|
{"Tooltip", gPopupConfig},
|
||||||
{"Popup", gPopupConfig},
|
|
||||||
{"JournalBooks", gJournalBooksConfig},
|
{"JournalBooks", gJournalBooksConfig},
|
||||||
{"InventoryCompanionWindow", gInventoryCompanionWindowConfig},
|
{"InventoryCompanionWindow", gInventoryCompanionWindowConfig},
|
||||||
{"InventoryWindow", gInventoryWindowConfig},
|
{"InventoryWindow", gInventoryWindowConfig},
|
||||||
|
@ -532,13 +523,13 @@ static std::map<std::string, LayerConfig&> gLayerConfigs =
|
||||||
{"DialogueWindow", gDialogueWindowConfig},
|
{"DialogueWindow", gDialogueWindowConfig},
|
||||||
{"MessageBox", gMessageBoxConfig},
|
{"MessageBox", gMessageBoxConfig},
|
||||||
{"Windows", gDefaultWindowsConfig},
|
{"Windows", gDefaultWindowsConfig},
|
||||||
{"Notification", gNotificationConfig}
|
{"Notification", gNotificationConfig},
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::set<std::string> layerBlacklist =
|
static std::set<std::string> layerBlacklist =
|
||||||
{
|
{
|
||||||
"Overlay",
|
"Overlay",
|
||||||
"AdditiveOverlay"
|
"AdditiveOverlay",
|
||||||
};
|
};
|
||||||
|
|
||||||
void VRGUIManager::updateSideBySideLayers()
|
void VRGUIManager::updateSideBySideLayers()
|
||||||
|
@ -582,9 +573,6 @@ void VRGUIManager::insertLayer(const std::string& name)
|
||||||
|
|
||||||
layer->mGeometry->setUserData(new VRGUILayerUserData(mLayers[name]));
|
layer->mGeometry->setUserData(new VRGUILayerUserData(mLayers[name]));
|
||||||
|
|
||||||
// Default new layer's pick to false
|
|
||||||
// TODO: re-add widget->setLayerPick(false) somewhere;
|
|
||||||
|
|
||||||
if (config.sideBySide)
|
if (config.sideBySide)
|
||||||
{
|
{
|
||||||
mSideBySideLayers.push_back(layer);
|
mSideBySideLayers.push_back(layer);
|
||||||
|
@ -715,7 +703,7 @@ void VRGUIManager::updateTracking(void)
|
||||||
layer.second->updateTracking(mHeadPose);
|
layer.second->updateTracking(mHeadPose);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRGUIManager::updateFocus()
|
bool VRGUIManager::updateFocus()
|
||||||
{
|
{
|
||||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
||||||
if (anim && anim->mPointerTarget.mHit)
|
if (anim && anim->mPointerTarget.mHit)
|
||||||
|
@ -728,12 +716,14 @@ void VRGUIManager::updateFocus()
|
||||||
newFocusLayer = userData->mLayer.lock();
|
newFocusLayer = userData->mLayer.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFocusLayer && newFocusLayer->mFilter != "Notification")
|
if (newFocusLayer && newFocusLayer->mLayerName != "Notification")
|
||||||
{
|
{
|
||||||
setFocusLayer(newFocusLayer.get());
|
setFocusLayer(newFocusLayer.get());
|
||||||
computeGuiCursor(anim->mPointerTarget.mHitPointLocal);
|
computeGuiCursor(anim->mPointerTarget.mHitPointLocal);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRGUIManager::setFocusLayer(VRGUILayer* layer)
|
void VRGUIManager::setFocusLayer(VRGUILayer* layer)
|
||||||
|
|
|
@ -61,6 +61,7 @@ namespace MWVR
|
||||||
osg::Vec2 myGUIViewSize; //!< Resizable elements are resized to this (fraction of full view)
|
osg::Vec2 myGUIViewSize; //!< Resizable elements are resized to this (fraction of full view)
|
||||||
SizingMode sizingMode; //!< How to size the layer
|
SizingMode sizingMode; //!< How to size the layer
|
||||||
TrackingMode trackingMode; //!< Tracking mode
|
TrackingMode trackingMode; //!< Tracking mode
|
||||||
|
std::string extraLayers; //!< Additional layers to draw (list separated by any non-alphabetic)
|
||||||
|
|
||||||
bool operator<(const LayerConfig& rhs) const { return priority < rhs.priority; }
|
bool operator<(const LayerConfig& rhs) const { return priority < rhs.priority; }
|
||||||
};
|
};
|
||||||
|
@ -71,7 +72,7 @@ namespace MWVR
|
||||||
VRGUILayer(
|
VRGUILayer(
|
||||||
osg::ref_ptr<osg::Group> geometryRoot,
|
osg::ref_ptr<osg::Group> geometryRoot,
|
||||||
osg::ref_ptr<osg::Group> cameraRoot,
|
osg::ref_ptr<osg::Group> cameraRoot,
|
||||||
std::string filter,
|
std::string layerName,
|
||||||
LayerConfig config,
|
LayerConfig config,
|
||||||
VRGUIManager* parent);
|
VRGUIManager* parent);
|
||||||
~VRGUILayer();
|
~VRGUILayer();
|
||||||
|
@ -95,7 +96,7 @@ namespace MWVR
|
||||||
public:
|
public:
|
||||||
Pose mTrackedPose{};
|
Pose mTrackedPose{};
|
||||||
LayerConfig mConfig;
|
LayerConfig mConfig;
|
||||||
std::string mFilter;
|
std::string mLayerName;
|
||||||
std::vector<MWGui::Layout*> mWidgets;
|
std::vector<MWGui::Layout*> mWidgets;
|
||||||
osg::ref_ptr<osg::Group> mGeometryRoot;
|
osg::ref_ptr<osg::Group> mGeometryRoot;
|
||||||
osg::ref_ptr<osg::Geometry> mGeometry{ new osg::Geometry };
|
osg::ref_ptr<osg::Geometry> mGeometry{ new osg::Geometry };
|
||||||
|
@ -123,8 +124,6 @@ namespace MWVR
|
||||||
|
|
||||||
~VRGUIManager(void);
|
~VRGUIManager(void);
|
||||||
|
|
||||||
void showGUIs(bool show);
|
|
||||||
|
|
||||||
void setVisible(MWGui::Layout*, bool visible);
|
void setVisible(MWGui::Layout*, bool visible);
|
||||||
|
|
||||||
void updateSideBySideLayers();
|
void updateSideBySideLayers();
|
||||||
|
@ -139,7 +138,7 @@ namespace MWVR
|
||||||
|
|
||||||
void updateTracking(void);
|
void updateTracking(void);
|
||||||
|
|
||||||
void updateFocus();
|
bool updateFocus();
|
||||||
|
|
||||||
void setFocusLayer(VRGUILayer* layer);
|
void setFocusLayer(VRGUILayer* layer);
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ namespace MWWorld
|
||||||
throw std::runtime_error("class cannot block");
|
throw std::runtime_error("class cannot block");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Class::onHit(const Ptr& ptr, float damage, bool ishealth, const Ptr& object, const Ptr& attacker, const osg::Vec3f& hitPosition, bool successful) const
|
void Class::onHit(const Ptr& ptr, float damage, bool ishealth, const Ptr& object, const Ptr& attacker, const osg::Vec3f& hitPosition, bool successful, float hitStrength) const
|
||||||
{
|
{
|
||||||
throw std::runtime_error("class cannot be hit");
|
throw std::runtime_error("class cannot be hit");
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,11 +131,12 @@ namespace MWWorld
|
||||||
/// @return True if the attack had a victim, regardless if hit was successful or not.
|
/// @return True if the attack had a victim, regardless if hit was successful or not.
|
||||||
/// (default implementation: throw an exception)
|
/// (default implementation: throw an exception)
|
||||||
|
|
||||||
virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) const;
|
virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful, float hitStrength = 0.f) const;
|
||||||
///< Alerts \a ptr that it's being hit for \a damage points to health if \a ishealth is
|
///< Alerts \a ptr that it's being hit for \a damage points to health if \a ishealth is
|
||||||
/// true (else fatigue) by \a object (sword, arrow, etc). \a attacker specifies the
|
/// true (else fatigue) by \a object (sword, arrow, etc). \a attacker specifies the
|
||||||
/// actor responsible for the attack, and \a successful specifies if the hit is
|
/// actor responsible for the attack, and \a successful specifies if the hit is
|
||||||
/// successful or not.
|
/// successful or not. \a hitStrength is the fraction of max attack strength applied, and is
|
||||||
|
/// used to determine haptic feedback intensity.
|
||||||
|
|
||||||
virtual void block (const Ptr& ptr) const;
|
virtual void block (const Ptr& ptr) const;
|
||||||
///< Play the appropriate sound for a blocked attack, depending on the currently equipped shield
|
///< Play the appropriate sound for a blocked attack, depending on the currently equipped shield
|
||||||
|
|
|
@ -277,8 +277,7 @@ namespace MWWorld
|
||||||
#ifdef USE_OPENXR
|
#ifdef USE_OPENXR
|
||||||
if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||||
{
|
{
|
||||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
osg::Matrix worldMatrix = MWVR::Environment::get().getPlayerAnimation()->getWeaponTransformMatrix();
|
||||||
osg::Matrix worldMatrix = osg::computeLocalToWorld(anim->mWeaponDirectionTransform->getParentalNodePaths()[0]);
|
|
||||||
orient = worldMatrix.getRotate();
|
orient = worldMatrix.getRotate();
|
||||||
pos = worldMatrix.getTrans();
|
pos = worldMatrix.getTrans();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1101,7 +1101,8 @@ namespace MWWorld
|
||||||
MWWorld::Ptr World::getFacedObject()
|
MWWorld::Ptr World::getFacedObject()
|
||||||
{
|
{
|
||||||
#ifdef USE_OPENXR
|
#ifdef USE_OPENXR
|
||||||
|
// TODO: Rename this method to getTargetObject?
|
||||||
|
// "getFacedObject" doesn't make sense with finger pointing.
|
||||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
||||||
if (anim && anim->mPointerTarget.mHit)
|
if (anim && anim->mPointerTarget.mHit)
|
||||||
return anim->mPointerTarget.mHitObject;
|
return anim->mPointerTarget.mHitObject;
|
||||||
|
@ -1163,12 +1164,8 @@ namespace MWWorld
|
||||||
if (ptr == getPlayerPtr())
|
if (ptr == getPlayerPtr())
|
||||||
{
|
{
|
||||||
#ifdef USE_OPENXR
|
#ifdef USE_OPENXR
|
||||||
// TODO: Configurable realistic fighting ?
|
|
||||||
|
|
||||||
// Use current aim of weapon to impact
|
// Use current aim of weapon to impact
|
||||||
// TODO: Use bounding box of weapon instead ?
|
osg::Matrix worldMatrix = MWVR::Environment::get().getPlayerAnimation()->getWeaponTransformMatrix();
|
||||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
|
||||||
osg::Matrix worldMatrix = osg::computeLocalToWorld(anim->mWeaponDirectionTransform->getParentalNodePaths()[0]);
|
|
||||||
|
|
||||||
auto result = mPhysics->getHitContact(ptr, worldMatrix.getTrans(), worldMatrix.getRotate(), distance, targets);
|
auto result = mPhysics->getHitContact(ptr, worldMatrix.getTrans(), worldMatrix.getRotate(), distance, targets);
|
||||||
if (!result.first.isEmpty())
|
if (!result.first.isEmpty())
|
||||||
|
@ -3110,8 +3107,7 @@ namespace MWWorld
|
||||||
#ifdef USE_OPENXR
|
#ifdef USE_OPENXR
|
||||||
if (actor == MWMechanics::getPlayer())
|
if (actor == MWMechanics::getPlayer())
|
||||||
{
|
{
|
||||||
auto* anim = MWVR::Environment::get().getPlayerAnimation();
|
osg::Matrix worldMatrix = MWVR::Environment::get().getPlayerAnimation()->getWeaponTransformMatrix();
|
||||||
osg::Matrix worldMatrix = osg::computeLocalToWorld(anim->mWeaponDirectionTransform->getParentalNodePaths()[0]);
|
|
||||||
origin = worldMatrix.getTrans();
|
origin = worldMatrix.getTrans();
|
||||||
orient = worldMatrix.getRotate();
|
orient = worldMatrix.getRotate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -563,8 +563,10 @@ void GUICamera::collectDrawCalls(std::string filter)
|
||||||
auto layer = myGUILayers->getLayer(i);
|
auto layer = myGUILayers->getLayer(i);
|
||||||
auto name = layer->getName();
|
auto name = layer->getName();
|
||||||
|
|
||||||
if (name == filter)
|
if (filter.find(name) != std::string::npos)
|
||||||
|
{
|
||||||
layer->renderToTarget(this, mUpdate);
|
layer->renderToTarget(this, mUpdate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end();
|
end();
|
||||||
|
|
|
@ -92,6 +92,7 @@ set(MYGUI_FILES
|
||||||
openmw_text.skin.xml
|
openmw_text.skin.xml
|
||||||
openmw_text_input.layout
|
openmw_text_input.layout
|
||||||
openmw_tooltips.layout
|
openmw_tooltips.layout
|
||||||
|
openmw_tooltips_vr.layout
|
||||||
openmw_trade_window.layout
|
openmw_trade_window.layout
|
||||||
openmw_trade_window_vr.layout
|
openmw_trade_window_vr.layout
|
||||||
openmw_trainingwindow.layout
|
openmw_trainingwindow.layout
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
</Layer>
|
</Layer>
|
||||||
<Layer name="Debug" overlapped="true" pick="true"/>
|
<Layer name="Debug" overlapped="true" pick="true"/>
|
||||||
<Layer name="Notification" overlapped="false" pick="false"/>
|
<Layer name="Notification" overlapped="false" pick="false"/>
|
||||||
|
<Layer name="Tooltip" overlapped="true" pick="true"/>
|
||||||
<Layer name="Popup" overlapped="true" pick="true"/>
|
<Layer name="Popup" overlapped="true" pick="true"/>
|
||||||
<Layer name="DragAndDrop" overlapped="false" pick="false"/>
|
<Layer name="DragAndDrop" overlapped="false" pick="false"/>
|
||||||
<Layer name="LoadingScreen" overlapped="false" pick="true"/>
|
<Layer name="LoadingScreen" overlapped="false" pick="true"/>
|
||||||
|
|
322
files/mygui/openmw_tooltips_vr.layout
Normal file
322
files/mygui/openmw_tooltips_vr.layout
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<MyGUI type="Layout">
|
||||||
|
<Widget type="Widget" layer="Tooltip" position="0 0 300 300" name="_Main">
|
||||||
|
|
||||||
|
<!-- Dynamically constructed tooltip goes here -->
|
||||||
|
<Widget type="Widget" skin="HUD_Box_NoTransp" position="0 0 300 300" align="Stretch" name="DynamicToolTipBox">
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Text tooltip, one line -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 300 300" align="Stretch" name="TextToolTipOneLine">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="8 8 284 284" align="Left Top" name="TextOneLine">
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Text tooltip, multiline -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 0" align="Stretch" name="TextToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="6"/>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedEditBox" skin="SandText" position="8 8 268 0" align="Left Top" name="Text">
|
||||||
|
<Property key="MultiLine" value="true"/>
|
||||||
|
<Property key="WordWrap" value="true"/>
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Faction tooltip -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 0" align="Stretch" name="FactionToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedEditBox" skin="SandText" position="8 8 436 0" align="Left Top" name="FactionText">
|
||||||
|
<Property key="MultiLine" value="true"/>
|
||||||
|
<Property key="WordWrap" value="true"/>
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Race tooltip -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 56" align="Stretch" name="RaceToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
<Property key="Spacing" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="NormalText" position="8 8 0 18" align="Left Top" name="CenteredCaption">
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedEditBox" skin="SandText" position="8 30 430 18" align="Left Top" name="CenteredCaptionText">
|
||||||
|
<Property key="MultiLine" value="true"/>
|
||||||
|
<Property key="Shrink" value="true"/>
|
||||||
|
<Property key="WordWrap" value="true"/>
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Specialization tooltip -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 56" align="Stretch" name="SpecializationToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="NormalText" position="8 8 140 18" align="Left Top" name="Caption">
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedEditBox" skin="SandText" position="0 30 140 18" align="Left Top" name="ColumnText">
|
||||||
|
<Property key="MultiLine" value="true"/>
|
||||||
|
<Property key="WordWrap" value="true"/>
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Class tooltip -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 78" align="Stretch" name="ClassToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
<Property key="Spacing" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="NormalText" position="8 8 0 18" align="Left Top HStretch" name="ClassName">
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedEditBox" skin="SandText" position="8 30 430 18" align="Left Top" name="ClassDescription">
|
||||||
|
<Property key="MultiLine" value="true"/>
|
||||||
|
<Property key="Shrink" value="true"/>
|
||||||
|
<Property key="WordWrap" value="true"/>
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="8 52 0 18" align="Left Bottom" name="ClassSpecialisation">
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Hand-to-hand tooltip -->
|
||||||
|
<Widget type="HBox" skin="HUD_Box_NoTransp" position="0 0 300 300" align="Stretch" name="HandToHandToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="6"/>
|
||||||
|
|
||||||
|
<Widget type="VBox">
|
||||||
|
<UserString key="VStretch" value="true"/>
|
||||||
|
<Widget type="ImageBox" skin="ImageBox" position="8 8 32 32" align="Left Top" name="HandToHandImage"/>
|
||||||
|
<Widget type="Spacer"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="44 8 248 284" align="Left Top" name="HandToHandText">
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Health/Magicka/Fatigue tooltip -->
|
||||||
|
<Widget type="HBox" skin="HUD_Box_NoTransp" position="0 0 0 0" align="Stretch" name="HealthToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="14"/>
|
||||||
|
<Property key="Spacing" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="VBox">
|
||||||
|
<UserString key="VStretch" value="true"/>
|
||||||
|
<Widget type="ImageBox" skin="ImageBox" position="8 8 32 32" align="Left Top" name="HealthImage"/>
|
||||||
|
<Widget type="Spacer"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedEditBox" skin="SandText" position="44 8 392 0" align="Left Top" name="HealthDescription">
|
||||||
|
<Property key="MultiLine" value="true"/>
|
||||||
|
<Property key="Shrink" value="true"/>
|
||||||
|
<Property key="WordWrap" value="true"/>
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Attribute tooltip -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 0" align="Stretch" name="AttributeToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
<Property key="Spacing" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="HBox">
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
<Property key="Spacing" value="8"/>
|
||||||
|
<Widget type="ImageBox" skin="ImageBox" position="8 8 32 32" align="Left Top" name="AttributeImage"/>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="NormalText" position="44 8 0 32" align="Left Top" name="AttributeName">
|
||||||
|
<Property key="TextAlign" value="Left VCenter"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedEditBox" skin="SandText" position="8 44 436 248" align="Left Top" name="AttributeDescription">
|
||||||
|
<Property key="MultiLine" value="true"/>
|
||||||
|
<Property key="Shrink" value="true"/>
|
||||||
|
<Property key="WordWrap" value="true"/>
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Skill tooltip -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 98" align="Stretch" name="SkillToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="HBox">
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
<Property key="Spacing" value="8"/>
|
||||||
|
<Widget type="ImageBox" skin="ImageBox" position="8 8 32 32" align="Left Top" name="SkillImage"/>
|
||||||
|
|
||||||
|
<Widget type="VBox">
|
||||||
|
<Widget type="AutoSizedTextBox" skin="NormalText" position="44 8 0 16" align="Left Top" name="SkillName">
|
||||||
|
<Property key="TextAlign" value="Left"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="44 24 0 16" align="Left Top" name="SkillAttribute">
|
||||||
|
<Property key="TextAlign" value="Left"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="Widget" skin="" position="0 0 0 2" align="Left Top" />
|
||||||
|
|
||||||
|
<Widget type="AutoSizedEditBox" skin="SandText" position="8 44 430 0" align="Left Top" name="SkillDescription">
|
||||||
|
<Property key="MultiLine" value="true"/>
|
||||||
|
<Property key="Shrink" value="true"/>
|
||||||
|
<Property key="WordWrap" value="true"/>
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
<Property key="Spacing" value="28"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="Widget" skin="" position="0 0 0 2" align="Left Top" />
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="8 48 200 18" align="Left Bottom" name="SkillMaxed">
|
||||||
|
<Property key="Caption" value="#{sSkillMaxReached}"/>
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="VBox" name="SkillProgressVBox">
|
||||||
|
<Widget type="AutoSizedTextBox" skin="NormalText" position="8 48 200 18" align="Left Bottom">
|
||||||
|
<Property key="Caption" value="#{sSkillProgress}"/>
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="ProgressBar" skin="MW_Progress_Red" position="50 70 200 20" align="HCenter Bottom" name="SkillProgress">
|
||||||
|
<Widget type="TextBox" skin="ProgressText" position="0 0 200 16" align="Stretch" name="SkillProgressText">
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Skill tooltip (without progress bar) -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 52" align="Stretch" name="SkillNoProgressToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="HBox">
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
<Property key="Spacing" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="ImageBox" skin="ImageBox" position="8 8 32 32" align="Left Top" name="SkillNoProgressImage"/>
|
||||||
|
|
||||||
|
<Widget type="VBox">
|
||||||
|
<Widget type="AutoSizedEditBox" skin="NormalText" position="44 8 0 16" align="Left Top" name="SkillNoProgressName">
|
||||||
|
<Property key="TextAlign" value="Left"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="44 24 0 16" align="Left Top" name="SkillNoProgressAttribute">
|
||||||
|
<Property key="TextAlign" value="Left"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="Widget" skin="" position="0 0 0 2" align="Left Top" />
|
||||||
|
|
||||||
|
<Widget type="AutoSizedEditBox" skin="SandText" position="8 44 430 0" align="Left Top" name="SkillNoProgressDescription">
|
||||||
|
<Property key="MultiLine" value="true"/>
|
||||||
|
<Property key="WordWrap" value="true"/>
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
<Property key="Spacing" value="28"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Level tooltip -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 300 58" align="HStretch" name="LevelToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="NormalText" position="8 8 284 18" align="Left Top">
|
||||||
|
<Property key="Caption" value="#{sLevelProgress}"/>
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="ProgressBar" skin="MW_Progress_Red" position="50 30 180 20" align="HCenter Bottom" name="LevelProgress">
|
||||||
|
<Widget type="TextBox" skin="ProgressText" position="0 0 180 20" align="HCenter" name="LevelProgressText">
|
||||||
|
<Property key="TextAlign" value="HCenter Top"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Birthsign tooltip -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 300 300" align="Stretch" name="BirthSignToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
|
||||||
|
<!-- Birthsign image -->
|
||||||
|
<Widget type="Widget" skin="MW_Box" position="18 13 263 137" align="Top HCenter">
|
||||||
|
<Widget type="ImageBox" skin="ImageBox" position="2 2 259 133" name="BirthSignImage" align="Left Top"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="NormalText" position="8 154 284 138" align="Top" name="BirthSignText">
|
||||||
|
<Property key="TextAlign" value="Top HCenter"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Magic effect tooltip -->
|
||||||
|
<Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 0" align="Stretch" name="MagicEffectToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="HBox">
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
<Property key="Spacing" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="ImageBox" skin="ImageBox" position="8 8 32 32" align="Left Top" name="MagicEffectImage"/>
|
||||||
|
|
||||||
|
<Widget type="VBox">
|
||||||
|
<Widget type="AutoSizedTextBox" skin="NormalText" position="44 8 404 16" align="Left Top" name="MagicEffectName">
|
||||||
|
<Property key="TextAlign" value="Left"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="44 24 404 16" align="Left Top" name="MagicEffectSchool">
|
||||||
|
<Property key="TextAlign" value="Left"/>
|
||||||
|
<UserString key="HStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedEditBox" skin="SandText" position="8 44 436 0" align="Left Top" name="MagicEffectDescription">
|
||||||
|
<Property key="MultiLine" value="true"/>
|
||||||
|
<Property key="WordWrap" value="true"/>
|
||||||
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
</Widget>
|
||||||
|
</MyGUI>
|
||||||
|
|
Loading…
Reference in a new issue