1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-01 04:45:34 +00:00

Fixed race.cpp

This commit is contained in:
Britt Mathis 2013-04-17 19:38:13 -04:00
commit 1dff1fabdb
50 changed files with 1007 additions and 252 deletions

View file

@ -439,7 +439,7 @@ void Record<ESM::Apparatus>::print()
template<>
void Record<ESM::BodyPart>::print()
{
std::cout << " Name: " << mData.mName << std::endl;
std::cout << " Race: " << mData.mRace << std::endl;
std::cout << " Model: " << mData.mModel << std::endl;
std::cout << " Type: " << meshTypeLabel(mData.mData.mType)
<< " (" << (int)mData.mData.mType << ")" << std::endl;

View file

@ -102,3 +102,9 @@ if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(omwlauncher gcov)
endif()
# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream
if (UNIX AND NOT APPLE)
target_link_libraries(omwlauncher dl Xt)
endif()

View file

@ -22,7 +22,7 @@ opencs_units (model/world
opencs_units_noqt (model/world
universalid data record idcollection commands columnbase scriptcontext
universalid data record idcollection commands columnbase scriptcontext cell
)
opencs_hdrs_noqt (model/world

View file

@ -0,0 +1,20 @@
#include "cell.hpp"
#include <sstream>
void CSMWorld::Cell::load (ESM::ESMReader &esm)
{
mName = mId;
ESM::Cell::load (esm, true); /// \todo set this to false, once the bug in ESM::Cell::load is fixed
if (!(mData.mFlags & Interior))
{
std::ostringstream stream;
stream << "#" << mData.mX << " " << mData.mY;
mId = stream.str();
}
}

View file

@ -0,0 +1,17 @@
#ifndef CSM_WOLRD_CELL_H
#define CSM_WOLRD_CELL_H
#include <components/esm/loadcell.hpp>
namespace CSMWorld
{
/// \brief Wrapper for Cell record
struct Cell : public ESM::Cell
{
std::string mId;
void load (ESM::ESMReader &esm);
};
}
#endif

View file

@ -748,6 +748,31 @@ namespace CSMWorld
return true;
}
};
template<typename ESXRecordT>
struct RegionColumn : public Column<ESXRecordT>
{
RegionColumn() : Column<ESXRecordT> ("Region", ColumnBase::Display_String) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mRegion.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mRegion = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
}
#endif

View file

@ -119,6 +119,15 @@ CSMWorld::Data::Data()
mSpells.addColumn (new FlagColumn<ESM::Spell> ("Starter Spell", 0x2));
mSpells.addColumn (new FlagColumn<ESM::Spell> ("Always Succeeds", 0x4));
mCells.addColumn (new StringIdColumn<Cell>);
mCells.addColumn (new RecordStateColumn<Cell>);
mCells.addColumn (new FixedRecordTypeColumn<Cell> (UniversalId::Type_Cell));
mCells.addColumn (new NameColumn<Cell>);
mCells.addColumn (new FlagColumn<Cell> ("Sleep forbidden", ESM::Cell::NoSleep));
mCells.addColumn (new FlagColumn<Cell> ("Interior Water", ESM::Cell::HasWater));
mCells.addColumn (new FlagColumn<Cell> ("Interior Sky", ESM::Cell::QuasiEx));
mCells.addColumn (new RegionColumn<Cell>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill);
@ -130,6 +139,7 @@ CSMWorld::Data::Data()
addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region);
addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign);
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell);
addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell);
}
CSMWorld::Data::~Data()
@ -248,6 +258,16 @@ CSMWorld::IdCollection<ESM::Spell>& CSMWorld::Data::getSpells()
return mSpells;
}
const CSMWorld::IdCollection<CSMWorld::Cell>& CSMWorld::Data::getCells() const
{
return mCells;
}
CSMWorld::IdCollection<CSMWorld::Cell>& CSMWorld::Data::getCells()
{
return mCells;
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id)
{
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -293,6 +313,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base)
case ESM::REC_REGN: mRegions.load (reader, base); break;
case ESM::REC_BSGN: mBirthsigns.load (reader, base); break;
case ESM::REC_SPEL: mSpells.load (reader, base); break;
case ESM::REC_CELL: mCells.load (reader, base); break;
default:

View file

@ -20,6 +20,7 @@
#include "idcollection.hpp"
#include "universalid.hpp"
#include "cell.hpp"
class QAbstractItemModel;
@ -38,6 +39,7 @@ namespace CSMWorld
IdCollection<ESM::Region> mRegions;
IdCollection<ESM::BirthSign> mBirthsigns;
IdCollection<ESM::Spell> mSpells;
IdCollection<Cell> mCells;
std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
@ -98,6 +100,10 @@ namespace CSMWorld
IdCollection<ESM::Spell>& getSpells();
const IdCollection<Cell>& getCells() const;
IdCollection<Cell>& getCells();
QAbstractItemModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown.
///

View file

@ -325,10 +325,10 @@ namespace CSMWorld
{
std::string id = reader.getHNOString ("NAME");
int index = searchId (id);
if (reader.isNextSub ("DELE"))
{
int index = searchId (id);
reader.skipRecord();
if (index==-1)
@ -354,6 +354,8 @@ namespace CSMWorld
record.mId = id;
record.load (reader);
int index = searchId (record.mId);
if (index==-1)
{
// new record

View file

@ -28,6 +28,7 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};
@ -45,6 +46,7 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};

View file

@ -55,7 +55,9 @@ namespace CSMWorld
Type_Birthsigns,
Type_Birthsign,
Type_Spells,
Type_Spell
Type_Spell,
Type_Cells,
Type_Cell
};
private:

View file

@ -125,6 +125,10 @@ void CSVDoc::View::setupWorldMenu()
QAction *spells = new QAction (tr ("Spells"), this);
connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView()));
world->addAction (spells);
QAction *cells = new QAction (tr ("Cells"), this);
connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView()));
world->addAction (cells);
}
void CSVDoc::View::setupUi()
@ -325,6 +329,11 @@ void CSVDoc::View::addSpellsSubView()
addSubView (CSMWorld::UniversalId::Type_Spells);
}
void CSVDoc::View::addCellsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Cells);
}
void CSVDoc::View::abortOperation (int type)
{
mDocument->abortOperation (type);

View file

@ -133,6 +133,8 @@ namespace CSVDoc
void addBirthsignsSubView();
void addSpellsSubView();
void addCellsSubView();
};
}

View file

@ -26,6 +26,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
CSMWorld::UniversalId::Type_Regions,
CSMWorld::UniversalId::Type_Birthsigns,
CSMWorld::UniversalId::Type_Spells,
CSMWorld::UniversalId::Type_Cells,
CSMWorld::UniversalId::Type_None // end marker
};

View file

@ -122,6 +122,12 @@ if (UNIX AND NOT APPLE)
target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
endif()
# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream
if (UNIX AND NOT APPLE)
target_link_libraries(openmw dl Xt)
endif()
if(APPLE)
find_library(CARBON_FRAMEWORK Carbon)
find_library(COCOA_FRAMEWORK Cocoa)

View file

@ -161,7 +161,7 @@ void OMW::Engine::loadBSA()
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
// Last data dir has the highest priority
std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i);
std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i, 8, '0');
Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName);
std::string dataDirectory = iter->string();
@ -176,7 +176,7 @@ void OMW::Engine::loadBSA()
if (mFileCollections.doesExist(*archive))
{
// Last BSA has the highest priority
std::string groupName = "DataBSA" + Ogre::StringConverter::toString(dataDirs.size()-i);
std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i, 8, '0');
Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName);
@ -368,6 +368,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins,
mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap,
mActivationDistanceOverride));
MWBase::Environment::get().getWorld()->setupPlayer(mNewGame);
//Load translation data
mTranslationDataStorage.setEncoder(mEncoder);

View file

@ -321,6 +321,7 @@ namespace MWBase
virtual void changeVanityModeScale(float factor) = 0;
virtual bool vanityRotateCamera(float * rot) = 0;
virtual void setupPlayer(bool newGame) = 0;
virtual void renderPlayer() = 0;
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;

View file

@ -292,7 +292,7 @@ namespace MWClass
ref->mBase = record;
}
int Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
std::pair<int, std::string> Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
{
MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc);
@ -317,10 +317,7 @@ namespace MWClass
{
if((*itr).mPart == ESM::PRT_Head)
{
if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() )
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}");
return 0;
return std::make_pair(0, "#{sNotifyMessage13}");
}
}
}
@ -331,9 +328,7 @@ namespace MWClass
{
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
{
if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() )
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}");
return 0;
return std::make_pair(0, "#{sNotifyMessage14}");
}
}
}
@ -344,7 +339,7 @@ namespace MWClass
MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if(weapon == invStore.end())
return 1;
return std::make_pair(1,"");
if(weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
@ -354,12 +349,12 @@ namespace MWClass
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
{
return 3;
return std::make_pair(3,"");
}
return 1;
return std::make_pair(1,"");
}
}
return 1;
return std::make_pair(1,"");
}
boost::shared_ptr<MWWorld::Action> Armor::use (const MWWorld::Ptr& ptr) const

View file

@ -67,8 +67,9 @@ namespace MWClass
virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const;
virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that.
virtual std::pair<int, std::string> canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. \n
/// Second item in the pair specifies the error message
virtual boost::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
const;

View file

@ -238,7 +238,7 @@ namespace MWClass
ref->mBase = record;
}
int Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
std::pair<int, std::string> Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
{
// slots that this item can be equipped in
std::pair<std::vector<int>, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
@ -260,12 +260,7 @@ namespace MWClass
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
if((*itr).mPart == ESM::PRT_Head)
{
if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() )
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}");
return 0;
}
return std::make_pair(0, "#{sNotifyMessage13}");
}
}
@ -274,19 +269,12 @@ namespace MWClass
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
{
if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() )
{
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}");
}
return 0;
}
return std::make_pair(0, "#{sNotifyMessage15}");
}
}
}
}
return 1;
return std::make_pair (1, "");
}
boost::shared_ptr<MWWorld::Action> Clothing::use (const MWWorld::Ptr& ptr) const

View file

@ -61,8 +61,9 @@ namespace MWClass
virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const;
virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
virtual std::pair<int, std::string> canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that.
/// Second item in the pair specifies the error message
virtual boost::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
const;

View file

@ -384,7 +384,7 @@ namespace MWClass
ref->mBase = record;
}
int Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
std::pair<int, std::string> Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
{
std::pair<std::vector<int>, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
@ -402,12 +402,12 @@ namespace MWClass
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
{
return 2;
return std::make_pair (2, "");
}
return 1;
return std::make_pair (1, "");
}
}
return 0;
return std::make_pair (0, "");
}
boost::shared_ptr<MWWorld::Action> Weapon::use (const MWWorld::Ptr& ptr) const

View file

@ -67,8 +67,9 @@ namespace MWClass
virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const;
virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
virtual std::pair<int, std::string> canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that.
/// Second item in the pair specifies the error message
virtual boost::shared_ptr<MWWorld::Action> use (const MWWorld::Ptr& ptr)
const;

View file

@ -21,36 +21,6 @@ namespace
else
return index;
}
int countParts(const std::string &part, const std::string &race, bool male)
{
/// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs
const MWWorld::Store<ESM::BodyPart> &store =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
std::string prefix =
"b_n_" + race + ((male) ? "_m_" : "_f_") + part;
std::string suffix;
suffix.reserve(prefix.size() + 3);
int count = -1;
do {
++count;
suffix = "_" + (boost::format("%02d") % (count + 1)).str();
}
while (store.search(prefix + suffix) != 0);
if (count == 0 && part == "hair") {
count = -1;
do {
++count;
suffix = (boost::format("%02d") % (count + 1)).str();
}
while (store.search(prefix + suffix) != 0);
}
return count;
}
}
namespace MWGui
@ -61,8 +31,6 @@ namespace MWGui
, mGenderIndex(0)
, mFaceIndex(0)
, mHairIndex(0)
, mFaceCount(10)
, mHairCount(14)
, mCurrentAngle(0)
{
// Centre dialog
@ -227,67 +195,28 @@ namespace MWGui
void RaceDialog::onSelectPreviousFace(MyGUI::Widget*)
{
do
mFaceIndex = wrap(mFaceIndex - 1, mFaceCount);
while (!isFacePlayable());
mFaceIndex = wrap(mFaceIndex - 1, mAvailableHeads.size());
updatePreview();
}
void RaceDialog::onSelectNextFace(MyGUI::Widget*)
{
do
mFaceIndex = wrap(mFaceIndex + 1, mFaceCount);
while (!isFacePlayable());
mFaceIndex = wrap(mFaceIndex + 1, mAvailableHeads.size());
updatePreview();
}
void RaceDialog::onSelectPreviousHair(MyGUI::Widget*)
{
do
mHairIndex = wrap(mHairIndex - 1, mHairCount);
while (!isHairPlayable());
mHairIndex = wrap(mHairIndex - 1, mAvailableHairs.size());
updatePreview();
}
void RaceDialog::onSelectNextHair(MyGUI::Widget*)
{
do
mHairIndex = wrap(mHairIndex + 1, mHairCount);
while (!isHairPlayable());
mHairIndex = wrap(mHairIndex + 1, mAvailableHairs.size());
updatePreview();
}
bool RaceDialog::isFacePlayable()
{
std::string prefix =
"b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_");
std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str();
const MWWorld::Store<ESM::BodyPart> &parts =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
if (parts.search(prefix + "head_" + headIndex) == 0)
return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable);
else
return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable);
}
bool RaceDialog::isHairPlayable()
{
std::string prefix =
"b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_");
std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str();
const MWWorld::Store<ESM::BodyPart> &parts =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
if (parts.search(prefix + "hair_" + hairIndex) == 0)
return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable);
else
return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable);
}
void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
@ -308,18 +237,41 @@ namespace MWGui
updateSpellPowers();
}
void RaceDialog::getBodyParts (int part, std::vector<std::string>& out)
{
out.clear();
const MWWorld::Store<ESM::BodyPart> &store =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
for (MWWorld::Store<ESM::BodyPart>::iterator it = store.begin(); it != store.end(); ++it)
{
const ESM::BodyPart& bodypart = *it;
if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable)
continue;
if (bodypart.mData.mType != ESM::BodyPart::MT_Skin)
continue;
if (bodypart.mData.mPart != static_cast<ESM::BodyPart::MeshPart>(part))
continue;
if (mGenderIndex != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female))
continue;
bool firstPerson = (bodypart.mId.size() >= 3)
&& bodypart.mId[bodypart.mId.size()-3] == '1'
&& bodypart.mId[bodypart.mId.size()-2] == 's'
&& bodypart.mId[bodypart.mId.size()-1] == 't';
if (firstPerson)
continue;
if (Misc::StringUtils::ciEqual(bodypart.mRace, mCurrentRaceId))
out.push_back(bodypart.mId);
}
}
void RaceDialog::recountParts()
{
mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0);
mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0);
getBodyParts(ESM::BodyPart::MP_Hair, mAvailableHairs);
getBodyParts(ESM::BodyPart::MP_Head, mAvailableHeads);
mFaceIndex = 0;
mHairIndex = 0;
while (!isHairPlayable())
mHairIndex = wrap(mHairIndex + 1, mHairCount);
while (!isFacePlayable())
mFaceIndex = wrap(mFaceIndex + 1, mFaceCount);
}
// update widget content
@ -330,21 +282,9 @@ namespace MWGui
record.mRace = mCurrentRaceId;
record.setIsMale(mGenderIndex == 0);
std::string prefix =
"b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_");
record.mHead = mAvailableHeads[mFaceIndex];
record.mHair = mAvailableHairs[mHairIndex];
std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str();
std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str();
record.mHead = prefix + "head_" + headIndex;
record.mHair = prefix + "hair_" + hairIndex;
const MWWorld::Store<ESM::BodyPart> &parts =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
if (parts.search(record.mHair) == 0) {
record.mHair = prefix + "hair" + hairIndex;
}
mPreview->setPrototype(record);
}
@ -442,5 +382,4 @@ namespace MWGui
++i;
}
}
}

View file

@ -76,8 +76,10 @@ namespace MWGui
void updatePreview();
void recountParts();
bool isHairPlayable();
bool isFacePlayable();
void getBodyParts (int part, std::vector<std::string>& out);
std::vector<std::string> mAvailableHeads;
std::vector<std::string> mAvailableHairs;
MyGUI::ImageBox* mPreviewImage;
MyGUI::ListBox* mRaceList;
@ -90,7 +92,6 @@ namespace MWGui
std::vector<MyGUI::Widget*> mSpellPowerItems;
int mGenderIndex, mFaceIndex, mHairIndex;
int mFaceCount, mHairCount;
std::string mCurrentRaceId;

View file

@ -134,21 +134,22 @@ namespace MWGui
int x,y;
bool interior = _sender->getUserString("interior") == "y";
MWBase::Environment::get().getWorld()->positionToIndex(pos.pos[0],pos.pos[1],x,y);
MWWorld::CellStore* cell;
if(interior) cell = MWBase::Environment::get().getWorld()->getInterior(cellname);
if(interior)
MWBase::Environment::get().getWorld()->changeToInteriorCell(cellname, pos);
else
{
cell = MWBase::Environment::get().getWorld()->getExterior(x,y);
ESM::Position PlayerPos = player.getRefData().getPosition();
float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) );
int time = int(d /MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fTravelTimeMult")->getFloat());
for(int i = 0;i < time;i++)
ESM::Position playerPos = player.getRefData().getPosition();
float d = Ogre::Vector3(pos.pos[0], pos.pos[1], 0).distance(
Ogre::Vector3(playerPos.pos[0], playerPos.pos[1], 0));
int hours = static_cast<int>(d /MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fTravelTimeMult")->getFloat());
for(int i = 0;i < hours;i++)
{
MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats ();
}
MWBase::Environment::get().getWorld()->advanceTime(time);
MWBase::Environment::get().getWorld()->advanceTime(hours);
MWBase::Environment::get().getWorld()->changeToExteriorCell(pos);
}
MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]);
MWWorld::Class::get(player).adjustPosition(player);
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel);

View file

@ -155,6 +155,18 @@ namespace MWMechanics
stat.setCurrent (stat.getModified());
creatureStats.setDynamic (i, stat);
}
// unequip any items that may not be equipped. we need this for when the race is changed to a beast race
MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr);
for (int i=0; i<MWWorld::InventoryStore::Slots; ++i)
{
MWWorld::ContainerStoreIterator it = invStore.getSlot(i);
if (it != invStore.end())
{
if (!MWWorld::Class::get(*it).canBeEquipped(*it, ptr).first)
invStore.equip(i, invStore.end());
}
}
}
MechanicsManager::MechanicsManager()

View file

@ -80,7 +80,7 @@ namespace MWMechanics
const ESM::Spell *spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mFlags & ESM::Spell::ST_Disease)
if (spell->mData.mType == ESM::Spell::ST_Disease)
return true;
}
@ -94,7 +94,7 @@ namespace MWMechanics
const ESM::Spell *spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mFlags & ESM::Spell::ST_Blight)
if (spell->mData.mType == ESM::Spell::ST_Blight)
return true;
}

View file

@ -94,6 +94,9 @@ void Actors::insertActivator (const MWWorld::Ptr& ptr)
bool Actors::deleteObject (const MWWorld::Ptr& ptr)
{
if (mAllActors.find(ptr) == mAllActors.end())
return false;
mRendering->removeWaterRippleEmitter (ptr);
delete mAllActors[ptr];
@ -139,6 +142,7 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store)
Ogre::SceneNode *base = celliter->second;
base->removeAndDestroyAllChildren();
mRend.getScene()->destroySceneNode(base);
mCellSceneNodes.erase(celliter);
}
}

View file

@ -305,56 +305,83 @@ void NpcAnimation::updateParts(bool forceupdate)
if(mViewMode == VM_HeadOnly)
return;
static const struct {
ESM::PartReferenceType type;
const char name[2][12];
} PartTypeList[] = {
{ ESM::PRT_Neck, { "neck", "" } },
{ ESM::PRT_Cuirass, { "chest", "" } },
{ ESM::PRT_Groin, { "groin", "" } },
{ ESM::PRT_RHand, { "hand", "hands" } },
{ ESM::PRT_LHand, { "hand", "hands" } },
{ ESM::PRT_RWrist, { "wrist", "" } },
{ ESM::PRT_LWrist, { "wrist", "" } },
{ ESM::PRT_RForearm, { "forearm", "" } },
{ ESM::PRT_LForearm, { "forearm", "" } },
{ ESM::PRT_RUpperarm, { "upper arm", "" } },
{ ESM::PRT_LUpperarm, { "upper arm", "" } },
{ ESM::PRT_RFoot, { "foot", "feet" } },
{ ESM::PRT_LFoot, { "foot", "feet" } },
{ ESM::PRT_RAnkle, { "ankle", "" } },
{ ESM::PRT_LAnkle, { "ankle", "" } },
{ ESM::PRT_RKnee, { "knee", "" } },
{ ESM::PRT_LKnee, { "knee", "" } },
{ ESM::PRT_RLeg, { "upper leg", "" } },
{ ESM::PRT_LLeg, { "upper leg", "" } },
{ ESM::PRT_Tail, { "tail", "" } }
};
std::map<int, int> bodypartMap;
bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck;
bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest;
bodypartMap[ESM::PRT_Groin] = ESM::BodyPart::MP_Groin;
bodypartMap[ESM::PRT_RHand] = ESM::BodyPart::MP_Hand;
bodypartMap[ESM::PRT_LHand] = ESM::BodyPart::MP_Hand;
bodypartMap[ESM::PRT_RWrist] = ESM::BodyPart::MP_Wrist;
bodypartMap[ESM::PRT_LWrist] = ESM::BodyPart::MP_Wrist;
bodypartMap[ESM::PRT_RForearm] = ESM::BodyPart::MP_Forearm;
bodypartMap[ESM::PRT_LForearm] = ESM::BodyPart::MP_Forearm;
bodypartMap[ESM::PRT_RUpperarm] = ESM::BodyPart::MP_Upperarm;
bodypartMap[ESM::PRT_LUpperarm] = ESM::BodyPart::MP_Upperarm;
bodypartMap[ESM::PRT_RFoot] = ESM::BodyPart::MP_Foot;
bodypartMap[ESM::PRT_LFoot] = ESM::BodyPart::MP_Foot;
bodypartMap[ESM::PRT_RAnkle] = ESM::BodyPart::MP_Ankle;
bodypartMap[ESM::PRT_LAnkle] = ESM::BodyPart::MP_Ankle;
bodypartMap[ESM::PRT_RKnee] = ESM::BodyPart::MP_Knee;
bodypartMap[ESM::PRT_LKnee] = ESM::BodyPart::MP_Knee;
bodypartMap[ESM::PRT_RLeg] = ESM::BodyPart::MP_Upperleg;
bodypartMap[ESM::PRT_LLeg] = ESM::BodyPart::MP_Upperleg;
bodypartMap[ESM::PRT_Tail] = ESM::BodyPart::MP_Tail;
const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : "";
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++)
const int Flag_Female = 0x01;
const int Flag_FirstPerson = 0x02;
int flags = 0;
if (!mNpc->isMale())
flags |= Flag_Female;
if (mViewMode == VM_FirstPerson)
flags |= Flag_FirstPerson;
// Remember body parts so we only have to search through the store once for each race/gender/viewmode combination
static std::map< std::pair<std::string, int> , std::vector<const ESM::BodyPart*> > sRaceMapping;
std::string race = Misc::StringUtils::lowerCase(mNpc->mRace);
std::pair<std::string, int> thisCombination = std::make_pair(race, flags);
if (sRaceMapping.find(thisCombination) == sRaceMapping.end())
{
if(mPartPriorities[PartTypeList[i].type] < 1)
sRaceMapping[thisCombination].resize(ESM::PRT_Count);
for (int i=0; i<ESM::PRT_Count; ++i)
sRaceMapping[thisCombination][i] = NULL;
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
for (MWWorld::Store<ESM::BodyPart>::iterator it = partStore.begin(); it != partStore.end(); ++it)
{
const ESM::BodyPart *part = NULL;
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
if(!mNpc->isMale())
const ESM::BodyPart& bodypart = *it;
if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable)
continue;
if (bodypart.mData.mType != ESM::BodyPart::MT_Skin)
{
part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]+ext);
if(part == 0)
part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]+ext);
continue;
}
if(part == 0)
part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]+ext);
if(part == 0)
part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]+ext);
if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female))
continue;
if (!Misc::StringUtils::ciEqual(bodypart.mRace, mNpc->mRace))
continue;
if(part)
addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel);
bool firstPerson = (bodypart.mId.size() >= 3)
&& bodypart.mId[bodypart.mId.size()-3] == '1'
&& bodypart.mId[bodypart.mId.size()-2] == 's'
&& bodypart.mId[bodypart.mId.size()-1] == 't';
if (firstPerson != (mViewMode == VM_FirstPerson))
continue;
for (std::map<int, int>::iterator bIt = bodypartMap.begin(); bIt != bodypartMap.end(); ++bIt )
if (bIt->second == bodypart.mData.mPart)
sRaceMapping[thisCombination][bIt->first] = &*it;
}
}
for (int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part)
{
const ESM::BodyPart* bodypart = sRaceMapping[thisCombination][part];
if (mPartPriorities[part] < 1 && bodypart)
addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
}
}
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)

View file

@ -788,8 +788,8 @@ void VideoState::decode_thread_loop(VideoState *self)
// main decode loop
while(!self->quit)
{
if((self->audio_st >= 0 && self->audioq.size > MAX_AUDIOQ_SIZE) ||
(self->video_st >= 0 && self->videoq.size > MAX_VIDEOQ_SIZE))
if((self->audio_st && self->audioq.size > MAX_AUDIOQ_SIZE) ||
(self->video_st && self->videoq.size > MAX_VIDEOQ_SIZE))
{
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
continue;

View file

@ -21,7 +21,13 @@ namespace MWWorld
MWWorld::Ptr object = getTarget();
MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor);
switch(MWWorld::Class::get (object).canBeEquipped (object, actor))
std::pair <int, std::string> result = MWWorld::Class::get (object).canBeEquipped (object, actor);
// display error message if the player tried to equip something
if (!result.second.empty() && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer())
MWBase::Environment::get().getWindowManager()->messageBox(result.second);
switch(result.first)
{
case 0:
return;
@ -48,8 +54,6 @@ namespace MWWorld
assert(it != invStore.end());
std::string npcRace = actor.get<ESM::NPC>()->mBase->mRace;
bool equipped = false;
// equip the item in the first free slot

View file

@ -13,8 +13,8 @@ namespace ESM
namespace MWWorld
{
/// List all (Ogre-)handles.
struct ListHandles
/// List all (Ogre-)handles, then reset RefData::mBaseNode to 0.
struct ListAndResetHandles
{
std::vector<Ogre::SceneNode*> mHandles;
@ -23,6 +23,8 @@ namespace MWWorld
Ogre::SceneNode* handle = data.getBaseNode();
if (handle)
mHandles.push_back (handle);
data.setBaseNode(0);
return true;
}
};

View file

@ -165,6 +165,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce
else
return Ptr();
}
MWWorld::Ptr ptr;
if (MWWorld::LiveCellRef<ESM::Activator> *ref = cell.mActivators.find (name))
@ -246,16 +247,16 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
}
// Then check cells that are already listed
for (std::map<std::string, Ptr::CellStore>::iterator iter = mInteriors.begin();
iter!=mInteriors.end(); ++iter)
for (std::map<std::pair<int, int>, Ptr::CellStore>::iterator iter = mExteriors.begin();
iter!=mExteriors.end(); ++iter)
{
Ptr ptr = getPtrAndCache (name, iter->second);
if (!ptr.isEmpty())
return ptr;
return ptr;
}
for (std::map<std::pair<int, int>, Ptr::CellStore>::iterator iter = mExteriors.begin();
iter!=mExteriors.end(); ++iter)
for (std::map<std::string, Ptr::CellStore>::iterator iter = mInteriors.begin();
iter!=mInteriors.end(); ++iter)
{
Ptr ptr = getPtrAndCache (name, iter->second);
if (!ptr.isEmpty())
@ -266,7 +267,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
const MWWorld::Store<ESM::Cell> &cells = mStore.get<ESM::Cell>();
MWWorld::Store<ESM::Cell>::iterator iter;
for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter)
for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter)
{
Ptr::CellStore *cellStore = getCellStore (&(*iter));
@ -276,7 +277,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
return ptr;
}
for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter)
for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter)
{
Ptr::CellStore *cellStore = getCellStore (&(*iter));

View file

@ -264,9 +264,9 @@ namespace MWWorld
throw std::runtime_error ("class can't be enchanted");
}
int Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
std::pair<int, std::string> Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
{
return 1;
return std::make_pair (1, "");
}
void Class::adjustPosition(const MWWorld::Ptr& ptr) const

View file

@ -245,8 +245,9 @@ namespace MWWorld
virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const;
virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
virtual std::pair<int, std::string> canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that.
/// Second item in the pair specifies the error message
virtual Ptr
copyToCell(const Ptr &ptr, CellStore &cell) const;

View file

@ -186,7 +186,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc)
}
}
switch(MWWorld::Class::get (test).canBeEquipped (test, npc))
switch(MWWorld::Class::get (test).canBeEquipped (test, npc).first)
{
case 0:
continue;

View file

@ -76,27 +76,28 @@ namespace MWWorld
void Scene::unloadCell (CellStoreCollection::iterator iter)
{
std::cout << "Unloading cell\n";
ListHandles functor;
ListAndResetHandles functor;
(*iter)->forEach<ListHandles>(functor);
(*iter)->forEach<ListAndResetHandles>(functor);
{
// silence annoying g++ warning
for (std::vector<Ogre::SceneNode*>::const_iterator iter2 (functor.mHandles.begin());
iter2!=functor.mHandles.end(); ++iter2){
Ogre::SceneNode* node = *iter2;
iter2!=functor.mHandles.end(); ++iter2)
{
Ogre::SceneNode* node = *iter2;
mPhysics->removeObject (node->getName());
}
}
if ((*iter)->mCell->isExterior())
{
ESM::Land* land =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Land>().search(
(*iter)->mCell->getGridX(),
(*iter)->mCell->getGridY()
);
if (land)
mPhysics->removeHeightField( (*iter)->mCell->getGridX(), (*iter)->mCell->getGridY() );
}
if ((*iter)->mCell->isExterior())
{
ESM::Land* land =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Land>().search(
(*iter)->mCell->getGridX(),
(*iter)->mCell->getGridY()
);
if (land)
mPhysics->removeHeightField( (*iter)->mCell->getGridX(), (*iter)->mCell->getGridY() );
}
mRendering.removeCell(*iter);

View file

@ -24,6 +24,7 @@
#include "manualref.hpp"
#include "cellfunctors.hpp"
#include "containerstore.hpp"
#include "inventorystore.hpp"
using namespace Ogre;
@ -210,9 +211,6 @@ namespace MWWorld
mStore.setUp();
mPlayer = new MWWorld::Player (mStore.get<ESM::NPC>().find ("player"), *this);
mRendering->attachCameraTo(mPlayer->getPlayer());
// global variables
mGlobalVariables = new Globals (mStore);
@ -801,8 +799,8 @@ namespace MWWorld
void World::scaleObject (const Ptr& ptr, float scale)
{
MWWorld::Class::get(ptr).adjustScale(ptr,scale);
ptr.getCellRef().mScale = scale;
MWWorld::Class::get(ptr).adjustScale(ptr,scale);
if(ptr.getRefData().getBaseNode() == 0)
return;
@ -1369,6 +1367,18 @@ namespace MWWorld
return mRendering->vanityRotateCamera(rot);
}
void World::setupPlayer(bool newGame)
{
const ESM::NPC* player = mStore.get<ESM::NPC>().find ("player");
mPlayer = new MWWorld::Player (player, *this);
mRendering->attachCameraTo(mPlayer->getPlayer());
if (newGame)
{
MWWorld::Class::get(mPlayer->getPlayer()).getContainerStore(mPlayer->getPlayer()).fill(player->mInventory, "", mStore);
MWWorld::Class::get(mPlayer->getPlayer()).getInventoryStore(mPlayer->getPlayer()).autoEquip (mPlayer->getPlayer());
}
}
void World::renderPlayer()
{
mRendering->renderPlayer(mPlayer->getPlayer());

View file

@ -363,6 +363,7 @@ namespace MWWorld
virtual bool vanityRotateCamera(float * rot);
virtual void setupPlayer(bool newGame);
virtual void renderPlayer();
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering);

View file

@ -38,7 +38,9 @@ enum PartReferenceType
PRT_RPauldron = 23,
PRT_LPauldron = 24,
PRT_Weapon = 25,
PRT_Tail = 26
PRT_Tail = 26,
PRT_Count = 27
};
// Reference to body parts

View file

@ -9,13 +9,13 @@ namespace ESM
void BodyPart::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
mName = esm.getHNString("FNAM");
mRace = esm.getHNString("FNAM");
esm.getHNT(mData, "BYDT", 4);
}
void BodyPart::save(ESMWriter &esm)
{
esm.writeHNCString("MODL", mModel);
esm.writeHNCString("FNAM", mName);
esm.writeHNCString("FNAM", mRace);
esm.writeHNT("BYDT", mData, 4);
}

View file

@ -27,7 +27,9 @@ struct BodyPart
MP_Knee = 11,
MP_Upperleg = 12,
MP_Clavicle = 13,
MP_Tail = 14
MP_Tail = 14,
MP_Count = 15
};
enum Flags
@ -52,7 +54,7 @@ struct BodyPart
};
BYDTstruct mData;
std::string mId, mModel, mName;
std::string mId, mModel, mRace;
void load(ESMReader &esm);
void save(ESMWriter &esm);

View file

@ -356,4 +356,22 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref)
return true;
}
void Cell::blank()
{
mName.clear();
mRegion.clear();
mWater = 0;
mWaterInt = false;
mMapColor = 0;
mNAM0 = 0;
mData.mFlags = 0;
mData.mX = 0;
mData.mY = 0;
mAmbi.mAmbient = 0;
mAmbi.mSunlight = 0;
mAmbi.mFog = 0;
mAmbi.mFogDensity = 0;
}
}

View file

@ -140,6 +140,9 @@ struct Cell
* Since they are comparably rare, we use a separate method for this.
*/
static bool getNextMVRF(ESMReader &esm, MovedCellRef &mref);
void blank();
///< Set record to default state (does not touch the ID/index).
};
}
#endif

View file

@ -351,14 +351,19 @@ class NIFObjectLoader
static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl)
{
Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point");
emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir)));
emitter->setAngle(Ogre::Radian(partctrl->verticalAngle));
Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif");
emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom,
partctrl->velocity+partctrl->velocityRandom);
emitter->setEmissionRate(partctrl->emitRate);
emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom,
partctrl->lifetime+partctrl->lifetimeRandom);
emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x));
emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.y));
emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.z));
emitter->setParameter("vertical_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalDir).valueDegrees()));
emitter->setParameter("vertical_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalAngle).valueDegrees()));
emitter->setParameter("horizontal_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalDir).valueDegrees()));
emitter->setParameter("horizontal_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalAngle).valueDegrees()));
Nif::ExtraPtr e = partctrl->extra;
while(!e.empty())
@ -366,21 +371,44 @@ class NIFObjectLoader
if(e->recType == Nif::RC_NiParticleGrowFade)
{
const Nif::NiParticleGrowFade *gf = static_cast<const Nif::NiParticleGrowFade*>(e.getPtr());
Ogre::ParticleAffector *affector = partsys->addAffector("GrowFade");
affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime));
affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime));
}
else if(e->recType == Nif::RC_NiParticleRotation)
else if(e->recType == Nif::RC_NiGravity)
{
// TODO: Implement (Ogre::RotationAffector?)
const Nif::NiGravity *gr = static_cast<const Nif::NiGravity*>(e.getPtr());
Ogre::ParticleAffector *affector = partsys->addAffector("Gravity");
affector->setParameter("force", Ogre::StringConverter::toString(gr->mForce));
affector->setParameter("force_type", (gr->mType==0) ? "wind" : "point");
affector->setParameter("direction", Ogre::StringConverter::toString(gr->mDirection));
affector->setParameter("position", Ogre::StringConverter::toString(gr->mPosition));
}
else if(e->recType == Nif::RC_NiParticleColorModifier)
{
// TODO: Implement (Ogre::ColourInterpolatorAffector?)
const Nif::NiParticleColorModifier *cl = static_cast<const Nif::NiParticleColorModifier*>(e.getPtr());
const Nif::NiColorData *clrdata = cl->data.getPtr();
Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator");
size_t num_colors = std::min<size_t>(6, clrdata->mKeyList.mKeys.size());
for(size_t i = 0;i < num_colors;i++)
{
Ogre::ColourValue color;
color.r = clrdata->mKeyList.mKeys[i].mValue[0];
color.g = clrdata->mKeyList.mKeys[i].mValue[1];
color.b = clrdata->mKeyList.mKeys[i].mValue[2];
color.a = clrdata->mKeyList.mKeys[i].mValue[3];
affector->setParameter("colour"+Ogre::StringConverter::toString(i),
Ogre::StringConverter::toString(color));
affector->setParameter("time"+Ogre::StringConverter::toString(i),
Ogre::StringConverter::toString(clrdata->mKeyList.mKeys[i].mTime));
}
}
else if(e->recType == Nif::RC_NiGravity)
else if(e->recType == Nif::RC_NiParticleRotation)
{
// TODO: Implement
// TODO: Implement (Ogre::RotationAffector?)
}
else
warn("Unhandled particle modifier "+e->recName);
@ -424,6 +452,9 @@ class NIFObjectLoader
particledata->particleRadius*2.0f);
partsys->setCullIndividually(false);
partsys->setParticleQuota(particledata->numParticles);
// TODO: There is probably a field or flag to specify this, as some
// particle effects have it and some don't.
partsys->setKeepParticlesInLocalSpace(true);
Nif::ControllerPtr ctrl = partnode->controller;
while(!ctrl.empty())
@ -461,7 +492,7 @@ class NIFObjectLoader
static void createObjects(const std::string &name, const std::string &group,
Ogre::SceneManager *sceneMgr, const Nif::Node *node,
ObjectList &objectlist, int flags=0)
ObjectList &objectlist, int flags)
{
// Do not create objects for the collision shape (includes all children)
if(node->recType == Nif::RC_RootCollisionNode)
@ -578,8 +609,8 @@ class NIFObjectLoader
}
}
if(node->recType == Nif::RC_NiAutoNormalParticles ||
node->recType == Nif::RC_NiRotatingParticles)
if((node->recType == Nif::RC_NiAutoNormalParticles ||
node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000))
{
Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node);
if(partsys != NULL)
@ -607,8 +638,7 @@ class NIFObjectLoader
{
/* This creates an empty mesh to which a skeleton gets attached. This
* is to ensure we have an entity with a skeleton instance, even if all
* other meshes are hidden or entities attached to a specific node
* instead of skinned. */
* other entities are attached to bones and not skinned. */
Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton();
if(meshMgr.getByName(name).isNull())
NIFMeshLoader::createMesh(name, name, group, ~(size_t)0);
@ -618,7 +648,7 @@ class NIFObjectLoader
}
public:
static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group)
static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group, int flags=0)
{
Nif::NIFFile::ptr nif = Nif::NIFFile::create(name);
if(nif->numRoots() < 1)
@ -644,7 +674,7 @@ public:
// Create a base skeleton entity if this NIF needs one
createSkelBase(name, group, sceneMgr, node, objectlist);
}
createObjects(name, group, sceneMgr, node, objectlist);
createObjects(name, group, sceneMgr, node, objectlist, flags);
}
};
@ -732,7 +762,7 @@ ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string na
ObjectList objectlist;
Misc::StringUtils::toLower(name);
NIFObjectLoader::load(sceneMgr, objectlist, name, group);
NIFObjectLoader::load(sceneMgr, objectlist, name, group, 0xC0000000);
return objectlist;
}

View file

@ -2,9 +2,347 @@
#include <OgreStringConverter.h>
#include <OgreParticleSystem.h>
#include <OgreParticleEmitter.h>
#include <OgreParticleAffector.h>
#include <OgreParticle.h>
/* FIXME: "Nif" isn't really an appropriate emitter name. */
class NifEmitter : public Ogre::ParticleEmitter
{
public:
/** Command object for the emitter width (see Ogre::ParamCommand).*/
class CmdWidth : public Ogre::ParamCommand
{
public:
Ogre::String doGet(const void *target) const
{
return Ogre::StringConverter::toString(static_cast<const NifEmitter*>(target)->getWidth());
}
void doSet(void *target, const Ogre::String &val)
{
static_cast<NifEmitter*>(target)->setWidth(Ogre::StringConverter::parseReal(val));
}
};
/** Command object for the emitter height (see Ogre::ParamCommand).*/
class CmdHeight : public Ogre::ParamCommand
{
public:
Ogre::String doGet(const void *target) const
{
return Ogre::StringConverter::toString(static_cast<const NifEmitter*>(target)->getHeight());
}
void doSet(void *target, const Ogre::String &val)
{
static_cast<NifEmitter*>(target)->setHeight(Ogre::StringConverter::parseReal(val));
}
};
/** Command object for the emitter depth (see Ogre::ParamCommand).*/
class CmdDepth : public Ogre::ParamCommand
{
public:
Ogre::String doGet(const void *target) const
{
return Ogre::StringConverter::toString(static_cast<const NifEmitter*>(target)->getDepth());
}
void doSet(void *target, const Ogre::String &val)
{
static_cast<NifEmitter*>(target)->setDepth(Ogre::StringConverter::parseReal(val));
}
};
/** Command object for the emitter vertical_direction (see Ogre::ParamCommand).*/
class CmdVerticalDir : public Ogre::ParamCommand
{
public:
Ogre::String doGet(const void *target) const
{
const NifEmitter *self = static_cast<const NifEmitter*>(target);
return Ogre::StringConverter::toString(self->getVerticalDirection().valueDegrees());
}
void doSet(void *target, const Ogre::String &val)
{
NifEmitter *self = static_cast<NifEmitter*>(target);
self->setVerticalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val)));
}
};
/** Command object for the emitter vertical_angle (see Ogre::ParamCommand).*/
class CmdVerticalAngle : public Ogre::ParamCommand
{
public:
Ogre::String doGet(const void *target) const
{
const NifEmitter *self = static_cast<const NifEmitter*>(target);
return Ogre::StringConverter::toString(self->getVerticalAngle().valueDegrees());
}
void doSet(void *target, const Ogre::String &val)
{
NifEmitter *self = static_cast<NifEmitter*>(target);
self->setVerticalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val)));
}
};
/** Command object for the emitter horizontal_direction (see Ogre::ParamCommand).*/
class CmdHorizontalDir : public Ogre::ParamCommand
{
public:
Ogre::String doGet(const void *target) const
{
const NifEmitter *self = static_cast<const NifEmitter*>(target);
return Ogre::StringConverter::toString(self->getHorizontalDirection().valueDegrees());
}
void doSet(void *target, const Ogre::String &val)
{
NifEmitter *self = static_cast<NifEmitter*>(target);
self->setHorizontalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val)));
}
};
/** Command object for the emitter horizontal_angle (see Ogre::ParamCommand).*/
class CmdHorizontalAngle : public Ogre::ParamCommand
{
public:
Ogre::String doGet(const void *target) const
{
const NifEmitter *self = static_cast<const NifEmitter*>(target);
return Ogre::StringConverter::toString(self->getHorizontalAngle().valueDegrees());
}
void doSet(void *target, const Ogre::String &val)
{
NifEmitter *self = static_cast<NifEmitter*>(target);
self->setHorizontalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val)));
}
};
NifEmitter(Ogre::ParticleSystem *psys)
: Ogre::ParticleEmitter(psys)
{
initDefaults("Nif");
}
/** See Ogre::ParticleEmitter. */
unsigned short _getEmissionCount(Ogre::Real timeElapsed)
{
// Use basic constant emission
return genConstantEmissionCount(timeElapsed);
}
/** See Ogre::ParticleEmitter. */
void _initParticle(Ogre::Particle *particle)
{
Ogre::Vector3 xOff, yOff, zOff;
// Call superclass
ParticleEmitter::_initParticle(particle);
xOff = Ogre::Math::SymmetricRandom() * mXRange;
yOff = Ogre::Math::SymmetricRandom() * mYRange;
zOff = Ogre::Math::SymmetricRandom() * mZRange;
particle->position = mPosition + xOff + yOff + zOff;
// Generate complex data by reference
genEmissionColour(particle->colour);
// NOTE: We do not use mDirection/mAngle for the initial direction.
Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom();
Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom();
particle->direction = (Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) *
Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) *
Ogre::Vector3::UNIT_Z;
genEmissionVelocity(particle->direction);
// Generate simpler data
particle->timeToLive = particle->totalTimeToLive = genEmissionTTL();
}
/** Overloaded to update the trans. matrix */
void setDirection(const Ogre::Vector3 &dir)
{
ParticleEmitter::setDirection(dir);
genAreaAxes();
}
/** Sets the size of the area from which particles are emitted.
@param
size Vector describing the size of the area. The area extends
around the center point by half the x, y and z components of
this vector. The box is aligned such that it's local Z axis points
along it's direction (see setDirection)
*/
void setSize(const Ogre::Vector3 &size)
{
mSize = size;
genAreaAxes();
}
/** Sets the size of the area from which particles are emitted.
@param x,y,z
Individual axis lengths describing the size of the area. The area
extends around the center point by half the x, y and z components
of this vector. The box is aligned such that it's local Z axis
points along it's direction (see setDirection)
*/
void setSize(Ogre::Real x, Ogre::Real y, Ogre::Real z)
{
mSize.x = x;
mSize.y = y;
mSize.z = z;
genAreaAxes();
}
/** Sets the width (local x size) of the emitter. */
void setWidth(Ogre::Real width)
{
mSize.x = width;
genAreaAxes();
}
/** Gets the width (local x size) of the emitter. */
Ogre::Real getWidth(void) const
{ return mSize.x; }
/** Sets the height (local y size) of the emitter. */
void setHeight(Ogre::Real height)
{
mSize.y = height;
genAreaAxes();
}
/** Gets the height (local y size) of the emitter. */
Ogre::Real getHeight(void) const
{ return mSize.y; }
/** Sets the depth (local y size) of the emitter. */
void setDepth(Ogre::Real depth)
{
mSize.z = depth;
genAreaAxes();
}
/** Gets the depth (local y size) of the emitter. */
Ogre::Real getDepth(void) const
{ return mSize.z; }
void setVerticalDirection(Ogre::Radian vdir)
{ mVerticalDir = vdir; }
Ogre::Radian getVerticalDirection(void) const
{ return mVerticalDir; }
void setVerticalAngle(Ogre::Radian vangle)
{ mVerticalAngle = vangle; }
Ogre::Radian getVerticalAngle(void) const
{ return mVerticalAngle; }
void setHorizontalDirection(Ogre::Radian hdir)
{ mHorizontalDir = hdir; }
Ogre::Radian getHorizontalDirection(void) const
{ return mHorizontalDir; }
void setHorizontalAngle(Ogre::Radian hangle)
{ mHorizontalAngle = hangle; }
Ogre::Radian getHorizontalAngle(void) const
{ return mHorizontalAngle; }
protected:
/// Size of the area
Ogre::Vector3 mSize;
Ogre::Radian mVerticalDir;
Ogre::Radian mVerticalAngle;
Ogre::Radian mHorizontalDir;
Ogre::Radian mHorizontalAngle;
/// Local axes, not normalised, their magnitude reflects area size
Ogre::Vector3 mXRange, mYRange, mZRange;
/// Internal method for generating the area axes
void genAreaAxes(void)
{
Ogre::Vector3 mLeft = mUp.crossProduct(mDirection);
mXRange = mLeft * (mSize.x * 0.5f);
mYRange = mUp * (mSize.y * 0.5f);
mZRange = mDirection * (mSize.z * 0.5f);
}
/** Internal for initializing some defaults and parameters
@return True if custom parameters need initialising
*/
bool initDefaults(const Ogre::String &t)
{
// Defaults
mDirection = Ogre::Vector3::UNIT_Z;
mUp = Ogre::Vector3::UNIT_Y;
setSize(100.0f, 100.0f, 100.0f);
mType = t;
// Set up parameters
if(createParamDictionary(mType + "Emitter"))
{
addBaseParameters();
Ogre::ParamDictionary *dict = getParamDictionary();
// Custom params
dict->addParameter(Ogre::ParameterDef("width",
"Width of the shape in world coordinates.",
Ogre::PT_REAL),
&msWidthCmd);
dict->addParameter(Ogre::ParameterDef("height",
"Height of the shape in world coordinates.",
Ogre::PT_REAL),
&msHeightCmd);
dict->addParameter(Ogre::ParameterDef("depth",
"Depth of the shape in world coordinates.",
Ogre::PT_REAL),
&msDepthCmd);
dict->addParameter(Ogre::ParameterDef("vertical_direction",
"Vertical direction of emitted particles (in degrees).",
Ogre::PT_REAL),
&msVerticalDirCmd);
dict->addParameter(Ogre::ParameterDef("vertical_angle",
"Vertical direction variance of emitted particles (in degrees).",
Ogre::PT_REAL),
&msVerticalAngleCmd);
dict->addParameter(Ogre::ParameterDef("horizontal_direction",
"Horizontal direction of emitted particles (in degrees).",
Ogre::PT_REAL),
&msHorizontalDirCmd);
dict->addParameter(Ogre::ParameterDef("horizontal_angle",
"Horizontal direction variance of emitted particles (in degrees).",
Ogre::PT_REAL),
&msHorizontalAngleCmd);
return true;
}
return false;
}
/// Command objects
static CmdWidth msWidthCmd;
static CmdHeight msHeightCmd;
static CmdDepth msDepthCmd;
static CmdVerticalDir msVerticalDirCmd;
static CmdVerticalAngle msVerticalAngleCmd;
static CmdHorizontalDir msHorizontalDirCmd;
static CmdHorizontalAngle msHorizontalAngleCmd;
};
NifEmitter::CmdWidth NifEmitter::msWidthCmd;
NifEmitter::CmdHeight NifEmitter::msHeightCmd;
NifEmitter::CmdDepth NifEmitter::msDepthCmd;
NifEmitter::CmdVerticalDir NifEmitter::msVerticalDirCmd;
NifEmitter::CmdVerticalAngle NifEmitter::msVerticalAngleCmd;
NifEmitter::CmdHorizontalDir NifEmitter::msHorizontalDirCmd;
NifEmitter::CmdHorizontalAngle NifEmitter::msHorizontalAngleCmd;
Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys)
{
Ogre::ParticleEmitter *emit = OGRE_NEW NifEmitter(psys);
mEmitters.push_back(emit);
return emit;
}
class GrowFadeAffector : public Ogre::ParticleAffector
{
public:
@ -144,3 +482,212 @@ Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSy
mAffectors.push_back(p);
return p;
}
class GravityAffector : public Ogre::ParticleAffector
{
enum ForceType {
Type_Wind,
Type_Point
};
public:
/** Command object for force (see Ogre::ParamCommand).*/
class CmdForce : public Ogre::ParamCommand
{
public:
Ogre::String doGet(const void *target) const
{
const GravityAffector *self = static_cast<const GravityAffector*>(target);
return Ogre::StringConverter::toString(self->getForce());
}
void doSet(void *target, const Ogre::String &val)
{
GravityAffector *self = static_cast<GravityAffector*>(target);
self->setForce(Ogre::StringConverter::parseReal(val));
}
};
/** Command object for force_type (see Ogre::ParamCommand).*/
class CmdForceType : public Ogre::ParamCommand
{
static ForceType getTypeFromString(const Ogre::String &type)
{
if(type == "wind")
return Type_Wind;
if(type == "point")
return Type_Point;
OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type string: "+type,
"CmdForceType::getTypeFromString");
}
static Ogre::String getStringFromType(ForceType type)
{
switch(type)
{
case Type_Wind: return "wind";
case Type_Point: return "point";
}
OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type enum: "+Ogre::StringConverter::toString(type),
"CmdForceType::getStringFromType");
}
public:
Ogre::String doGet(const void *target) const
{
const GravityAffector *self = static_cast<const GravityAffector*>(target);
return getStringFromType(self->getForceType());
}
void doSet(void *target, const Ogre::String &val)
{
GravityAffector *self = static_cast<GravityAffector*>(target);
self->setForceType(getTypeFromString(val));
}
};
/** Command object for direction (see Ogre::ParamCommand).*/
class CmdDirection : public Ogre::ParamCommand
{
public:
Ogre::String doGet(const void *target) const
{
const GravityAffector *self = static_cast<const GravityAffector*>(target);
return Ogre::StringConverter::toString(self->getDirection());
}
void doSet(void *target, const Ogre::String &val)
{
GravityAffector *self = static_cast<GravityAffector*>(target);
self->setDirection(Ogre::StringConverter::parseVector3(val));
}
};
/** Command object for position (see Ogre::ParamCommand).*/
class CmdPosition : public Ogre::ParamCommand
{
public:
Ogre::String doGet(const void *target) const
{
const GravityAffector *self = static_cast<const GravityAffector*>(target);
return Ogre::StringConverter::toString(self->getPosition());
}
void doSet(void *target, const Ogre::String &val)
{
GravityAffector *self = static_cast<GravityAffector*>(target);
self->setPosition(Ogre::StringConverter::parseVector3(val));
}
};
/** Default constructor. */
GravityAffector(Ogre::ParticleSystem *psys)
: ParticleAffector(psys)
, mForce(0.0f)
, mForceType(Type_Wind)
, mPosition(0.0f)
, mDirection(0.0f)
{
mType = "Gravity";
// Init parameters
if(createParamDictionary("GravityAffector"))
{
Ogre::ParamDictionary *dict = getParamDictionary();
Ogre::String force_title("force");
Ogre::String force_descr("Amount of force applied to particles.");
Ogre::String force_type_title("force_type");
Ogre::String force_type_descr("Type of force applied to particles (point or wind).");
Ogre::String direction_title("direction");
Ogre::String direction_descr("Direction of wind forces.");
Ogre::String position_title("position");
Ogre::String position_descr("Position of point forces.");
dict->addParameter(Ogre::ParameterDef(force_title, force_descr, Ogre::PT_REAL), &msForceCmd);
dict->addParameter(Ogre::ParameterDef(force_type_title, force_type_descr, Ogre::PT_STRING), &msForceTypeCmd);
dict->addParameter(Ogre::ParameterDef(direction_title, direction_descr, Ogre::PT_VECTOR3), &msDirectionCmd);
dict->addParameter(Ogre::ParameterDef(position_title, position_descr, Ogre::PT_VECTOR3), &msPositionCmd);
}
}
/** See Ogre::ParticleAffector. */
void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed)
{
switch(mForceType)
{
case Type_Wind:
applyWindForce(psys, timeElapsed);
break;
case Type_Point:
applyPointForce(psys, timeElapsed);
break;
}
}
void setForce(Ogre::Real force)
{ mForce = force; }
Ogre::Real getForce() const
{ return mForce; }
void setForceType(ForceType type)
{ mForceType = type; }
ForceType getForceType() const
{ return mForceType; }
void setDirection(const Ogre::Vector3 &dir)
{ mDirection = dir; }
const Ogre::Vector3 &getDirection() const
{ return mDirection; }
void setPosition(const Ogre::Vector3 &pos)
{ mPosition = pos; }
const Ogre::Vector3 &getPosition() const
{ return mPosition; }
static CmdForce msForceCmd;
static CmdForceType msForceTypeCmd;
static CmdDirection msDirectionCmd;
static CmdPosition msPositionCmd;
protected:
void applyWindForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed)
{
const Ogre::Vector3 vec = mDirection * mForce * timeElapsed;
Ogre::ParticleIterator pi = psys->_getIterator();
while (!pi.end())
{
Ogre::Particle *p = pi.getNext();
p->direction += vec;
}
}
void applyPointForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed)
{
const Ogre::Real force = mForce * timeElapsed;
Ogre::ParticleIterator pi = psys->_getIterator();
while (!pi.end())
{
Ogre::Particle *p = pi.getNext();
const Ogre::Vector3 vec = (p->position - mPosition).normalisedCopy() * force;
p->direction += vec;
}
}
float mForce;
ForceType mForceType;
Ogre::Vector3 mPosition;
Ogre::Vector3 mDirection;
};
GravityAffector::CmdForce GravityAffector::msForceCmd;
GravityAffector::CmdForceType GravityAffector::msForceTypeCmd;
GravityAffector::CmdDirection GravityAffector::msDirectionCmd;
GravityAffector::CmdPosition GravityAffector::msPositionCmd;
Ogre::ParticleAffector *GravityAffectorFactory::createAffector(Ogre::ParticleSystem *psys)
{
Ogre::ParticleAffector *p = new GravityAffector(psys);
mAffectors.push_back(p);
return p;
}

View file

@ -1,8 +1,21 @@
#ifndef OENGINE_OGRE_PARTICLES_H
#define OENGINE_OGRE_PARTICLES_H
#include <OgreParticleEmitterFactory.h>
#include <OgreParticleAffectorFactory.h>
/** Factory class for NifEmitter. */
class NifEmitterFactory : public Ogre::ParticleEmitterFactory
{
public:
/** See ParticleEmitterFactory */
Ogre::String getName() const
{ return "Nif"; }
/** See ParticleEmitterFactory */
Ogre::ParticleEmitter* createEmitter(Ogre::ParticleSystem *psys);
};
/** Factory class for GrowFadeAffector. */
class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory
{
@ -14,4 +27,15 @@ class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory
Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys);
};
/** Factory class for GravityAffector. */
class GravityAffectorFactory : public Ogre::ParticleAffectorFactory
{
/** See Ogre::ParticleAffectorFactory */
Ogre::String getName() const
{ return "Gravity"; }
/** See Ogre::ParticleAffectorFactory */
Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys);
};
#endif /* OENGINE_OGRE_PARTICLES_H */

View file

@ -110,6 +110,11 @@ void OgreRenderer::loadPlugins()
void OgreRenderer::unloadPlugins()
{
std::vector<Ogre::ParticleEmitterFactory*>::iterator ei;
for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();ei++)
OGRE_DELETE (*ei);
mEmitterFactories.clear();
std::vector<Ogre::ParticleAffectorFactory*>::iterator ai;
for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();ai++)
OGRE_DELETE (*ai);
@ -206,11 +211,22 @@ void OgreRenderer::configure(const std::string &logPath,
Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot);
Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot);
Ogre::ParticleEmitterFactory *emitter;
emitter = OGRE_NEW NifEmitterFactory();
Ogre::ParticleSystemManager::getSingleton().addEmitterFactory(emitter);
mEmitterFactories.push_back(emitter);
Ogre::ParticleAffectorFactory *affector;
affector = OGRE_NEW GrowFadeAffectorFactory();
Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector);
mAffectorFactories.push_back(affector);
affector = OGRE_NEW GravityAffectorFactory();
Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector);
mAffectorFactories.push_back(affector);
RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem);
if (rs == 0)

View file

@ -40,6 +40,7 @@ namespace Ogre
class SceneManager;
class Camera;
class Viewport;
class ParticleEmitterFactory;
class ParticleAffectorFactory;
}
@ -95,6 +96,7 @@ namespace OEngine
Ogre::D3D9Plugin* mD3D9Plugin;
#endif
Fader* mFader;
std::vector<Ogre::ParticleEmitterFactory*> mEmitterFactories;
std::vector<Ogre::ParticleAffectorFactory*> mAffectorFactories;
bool logging;