1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-21 05:39:42 +00:00

Merge remote-tracking branch 'upstream/master' into osgshadow-test-vdsm

This commit is contained in:
AnyOldName3 2017-10-19 15:06:49 +01:00
commit 2a90dff388
51 changed files with 530 additions and 302 deletions

View file

@ -41,8 +41,8 @@ addons:
project:
name: "OpenMW/openmw"
description: "<Your project description here>"
notification_email: scrawl@baseoftrash.de
build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE"
notification_email: 720642+scrawl@users.noreply.github.com
build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_MWINIIMPORTER=FALSE -DBUILD_LAUNCHER=FALSE"
build_command: "make -j3"
branch_pattern: coverity_scan
matrix:

View file

@ -329,8 +329,9 @@ endif ()
configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
"${OpenMW_BINARY_DIR}" "openmw-cs.cfg")
configure_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
"${OpenMW_BINARY_DIR}" "resources/defaultfilters" COPYONLY)
# Needs the copy version because the configure version assumes the end of the file has been reached when a null character is reached and there are no CMake expressions to evaluate.
copy_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
"${OpenMW_BINARY_DIR}" "resources/defaultfilters")
configure_resource_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt
"${OpenMW_BINARY_DIR}" "gamecontrollerdb.txt")

View file

@ -90,16 +90,16 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options");
desc.add_options()
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken()->composing())
("data-local", boost::program_options::value<std::string>()->default_value(""))
("data", boost::program_options::value<Files::EscapePathContainer>()->default_value(Files::EscapePathContainer(), "data")->multitoken()->composing())
("data-local", boost::program_options::value<Files::EscapeHashString>()->default_value(""))
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
("encoding", boost::program_options::value<std::string>()->default_value("win1252"))
("resources", boost::program_options::value<std::string>()->default_value("resources"))
("fallback-archive", boost::program_options::value<std::vector<std::string> >()->
default_value(std::vector<std::string>(), "fallback-archive")->multitoken())
("encoding", boost::program_options::value<Files::EscapeHashString>()->default_value("win1252"))
("resources", boost::program_options::value<Files::EscapeHashString>()->default_value("resources"))
("fallback-archive", boost::program_options::value<Files::EscapeStringVector>()->
default_value(Files::EscapeStringVector(), "fallback-archive")->multitoken())
("fallback", boost::program_options::value<FallbackMap>()->default_value(FallbackMap(), "")
->multitoken()->composing(), "fallback values")
("script-blacklist", boost::program_options::value<std::vector<std::string> >()->default_value(std::vector<std::string>(), "")
("script-blacklist", boost::program_options::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "")
->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)")
("script-blacklist-use", boost::program_options::value<bool>()->implicit_value(true)
->default_value(true), "enable script blacklisting");
@ -109,25 +109,29 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
mCfgMgr.readConfiguration(variables, desc, quiet);
mDocumentManager.setEncoding (
ToUTF8::calculateEncoding (variables["encoding"].as<std::string>()));
ToUTF8::calculateEncoding (variables["encoding"].as<Files::EscapeHashString>().toStdString()));
mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>());
mDocumentManager.setResourceDir (mResources = variables["resources"].as<Files::EscapeHashString>().toStdString());
mDocumentManager.setFallbackMap (variables["fallback"].as<FallbackMap>().mMap);
if (variables["script-blacklist-use"].as<bool>())
mDocumentManager.setBlacklistedScripts (
variables["script-blacklist"].as<std::vector<std::string> >());
variables["script-blacklist"].as<Files::EscapeStringVector>().toStdStringVector());
mFsStrict = variables["fs-strict"].as<bool>();
Files::PathContainer dataDirs, dataLocal;
if (!variables["data"].empty()) {
dataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
dataDirs = Files::PathContainer(Files::EscapePath::toPathContainer(variables["data"].as<Files::EscapePathContainer>()));
}
std::string local = variables["data-local"].as<std::string>();
if (!local.empty()) {
std::string local = variables["data-local"].as<Files::EscapeHashString>().toStdString();
if (!local.empty())
{
if (local.front() == '\"')
local = local.substr(1, local.length() - 2);
dataLocal.push_back(Files::PathContainer::value_type(local));
}
@ -157,7 +161,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
mFileDialog.addFiles(path);
}
return std::make_pair (dataDirs, variables["fallback-archive"].as<std::vector<std::string> >());
return std::make_pair (dataDirs, variables["fallback-archive"].as<Files::EscapeStringVector>().toStdStringVector());
}
void CS::Editor::createGame()

View file

@ -288,7 +288,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
if (mContentFiles.empty())
throw std::runtime_error ("Empty content file sequence");
if (!boost::filesystem::exists (mProjectPath))
if (mNew || !boost::filesystem::exists (mProjectPath))
{
boost::filesystem::path customFiltersPath (configuration.getUserDataPath());
customFiltersPath /= "defaultfilters";

View file

@ -38,9 +38,10 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr
appendStage (new MergeRefIdsStage (mState));
appendStage (new MergeReferencesStage (mState));
appendStage (new MergeReferencesStage (mState));
appendStage (new ListLandTexturesMergeStage (mState));
appendStage (new MergeLandTexturesStage (mState));
appendStage (new PopulateLandTexturesMergeStage (mState));
appendStage (new MergeLandStage (mState));
appendStage (new FixLandsAndLandTexturesMergeStage (mState));
appendStage (new CleanupLandTexturesMergeStage (mState));
appendStage (new FinishMergedDocumentStage (mState, encoding));
}

View file

@ -8,7 +8,9 @@
#include "mergestate.hpp"
#include "../doc/document.hpp"
#include "../world/commands.hpp"
#include "../world/data.hpp"
#include "../world/idtable.hpp"
CSMTools::StartMergeStage::StartMergeStage (MergeState& state)
@ -109,102 +111,32 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa
}
CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state)
: mState (state)
{}
int CSMTools::ListLandTexturesMergeStage::setup()
CSMTools::PopulateLandTexturesMergeStage::PopulateLandTexturesMergeStage (MergeState& state)
: mState (state)
{
return mState.mSource.getData().getLand().getSize();
}
void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
int CSMTools::PopulateLandTexturesMergeStage::setup()
{
const CSMWorld::Record<CSMWorld::Land>& record =
mState.mSource.getData().getLand().getRecord (stage);
if (!record.isDeleted())
{
const CSMWorld::Land& land = record.get();
// make sure record is loaded
land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX);
if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX))
{
// list texture indices
std::pair<uint16_t, int> key;
key.second = land.mPlugin;
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i)
{
key.first = data->mTextures[i];
mState.mTextureIndices[key] = -1;
}
}
}
}
CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state)
: mState (state), mNext (mState.mTextureIndices.end())
{}
int CSMTools::MergeLandTexturesStage::setup()
{
// Should use the size of mState.mTextureIndices instead, but that is not available at this
// point. Unless there are any errors in the land and land texture records this will not
// make a difference.
return mState.mSource.getData().getLandTextures().getSize();
}
void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages)
void CSMTools::PopulateLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
{
if (stage==0)
mNext = mState.mTextureIndices.begin();
const CSMWorld::Record<CSMWorld::LandTexture>& record =
mState.mSource.getData().getLandTextures().getRecord (stage);
bool found = false;
do
if (!record.isDeleted())
{
if (mNext==mState.mTextureIndices.end())
return;
mNext->second = stage+1;
std::ostringstream stream;
stream << mNext->first.first-1 << "_" << mNext->first.second;
int index = mState.mSource.getData().getLandTextures().searchId (stream.str());
if (index!=-1)
{
CSMWorld::LandTexture texture =
mState.mSource.getData().getLandTextures().getRecord (index).get();
stream.clear();
stream << mNext->second-1 << "_0";
texture.mIndex = mNext->second-1;
texture.mId = stream.str();
CSMWorld::Record<CSMWorld::LandTexture> newRecord (
CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture);
mState.mTarget->getData().getLandTextures().appendRecord (newRecord);
found = true;
}
++mNext;
mState.mTarget->getData().getLandTextures().appendRecord(record);
}
while (!found);
}
CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {}
CSMTools::MergeLandStage::MergeLandStage (MergeState& state)
: mState (state)
{
}
int CSMTools::MergeLandStage::setup()
{
@ -218,40 +150,66 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages)
if (!record.isDeleted())
{
const CSMWorld::Land& land = record.get();
land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
ESM::Land::DATA_VTEX);
CSMWorld::Land newLand (land);
newLand.mPlugin = 0;
if (land.mDataTypes & ESM::Land::DATA_VTEX)
{
// adjust land texture references
if (ESM::Land::LandData *data = newLand.getLandData())
{
std::pair<uint16_t, int> key;
key.second = land.mPlugin;
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i)
{
key.first = data->mTextures[i];
std::map<std::pair<uint16_t, int>, int>::const_iterator iter =
mState.mTextureIndices.find (key);
if (iter!=mState.mTextureIndices.end())
data->mTextures[i] = iter->second;
else
data->mTextures[i] = 0;
}
}
}
CSMWorld::Record<CSMWorld::Land> newRecord (
CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand);
mState.mTarget->getData().getLand().appendRecord (newRecord);
mState.mTarget->getData().getLand().appendRecord (record);
}
}
CSMTools::FixLandsAndLandTexturesMergeStage::FixLandsAndLandTexturesMergeStage (MergeState& state)
: mState (state)
{
}
int CSMTools::FixLandsAndLandTexturesMergeStage::setup()
{
// We will have no more than the source
return mState.mSource.getData().getLand().getSize();
}
void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
{
if (stage < mState.mTarget->getData().getLand().getSize())
{
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&>(
*mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_Lands));
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&>(
*mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures));
std::string id = mState.mTarget->getData().getLand().getId(stage);
CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id);
cmd.redo();
// Get rid of base data
const CSMWorld::Record<CSMWorld::Land>& oldRecord =
mState.mTarget->getData().getLand().getRecord (stage);
CSMWorld::Record<CSMWorld::Land> newRecord(CSMWorld::RecordBase::State_ModifiedOnly,
nullptr, &oldRecord.get());
mState.mTarget->getData().getLand().setRecord(stage, newRecord);
}
}
CSMTools::CleanupLandTexturesMergeStage::CleanupLandTexturesMergeStage (MergeState& state)
: mState (state)
{
}
int CSMTools::CleanupLandTexturesMergeStage::setup()
{
return 1;
}
void CSMTools::CleanupLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
{
auto& landTextures = mState.mTarget->getData().getLandTextures();
for (int i = 0; i < landTextures.getSize(); )
{
if (!landTextures.getRecord(i).isModified())
landTextures.removeRows(i, 1);
else
++i;
}
}

View file

@ -116,29 +116,14 @@ namespace CSMTools
///< Messages resulting from this stage will be appended to \a messages.
};
class ListLandTexturesMergeStage : public CSMDoc::Stage
/// Adds all land texture records that could potentially be referenced when merging
class PopulateLandTexturesMergeStage : public CSMDoc::Stage
{
MergeState& mState;
public:
ListLandTexturesMergeStage (MergeState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class MergeLandTexturesStage : public CSMDoc::Stage
{
MergeState& mState;
std::map<std::pair<uint16_t, int>, int>::iterator mNext;
public:
MergeLandTexturesStage (MergeState& state);
PopulateLandTexturesMergeStage (MergeState& state);
virtual int setup();
///< \return number of steps
@ -161,6 +146,40 @@ namespace CSMTools
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
/// During this stage, the complex process of combining LandTextures from
/// potentially multiple plugins is undertaken.
class FixLandsAndLandTexturesMergeStage : public CSMDoc::Stage
{
MergeState& mState;
public:
FixLandsAndLandTexturesMergeStage (MergeState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
/// Removes base LandTexture records. This gets rid of the base records previously
/// needed in FixLandsAndLandTexturesMergeStage.
class CleanupLandTexturesMergeStage : public CSMDoc::Stage
{
MergeState& mState;
public:
CleanupLandTexturesMergeStage (MergeState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
}
#endif

View file

@ -108,7 +108,7 @@ namespace CSMWorld
throw std::runtime_error("invalid land map LOD data");
Land copy = record.get();
copy.setDataLoaded(Land::DATA_WNAM);
copy.add(Land::DATA_WNAM);
for (int i = 0; i < values.size(); ++i)
{
@ -155,7 +155,7 @@ namespace CSMWorld
throw std::runtime_error("invalid land normals data");
Land copy = record.get();
copy.setDataLoaded(Land::DATA_VNML);
copy.add(Land::DATA_VNML);
for (int i = 0; i < values.size(); ++i)
{
@ -202,7 +202,7 @@ namespace CSMWorld
throw std::runtime_error("invalid land heights data");
Land copy = record.get();
copy.setDataLoaded(Land::DATA_VHGT);
copy.add(Land::DATA_VHGT);
for (int i = 0; i < values.size(); ++i)
{
@ -249,7 +249,7 @@ namespace CSMWorld
throw std::runtime_error("invalid land colours data");
Land copy = record.get();
copy.setDataLoaded(Land::DATA_VCLR);
copy.add(Land::DATA_VCLR);
for (int i = 0; i < values.size(); ++i)
{
@ -296,7 +296,7 @@ namespace CSMWorld
throw std::runtime_error("invalid land textures data");
Land copy = record.get();
copy.setDataLoaded(Land::DATA_VTEX);
copy.add(Land::DATA_VTEX);
for (int i = 0; i < values.size(); ++i)
{

View file

@ -44,6 +44,15 @@ namespace CSMWorld
bool mChanged;
};
/// \brief Adds LandTexture records and modifies texture indices as needed.
///
/// LandTexture records are different from other types of records, because
/// they only effect the current plugin. Thus, when modifying or copying
/// a Land record, all of the LandTexture records referenced need to be
/// added to the current plugin. Since these newly added LandTextures could
/// have indices that conflict with pre-existing LandTextures in the current
/// plugin, the indices might have to be changed, both for the newly added
/// LandRecord and within the Land record.
class ImportLandTexturesCommand : public QUndoCommand
{
public:
@ -71,6 +80,9 @@ namespace CSMWorld
std::vector<std::string> mCreatedTextures;
};
/// \brief This command is used to fix LandTexture records and texture
/// indices after cloning a Land. See ImportLandTexturesCommand for
/// details.
class CopyLandTexturesCommand : public ImportLandTexturesCommand
{
public:
@ -90,6 +102,9 @@ namespace CSMWorld
std::string mDestId;
};
/// \brief This command brings a land record into the current plugin, adding
/// LandTexture records and modifying texture indices as needed.
/// \note See ImportLandTextures for more details.
class TouchLandCommand : public ImportLandTexturesCommand
{
public:

View file

@ -336,7 +336,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
int oldRow = idCollection()->searchId(id);
// If it does not exist or it is in the current plugin, it can be skipped.
if (oldRow <= 0 || plugin == 0)
if (oldRow < 0 || plugin == 0)
{
results.recordMapping.push_back(std::make_pair(id, id));
continue;

View file

@ -194,6 +194,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
std::string local(variables["data-local"].as<Files::EscapeHashString>().toStdString());
if (!local.empty())
{
if (local.front() == '\"')
local = local.substr(1, local.length() - 2);
dataDirs.push_back(Files::PathContainer::value_type(local));
}

View file

@ -155,8 +155,6 @@ namespace MWGui
void restock();
void deleteLater();
bool mEnabled;
bool mIsCompanion;
std::list<std::string> mKeywords;

View file

@ -80,7 +80,6 @@ namespace MWGui
, mSpellStatus(NULL)
, mEffectBox(NULL)
, mMinimap(NULL)
, mCompass(NULL)
, mCrosshair(NULL)
, mCellNameBox(NULL)
, mDrowningFrame(NULL)

View file

@ -69,7 +69,6 @@ namespace MWGui
MyGUI::Widget *mEffectBox, *mMinimapBox;
MyGUI::Button* mMinimapButton;
MyGUI::ScrollView* mMinimap;
MyGUI::ImageBox* mCompass;
MyGUI::ImageBox* mCrosshair;
MyGUI::TextBox* mCellNameBox;
MyGUI::TextBox* mWeaponSpellBox;

View file

@ -58,6 +58,7 @@ namespace MWGui
{
MWWorld::Ptr player = MWMechanics::getPlayer();
MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker");
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.f); // override fade-in caused by cell transition
setVisible(true);
mTimeAdvancer.run(100);

View file

@ -84,6 +84,7 @@ namespace MWGui
dialog->eventOkClicked.clear();
dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed);
dialog->eventCancelClicked.clear();
dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotCancel);
}
void SaveGameDialog::onDeleteSlotConfirmed()

View file

@ -46,7 +46,7 @@ namespace MWGui
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
void addSpell(const ESM::Spell& spell);
void clearSpells();
int mLastPos,mCurrentY;
int mCurrentY;
static const int sLineHeight;

View file

@ -105,7 +105,7 @@ namespace MWGui
std::stringstream out;
out << val << "/" << max;
setText(tname, out.str().c_str());
setText(tname, out.str());
pt->setProgressRange(std::max(0, max));
pt->setProgressPosition(std::max(0, val));

View file

@ -451,11 +451,10 @@ namespace MWMechanics
// Check if an idle actor is too close to a door - if so start walking
storage.mDoorCheckDuration += duration;
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
if (storage.mDoorCheckDuration >= DOOR_CHECK_INTERVAL)
{
storage.mDoorCheckDuration = 0; // restart timer
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
if (mDistance && // actor is not intended to be stationary
proximityToDoor(actor, distance*1.6f))
{
@ -531,11 +530,10 @@ namespace MWMechanics
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos)
{
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
if (mObstacleCheck.isEvading())
{
// first check if we're walking into a door
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
if (proximityToDoor(actor, distance))
{
// remove allowed points then select another random destination

View file

@ -1874,7 +1874,7 @@ void CharacterController::update(float duration)
: (sneak ? CharState_SneakBack
: (isrunning ? CharState_RunBack : CharState_WalkBack)));
}
else if(rot.z() != 0.0f && !inwater && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson()))
else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson()))
{
if(rot.z() > 0.0f)
movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight;

View file

@ -424,26 +424,6 @@ namespace MWMechanics
}
}
bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim)
{
const MWWorld::Class& attackerClass = attacker.getClass();
MWBase::World* world = MWBase::Environment::get().getWorld();
// If attacker is fish, victim must be in water
if (attackerClass.isPureWaterCreature(attacker))
{
return world->isWading(victim);
}
// If attacker can't swim, victim must not be in water
if (!attackerClass.canSwim(attacker))
{
return !world->isSwimming(victim);
}
return true;
}
float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2)
{
osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3());

View file

@ -39,10 +39,6 @@ void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& vict
/// Apply the fatigue loss incurred by attacking with the given weapon (weapon may be empty = hand-to-hand)
void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float attackStrength);
/// Can attacker operate in victim's environment?
/// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land?
bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim);
float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2);
}

View file

@ -1123,6 +1123,10 @@ namespace MWMechanics
if (playerFollowers.find(*it) != playerFollowers.end())
continue;
// NPC will complain about theft even if he will do nothing about it
if (type == OT_Theft || type == OT_Pickpocket)
MWBase::Environment::get().getDialogueManager()->say(*it, "thief");
crimeSeen = true;
}
}
@ -1243,9 +1247,7 @@ namespace MWMechanics
{
reported = true;
if (type == OT_Theft || type == OT_Pickpocket)
MWBase::Environment::get().getDialogueManager()->say(*it, "thief");
else if (type == OT_Trespassing)
if (type == OT_Trespassing)
MWBase::Environment::get().getDialogueManager()->say(*it, "intruder");
}

View file

@ -536,6 +536,13 @@ namespace MWMechanics
appliedLastingEffects.push_back(effect);
// Unequip all items, if a spell with the ExtraSpell effect was casted
if (effectIt->mEffectID == ESM::MagicEffect::ExtraSpell && target.getClass().hasInventoryStore(target))
{
MWWorld::InventoryStore& store = target.getClass().getInventoryStore(target);
store.unequipAll(target);
}
// Command spells should have their effect, including taking the target out of combat, each time the spell successfully affects the target
if (((effectIt->mEffectID == ESM::MagicEffect::CommandHumanoid && target.getClass().isNpc())
|| (effectIt->mEffectID == ESM::MagicEffect::CommandCreature && target.getTypeName() == typeid(ESM::Creature).name()))

View file

@ -702,8 +702,6 @@ namespace MWPhysics
const char* env = getenv("OPENMW_PHYSICS_FPS");
if (env)
{
std::string str(env);
float physFramerate = std::atof(env);
if (physFramerate > 0)
{
@ -1046,7 +1044,7 @@ namespace MWPhysics
bool PhysicsSystem::isOnGround(const MWWorld::Ptr &actor)
{
Actor* physactor = getActor(actor);
return physactor->getOnGround();
return physactor && physactor->getOnGround();
}
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)

View file

@ -290,11 +290,9 @@ namespace MWRender
sceneRoot->setNodeMask(Mask_Scene);
sceneRoot->setName("Scene Root");
mUniformRainIntensity = new osg::Uniform("rainIntensity",(float) 0.0);
mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity);
mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager()));
mSky->setCamera(mViewer->getCamera());
mSky->setRainIntensityUniform(mWater->getRainIntensityUniform());
source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON);
@ -544,9 +542,6 @@ namespace MWRender
mWater->update(dt);
}
if (!mSky->isEnabled() || !mSky->hasRain())
clearRainRipples();
mCamera->update(dt, paused);
osg::Vec3f focal, cameraPos;
@ -845,12 +840,6 @@ namespace MWRender
void RenderingManager::notifyWorldSpaceChanged()
{
mEffectManager->clear();
mWater->clearRipples();
}
void RenderingManager::clearRainRipples()
{
mUniformRainIntensity->set((float) 0.0);
}
void RenderingManager::clear()

View file

@ -85,7 +85,6 @@ namespace MWRender
osg::Uniform* mUniformNear;
osg::Uniform* mUniformFar;
osg::Uniform* mUniformRainIntensity;
void preloadCommonAssets();
@ -160,8 +159,6 @@ namespace MWRender
/// Clear all worldspace-specific data
void notifyWorldSpaceChanged();
void clearRainRipples();
void update(float dt, bool paused);
Animation* getAnimation(const MWWorld::Ptr& ptr);

View file

@ -25,6 +25,9 @@
#include <osgParticle/ConstantRateCounter>
#include <osgParticle/RadialShooter>
#include <osgParticle/Operator>
#include <osgParticle/ModularProgram>
#include <components/misc/rng.hpp>
#include <components/misc/resourcehelpers.hpp>
@ -48,7 +51,6 @@
namespace
{
osg::ref_ptr<osg::Material> createAlphaTrackingUnlitMaterial()
{
osg::ref_ptr<osg::Material> mat = new osg::Material;
@ -1093,6 +1095,8 @@ private:
SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager)
: mSceneManager(sceneManager)
, mCamera(NULL)
, mRainIntensityUniform(NULL)
, mAtmosphereNightRoll(0.f)
, mCreated(false)
, mIsStorm(false)
@ -1135,6 +1139,11 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana
mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot);
}
void SkyManager::setRainIntensityUniform(osg::Uniform *uniform)
{
mRainIntensityUniform = uniform;
}
void SkyManager::create()
{
assert(!mCreated);
@ -1236,9 +1245,11 @@ private:
class AlphaFader : public SceneUtil::StateSetUpdater
{
public:
AlphaFader()
/// @param alphaUpdate variable which to update with alpha value
AlphaFader(float *alphaUpdate)
: mAlpha(1.f)
{
mAlphaUpdate = alphaUpdate;
}
void setAlpha(float alpha)
@ -1257,15 +1268,19 @@ public:
{
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha));
if (mAlphaUpdate)
*mAlphaUpdate = mAlpha;
}
// Helper for adding AlphaFaders to a subgraph
class SetupVisitor : public osg::NodeVisitor
{
public:
SetupVisitor()
SetupVisitor(float *alphaUpdate)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{
mAlphaUpdate = alphaUpdate;
}
virtual void apply(osg::Node &node)
@ -1276,14 +1291,16 @@ public:
{
SceneUtil::CompositeStateSetUpdater* composite = NULL;
osg::Callback* callback = node.getUpdateCallback();
while (callback)
{
if ((composite = dynamic_cast<SceneUtil::CompositeStateSetUpdater*>(callback)))
break;
callback = callback->getNestedCallback();
}
osg::ref_ptr<AlphaFader> alphaFader (new AlphaFader);
osg::ref_ptr<AlphaFader> alphaFader (new AlphaFader(mAlphaUpdate));
if (composite)
composite->addController(alphaFader);
@ -1293,6 +1310,7 @@ public:
mAlphaFaders.push_back(alphaFader);
}
}
traverse(node);
}
@ -1303,19 +1321,19 @@ public:
private:
std::vector<osg::ref_ptr<AlphaFader> > mAlphaFaders;
float *mAlphaUpdate;
};
protected:
float mAlpha;
float *mAlphaUpdate;
};
class RainFader : public AlphaFader
{
public:
RainFader(osg::Uniform *rainIntensityUniform): AlphaFader()
RainFader(float *alphaUpdate): AlphaFader(alphaUpdate)
{
mRainIntensityUniform = rainIntensityUniform;
}
virtual void setDefaults(osg::StateSet* stateset)
@ -1330,11 +1348,89 @@ public:
virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv)
{
AlphaFader::apply(stateset,nv);
mRainIntensityUniform->set((float) (mAlpha * 2.0)); // mAlpha is limited to 0.6 so multiply by 2 to reach full intensity
*mAlphaUpdate = mAlpha * 2.0; // mAlpha is limited to 0.6 so multiply by 2 to reach full intensity
}
};
void SkyManager::setCamera(osg::Camera *camera)
{
mCamera = camera;
}
class WrapAroundOperator : public osgParticle::Operator
{
public:
WrapAroundOperator(osg::Camera *camera, const osg::Vec3 &wrapRange): osgParticle::Operator()
{
mCamera = camera;
mWrapRange = wrapRange;
mHalfWrapRange = mWrapRange / 2.0;
mPreviousCameraPosition = getCameraPosition();
}
virtual osg::Object *cloneType() const override
{
return NULL;
}
virtual osg::Object *clone(const osg::CopyOp &op) const override
{
return NULL;
}
virtual void operate(osgParticle::Particle *P, double dt) override
{
}
virtual void operateParticles(osgParticle::ParticleSystem *ps, double dt) override
{
osg::Vec3 position = getCameraPosition();
osg::Vec3 positionDifference = position - mPreviousCameraPosition;
osg::Matrix toWorld, toLocal;
std::vector<osg::Matrix> worldMatrices = ps->getWorldMatrices();
if (!worldMatrices.empty())
{
toWorld = worldMatrices[0];
toLocal.invert(toWorld);
}
for (int i = 0; i < ps->numParticles(); ++i)
{
osgParticle::Particle *p = ps->getParticle(i);
p->setPosition(toWorld.preMult(p->getPosition()));
p->setPosition(p->getPosition() - positionDifference);
for (int j = 0; j < 3; ++j) // wrap-around in all 3 dimensions
{
osg::Vec3 pos = p->getPosition();
if (pos[j] < -mHalfWrapRange[j])
pos[j] = mHalfWrapRange[j] + fmod(pos[j] - mHalfWrapRange[j],mWrapRange[j]);
else if (pos[j] > mHalfWrapRange[j])
pos[j] = fmod(pos[j] + mHalfWrapRange[j],mWrapRange[j]) - mHalfWrapRange[j];
p->setPosition(pos);
}
p->setPosition(toLocal.preMult(p->getPosition()));
}
mPreviousCameraPosition = position;
}
protected:
osg::Uniform* mRainIntensityUniform;
osg::Camera *mCamera;
osg::Vec3 mPreviousCameraPosition;
osg::Vec3 mWrapRange;
osg::Vec3 mHalfWrapRange;
osg::Vec3 getCameraPosition()
{
return mCamera->getInverseViewMatrix().getTrans();
}
};
void SkyManager::createRain()
@ -1345,6 +1441,8 @@ void SkyManager::createRain()
mRainNode = new osg::Group;
mRainParticleSystem = new osgParticle::ParticleSystem;
osg::Vec3 rainRange = osg::Vec3(600,600,600);
mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED);
mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0));
mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,1));
@ -1370,8 +1468,8 @@ void SkyManager::createRain()
emitter->setParticleSystem(mRainParticleSystem);
osg::ref_ptr<osgParticle::BoxPlacer> placer (new osgParticle::BoxPlacer);
placer->setXRange(-300, 300); // Rain_Diameter
placer->setYRange(-300, 300);
placer->setXRange(-rainRange.x() / 2, rainRange.x() / 2); // Rain_Diameter
placer->setYRange(-rainRange.y() / 2, rainRange.y() / 2);
placer->setZRange(300, 300);
emitter->setPlacer(placer);
@ -1386,11 +1484,16 @@ void SkyManager::createRain()
osg::ref_ptr<osgParticle::ParticleSystemUpdater> updater (new osgParticle::ParticleSystemUpdater);
updater->addParticleSystem(mRainParticleSystem);
osg::ref_ptr<osgParticle::ModularProgram> program (new osgParticle::ModularProgram);
program->addOperator(new WrapAroundOperator(mCamera,rainRange));
program->setParticleSystem(mRainParticleSystem);
mRainNode->addChild(program);
mRainNode->addChild(emitter);
mRainNode->addChild(mRainParticleSystem);
mRainNode->addChild(updater);
mRainFader = new RainFader(mRootNode->getParent(0)->getParent(0)->getStateSet()->getUniform("rainIntensity"));
mRainFader = new RainFader(&mWeatherAlpha);
mRainNode->addUpdateCallback(mRainFader);
mRainNode->addCullCallback(mUnderwaterSwitch);
mRainNode->setNodeMask(Mask_WeatherParticles);
@ -1443,7 +1546,21 @@ bool SkyManager::hasRain()
void SkyManager::update(float duration)
{
if (!mEnabled) return;
if (!mEnabled)
{
if (mRainIntensityUniform)
mRainIntensityUniform->set((float) 0.0);
return;
}
if (mRainIntensityUniform)
{
if (mIsStorm || (!hasRain() && !mParticleNode))
mRainIntensityUniform->set((float) 0.0);
else
mRainIntensityUniform->set((float) mWeatherAlpha);
}
if (mIsStorm)
{
@ -1452,6 +1569,7 @@ void SkyManager::update(float duration)
if (mParticleNode)
mParticleNode->setAttitude(quat);
mCloudNode->setAttitude(quat);
}
else
@ -1548,17 +1666,35 @@ void SkyManager::setWeather(const WeatherResult& weather)
mParticleNode->setNodeMask(Mask_WeatherParticles);
mRootNode->addChild(mParticleNode);
}
mParticleEffect = mSceneManager->getInstance(mCurrentParticleEffect, mParticleNode);
SceneUtil::AssignControllerSourcesVisitor assignVisitor(std::shared_ptr<SceneUtil::ControllerSource>(new SceneUtil::FrameTimeSource));
mParticleEffect->accept(assignVisitor);
AlphaFader::SetupVisitor alphaFaderSetupVisitor;
AlphaFader::SetupVisitor alphaFaderSetupVisitor(&mWeatherAlpha);
mParticleEffect->accept(alphaFaderSetupVisitor);
mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders();
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
mParticleEffect->accept(disableFreezeOnCullVisitor);
if (!weather.mIsStorm)
{
SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem"));
mParticleEffect->accept(findPSVisitor);
for (unsigned int i = 0; i < findPSVisitor.mFoundNodes.size(); ++i)
{
osgParticle::ParticleSystem *ps = static_cast<osgParticle::ParticleSystem *>(findPSVisitor.mFoundNodes[i]);
osg::ref_ptr<osgParticle::ModularProgram> program (new osgParticle::ModularProgram);
program->addOperator(new WrapAroundOperator(mCamera,osg::Vec3(1024,1024,800)));
program->setParticleSystem(ps);
mParticleNode->addChild(program);
}
}
}
}
@ -1634,7 +1770,8 @@ void SkyManager::setWeather(const WeatherResult& weather)
mSun->adjustTransparency(weather.mGlareView * weather.mSunDiscColor.a());
float nextStarsOpacity = weather.mNightFade * weather.mGlareView;
if(weather.mNight && mStarsOpacity != nextStarsOpacity)
if (weather.mNight && mStarsOpacity != nextStarsOpacity)
{
mStarsOpacity = nextStarsOpacity;
@ -1645,6 +1782,7 @@ void SkyManager::setWeather(const WeatherResult& weather)
if (mRainFader)
mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold?
for (std::vector<osg::ref_ptr<AlphaFader> >::const_iterator it = mParticleFaders.begin(); it != mParticleFaders.end(); ++it)
(*it)->setAlpha(weather.mEffectFade);
}

View file

@ -8,6 +8,12 @@
#include <osg/ref_ptr>
#include <osg/Vec4f>
#include <osg/Uniform>
namespace osg
{
class Camera;
}
namespace osg
{
@ -161,6 +167,10 @@ namespace MWRender
void listAssetsToPreload(std::vector<std::string>& models, std::vector<std::string>& textures);
void setCamera(osg::Camera *camera);
void setRainIntensityUniform(osg::Uniform *uniform);
private:
void create();
///< no need to call this, automatically done on first enable()
@ -171,6 +181,9 @@ namespace MWRender
Resource::SceneManager* mSceneManager;
osg::Camera *mCamera;
osg::Uniform *mRainIntensityUniform;
osg::ref_ptr<osg::Group> mRootNode;
osg::ref_ptr<osg::Group> mEarlyRenderBinRoot;
@ -239,6 +252,8 @@ namespace MWRender
bool mEnabled;
bool mSunEnabled;
float mWeatherAlpha;
osg::Vec4f mMoonScriptColor;
};
}

View file

@ -411,12 +411,19 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem
createSimpleWaterStateSet(geom2, mFallback->getFallbackFloat("Water_Map_Alpha"));
geom2->setNodeMask(Mask_SimpleWater);
mWaterNode->addChild(geom2);
mSceneRoot->addChild(mWaterNode);
setHeight(mTop);
updateWaterMaterial();
mRainIntensityUniform = new osg::Uniform("rainIntensity",(float) 0.0);
}
osg::Uniform *Water::getRainIntensityUniform()
{
return mRainIntensityUniform.get();
}
void Water::updateWaterMaterial()
@ -550,6 +557,8 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R
program->addShader(fragmentShader);
shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON);
shaderStateset->addUniform(mRainIntensityUniform);
node->setStateSet(shaderStateset);
node->setUpdateCallback(NULL);
}

View file

@ -6,6 +6,7 @@
#include <osg/ref_ptr>
#include <osg/Vec3f>
#include <osg/Uniform>
#include <components/settings/settings.hpp>
@ -50,6 +51,8 @@ namespace MWRender
{
static const int CELL_SIZE = 8192;
osg::ref_ptr<osg::Uniform> mRainIntensityUniform;
osg::ref_ptr<osg::Group> mParent;
osg::ref_ptr<osg::Group> mSceneRoot;
osg::ref_ptr<osg::PositionAttitudeTransform> mWaterNode;
@ -110,6 +113,8 @@ namespace MWRender
void update(float dt);
void processChangedSettings(const Settings::CategorySettingVector& settings);
osg::Uniform *getRainIntensityUniform();
};
}

View file

@ -55,7 +55,6 @@ void Config::GameSettings::validatePaths()
for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) {
QString path = QString::fromUtf8(it->string().c_str());
path.remove(QChar('\"'));
QDir dir(path);
if (dir.exists())
@ -64,6 +63,11 @@ void Config::GameSettings::validatePaths()
// Do the same for data-local
QString local = mSettings.value(QString("data-local"));
if (local.at(0) == QChar('\"'))
{
local.remove(0, 1);
local.chop(1);
}
if (local.isEmpty())
return;
@ -76,7 +80,6 @@ void Config::GameSettings::validatePaths()
if (!dataDirs.empty()) {
QString path = QString::fromUtf8(dataDirs.front().string().c_str());
path.remove(QChar('\"'));
QDir dir(path);
if (dir.exists())
@ -120,6 +123,28 @@ bool Config::GameSettings::readFile(QTextStream &stream, QMap<QString, QString>
// Don't remove existing data entries
if (key != QLatin1String("data"))
settings.remove(key);
else
{
// 'data=...' line, so needs processing to deal with ampersands and quotes
// The following is based on boost::io::detail::quoted_manip.hpp, but calling those functions did not work as there are too may QStrings involved
QChar delim = '\"';
QChar escape = '&';
if (value.at(0) == delim)
{
QString valueOriginal = value;
value = "";
for (QString::const_iterator it = valueOriginal.begin() + 1; it != valueOriginal.end(); ++it)
{
if (*it == escape)
++it;
else if (*it == delim)
break;
value += *it;
}
}
}
QStringList values = cache.values(key);
values.append(settings.values(key));
@ -152,9 +177,31 @@ bool Config::GameSettings::writeFile(QTextStream &stream)
while (i.hasPrevious()) {
i.previous();
// 'data=...' lines need quotes and ampersands escaping to match how boost::filesystem::path uses boost::io::quoted
if (i.key() == QLatin1String("data"))
{
stream << i.key() << "=";
// The following is based on boost::io::detail::quoted_manip.hpp, but calling those functions did not work as there are too may QStrings involved
QChar delim = '\"';
QChar escape = '&';
QString string = i.value();
stream << delim;
for (QString::const_iterator it = string.begin(); it != string.end(); ++it)
{
if (*it == delim || *it == escape)
stream << escape;
stream << *it;
}
stream << delim;
stream << '\n';
continue;
}
// Quote paths with spaces
if (i.key() == QLatin1String("data")
|| i.key() == QLatin1String("data-local")
if (i.key() == QLatin1String("data-local")
|| i.key() == QLatin1String("resources"))
{
if (i.value().contains(QChar(' ')))
@ -358,9 +405,26 @@ bool Config::GameSettings::writeFileWithComments(QFile &file)
{
it.previous();
if (it.key() == QLatin1String("data"))
{
settingLine = it.key() + "=";
// The following is based on boost::io::detail::quoted_manip.hpp, but calling those functions did not work as there are too may QStrings involved
QChar delim = '\"';
QChar escape = '&';
QString string = it.value();
settingLine += delim;
for (QString::const_iterator iter = string.begin(); iter != string.end(); ++iter)
{
if (*iter == delim || *iter == escape)
settingLine += escape;
settingLine += *iter;
}
settingLine += delim;
}
// Quote paths with spaces
if ((it.key() == QLatin1String("data")
|| it.key() == QLatin1String("data-local")
else if ((it.key() == QLatin1String("data-local")
|| it.key() == QLatin1String("resources")) && it.value().contains(QChar(' ')))
{
QString stripped = it.value();

View file

@ -315,16 +315,7 @@ namespace ESM
bool Land::isDataLoaded(int flags) const
{
return mLandData && (mLandData->mDataLoaded & flags) == (flags & mDataTypes);
}
void Land::setDataLoaded(int flags)
{
if (!mLandData)
mLandData = new LandData;
mDataTypes |= flags;
mLandData->mDataLoaded |= flags;
return mLandData && (mLandData->mDataLoaded & flags) == flags;
}
Land::Land (const Land& land)

View file

@ -132,7 +132,6 @@ struct Land
void unloadData() const;
/// Check if given data type is loaded
/// @note We only check data types that *can* be loaded (present in mDataTypes)
bool isDataLoaded(int flags) const;
/// Sets the flags and creates a LandData if needed

View file

@ -380,6 +380,7 @@ static std::map<short,std::string> genNameMap()
names[131] ="sEffectBoundGloves";
names[128] ="sEffectBoundHelm";
names[125] ="sEffectBoundLongbow";
names[126] ="sEffectExtraSpell";
names[121] ="sEffectBoundLongsword";
names[122] ="sEffectBoundMace";
names[130] ="sEffectBoundShield";

View file

@ -75,8 +75,6 @@ void ConfigurationManager::processPaths(Files::PathContainer& dataDirs, bool cre
for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
{
path = it->string();
boost::erase_all(path, "\"");
*it = boost::filesystem::path(path);
// Check if path contains a token
if (!path.empty() && *path.begin() == '?')

View file

@ -49,7 +49,7 @@ BulletNifLoader::~BulletNifLoader()
{
}
osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr nif)
osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr& nif)
{
mShape = new Resource::BulletShape;

View file

@ -50,7 +50,7 @@ public:
abort();
}
osg::ref_ptr<Resource::BulletShape> load(const Nif::NIFFilePtr file);
osg::ref_ptr<Resource::BulletShape> load(const Nif::NIFFilePtr& file);
private:
bool findBoundingBox(const Nif::Node* node, int flags = 0);

View file

@ -1191,8 +1191,8 @@ namespace NifOsg
if (pixelData->mipmaps.empty())
return NULL;
unsigned int width = 0;
unsigned int height = 0;
int width = 0;
int height = 0;
std::vector<unsigned int> mipmapVector;
for (unsigned int i=0; i<pixelData->mipmaps.size()-3; ++i)

View file

@ -63,7 +63,7 @@ class NodeToShapeVisitor : public osg::NodeVisitor
public:
NodeToShapeVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mTriangleMesh(NULL)
, mTriangleMesh(nullptr)
{
}
@ -71,11 +71,11 @@ public:
virtual void apply(osg::Drawable &drawable)
{
if (!mTriangleMesh)
mTriangleMesh = new btTriangleMesh;
mTriangleMesh.reset(new btTriangleMesh);
osg::Matrixf worldMat = osg::computeLocalToWorld(getNodePath());
osg::TriangleFunctor<GetTriangleFunctor> functor;
functor.setTriMesh(mTriangleMesh);
functor.setTriMesh(mTriangleMesh.get());
functor.setMatrix(worldMat);
drawable.accept(functor);
}
@ -86,14 +86,12 @@ public:
return osg::ref_ptr<BulletShape>();
osg::ref_ptr<BulletShape> shape (new BulletShape);
TriangleMeshShape* meshShape = new TriangleMeshShape(mTriangleMesh, true);
shape->mCollisionShape = meshShape;
mTriangleMesh = NULL;
shape->mCollisionShape = new TriangleMeshShape(mTriangleMesh.release(), true);
return shape;
}
private:
btTriangleMesh* mTriangleMesh;
std::unique_ptr<btTriangleMesh> mTriangleMesh;
};
BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager)
@ -141,10 +139,7 @@ osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(const std::string &
node->accept(visitor);
shape = visitor.getShape();
if (!shape)
{
mCache->addEntryToObjectCache(normalized, NULL);
return osg::ref_ptr<BulletShape>();
}
}
mCache->addEntryToObjectCache(normalized, shape);
@ -158,7 +153,8 @@ osg::ref_ptr<BulletShapeInstance> BulletShapeManager::cacheInstance(const std::s
mVFS->normalizeFilename(normalized);
osg::ref_ptr<BulletShapeInstance> instance = createInstance(normalized);
mInstanceCache->addEntryToObjectCache(normalized, instance.get());
if (instance)
mInstanceCache->addEntryToObjectCache(normalized, instance.get());
return instance;
}

View file

@ -69,7 +69,6 @@ namespace Resource
// This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG.
&& !osg::isGLExtensionSupported(0, "GL_S3_s3tc"))
{
std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl;
return false;
}
break;
@ -123,12 +122,31 @@ namespace Resource
return mWarningImage;
}
osg::Image* image = result.getImage();
osg::ref_ptr<osg::Image> image = result.getImage();
image->setFileName(normalized);
if (!checkSupported(image, filename))
{
mCache->addEntryToObjectCache(normalized, mWarningImage);
return mWarningImage;
static bool uncompress = (getenv("OPENMW_DECOMPRESS_TEXTURES") != 0);
if (!uncompress)
{
std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl;
mCache->addEntryToObjectCache(normalized, mWarningImage);
return mWarningImage;
}
else
{
// decompress texture in software if not supported by GPU
// requires update to getColor() to be released with OSG 3.6
osg::ref_ptr<osg::Image> newImage = new osg::Image;
newImage->setFileName(image->getFileName());
newImage->allocateImage(image->s(), image->t(), image->r(), image->isImageTranslucent() ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE);
for (int s=0; s<image->s(); ++s)
for (int t=0; t<image->t(); ++t)
for (int r=0; r<image->r(); ++r)
newImage->setColor(image->getColor(s,t,r), s,t,r);
image = newImage;
}
}
mCache->addEntryToObjectCache(normalized, image);

View file

@ -51,6 +51,11 @@ namespace Resource
void MultiObjectCache::addEntryToObjectCache(const std::string &filename, osg::Object *object)
{
if (!object)
{
OSG_ALWAYS << " trying to add NULL object to cache for " << filename << std::endl;
return;
}
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
_objectCache.insert(std::make_pair(filename, object));
}

View file

@ -34,6 +34,11 @@ ObjectCache::~ObjectCache()
void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp)
{
if (!object)
{
OSG_ALWAYS << " trying to add NULL object to cache for " << filename << std::endl;
return;
}
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
_objectCache[filename]=ObjectTimeStampPair(object,timestamp);
}

View file

@ -244,12 +244,9 @@ namespace Resource
void SceneManager::recreateShaders(osg::ref_ptr<osg::Node> node)
{
Shader::ShaderVisitor shaderVisitor(*mShaderManager.get(), *mImageManager, "objects_vertex.glsl", "objects_fragment.glsl");
shaderVisitor.setForceShaders(mForceShaders);
shaderVisitor.setClampLighting(mClampLighting);
shaderVisitor.setForcePerPixelLighting(mForcePerPixelLighting);
shaderVisitor.setAllowedToModifyStateSets(false);
node->accept(shaderVisitor);
osg::ref_ptr<Shader::ShaderVisitor> shaderVisitor(createShaderVisitor());
shaderVisitor->setAllowedToModifyStateSets(false);
node->accept(*shaderVisitor);
}
void SceneManager::setClampLighting(bool clamp)
@ -516,16 +513,8 @@ namespace Resource
SetFilterSettingsControllerVisitor setFilterSettingsControllerVisitor(mMinFilter, mMagFilter, mMaxAnisotropy);
loaded->accept(setFilterSettingsControllerVisitor);
Shader::ShaderVisitor shaderVisitor(*mShaderManager.get(), *mImageManager, "objects_vertex.glsl", "objects_fragment.glsl");
shaderVisitor.setForceShaders(mForceShaders);
shaderVisitor.setClampLighting(mClampLighting);
shaderVisitor.setForcePerPixelLighting(mForcePerPixelLighting);
shaderVisitor.setAutoUseNormalMaps(mAutoUseNormalMaps);
shaderVisitor.setNormalMapPattern(mNormalMapPattern);
shaderVisitor.setNormalHeightMapPattern(mNormalHeightMapPattern);
shaderVisitor.setAutoUseSpecularMaps(mAutoUseSpecularMaps);
shaderVisitor.setSpecularMapPattern(mSpecularMapPattern);
loaded->accept(shaderVisitor);
osg::ref_ptr<Shader::ShaderVisitor> shaderVisitor (createShaderVisitor());
loaded->accept(*shaderVisitor);
// share state
// do this before optimizing so the optimizer will be able to combine nodes more aggressively
@ -748,4 +737,18 @@ namespace Resource
stats->setAttribute(frameNumber, "Node Instance", mInstanceCache->getCacheSize());
}
Shader::ShaderVisitor *SceneManager::createShaderVisitor()
{
Shader::ShaderVisitor* shaderVisitor = new Shader::ShaderVisitor(*mShaderManager.get(), *mImageManager, "objects_vertex.glsl", "objects_fragment.glsl");
shaderVisitor->setForceShaders(mForceShaders);
shaderVisitor->setClampLighting(mClampLighting);
shaderVisitor->setForcePerPixelLighting(mForcePerPixelLighting);
shaderVisitor->setAutoUseNormalMaps(mAutoUseNormalMaps);
shaderVisitor->setNormalMapPattern(mNormalMapPattern);
shaderVisitor->setNormalHeightMapPattern(mNormalHeightMapPattern);
shaderVisitor->setAutoUseSpecularMaps(mAutoUseSpecularMaps);
shaderVisitor->setSpecularMapPattern(mSpecularMapPattern);
return shaderVisitor;
}
}

View file

@ -31,6 +31,7 @@ namespace osgDB
namespace Shader
{
class ShaderManager;
class ShaderVisitor;
}
namespace Resource
@ -149,6 +150,8 @@ namespace Resource
private:
Shader::ShaderVisitor* createShaderVisitor();
std::unique_ptr<Shader::ShaderManager> mShaderManager;
bool mForceShaders;
bool mClampLighting;

View file

@ -42,13 +42,4 @@ osg::Vec4f colourFromRGB(unsigned int clr)
return colour;
}
osg::Vec4f colourFromRGBA(unsigned int clr)
{
osg::Vec4f colour(((clr >> 0) & 0xFF) / 255.0f,
((clr >> 8) & 0xFF) / 255.0f,
((clr >> 16) & 0xFF) / 255.0f,
((clr >> 24) & 0xFF) / 255.0f);
return colour;
}
}

View file

@ -15,8 +15,6 @@ namespace SceneUtil
osg::Vec4f colourFromRGB (unsigned int clr);
osg::Vec4f colourFromRGBA (unsigned int clr);
}
#endif

View file

@ -19,6 +19,14 @@ namespace SceneUtil
return false;
}
void FindByClassVisitor::apply(osg::Node &node)
{
if (Misc::StringUtils::ciEqual(node.className(), mNameToFind))
mFoundNodes.push_back(&node);
traverse(node);
}
void FindByNameVisitor::apply(osg::Group &group)
{
if (!checkGroup(group))

View file

@ -20,7 +20,6 @@ namespace SceneUtil
}
virtual void apply(osg::Group& group);
virtual void apply(osg::MatrixTransform& node);
virtual void apply(osg::Geometry& node);
@ -30,6 +29,21 @@ namespace SceneUtil
osg::Group* mFoundNode;
};
class FindByClassVisitor : public osg::NodeVisitor
{
public:
FindByClassVisitor(const std::string& nameToFind)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mNameToFind(nameToFind)
{
}
virtual void apply(osg::Node &node);
std::string mNameToFind;
std::vector<osg::Node *> mFoundNodes;
};
// Disable freezeOnCull for all visited particlesystems
class DisableFreezeOnCullVisitor : public osg::NodeVisitor
{

View file

@ -119,6 +119,7 @@ unsigned int WorkQueue::getNumActiveThreads() const
WorkThread::WorkThread(WorkQueue *workQueue)
: mWorkQueue(workQueue)
, mActive(false)
{
}

View file

@ -1,4 +1,4 @@
Copyright (c) 2014 Jannik Heller <scrawl@baseoftrash.de>, Chris Robinson
Copyright (c) 2014 scrawl, Chris Robinson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: