mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-20 20:09:41 +00:00
Merge branch 'master' of https://github.com/OpenMW/openmw
This commit is contained in:
commit
4d2bdda22f
90 changed files with 2910 additions and 7407 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -37,6 +37,7 @@ resources
|
|||
/omwlauncher
|
||||
/openmw
|
||||
/opencs
|
||||
/niftest
|
||||
|
||||
## generated objects
|
||||
apps/openmw/config.hpp
|
||||
|
|
139
.mailmap
Normal file
139
.mailmap
Normal file
|
@ -0,0 +1,139 @@
|
|||
Adam Hogan <comrade@comrade-desktop.(none)>
|
||||
Aleksandar Jovanov <ajovanov93@yahoo.com>
|
||||
Alexander Olofsson <ace@haxalot.com>
|
||||
Alex McKibben <mckibbenta@gmail.com>
|
||||
Alex "rainChu" Haddad <alx1213@gmail.com>
|
||||
Ardekantur <greystone@ardekantur.com>
|
||||
Armin Preiml <b.nutzer@gmail.com>
|
||||
Artem Kotsynyak <greye@carceri>
|
||||
Arthur Moore <arthur@Behemoth>
|
||||
Arthur Moore <Arthur.Moore.git@cd-net.net>
|
||||
athile <athile@athile.net>
|
||||
athile <athile.g@gmail.com>
|
||||
Stefan Galowicz <bogglez@the.mind>
|
||||
Bret Curtis <psi29a@gmail.com>
|
||||
Britt Mathis <britt.mathis@gmail.com>
|
||||
Sandy Carter <bwrsandman@gmail.com>
|
||||
Sandy Carter <mr.sandy.carter@gmail.com>
|
||||
Carl Maxwell <carl.maxwell@gmail.com>
|
||||
cc9cii <cc9c@iinet.net.au>
|
||||
Cory F. Cohen <cfcohen@verizon.net>
|
||||
Chris Robinson <chris.kcat@gmail.com>
|
||||
Cris Mihalache <mirceam94@hotmail.com>
|
||||
darkf <lw9k123@gmail.com>
|
||||
Diggory Hardy <diggory.hardy@gmail.com>
|
||||
Thomas Luppi <ThomasLuppi@gmail.com>
|
||||
Thomas Luppi <tluppi@thomas-GE60.(none)>
|
||||
Dmitriy 'Endorph' Shkurskiy <end0rph@hotmail.com>
|
||||
Dmitry Marakasov <amdmi3@amdmi3.ru>
|
||||
Douglas Diniz <dgdiniz@gmail.com>
|
||||
Douglas Mencken <dougmencken@gmail.com>
|
||||
Edmondo Tommasina <edmondo.tommasina@gmail.com>
|
||||
Eduard Cot <eduard@eduard-iMac.(none)>
|
||||
Eli2 <fabian@fabian-desktop.(none)>
|
||||
Emanuel Guével <guevel.emanuel@gmail.com>
|
||||
Leon Saunders <LeonDavidSaunders@gmail.com>
|
||||
Fil Krynicki <filipkrynicki@gmail.com>
|
||||
John Blomberg <johnblo@kth.se>
|
||||
Gašper Sedej <gsedej@gmail.com>
|
||||
Michał Bień <michal1.bien@gmail.com>
|
||||
Joel Graff <monograff76@gmail.com>
|
||||
Paul McElroy <pcm1123@gmail.com>
|
||||
Artem Kotsynyak <greye@carceri>
|
||||
Artem Kotsynyak <greye@null.net>
|
||||
gugus <gus_512@hotmail.com>
|
||||
guidoj <guido@thuisbasis.net>
|
||||
gus <gus_512@hotmail.com>
|
||||
Hallfaer Tuilinn <gijsbertth@gmail.com>
|
||||
Julian Ospald <julian.ospald@googlemail.com>
|
||||
Jacob Essex <jacob@jacobessex.com>
|
||||
Jan Borsodi <jborsodi@gmail.com>
|
||||
Jan-Peter Nilsson <peppe@pappkartong.se>
|
||||
Jason Hooks <Hooks@.(none)>
|
||||
Jason Hooks <jason@Jason-ThinkPad-R61.(none)>
|
||||
Jason Hooks <jhooks1@mix.wvu.edu>
|
||||
Jeffrey Haines <jeffhaines@me.com>
|
||||
Jeffrey Haines <jib-y@users.noreply.github.com>
|
||||
Jordan Ayers <jordan.ayers@gmail.com>
|
||||
Jordan Milne <jordan.milne@saynotolinux.com>
|
||||
Josua Grawitter <josh@greyage.org>
|
||||
Julien Voisin <pouicpouicpouic@gmail.com>
|
||||
Karl-Felix Glatzer <karl.glatzer@gmx.de>
|
||||
Chris Robinson <chris.kcat@gmail.com>
|
||||
Kevin Poitra <pupkev@yahoo.com>
|
||||
Roman Proskuryakov <humbug@deeptown.org>
|
||||
Lars Söderberg <lazze_1983@hotmail.com>
|
||||
lazydev <lazydev@homecomp>
|
||||
lazydev <lazydev@nomail>
|
||||
Lukasz Gromanowski <lgromanowski@gmail.com>
|
||||
Marc Bouvier <marcrbouvier@gmail.com>
|
||||
Marcin Hulist <Gohan1989@gmail.com>
|
||||
Marc Zinnschlag <marc@zpages.de>
|
||||
Marek Kochanowicz <herr@mikrus.pl>
|
||||
Marek Kochanowicz <marek@localhost.localdomain>
|
||||
Marek Kochanowicz <sirherrbatka@gmail.com>
|
||||
Mark Siewert <mark.siewert@t-online.de>
|
||||
Mark Siewert <ms@cerebra.localdomain>
|
||||
megaton <9megaton6@gmail.com>
|
||||
Michael Mc Donnell <michael@mcdonnell.dk>
|
||||
Michael Papageorgiou <werdanith@yahoo.gr>
|
||||
Michal Sciubidlo <michal.sciubidlo@gmail.com>
|
||||
Michał Ściubidło <michal.sciubidlo@gmail.com>
|
||||
Nathan Jeffords <blunted2night@gmail.com>
|
||||
Nicolay Korslund <korslund@gmail.com>
|
||||
Nicolay Korslund <nicolayk@met.no>
|
||||
Nikolay Kasyanov <corrmage@gmail.com>
|
||||
pchan3 <chantlerpeter@gmail.com>
|
||||
Pieter van der Kloet <pvdkloet@gmail.com>
|
||||
Mateusz Kołaczek <mateusz.kolaczek@gmail.com>
|
||||
Bret Curtis <psi29a@gmail.com>
|
||||
Pieter van der Kloet <pvdkloet@gmail.com>
|
||||
Rohit Nirmal <rohitnirmal9@gmail.com>
|
||||
Roman Melnik <kromgart@gmail.com>
|
||||
Radu-Marius Popovici <rpopovici@github.com>
|
||||
Sandy Carter <bwrsandman@gmail.com>
|
||||
Scott Howard <showard314@gmail.com>
|
||||
Jannik Heller <scrawl@baseoftrash.de>
|
||||
Jannik Heller <scrawl@scrawl-laptop.(none)>
|
||||
Sebastian Wick <sebastian@sebastianwick.net>
|
||||
Sebastian Wick <wick.sebastian@gmail.com>
|
||||
Sergey Shambir <sergey.shambir.auto@gmail.com>
|
||||
sergoz <parapvr@yandex.ru>
|
||||
Chris Boyce <slothlife@users.noreply.github.com>
|
||||
Star-Demon <starsickle@yahoo.com>
|
||||
Sylvain Thesnieres <garvek@gmail.com>
|
||||
Thomas Luppi <digrules@gmail.com>
|
||||
Thomas Luppi <tluppi@thomas-GE60.(none)>
|
||||
Thoronador <thoronador@users.sourceforge.net>
|
||||
TomKoenderink <tom_koenderink-github@omniadicta.net>
|
||||
Tom Mason <wheybags@wheybags.com>
|
||||
Torben Carrington <torbenlcarrington@Gmail.com>
|
||||
Vincent Heuken <vincent@vincentheuken.com>
|
||||
Manuel Edelmann <edelmann.manuel@gmail.com>
|
||||
Manuel Edelmann <vorenon@hotmail.com>
|
||||
Alexander Nadeau <wareya@gmail.com>
|
||||
Michael Hogan <mr.michaelhogan@gmail.com>
|
||||
Jacob Essex <github@JacobEssex.com>
|
||||
Yuri Krupenin <yuri.krupenin@gmail.com>
|
||||
Bret Curtis <noone@your.box>
|
||||
|
||||
sirherrbatka <herr@localhost.localdomain>
|
||||
sirherrbatka <sirherrbatka@myopera.com>
|
||||
sergei <sergei@ubuntu.(none)>
|
||||
riothamus <digimars@gmail.com>
|
||||
nobrakal <nobrakal@gmail.com>
|
||||
nkorslund <nkorslund@ea6a568a-9f4f-0410-981a-c910a81bb256>
|
||||
mrcheko <cheko@sevas.ua>
|
||||
Miroslav Puda <pakanek@gmail.com>
|
||||
MiroslavR <miroslavr256@gmail.com>
|
||||
mckibbenta <mckibbenta@gmail.com>
|
||||
jeaye <jeaye@arrownext.com>
|
||||
eroen <eroen@falcon.eroen.eu>
|
||||
eroen <eroen@occam.eroen.eu>
|
||||
dreamer-dead <dreamer.dead@gmail.com>
|
||||
crysthala <crystalsoulslayer@gmail.com>
|
||||
Berulacks <beru@eml.cc>
|
||||
Axujen <axujen@gmail.com>
|
||||
root <root@debian>
|
||||
unknown <Hooks@.(none)>
|
||||
|
|
@ -77,6 +77,7 @@ option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
|
|||
option(BUILD_OPENCS "build OpenMW Construction Set" ON)
|
||||
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
||||
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF)
|
||||
option(BUILD_NIFTEST "build nif file tester" OFF)
|
||||
|
||||
# OS X deployment
|
||||
option(OPENMW_OSX_DEPLOYMENT OFF)
|
||||
|
@ -396,6 +397,9 @@ IF(NOT WIN32 AND NOT APPLE)
|
|||
IF(BUILD_OPENCS)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" )
|
||||
ENDIF(BUILD_OPENCS)
|
||||
IF(BUILD_NIFTEST)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" )
|
||||
ENDIF(BUILD_NIFTEST)
|
||||
|
||||
# Install licenses
|
||||
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
|
||||
|
@ -512,6 +516,11 @@ add_subdirectory (extern/sdl4ogre)
|
|||
# Components
|
||||
add_subdirectory (components)
|
||||
|
||||
#Testing
|
||||
if (BUILD_NIFTEST)
|
||||
add_subdirectory(components/nif/tests/)
|
||||
endif(BUILD_NIFTEST)
|
||||
|
||||
# Apps and tools
|
||||
add_subdirectory( apps/openmw )
|
||||
|
||||
|
|
|
@ -950,9 +950,9 @@ void Record<ESM::MagicEffect>::print()
|
|||
std::cout << " School: " << schoolLabel(mData.mData.mSchool)
|
||||
<< " (" << mData.mData.mSchool << ")" << std::endl;
|
||||
std::cout << " Base Cost: " << mData.mData.mBaseCost << std::endl;
|
||||
std::cout << " Unknown 1: " << mData.mData.mUnknown1 << std::endl;
|
||||
std::cout << " Speed: " << mData.mData.mSpeed << std::endl;
|
||||
std::cout << " Size: " << mData.mData.mSize << std::endl;
|
||||
std::cout << " Size Cap: " << mData.mData.mSizeCap << std::endl;
|
||||
std::cout << " Unknown 2: " << mData.mData.mUnknown2 << std::endl;
|
||||
std::cout << " RGB Color: " << "("
|
||||
<< mData.mData.mRed << ","
|
||||
<< mData.mData.mGreen << ","
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include <components/files/multidircollection.hpp>
|
||||
|
||||
#include <components/nifcache/nifcache.hpp>
|
||||
|
||||
#include "model/settings/usersettings.hpp"
|
||||
#include "model/doc/documentmanager.hpp"
|
||||
|
||||
|
@ -37,6 +39,7 @@ namespace CS
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
Nif::Cache mNifCache;
|
||||
Files::ConfigurationManager mCfgMgr;
|
||||
CSMSettings::UserSettings mUserSettings;
|
||||
CSMDoc::DocumentManager mDocumentManager;
|
||||
|
|
|
@ -37,6 +37,10 @@ static const char pipe_err[] = "!!! Failed to create pipe\n";
|
|||
static const char fork_err[] = "!!! Failed to fork debug process\n";
|
||||
static const char exec_err[] = "!!! Failed to exec debug process\n";
|
||||
|
||||
#ifndef PATH_MAX /* Not all platforms (GNU Hurd) have this. */
|
||||
# define PATH_MAX 256
|
||||
#endif
|
||||
|
||||
static char argv0[PATH_MAX];
|
||||
|
||||
static char altstack[SIGSTKSZ];
|
||||
|
@ -66,7 +70,7 @@ static const struct {
|
|||
int code;
|
||||
const char *name;
|
||||
} sigill_codes[] = {
|
||||
#ifndef __FreeBSD__
|
||||
#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
|
||||
{ ILL_ILLOPC, "Illegal opcode" },
|
||||
{ ILL_ILLOPN, "Illegal operand" },
|
||||
{ ILL_ILLADR, "Illegal addressing mode" },
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <components/bsa/resources.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/translation/translation.hpp>
|
||||
#include <components/nif/niffile.hpp>
|
||||
#include <components/nifoverrides/nifoverrides.hpp>
|
||||
|
||||
#include <components/nifbullet/bulletnifloader.hpp>
|
||||
|
@ -315,8 +314,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
mEnvironment.setStateManager (
|
||||
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
|
||||
|
||||
Nif::NIFFile::CacheLock cachelock;
|
||||
|
||||
std::string renderSystem = settings.getString("render system", "Video");
|
||||
if (renderSystem == "")
|
||||
{
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <components/files/collections.hpp>
|
||||
#include <components/translation/translation.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/nifcache/nifcache.hpp>
|
||||
|
||||
|
||||
#include "mwbase/environment.hpp"
|
||||
|
||||
|
@ -94,6 +96,8 @@ namespace OMW
|
|||
std::vector<std::string> mScriptBlacklist;
|
||||
bool mScriptBlacklistUse;
|
||||
|
||||
Nif::Cache mNifCache;
|
||||
|
||||
// not implemented
|
||||
Engine (const Engine&);
|
||||
Engine& operator= (const Engine&);
|
||||
|
|
|
@ -863,9 +863,9 @@ namespace MWClass
|
|||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
|
||||
if(ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat())
|
||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("#{sActorInCombat}"));
|
||||
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak))
|
||||
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak)
|
||||
|| ptr.getClass().getCreatureStats(ptr).getKnockedDown())
|
||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
|
||||
|
||||
// Can't talk to werewolfs
|
||||
if(ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).isWerewolf())
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
||||
|
|
|
@ -244,7 +244,8 @@ namespace MWGui
|
|||
{
|
||||
// we are stealing stuff
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
mModel = new PickpocketItemModel(player, new InventoryItemModel(container));
|
||||
mModel = new PickpocketItemModel(player, new InventoryItemModel(container),
|
||||
!mPtr.getClass().getCreatureStats(mPtr).getKnockedDown());
|
||||
}
|
||||
else
|
||||
mModel = new InventoryItemModel(container);
|
||||
|
@ -368,7 +369,9 @@ namespace MWGui
|
|||
bool ContainerWindow::onTakeItem(const ItemStack &item, int count)
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
if (dynamic_cast<PickpocketItemModel*>(mModel))
|
||||
// TODO: move to ItemModels
|
||||
if (dynamic_cast<PickpocketItemModel*>(mModel)
|
||||
&& !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown())
|
||||
{
|
||||
MWMechanics::Pickpocket pickpocket(player, mPtr);
|
||||
if (pickpocket.pick(item.mBase, count))
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace MWGui
|
|||
|
||||
EnchantingDialog::EnchantingDialog()
|
||||
: WindowBase("openmw_enchanting_dialog.layout")
|
||||
, EffectEditorBase()
|
||||
, EffectEditorBase(EffectEditorBase::Enchanting)
|
||||
, mItemSelectionDialog(NULL)
|
||||
{
|
||||
getWidget(mName, "NameEdit");
|
||||
|
@ -87,6 +87,7 @@ namespace MWGui
|
|||
}
|
||||
else
|
||||
{
|
||||
mName->setCaption(item.getClass().getName(item));
|
||||
mItemBox->setItem(item);
|
||||
mItemBox->setUserString ("ToolTipType", "ItemPtr");
|
||||
mItemBox->setUserData(item);
|
||||
|
@ -208,6 +209,7 @@ namespace MWGui
|
|||
else
|
||||
{
|
||||
setItem(MWWorld::Ptr());
|
||||
updateLabels();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,6 +218,7 @@ namespace MWGui
|
|||
mItemSelectionDialog->setVisible(false);
|
||||
|
||||
setItem(item);
|
||||
MWBase::Environment::get().getSoundManager()->playSound(item.getClass().getDownSoundId(item), 1, 1);
|
||||
mEnchanting.nextCastStyle();
|
||||
updateLabels();
|
||||
}
|
||||
|
@ -237,6 +240,7 @@ namespace MWGui
|
|||
}
|
||||
|
||||
setSoulGem(item);
|
||||
MWBase::Environment::get().getSoundManager()->playSound(item.getClass().getDownSoundId(item), 1, 1);
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
|
|
|
@ -471,6 +471,7 @@ namespace MWGui
|
|||
mWeaponSpellBox->setVisible(true);
|
||||
}
|
||||
|
||||
mWeapBox->clearUserStrings();
|
||||
mWeapBox->setUserString("ToolTipType", "ItemPtr");
|
||||
mWeapBox->setUserData(item);
|
||||
|
||||
|
@ -515,12 +516,14 @@ namespace MWGui
|
|||
MWWorld::Ptr player = world->getPlayerPtr();
|
||||
|
||||
mWeapImage->setItem(MWWorld::Ptr());
|
||||
if (player.getClass().getNpcStats(player).isWerewolf())
|
||||
mWeapImage->setIcon("icons\\k\\tx_werewolf_hand.dds");
|
||||
else
|
||||
mWeapImage->setIcon("icons\\k\\stealth_handtohand.dds");
|
||||
std::string icon = (player.getClass().getNpcStats(player).isWerewolf()) ? "icons\\k\\tx_werewolf_hand.dds" : "icons\\k\\stealth_handtohand.dds";
|
||||
mWeapImage->setIcon(icon);
|
||||
|
||||
mWeapBox->clearUserStrings();
|
||||
mWeapBox->setUserString("ToolTipType", "Layout");
|
||||
mWeapBox->setUserString("ToolTipLayout", "HandToHandToolTip");
|
||||
mWeapBox->setUserString("Caption_HandToHandText", itemName);
|
||||
mWeapBox->setUserString("ImageTexture_HandToHandImage", icon);
|
||||
}
|
||||
|
||||
void HUD::setCrosshairVisible(bool visible)
|
||||
|
|
|
@ -493,6 +493,7 @@ namespace MWGui
|
|||
|
||||
float capacity = player.getClass().getCapacity(player);
|
||||
float encumbrance = player.getClass().getEncumbrance(player);
|
||||
mTradeModel->adjustEncumbrance(encumbrance);
|
||||
mEncumbranceBar->setValue(encumbrance, capacity);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,16 +6,19 @@
|
|||
namespace MWGui
|
||||
{
|
||||
|
||||
PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel)
|
||||
PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel, bool hideItems)
|
||||
{
|
||||
mSourceModel = sourceModel;
|
||||
int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak);
|
||||
|
||||
mSourceModel->update();
|
||||
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
|
||||
if (hideItems)
|
||||
{
|
||||
if (std::rand() / static_cast<float>(RAND_MAX) * 100 > chance)
|
||||
mHiddenItems.push_back(mSourceModel->getItem(i));
|
||||
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
|
||||
{
|
||||
if (std::rand() / static_cast<float>(RAND_MAX) * 100 > chance)
|
||||
mHiddenItems.push_back(mSourceModel->getItem(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace MWGui
|
|||
class PickpocketItemModel : public ProxyItemModel
|
||||
{
|
||||
public:
|
||||
PickpocketItemModel (const MWWorld::Ptr& thief, ItemModel* sourceModel);
|
||||
PickpocketItemModel (const MWWorld::Ptr& thief, ItemModel* sourceModel, bool hideItems=true);
|
||||
virtual ItemStack getItem (ModelIndex index);
|
||||
virtual size_t getItemCount();
|
||||
virtual void update();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -293,12 +294,18 @@ namespace MWGui
|
|||
return;
|
||||
store.setSelectedEnchantItem(store.end());
|
||||
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell);
|
||||
}
|
||||
else if (type == Type_Item)
|
||||
{
|
||||
MWWorld::Ptr item = *button->getUserData<MWWorld::Ptr>();
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item);
|
||||
MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
// change draw state only if the item is in player's right hand
|
||||
if (rightHand != store.end() && item == *rightHand)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon);
|
||||
}
|
||||
}
|
||||
else if (type == Type_MagicItem)
|
||||
{
|
||||
|
@ -322,6 +329,7 @@ namespace MWGui
|
|||
}
|
||||
|
||||
store.setSelectedEnchantItem(it);
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,10 +37,11 @@ namespace MWGui
|
|||
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked);
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked);
|
||||
mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteButtonClicked);
|
||||
mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
|
||||
mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
|
||||
mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected);
|
||||
mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick);
|
||||
mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated);
|
||||
mSaveList->eventKeyButtonPressed += MyGUI::newDelegate(this, &SaveGameDialog::onKeyButtonPressed);
|
||||
mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept);
|
||||
mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged);
|
||||
}
|
||||
|
@ -247,6 +248,12 @@ namespace MWGui
|
|||
}
|
||||
}
|
||||
|
||||
void SaveGameDialog::onKeyButtonPressed(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char character)
|
||||
{
|
||||
if (key == MyGUI::KeyCode::Delete && mCurrentSlot)
|
||||
confirmDeleteSave();
|
||||
}
|
||||
|
||||
void SaveGameDialog::onOkButtonClicked(MyGUI::Widget *sender)
|
||||
{
|
||||
accept();
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace MWGui
|
|||
private:
|
||||
void confirmDeleteSave();
|
||||
|
||||
void onKeyButtonPressed(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char character);
|
||||
void onCancelButtonClicked (MyGUI::Widget* sender);
|
||||
void onOkButtonClicked (MyGUI::Widget* sender);
|
||||
void onDeleteButtonClicked (MyGUI::Widget* sender);
|
||||
|
|
|
@ -287,7 +287,7 @@ namespace MWGui
|
|||
|
||||
SpellCreationDialog::SpellCreationDialog()
|
||||
: WindowBase("openmw_spellcreation_dialog.layout")
|
||||
, EffectEditorBase()
|
||||
, EffectEditorBase(EffectEditorBase::Spellmaking)
|
||||
{
|
||||
getWidget(mNameEdit, "NameEdit");
|
||||
getWidget(mMagickaCost, "MagickaCost");
|
||||
|
@ -444,10 +444,11 @@ namespace MWGui
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
EffectEditorBase::EffectEditorBase()
|
||||
EffectEditorBase::EffectEditorBase(Type type)
|
||||
: mAddEffectDialog()
|
||||
, mSelectAttributeDialog(NULL)
|
||||
, mSelectSkillDialog(NULL)
|
||||
, mType(type)
|
||||
{
|
||||
mAddEffectDialog.eventEffectAdded += MyGUI::newDelegate(this, &EffectEditorBase::onEffectAdded);
|
||||
mAddEffectDialog.eventEffectModified += MyGUI::newDelegate(this, &EffectEditorBase::onEffectModified);
|
||||
|
@ -482,6 +483,13 @@ namespace MWGui
|
|||
const std::vector<ESM::ENAMstruct>& list = spell->mEffects.mList;
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator it2 = list.begin(); it2 != list.end(); ++it2)
|
||||
{
|
||||
const ESM::MagicEffect * effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(it2->mEffectID);
|
||||
|
||||
// skip effects that do not allow spellmaking/enchanting
|
||||
int requiredFlags = (mType == Spellmaking) ? ESM::MagicEffect::AllowSpellmaking : ESM::MagicEffect::AllowEnchanting;
|
||||
if (!(effect->mData.mFlags & requiredFlags))
|
||||
continue;
|
||||
|
||||
if (std::find(knownEffects.begin(), knownEffects.end(), it2->mEffectID) == knownEffects.end())
|
||||
knownEffects.push_back(it2->mEffectID);
|
||||
}
|
||||
|
|
|
@ -85,7 +85,13 @@ namespace MWGui
|
|||
class EffectEditorBase
|
||||
{
|
||||
public:
|
||||
EffectEditorBase();
|
||||
enum Type
|
||||
{
|
||||
Spellmaking,
|
||||
Enchanting
|
||||
};
|
||||
|
||||
EffectEditorBase(Type type);
|
||||
virtual ~EffectEditorBase();
|
||||
|
||||
protected:
|
||||
|
@ -121,6 +127,9 @@ namespace MWGui
|
|||
void setWidgets (Widgets::MWList* availableEffectsList, MyGUI::ScrollView* usedEffectsView);
|
||||
|
||||
virtual void notifyEffectsChanged () {}
|
||||
|
||||
private:
|
||||
Type mType;
|
||||
};
|
||||
|
||||
class SpellCreationDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
|
||||
#include "mapwindow.hpp"
|
||||
#include "inventorywindow.hpp"
|
||||
|
@ -19,6 +20,7 @@
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
std::string ToolTips::sSchoolNames[] = {"#{sSchoolAlteration}", "#{sSchoolConjuration}", "#{sSchoolDestruction}", "#{sSchoolIllusion}", "#{sSchoolMysticism}", "#{sSchoolRestoration}"};
|
||||
|
||||
ToolTips::ToolTips() :
|
||||
Layout("openmw_tooltips.layout")
|
||||
|
@ -220,6 +222,12 @@ namespace MWGui
|
|||
params.mNoTarget = false;
|
||||
effects.push_back(params);
|
||||
}
|
||||
if (MWMechanics::spellIncreasesSkill(spell)) // display school of spells that contribute to skill progress
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
int school = MWMechanics::getSpellSchool(spell, player);
|
||||
info.text = "#{sSchool}: " + sSchoolNames[school];
|
||||
}
|
||||
info.effects = effects;
|
||||
tooltipSize = createToolTip(info);
|
||||
}
|
||||
|
@ -739,19 +747,11 @@ namespace MWGui
|
|||
icon.insert(slashPos+1, "b_");
|
||||
icon = Misc::ResourceHelpers::correctIconPath(icon);
|
||||
|
||||
std::vector<std::string> schools;
|
||||
schools.push_back ("#{sSchoolAlteration}");
|
||||
schools.push_back ("#{sSchoolConjuration}");
|
||||
schools.push_back ("#{sSchoolDestruction}");
|
||||
schools.push_back ("#{sSchoolIllusion}");
|
||||
schools.push_back ("#{sSchoolMysticism}");
|
||||
schools.push_back ("#{sSchoolRestoration}");
|
||||
|
||||
widget->setUserString("ToolTipType", "Layout");
|
||||
widget->setUserString("ToolTipLayout", "MagicEffectToolTip");
|
||||
widget->setUserString("Caption_MagicEffectName", "#{" + name + "}");
|
||||
widget->setUserString("Caption_MagicEffectDescription", effect->mDescription);
|
||||
widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + schools[effect->mData.mSchool]);
|
||||
widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + sSchoolNames[effect->mData.mSchool]);
|
||||
widget->setUserString("ImageTexture_MagicEffectImage", icon);
|
||||
}
|
||||
|
||||
|
|
|
@ -96,6 +96,8 @@ namespace MWGui
|
|||
/// Adjust position for a tooltip so that it doesn't leave the screen and does not obscure the mouse cursor
|
||||
void position(MyGUI::IntPoint& position, MyGUI::IntSize size, MyGUI::IntSize viewportSize);
|
||||
|
||||
static std::string sSchoolNames[6];
|
||||
|
||||
int mHorizontalScrollIndex;
|
||||
|
||||
|
||||
|
|
|
@ -93,6 +93,21 @@ namespace MWGui
|
|||
unborrowImpl(item, count, mBorrowedFromUs);
|
||||
}
|
||||
|
||||
void TradeItemModel::adjustEncumbrance(float &encumbrance)
|
||||
{
|
||||
for (std::vector<ItemStack>::iterator it = mBorrowedToUs.begin(); it != mBorrowedToUs.end(); ++it)
|
||||
{
|
||||
MWWorld::Ptr item = it->mBase;
|
||||
encumbrance += item.getClass().getWeight(item) * it->mCount;
|
||||
}
|
||||
for (std::vector<ItemStack>::iterator it = mBorrowedFromUs.begin(); it != mBorrowedFromUs.end(); ++it)
|
||||
{
|
||||
MWWorld::Ptr item = it->mBase;
|
||||
encumbrance -= item.getClass().getWeight(item) * it->mCount;
|
||||
}
|
||||
encumbrance = std::max(0.f, encumbrance);
|
||||
}
|
||||
|
||||
void TradeItemModel::abort()
|
||||
{
|
||||
mBorrowedFromUs.clear();
|
||||
|
|
|
@ -34,6 +34,10 @@ namespace MWGui
|
|||
/// Aborts trade
|
||||
void abort();
|
||||
|
||||
/// Adjusts the given encumbrance by adding weight for items that have been lent to us,
|
||||
/// and removing weight for items we've lent to someone else.
|
||||
void adjustEncumbrance (float& encumbrance);
|
||||
|
||||
std::vector<ItemStack> getItemsBorrowedToUs();
|
||||
|
||||
private:
|
||||
|
|
|
@ -206,6 +206,15 @@ namespace MWGui
|
|||
mVideoWidget = mVideoBackground->createWidgetReal<VideoWidget>("ImageBox", 0,0,1,1, MyGUI::Align::Default);
|
||||
mVideoWidget->setNeedMouseFocus(true);
|
||||
mVideoWidget->setNeedKeyFocus(true);
|
||||
|
||||
#if MYGUI_VERSION >= MYGUI_DEFINE_VERSION(3,2,1)
|
||||
// Removes default MyGUI system clipboard implementation, which supports windows only
|
||||
MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear();
|
||||
MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear();
|
||||
|
||||
MyGUI::ClipboardManager::getInstance().eventClipboardChanged += MyGUI::newDelegate(this, &WindowManager::onClipboardChanged);
|
||||
MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WindowManager::initUI()
|
||||
|
@ -1699,4 +1708,27 @@ namespace MWGui
|
|||
{
|
||||
mScreenFader->setFactor(factor);
|
||||
}
|
||||
|
||||
void WindowManager::onClipboardChanged(const std::string &_type, const std::string &_data)
|
||||
{
|
||||
if (_type == "Text")
|
||||
SDL_SetClipboardText(MyGUI::TextIterator::getOnlyText(MyGUI::UString(_data)).asUTF8().c_str());
|
||||
}
|
||||
|
||||
void WindowManager::onClipboardRequested(const std::string &_type, std::string &_data)
|
||||
{
|
||||
if (_type != "Text")
|
||||
return;
|
||||
char* text=0;
|
||||
text = SDL_GetClipboardText();
|
||||
if (text)
|
||||
{
|
||||
// MyGUI's clipboard might still have color information, to retain that information, only set the new text
|
||||
// if it actually changed (clipboard inserted by an external application)
|
||||
if (MyGUI::TextIterator::getOnlyText(_data) != text)
|
||||
_data = text;
|
||||
}
|
||||
SDL_free(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -448,6 +448,9 @@ namespace MWGui
|
|||
void onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char);
|
||||
|
||||
void sizeVideo(int screenWidth, int screenHeight);
|
||||
|
||||
void onClipboardChanged(const std::string& _type, const std::string& _data);
|
||||
void onClipboardRequested(const std::string& _type, std::string& _data);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -498,6 +498,7 @@ namespace MWInput
|
|||
|
||||
void InputManager::keyPressed( const SDL_KeyboardEvent &arg )
|
||||
{
|
||||
#if MYGUI_VERSION <= MYGUI_DEFINE_VERSION(3,2,0)
|
||||
// Cut, copy & paste
|
||||
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
|
||||
if (focus)
|
||||
|
@ -537,20 +538,26 @@ namespace MWInput
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
|
||||
|
||||
bool consumed = false;
|
||||
if (kc != OIS::KC_UNASSIGNED)
|
||||
{
|
||||
consumed = SDL_IsTextInputActive() &&
|
||||
( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)); // Little trick to check if key is printable
|
||||
bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0);
|
||||
setPlayerControlsEnabled(!guiFocus);
|
||||
}
|
||||
if (!mControlsDisabled)
|
||||
if (!mControlsDisabled && !consumed)
|
||||
mInputBinder->keyPressed (arg);
|
||||
|
||||
// Clear MyGUI's clipboard, so it doesn't interfere with our own clipboard implementation.
|
||||
// We do not use MyGUI's clipboard manager because it doesn't support system clipboard integration with SDL.
|
||||
#if MYGUI_VERSION <= MYGUI_DEFINE_VERSION(3,2,0)
|
||||
MyGUI::ClipboardManager::getInstance().clearClipboardData("Text");
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputManager::textInput(const SDL_TextInputEvent &arg)
|
||||
|
@ -804,8 +811,7 @@ namespace MWInput
|
|||
return;
|
||||
|
||||
if(MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Journal
|
||||
&& MWBase::Environment::get().getWindowManager ()->getJournalAllowed()
|
||||
&& MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console)
|
||||
&& MWBase::Environment::get().getWindowManager ()->getJournalAllowed())
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0);
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal);
|
||||
|
|
|
@ -1402,6 +1402,7 @@ namespace MWMechanics
|
|||
if (stats.isDead())
|
||||
continue;
|
||||
|
||||
// An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package
|
||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
|
||||
{
|
||||
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow)
|
||||
|
@ -1412,6 +1413,8 @@ namespace MWMechanics
|
|||
if (followTarget == actor)
|
||||
list.push_back(iter->first);
|
||||
}
|
||||
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
|
|
|
@ -32,6 +32,15 @@ MWMechanics::AiFollow::AiFollow(const std::string &actorId, bool commanded)
|
|||
{
|
||||
}
|
||||
|
||||
MWMechanics::AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
||||
: mAlwaysFollow(follow->mAlwaysFollow), mRemainingDuration(follow->mRemainingDuration)
|
||||
, mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ)
|
||||
, mActorRefId(follow->mTargetId), mActorId(-1), mCellId(follow->mCellId)
|
||||
, mCommanded(follow->mCommanded)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
MWWorld::Ptr target = getTarget();
|
||||
|
@ -131,15 +140,6 @@ void MWMechanics::AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) co
|
|||
sequence.mPackages.push_back(package);
|
||||
}
|
||||
|
||||
MWMechanics::AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
||||
: mAlwaysFollow(follow->mAlwaysFollow), mRemainingDuration(follow->mRemainingDuration)
|
||||
, mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ)
|
||||
, mActorRefId(follow->mTargetId), mCellId(follow->mCellId)
|
||||
, mCommanded(follow->mCommanded)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MWWorld::Ptr MWMechanics::AiFollow::getTarget()
|
||||
{
|
||||
if (mActorId == -2)
|
||||
|
|
|
@ -32,12 +32,18 @@ AiPursue *MWMechanics::AiPursue::clone() const
|
|||
}
|
||||
bool AiPursue::execute (const MWWorld::Ptr& actor, float duration)
|
||||
{
|
||||
if(actor.getClass().getCreatureStats(actor).isDead())
|
||||
return true;
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); //The target to follow
|
||||
|
||||
if(target == MWWorld::Ptr())
|
||||
return true; //Target doesn't exist
|
||||
|
||||
if(target.getClass().getCreatureStats(target).isDead())
|
||||
return true;
|
||||
|
||||
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
||||
|
||||
//Set the target desition from the actor
|
||||
|
|
|
@ -196,7 +196,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock();
|
||||
if(mHitState == CharState_None)
|
||||
{
|
||||
if (mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0)
|
||||
if (mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0
|
||||
|| mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0)
|
||||
{
|
||||
mHitState = CharState_KnockOut;
|
||||
mCurrentHit = "knockout";
|
||||
|
@ -1663,6 +1664,9 @@ void CharacterController::updateVisibility()
|
|||
}
|
||||
|
||||
mAnimation->setAlpha(alpha);
|
||||
|
||||
float light = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Light).getMagnitude();
|
||||
mAnimation->setLightEffect(light);
|
||||
}
|
||||
|
||||
void CharacterController::determineAttackType()
|
||||
|
@ -1671,9 +1675,9 @@ void CharacterController::determineAttackType()
|
|||
|
||||
if(mPtr.getClass().hasInventoryStore(mPtr))
|
||||
{
|
||||
if (move[1]) // forward-backward
|
||||
if (move[1] && !move[0]) // forward-backward
|
||||
mAttackType = "thrust";
|
||||
else if (move[0]) //sideway
|
||||
else if (move[0] && !move[1]) //sideway
|
||||
mAttackType = "slash";
|
||||
else
|
||||
mAttackType = "chop";
|
||||
|
|
|
@ -19,9 +19,6 @@ namespace ESM
|
|||
namespace MWMechanics
|
||||
{
|
||||
/// \brief Additional stats for NPCs
|
||||
///
|
||||
/// \note For technical reasons the spell list and the currently selected spell is also handled by
|
||||
/// CreatureStats, even though they are actually NPC stats.
|
||||
|
||||
class NpcStats : public CreatureStats
|
||||
{
|
||||
|
|
|
@ -151,6 +151,20 @@ namespace MWMechanics
|
|||
return school;
|
||||
}
|
||||
|
||||
bool spellIncreasesSkill(const ESM::Spell *spell)
|
||||
{
|
||||
if (spell->mData.mType == ESM::Spell::ST_Spell && !(spell->mData.mFlags & ESM::Spell::F_Always))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool spellIncreasesSkill(const std::string &spellId)
|
||||
{
|
||||
const ESM::Spell* spell =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
|
||||
return spellIncreasesSkill(spell);
|
||||
}
|
||||
|
||||
float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects)
|
||||
{
|
||||
short resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId);
|
||||
|
@ -775,7 +789,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
if (mCaster.getRefData().getHandle() == "player" && spell->mData.mType == ESM::Spell::ST_Spell)
|
||||
if (mCaster.getRefData().getHandle() == "player" && spellIncreasesSkill(spell))
|
||||
mCaster.getClass().skillUsageSucceeded(mCaster,
|
||||
spellSchoolToSkill(school), 0);
|
||||
|
||||
|
@ -874,5 +888,4 @@ namespace MWMechanics
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,10 @@ namespace MWMechanics
|
|||
int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor);
|
||||
int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor);
|
||||
|
||||
/// Get whether or not the given spell contributes to skill progress.
|
||||
bool spellIncreasesSkill(const ESM::Spell* spell);
|
||||
bool spellIncreasesSkill(const std::string& spellId);
|
||||
|
||||
/// Get the resistance attribute against an effect for a given actor. This will add together
|
||||
/// ResistX and Weakness to X effects relevant against the given effect.
|
||||
float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects);
|
||||
|
|
|
@ -63,12 +63,26 @@ namespace MWMechanics
|
|||
TContainer::iterator iter = mSpells.find (lower);
|
||||
std::map<std::string, CorprusStats>::iterator corprusIt = mCorprusSpells.find(lower);
|
||||
|
||||
// if it's corprus, remove negative and keep positive effects
|
||||
if (corprusIt != mCorprusSpells.end())
|
||||
{
|
||||
worsenCorprus(lower);
|
||||
if (mPermanentSpellEffects.find(lower) != mPermanentSpellEffects.end())
|
||||
{
|
||||
MagicEffects & effects = mPermanentSpellEffects[lower];
|
||||
for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||
{
|
||||
const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->first.mId);
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
|
||||
effects.remove(effectIt->first);
|
||||
}
|
||||
}
|
||||
mCorprusSpells.erase(corprusIt);
|
||||
}
|
||||
|
||||
if (iter!=mSpells.end())
|
||||
mSpells.erase (iter);
|
||||
|
||||
if (corprusIt != mCorprusSpells.end())
|
||||
mCorprusSpells.erase(corprusIt);
|
||||
|
||||
if (spellId==mSelectedSpell)
|
||||
mSelectedSpell.clear();
|
||||
}
|
||||
|
@ -94,20 +108,17 @@ namespace MWMechanics
|
|||
if (iter->second.find(i) != iter->second.end())
|
||||
random = iter->second.at(i);
|
||||
|
||||
int magnMult = 1;
|
||||
if (mCorprusSpells.find(spell->mId) != mCorprusSpells.end())
|
||||
{
|
||||
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(spell->mEffects.mList.front().mEffectID);
|
||||
if ((it->mEffectID != ESM::MagicEffect::Corprus) && (effect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) // APPLIED_ONCE
|
||||
magnMult += mCorprusSpells.at(spell->mId).mWorsenings;
|
||||
}
|
||||
|
||||
effects.add (*it, (it->mMagnMin + (it->mMagnMax - it->mMagnMin) * random) * magnMult);
|
||||
effects.add (*it, it->mMagnMin + (it->mMagnMax - it->mMagnMin) * random);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, MagicEffects>::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it)
|
||||
{
|
||||
effects += it->second;
|
||||
}
|
||||
|
||||
return effects;
|
||||
}
|
||||
|
||||
|
@ -241,6 +252,25 @@ namespace MWMechanics
|
|||
{
|
||||
mCorprusSpells[corpSpellId].mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod;
|
||||
mCorprusSpells[corpSpellId].mWorsenings++;
|
||||
|
||||
// update worsened effects
|
||||
mPermanentSpellEffects[corpSpellId] = MagicEffects();
|
||||
const ESM::Spell * spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(corpSpellId);
|
||||
int i=0;
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt, ++i)
|
||||
{
|
||||
const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
||||
if ((effectIt->mEffectID != ESM::MagicEffect::Corprus) && (magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) // APPLIED_ONCE
|
||||
{
|
||||
float random = 1.f;
|
||||
if (mSpells[corpSpellId].find(i) != mSpells[corpSpellId].end())
|
||||
random = mSpells[corpSpellId].at(i);
|
||||
|
||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
|
||||
magnitude *= std::max(1, mCorprusSpells[corpSpellId].mWorsenings);
|
||||
mPermanentSpellEffects[corpSpellId].add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(magnitude));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Spells::hasCorprusEffect(const ESM::Spell *spell)
|
||||
|
@ -297,6 +327,20 @@ namespace MWMechanics
|
|||
for (std::map<std::string, ESM::TimeStamp>::const_iterator it = state.mUsedPowers.begin(); it != state.mUsedPowers.end(); ++it)
|
||||
mUsedPowers[it->first] = MWWorld::TimeStamp(it->second);
|
||||
|
||||
for (std::map<std::string, std::vector<ESM::SpellState::PermanentSpellEffectInfo> >::const_iterator it =
|
||||
state.mPermanentSpellEffects.begin(); it != state.mPermanentSpellEffects.end(); ++it)
|
||||
{
|
||||
const ESM::Spell * spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(it->first);
|
||||
if (!spell)
|
||||
continue;
|
||||
|
||||
mPermanentSpellEffects[it->first] = MagicEffects();
|
||||
for (std::vector<ESM::SpellState::PermanentSpellEffectInfo>::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt)
|
||||
{
|
||||
mPermanentSpellEffects[it->first].add(EffectKey(effectIt->mId, effectIt->mArg), effectIt->mMagnitude);
|
||||
}
|
||||
}
|
||||
|
||||
mCorprusSpells.clear();
|
||||
for (std::map<std::string, ESM::SpellState::CorprusStats>::const_iterator it = state.mCorprusSpells.begin(); it != state.mCorprusSpells.end(); ++it)
|
||||
{
|
||||
|
@ -316,6 +360,21 @@ namespace MWMechanics
|
|||
for (std::map<std::string, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it)
|
||||
state.mUsedPowers[it->first] = it->second.toEsm();
|
||||
|
||||
for (std::map<std::string, MagicEffects>::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it)
|
||||
{
|
||||
std::vector<ESM::SpellState::PermanentSpellEffectInfo> effectList;
|
||||
for (MagicEffects::Collection::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt)
|
||||
{
|
||||
ESM::SpellState::PermanentSpellEffectInfo info;
|
||||
info.mId = effectIt->first.mId;
|
||||
info.mArg = effectIt->first.mArg;
|
||||
info.mMagnitude = effectIt->second.getModifier();
|
||||
|
||||
effectList.push_back(info);
|
||||
}
|
||||
state.mPermanentSpellEffects[it->first] = effectList;
|
||||
}
|
||||
|
||||
for (std::map<std::string, CorprusStats>::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it)
|
||||
{
|
||||
state.mCorprusSpells[it->first].mWorsenings = mCorprusSpells.at(it->first).mWorsenings;
|
||||
|
|
|
@ -46,6 +46,9 @@ namespace MWMechanics
|
|||
|
||||
TContainer mSpells;
|
||||
|
||||
// spell-tied effects that will be applied even after removing the spell (currently used to keep positive effects when corprus is removed)
|
||||
std::map<std::string, MagicEffects> mPermanentSpellEffects;
|
||||
|
||||
// Note: this is the spell that's about to be cast, *not* the spell selected in the GUI (which may be different)
|
||||
std::string mSelectedSpell;
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node)
|
|||
, mNonAccumCtrl(NULL)
|
||||
, mAccumulate(0.0f)
|
||||
, mNullAnimationTimePtr(OGRE_NEW NullAnimationTime)
|
||||
, mGlowLight(NULL)
|
||||
{
|
||||
for(size_t i = 0;i < sNumGroups;i++)
|
||||
mAnimationTimePtr[i].bind(OGRE_NEW AnimationTime(this));
|
||||
|
@ -78,6 +79,8 @@ Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node)
|
|||
|
||||
Animation::~Animation()
|
||||
{
|
||||
setLightEffect(0);
|
||||
|
||||
mEffects.clear();
|
||||
|
||||
mAnimSources.clear();
|
||||
|
@ -110,6 +113,11 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
|
|||
|
||||
mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
|
||||
NifOgre::Loader::createObjectBase(mInsert, mdlname));
|
||||
|
||||
// Fast forward auto-play particles, which will have been set up as Emitting by the loader.
|
||||
for (unsigned int i=0; i<mObjectRoot->mParticles.size(); ++i)
|
||||
mObjectRoot->mParticles[i]->fastForward(1, 0.1);
|
||||
|
||||
if(mObjectRoot->mSkelBase)
|
||||
{
|
||||
mSkelBase = mObjectRoot->mSkelBase;
|
||||
|
@ -1194,8 +1202,9 @@ bool Animation::allowSwitchViewMode() const
|
|||
{
|
||||
for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter)
|
||||
{
|
||||
if(stateiter->second.mPriority > MWMechanics::Priority_Movement
|
||||
if((stateiter->second.mPriority > MWMechanics::Priority_Movement
|
||||
&& stateiter->second.mPriority < MWMechanics::Priority_Torch)
|
||||
|| stateiter->second.mPriority == MWMechanics::Priority_Death)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1391,6 +1400,37 @@ Ogre::Vector3 Animation::getEnchantmentColor(MWWorld::Ptr item)
|
|||
return result;
|
||||
}
|
||||
|
||||
void Animation::setLightEffect(float effect)
|
||||
{
|
||||
if (effect == 0)
|
||||
{
|
||||
if (mGlowLight)
|
||||
{
|
||||
mInsert->getCreator()->destroySceneNode(mGlowLight->getParentSceneNode());
|
||||
mInsert->getCreator()->destroyLight(mGlowLight);
|
||||
mGlowLight = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mGlowLight)
|
||||
{
|
||||
mGlowLight = mInsert->getCreator()->createLight();
|
||||
|
||||
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
|
||||
for(size_t i = 0;i < mObjectRoot->mEntities.size();i++)
|
||||
{
|
||||
Ogre::Entity *ent = mObjectRoot->mEntities[i];
|
||||
bounds.merge(ent->getBoundingBox());
|
||||
}
|
||||
mInsert->createChildSceneNode(bounds.getCenter())->attachObject(mGlowLight);
|
||||
}
|
||||
mGlowLight->setType(Ogre::Light::LT_POINT);
|
||||
effect += 3;
|
||||
mGlowLight->setAttenuation(1.0f / (0.03 * (0.5/effect)), 0, 0.5/effect, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model)
|
||||
: Animation(ptr, ptr.getRefData().getBaseNode())
|
||||
|
|
|
@ -126,6 +126,8 @@ protected:
|
|||
|
||||
MWWorld::Ptr mPtr;
|
||||
|
||||
Ogre::Light* mGlowLight;
|
||||
|
||||
Ogre::SceneNode *mInsert;
|
||||
Ogre::Entity *mSkelBase;
|
||||
NifOgre::ObjectScenePtr mObjectRoot;
|
||||
|
@ -301,6 +303,11 @@ public:
|
|||
/// This is typically called as part of runAnimation, but may be called manually if needed.
|
||||
void updateEffects(float duration);
|
||||
|
||||
// TODO: move outside of this class
|
||||
/// Makes this object glow, by placing a Light in its center.
|
||||
/// @param effect Controls the radius and intensity of the light.
|
||||
void setLightEffect(float effect);
|
||||
|
||||
virtual void showWeapons(bool showWeapon);
|
||||
virtual void showCarriedLeft(bool show) {}
|
||||
virtual void attachArrow() {}
|
||||
|
|
|
@ -552,6 +552,10 @@ NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model
|
|||
std::for_each(objects->mEntities.begin(), objects->mEntities.end(), SetObjectGroup(group));
|
||||
std::for_each(objects->mParticles.begin(), objects->mParticles.end(), SetObjectGroup(group));
|
||||
|
||||
// Fast forward auto-play particles, which will have been set up as Emitting by the loader.
|
||||
for (unsigned int i=0; i<objects->mParticles.size(); ++i)
|
||||
objects->mParticles[i]->fastForward(1, 0.1);
|
||||
|
||||
if(objects->mSkelBase)
|
||||
{
|
||||
Ogre::AnimationStateSet *aset = objects->mSkelBase->getAllAnimationStates();
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace MWScript
|
|||
const std::string& name, char type) const
|
||||
{
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocals (scriptId).
|
||||
search (type, name);
|
||||
searchIndex (type, name);
|
||||
|
||||
if (index!=-1)
|
||||
return index;
|
||||
|
|
|
@ -528,11 +528,12 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr actor = R()(runtime, false);
|
||||
|
||||
std::string factionID = "";
|
||||
|
||||
if(arg0==0)
|
||||
{
|
||||
MWWorld::Ptr actor = R()(runtime);
|
||||
factionID = getDialogueActorFaction(actor);
|
||||
}
|
||||
else
|
||||
|
@ -562,11 +563,12 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr actor = R()(runtime, false);
|
||||
|
||||
std::string factionID = "";
|
||||
|
||||
if(arg0==0)
|
||||
{
|
||||
MWWorld::Ptr actor = R()(runtime);
|
||||
factionID = getDialogueActorFaction(actor);
|
||||
}
|
||||
else
|
||||
|
@ -602,11 +604,12 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr actor = R()(runtime, false);
|
||||
|
||||
std::string factionID = "";
|
||||
|
||||
if(arg0==0)
|
||||
{
|
||||
MWWorld::Ptr actor = R()(runtime);
|
||||
factionID = getDialogueActorFaction(actor);
|
||||
}
|
||||
else
|
||||
|
@ -637,6 +640,8 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime, false);
|
||||
|
||||
std::string factionID = "";
|
||||
if(arg0 >0)
|
||||
{
|
||||
|
@ -645,8 +650,6 @@ namespace MWScript
|
|||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
||||
{
|
||||
factionID = "";
|
||||
|
@ -750,6 +753,8 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime, false);
|
||||
|
||||
std::string factionId;
|
||||
|
||||
if (arg0==1)
|
||||
|
@ -759,8 +764,6 @@ namespace MWScript
|
|||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
if (!ptr.getClass().getNpcStats (ptr).getFactionRanks().empty())
|
||||
factionId = ptr.getClass().getNpcStats (ptr).getFactionRanks().begin()->first;
|
||||
}
|
||||
|
@ -783,6 +786,8 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime, false);
|
||||
|
||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
|
@ -795,8 +800,6 @@ namespace MWScript
|
|||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
if (!ptr.getClass().getNpcStats (ptr).getFactionRanks().empty())
|
||||
factionId = ptr.getClass().getNpcStats (ptr).getFactionRanks().begin()->first;
|
||||
}
|
||||
|
@ -818,6 +821,8 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime, false);
|
||||
|
||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
|
@ -830,8 +835,6 @@ namespace MWScript
|
|||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
if (!ptr.getClass().getNpcStats (ptr).getFactionRanks().empty())
|
||||
factionId = ptr.getClass().getNpcStats (ptr).getFactionRanks().begin()->first;
|
||||
}
|
||||
|
@ -913,6 +916,8 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime, false);
|
||||
|
||||
std::string factionID = "";
|
||||
if(arg0 >0 )
|
||||
{
|
||||
|
@ -921,8 +926,6 @@ namespace MWScript
|
|||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
||||
{
|
||||
factionID = "";
|
||||
|
@ -952,6 +955,8 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime, false);
|
||||
|
||||
std::string factionID = "";
|
||||
if(arg0 >0 )
|
||||
{
|
||||
|
@ -960,7 +965,6 @@ namespace MWScript
|
|||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
||||
{
|
||||
factionID = "";
|
||||
|
@ -985,6 +989,8 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime, false);
|
||||
|
||||
std::string factionID = "";
|
||||
if(arg0 >0 )
|
||||
{
|
||||
|
@ -993,7 +999,6 @@ namespace MWScript
|
|||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
||||
{
|
||||
factionID = "";
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include "actionteleport.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -16,15 +15,19 @@ namespace MWWorld
|
|||
|
||||
void ActionTeleport::executeImp (const Ptr& actor)
|
||||
{
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
|
||||
//find any NPC that is following the actor and teleport him too
|
||||
std::list<MWWorld::Ptr> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor);
|
||||
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||
{
|
||||
executeImp(*it);
|
||||
teleport(*it);
|
||||
}
|
||||
|
||||
teleport(actor);
|
||||
}
|
||||
|
||||
void ActionTeleport::teleport(const Ptr &actor)
|
||||
{
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
if(actor == world->getPlayerPtr())
|
||||
{
|
||||
world->getPlayer().setTeleported(true);
|
||||
|
|
|
@ -14,12 +14,16 @@ namespace MWWorld
|
|||
std::string mCellName;
|
||||
ESM::Position mPosition;
|
||||
|
||||
/// Teleports this actor and also teleports anyone following that actor.
|
||||
virtual void executeImp (const Ptr& actor);
|
||||
|
||||
/// Teleports only the given actor (internal use).
|
||||
void teleport(const Ptr &actor);
|
||||
|
||||
public:
|
||||
|
||||
ActionTeleport (const std::string& cellName, const ESM::Position& position);
|
||||
///< If cellName is empty, an exterior cell is asumed.
|
||||
///< If cellName is empty, an exterior cell is assumed.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "../mwmechanics/spellcasting.hpp"
|
||||
|
||||
#include "../mwrender/effectmanager.hpp"
|
||||
#include "../mwrender/animation.hpp"
|
||||
#include "../mwrender/renderconst.hpp"
|
||||
|
||||
#include "../mwsound/sound.hpp"
|
||||
|
||||
|
@ -41,6 +43,9 @@ namespace MWWorld
|
|||
if(state.mObject->mControllers[i].getSource().isNull())
|
||||
state.mObject->mControllers[i].setSource(Ogre::SharedPtr<MWRender::EffectAnimationTime> (new MWRender::EffectAnimationTime()));
|
||||
}
|
||||
|
||||
MWRender::Animation::setRenderProperties(state.mObject, MWRender::RV_Misc,
|
||||
MWRender::RQG_Main, MWRender::RQG_Alpha, 0.f, false, NULL);
|
||||
}
|
||||
|
||||
void ProjectileManager::update(NifOgre::ObjectScenePtr object, float duration)
|
||||
|
|
|
@ -259,8 +259,6 @@ namespace MWWorld
|
|||
|
||||
void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos)
|
||||
{
|
||||
Nif::NIFFile::CacheLock cachelock;
|
||||
|
||||
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||
Loading::ScopedLoad load(loadingListener);
|
||||
|
||||
|
@ -271,24 +269,6 @@ namespace MWWorld
|
|||
|
||||
CellStoreCollection::iterator active = mActiveCells.begin();
|
||||
|
||||
// get the number of cells to unload
|
||||
int numUnload = 0;
|
||||
while (active!=mActiveCells.end())
|
||||
{
|
||||
if ((*active)->getCell()->isExterior())
|
||||
{
|
||||
if (std::abs (X-(*active)->getCell()->getGridX())<=1 &&
|
||||
std::abs (Y-(*active)->getCell()->getGridY())<=1)
|
||||
{
|
||||
// keep cells within the new 3x3 grid
|
||||
++active;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
++active;
|
||||
++numUnload;
|
||||
}
|
||||
|
||||
active = mActiveCells.begin();
|
||||
while (active!=mActiveCells.end())
|
||||
{
|
||||
|
@ -408,7 +388,6 @@ namespace MWWorld
|
|||
if(!loadcell)
|
||||
loadcell = *mCurrentCell != *cell;
|
||||
|
||||
Nif::NIFFile::CacheLock lock;
|
||||
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5);
|
||||
|
||||
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||
|
@ -438,14 +417,6 @@ namespace MWWorld
|
|||
// remove active
|
||||
CellStoreCollection::iterator active = mActiveCells.begin();
|
||||
|
||||
// count number of cells to unload
|
||||
int numUnload = 0;
|
||||
while (active!=mActiveCells.end())
|
||||
{
|
||||
++active;
|
||||
++numUnload;
|
||||
}
|
||||
|
||||
// unload
|
||||
int current = 0;
|
||||
active = mActiveCells.begin();
|
||||
|
|
|
@ -19,7 +19,11 @@ add_component_dir (bsa
|
|||
)
|
||||
|
||||
add_component_dir (nif
|
||||
controlled effect niftypes record controller extra node record_ptr data niffile property
|
||||
controlled effect niftypes record controller extra node record_ptr data niffile property nifkey data node
|
||||
)
|
||||
|
||||
add_component_dir (nifcache
|
||||
nifcache
|
||||
)
|
||||
|
||||
add_component_dir (nifogre
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
#include "lineparser.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "scanner.hpp"
|
||||
|
@ -120,7 +122,7 @@ namespace Compiler
|
|||
|
||||
if (mState==SetMemberVarState)
|
||||
{
|
||||
mMemberName = name;
|
||||
mMemberName = Misc::StringUtils::lowerCase (name);
|
||||
std::pair<char, bool> type = getContext().getMemberType (mMemberName, mName);
|
||||
|
||||
if (type.first!=' ')
|
||||
|
@ -297,7 +299,12 @@ namespace Compiler
|
|||
|
||||
try
|
||||
{
|
||||
ErrorDowngrade errorDowngrade (getErrorHandler());
|
||||
// workaround for broken positioncell instructions.
|
||||
/// \todo add option to disable this
|
||||
std::auto_ptr<ErrorDowngrade> errorDowngrade (0);
|
||||
if (Misc::StringUtils::lowerCase (loc.mLiteral)=="positioncell")
|
||||
errorDowngrade.reset (new ErrorDowngrade (getErrorHandler()));
|
||||
|
||||
std::vector<Interpreter::Type_Code> code;
|
||||
optionals = mExprParser.parseArguments (argumentType, scanner, code);
|
||||
mCode.insert (mCode.begin(), code.begin(), code.end());
|
||||
|
|
|
@ -15,8 +15,6 @@ namespace Compiler
|
|||
std::vector<std::string> mLongs;
|
||||
std::vector<std::string> mFloats;
|
||||
|
||||
int searchIndex (char type, const std::string& name) const;
|
||||
|
||||
std::vector<std::string>& get (char type);
|
||||
|
||||
public:
|
||||
|
@ -27,9 +25,11 @@ namespace Compiler
|
|||
int getIndex (const std::string& name) const;
|
||||
///< return index for local variable \a name (-1: does not exist).
|
||||
|
||||
bool search (char type, const std::string& name) const;
|
||||
|
||||
/// Return index for local variable \a name of type \a type (-1: variable does not
|
||||
/// exit).
|
||||
bool search (char type, const std::string& name) const;
|
||||
int searchIndex (char type, const std::string& name) const;
|
||||
|
||||
const std::vector<std::string>& get (char type) const;
|
||||
|
||||
|
|
|
@ -42,8 +42,13 @@ void MagicEffect::load(ESMReader &esm)
|
|||
esm.getHNT(mIndex, "INDX");
|
||||
|
||||
esm.getHNT(mData, "MEDT", 36);
|
||||
if (mIndex>=0 && mIndex<NumberOfHardcodedFlags)
|
||||
mData.mFlags |= HardcodedFlags[mIndex];
|
||||
if (esm.getFormat() == 0)
|
||||
{
|
||||
// don't allow mods to change fixed flags in the legacy format
|
||||
mData.mFlags &= (AllowSpellmaking | AllowEnchanting | NegativeLight);
|
||||
if (mIndex>=0 && mIndex<NumberOfHardcodedFlags)
|
||||
mData.mFlags |= HardcodedFlags[mIndex];
|
||||
}
|
||||
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
mParticle = esm.getHNOString("PTEX");
|
||||
|
|
|
@ -16,6 +16,7 @@ struct MagicEffect
|
|||
|
||||
enum Flags
|
||||
{
|
||||
// Originally fixed flags (HardcodedFlags array consists of just these)
|
||||
TargetSkill = 0x1, // Affects a specific skill, which is specified elsewhere in the effect structure.
|
||||
TargetAttribute = 0x2, // Affects a specific attribute, which is specified elsewhere in the effect structure.
|
||||
NoDuration = 0x4, // Has no duration. Only runs effect once on cast.
|
||||
|
@ -28,8 +29,14 @@ struct MagicEffect
|
|||
UncappedDamage = 0x1000, // Negates multiple cap behaviours. Allows an effect to reduce an attribute below zero; removes the normal minimum effect duration of 1 second.
|
||||
NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target.
|
||||
Unreflectable = 0x10000, // Cannot be reflected, the effect always lands normally.
|
||||
CasterLinked = 0x20000 // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells.
|
||||
CasterLinked = 0x20000, // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells.
|
||||
|
||||
// Originally modifiable flags
|
||||
AllowSpellmaking = 0x200, // Can be used for spellmaking
|
||||
AllowEnchanting = 0x400, // Can be used for enchanting
|
||||
NegativeLight = 0x800 // Negative light source
|
||||
};
|
||||
|
||||
enum MagnitudeDisplayType
|
||||
{
|
||||
MDT_None,
|
||||
|
@ -47,8 +54,10 @@ struct MagicEffect
|
|||
int mFlags;
|
||||
// Glow color for enchanted items with this effect
|
||||
int mRed, mGreen, mBlue;
|
||||
// Properties of the fired magic 'ball'
|
||||
float mSpeed, mSize, mSizeCap;
|
||||
|
||||
float mUnknown1;
|
||||
float mSpeed; // Speed of fired projectile
|
||||
float mUnknown2;
|
||||
}; // 36 bytes
|
||||
|
||||
static const std::map<short,std::string> sNames;
|
||||
|
|
|
@ -27,6 +27,23 @@ namespace ESM
|
|||
mSpells[id] = random;
|
||||
}
|
||||
|
||||
while (esm.isNextSub("PERM"))
|
||||
{
|
||||
std::string spellId = esm.getHString();
|
||||
|
||||
std::vector<PermanentSpellEffectInfo> permEffectList;
|
||||
while (esm.isNextSub("EFID"))
|
||||
{
|
||||
PermanentSpellEffectInfo info;
|
||||
esm.getHT(info.mId);
|
||||
esm.getHNT(info.mArg, "ARG_");
|
||||
esm.getHNT(info.mMagnitude, "MAGN");
|
||||
|
||||
permEffectList.push_back(info);
|
||||
}
|
||||
mPermanentSpellEffects[spellId] = permEffectList;
|
||||
}
|
||||
|
||||
while (esm.isNextSub("CORP"))
|
||||
{
|
||||
std::string id = esm.getHString();
|
||||
|
@ -64,6 +81,19 @@ namespace ESM
|
|||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::vector<PermanentSpellEffectInfo> >::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it)
|
||||
{
|
||||
esm.writeHNString("PERM", it->first);
|
||||
|
||||
const std::vector<PermanentSpellEffectInfo> & effects = it->second;
|
||||
for (std::vector<PermanentSpellEffectInfo>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||
{
|
||||
esm.writeHNT("EFID", effectIt->mId);
|
||||
esm.writeHNT("ARG_", effectIt->mArg);
|
||||
esm.writeHNT("MAGN", effectIt->mMagnitude);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, CorprusStats>::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it)
|
||||
{
|
||||
esm.writeHNString("CORP", it->first);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define OPENMW_ESM_SPELLSTATE_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "defs.hpp"
|
||||
|
@ -19,9 +20,18 @@ namespace ESM
|
|||
TimeStamp mNextWorsening;
|
||||
};
|
||||
|
||||
struct PermanentSpellEffectInfo
|
||||
{
|
||||
int mId;
|
||||
int mArg;
|
||||
float mMagnitude;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, std::map<const int, float> > TContainer;
|
||||
TContainer mSpells;
|
||||
|
||||
std::map<std::string, std::vector<PermanentSpellEffectInfo> > mPermanentSpellEffects;
|
||||
|
||||
std::map<std::string, CorprusStats> mCorprusSpells;
|
||||
|
||||
std::map<std::string, TimeStamp> mUsedPowers;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <string>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#ifndef ANDROID
|
||||
#include <components/files/linuxpath.hpp>
|
||||
namespace Files { typedef LinuxPath TargetPathType; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "linuxpath.hpp"
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
@ -157,4 +157,4 @@ boost::filesystem::path LinuxPath::getInstallPath() const
|
|||
|
||||
} /* namespace Files */
|
||||
|
||||
#endif /* defined(__linux__) || defined(__FreeBSD__) */
|
||||
#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef COMPONENTS_FILES_LINUXPATH_H
|
||||
#define COMPONENTS_FILES_LINUXPATH_H
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
@ -56,6 +56,6 @@ struct LinuxPath
|
|||
|
||||
} /* namespace Files */
|
||||
|
||||
#endif /* defined(__linux__) || defined(__FreeBSD__) */
|
||||
#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
|
||||
|
||||
#endif /* COMPONENTS_FILES_LINUXPATH_H */
|
||||
|
|
29
components/nif/data.cpp
Normal file
29
components/nif/data.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include "data.hpp"
|
||||
#include "node.hpp"
|
||||
|
||||
namespace Nif
|
||||
{
|
||||
void NiSkinInstance::post(NIFFile *nif)
|
||||
{
|
||||
data.post(nif);
|
||||
root.post(nif);
|
||||
bones.post(nif);
|
||||
|
||||
if(data.empty() || root.empty())
|
||||
nif->fail("NiSkinInstance missing root or data");
|
||||
|
||||
size_t bnum = bones.length();
|
||||
if(bnum != data->bones.size())
|
||||
nif->fail("Mismatch in NiSkinData bone count");
|
||||
|
||||
root->makeRootBone(&data->trafo);
|
||||
|
||||
for(size_t i=0; i<bnum; i++)
|
||||
{
|
||||
if(bones[i].empty())
|
||||
nif->fail("Oops: Missing bone! Don't know how to handle this.");
|
||||
bones[i]->makeBone(i, data->bones[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace
|
|
@ -25,9 +25,8 @@
|
|||
#define OPENMW_COMPONENTS_NIF_DATA_HPP
|
||||
|
||||
#include "controlled.hpp"
|
||||
|
||||
#include <OgreQuaternion.h>
|
||||
#include <OgreVector3.h>
|
||||
#include "nifstream.hpp"
|
||||
#include "nifkey.hpp"
|
||||
|
||||
namespace Nif
|
||||
{
|
||||
|
|
|
@ -1,177 +1,15 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008-2010 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.sourceforge.net/
|
||||
|
||||
This file (nif_file.cpp) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
|
||||
#include "niffile.hpp"
|
||||
#include "record.hpp"
|
||||
#include "components/misc/stringops.hpp"
|
||||
|
||||
#include "extra.hpp"
|
||||
#include "controlled.hpp"
|
||||
#include "node.hpp"
|
||||
#include "property.hpp"
|
||||
#include "data.hpp"
|
||||
#include "effect.hpp"
|
||||
#include "controller.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
//TODO: when threading is needed, enable these
|
||||
//#include <boost/mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <OgreResourceGroupManager.h>
|
||||
|
||||
namespace Nif
|
||||
{
|
||||
|
||||
class NIFFile::LoadedCache
|
||||
{
|
||||
//TODO: enable this to make cache thread safe...
|
||||
//typedef boost::mutex mutex;
|
||||
|
||||
struct mutex
|
||||
{
|
||||
void lock () {};
|
||||
void unlock () {}
|
||||
};
|
||||
|
||||
typedef boost::lock_guard <mutex> lock_guard;
|
||||
typedef std::map < std::string, boost::weak_ptr <NIFFile> > loaded_map;
|
||||
typedef std::vector < boost::shared_ptr <NIFFile> > locked_files;
|
||||
|
||||
static int sLockLevel;
|
||||
static mutex sProtector;
|
||||
static loaded_map sLoadedMap;
|
||||
static locked_files sLockedFiles;
|
||||
|
||||
public:
|
||||
|
||||
static ptr create (const std::string &name)
|
||||
{
|
||||
lock_guard _ (sProtector);
|
||||
|
||||
ptr result;
|
||||
|
||||
// lookup the resource
|
||||
loaded_map::iterator i = sLoadedMap.find (name);
|
||||
|
||||
if (i == sLoadedMap.end ()) // it doesn't existing currently,
|
||||
{ // or hasn't in the very near past
|
||||
|
||||
// create it now, for smoother threading if needed, the
|
||||
// loading should be performed outside of the sLoaderMap
|
||||
// lock and an alternate mechanism should be used to
|
||||
// synchronize threads competing to load the same resource
|
||||
result = boost::make_shared <NIFFile> (name, psudo_private_modifier());
|
||||
|
||||
// if we are locking the cache add an extra reference
|
||||
// to keep the file in memory
|
||||
if (sLockLevel > 0)
|
||||
sLockedFiles.push_back (result);
|
||||
|
||||
// stash a reference to the resource so that future
|
||||
// calls can benefit
|
||||
sLoadedMap [name] = boost::weak_ptr <NIFFile> (result);
|
||||
}
|
||||
else // it may (probably) still exists
|
||||
{
|
||||
// attempt to get the reference
|
||||
result = i->second.lock ();
|
||||
|
||||
if (!result) // resource is in the process of being destroyed
|
||||
{
|
||||
// create a new instance, to replace the one that has
|
||||
// begun the irreversible process of being destroyed
|
||||
result = boost::make_shared <NIFFile> (name, psudo_private_modifier());
|
||||
|
||||
// respect the cache lock...
|
||||
if (sLockLevel > 0)
|
||||
sLockedFiles.push_back (result);
|
||||
|
||||
// we potentially overwrite an expired pointer here
|
||||
// but the other thread performing the delete on
|
||||
// the previous copy of this resource will detect it
|
||||
// and make sure not to erase the new reference
|
||||
sLoadedMap [name] = boost::weak_ptr <NIFFile> (result);
|
||||
}
|
||||
}
|
||||
|
||||
// we made it!
|
||||
return result;
|
||||
}
|
||||
|
||||
static void release (NIFFile * file)
|
||||
{
|
||||
lock_guard _ (sProtector);
|
||||
|
||||
loaded_map::iterator i = sLoadedMap.find (file->filename);
|
||||
|
||||
// its got to be in here, it just might not be us...
|
||||
assert (i != sLoadedMap.end ());
|
||||
|
||||
// if weak_ptr is still expired, this resource hasn't been recreated
|
||||
// between the initiation of the final release due to destruction
|
||||
// of the last shared pointer and this thread acquiring the lock on
|
||||
// the loader map
|
||||
if (i->second.expired ())
|
||||
sLoadedMap.erase (i);
|
||||
}
|
||||
|
||||
static void lockCache ()
|
||||
{
|
||||
lock_guard _ (sProtector);
|
||||
|
||||
sLockLevel++;
|
||||
}
|
||||
|
||||
static void unlockCache ()
|
||||
{
|
||||
locked_files resetList;
|
||||
|
||||
{
|
||||
lock_guard _ (sProtector);
|
||||
|
||||
if (--sLockLevel)
|
||||
sLockedFiles.swap(resetList);
|
||||
}
|
||||
|
||||
// this not necessary, but makes it clear that the
|
||||
// deletion of the locked cache entries is being done
|
||||
// outside the protection of sProtector
|
||||
resetList.clear ();
|
||||
}
|
||||
};
|
||||
|
||||
int NIFFile::LoadedCache::sLockLevel = 0;
|
||||
NIFFile::LoadedCache::mutex NIFFile::LoadedCache::sProtector;
|
||||
NIFFile::LoadedCache::loaded_map NIFFile::LoadedCache::sLoadedMap;
|
||||
NIFFile::LoadedCache::locked_files NIFFile::LoadedCache::sLockedFiles;
|
||||
|
||||
// these three calls are forwarded to the cache implementation...
|
||||
void NIFFile::lockCache () { LoadedCache::lockCache (); }
|
||||
void NIFFile::unlockCache () { LoadedCache::unlockCache (); }
|
||||
NIFFile::ptr NIFFile::create (const std::string &name) { return LoadedCache::create (name); }
|
||||
|
||||
/// Open a NIF stream. The name is used for error messages.
|
||||
NIFFile::NIFFile(const std::string &name, psudo_private_modifier)
|
||||
NIFFile::NIFFile(const std::string &name)
|
||||
: ver(0)
|
||||
, filename(name)
|
||||
{
|
||||
|
@ -180,10 +18,10 @@ NIFFile::NIFFile(const std::string &name, psudo_private_modifier)
|
|||
|
||||
NIFFile::~NIFFile()
|
||||
{
|
||||
LoadedCache::release (this);
|
||||
|
||||
for(std::size_t i=0; i<records.size(); i++)
|
||||
delete records[i];
|
||||
for (std::vector<Record*>::iterator it = records.begin() ; it != records.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename NodeType> static Record* construct() { return new NodeType; }
|
||||
|
@ -192,100 +30,84 @@ struct RecordFactoryEntry {
|
|||
|
||||
typedef Record* (*create_t) ();
|
||||
|
||||
char const * mName;
|
||||
create_t mCreate;
|
||||
RecordType mType;
|
||||
|
||||
};
|
||||
|
||||
/* These are all the record types we know how to read.
|
||||
|
||||
This can be heavily optimized later if needed. For example, a
|
||||
hash table or a FSM-based parser could be used to look up
|
||||
node names.
|
||||
*/
|
||||
|
||||
static const RecordFactoryEntry recordFactories [] = {
|
||||
|
||||
{ "NiNode", &construct <NiNode >, RC_NiNode },
|
||||
{ "AvoidNode", &construct <NiNode >, RC_AvoidNode },
|
||||
{ "NiBSParticleNode", &construct <NiNode >, RC_NiBSParticleNode },
|
||||
{ "NiBSAnimationNode", &construct <NiNode >, RC_NiBSAnimationNode },
|
||||
{ "NiBillboardNode", &construct <NiNode >, RC_NiBillboardNode },
|
||||
{ "NiTriShape", &construct <NiTriShape >, RC_NiTriShape },
|
||||
{ "NiRotatingParticles", &construct <NiRotatingParticles >, RC_NiRotatingParticles },
|
||||
{ "NiAutoNormalParticles", &construct <NiAutoNormalParticles >, RC_NiAutoNormalParticles },
|
||||
{ "NiCamera", &construct <NiCamera >, RC_NiCamera },
|
||||
{ "RootCollisionNode", &construct <NiNode >, RC_RootCollisionNode },
|
||||
{ "NiTexturingProperty", &construct <NiTexturingProperty >, RC_NiTexturingProperty },
|
||||
{ "NiMaterialProperty", &construct <NiMaterialProperty >, RC_NiMaterialProperty },
|
||||
{ "NiZBufferProperty", &construct <NiZBufferProperty >, RC_NiZBufferProperty },
|
||||
{ "NiAlphaProperty", &construct <NiAlphaProperty >, RC_NiAlphaProperty },
|
||||
{ "NiVertexColorProperty", &construct <NiVertexColorProperty >, RC_NiVertexColorProperty },
|
||||
{ "NiShadeProperty", &construct <NiShadeProperty >, RC_NiShadeProperty },
|
||||
{ "NiDitherProperty", &construct <NiDitherProperty >, RC_NiDitherProperty },
|
||||
{ "NiWireframeProperty", &construct <NiWireframeProperty >, RC_NiWireframeProperty },
|
||||
{ "NiSpecularProperty", &construct <NiSpecularProperty >, RC_NiSpecularProperty },
|
||||
{ "NiStencilProperty", &construct <NiStencilProperty >, RC_NiStencilProperty },
|
||||
{ "NiVisController", &construct <NiVisController >, RC_NiVisController },
|
||||
{ "NiGeomMorpherController", &construct <NiGeomMorpherController >, RC_NiGeomMorpherController },
|
||||
{ "NiKeyframeController", &construct <NiKeyframeController >, RC_NiKeyframeController },
|
||||
{ "NiAlphaController", &construct <NiAlphaController >, RC_NiAlphaController },
|
||||
{ "NiUVController", &construct <NiUVController >, RC_NiUVController },
|
||||
{ "NiPathController", &construct <NiPathController >, RC_NiPathController },
|
||||
{ "NiMaterialColorController", &construct <NiMaterialColorController >, RC_NiMaterialColorController },
|
||||
{ "NiBSPArrayController", &construct <NiBSPArrayController >, RC_NiBSPArrayController },
|
||||
{ "NiParticleSystemController", &construct <NiParticleSystemController >, RC_NiParticleSystemController },
|
||||
{ "NiFlipController", &construct <NiFlipController >, RC_NiFlipController },
|
||||
{ "NiAmbientLight", &construct <NiLight >, RC_NiLight },
|
||||
{ "NiDirectionalLight", &construct <NiLight >, RC_NiLight },
|
||||
{ "NiTextureEffect", &construct <NiTextureEffect >, RC_NiTextureEffect },
|
||||
{ "NiVertWeightsExtraData", &construct <NiVertWeightsExtraData >, RC_NiVertWeightsExtraData },
|
||||
{ "NiTextKeyExtraData", &construct <NiTextKeyExtraData >, RC_NiTextKeyExtraData },
|
||||
{ "NiStringExtraData", &construct <NiStringExtraData >, RC_NiStringExtraData },
|
||||
{ "NiGravity", &construct <NiGravity >, RC_NiGravity },
|
||||
{ "NiPlanarCollider", &construct <NiPlanarCollider >, RC_NiPlanarCollider },
|
||||
{ "NiParticleGrowFade", &construct <NiParticleGrowFade >, RC_NiParticleGrowFade },
|
||||
{ "NiParticleColorModifier", &construct <NiParticleColorModifier >, RC_NiParticleColorModifier },
|
||||
{ "NiParticleRotation", &construct <NiParticleRotation >, RC_NiParticleRotation },
|
||||
{ "NiFloatData", &construct <NiFloatData >, RC_NiFloatData },
|
||||
{ "NiTriShapeData", &construct <NiTriShapeData >, RC_NiTriShapeData },
|
||||
{ "NiVisData", &construct <NiVisData >, RC_NiVisData },
|
||||
{ "NiColorData", &construct <NiColorData >, RC_NiColorData },
|
||||
{ "NiPixelData", &construct <NiPixelData >, RC_NiPixelData },
|
||||
{ "NiMorphData", &construct <NiMorphData >, RC_NiMorphData },
|
||||
{ "NiKeyframeData", &construct <NiKeyframeData >, RC_NiKeyframeData },
|
||||
{ "NiSkinData", &construct <NiSkinData >, RC_NiSkinData },
|
||||
{ "NiUVData", &construct <NiUVData >, RC_NiUVData },
|
||||
{ "NiPosData", &construct <NiPosData >, RC_NiPosData },
|
||||
{ "NiRotatingParticlesData", &construct <NiRotatingParticlesData >, RC_NiRotatingParticlesData },
|
||||
{ "NiAutoNormalParticlesData", &construct <NiAutoNormalParticlesData >, RC_NiAutoNormalParticlesData },
|
||||
{ "NiSequenceStreamHelper", &construct <NiSequenceStreamHelper >, RC_NiSequenceStreamHelper },
|
||||
{ "NiSourceTexture", &construct <NiSourceTexture >, RC_NiSourceTexture },
|
||||
{ "NiSkinInstance", &construct <NiSkinInstance >, RC_NiSkinInstance },
|
||||
};
|
||||
|
||||
static RecordFactoryEntry const * recordFactories_begin = &recordFactories [0];
|
||||
static RecordFactoryEntry const * recordFactories_end = &recordFactories [sizeof (recordFactories) / sizeof (recordFactories[0])];
|
||||
|
||||
RecordFactoryEntry const * lookupRecordFactory (char const * name)
|
||||
///Helper function for adding records to the factory map
|
||||
static std::pair<std::string,RecordFactoryEntry> makeEntry(std::string recName, Record* (*create_t) (), RecordType type)
|
||||
{
|
||||
RecordFactoryEntry const * i;
|
||||
|
||||
for (i = recordFactories_begin; i != recordFactories_end; ++i)
|
||||
if (strcmp (name, i->mName) == 0)
|
||||
break;
|
||||
|
||||
if (i == recordFactories_end)
|
||||
return NULL;
|
||||
|
||||
return i;
|
||||
RecordFactoryEntry anEntry = {create_t,type};
|
||||
return std::make_pair<std::string,RecordFactoryEntry>(recName, anEntry);
|
||||
}
|
||||
|
||||
/* This file implements functions from the NIFFile class. It is also
|
||||
where we stash all the functions we couldn't add as inline
|
||||
definitions in the record types.
|
||||
*/
|
||||
///These are all the record types we know how to read.
|
||||
static std::map<std::string,RecordFactoryEntry> makeFactory()
|
||||
{
|
||||
std::map<std::string,RecordFactoryEntry> newFactory;
|
||||
newFactory.insert(makeEntry("NiNode", &construct <NiNode> , RC_NiNode ));
|
||||
newFactory.insert(makeEntry("AvoidNode", &construct <NiNode> , RC_AvoidNode ));
|
||||
newFactory.insert(makeEntry("NiBSParticleNode", &construct <NiNode> , RC_NiBSParticleNode ));
|
||||
newFactory.insert(makeEntry("NiBSAnimationNode", &construct <NiNode> , RC_NiBSAnimationNode ));
|
||||
newFactory.insert(makeEntry("NiBillboardNode", &construct <NiNode> , RC_NiBillboardNode ));
|
||||
newFactory.insert(makeEntry("NiTriShape", &construct <NiTriShape> , RC_NiTriShape ));
|
||||
newFactory.insert(makeEntry("NiRotatingParticles", &construct <NiRotatingParticles> , RC_NiRotatingParticles ));
|
||||
newFactory.insert(makeEntry("NiAutoNormalParticles", &construct <NiAutoNormalParticles> , RC_NiAutoNormalParticles ));
|
||||
newFactory.insert(makeEntry("NiCamera", &construct <NiCamera> , RC_NiCamera ));
|
||||
newFactory.insert(makeEntry("RootCollisionNode", &construct <NiNode> , RC_RootCollisionNode ));
|
||||
newFactory.insert(makeEntry("NiTexturingProperty", &construct <NiTexturingProperty> , RC_NiTexturingProperty ));
|
||||
newFactory.insert(makeEntry("NiMaterialProperty", &construct <NiMaterialProperty> , RC_NiMaterialProperty ));
|
||||
newFactory.insert(makeEntry("NiZBufferProperty", &construct <NiZBufferProperty> , RC_NiZBufferProperty ));
|
||||
newFactory.insert(makeEntry("NiAlphaProperty", &construct <NiAlphaProperty> , RC_NiAlphaProperty ));
|
||||
newFactory.insert(makeEntry("NiVertexColorProperty", &construct <NiVertexColorProperty> , RC_NiVertexColorProperty ));
|
||||
newFactory.insert(makeEntry("NiShadeProperty", &construct <NiShadeProperty> , RC_NiShadeProperty ));
|
||||
newFactory.insert(makeEntry("NiDitherProperty", &construct <NiDitherProperty> , RC_NiDitherProperty ));
|
||||
newFactory.insert(makeEntry("NiWireframeProperty", &construct <NiWireframeProperty> , RC_NiWireframeProperty ));
|
||||
newFactory.insert(makeEntry("NiSpecularProperty", &construct <NiSpecularProperty> , RC_NiSpecularProperty ));
|
||||
newFactory.insert(makeEntry("NiStencilProperty", &construct <NiStencilProperty> , RC_NiStencilProperty ));
|
||||
newFactory.insert(makeEntry("NiVisController", &construct <NiVisController> , RC_NiVisController ));
|
||||
newFactory.insert(makeEntry("NiGeomMorpherController", &construct <NiGeomMorpherController> , RC_NiGeomMorpherController ));
|
||||
newFactory.insert(makeEntry("NiKeyframeController", &construct <NiKeyframeController> , RC_NiKeyframeController ));
|
||||
newFactory.insert(makeEntry("NiAlphaController", &construct <NiAlphaController> , RC_NiAlphaController ));
|
||||
newFactory.insert(makeEntry("NiUVController", &construct <NiUVController> , RC_NiUVController ));
|
||||
newFactory.insert(makeEntry("NiPathController", &construct <NiPathController> , RC_NiPathController ));
|
||||
newFactory.insert(makeEntry("NiMaterialColorController", &construct <NiMaterialColorController> , RC_NiMaterialColorController ));
|
||||
newFactory.insert(makeEntry("NiBSPArrayController", &construct <NiBSPArrayController> , RC_NiBSPArrayController ));
|
||||
newFactory.insert(makeEntry("NiParticleSystemController", &construct <NiParticleSystemController> , RC_NiParticleSystemController ));
|
||||
newFactory.insert(makeEntry("NiFlipController", &construct <NiFlipController> , RC_NiFlipController ));
|
||||
newFactory.insert(makeEntry("NiAmbientLight", &construct <NiLight> , RC_NiLight ));
|
||||
newFactory.insert(makeEntry("NiDirectionalLight", &construct <NiLight> , RC_NiLight ));
|
||||
newFactory.insert(makeEntry("NiTextureEffect", &construct <NiTextureEffect> , RC_NiTextureEffect ));
|
||||
newFactory.insert(makeEntry("NiVertWeightsExtraData", &construct <NiVertWeightsExtraData> , RC_NiVertWeightsExtraData ));
|
||||
newFactory.insert(makeEntry("NiTextKeyExtraData", &construct <NiTextKeyExtraData> , RC_NiTextKeyExtraData ));
|
||||
newFactory.insert(makeEntry("NiStringExtraData", &construct <NiStringExtraData> , RC_NiStringExtraData ));
|
||||
newFactory.insert(makeEntry("NiGravity", &construct <NiGravity> , RC_NiGravity ));
|
||||
newFactory.insert(makeEntry("NiPlanarCollider", &construct <NiPlanarCollider> , RC_NiPlanarCollider ));
|
||||
newFactory.insert(makeEntry("NiParticleGrowFade", &construct <NiParticleGrowFade> , RC_NiParticleGrowFade ));
|
||||
newFactory.insert(makeEntry("NiParticleColorModifier", &construct <NiParticleColorModifier> , RC_NiParticleColorModifier ));
|
||||
newFactory.insert(makeEntry("NiParticleRotation", &construct <NiParticleRotation> , RC_NiParticleRotation ));
|
||||
newFactory.insert(makeEntry("NiFloatData", &construct <NiFloatData> , RC_NiFloatData ));
|
||||
newFactory.insert(makeEntry("NiTriShapeData", &construct <NiTriShapeData> , RC_NiTriShapeData ));
|
||||
newFactory.insert(makeEntry("NiVisData", &construct <NiVisData> , RC_NiVisData ));
|
||||
newFactory.insert(makeEntry("NiColorData", &construct <NiColorData> , RC_NiColorData ));
|
||||
newFactory.insert(makeEntry("NiPixelData", &construct <NiPixelData> , RC_NiPixelData ));
|
||||
newFactory.insert(makeEntry("NiMorphData", &construct <NiMorphData> , RC_NiMorphData ));
|
||||
newFactory.insert(makeEntry("NiKeyframeData", &construct <NiKeyframeData> , RC_NiKeyframeData ));
|
||||
newFactory.insert(makeEntry("NiSkinData", &construct <NiSkinData> , RC_NiSkinData ));
|
||||
newFactory.insert(makeEntry("NiUVData", &construct <NiUVData> , RC_NiUVData ));
|
||||
newFactory.insert(makeEntry("NiPosData", &construct <NiPosData> , RC_NiPosData ));
|
||||
newFactory.insert(makeEntry("NiRotatingParticlesData", &construct <NiRotatingParticlesData> , RC_NiRotatingParticlesData ));
|
||||
newFactory.insert(makeEntry("NiAutoNormalParticlesData", &construct <NiAutoNormalParticlesData> , RC_NiAutoNormalParticlesData ));
|
||||
newFactory.insert(makeEntry("NiSequenceStreamHelper", &construct <NiSequenceStreamHelper> , RC_NiSequenceStreamHelper ));
|
||||
newFactory.insert(makeEntry("NiSourceTexture", &construct <NiSourceTexture> , RC_NiSourceTexture ));
|
||||
newFactory.insert(makeEntry("NiSkinInstance", &construct <NiSkinInstance> , RC_NiSkinInstance ));
|
||||
return newFactory;
|
||||
}
|
||||
|
||||
|
||||
///Make the factory map used for parsing the file
|
||||
static const std::map<std::string,RecordFactoryEntry> factories = makeFactory();
|
||||
|
||||
void NIFFile::parse()
|
||||
{
|
||||
|
@ -322,12 +144,13 @@ void NIFFile::parse()
|
|||
if(rec.empty())
|
||||
fail("Record number " + Ogre::StringConverter::toString(i) + " out of " + Ogre::StringConverter::toString(recNum) + " is blank.");
|
||||
|
||||
RecordFactoryEntry const * entry = lookupRecordFactory (rec.c_str ());
|
||||
|
||||
if (entry != NULL)
|
||||
std::map<std::string,RecordFactoryEntry>::const_iterator entry = factories.find(rec);
|
||||
|
||||
if (entry != factories.end())
|
||||
{
|
||||
r = entry->mCreate ();
|
||||
r->recType = entry->mType;
|
||||
r = entry->second.mCreate ();
|
||||
r->recType = entry->second.mType;
|
||||
}
|
||||
else
|
||||
fail("Unknown record type " + rec);
|
||||
|
@ -338,24 +161,24 @@ void NIFFile::parse()
|
|||
r->recIndex = i;
|
||||
records[i] = r;
|
||||
r->read(&nif);
|
||||
|
||||
// Discard tranformations for the root node, otherwise some meshes
|
||||
// occasionally get wrong orientation. Only for NiNode-s for now, but
|
||||
// can be expanded if needed.
|
||||
// This should be rewritten when the method is cleaned up.
|
||||
if (0 == i && rec == "NiNode")
|
||||
{
|
||||
static_cast<Nif::Node*>(r)->trafo = Nif::Transformation::getIdentity();
|
||||
}
|
||||
}
|
||||
|
||||
size_t rootNum = nif.getUInt();
|
||||
roots.resize(rootNum);
|
||||
|
||||
//Determine which records are roots
|
||||
for(size_t i = 0;i < rootNum;i++)
|
||||
{
|
||||
intptr_t idx = nif.getInt();
|
||||
roots[i] = ((idx >= 0) ? records.at(idx) : NULL);
|
||||
int idx = nif.getInt();
|
||||
if (idx >= 0)
|
||||
{
|
||||
roots[i] = records.at(idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
roots[i] = NULL;
|
||||
warn("Null Root found");
|
||||
}
|
||||
}
|
||||
|
||||
// Once parsing is done, do post-processing.
|
||||
|
@ -363,81 +186,4 @@ void NIFFile::parse()
|
|||
records[i]->post(this);
|
||||
}
|
||||
|
||||
/// \todo move to the write cpp file
|
||||
|
||||
void NiSkinInstance::post(NIFFile *nif)
|
||||
{
|
||||
data.post(nif);
|
||||
root.post(nif);
|
||||
bones.post(nif);
|
||||
|
||||
if(data.empty() || root.empty())
|
||||
nif->fail("NiSkinInstance missing root or data");
|
||||
|
||||
size_t bnum = bones.length();
|
||||
if(bnum != data->bones.size())
|
||||
nif->fail("Mismatch in NiSkinData bone count");
|
||||
|
||||
root->makeRootBone(&data->trafo);
|
||||
|
||||
for(size_t i=0; i<bnum; i++)
|
||||
{
|
||||
if(bones[i].empty())
|
||||
nif->fail("Oops: Missing bone! Don't know how to handle this.");
|
||||
bones[i]->makeBone(i, data->bones[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Node::getProperties(const Nif::NiTexturingProperty *&texprop,
|
||||
const Nif::NiMaterialProperty *&matprop,
|
||||
const Nif::NiAlphaProperty *&alphaprop,
|
||||
const Nif::NiVertexColorProperty *&vertprop,
|
||||
const Nif::NiZBufferProperty *&zprop,
|
||||
const Nif::NiSpecularProperty *&specprop,
|
||||
const Nif::NiWireframeProperty *&wireprop) const
|
||||
{
|
||||
if(parent)
|
||||
parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop);
|
||||
|
||||
for(size_t i = 0;i < props.length();i++)
|
||||
{
|
||||
// Entries may be empty
|
||||
if(props[i].empty())
|
||||
continue;
|
||||
|
||||
const Nif::Property *pr = props[i].getPtr();
|
||||
if(pr->recType == Nif::RC_NiTexturingProperty)
|
||||
texprop = static_cast<const Nif::NiTexturingProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiMaterialProperty)
|
||||
matprop = static_cast<const Nif::NiMaterialProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiAlphaProperty)
|
||||
alphaprop = static_cast<const Nif::NiAlphaProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiVertexColorProperty)
|
||||
vertprop = static_cast<const Nif::NiVertexColorProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiZBufferProperty)
|
||||
zprop = static_cast<const Nif::NiZBufferProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiSpecularProperty)
|
||||
specprop = static_cast<const Nif::NiSpecularProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiWireframeProperty)
|
||||
wireprop = static_cast<const Nif::NiWireframeProperty*>(pr);
|
||||
else
|
||||
std::cerr<< "Unhandled property type: "<<pr->recName <<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Ogre::Matrix4 Node::getLocalTransform() const
|
||||
{
|
||||
Ogre::Matrix4 mat4 = Ogre::Matrix4(Ogre::Matrix4::IDENTITY);
|
||||
mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation));
|
||||
return mat4;
|
||||
}
|
||||
|
||||
Ogre::Matrix4 Node::getWorldTransform() const
|
||||
{
|
||||
if(parent != NULL)
|
||||
return parent->getWorldTransform() * getLocalTransform();
|
||||
return getLocalTransform();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,53 +1,13 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008-2010 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.sourceforge.net/
|
||||
|
||||
This file (nif_file.h) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
///Main header for reading .nif files
|
||||
|
||||
#ifndef OPENMW_COMPONENTS_NIF_NIFFILE_HPP
|
||||
#define OPENMW_COMPONENTS_NIF_NIFFILE_HPP
|
||||
|
||||
#include <OgreResourceGroupManager.h>
|
||||
#include <OgreDataStream.h>
|
||||
#include <OgreVector2.h>
|
||||
#include <OgreVector3.h>
|
||||
#include <OgreVector4.h>
|
||||
#include <OgreMatrix3.h>
|
||||
#include <OgreQuaternion.h>
|
||||
#include <OgreStringConverter.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <boost/weak_ptr.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/detail/endian.hpp>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "record.hpp"
|
||||
#include "niftypes.hpp"
|
||||
#include "nifstream.hpp"
|
||||
|
||||
namespace Nif
|
||||
{
|
||||
|
@ -61,62 +21,46 @@ class NIFFile
|
|||
/// Nif file version
|
||||
int ver;
|
||||
|
||||
/// File name, used for error messages
|
||||
/// File name, used for error messages and opening the file
|
||||
std::string filename;
|
||||
|
||||
/// Record list
|
||||
std::vector<Record*> records;
|
||||
|
||||
/// Root list
|
||||
/// Root list. This is a select portion of the pointers from records
|
||||
std::vector<Record*> roots;
|
||||
|
||||
/// Parse the file
|
||||
void parse();
|
||||
|
||||
class LoadedCache;
|
||||
friend class LoadedCache;
|
||||
|
||||
// attempt to protect NIFFile from misuse...
|
||||
struct psudo_private_modifier {}; // this dirty little trick should optimize out
|
||||
///Private Copy Constructor
|
||||
NIFFile (NIFFile const &);
|
||||
///\overload
|
||||
void operator = (NIFFile const &);
|
||||
|
||||
public:
|
||||
/// Used for error handling
|
||||
/// Used if file parsing fails
|
||||
void fail(const std::string &msg)
|
||||
{
|
||||
std::string err = "NIFFile Error: " + msg;
|
||||
err += "\nFile: " + filename;
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
/// Used when something goes wrong, but not catastrophically so
|
||||
void warn(const std::string &msg)
|
||||
{
|
||||
std::cerr << "NIFFile Warning: " << msg <<std::endl
|
||||
<< "File: " << filename <<std::endl;
|
||||
}
|
||||
|
||||
typedef boost::shared_ptr <NIFFile> ptr;
|
||||
|
||||
/// Open a NIF stream. The name is used for error messages.
|
||||
NIFFile(const std::string &name, psudo_private_modifier);
|
||||
/// Open a NIF stream. The name is used for error messages and opening the file.
|
||||
NIFFile(const std::string &name);
|
||||
~NIFFile();
|
||||
|
||||
static ptr create (const std::string &name);
|
||||
static void lockCache ();
|
||||
static void unlockCache ();
|
||||
|
||||
struct CacheLock
|
||||
{
|
||||
CacheLock () { lockCache (); }
|
||||
~CacheLock () { unlockCache (); }
|
||||
};
|
||||
|
||||
/// Get a given record
|
||||
Record *getRecord(size_t index) const
|
||||
{
|
||||
Record *res = records.at(index);
|
||||
assert(res != NULL);
|
||||
return res;
|
||||
}
|
||||
/// Number of records
|
||||
|
@ -126,7 +70,6 @@ public:
|
|||
Record *getRoot(size_t index=0) const
|
||||
{
|
||||
Record *res = roots.at(index);
|
||||
assert(res != NULL);
|
||||
return res;
|
||||
}
|
||||
/// Number of roots
|
||||
|
@ -134,131 +77,6 @@ public:
|
|||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct KeyT {
|
||||
float mTime;
|
||||
T mValue;
|
||||
T mForwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList
|
||||
T mBackwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList
|
||||
float mTension; // Only for TBC interpolation
|
||||
float mBias; // Only for TBC interpolation
|
||||
float mContinuity; // Only for TBC interpolation
|
||||
};
|
||||
typedef KeyT<float> FloatKey;
|
||||
typedef KeyT<Ogre::Vector3> Vector3Key;
|
||||
typedef KeyT<Ogre::Vector4> Vector4Key;
|
||||
typedef KeyT<Ogre::Quaternion> QuaternionKey;
|
||||
|
||||
template<typename T, T (NIFStream::*getValue)()>
|
||||
struct KeyListT {
|
||||
typedef std::vector< KeyT<T> > VecType;
|
||||
|
||||
static const unsigned int sLinearInterpolation = 1;
|
||||
static const unsigned int sQuadraticInterpolation = 2;
|
||||
static const unsigned int sTBCInterpolation = 3;
|
||||
static const unsigned int sXYZInterpolation = 4;
|
||||
|
||||
unsigned int mInterpolationType;
|
||||
VecType mKeys;
|
||||
|
||||
KeyListT() : mInterpolationType(sLinearInterpolation) {}
|
||||
|
||||
//Read in a KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html)
|
||||
void read(NIFStream *nif, bool force=false)
|
||||
{
|
||||
assert(nif);
|
||||
|
||||
mInterpolationType = 0;
|
||||
|
||||
size_t count = nif->getUInt();
|
||||
if(count == 0 && !force)
|
||||
return;
|
||||
|
||||
//If we aren't forcing things, make sure that read clears any previous keys
|
||||
if(!force)
|
||||
mKeys.clear();
|
||||
|
||||
mInterpolationType = nif->getUInt();
|
||||
|
||||
KeyT<T> key;
|
||||
NIFStream &nifReference = *nif;
|
||||
|
||||
if(mInterpolationType == sLinearInterpolation)
|
||||
{
|
||||
for(size_t i = 0;i < count;i++)
|
||||
{
|
||||
readTimeAndValue(nifReference, key);
|
||||
mKeys.push_back(key);
|
||||
}
|
||||
}
|
||||
else if(mInterpolationType == sQuadraticInterpolation)
|
||||
{
|
||||
for(size_t i = 0;i < count;i++)
|
||||
{
|
||||
readQuadratic(nifReference, key);
|
||||
mKeys.push_back(key);
|
||||
}
|
||||
}
|
||||
else if(mInterpolationType == sTBCInterpolation)
|
||||
{
|
||||
for(size_t i = 0;i < count;i++)
|
||||
{
|
||||
readTBC(nifReference, key);
|
||||
mKeys.push_back(key);
|
||||
}
|
||||
}
|
||||
//XYZ keys aren't actually read here.
|
||||
//data.hpp sees that the last type read was sXYZInterpolation and:
|
||||
// Eats a floating point number, then
|
||||
// Re-runs the read function 3 more times, with force enabled so that the previous values aren't cleared.
|
||||
// When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation.
|
||||
else if(mInterpolationType == sXYZInterpolation)
|
||||
{
|
||||
//Don't try to read XYZ keys into the wrong part
|
||||
if ( count != 1 )
|
||||
nif->file->fail("XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: "+Ogre::StringConverter::toString(count));
|
||||
}
|
||||
else if (0 == mInterpolationType)
|
||||
{
|
||||
if (count != 0)
|
||||
nif->file->fail("Interpolation type 0 doesn't work with keys");
|
||||
}
|
||||
else
|
||||
nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType));
|
||||
}
|
||||
|
||||
private:
|
||||
static void readTimeAndValue(NIFStream &nif, KeyT<T> &key)
|
||||
{
|
||||
key.mTime = nif.getFloat();
|
||||
key.mValue = (nif.*getValue)();
|
||||
}
|
||||
|
||||
static void readQuadratic(NIFStream &nif, KeyT<Ogre::Quaternion> &key)
|
||||
{
|
||||
readTimeAndValue(nif, key);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static void readQuadratic(NIFStream &nif, KeyT<U> &key)
|
||||
{
|
||||
readTimeAndValue(nif, key);
|
||||
key.mForwardValue = (nif.*getValue)();
|
||||
key.mBackwardValue = (nif.*getValue)();
|
||||
}
|
||||
|
||||
static void readTBC(NIFStream &nif, KeyT<T> &key)
|
||||
{
|
||||
readTimeAndValue(nif, key);
|
||||
key.mTension = nif.getFloat();
|
||||
key.mBias = nif.getFloat();
|
||||
key.mContinuity = nif.getFloat();
|
||||
}
|
||||
};
|
||||
typedef KeyListT<float,&NIFStream::getFloat> FloatKeyList;
|
||||
typedef KeyListT<Ogre::Vector3,&NIFStream::getVector3> Vector3KeyList;
|
||||
typedef KeyListT<Ogre::Vector4,&NIFStream::getVector4> Vector4KeyList;
|
||||
typedef KeyListT<Ogre::Quaternion,&NIFStream::getQuaternion> QuaternionKeyList;
|
||||
|
||||
} // Namespace
|
||||
#endif
|
||||
|
|
140
components/nif/nifkey.hpp
Normal file
140
components/nif/nifkey.hpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
///File to handle keys used by nif file records
|
||||
|
||||
#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP
|
||||
#define OPENMW_COMPONENTS_NIF_NIFKEY_HPP
|
||||
|
||||
#include <OgreStringConverter.h>
|
||||
|
||||
#include "nifstream.hpp"
|
||||
|
||||
namespace Nif
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct KeyT {
|
||||
float mTime;
|
||||
T mValue;
|
||||
T mForwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList
|
||||
T mBackwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList
|
||||
float mTension; // Only for TBC interpolation
|
||||
float mBias; // Only for TBC interpolation
|
||||
float mContinuity; // Only for TBC interpolation
|
||||
};
|
||||
typedef KeyT<float> FloatKey;
|
||||
typedef KeyT<Ogre::Vector3> Vector3Key;
|
||||
typedef KeyT<Ogre::Vector4> Vector4Key;
|
||||
typedef KeyT<Ogre::Quaternion> QuaternionKey;
|
||||
|
||||
template<typename T, T (NIFStream::*getValue)()>
|
||||
struct KeyListT {
|
||||
typedef std::vector< KeyT<T> > VecType;
|
||||
|
||||
static const unsigned int sLinearInterpolation = 1;
|
||||
static const unsigned int sQuadraticInterpolation = 2;
|
||||
static const unsigned int sTBCInterpolation = 3;
|
||||
static const unsigned int sXYZInterpolation = 4;
|
||||
|
||||
unsigned int mInterpolationType;
|
||||
VecType mKeys;
|
||||
|
||||
KeyListT() : mInterpolationType(sLinearInterpolation) {}
|
||||
|
||||
//Read in a KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html)
|
||||
void read(NIFStream *nif, bool force=false)
|
||||
{
|
||||
assert(nif);
|
||||
|
||||
mInterpolationType = 0;
|
||||
|
||||
size_t count = nif->getUInt();
|
||||
if(count == 0 && !force)
|
||||
return;
|
||||
|
||||
//If we aren't forcing things, make sure that read clears any previous keys
|
||||
if(!force)
|
||||
mKeys.clear();
|
||||
|
||||
mInterpolationType = nif->getUInt();
|
||||
|
||||
KeyT<T> key;
|
||||
NIFStream &nifReference = *nif;
|
||||
|
||||
if(mInterpolationType == sLinearInterpolation)
|
||||
{
|
||||
for(size_t i = 0;i < count;i++)
|
||||
{
|
||||
readTimeAndValue(nifReference, key);
|
||||
mKeys.push_back(key);
|
||||
}
|
||||
}
|
||||
else if(mInterpolationType == sQuadraticInterpolation)
|
||||
{
|
||||
for(size_t i = 0;i < count;i++)
|
||||
{
|
||||
readQuadratic(nifReference, key);
|
||||
mKeys.push_back(key);
|
||||
}
|
||||
}
|
||||
else if(mInterpolationType == sTBCInterpolation)
|
||||
{
|
||||
for(size_t i = 0;i < count;i++)
|
||||
{
|
||||
readTBC(nifReference, key);
|
||||
mKeys.push_back(key);
|
||||
}
|
||||
}
|
||||
//XYZ keys aren't actually read here.
|
||||
//data.hpp sees that the last type read was sXYZInterpolation and:
|
||||
// Eats a floating point number, then
|
||||
// Re-runs the read function 3 more times, with force enabled so that the previous values aren't cleared.
|
||||
// When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation.
|
||||
else if(mInterpolationType == sXYZInterpolation)
|
||||
{
|
||||
//Don't try to read XYZ keys into the wrong part
|
||||
if ( count != 1 )
|
||||
nif->file->fail("XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: "+Ogre::StringConverter::toString(count));
|
||||
}
|
||||
else if (0 == mInterpolationType)
|
||||
{
|
||||
if (count != 0)
|
||||
nif->file->fail("Interpolation type 0 doesn't work with keys");
|
||||
}
|
||||
else
|
||||
nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType));
|
||||
}
|
||||
|
||||
private:
|
||||
static void readTimeAndValue(NIFStream &nif, KeyT<T> &key)
|
||||
{
|
||||
key.mTime = nif.getFloat();
|
||||
key.mValue = (nif.*getValue)();
|
||||
}
|
||||
|
||||
static void readQuadratic(NIFStream &nif, KeyT<Ogre::Quaternion> &key)
|
||||
{
|
||||
readTimeAndValue(nif, key);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static void readQuadratic(NIFStream &nif, KeyT<U> &key)
|
||||
{
|
||||
readTimeAndValue(nif, key);
|
||||
key.mForwardValue = (nif.*getValue)();
|
||||
key.mBackwardValue = (nif.*getValue)();
|
||||
}
|
||||
|
||||
static void readTBC(NIFStream &nif, KeyT<T> &key)
|
||||
{
|
||||
readTimeAndValue(nif, key);
|
||||
key.mTension = nif.getFloat();
|
||||
key.mBias = nif.getFloat();
|
||||
key.mContinuity = nif.getFloat();
|
||||
}
|
||||
};
|
||||
typedef KeyListT<float,&NIFStream::getFloat> FloatKeyList;
|
||||
typedef KeyListT<Ogre::Vector3,&NIFStream::getVector3> Vector3KeyList;
|
||||
typedef KeyListT<Ogre::Vector4,&NIFStream::getVector4> Vector4KeyList;
|
||||
typedef KeyListT<Ogre::Quaternion,&NIFStream::getQuaternion> QuaternionKeyList;
|
||||
|
||||
} // Namespace
|
||||
#endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP
|
|
@ -1,6 +1,20 @@
|
|||
///Functions used to read raw binary data from .nif files
|
||||
|
||||
#ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP
|
||||
#define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <OgreDataStream.h>
|
||||
#include <OgreVector2.h>
|
||||
#include <OgreVector3.h>
|
||||
#include <OgreVector4.h>
|
||||
#include <OgreMatrix3.h>
|
||||
#include <OgreQuaternion.h>
|
||||
|
||||
#include "niftypes.hpp"
|
||||
|
||||
namespace Nif
|
||||
{
|
||||
|
||||
|
|
57
components/nif/node.cpp
Normal file
57
components/nif/node.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "node.hpp"
|
||||
|
||||
namespace Nif
|
||||
{
|
||||
|
||||
void Node::getProperties(const Nif::NiTexturingProperty *&texprop,
|
||||
const Nif::NiMaterialProperty *&matprop,
|
||||
const Nif::NiAlphaProperty *&alphaprop,
|
||||
const Nif::NiVertexColorProperty *&vertprop,
|
||||
const Nif::NiZBufferProperty *&zprop,
|
||||
const Nif::NiSpecularProperty *&specprop,
|
||||
const Nif::NiWireframeProperty *&wireprop) const
|
||||
{
|
||||
if(parent)
|
||||
parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop);
|
||||
|
||||
for(size_t i = 0;i < props.length();i++)
|
||||
{
|
||||
// Entries may be empty
|
||||
if(props[i].empty())
|
||||
continue;
|
||||
|
||||
const Nif::Property *pr = props[i].getPtr();
|
||||
if(pr->recType == Nif::RC_NiTexturingProperty)
|
||||
texprop = static_cast<const Nif::NiTexturingProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiMaterialProperty)
|
||||
matprop = static_cast<const Nif::NiMaterialProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiAlphaProperty)
|
||||
alphaprop = static_cast<const Nif::NiAlphaProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiVertexColorProperty)
|
||||
vertprop = static_cast<const Nif::NiVertexColorProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiZBufferProperty)
|
||||
zprop = static_cast<const Nif::NiZBufferProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiSpecularProperty)
|
||||
specprop = static_cast<const Nif::NiSpecularProperty*>(pr);
|
||||
else if(pr->recType == Nif::RC_NiWireframeProperty)
|
||||
wireprop = static_cast<const Nif::NiWireframeProperty*>(pr);
|
||||
else
|
||||
std::cerr<< "Unhandled property type: "<<pr->recName <<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Ogre::Matrix4 Node::getLocalTransform() const
|
||||
{
|
||||
Ogre::Matrix4 mat4 = Ogre::Matrix4(Ogre::Matrix4::IDENTITY);
|
||||
mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation));
|
||||
return mat4;
|
||||
}
|
||||
|
||||
Ogre::Matrix4 Node::getWorldTransform() const
|
||||
{
|
||||
if(parent != NULL)
|
||||
return parent->getWorldTransform() * getLocalTransform();
|
||||
return getLocalTransform();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,26 +1,3 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008-2010 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.sourceforge.net/
|
||||
|
||||
This file (node.h) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENMW_COMPONENTS_NIF_NODE_HPP
|
||||
#define OPENMW_COMPONENTS_NIF_NODE_HPP
|
||||
|
||||
|
@ -29,6 +6,7 @@
|
|||
#include "controlled.hpp"
|
||||
#include "data.hpp"
|
||||
#include "property.hpp"
|
||||
#include "niftypes.hpp"
|
||||
|
||||
namespace Nif
|
||||
{
|
||||
|
@ -149,6 +127,14 @@ struct NiNode : Node
|
|||
Node::read(nif);
|
||||
children.read(nif);
|
||||
effects.read(nif);
|
||||
|
||||
// Discard tranformations for the root node, otherwise some meshes
|
||||
// occasionally get wrong orientation. Only for NiNode-s for now, but
|
||||
// can be expanded if needed.
|
||||
if (0 == recIndex)
|
||||
{
|
||||
static_cast<Nif::Node*>(this)->trafo = Nif::Transformation::getIdentity();
|
||||
}
|
||||
}
|
||||
|
||||
void post(NIFFile *nif)
|
||||
|
|
|
@ -1,30 +1,8 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008-2010 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.sourceforge.net/
|
||||
|
||||
This file (record_ptr.h) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPENMW_COMPONENTS_NIF_RECORDPTR_HPP
|
||||
#define OPENMW_COMPONENTS_NIF_RECORDPTR_HPP
|
||||
|
||||
#include "niffile.hpp"
|
||||
#include "nifstream.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace Nif
|
||||
|
|
6
components/nif/tests/.gitignore
vendored
6
components/nif/tests/.gitignore
vendored
|
@ -1,5 +1 @@
|
|||
niftool
|
||||
*_test
|
||||
*.nif
|
||||
*.kf
|
||||
output.txt
|
||||
*.log
|
||||
|
|
19
components/nif/tests/CMakeLists.txt
Normal file
19
components/nif/tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
set(NIFTEST
|
||||
niftest.cpp
|
||||
)
|
||||
source_group(components\\nif\\tests FILES ${NIFTEST})
|
||||
|
||||
# Main executable
|
||||
add_executable(niftest
|
||||
${NIFTEST}
|
||||
)
|
||||
|
||||
target_link_libraries(niftest
|
||||
${Boost_LIBRARIES}
|
||||
components
|
||||
)
|
||||
|
||||
if (BUILD_WITH_CODE_COVERAGE)
|
||||
add_definitions (--coverage)
|
||||
target_link_libraries(niftest gcov)
|
||||
endif()
|
|
@ -1,12 +0,0 @@
|
|||
GCC=g++
|
||||
|
||||
all: niftool nif_bsa_test
|
||||
|
||||
niftool: niftool.cpp ../nif_file.hpp ../nif_file.cpp ../record.hpp
|
||||
$(GCC) $< ../nif_file.cpp ../../tools/stringops.cpp -o $@
|
||||
|
||||
nif_bsa_test: nif_bsa_test.cpp ../nif_file.cpp ../../bsa/bsa_file.cpp ../../tools/stringops.cpp
|
||||
$(GCC) $^ -o $@
|
||||
|
||||
clean:
|
||||
rm niftool *_test
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
Runs NIFFile through all the NIFs in Morrowind.bsa.
|
||||
*/
|
||||
|
||||
#include "../nif_file.hpp"
|
||||
#include "../../bsa/bsa_file.hpp"
|
||||
#include "../../tools/stringops.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace Mangle::Stream;
|
||||
using namespace std;
|
||||
using namespace Nif;
|
||||
|
||||
int main(int argc, char **args)
|
||||
{
|
||||
BSAFile bsa;
|
||||
cout << "Reading Morrowind.bsa\n";
|
||||
bsa.open("../../data/Morrowind.bsa");
|
||||
|
||||
const BSAFile::FileList &files = bsa.getList();
|
||||
|
||||
for(int i=0; i<files.size(); i++)
|
||||
{
|
||||
const char *n = files[i].name;
|
||||
if(!ends(n, ".nif")) continue;
|
||||
|
||||
cout << "Decoding " << n << endl;
|
||||
NIFFile nif(bsa.getFile(n), n);
|
||||
}
|
||||
}
|
96
components/nif/tests/niftest.cpp
Normal file
96
components/nif/tests/niftest.cpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
///Program to test .nif files both on the FileSystem and in BSA archives.
|
||||
|
||||
#include "../niffile.hpp"
|
||||
#include "../../bsa/bsa_file.hpp"
|
||||
#include "../../bsa/bsa_archive.hpp"
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreResourceGroupManager.h>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
|
||||
///See if the file has the named extension
|
||||
bool hasExtension(std::string filename, std::string extensionToFind)
|
||||
{
|
||||
std::string extension = filename.substr(filename.find_last_of(".")+1);
|
||||
|
||||
//Convert strings to lower case for comparison
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
std::transform(extensionToFind.begin(), extensionToFind.end(), extensionToFind.begin(), ::tolower);
|
||||
|
||||
if(extension == extensionToFind)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
///See if the file has the "nif" extension.
|
||||
bool isNIF(std::string filename)
|
||||
{
|
||||
return hasExtension(filename,"nif");
|
||||
}
|
||||
///See if the file has the "bsa" extension.
|
||||
bool isBSA(std::string filename)
|
||||
{
|
||||
return hasExtension(filename,"bsa");
|
||||
}
|
||||
|
||||
///Check all the nif files in the given BSA archive
|
||||
void readBSA(std::string filename)
|
||||
{
|
||||
Bsa::BSAFile bsa;
|
||||
bsa.open(filename.c_str());
|
||||
|
||||
const Bsa::BSAFile::FileList &files = bsa.getList();
|
||||
Bsa::addBSA(filename,"Bsa Files");
|
||||
|
||||
for(unsigned int i=0; i<files.size(); i++)
|
||||
{
|
||||
std::string name = files[i].name;
|
||||
if(isNIF(name))
|
||||
{
|
||||
//std::cout << "Decoding " << name << std::endl;
|
||||
Nif::NIFFile temp_nif(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
//Need this for Ogre's getSingleton
|
||||
new Ogre::Root("", "", "niftest.log");
|
||||
Ogre::ResourceGroupManager::getSingleton ().createResourceGroup ("Bsa Files");
|
||||
//Needed to read files from file system
|
||||
Ogre::ResourceGroupManager::getSingleton().addResourceLocation("/", "FileSystem");
|
||||
// Initialize the resource groups:
|
||||
Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
|
||||
|
||||
std::cout << "Reading Files" << std::endl;
|
||||
for(int i = 1; i<argc;i++)
|
||||
{
|
||||
std::string name = argv[i];
|
||||
|
||||
try{
|
||||
if(isNIF(name))
|
||||
{
|
||||
//std::cout << "Decoding " << name << std::endl;
|
||||
Nif::NIFFile temp_nif(name);
|
||||
}
|
||||
else if(isBSA(name))
|
||||
{
|
||||
std::cout << "Reading " << name << std::endl;
|
||||
readBSA(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: \"" << name << "\" is not a nif or bsa file!" << std::endl;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR, an exception has occured" << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,18 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
make || exit
|
||||
#Script to test all nif files (both loose, and in BSA archives) in data files directory
|
||||
|
||||
mkdir -p output
|
||||
DATAFILESDIR="$1"
|
||||
|
||||
PROGS=*_test
|
||||
find "$DATAFILESDIR" -iname *bsa > nifs.txt
|
||||
find "$DATAFILESDIR" -iname *nif >> nifs.txt
|
||||
|
||||
for a in $PROGS; do
|
||||
if [ -f "output/$a.out" ]; then
|
||||
echo "Running $a:"
|
||||
./$a | diff output/$a.out -
|
||||
else
|
||||
echo "Creating $a.out"
|
||||
./$a > "output/$a.out"
|
||||
git add "output/$a.out"
|
||||
fi
|
||||
done
|
||||
sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt
|
||||
|
||||
xargs --arg-file=quoted_nifs.txt ../../../niftest
|
||||
|
||||
rm nifs.txt
|
||||
rm quoted_nifs.txt
|
||||
|
|
|
@ -28,6 +28,8 @@ http://www.gnu.org/licenses/ .
|
|||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/nifcache/nifcache.hpp>
|
||||
|
||||
#include "../nif/niffile.hpp"
|
||||
#include "../nif/node.hpp"
|
||||
#include "../nif/data.hpp"
|
||||
|
@ -74,7 +76,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
|||
// of the early stages of development. Right now we WANT to catch
|
||||
// every error as early and intrusively as possible, as it's most
|
||||
// likely a sign of incomplete code rather than faulty input.
|
||||
Nif::NIFFile::ptr pnif (Nif::NIFFile::create (mResourceName.substr(0, mResourceName.length()-7)));
|
||||
Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7)));
|
||||
Nif::NIFFile & nif = *pnif.get ();
|
||||
if (nif.numRoots() < 1)
|
||||
{
|
||||
|
@ -388,7 +390,7 @@ bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::V
|
|||
|
||||
bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation)
|
||||
{
|
||||
Nif::NIFFile::ptr pnif (Nif::NIFFile::create (nifFile));
|
||||
Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(nifFile));
|
||||
Nif::NIFFile & nif = *pnif.get ();
|
||||
|
||||
if (nif.numRoots() < 1)
|
||||
|
|
40
components/nifcache/nifcache.cpp
Normal file
40
components/nifcache/nifcache.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "nifcache.hpp"
|
||||
|
||||
namespace Nif
|
||||
{
|
||||
|
||||
Cache* Cache::sThis = 0;
|
||||
|
||||
Cache& Cache::getInstance()
|
||||
{
|
||||
assert (sThis);
|
||||
return *sThis;
|
||||
}
|
||||
|
||||
Cache* Cache::getInstancePtr()
|
||||
{
|
||||
return sThis;
|
||||
}
|
||||
|
||||
Cache::Cache()
|
||||
{
|
||||
assert (!sThis);
|
||||
sThis = this;
|
||||
}
|
||||
|
||||
NIFFilePtr Cache::load(const std::string &filename)
|
||||
{
|
||||
// TODO: normalize file path to make sure we're not loading the same file twice
|
||||
|
||||
LoadedMap::iterator it = mLoadedMap.find(filename);
|
||||
if (it != mLoadedMap.end())
|
||||
return it->second;
|
||||
else
|
||||
{
|
||||
NIFFilePtr file(new Nif::NIFFile(filename));
|
||||
mLoadedMap[filename] = file;
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
50
components/nifcache/nifcache.hpp
Normal file
50
components/nifcache/nifcache.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef OPENMW_COMPONENTS_NIFCACHE_H
|
||||
#define OPENMW_COMPONENTS_NIFCACHE_H
|
||||
|
||||
#include <components/nif/niffile.hpp>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace Nif
|
||||
{
|
||||
|
||||
typedef boost::shared_ptr<Nif::NIFFile> NIFFilePtr;
|
||||
|
||||
/// @brief A basic resource manager for NIF files
|
||||
class Cache
|
||||
{
|
||||
public:
|
||||
Cache();
|
||||
|
||||
/// Queue this file for background loading. A worker thread will start loading the file.
|
||||
/// To get the loaded NIFFilePtr, use the load method, which will wait until the worker thread is finished
|
||||
/// and then return the loaded file.
|
||||
//void loadInBackground (const std::string& file);
|
||||
|
||||
/// Read and parse the given file. May retrieve from cache if this file has been used previously.
|
||||
/// @note If the file is currently loading in the background, this function will block until
|
||||
/// the background loading finishes, then return the background loaded file.
|
||||
/// @note Returns a SharedPtr to the file and the file will stay loaded as long as the user holds on to this pointer.
|
||||
/// When all external SharedPtrs to a file are released, the cache may decide to unload the file.
|
||||
NIFFilePtr load (const std::string& filename);
|
||||
|
||||
/// Return instance of this class.
|
||||
static Cache& getInstance();
|
||||
static Cache* getInstancePtr();
|
||||
|
||||
private:
|
||||
static Cache* sThis;
|
||||
|
||||
Cache(const Cache&);
|
||||
Cache& operator =(const Cache&);
|
||||
|
||||
typedef std::map<std::string, NIFFilePtr> LoadedMap;
|
||||
|
||||
LoadedMap mLoadedMap;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -15,6 +15,7 @@
|
|||
#include <OgreKeyFrame.h>
|
||||
|
||||
#include <components/nif/node.hpp>
|
||||
#include <components/nifcache/nifcache.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "material.hpp"
|
||||
|
@ -383,7 +384,7 @@ void NIFMeshLoader::loadResource(Ogre::Resource *resource)
|
|||
Ogre::Mesh *mesh = dynamic_cast<Ogre::Mesh*>(resource);
|
||||
OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!");
|
||||
|
||||
Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName);
|
||||
Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(mName);
|
||||
if(mShapeIndex >= nif->numRecords())
|
||||
{
|
||||
Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr();
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <extern/shiny/Main/Factory.hpp>
|
||||
|
||||
#include <components/nif/node.hpp>
|
||||
#include <components/nifcache/nifcache.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
|
||||
|
@ -52,6 +53,24 @@
|
|||
#include "material.hpp"
|
||||
#include "mesh.hpp"
|
||||
#include "controller.hpp"
|
||||
#include "particles.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void getAllNiNodes(const Nif::Node* node, std::vector<const Nif::NiNode*>& out)
|
||||
{
|
||||
const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(node);
|
||||
if (ninode)
|
||||
{
|
||||
out.push_back(ninode);
|
||||
for (unsigned int i=0; i<ninode->children.length(); ++i)
|
||||
if (!ninode->children[i].empty())
|
||||
getAllNiNodes(ninode->children[i].getPtr(), out);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace NifOgre
|
||||
{
|
||||
|
@ -390,9 +409,10 @@ public:
|
|||
class Value : public NodeTargetValue<Ogre::Real>, public ValueInterpolator
|
||||
{
|
||||
private:
|
||||
Nif::QuaternionKeyList mRotations;
|
||||
Nif::Vector3KeyList mTranslations;
|
||||
Nif::FloatKeyList mScales;
|
||||
const Nif::QuaternionKeyList* mRotations;
|
||||
const Nif::Vector3KeyList* mTranslations;
|
||||
const Nif::FloatKeyList* mScales;
|
||||
Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid
|
||||
|
||||
using ValueInterpolator::interpKey;
|
||||
|
||||
|
@ -420,31 +440,33 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
Value(Ogre::Node *target, const Nif::NiKeyframeData *data)
|
||||
/// @note The NiKeyFrameData must be valid as long as this KeyframeController exists.
|
||||
Value(Ogre::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data)
|
||||
: NodeTargetValue<Ogre::Real>(target)
|
||||
, mRotations(data->mRotations)
|
||||
, mTranslations(data->mTranslations)
|
||||
, mScales(data->mScales)
|
||||
, mRotations(&data->mRotations)
|
||||
, mTranslations(&data->mTranslations)
|
||||
, mScales(&data->mScales)
|
||||
, mNif(nif)
|
||||
{ }
|
||||
|
||||
virtual Ogre::Quaternion getRotation(float time) const
|
||||
{
|
||||
if(mRotations.mKeys.size() > 0)
|
||||
return interpKey(mRotations.mKeys, time);
|
||||
if(mRotations->mKeys.size() > 0)
|
||||
return interpKey(mRotations->mKeys, time);
|
||||
return mNode->getOrientation();
|
||||
}
|
||||
|
||||
virtual Ogre::Vector3 getTranslation(float time) const
|
||||
{
|
||||
if(mTranslations.mKeys.size() > 0)
|
||||
return interpKey(mTranslations.mKeys, time);
|
||||
if(mTranslations->mKeys.size() > 0)
|
||||
return interpKey(mTranslations->mKeys, time);
|
||||
return mNode->getPosition();
|
||||
}
|
||||
|
||||
virtual Ogre::Vector3 getScale(float time) const
|
||||
{
|
||||
if(mScales.mKeys.size() > 0)
|
||||
return Ogre::Vector3(interpKey(mScales.mKeys, time));
|
||||
if(mScales->mKeys.size() > 0)
|
||||
return Ogre::Vector3(interpKey(mScales->mKeys, time));
|
||||
return mNode->getScale();
|
||||
}
|
||||
|
||||
|
@ -456,12 +478,12 @@ public:
|
|||
|
||||
virtual void setValue(Ogre::Real time)
|
||||
{
|
||||
if(mRotations.mKeys.size() > 0)
|
||||
mNode->setOrientation(interpKey(mRotations.mKeys, time));
|
||||
if(mTranslations.mKeys.size() > 0)
|
||||
mNode->setPosition(interpKey(mTranslations.mKeys, time));
|
||||
if(mScales.mKeys.size() > 0)
|
||||
mNode->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time)));
|
||||
if(mRotations->mKeys.size() > 0)
|
||||
mNode->setOrientation(interpKey(mRotations->mKeys, time));
|
||||
if(mTranslations->mKeys.size() > 0)
|
||||
mNode->setPosition(interpKey(mTranslations->mKeys, time));
|
||||
if(mScales->mKeys.size() > 0)
|
||||
mNode->setScale(Ogre::Vector3(interpKey(mScales->mKeys, time)));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -898,9 +920,28 @@ class NIFObjectLoader
|
|||
{
|
||||
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex);
|
||||
Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
|
||||
// Set the emitter bone as user data on the particle system
|
||||
// Set the emitter bone(s) as user data on the particle system
|
||||
// so the emitters/affectors can access it easily.
|
||||
partsys->getUserObjectBindings().setUserAny(Ogre::Any(trgtbone));
|
||||
std::vector<Ogre::Bone*> bones;
|
||||
if (partctrl->recType == Nif::RC_NiBSPArrayController)
|
||||
{
|
||||
std::vector<const Nif::NiNode*> nodes;
|
||||
getAllNiNodes(partctrl->emitter.getPtr(), nodes);
|
||||
if (nodes.empty())
|
||||
throw std::runtime_error("Emitter for NiBSPArrayController must be a NiNode");
|
||||
for (unsigned int i=0; i<nodes.size(); ++i)
|
||||
{
|
||||
bones.push_back(scene->mSkelBase->getSkeleton()->getBone(
|
||||
NIFSkeletonLoader::lookupOgreBoneHandle(name, nodes[i]->recIndex)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bones.push_back(trgtbone);
|
||||
}
|
||||
NiNodeHolder holder;
|
||||
holder.mBones = bones;
|
||||
partsys->getUserObjectBindings().setUserAny(Ogre::Any(holder));
|
||||
createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName());
|
||||
}
|
||||
|
||||
|
@ -916,8 +957,10 @@ class NIFObjectLoader
|
|||
|
||||
scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
|
||||
|
||||
if (partflags&Nif::NiNode::ParticleFlag_AutoPlay)
|
||||
partsys->fastForward(1, 0.1);
|
||||
// Emitting state will be overwritten on frame update by the ParticleSystemController,
|
||||
// but set up an initial value anyway so the user can fast-forward particle systems
|
||||
// immediately after creation if desired.
|
||||
partsys->setEmitting(partflags&Nif::NiNode::ParticleFlag_AutoPlay);
|
||||
}
|
||||
ctrl = ctrl->next;
|
||||
}
|
||||
|
@ -929,7 +972,7 @@ class NIFObjectLoader
|
|||
}
|
||||
|
||||
|
||||
static void createNodeControllers(const std::string &name, Nif::ControllerPtr ctrl, ObjectScenePtr scene, int animflags)
|
||||
static void createNodeControllers(const Nif::NIFFilePtr& nif, const std::string &name, Nif::ControllerPtr ctrl, ObjectScenePtr scene, int animflags)
|
||||
{
|
||||
do {
|
||||
if (ctrl->flags & Nif::NiNode::ControllerFlag_Active)
|
||||
|
@ -963,7 +1006,7 @@ class NIFObjectLoader
|
|||
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
|
||||
Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
|
||||
Ogre::ControllerValueRealPtr());
|
||||
Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr()));
|
||||
Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, nif, key->data.getPtr()));
|
||||
KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
|
||||
scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
|
||||
Ogre::ControllerFunctionRealPtr func(function);
|
||||
|
@ -1016,7 +1059,7 @@ class NIFObjectLoader
|
|||
}
|
||||
|
||||
|
||||
static void createObjects(const std::string &name, const std::string &group,
|
||||
static void createObjects(const Nif::NIFFilePtr& nif, const std::string &name, const std::string &group,
|
||||
Ogre::SceneNode *sceneNode, const Nif::Node *node,
|
||||
ObjectScenePtr scene, int flags, int animflags, int partflags)
|
||||
{
|
||||
|
@ -1073,7 +1116,7 @@ class NIFObjectLoader
|
|||
}
|
||||
|
||||
if(!node->controller.empty())
|
||||
createNodeControllers(name, node->controller, scene, animflags);
|
||||
createNodeControllers(nif, name, node->controller, scene, animflags);
|
||||
|
||||
if(node->recType == Nif::RC_NiCamera)
|
||||
{
|
||||
|
@ -1098,7 +1141,7 @@ class NIFObjectLoader
|
|||
for(size_t i = 0;i < children.length();i++)
|
||||
{
|
||||
if(!children[i].empty())
|
||||
createObjects(name, group, sceneNode, children[i].getPtr(), scene, flags, animflags, partflags);
|
||||
createObjects(nif, name, group, sceneNode, children[i].getPtr(), scene, flags, animflags, partflags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1121,7 +1164,7 @@ class NIFObjectLoader
|
|||
public:
|
||||
static void load(Ogre::SceneNode *sceneNode, ObjectScenePtr scene, const std::string &name, const std::string &group, int flags=0)
|
||||
{
|
||||
Nif::NIFFile::ptr nif = Nif::NIFFile::create(name);
|
||||
Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(name);
|
||||
if(nif->numRoots() < 1)
|
||||
{
|
||||
nif->warn("Found no root nodes in "+name+".");
|
||||
|
@ -1145,13 +1188,13 @@ public:
|
|||
// Create a base skeleton entity if this NIF needs one
|
||||
createSkelBase(name, group, sceneNode->getCreator(), node, scene);
|
||||
}
|
||||
createObjects(name, group, sceneNode, node, scene, flags, 0, 0);
|
||||
createObjects(nif, name, group, sceneNode, node, scene, flags, 0, 0);
|
||||
}
|
||||
|
||||
static void loadKf(Ogre::Skeleton *skel, const std::string &name,
|
||||
TextKeyMap &textKeys, std::vector<Ogre::Controller<Ogre::Real> > &ctrls)
|
||||
{
|
||||
Nif::NIFFile::ptr nif = Nif::NIFFile::create(name);
|
||||
Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(name);
|
||||
if(nif->numRoots() < 1)
|
||||
{
|
||||
nif->warn("Found no root nodes in "+name+".");
|
||||
|
@ -1202,7 +1245,7 @@ public:
|
|||
|
||||
Ogre::Bone *trgtbone = skel->getBone(strdata->string);
|
||||
Ogre::ControllerValueRealPtr srcval;
|
||||
Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr()));
|
||||
Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, nif, key->data.getPtr()));
|
||||
Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false));
|
||||
|
||||
ctrls.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
class NifEmitter : public Ogre::ParticleEmitter
|
||||
{
|
||||
public:
|
||||
Ogre::Bone* mEmitterBone;
|
||||
std::vector<Ogre::Bone*> mEmitterBones;
|
||||
Ogre::Bone* mParticleBone;
|
||||
|
||||
Ogre::ParticleSystem* getPartSys() { return mParent; }
|
||||
|
@ -131,7 +131,8 @@ public:
|
|||
NifEmitter(Ogre::ParticleSystem *psys)
|
||||
: Ogre::ParticleEmitter(psys)
|
||||
{
|
||||
mEmitterBone = Ogre::any_cast<Ogre::Bone*>(psys->getUserObjectBindings().getUserAny());
|
||||
mEmitterBones = Ogre::any_cast<NiNodeHolder>(psys->getUserObjectBindings().getUserAny()).mBones;
|
||||
assert (!mEmitterBones.empty());
|
||||
Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode());
|
||||
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());
|
||||
initDefaults("Nif");
|
||||
|
@ -170,8 +171,10 @@ public:
|
|||
Ogre::Real& timeToLive = particle->timeToLive;
|
||||
#endif
|
||||
|
||||
Ogre::Node* emitterBone = mEmitterBones.at((int)(::rand()/(RAND_MAX+1.0)*mEmitterBones.size()));
|
||||
|
||||
position = xOff + yOff + zOff +
|
||||
mParticleBone->_getDerivedOrientation().Inverse() * (mEmitterBone->_getDerivedPosition()
|
||||
mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition()
|
||||
- mParticleBone->_getDerivedPosition());
|
||||
|
||||
// Generate complex data by reference
|
||||
|
@ -181,7 +184,7 @@ public:
|
|||
Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom();
|
||||
Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom();
|
||||
direction = (mParticleBone->_getDerivedOrientation().Inverse()
|
||||
* mEmitterBone->_getDerivedOrientation() *
|
||||
* emitterBone->_getDerivedOrientation() *
|
||||
Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) *
|
||||
Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) *
|
||||
Ogre::Vector3::UNIT_Z;
|
||||
|
@ -635,7 +638,9 @@ public:
|
|||
, mPosition(0.0f)
|
||||
, mDirection(0.0f)
|
||||
{
|
||||
mEmitterBone = Ogre::any_cast<Ogre::Bone*>(psys->getUserObjectBindings().getUserAny());
|
||||
std::vector<Ogre::Bone*> bones = Ogre::any_cast<NiNodeHolder>(psys->getUserObjectBindings().getUserAny()).mBones;
|
||||
assert (!bones.empty());
|
||||
mEmitterBone = bones[0];
|
||||
Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode());
|
||||
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());
|
||||
|
||||
|
|
|
@ -38,4 +38,13 @@ class GravityAffectorFactory : public Ogre::ParticleAffectorFactory
|
|||
Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys);
|
||||
};
|
||||
|
||||
struct NiNodeHolder
|
||||
{
|
||||
std::vector<Ogre::Bone*> mBones;
|
||||
|
||||
// Ogre::Any needs this for some reason
|
||||
friend std::ostream& operator<<(std::ostream& o, const NiNodeHolder& r)
|
||||
{ return o; }
|
||||
};
|
||||
|
||||
#endif /* OENGINE_OGRE_PARTICLES_H */
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <OgreBone.h>
|
||||
|
||||
#include <components/nif/node.hpp>
|
||||
#include <components/nifcache/nifcache.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace NifOgre
|
||||
|
@ -83,7 +84,7 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource)
|
|||
Ogre::Skeleton *skel = dynamic_cast<Ogre::Skeleton*>(resource);
|
||||
OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!");
|
||||
|
||||
Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName()));
|
||||
Nif::NIFFilePtr nif(Nif::Cache::getInstance().load(skel->getName()));
|
||||
const Nif::Node *node = static_cast<const Nif::Node*>(nif->getRoot(0));
|
||||
|
||||
try {
|
||||
|
|
2373
docs/Doxyfile
2373
docs/Doxyfile
File diff suppressed because it is too large
Load diff
4
extern/sdl4ogre/sdlinputwrapper.hpp
vendored
4
extern/sdl4ogre/sdlinputwrapper.hpp
vendored
|
@ -24,7 +24,7 @@ namespace SFO
|
|||
void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; }
|
||||
void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; }
|
||||
void setWindowEventCallback(WindowListener* listen) { mWindowListener = listen; }
|
||||
void setJoyEventCallback(JoyListener* listen) { mJoyListener = listen; }
|
||||
void setJoyEventCallback(JoyListener* listen) { mJoyListener = listen; }
|
||||
|
||||
void capture(bool windowEventsOnly);
|
||||
bool isModifierHeld(SDL_Keymod mod);
|
||||
|
@ -54,7 +54,7 @@ namespace SFO
|
|||
SFO::MouseListener* mMouseListener;
|
||||
SFO::KeyListener* mKeyboardListener;
|
||||
SFO::WindowListener* mWindowListener;
|
||||
SFO::JoyListener* mJoyListener;
|
||||
SFO::JoyListener* mJoyListener;
|
||||
|
||||
typedef boost::unordered_map<SDL_Keycode, OIS::KeyCode> KeyMap;
|
||||
KeyMap mKeyMap;
|
||||
|
|
2
extern/shiny/Main/Factory.cpp
vendored
2
extern/shiny/Main/Factory.cpp
vendored
|
@ -803,7 +803,7 @@ namespace sh
|
|||
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
|
||||
{
|
||||
if (it->second.getMaterial()->isUnreferenced())
|
||||
it->second.destroyAll();
|
||||
it->second.getMaterial()->unreferenceTextures();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
1
extern/shiny/Main/Platform.hpp
vendored
1
extern/shiny/Main/Platform.hpp
vendored
|
@ -69,6 +69,7 @@ namespace sh
|
|||
virtual void removeAll () = 0; ///< remove all configurations
|
||||
|
||||
virtual bool isUnreferenced() = 0;
|
||||
virtual void unreferenceTextures() = 0;
|
||||
virtual void ensureLoaded() = 0;
|
||||
|
||||
virtual void setLodLevels (const std::string& lodLevels) = 0;
|
||||
|
|
5
extern/shiny/Platforms/Ogre/OgreMaterial.cpp
vendored
5
extern/shiny/Platforms/Ogre/OgreMaterial.cpp
vendored
|
@ -35,6 +35,11 @@ namespace sh
|
|||
return (!mMaterial.isNull() && mMaterial.useCount() <= Ogre::ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS+1);
|
||||
}
|
||||
|
||||
void OgreMaterial::unreferenceTextures()
|
||||
{
|
||||
mMaterial->unload();
|
||||
}
|
||||
|
||||
OgreMaterial::~OgreMaterial()
|
||||
{
|
||||
if (!mMaterial.isNull())
|
||||
|
|
1
extern/shiny/Platforms/Ogre/OgreMaterial.hpp
vendored
1
extern/shiny/Platforms/Ogre/OgreMaterial.hpp
vendored
|
@ -19,6 +19,7 @@ namespace sh
|
|||
virtual bool createConfiguration (const std::string& name, unsigned short lodIndex);
|
||||
|
||||
virtual bool isUnreferenced();
|
||||
virtual void unreferenceTextures();
|
||||
virtual void ensureLoaded();
|
||||
|
||||
virtual void removeAll ();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<!-- Label -->
|
||||
<Widget type="TextBox" skin="HeaderText" position="0 0 186 18" name="LabelT" align="Left Top">
|
||||
<Property key="Caption" value="Choose a Specialization"/>
|
||||
<Property key="TextAlign" value="Left Top"/>
|
||||
<Property key="TextAlign" value="HCenter Top"/>
|
||||
</Widget>
|
||||
|
||||
<!-- Attribute list -->
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
<Widget type="AutoSizedTextBox" skin="NormalText">
|
||||
<Property key="Caption" value="#{sName}"/>
|
||||
<UserString key="ToolTipType" value="Layout"/>
|
||||
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||
<UserString key="Caption_Text" value="#{sEnchantmentHelp8}"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="EditBox" skin="MW_TextEdit" position="0 0 30 30" name="NameEdit">
|
||||
|
@ -25,6 +28,9 @@
|
|||
|
||||
<Widget type="AutoSizedTextBox" skin="NormalText">
|
||||
<Property key="Caption" value="#{sItem}"/>
|
||||
<UserString key="ToolTipType" value="Layout"/>
|
||||
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||
<UserString key="Caption_Text" value="#{sEnchantmentHelp1}"/>
|
||||
</Widget>
|
||||
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 0 50 50" name="ItemBox">
|
||||
</Widget>
|
||||
|
@ -33,6 +39,9 @@
|
|||
|
||||
<Widget type="AutoSizedTextBox" skin="NormalText">
|
||||
<Property key="Caption" value="#{sSoulGem}"/>
|
||||
<UserString key="ToolTipType" value="Layout"/>
|
||||
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||
<UserString key="Caption_Text" value="#{sEnchantmentHelp2}"/>
|
||||
</Widget>
|
||||
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 0 50 50" name="SoulBox">
|
||||
</Widget>
|
||||
|
@ -70,6 +79,9 @@
|
|||
<!-- Available effects -->
|
||||
<Widget type="TextBox" skin="NormalText" position="12 108 300 24">
|
||||
<Property key="Caption" value="#{sMagicEffects}"/>
|
||||
<UserString key="ToolTipType" value="Layout"/>
|
||||
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||
<UserString key="Caption_Text" value="#{sEnchantmentHelp9}"/>
|
||||
</Widget>
|
||||
<Widget type="MWList" skin="MW_SimpleList" position="12 136 202 209" name="AvailableEffects">
|
||||
</Widget>
|
||||
|
@ -77,6 +89,9 @@
|
|||
<!-- Used effects -->
|
||||
<Widget type="TextBox" skin="NormalText" position="226 108 300 24">
|
||||
<Property key="Caption" value="#{sEffects}"/>
|
||||
<UserString key="ToolTipType" value="Layout"/>
|
||||
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||
<UserString key="Caption_Text" value="#{sEnchantmentHelp10}"/>
|
||||
</Widget>
|
||||
<Widget type="Widget" skin="MW_Box" position="226 136 316 209">
|
||||
<Widget type="ScrollView" skin="MW_ScrollViewH" position="4 4 308 201" name="UsedEffects">
|
||||
|
@ -89,6 +104,9 @@
|
|||
|
||||
<Widget type="AutoSizedButton" skin="MW_Button" name="TypeButton">
|
||||
<Property key="Caption" value="Constant effect"/>
|
||||
<UserString key="ToolTipType" value="Layout"/>
|
||||
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||
<UserString key="Caption_Text" value="#{sEnchantmentHelp7}"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="Widget">
|
||||
|
@ -100,6 +118,9 @@
|
|||
</Widget>
|
||||
<Widget type="AutoSizedTextBox" skin="SandText" name="PriceLabel">
|
||||
<Property key="Caption" value="0"/>
|
||||
<UserString key="ToolTipType" value="Layout"/>
|
||||
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||
<UserString key="Caption_Text" value="#{sEnchantmentHelp6}"/>
|
||||
</Widget>
|
||||
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@
|
|||
<State name="disabled" colour="0.70 0.57 0.33" shift="0"/>
|
||||
<State name="normal" colour="0.70 0.57 0.33" shift="0"/>
|
||||
<State name="highlighted" colour="0.85 0.76 0.60" shift="0"/>
|
||||
<State name="pushed" colour="0.33 0.38 0.67" shift="0"/>
|
||||
<State name="pushed" colour="1 1 1" shift="0"/>
|
||||
<State name="disabled_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||
<State name="normal_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||
<State name="highlighted_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||
|
|
|
@ -65,6 +65,24 @@
|
|||
</Widget>
|
||||
</Widget>
|
||||
|
||||
<!-- Hand-to-hand tooltip -->
|
||||
<Widget type="HBox" skin="HUD_Box_NoTransp" position="0 0 300 300" align="Stretch" name="HandToHandToolTip">
|
||||
<Property key="AutoResize" value="true"/>
|
||||
<Property key="Padding" value="8"/>
|
||||
|
||||
<Widget type="VBox">
|
||||
<UserString key="VStretch" value="true"/>
|
||||
<Widget type="ImageBox" skin="ImageBox" position="8 8 32 32" align="Left Top" name="HandToHandImage"/>
|
||||
<Widget type="Widget">
|
||||
<UserString key="VStretch" value="true"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
<Widget type="AutoSizedTextBox" skin="SandText" position="44 8 248 284" align="Left Top" name="HandToHandText">
|
||||
<Property key="TextAlign" value="Center"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
<!-- Health tooltip -->
|
||||
<Widget type="HBox" skin="HUD_Box_NoTransp" position="0 0 300 300" align="Stretch" name="HealthToolTip">
|
||||
<Property key="AutoResize" value="true"/>
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace Render
|
|||
void SelectionBuffer::setupRenderTarget()
|
||||
{
|
||||
mRenderTarget = mTexture->getBuffer()->getRenderTarget();
|
||||
mRenderTarget->removeAllViewports();
|
||||
Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera);
|
||||
vp->setOverlaysEnabled(false);
|
||||
vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0));
|
||||
|
@ -65,6 +66,7 @@ namespace Render
|
|||
{
|
||||
Ogre::MaterialManager::getSingleton ().addListener (this);
|
||||
|
||||
mTexture->load();
|
||||
if (mRenderTarget == NULL)
|
||||
setupRenderTarget();
|
||||
|
||||
|
|
Loading…
Reference in a new issue