mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-04 03:40:14 +00:00
Merge branch 'master' into HEAD
This commit is contained in:
commit
cb0a609d59
@ -98,6 +98,7 @@
|
||||
Bug #4984: "Friendly hits" feature should be used only for player's followers
|
||||
Bug #4989: Object dimension-dependent VFX scaling behavior is inconsistent
|
||||
Bug #4990: Dead bodies prevent you from hitting
|
||||
Bug #4991: Jumping occasionally takes too much fatigue
|
||||
Bug #4999: Drop instruction behaves differently from vanilla
|
||||
Bug #5001: Possible data race in the Animation::setAlpha()
|
||||
Bug #5004: Werewolves shield their eyes during storm
|
||||
@ -115,11 +116,13 @@
|
||||
Bug #5069: Blocking creatures' attacks doesn't degrade shields
|
||||
Bug #5074: Paralyzed actors greet the player
|
||||
Bug #5075: Enchanting cast style can be changed if there's no object
|
||||
Bug #5078: DisablePlayerLooking is broken
|
||||
Bug #5082: Scrolling with controller in GUI mode is broken
|
||||
Bug #5089: Swimming/Underwater creatures only swim around ground level
|
||||
Bug #5092: NPCs with enchanted weapons play sound when out of charges
|
||||
Bug #5093: Hand to hand sound plays on knocked out enemies
|
||||
Bug #5099: Non-swimming enemies will enter water if player is water walking
|
||||
Bug #5103: Sneaking state behavior is still inconsistent
|
||||
Bug #5104: Black Dart's enchantment doesn't trigger at low Enchant levels
|
||||
Bug #5105: NPCs start combat with werewolves from any distance
|
||||
Bug #5106: Still can jump even when encumbered
|
||||
@ -127,6 +130,9 @@
|
||||
Bug #5112: Insufficient magicka for current spell not reflected on HUD icon
|
||||
Bug #5123: Script won't run on respawn
|
||||
Bug #5124: Arrow remains attached to actor if pulling animation was cancelled
|
||||
Bug #5126: Swimming creatures without RunForward animations are motionless during combat
|
||||
Bug #5134: Doors rotation by "Lock" console command is inconsistent
|
||||
Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries
|
||||
Feature #1774: Handle AvoidNode
|
||||
Feature #2229: Improve pathfinding AI
|
||||
Feature #3025: Analogue gamepad movement controls
|
||||
@ -147,6 +153,7 @@
|
||||
Feature #4812: Support NiSwitchNode
|
||||
Feature #4836: Daytime node switch
|
||||
Feature #4859: Make water reflections more configurable
|
||||
Feature #4882: Support for NiPalette node
|
||||
Feature #4887: Add openmw command option to set initial random seed
|
||||
Feature #4890: Make Distant Terrain configurable
|
||||
Feature #4958: Support eight blood types
|
||||
@ -162,6 +169,7 @@
|
||||
Feature #5036: Allow scripted faction leaving
|
||||
Feature #5046: Gamepad thumbstick cursor speed
|
||||
Feature #5051: Provide a separate textures for scrollbars
|
||||
Feature #5091: Human-readable light source duration
|
||||
Feature #5094: Unix like console hotkeys
|
||||
Feature #5098: Allow user controller bindings
|
||||
Feature #5121: Handle NiTriStrips and NiTriStripsData
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <components/esm/cellid.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/doorstate.hpp"
|
||||
|
||||
#include "../mwrender/rendermode.hpp"
|
||||
|
||||
@ -407,7 +408,6 @@ namespace MWBase
|
||||
virtual void togglePreviewMode(bool enable) = 0;
|
||||
virtual bool toggleVanityMode(bool enable) = 0;
|
||||
virtual void allowVanityMode(bool allow) = 0;
|
||||
virtual void togglePlayerLooking(bool enable) = 0;
|
||||
virtual void changeVanityModeScale(float factor) = 0;
|
||||
virtual bool vanityRotateCamera(float * rot) = 0;
|
||||
virtual void setCameraDistance(float dist, bool adjust = false, bool override = true)=0;
|
||||
@ -420,7 +420,7 @@ namespace MWBase
|
||||
/// update movement state of a non-teleport door as specified
|
||||
/// @param state see MWClass::setDoorState
|
||||
/// @note throws an exception when invoked on a teleport door
|
||||
virtual void activateDoor(const MWWorld::Ptr& door, int state) = 0;
|
||||
virtual void activateDoor(const MWWorld::Ptr& door, MWWorld::DoorState state) = 0;
|
||||
|
||||
virtual void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr> &actors) = 0; ///< get a list of actors standing on \a object
|
||||
virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is standing on \a object
|
||||
|
@ -103,7 +103,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
|
||||
std::string text;
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
|
@ -105,7 +105,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
@ -211,7 +211,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
@ -121,7 +121,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
@ -169,7 +169,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
@ -271,7 +271,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||
|
||||
std::string text;
|
||||
int lockLevel = ptr.getCellRef().getLockLevel();
|
||||
|
@ -586,7 +586,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||
|
||||
std::string text;
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
|
@ -34,7 +34,7 @@ namespace MWClass
|
||||
class DoorCustomData : public MWWorld::CustomData
|
||||
{
|
||||
public:
|
||||
int mDoorState; // 0 = nothing, 1 = opening, 2 = closing
|
||||
MWWorld::DoorState mDoorState;
|
||||
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
|
||||
@ -71,7 +71,7 @@ namespace MWClass
|
||||
if (ptr.getRefData().getCustomData())
|
||||
{
|
||||
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
||||
if (customData.mDoorState > 0)
|
||||
if (customData.mDoorState != MWWorld::DoorState::Idle)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState);
|
||||
}
|
||||
@ -201,12 +201,12 @@ namespace MWClass
|
||||
{
|
||||
// animated door
|
||||
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionDoor(ptr));
|
||||
int doorstate = getDoorState(ptr);
|
||||
const auto doorState = getDoorState(ptr);
|
||||
bool opening = true;
|
||||
float doorRot = ptr.getRefData().getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2];
|
||||
if (doorstate == 1)
|
||||
if (doorState == MWWorld::DoorState::Opening)
|
||||
opening = false;
|
||||
if (doorstate == 0 && doorRot != 0)
|
||||
if (doorState == MWWorld::DoorState::Idle && doorRot != 0)
|
||||
opening = false;
|
||||
|
||||
if (opening)
|
||||
@ -293,7 +293,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||
|
||||
std::string text;
|
||||
|
||||
@ -365,20 +365,20 @@ namespace MWClass
|
||||
{
|
||||
std::unique_ptr<DoorCustomData> data(new DoorCustomData);
|
||||
|
||||
data->mDoorState = 0;
|
||||
data->mDoorState = MWWorld::DoorState::Idle;
|
||||
ptr.getRefData().setCustomData(data.release());
|
||||
}
|
||||
}
|
||||
|
||||
int Door::getDoorState (const MWWorld::ConstPtr &ptr) const
|
||||
MWWorld::DoorState Door::getDoorState (const MWWorld::ConstPtr &ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
return 0;
|
||||
return MWWorld::DoorState::Idle;
|
||||
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
||||
return customData.mDoorState;
|
||||
}
|
||||
|
||||
void Door::setDoorState (const MWWorld::Ptr &ptr, int state) const
|
||||
void Door::setDoorState (const MWWorld::Ptr &ptr, MWWorld::DoorState state) const
|
||||
{
|
||||
if (ptr.getCellRef().getTeleport())
|
||||
throw std::runtime_error("load doors can't be moved");
|
||||
@ -396,7 +396,7 @@ namespace MWClass
|
||||
DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
||||
|
||||
const ESM::DoorState& state2 = dynamic_cast<const ESM::DoorState&>(state);
|
||||
customData.mDoorState = state2.mDoorState;
|
||||
customData.mDoorState = static_cast<MWWorld::DoorState>(state2.mDoorState);
|
||||
}
|
||||
|
||||
void Door::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
|
||||
@ -409,7 +409,7 @@ namespace MWClass
|
||||
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
||||
|
||||
ESM::DoorState& state2 = dynamic_cast<ESM::DoorState&>(state);
|
||||
state2.mDoorState = customData.mDoorState;
|
||||
state2.mDoorState = static_cast<int>(customData.mDoorState);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -59,10 +59,9 @@ namespace MWClass
|
||||
|
||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||
|
||||
/// 0 = nothing, 1 = opening, 2 = closing
|
||||
virtual int getDoorState (const MWWorld::ConstPtr &ptr) const;
|
||||
virtual MWWorld::DoorState getDoorState (const MWWorld::ConstPtr &ptr) const;
|
||||
/// This does not actually cause the door to move. Use World::activateDoor instead.
|
||||
virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const;
|
||||
virtual void setDoorState (const MWWorld::Ptr &ptr, MWWorld::DoorState state) const;
|
||||
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
|
@ -117,7 +117,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
@ -151,18 +151,14 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
||||
if (Settings::Manager::getBool("show effect duration","Game"))
|
||||
{
|
||||
// -1 is infinite light source, so duration makes no sense here. Other negative values are treated as 0.
|
||||
float remainingTime = ptr.getClass().getRemainingUsageTime(ptr);
|
||||
if (remainingTime != -1.0f)
|
||||
text += "\n#{sDuration}: " + MWGui::ToolTips::toString(std::max(0.f, remainingTime));
|
||||
}
|
||||
// Don't show duration for infinite light sources.
|
||||
if (Settings::Manager::getBool("show effect duration","Game") && ptr.getClass().getRemainingUsageTime(ptr) != -1)
|
||||
text += MWGui::ToolTips::getDurationString(ptr.getClass().getRemainingUsageTime(ptr), "\n#{sDuration}");
|
||||
|
||||
text += MWGui::ToolTips::getWeightString(ref->mBase->mData.mWeight, "#{sWeight}");
|
||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||
|
@ -116,7 +116,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
@ -159,7 +159,7 @@ namespace MWClass
|
||||
else // gold displays its count also if it's 1.
|
||||
countString = " (" + std::to_string(count) + ")";
|
||||
|
||||
info.caption = ref->mBase->mName + countString;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + countString;
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
if (ref->mRef.getSoul() != "")
|
||||
|
@ -940,10 +940,9 @@ namespace MWClass
|
||||
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
|
||||
|
||||
bool swimming = world->isSwimming(ptr);
|
||||
bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
|
||||
bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||
bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr);
|
||||
bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||
sneaking = sneaking && (inair || MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr));
|
||||
bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||
running = running && (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
|
||||
|
||||
float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()*
|
||||
@ -1071,11 +1070,11 @@ namespace MWClass
|
||||
bool fullHelp = MWBase::Environment::get().getWindowManager()->getFullHelp();
|
||||
MWGui::ToolTipInfo info;
|
||||
|
||||
info.caption = getName(ptr);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr));
|
||||
if(fullHelp && ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf())
|
||||
{
|
||||
info.caption += " (";
|
||||
info.caption += ref->mBase->mName;
|
||||
info.caption += MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||
info.caption += ")";
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
@ -116,7 +116,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
@ -117,7 +117,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
@ -168,7 +168,7 @@ namespace MWClass
|
||||
const ESM::WeaponType* weaponType = MWMechanics::getWeaponType(ref->mBase->mData.mType);
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
@ -137,27 +137,8 @@ namespace MWGui
|
||||
MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") );
|
||||
}
|
||||
}
|
||||
if (effectInfo.mRemainingTime > -1 &&
|
||||
Settings::Manager::getBool("show effect duration","Game")) {
|
||||
sourcesDescription += " #{sDuration}: ";
|
||||
float duration = effectInfo.mRemainingTime;
|
||||
if (duration > 3600)
|
||||
{
|
||||
int hour = duration / 3600;
|
||||
duration -= hour*3600;
|
||||
sourcesDescription += MWGui::ToolTips::toString(hour) + "h";
|
||||
}
|
||||
if (duration > 60)
|
||||
{
|
||||
int minute = duration / 60;
|
||||
duration -= minute*60;
|
||||
sourcesDescription += MWGui::ToolTips::toString(minute) + "m";
|
||||
}
|
||||
if (duration > 0.1)
|
||||
{
|
||||
sourcesDescription += MWGui::ToolTips::toString(duration) + "s";
|
||||
}
|
||||
}
|
||||
if (effectInfo.mRemainingTime > -1 && Settings::Manager::getBool("show effect duration","Game"))
|
||||
sourcesDescription += MWGui::ToolTips::getDurationString(effectInfo.mRemainingTime, " #{sDuration}");
|
||||
|
||||
addNewLine = true;
|
||||
}
|
||||
|
@ -667,6 +667,60 @@ namespace MWGui
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string ToolTips::getDurationString(float duration, const std::string& prefix)
|
||||
{
|
||||
std::string ret;
|
||||
ret = prefix + ": ";
|
||||
|
||||
if (duration < 1.f)
|
||||
{
|
||||
ret += "0 s";
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr int secondsPerMinute = 60; // 60 seconds
|
||||
constexpr int secondsPerHour = secondsPerMinute * 60; // 60 minutes
|
||||
constexpr int secondsPerDay = secondsPerHour * 24; // 24 hours
|
||||
constexpr int secondsPerMonth = secondsPerDay * 30; // 30 days
|
||||
constexpr int secondsPerYear = secondsPerDay * 365;
|
||||
int fullDuration = static_cast<int>(duration);
|
||||
int units = 0;
|
||||
int years = fullDuration / secondsPerYear;
|
||||
int months = fullDuration % secondsPerYear / secondsPerMonth;
|
||||
int days = fullDuration % secondsPerYear % secondsPerMonth / secondsPerDay; // Because a year is not exactly 12 "months"
|
||||
int hours = fullDuration % secondsPerDay / secondsPerHour;
|
||||
int minutes = fullDuration % secondsPerHour / secondsPerMinute;
|
||||
int seconds = fullDuration % secondsPerMinute;
|
||||
if (years)
|
||||
{
|
||||
units++;
|
||||
ret += toString(years) + " y ";
|
||||
}
|
||||
if (months)
|
||||
{
|
||||
units++;
|
||||
ret += toString(months) + " mo ";
|
||||
}
|
||||
if (units < 2 && days)
|
||||
{
|
||||
units++;
|
||||
ret += toString(days) + " d ";
|
||||
}
|
||||
if (units < 2 && hours)
|
||||
{
|
||||
units++;
|
||||
ret += toString(hours) + " h ";
|
||||
}
|
||||
if (units >= 2)
|
||||
return ret;
|
||||
if (minutes)
|
||||
ret += toString(minutes) + " min ";
|
||||
if (seconds)
|
||||
ret += toString(seconds) + " s ";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ToolTips::toggleFullHelp()
|
||||
{
|
||||
mFullHelp = !mFullHelp;
|
||||
|
@ -84,6 +84,9 @@ namespace MWGui
|
||||
static std::string getCellRefString(const MWWorld::CellRef& cellref);
|
||||
///< Returns a string containing debug tooltip information about the given cellref.
|
||||
|
||||
static std::string getDurationString (float duration, const std::string& prefix);
|
||||
///< Returns duration as two largest time units, rounded down. Note: not localized; no line break.
|
||||
|
||||
// these do not create an actual tooltip, but they fill in the data that is required so the tooltip
|
||||
// system knows what to show in case this widget is hovered
|
||||
static void createSkillToolTip(MyGUI::Widget* widget, int skillId);
|
||||
|
@ -202,6 +202,11 @@ namespace MWInput
|
||||
|
||||
void InputManager::handleGuiArrowKey(int action)
|
||||
{
|
||||
// This is currently keyboard-specific code
|
||||
// TODO: see if GUI controls can be refactored into a single function
|
||||
if (mJoystickLastUsed)
|
||||
return;
|
||||
|
||||
if (SDL_IsTextInputActive())
|
||||
return;
|
||||
|
||||
@ -229,13 +234,10 @@ namespace MWInput
|
||||
MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false);
|
||||
}
|
||||
|
||||
bool InputManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg, bool release=false)
|
||||
bool InputManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg)
|
||||
{
|
||||
// Presumption of GUI mode will be removed in the future.
|
||||
// MyGUI KeyCodes *may* change.
|
||||
// Currently button releases are ignored.
|
||||
if (release)
|
||||
return false;
|
||||
|
||||
MyGUI::KeyCode key = MyGUI::KeyCode::None;
|
||||
switch (arg.button)
|
||||
@ -386,9 +388,6 @@ namespace MWInput
|
||||
case A_GameMenu:
|
||||
toggleMainMenu ();
|
||||
break;
|
||||
case A_OptionsMenu:
|
||||
toggleOptionsMenu();
|
||||
break;
|
||||
case A_Screenshot:
|
||||
screenshot();
|
||||
break;
|
||||
@ -406,8 +405,7 @@ namespace MWInput
|
||||
case A_MoveRight:
|
||||
case A_MoveForward:
|
||||
case A_MoveBackward:
|
||||
// Temporary shut-down of this function until deemed necessary.
|
||||
//handleGuiArrowKey(action);
|
||||
handleGuiArrowKey(action);
|
||||
break;
|
||||
case A_Journal:
|
||||
toggleJournal ();
|
||||
@ -594,7 +592,7 @@ namespace MWInput
|
||||
rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertX ? -1 : 1);
|
||||
|
||||
// Only actually turn player when we're not in vanity mode
|
||||
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
||||
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && mControlSwitch["playerlooking"])
|
||||
{
|
||||
mPlayer->yaw(rot[2]);
|
||||
mPlayer->pitch(rot[0]);
|
||||
@ -832,9 +830,6 @@ namespace MWInput
|
||||
|
||||
void InputManager::toggleControlSwitch (const std::string& sw, bool value)
|
||||
{
|
||||
if (mControlSwitch[sw] == value) {
|
||||
return;
|
||||
}
|
||||
/// \note 7 switches at all, if-else is relevant
|
||||
if (sw == "playercontrols" && !value) {
|
||||
mPlayer->setLeftRight(0);
|
||||
@ -846,8 +841,8 @@ namespace MWInput
|
||||
mPlayer->setUpDown(0);
|
||||
} else if (sw == "vanitymode") {
|
||||
MWBase::Environment::get().getWorld()->allowVanityMode(value);
|
||||
} else if (sw == "playerlooking") {
|
||||
MWBase::Environment::get().getWorld()->togglePlayerLooking(value);
|
||||
} else if (sw == "playerlooking" && !value) {
|
||||
MWBase::Environment::get().getWorld()->rotateObject(mPlayer->getPlayer(), 0.f, 0.f, 0.f);
|
||||
}
|
||||
mControlSwitch[sw] = value;
|
||||
}
|
||||
@ -981,7 +976,7 @@ namespace MWInput
|
||||
rot[2] = -x;
|
||||
|
||||
// Only actually turn player when we're not in vanity mode
|
||||
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
||||
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && mControlSwitch["playerlooking"])
|
||||
{
|
||||
mPlayer->yaw(x);
|
||||
mPlayer->pitch(y);
|
||||
@ -1005,9 +1000,9 @@ namespace MWInput
|
||||
mJoystickLastUsed = true;
|
||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
{
|
||||
if (gamepadToGuiControl(arg, false))
|
||||
if (gamepadToGuiControl(arg))
|
||||
return;
|
||||
else if (mGamepadGuiCursorEnabled)
|
||||
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.
|
||||
@ -1048,9 +1043,7 @@ namespace MWInput
|
||||
mJoystickLastUsed = true;
|
||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
{
|
||||
if (gamepadToGuiControl(arg, true))
|
||||
return;
|
||||
else if (mGamepadGuiCursorEnabled)
|
||||
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.
|
||||
@ -1149,37 +1142,19 @@ namespace MWInput
|
||||
}
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||
return;
|
||||
|
||||
bool inGame = MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame;
|
||||
MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode();
|
||||
|
||||
if ((inGame && mode == MWGui::GM_MainMenu) || mode == MWGui::GM_Settings)
|
||||
MWBase::Environment::get().getWindowManager()->popGuiMode();
|
||||
|
||||
if (inGame && mode != MWGui::GM_MainMenu)
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_MainMenu);
|
||||
}
|
||||
|
||||
void InputManager::toggleOptionsMenu()
|
||||
{
|
||||
if (MyGUI::InputManager::getInstance().isModalAny())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->exitCurrentModal();
|
||||
MWBase::Environment::get().getWindowManager()->toggleConsole();
|
||||
return;
|
||||
}
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||
return;
|
||||
|
||||
MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode();
|
||||
bool inGame = MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame;
|
||||
|
||||
if ((inGame && mode == MWGui::GM_MainMenu) || mode == MWGui::GM_Settings)
|
||||
MWBase::Environment::get().getWindowManager()->popGuiMode();
|
||||
|
||||
if (inGame && mode != MWGui::GM_Settings)
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Settings);
|
||||
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 InputManager::quickLoad() {
|
||||
@ -1534,7 +1509,6 @@ namespace MWInput
|
||||
defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
||||
defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B;
|
||||
defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START;
|
||||
defaultButtonBindings[A_OptionsMenu] = SDL_CONTROLLER_BUTTON_BACK;
|
||||
defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE;
|
||||
defaultButtonBindings[A_MoveForward] = SDL_CONTROLLER_BUTTON_DPAD_UP;
|
||||
defaultButtonBindings[A_MoveLeft] = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
|
||||
@ -1615,7 +1589,6 @@ namespace MWInput
|
||||
descriptions[A_Journal] = "sJournal";
|
||||
descriptions[A_Rest] = "sRestKey";
|
||||
descriptions[A_Inventory] = "sInventory";
|
||||
descriptions[A_OptionsMenu] = "sPreferences";
|
||||
descriptions[A_TogglePOV] = "sTogglePOVCmd";
|
||||
descriptions[A_QuickKeysMenu] = "sQuickMenu";
|
||||
descriptions[A_QuickKey1] = "sQuick1Cmd";
|
||||
@ -1753,7 +1726,6 @@ namespace MWInput
|
||||
ret.push_back(A_Inventory);
|
||||
ret.push_back(A_Journal);
|
||||
ret.push_back(A_Rest);
|
||||
ret.push_back(A_OptionsMenu);
|
||||
ret.push_back(A_Console);
|
||||
ret.push_back(A_QuickSave);
|
||||
ret.push_back(A_QuickLoad);
|
||||
@ -1786,7 +1758,6 @@ namespace MWInput
|
||||
ret.push_back(A_Inventory);
|
||||
ret.push_back(A_Journal);
|
||||
ret.push_back(A_Rest);
|
||||
ret.push_back(A_OptionsMenu);
|
||||
ret.push_back(A_QuickSave);
|
||||
ret.push_back(A_QuickLoad);
|
||||
ret.push_back(A_Screenshot);
|
||||
|
@ -226,7 +226,7 @@ namespace MWInput
|
||||
void setPlayerControlsEnabled(bool enabled);
|
||||
void handleGuiArrowKey(int action);
|
||||
// Return true if GUI consumes input.
|
||||
bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg, bool release);
|
||||
bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg);
|
||||
bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg);
|
||||
|
||||
void updateCursorMode();
|
||||
@ -235,7 +235,6 @@ namespace MWInput
|
||||
|
||||
private:
|
||||
void toggleMainMenu();
|
||||
void toggleOptionsMenu();
|
||||
void toggleSpell();
|
||||
void toggleWeapon();
|
||||
void toggleInventory();
|
||||
@ -328,8 +327,6 @@ namespace MWInput
|
||||
A_MoveForwardBackward,
|
||||
A_MoveLeftRight,
|
||||
|
||||
A_OptionsMenu,
|
||||
|
||||
A_Last // Marker for the last item
|
||||
};
|
||||
};
|
||||
|
@ -1785,14 +1785,7 @@ namespace MWMechanics
|
||||
|
||||
MWWorld::Ptr player = getPlayer();
|
||||
|
||||
CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
|
||||
bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||
bool inair = !world->isOnGround(player) && !world->isSwimming(player) && !world->isFlying(player);
|
||||
sneaking = sneaking && (ctrl->isSneaking() || inair);
|
||||
|
||||
if (!sneaking)
|
||||
if (!MWBase::Environment::get().getMechanicsManager()->isSneaking(player))
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
|
||||
return;
|
||||
@ -1800,6 +1793,7 @@ namespace MWMechanics
|
||||
|
||||
static float sneakSkillTimer = 0.f; // Times sneak skill progress from "avoid notice"
|
||||
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::Store<ESM::GameSetting>& gmst = world->getStore().get<ESM::GameSetting>();
|
||||
static const float fSneakUseDist = gmst.find("fSneakUseDist")->mValue.getFloat();
|
||||
static const float fSneakUseDelay = gmst.find("fSneakUseDelay")->mValue.getFloat();
|
||||
|
@ -44,7 +44,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
|
||||
return true; // We have tried backing up for more than one second, we've probably cleared it
|
||||
}
|
||||
|
||||
if (!mDoorPtr.getClass().getDoorState(mDoorPtr))
|
||||
if (mDoorPtr.getClass().getDoorState(mDoorPtr) == MWWorld::DoorState::Idle)
|
||||
return true; //Door is no longer opening
|
||||
|
||||
ESM::Position tPos = mDoorPtr.getRefData().getPosition(); //Position of the door
|
||||
|
@ -232,7 +232,7 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor)
|
||||
return;
|
||||
|
||||
// note: AiWander currently does not open doors
|
||||
if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0)
|
||||
if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle)
|
||||
{
|
||||
if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 ))
|
||||
{
|
||||
|
@ -529,19 +529,7 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
|
||||
if(!mAnimation->hasAnimation(movementAnimName))
|
||||
{
|
||||
std::string::size_type swimpos = movementAnimName.find("swim");
|
||||
if(swimpos == std::string::npos)
|
||||
{
|
||||
std::string::size_type runpos = movementAnimName.find("run");
|
||||
if (runpos != std::string::npos)
|
||||
{
|
||||
movementAnimName.replace(runpos, runpos+3, "walk");
|
||||
if (!mAnimation->hasAnimation(movementAnimName))
|
||||
movementAnimName.clear();
|
||||
}
|
||||
else
|
||||
movementAnimName.clear();
|
||||
}
|
||||
else
|
||||
if (swimpos != std::string::npos)
|
||||
{
|
||||
movementAnimName.erase(swimpos, 4);
|
||||
if (!weapShortGroup.empty())
|
||||
@ -552,8 +540,18 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
|
||||
else
|
||||
movementAnimName = fallbackShortWeaponGroup(movementAnimName, &movemask);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mAnimation->hasAnimation(movementAnimName))
|
||||
if (swimpos == std::string::npos || !mAnimation->hasAnimation(movementAnimName))
|
||||
{
|
||||
std::string::size_type runpos = movementAnimName.find("run");
|
||||
if (runpos != std::string::npos)
|
||||
{
|
||||
movementAnimName.replace(runpos, runpos+3, "walk");
|
||||
if (!mAnimation->hasAnimation(movementAnimName))
|
||||
movementAnimName.clear();
|
||||
}
|
||||
else
|
||||
movementAnimName.clear();
|
||||
}
|
||||
}
|
||||
@ -570,10 +568,6 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
|
||||
mCurrentMovement = movementAnimName;
|
||||
if(!mCurrentMovement.empty())
|
||||
{
|
||||
bool isflying = MWBase::Environment::get().getWorld()->isFlying(mPtr);
|
||||
bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) && !isflying;
|
||||
bool issneaking = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak) && !isflying;
|
||||
|
||||
// For non-flying creatures, MW uses the Walk animation to calculate the animation velocity
|
||||
// even if we are running. This must be replicated, otherwise the observed speed would differ drastically.
|
||||
std::string anim = mCurrentMovement;
|
||||
@ -606,7 +600,7 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
|
||||
// The first person anims don't have any velocity to calculate a speed multiplier from.
|
||||
// We use the third person velocities instead.
|
||||
// FIXME: should be pulled from the actual animation, but it is not presently loaded.
|
||||
mMovementAnimSpeed = (issneaking ? 33.5452f : (isrunning ? 222.857f : 154.064f));
|
||||
mMovementAnimSpeed = (isSneaking() ? 33.5452f : (isRunning() ? 222.857f : 154.064f));
|
||||
mMovementAnimationControlled = false;
|
||||
}
|
||||
}
|
||||
@ -2048,28 +2042,6 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||
lat.normalize();
|
||||
vec = osg::Vec3f(lat.x(), lat.y(), 1.0f) * z * 0.707f;
|
||||
}
|
||||
|
||||
// advance acrobatics
|
||||
// also set jumping flag to allow GetPCJumping works
|
||||
if (isPlayer)
|
||||
{
|
||||
cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0);
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setJumping(true);
|
||||
}
|
||||
|
||||
// decrease fatigue
|
||||
const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat();
|
||||
const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat();
|
||||
float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr);
|
||||
if (normalizedEncumbrance > 1)
|
||||
normalizedEncumbrance = 1;
|
||||
const float fatigueDecrease = fatigueJumpBase + normalizedEncumbrance * fatigueJumpMult;
|
||||
|
||||
if (!godmode)
|
||||
{
|
||||
fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease);
|
||||
cls.getCreatureStats(mPtr).setFatigue(fatigue);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(mJumpState == JumpState_InAir && !inwater && !flying && solid)
|
||||
@ -2282,7 +2254,9 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||
|
||||
movement = vec;
|
||||
cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = 0;
|
||||
// Can't reset jump state (mPosition[2]) here; we don't know for sure whether the PhysicSystem will actually handle it in this frame
|
||||
if (movement.z() == 0.f)
|
||||
cls.getMovementSettings(mPtr).mPosition[2] = 0;
|
||||
// Can't reset jump state (mPosition[2]) here in full; we don't know for sure whether the PhysicSystem will actually handle it in this frame
|
||||
// due to the fixed minimum timestep used for the physics update. It will be reset in PhysicSystem::move once the jump is handled.
|
||||
|
||||
if (!mSkipAnim)
|
||||
|
@ -477,7 +477,12 @@ namespace MWMechanics
|
||||
|
||||
bool MechanicsManager::isSneaking(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
return mActors.isSneaking(ptr);
|
||||
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
bool animActive = mActors.isSneaking(ptr);
|
||||
bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
|
||||
return stanceOn && (animActive || inair);
|
||||
}
|
||||
|
||||
void MechanicsManager::rest(double hours, bool sleep)
|
||||
@ -965,8 +970,7 @@ namespace MWMechanics
|
||||
return true;
|
||||
|
||||
// check if a player tries to pickpocket a target NPC
|
||||
if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak)
|
||||
|| target.getClass().getCreatureStats(target).getKnockedDown())
|
||||
if (target.getClass().getCreatureStats(target).getKnockedDown() || isSneaking(ptr))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -1586,9 +1590,7 @@ namespace MWMechanics
|
||||
return false;
|
||||
|
||||
float sneakTerm = 0;
|
||||
if (ptr.getClass().getCreatureStats(ptr).getStance(CreatureStats::Stance_Sneak)
|
||||
&& !MWBase::Environment::get().getWorld()->isSwimming(ptr)
|
||||
&& MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
||||
if (isSneaking(ptr))
|
||||
{
|
||||
static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat();
|
||||
static float fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat();
|
||||
@ -1596,7 +1598,7 @@ namespace MWMechanics
|
||||
int agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||
int luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float bootWeight = 0;
|
||||
if (ptr.getClass().isNpc())
|
||||
if (ptr.getClass().isNpc() && MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
||||
{
|
||||
const MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
||||
MWWorld::ConstContainerStoreIterator it = inv.getSlot(MWWorld::InventoryStore::Slot_Boots);
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
|
||||
@ -54,10 +52,10 @@ namespace MWMechanics
|
||||
// FIXME: cast
|
||||
const MWWorld::Ptr doorPtr = MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door> &>(ref), actor.getCell());
|
||||
|
||||
int doorState = doorPtr.getClass().getDoorState(doorPtr);
|
||||
const auto doorState = doorPtr.getClass().getDoorState(doorPtr);
|
||||
float doorRot = ref.mData.getPosition().rot[2] - doorPtr.getCellRef().getPosition().rot[2];
|
||||
|
||||
if (doorState != 0 || doorRot != 0)
|
||||
if (doorState != MWWorld::DoorState::Idle || doorRot != 0)
|
||||
continue; // the door is already opened/opening
|
||||
|
||||
doorPos.z() = 0;
|
||||
@ -78,10 +76,8 @@ namespace MWMechanics
|
||||
return MWWorld::Ptr(); // none found
|
||||
}
|
||||
|
||||
ObstacleCheck::ObstacleCheck():
|
||||
mPrevX(0) // to see if the moved since last time
|
||||
, mPrevY(0)
|
||||
, mWalkState(State_Norm)
|
||||
ObstacleCheck::ObstacleCheck()
|
||||
: mWalkState(State_Norm)
|
||||
, mStuckDuration(0)
|
||||
, mEvadeDuration(0)
|
||||
, mDistSameSpot(-1) // avoid calculating it each time
|
||||
@ -125,21 +121,15 @@ namespace MWMechanics
|
||||
*/
|
||||
void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration)
|
||||
{
|
||||
const ESM::Position pos = actor.getRefData().getPosition();
|
||||
const osg::Vec3f pos = actor.getRefData().getPosition().asVec3();
|
||||
|
||||
if (mDistSameSpot == -1)
|
||||
{
|
||||
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor);
|
||||
mDistSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor) + 1.2 * std::max(halfExtents.x(), halfExtents.y());
|
||||
}
|
||||
mDistSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor);
|
||||
|
||||
const float distSameSpot = mDistSameSpot * duration;
|
||||
const float squaredMovedDistance = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2();
|
||||
const bool samePosition = squaredMovedDistance < distSameSpot * distSameSpot;
|
||||
const bool samePosition = (pos - mPrev).length2() < distSameSpot * distSameSpot;
|
||||
|
||||
// update position
|
||||
mPrevX = pos.pos[0];
|
||||
mPrevY = pos.pos[1];
|
||||
mPrev = pos;
|
||||
|
||||
switch(mWalkState)
|
||||
{
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef OPENMW_MECHANICS_OBSTACLE_H
|
||||
#define OPENMW_MECHANICS_OBSTACLE_H
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Ptr;
|
||||
@ -37,9 +39,8 @@ namespace MWMechanics
|
||||
|
||||
private:
|
||||
|
||||
// for checking if we're stuck (ignoring Z axis)
|
||||
float mPrevX;
|
||||
float mPrevY;
|
||||
// for checking if we're stuck
|
||||
osg::Vec3f mPrev;
|
||||
|
||||
// directions to try moving in when get stuck
|
||||
static const float evadeDirections[NUM_EVADE_DIRECTIONS][2];
|
||||
|
@ -238,7 +238,7 @@ namespace MWMechanics
|
||||
{
|
||||
/* short group */ "",
|
||||
/* long group */ "",
|
||||
/* sound ID */ "Item Weapon Ammo",
|
||||
/* sound ID */ "Item Ammo",
|
||||
/* attach bone */ "ArrowBone",
|
||||
/* sheath bone */ "",
|
||||
/* usage skill */ ESM::Skill::Marksman,
|
||||
@ -252,7 +252,7 @@ namespace MWMechanics
|
||||
{
|
||||
/* short group */ "",
|
||||
/* long group */ "",
|
||||
/* sound ID */ "Item Weapon Ammo",
|
||||
/* sound ID */ "Item Ammo",
|
||||
/* attach bone */ "ArrowBone",
|
||||
/* sheath bone */ "",
|
||||
/* usage skill */ ESM::Skill::Marksman,
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
#include "../mwrender/bulletdebugdraw.hpp"
|
||||
|
||||
@ -326,7 +327,30 @@ namespace MWPhysics
|
||||
if (movement.z() > 0 && ptr.getClass().getCreatureStats(ptr).isDead() && position.z() < swimlevel)
|
||||
velocity = osg::Vec3f(0,0,1) * 25;
|
||||
|
||||
ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0;
|
||||
if (ptr.getClass().getMovementSettings(ptr).mPosition[2])
|
||||
{
|
||||
const bool isPlayer = (ptr == MWMechanics::getPlayer());
|
||||
// Advance acrobatics and set flag for GetPCJumping
|
||||
if (isPlayer)
|
||||
{
|
||||
ptr.getClass().skillUsageSucceeded(ptr, ESM::Skill::Acrobatics, 0);
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setJumping(true);
|
||||
}
|
||||
|
||||
// Decrease fatigue
|
||||
if (!isPlayer || !MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
{
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
const float fFatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat();
|
||||
const float fFatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat();
|
||||
const float normalizedEncumbrance = std::min(1.f, ptr.getClass().getNormalizedEncumbrance(ptr));
|
||||
const float fatigueDecrease = fFatigueJumpBase + normalizedEncumbrance * fFatigueJumpMult;
|
||||
MWMechanics::DynamicStat<float> fatigue = ptr.getClass().getCreatureStats(ptr).getFatigue();
|
||||
fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease);
|
||||
ptr.getClass().getCreatureStats(ptr).setFatigue(fatigue);
|
||||
}
|
||||
ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0;
|
||||
}
|
||||
|
||||
// Now that we have the effective movement vector, apply wind forces to it
|
||||
if (MWBase::Environment::get().getWorld()->isInStorm())
|
||||
|
@ -64,7 +64,7 @@ ActorAnimation::~ActorAnimation()
|
||||
mScabbard.reset();
|
||||
}
|
||||
|
||||
PartHolderPtr ActorAnimation::getWeaponPart(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor)
|
||||
PartHolderPtr ActorAnimation::attachMesh(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor)
|
||||
{
|
||||
osg::Group* parent = getBoneByName(bonename);
|
||||
if (!parent)
|
||||
@ -160,7 +160,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
||||
if (showHolsteredWeapons)
|
||||
{
|
||||
osg::Vec4f glowColor = weapon->getClass().getEnchantmentColor(*weapon);
|
||||
mScabbard = getWeaponPart(mesh, boneName, isEnchanted, &glowColor);
|
||||
mScabbard = attachMesh(mesh, boneName, isEnchanted, &glowColor);
|
||||
if (mScabbard)
|
||||
resetControllers(mScabbard->getNode());
|
||||
}
|
||||
@ -168,7 +168,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
||||
return;
|
||||
}
|
||||
|
||||
mScabbard = getWeaponPart(scabbardName, boneName);
|
||||
mScabbard = attachMesh(scabbardName, boneName);
|
||||
|
||||
osg::Group* weaponNode = getBoneByName("Bip01 Weapon");
|
||||
if (!weaponNode)
|
||||
|
@ -44,11 +44,11 @@ class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener
|
||||
virtual void updateHolsteredWeapon(bool showHolsteredWeapons);
|
||||
virtual void updateQuiver();
|
||||
virtual std::string getHolsteredWeaponBoneName(const MWWorld::ConstPtr& weapon);
|
||||
virtual PartHolderPtr getWeaponPart(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor);
|
||||
virtual PartHolderPtr getWeaponPart(const std::string& model, const std::string& bonename)
|
||||
virtual PartHolderPtr attachMesh(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor);
|
||||
virtual PartHolderPtr attachMesh(const std::string& model, const std::string& bonename)
|
||||
{
|
||||
osg::Vec4f stubColor = osg::Vec4f(0,0,0,0);
|
||||
return getWeaponPart(model, bonename, false, &stubColor);
|
||||
return attachMesh(model, bonename, false, &stubColor);
|
||||
};
|
||||
|
||||
PartHolderPtr mScabbard;
|
||||
|
@ -18,12 +18,14 @@
|
||||
#include <components/resource/keyframemanager.hpp>
|
||||
|
||||
#include <components/misc/constants.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
|
||||
#include <components/nifosg/nifloader.hpp> // KeyframeHolder
|
||||
#include <components/nifosg/controller.hpp>
|
||||
|
||||
#include <components/vfs/manager.hpp>
|
||||
|
||||
#include <components/sceneutil/actorutil.hpp>
|
||||
#include <components/sceneutil/statesetupdater.hpp>
|
||||
#include <components/sceneutil/visitor.hpp>
|
||||
#include <components/sceneutil/lightmanager.hpp>
|
||||
@ -245,7 +247,10 @@ namespace
|
||||
void apply(osg::Node& node)
|
||||
{
|
||||
if (SceneUtil::hasUserDescription(&node, "CustomBone"))
|
||||
{
|
||||
mFoundBones.emplace_back(&node, node.getParent(0));
|
||||
return;
|
||||
}
|
||||
|
||||
traverse(node);
|
||||
}
|
||||
@ -1378,6 +1383,9 @@ namespace MWRender
|
||||
|
||||
void injectCustomBones(osg::ref_ptr<osg::Node>& node, const std::string& model, Resource::ResourceSystem* resourceSystem)
|
||||
{
|
||||
if (model.empty())
|
||||
return;
|
||||
|
||||
const std::map<std::string, VFS::File*>& index = resourceSystem->getVFS()->getIndex();
|
||||
|
||||
std::string animationPath = model;
|
||||
@ -1405,14 +1413,7 @@ namespace MWRender
|
||||
}
|
||||
}
|
||||
|
||||
enum InjectType
|
||||
{
|
||||
None,
|
||||
Model,
|
||||
ModelWithFallback
|
||||
};
|
||||
|
||||
osg::ref_ptr<osg::Node> getModelInstance(Resource::ResourceSystem* resourceSystem, const std::string& model, bool baseonly, InjectType inject)
|
||||
osg::ref_ptr<osg::Node> getModelInstance(Resource::ResourceSystem* resourceSystem, const std::string& model, bool baseonly, bool inject, const std::string& defaultSkeleton)
|
||||
{
|
||||
Resource::SceneManager* sceneMgr = resourceSystem->getSceneManager();
|
||||
if (baseonly)
|
||||
@ -1424,11 +1425,11 @@ namespace MWRender
|
||||
{
|
||||
osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model);
|
||||
|
||||
if (inject == InjectType::ModelWithFallback)
|
||||
injectCustomBones(created, "meshes\\xbase_anim.nif", resourceSystem);
|
||||
|
||||
if (inject != InjectType::None)
|
||||
if (inject)
|
||||
{
|
||||
injectCustomBones(created, defaultSkeleton, resourceSystem);
|
||||
injectCustomBones(created, model, resourceSystem);
|
||||
}
|
||||
|
||||
SceneUtil::CleanObjectRootVisitor removeDrawableVisitor;
|
||||
created->accept(removeDrawableVisitor);
|
||||
@ -1445,11 +1446,11 @@ namespace MWRender
|
||||
{
|
||||
osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model);
|
||||
|
||||
if (inject == InjectType::ModelWithFallback)
|
||||
injectCustomBones(created, "meshes\\xbase_anim.nif", resourceSystem);
|
||||
|
||||
if (inject != InjectType::None)
|
||||
if (inject)
|
||||
{
|
||||
injectCustomBones(created, defaultSkeleton, resourceSystem);
|
||||
injectCustomBones(created, model, resourceSystem);
|
||||
}
|
||||
|
||||
return created;
|
||||
}
|
||||
@ -1475,17 +1476,44 @@ namespace MWRender
|
||||
mAccumCtrl = nullptr;
|
||||
|
||||
static const bool useAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game");
|
||||
InjectType inject = useAdditionalSources && mPtr.getClass().isActor() ? InjectType::Model : InjectType::None;
|
||||
if (inject != InjectType::None && isCreature)
|
||||
std::string defaultSkeleton;
|
||||
bool inject = false;
|
||||
|
||||
if (useAdditionalSources && mPtr.getClass().isActor())
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
||||
if(ref->mBase->mFlags & ESM::Creature::Bipedal)
|
||||
inject = InjectType::ModelWithFallback;
|
||||
if (isCreature)
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
||||
if(ref->mBase->mFlags & ESM::Creature::Bipedal)
|
||||
{
|
||||
defaultSkeleton = "meshes\\xbase_anim.nif";
|
||||
inject = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inject = true;
|
||||
MWWorld::LiveCellRef<ESM::NPC> *ref = mPtr.get<ESM::NPC>();
|
||||
if (!ref->mBase->mModel.empty())
|
||||
{
|
||||
// If NPC has a custom animation model attached, we should inject bones from default skeleton for given race and gender as well
|
||||
// Since it is a quite rare case, there should not be a noticable performance loss
|
||||
// Note: consider that player and werewolves have no custom animation files attached for now
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
const ESM::Race *race = store.get<ESM::Race>().find(ref->mBase->mRace);
|
||||
|
||||
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
||||
bool isFemale = !ref->mBase->isMale();
|
||||
|
||||
defaultSkeleton = SceneUtil::getActorSkeleton(false, isFemale, isBeast, false);
|
||||
defaultSkeleton = Misc::ResourceHelpers::correctActorModelPath(defaultSkeleton, mResourceSystem->getVFS());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!forceskeleton)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem, model, baseonly, inject);
|
||||
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem, model, baseonly, inject, defaultSkeleton);
|
||||
mInsert->addChild(created);
|
||||
mObjectRoot = created->asGroup();
|
||||
if (!mObjectRoot)
|
||||
@ -1501,7 +1529,7 @@ namespace MWRender
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem, model, baseonly, inject);
|
||||
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem, model, baseonly, inject, defaultSkeleton);
|
||||
osg::ref_ptr<SceneUtil::Skeleton> skel = dynamic_cast<SceneUtil::Skeleton*>(created.get());
|
||||
if (!skel)
|
||||
{
|
||||
|
@ -48,7 +48,6 @@ namespace MWRender
|
||||
mAnimation(nullptr),
|
||||
mFirstPersonView(true),
|
||||
mPreviewMode(false),
|
||||
mFreeLook(true),
|
||||
mNearest(30.f),
|
||||
mFurthest(800.f),
|
||||
mIsNearest(false),
|
||||
@ -393,11 +392,6 @@ namespace MWRender
|
||||
camera = focal + offset;
|
||||
}
|
||||
|
||||
void Camera::togglePlayerLooking(bool enable)
|
||||
{
|
||||
mFreeLook = enable;
|
||||
}
|
||||
|
||||
bool Camera::isVanityOrPreviewModeEnabled()
|
||||
{
|
||||
return mPreviewMode || mVanity.enabled;
|
||||
|
@ -37,7 +37,6 @@ namespace MWRender
|
||||
|
||||
bool mFirstPersonView;
|
||||
bool mPreviewMode;
|
||||
bool mFreeLook;
|
||||
float mNearest;
|
||||
float mFurthest;
|
||||
bool mIsNearest;
|
||||
@ -119,8 +118,6 @@ namespace MWRender
|
||||
/// Stores focal and camera world positions in passed arguments
|
||||
void getPosition(osg::Vec3f &focal, osg::Vec3f &camera);
|
||||
|
||||
void togglePlayerLooking(bool enable);
|
||||
|
||||
bool isVanityOrPreviewModeEnabled();
|
||||
|
||||
bool isNearest();
|
||||
|
@ -1353,11 +1353,6 @@ namespace MWRender
|
||||
mCamera->allowVanityMode(allow);
|
||||
}
|
||||
|
||||
void RenderingManager::togglePlayerLooking(bool enable)
|
||||
{
|
||||
mCamera->togglePlayerLooking(enable);
|
||||
}
|
||||
|
||||
void RenderingManager::changeVanityModeScale(float factor)
|
||||
{
|
||||
if(mCamera->isVanityOrPreviewModeEnabled())
|
||||
|
@ -208,7 +208,6 @@ namespace MWRender
|
||||
void togglePreviewMode(bool enable);
|
||||
bool toggleVanityMode(bool enable);
|
||||
void allowVanityMode(bool allow);
|
||||
void togglePlayerLooking(bool enable);
|
||||
void changeVanityModeScale(float factor);
|
||||
|
||||
/// temporarily override the field of view with given value.
|
||||
|
@ -186,14 +186,7 @@ namespace MWScript
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
|
||||
bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||
bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
|
||||
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
|
||||
|
||||
runtime.push(stanceOn && (sneaking || inair));
|
||||
runtime.push(MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -188,13 +188,7 @@ namespace MWScript
|
||||
// This is done when using Lock in scripts, but not when using Lock spells.
|
||||
if (ptr.getTypeName() == typeid(ESM::Door).name() && !ptr.getCellRef().getTeleport())
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->activateDoor(ptr, 0);
|
||||
|
||||
float xr = ptr.getCellRef().getPosition().rot[0];
|
||||
float yr = ptr.getCellRef().getPosition().rot[1];
|
||||
float zr = ptr.getCellRef().getPosition().rot[2];
|
||||
|
||||
MWBase::Environment::get().getWorld()->rotateObject(ptr, xr, yr, zr);
|
||||
MWBase::Environment::get().getWorld()->activateDoor(ptr, MWWorld::DoorState::Idle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -798,7 +798,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
|
||||
if(alGetError() == AL_NO_ERROR)
|
||||
Log(Debug::Info) << "Standard Reverb supported";
|
||||
}
|
||||
EFXEAXREVERBPROPERTIES props = EFX_REVERB_PRESET_GENERIC;
|
||||
EFXEAXREVERBPROPERTIES props = EFX_REVERB_PRESET_LIVINGROOM;
|
||||
props.flGain = 0.0f;
|
||||
LoadEffect(mDefaultEffect, props);
|
||||
}
|
||||
|
@ -460,12 +460,12 @@ namespace MWWorld
|
||||
return false;
|
||||
}
|
||||
|
||||
int Class::getDoorState (const MWWorld::ConstPtr &ptr) const
|
||||
MWWorld::DoorState Class::getDoorState (const MWWorld::ConstPtr &ptr) const
|
||||
{
|
||||
throw std::runtime_error("this is not a door");
|
||||
}
|
||||
|
||||
void Class::setDoorState (const MWWorld::Ptr &ptr, int state) const
|
||||
void Class::setDoorState (const MWWorld::Ptr &ptr, MWWorld::DoorState state) const
|
||||
{
|
||||
throw std::runtime_error("this is not a door");
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <osg/Vec4f>
|
||||
|
||||
#include "ptr.hpp"
|
||||
#include "doorstate.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -298,7 +299,7 @@ namespace MWWorld
|
||||
|
||||
virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const { return true; }
|
||||
///< Return whether this class of object can be activated with telekinesis
|
||||
|
||||
|
||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;
|
||||
|
||||
@ -350,10 +351,9 @@ namespace MWWorld
|
||||
|
||||
virtual bool isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const;
|
||||
|
||||
/// 0 = nothing, 1 = opening, 2 = closing
|
||||
virtual int getDoorState (const MWWorld::ConstPtr &ptr) const;
|
||||
virtual DoorState getDoorState (const MWWorld::ConstPtr &ptr) const;
|
||||
/// This does not actually cause the door to move. Use World::activateDoor instead.
|
||||
virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const;
|
||||
virtual void setDoorState (const MWWorld::Ptr &ptr, DoorState state) const;
|
||||
|
||||
virtual void respawn (const MWWorld::Ptr& ptr) const {}
|
||||
|
||||
|
14
apps/openmw/mwworld/doorstate.hpp
Normal file
14
apps/openmw/mwworld/doorstate.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef GAME_MWWORLD_DOORSTATE_H
|
||||
#define GAME_MWWORLD_DOORSTATE_H
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
enum class DoorState
|
||||
{
|
||||
Idle = 0,
|
||||
Opening = 1,
|
||||
Closing = 2,
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1458,6 +1458,9 @@ namespace MWWorld
|
||||
{
|
||||
mRendering->rotateObject(ptr, rotate);
|
||||
mPhysics->updateRotation(ptr);
|
||||
|
||||
if (const auto object = mPhysics->getObject(ptr))
|
||||
updateNavigatorObject(object);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1614,9 +1617,48 @@ namespace MWWorld
|
||||
return result.mHit;
|
||||
}
|
||||
|
||||
bool World::rotateDoor(const Ptr door, MWWorld::DoorState state, float duration)
|
||||
{
|
||||
const ESM::Position& objPos = door.getRefData().getPosition();
|
||||
float oldRot = objPos.rot[2];
|
||||
|
||||
float minRot = door.getCellRef().getPosition().rot[2];
|
||||
float maxRot = minRot + osg::DegreesToRadians(90.f);
|
||||
|
||||
float diff = duration * osg::DegreesToRadians(90.f);
|
||||
float targetRot = std::min(std::max(minRot, oldRot + diff * (state == MWWorld::DoorState::Opening ? 1 : -1)), maxRot);
|
||||
rotateObject(door, objPos.rot[0], objPos.rot[1], targetRot);
|
||||
|
||||
bool reached = (targetRot == maxRot && state != MWWorld::DoorState::Idle) || targetRot == minRot;
|
||||
|
||||
/// \todo should use convexSweepTest here
|
||||
std::vector<MWWorld::Ptr> collisions = mPhysics->getCollisions(door, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor);
|
||||
for (MWWorld::Ptr& ptr : collisions)
|
||||
{
|
||||
if (ptr.getClass().isActor())
|
||||
{
|
||||
// Collided with actor, ask actor to try to avoid door
|
||||
if(ptr != getPlayerPtr() )
|
||||
{
|
||||
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
||||
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once
|
||||
seq.stack(MWMechanics::AiAvoidDoor(door),ptr);
|
||||
}
|
||||
|
||||
// we need to undo the rotation
|
||||
rotateObject(door, objPos.rot[0], objPos.rot[1], oldRot);
|
||||
reached = false;
|
||||
}
|
||||
}
|
||||
|
||||
// the rotation order we want to use
|
||||
mWorldScene->updateObjectRotation(door, false);
|
||||
return reached;
|
||||
}
|
||||
|
||||
void World::processDoors(float duration)
|
||||
{
|
||||
std::map<MWWorld::Ptr, int>::iterator it = mDoorStates.begin();
|
||||
auto it = mDoorStates.begin();
|
||||
while (it != mDoorStates.end())
|
||||
{
|
||||
if (!mWorldScene->isCellActive(*it->first.getCell()) || !it->first.getRefData().getBaseNode())
|
||||
@ -1628,45 +1670,12 @@ namespace MWWorld
|
||||
}
|
||||
else
|
||||
{
|
||||
const ESM::Position& objPos = it->first.getRefData().getPosition();
|
||||
float oldRot = objPos.rot[2];
|
||||
|
||||
float minRot = it->first.getCellRef().getPosition().rot[2];
|
||||
float maxRot = minRot + osg::DegreesToRadians(90.f);
|
||||
|
||||
float diff = duration * osg::DegreesToRadians(90.f);
|
||||
float targetRot = std::min(std::max(minRot, oldRot + diff * (it->second == 1 ? 1 : -1)), maxRot);
|
||||
rotateObject(it->first, objPos.rot[0], objPos.rot[1], targetRot);
|
||||
|
||||
bool reached = (targetRot == maxRot && it->second) || targetRot == minRot;
|
||||
|
||||
/// \todo should use convexSweepTest here
|
||||
std::vector<MWWorld::Ptr> collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor);
|
||||
for (MWWorld::Ptr& ptr : collisions)
|
||||
{
|
||||
if (ptr.getClass().isActor())
|
||||
{
|
||||
// Collided with actor, ask actor to try to avoid door
|
||||
if(ptr != getPlayerPtr() )
|
||||
{
|
||||
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
||||
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once
|
||||
seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr);
|
||||
}
|
||||
|
||||
// we need to undo the rotation
|
||||
rotateObject(it->first, objPos.rot[0], objPos.rot[1], oldRot);
|
||||
reached = false;
|
||||
}
|
||||
}
|
||||
|
||||
// the rotation order we want to use
|
||||
mWorldScene->updateObjectRotation(it->first, false);
|
||||
bool reached = rotateDoor(it->first, it->second, duration);
|
||||
|
||||
if (reached)
|
||||
{
|
||||
// Mark as non-moving
|
||||
it->first.getClass().setDoorState(it->first, 0);
|
||||
it->first.getClass().setDoorState(it->first, MWWorld::DoorState::Idle);
|
||||
mDoorStates.erase(it++);
|
||||
}
|
||||
else
|
||||
@ -2389,11 +2398,6 @@ namespace MWWorld
|
||||
mRendering->allowVanityMode(allow);
|
||||
}
|
||||
|
||||
void World::togglePlayerLooking(bool enable)
|
||||
{
|
||||
mRendering->togglePlayerLooking(enable);
|
||||
}
|
||||
|
||||
void World::changeVanityModeScale(float factor)
|
||||
{
|
||||
mRendering->changeVanityModeScale(factor);
|
||||
@ -2506,33 +2510,36 @@ namespace MWWorld
|
||||
|
||||
void World::activateDoor(const MWWorld::Ptr& door)
|
||||
{
|
||||
int state = door.getClass().getDoorState(door);
|
||||
auto state = door.getClass().getDoorState(door);
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
case MWWorld::DoorState::Idle:
|
||||
if (door.getRefData().getPosition().rot[2] == door.getCellRef().getPosition().rot[2])
|
||||
state = 1; // if closed, then open
|
||||
state = MWWorld::DoorState::Opening; // if closed, then open
|
||||
else
|
||||
state = 2; // if open, then close
|
||||
state = MWWorld::DoorState::Closing; // if open, then close
|
||||
break;
|
||||
case 2:
|
||||
state = 1; // if closing, then open
|
||||
case MWWorld::DoorState::Closing:
|
||||
state = MWWorld::DoorState::Opening; // if closing, then open
|
||||
break;
|
||||
case 1:
|
||||
case MWWorld::DoorState::Opening:
|
||||
default:
|
||||
state = 2; // if opening, then close
|
||||
state = MWWorld::DoorState::Closing; // if opening, then close
|
||||
break;
|
||||
}
|
||||
door.getClass().setDoorState(door, state);
|
||||
mDoorStates[door] = state;
|
||||
}
|
||||
|
||||
void World::activateDoor(const Ptr &door, int state)
|
||||
void World::activateDoor(const Ptr &door, MWWorld::DoorState state)
|
||||
{
|
||||
door.getClass().setDoorState(door, state);
|
||||
mDoorStates[door] = state;
|
||||
if (state == 0)
|
||||
if (state == MWWorld::DoorState::Idle)
|
||||
{
|
||||
mDoorStates.erase(door);
|
||||
rotateDoor(door, state, 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool World::getPlayerStandingOn (const MWWorld::ConstPtr& object)
|
||||
|
@ -118,7 +118,7 @@ namespace MWWorld
|
||||
|
||||
int mActivationDistanceOverride;
|
||||
|
||||
std::map<MWWorld::Ptr, int> mDoorStates;
|
||||
std::map<MWWorld::Ptr, MWWorld::DoorState> mDoorStates;
|
||||
///< only holds doors that are currently moving. 1 = opening, 2 = closing
|
||||
|
||||
std::string mStartCell;
|
||||
@ -146,6 +146,8 @@ namespace MWWorld
|
||||
private:
|
||||
void PCDropped (const Ptr& item);
|
||||
|
||||
bool rotateDoor(const Ptr door, DoorState state, float duration);
|
||||
|
||||
void processDoors(float duration);
|
||||
///< Run physics simulation and modify \a world accordingly.
|
||||
|
||||
@ -526,8 +528,6 @@ namespace MWWorld
|
||||
|
||||
void allowVanityMode(bool allow) override;
|
||||
|
||||
void togglePlayerLooking(bool enable) override;
|
||||
|
||||
void changeVanityModeScale(float factor) override;
|
||||
|
||||
bool vanityRotateCamera(float * rot) override;
|
||||
@ -542,7 +542,7 @@ namespace MWWorld
|
||||
/// update movement state of a non-teleport door as specified
|
||||
/// @param state see MWClass::setDoorState
|
||||
/// @note throws an exception when invoked on a teleport door
|
||||
void activateDoor(const MWWorld::Ptr& door, int state) override;
|
||||
void activateDoor(const MWWorld::Ptr& door, MWWorld::DoorState state) override;
|
||||
|
||||
void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr> &actors) override; ///< get a list of actors standing on \a object
|
||||
bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object
|
||||
|
@ -163,22 +163,23 @@ void NiPixelData::read(NIFStream *nif)
|
||||
{
|
||||
fmt = (Format)nif->getUInt();
|
||||
|
||||
rmask = nif->getInt(); // usually 0xff
|
||||
gmask = nif->getInt(); // usually 0xff00
|
||||
bmask = nif->getInt(); // usually 0xff0000
|
||||
amask = nif->getInt(); // usually 0xff000000 or zero
|
||||
rmask = nif->getUInt(); // usually 0xff
|
||||
gmask = nif->getUInt(); // usually 0xff00
|
||||
bmask = nif->getUInt(); // usually 0xff0000
|
||||
amask = nif->getUInt(); // usually 0xff000000 or zero
|
||||
|
||||
bpp = nif->getInt();
|
||||
bpp = nif->getUInt();
|
||||
|
||||
// Unknown
|
||||
nif->skip(12);
|
||||
// 8 bytes of "Old Fast Compare". Whatever that means.
|
||||
nif->skip(8);
|
||||
palette.read(nif);
|
||||
|
||||
numberOfMipmaps = nif->getInt();
|
||||
numberOfMipmaps = nif->getUInt();
|
||||
|
||||
// Bytes per pixel, should be bpp * 8
|
||||
/* int bytes = */ nif->getInt();
|
||||
/* int bytes = */ nif->getUInt();
|
||||
|
||||
for(int i=0; i<numberOfMipmaps; i++)
|
||||
for(unsigned int i=0; i<numberOfMipmaps; i++)
|
||||
{
|
||||
// Image size and offset in the following data field
|
||||
Mipmap m;
|
||||
@ -189,12 +190,17 @@ void NiPixelData::read(NIFStream *nif)
|
||||
}
|
||||
|
||||
// Read the data
|
||||
unsigned int dataSize = nif->getInt();
|
||||
unsigned int dataSize = nif->getUInt();
|
||||
data.reserve(dataSize);
|
||||
for (unsigned i=0; i<dataSize; ++i)
|
||||
data.push_back((unsigned char)nif->getChar());
|
||||
}
|
||||
|
||||
void NiPixelData::post(NIFFile *nif)
|
||||
{
|
||||
palette.post(nif);
|
||||
}
|
||||
|
||||
void NiColorData::read(NIFStream *nif)
|
||||
{
|
||||
mKeyMap = std::make_shared<Vector4KeyMap>();
|
||||
@ -278,4 +284,14 @@ void NiKeyframeData::read(NIFStream *nif)
|
||||
mScales->read(nif);
|
||||
}
|
||||
|
||||
void NiPalette::read(NIFStream *nif)
|
||||
{
|
||||
unsigned int alphaMask = !nif->getChar() ? 0xFF000000 : 0;
|
||||
// Fill the entire palette with black even if there isn't enough entries.
|
||||
colors.resize(256);
|
||||
unsigned int numEntries = nif->getUInt();
|
||||
for (unsigned int i = 0; i < numEntries; i++)
|
||||
colors[i] = nif->getUInt() | alphaMask;
|
||||
}
|
||||
|
||||
} // Namespace
|
||||
|
@ -116,6 +116,7 @@ public:
|
||||
NIPXFMT_RGB8,
|
||||
NIPXFMT_RGBA8,
|
||||
NIPXFMT_PAL8,
|
||||
NIPXFMT_PALA8,
|
||||
NIPXFMT_DXT1,
|
||||
NIPXFMT_DXT3,
|
||||
NIPXFMT_DXT5,
|
||||
@ -123,8 +124,10 @@ public:
|
||||
};
|
||||
Format fmt;
|
||||
|
||||
unsigned int rmask, gmask, bmask, amask;
|
||||
int bpp, numberOfMipmaps;
|
||||
unsigned int rmask, gmask, bmask, amask, bpp;
|
||||
|
||||
NiPalettePtr palette;
|
||||
unsigned int numberOfMipmaps;
|
||||
|
||||
struct Mipmap
|
||||
{
|
||||
@ -136,6 +139,7 @@ public:
|
||||
std::vector<unsigned char> data;
|
||||
|
||||
void read(NIFStream *nif);
|
||||
void post(NIFFile *nif);
|
||||
};
|
||||
|
||||
class NiColorData : public Record
|
||||
@ -219,5 +223,14 @@ struct NiKeyframeData : public Record
|
||||
void read(NIFStream *nif);
|
||||
};
|
||||
|
||||
class NiPalette : public Record
|
||||
{
|
||||
public:
|
||||
// 32-bit RGBA colors that correspond to 8-bit indices
|
||||
std::vector<unsigned int> colors;
|
||||
|
||||
void read(NIFStream *nif);
|
||||
};
|
||||
|
||||
} // Namespace
|
||||
#endif
|
||||
|
@ -112,6 +112,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
|
||||
newFactory.insert(makeEntry("NiSourceTexture", &construct <NiSourceTexture> , RC_NiSourceTexture ));
|
||||
newFactory.insert(makeEntry("NiSkinInstance", &construct <NiSkinInstance> , RC_NiSkinInstance ));
|
||||
newFactory.insert(makeEntry("NiLookAtController", &construct <NiLookAtController> , RC_NiLookAtController ));
|
||||
newFactory.insert(makeEntry("NiPalette", &construct <NiPalette> , RC_NiPalette ));
|
||||
return newFactory;
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,8 @@ enum RecordType
|
||||
RC_NiSkinInstance,
|
||||
RC_RootCollisionNode,
|
||||
RC_NiSphericalCollider,
|
||||
RC_NiLookAtController
|
||||
RC_NiLookAtController,
|
||||
RC_NiPalette
|
||||
};
|
||||
|
||||
/// Base class for all records
|
||||
|
@ -140,6 +140,7 @@ class NiSkinInstance;
|
||||
class NiSourceTexture;
|
||||
class NiRotatingParticlesData;
|
||||
class NiAutoNormalParticlesData;
|
||||
class NiPalette;
|
||||
|
||||
typedef RecordPtrT<Node> NodePtr;
|
||||
typedef RecordPtrT<Extra> ExtraPtr;
|
||||
@ -160,6 +161,7 @@ typedef RecordPtrT<NiSkinInstance> NiSkinInstancePtr;
|
||||
typedef RecordPtrT<NiSourceTexture> NiSourceTexturePtr;
|
||||
typedef RecordPtrT<NiRotatingParticlesData> NiRotatingParticlesDataPtr;
|
||||
typedef RecordPtrT<NiAutoNormalParticlesData> NiAutoNormalParticlesDataPtr;
|
||||
typedef RecordPtrT<NiPalette> NiPalettePtr;
|
||||
|
||||
typedef RecordListT<Node> NodeList;
|
||||
typedef RecordListT<Property> PropertyList;
|
||||
|
@ -408,8 +408,8 @@ namespace NifOsg
|
||||
unsigned int clamp = static_cast<unsigned int>(textureEffect->clamp);
|
||||
int wrapT = (clamp) & 0x1;
|
||||
int wrapS = (clamp >> 1) & 0x1;
|
||||
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP);
|
||||
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP);
|
||||
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
||||
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
||||
|
||||
osg::ref_ptr<osg::TexEnvCombine> texEnv = new osg::TexEnvCombine;
|
||||
texEnv->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
|
||||
@ -777,8 +777,8 @@ namespace NifOsg
|
||||
|
||||
// inherit wrap settings from the target slot
|
||||
osg::Texture2D* inherit = dynamic_cast<osg::Texture2D*>(stateset->getTextureAttribute(flipctrl->mTexSlot, osg::StateAttribute::TEXTURE));
|
||||
osg::Texture2D::WrapMode wrapS = osg::Texture2D::CLAMP;
|
||||
osg::Texture2D::WrapMode wrapT = osg::Texture2D::CLAMP;
|
||||
osg::Texture2D::WrapMode wrapS = osg::Texture2D::CLAMP_TO_EDGE;
|
||||
osg::Texture2D::WrapMode wrapT = osg::Texture2D::CLAMP_TO_EDGE;
|
||||
if (inherit)
|
||||
{
|
||||
wrapS = inherit->getWrap(osg::Texture2D::WRAP_S);
|
||||
@ -1072,28 +1072,34 @@ namespace NifOsg
|
||||
if (nifNode->recType == Nif::RC_NiTriShape)
|
||||
{
|
||||
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
|
||||
const Nif::NiTriShapeData* data = triShape->data.getPtr();
|
||||
vertexColorsPresent = !data->colors.empty();
|
||||
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name);
|
||||
if (!data->triangles.empty())
|
||||
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
|
||||
(unsigned short*)data->triangles.data()));
|
||||
if (!triShape->data.empty())
|
||||
{
|
||||
const Nif::NiTriShapeData* data = triShape->data.getPtr();
|
||||
vertexColorsPresent = !data->colors.empty();
|
||||
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name);
|
||||
if (!data->triangles.empty())
|
||||
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
|
||||
(unsigned short*)data->triangles.data()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const Nif::NiTriStrips* triStrips = static_cast<const Nif::NiTriStrips*>(nifNode);
|
||||
const Nif::NiTriStripsData* data = triStrips->data.getPtr();
|
||||
vertexColorsPresent = !data->colors.empty();
|
||||
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name);
|
||||
if (!data->strips.empty())
|
||||
if (!triStrips->data.empty())
|
||||
{
|
||||
for (const std::vector<unsigned short>& strip : data->strips)
|
||||
const Nif::NiTriStripsData* data = triStrips->data.getPtr();
|
||||
vertexColorsPresent = !data->colors.empty();
|
||||
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name);
|
||||
if (!data->strips.empty())
|
||||
{
|
||||
// Can't make a triangle from less than three vertices.
|
||||
if (strip.size() < 3)
|
||||
continue;
|
||||
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(),
|
||||
(unsigned short*)strip.data()));
|
||||
for (const std::vector<unsigned short>& strip : data->strips)
|
||||
{
|
||||
// Can't make a triangle from less than three vertices.
|
||||
if (strip.size() < 3)
|
||||
continue;
|
||||
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(),
|
||||
(unsigned short*)strip.data()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1276,9 +1282,11 @@ namespace NifOsg
|
||||
switch (pixelData->fmt)
|
||||
{
|
||||
case Nif::NiPixelData::NIPXFMT_RGB8:
|
||||
case Nif::NiPixelData::NIPXFMT_PAL8:
|
||||
pixelformat = GL_RGB;
|
||||
break;
|
||||
case Nif::NiPixelData::NIPXFMT_RGBA8:
|
||||
case Nif::NiPixelData::NIPXFMT_PALA8:
|
||||
pixelformat = GL_RGBA;
|
||||
break;
|
||||
default:
|
||||
@ -1293,7 +1301,7 @@ namespace NifOsg
|
||||
int height = 0;
|
||||
|
||||
std::vector<unsigned int> mipmapVector;
|
||||
for (unsigned int i=0; i<pixelData->mipmaps.size()-3; ++i)
|
||||
for (unsigned int i=0; i<pixelData->mipmaps.size(); ++i)
|
||||
{
|
||||
const Nif::NiPixelData::Mipmap& mip = pixelData->mipmaps[i];
|
||||
|
||||
@ -1319,10 +1327,59 @@ namespace NifOsg
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned char* data = new unsigned char[pixelData->data.size()];
|
||||
memcpy(data, pixelData->data.data(), pixelData->data.size());
|
||||
const std::vector<unsigned char>& pixels = pixelData->data;
|
||||
switch (pixelData->fmt)
|
||||
{
|
||||
case Nif::NiPixelData::NIPXFMT_RGB8:
|
||||
case Nif::NiPixelData::NIPXFMT_RGBA8:
|
||||
{
|
||||
unsigned char* data = new unsigned char[pixels.size()];
|
||||
memcpy(data, pixels.data(), pixels.size());
|
||||
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
|
||||
break;
|
||||
}
|
||||
case Nif::NiPixelData::NIPXFMT_PAL8:
|
||||
case Nif::NiPixelData::NIPXFMT_PALA8:
|
||||
{
|
||||
if (pixelData->palette.empty() || pixelData->bpp != 8)
|
||||
{
|
||||
Log(Debug::Info) << "Palettized texture in " << mFilename << " is invalid, ignoring";
|
||||
return nullptr;
|
||||
}
|
||||
// We're going to convert the indices that pixel data contains
|
||||
// into real colors using the palette.
|
||||
const std::vector<unsigned int>& palette = pixelData->palette->colors;
|
||||
if (pixelData->fmt == Nif::NiPixelData::NIPXFMT_PAL8)
|
||||
{
|
||||
unsigned char* data = new unsigned char[pixels.size() * 3];
|
||||
for (size_t i = 0; i < pixels.size(); i++)
|
||||
{
|
||||
unsigned int color = palette[pixels[i]];
|
||||
data[i * 3 + 0] = (color >> 0) & 0xFF;
|
||||
data[i * 3 + 1] = (color >> 8) & 0xFF;
|
||||
data[i * 3 + 2] = (color >> 16) & 0xFF;
|
||||
}
|
||||
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
|
||||
}
|
||||
else // if (fmt = NIPXFMT_PALA8)
|
||||
{
|
||||
unsigned char* data = new unsigned char[pixels.size() * 4];
|
||||
for (size_t i = 0; i < pixels.size(); i++)
|
||||
{
|
||||
unsigned int color = palette[pixels[i]];
|
||||
data[i * 4 + 0] = (color >> 0) & 0xFF;
|
||||
data[i * 4 + 1] = (color >> 8) & 0xFF;
|
||||
data[i * 4 + 2] = (color >> 16) & 0xFF;
|
||||
data[i * 4 + 3] = (color >> 24) & 0xFF;
|
||||
}
|
||||
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
|
||||
image->setMipmapLevels(mipmapVector);
|
||||
image->flipVertical();
|
||||
|
||||
@ -1392,8 +1449,8 @@ namespace NifOsg
|
||||
int wrapT = (clamp) & 0x1;
|
||||
int wrapS = (clamp >> 1) & 0x1;
|
||||
|
||||
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP);
|
||||
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP);
|
||||
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
||||
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
||||
|
||||
int texUnit = boundTextures.size();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user