Merge remote-tracking branch 'zini/master' into animation2

Conflicts:
	components/nifogre/ogre_nif_loader.cpp
This commit is contained in:
Chris Robinson 2013-01-15 14:56:08 -08:00
commit 94e30199d1
37 changed files with 598 additions and 289 deletions

View file

@ -1,123 +0,0 @@
Bitstream Vera Fonts Copyright
The fonts have a generous copyright, allowing derivative works (as
long as "Bitstream" or "Vera" are not in the names), and full
redistribution (so long as they are not *sold* by themselves). They
can be be bundled, redistributed and sold with any software.
The fonts are distributed under the following copyright:
Copyright
=========
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
Vera is a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute
the Font Software, including without limitation the rights to use,
copy, merge, publish, distribute, and/or sell copies of the Font
Software, and to permit persons to whom the Font Software is furnished
to do so, subject to the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Bitstream" or the word "Vera".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Bitstream Vera" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font
Software without prior written authorization from the Gnome Foundation
or Bitstream Inc., respectively. For further information, contact:
fonts at gnome dot org.
Copyright FAQ
=============
1. I don't understand the resale restriction... What gives?
Bitstream is giving away these fonts, but wishes to ensure its
competitors can't just drop the fonts as is into a font sale system
and sell them as is. It seems fair that if Bitstream can't make money
from the Bitstream Vera fonts, their competitors should not be able to
do so either. You can sell the fonts as part of any software package,
however.
2. I want to package these fonts separately for distribution and
sale as part of a larger software package or system. Can I do so?
Yes. A RPM or Debian package is a "larger software package" to begin
with, and you aren't selling them independently by themselves.
See 1. above.
3. Are derivative works allowed?
Yes!
4. Can I change or add to the font(s)?
Yes, but you must change the name(s) of the font(s).
5. Under what terms are derivative works allowed?
You must change the name(s) of the fonts. This is to ensure the
quality of the fonts, both to protect Bitstream and Gnome. We want to
ensure that if an application has opened a font specifically of these
names, it gets what it expects (though of course, using fontconfig,
substitutions could still could have occurred during font
opening). You must include the Bitstream copyright. Additional
copyrights can be added, as per copyright law. Happy Font Hacking!
6. If I have improvements for Bitstream Vera, is it possible they might get
adopted in future versions?
Yes. The contract between the Gnome Foundation and Bitstream has
provisions for working with Bitstream to ensure quality additions to
the Bitstream Vera font family. Please contact us if you have such
additions. Note, that in general, we will want such additions for the
entire family, not just a single font, and that you'll have to keep
both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
glyphs to the font, they must be stylistically in keeping with Vera's
design. Vera cannot become a "ransom note" font. Jim Lyles will be
providing a document describing the design elements used in Vera, as a
guide and aid for people interested in contributing to Vera.
7. I want to sell a software package that uses these fonts: Can I do so?
Sure. Bundle the fonts with your software and sell your software
with the fonts. That is the intent of the copyright.
8. If applications have built the names "Bitstream Vera" into them,
can I override this somehow to use fonts of my choosing?
This depends on exact details of the software. Most open source
systems and software (e.g., Gnome, KDE, etc.) are now converting to
use fontconfig (see www.fontconfig.org) to handle font configuration,
selection and substitution; it has provisions for overriding font
names and subsituting alternatives. An example is provided by the
supplied local.conf file, which chooses the family Bitstream Vera for
"sans", "serif" and "monospace". Other software (e.g., the XFree86
core server) has other mechanisms for font substitution.

View file

@ -0,0 +1,99 @@
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
Bitstream Vera Fonts Copyright
------------------------------
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute the
Font Software, including without limitation the rights to use, copy, merge,
publish, distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to the
following conditions:
The above copyright and trademark notices and this permission notice shall
be included in all copies of one or more of the Font Software typefaces.
The Font Software may be modified, altered, or added to, and in particular
the designs of glyphs or characters in the Fonts may be modified and
additional glyphs or characters may be added to the Fonts, only if the fonts
are renamed to names not containing either the words "Bitstream" or the word
"Vera".
This License becomes null and void to the extent applicable to Fonts or Font
Software that has been modified and is distributed under the "Bitstream
Vera" names.
The Font Software may be sold as part of a larger software package but no
copy of one or more of the Font Software typefaces may be sold by itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font Software
without prior written authorization from the Gnome Foundation or Bitstream
Inc., respectively. For further information, contact: fonts at gnome dot
org.
Arev Fonts Copyright
------------------------------
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and
associated documentation files (the "Font Software"), to reproduce
and distribute the modifications to the Bitstream Vera Font Software,
including without limitation the rights to use, copy, merge, publish,
distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to
the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Tavmjong Bah" or the word "Arev".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Tavmjong Bah Arev" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the name of Tavmjong Bah shall not
be used in advertising or otherwise to promote the sale, use or other
dealings in this Font Software without prior written authorization
from Tavmjong Bah. For further information, contact: tavmjong @ free
. fr.
$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $

View file

@ -240,18 +240,9 @@ void OMW::Engine::setNewGame(bool newGame)
mNewGame = newGame; mNewGame = newGame;
} }
// Initialise and enter main loop. std::string OMW::Engine::loadSettings (Settings::Manager & settings)
void OMW::Engine::go()
{ {
assert (!mCellName.empty());
assert (!mMaster.empty());
assert (!mOgre);
mOgre = new OEngine::Render::OgreRenderer;
// Create the settings manager and load default settings file // Create the settings manager and load default settings file
Settings::Manager settings;
const std::string localdefault = mCfgMgr.getLocalPath().string() + "/settings-default.cfg"; const std::string localdefault = mCfgMgr.getLocalPath().string() + "/settings-default.cfg";
const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/settings-default.cfg"; const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/settings-default.cfg";
@ -272,10 +263,6 @@ void OMW::Engine::go()
else if (boost::filesystem::exists(globaldefault)) else if (boost::filesystem::exists(globaldefault))
settings.loadUser(globaldefault); settings.loadUser(globaldefault);
// Get the path for the keybinder xml file
std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string();
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
mFpsLevel = settings.getInt("fps", "HUD"); mFpsLevel = settings.getInt("fps", "HUD");
// load nif overrides // load nif overrides
@ -285,6 +272,13 @@ void OMW::Engine::go()
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg")) else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"))
nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"); nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg");
return settingspath;
}
void OMW::Engine::prepareEngine (Settings::Manager & settings)
{
Nif::NIFFile::CacheLock cachelock;
std::string renderSystem = settings.getString("render system", "Video"); std::string renderSystem = settings.getString("render system", "Video");
if (renderSystem == "") if (renderSystem == "")
{ {
@ -294,6 +288,9 @@ void OMW::Engine::go()
renderSystem = "OpenGL Rendering Subsystem"; renderSystem = "OpenGL Rendering Subsystem";
#endif #endif
} }
mOgre = new OEngine::Render::OgreRenderer;
mOgre->configure( mOgre->configure(
mCfgMgr.getLogPath().string(), mCfgMgr.getLogPath().string(),
renderSystem, renderSystem,
@ -328,16 +325,13 @@ void OMW::Engine::go()
// cursor replacer (converts the cursor from the bsa so they can be used by mygui) // cursor replacer (converts the cursor from the bsa so they can be used by mygui)
MWGui::CursorReplace replacer; MWGui::CursorReplace replacer;
// Create encoder
ToUTF8::Utf8Encoder encoder (mEncoding);
// Create the world // Create the world
mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster,
mResDir, mCfgMgr.getCachePath(), mNewGame, &encoder, mFallbackMap, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap,
mActivationDistanceOverride)); mActivationDistanceOverride));
//Load translation data //Load translation data
mTranslationDataStorage.setEncoder(&encoder); mTranslationDataStorage.setEncoder(mEncoder);
mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster); mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster);
// Create window manager - this manages all the MW-specific GUI windows // Create window manager - this manages all the MW-specific GUI windows
@ -365,6 +359,11 @@ void OMW::Engine::go()
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage));
// Sets up the input system // Sets up the input system
// Get the path for the keybinder xml file
std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string();
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, mEnvironment.setInputManager (new MWInput::InputManager (*mOgre,
MWBase::Environment::get().getWorld()->getPlayer(), MWBase::Environment::get().getWorld()->getPlayer(),
*MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists)); *MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists));
@ -388,13 +387,8 @@ void OMW::Engine::go()
MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, pos); MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, pos);
} }
std::cout << "\nPress Q/ESC or close window to exit.\n";
mOgre->getRoot()->addFrameListener (this); mOgre->getRoot()->addFrameListener (this);
// Play some good 'ol tunes
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
// scripts // scripts
if (mCompileAll) if (mCompileAll)
{ {
@ -407,10 +401,35 @@ void OMW::Engine::go()
<< "%)" << "%)"
<< std::endl; << std::endl;
} }
}
// Initialise and enter main loop.
void OMW::Engine::go()
{
assert (!mCellName.empty());
assert (!mMaster.empty());
assert (!mOgre);
Settings::Manager settings;
std::string settingspath;
settingspath = loadSettings (settings);
// Create encoder
ToUTF8::Utf8Encoder encoder (mEncoding);
mEncoder = &encoder;
prepareEngine (settings);
// Play some good 'ol tunes
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
if (!mStartupScript.empty()) if (!mStartupScript.empty())
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript); MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
std::cout << "\nPress Q/ESC or close window to exit.\n";
// Start the main rendering loop // Start the main rendering loop
mOgre->start(); mOgre->start();

View file

@ -6,6 +6,7 @@
#include <components/compiler/extensions.hpp> #include <components/compiler/extensions.hpp>
#include <components/files/collections.hpp> #include <components/files/collections.hpp>
#include <components/translation/translation.hpp> #include <components/translation/translation.hpp>
#include <components/settings/settings.hpp>
#include "mwbase/environment.hpp" #include "mwbase/environment.hpp"
@ -61,6 +62,7 @@ namespace OMW
{ {
MWBase::Environment mEnvironment; MWBase::Environment mEnvironment;
ToUTF8::FromType mEncoding; ToUTF8::FromType mEncoding;
ToUTF8::Utf8Encoder* mEncoder;
Files::PathContainer mDataDirs; Files::PathContainer mDataDirs;
boost::filesystem::path mResDir; boost::filesystem::path mResDir;
OEngine::Render::OgreRenderer *mOgre; OEngine::Render::OgreRenderer *mOgre;
@ -103,6 +105,12 @@ namespace OMW
virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt);
/// Load settings from various files, returns the path to the user settings file
std::string loadSettings (Settings::Manager & settings);
/// Prepare engine for game play
void prepareEngine (Settings::Manager & settings);
public: public:
Engine(Files::ConfigurationManager& configurationManager); Engine(Files::ConfigurationManager& configurationManager);
virtual ~Engine(); virtual ~Engine();

View file

@ -280,7 +280,7 @@ namespace MWBase
/// @param cursor Y (relative 0-1) /// @param cursor Y (relative 0-1)
/// @return true if the object was placed, or false if it was rejected because the position is too far away /// @return true if the object was placed, or false if it was rejected because the position is too far away
virtual void dropObjectOnGround (const MWWorld::Ptr& object) = 0; virtual void dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object) = 0;
virtual bool canPlaceObject (float cursorX, float cursorY) = 0; virtual bool canPlaceObject (float cursorX, float cursorY) = 0;
///< @return true if it is possible to place on object at specified cursor location ///< @return true if it is possible to place on object at specified cursor location

View file

@ -12,6 +12,9 @@
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/actioneat.hpp" #include "../mwworld/actioneat.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
@ -154,6 +157,10 @@ namespace MWClass
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer();
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player);
int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase();
MWGui::Widgets::SpellEffectList list; MWGui::Widgets::SpellEffectList list;
for (int i=0; i<4; ++i) for (int i=0; i<4; ++i)
{ {
@ -163,6 +170,12 @@ namespace MWClass
params.mEffectID = ref->mBase->mData.mEffectID[i]; params.mEffectID = ref->mBase->mData.mEffectID[i];
params.mAttribute = ref->mBase->mData.mAttributes[i]; params.mAttribute = ref->mBase->mData.mAttributes[i];
params.mSkill = ref->mBase->mData.mSkills[i]; params.mSkill = ref->mBase->mData.mSkills[i];
params.mKnown = ( (i == 0 && alchemySkill >= 15)
|| (i == 1 && alchemySkill >= 30)
|| (i == 2 && alchemySkill >= 45)
|| (i == 3 && alchemySkill >= 60));
list.push_back(params); list.push_back(params);
} }
info.effects = list; info.effects = list;

View file

@ -220,7 +220,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender)
if (world->canPlaceObject(mouseX, mouseY)) if (world->canPlaceObject(mouseX, mouseY))
world->placeObject(object, mouseX, mouseY); world->placeObject(object, mouseX, mouseY);
else else
world->dropObjectOnGround(object); world->dropObjectOnGround(world->getPlayer().getPlayer(), object);
MyGUI::PointerManager::getInstance().setPointer("arrow"); MyGUI::PointerManager::getInstance().setPointer("arrow");

View file

@ -440,7 +440,7 @@ namespace MWGui
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{ {
spellList.push_back(*it); spellList.push_back (it->first);
} }
const MWWorld::ESMStore &esmStore = const MWWorld::ESMStore &esmStore =

View file

@ -102,7 +102,7 @@ namespace MWGui
for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter) for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter)
{ {
const ESM::Spell* spell = const ESM::Spell* spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (*iter); MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mType!=ESM::Spell::ST_Spell) if (spell->mData.mType!=ESM::Spell::ST_Spell)
continue; // don't try to sell diseases, curses or powers continue; // don't try to sell diseases, curses or powers
@ -110,7 +110,7 @@ namespace MWGui
if (std::find (playerSpells.begin(), playerSpells.end(), *iter)!=playerSpells.end()) if (std::find (playerSpells.begin(), playerSpells.end(), *iter)!=playerSpells.end())
continue; // we have that spell already continue; // we have that spell already
addSpell (*iter); addSpell (iter->first);
} }
updateLabels(); updateLabels();

View file

@ -436,7 +436,7 @@ namespace MWGui
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{ {
const ESM::Spell* spell = const ESM::Spell* spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(*it); MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (it->first);
// only normal spells count // only normal spells count
if (spell->mData.mType != ESM::Spell::ST_Spell) if (spell->mData.mType != ESM::Spell::ST_Spell)

View file

@ -139,7 +139,7 @@ namespace MWGui
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{ {
spellList.push_back(*it); spellList.push_back (it->first);
} }
const MWWorld::ESMStore &esmStore = const MWWorld::ESMStore &esmStore =

View file

@ -390,8 +390,13 @@ void MWSpellEffect::setSpellEffect(const SpellEffectParams& params)
void MWSpellEffect::updateWidgets() void MWSpellEffect::updateWidgets()
{ {
if (!mWindowManager) if (!mEffectParams.mKnown)
{
mTextWidget->setCaption ("?");
mRequestedWidth = mTextWidget->getTextSize().width + 24;
mImageWidget->setImageTexture ("");
return; return;
}
const MWWorld::ESMStore &store = const MWWorld::ESMStore &store =
MWBase::Environment::get().getWorld()->getStore(); MWBase::Environment::get().getWorld()->getStore();
@ -400,7 +405,6 @@ void MWSpellEffect::updateWidgets()
store.get<ESM::MagicEffect>().search(mEffectParams.mEffectID); store.get<ESM::MagicEffect>().search(mEffectParams.mEffectID);
assert(magicEffect); assert(magicEffect);
assert(mWindowManager);
std::string pt = mWindowManager->getGameSettingString("spoint", ""); std::string pt = mWindowManager->getGameSettingString("spoint", "");
std::string pts = mWindowManager->getGameSettingString("spoints", ""); std::string pts = mWindowManager->getGameSettingString("spoints", "");

View file

@ -37,12 +37,15 @@ namespace MWGui
, mEffectID(-1) , mEffectID(-1)
, mNoTarget(false) , mNoTarget(false)
, mIsConstant(false) , mIsConstant(false)
, mKnown(true)
{ {
} }
bool mNoTarget; // potion effects for example have no target (target is always the player) bool mNoTarget; // potion effects for example have no target (target is always the player)
bool mIsConstant; // constant effect means that duration will not be displayed bool mIsConstant; // constant effect means that duration will not be displayed
bool mKnown; // is this effect known to the player? (If not, will display as a question mark instead)
// value of -1 here means the effect is unknown to the player // value of -1 here means the effect is unknown to the player
short mEffectID; short mEffectID;

View file

@ -68,7 +68,7 @@ namespace MWMechanics
} }
} }
void MagicEffects::add (const ESM::EffectList& list) void MagicEffects::add (const ESM::EffectList& list, float magnitude)
{ {
for (std::vector<ESM::ENAMstruct>::const_iterator iter (list.mList.begin()); iter!=list.mList.end(); for (std::vector<ESM::ENAMstruct>::const_iterator iter (list.mList.begin()); iter!=list.mList.end();
++iter) ++iter)
@ -78,9 +78,13 @@ namespace MWMechanics
if (iter->mMagnMin>=iter->mMagnMax) if (iter->mMagnMin>=iter->mMagnMax)
param.mMagnitude = iter->mMagnMin; param.mMagnitude = iter->mMagnMin;
else else
{
if (magnitude==-1)
magnitude = static_cast<float> (std::rand()) / RAND_MAX;
param.mMagnitude = static_cast<int> ( param.mMagnitude = static_cast<int> (
(iter->mMagnMax-iter->mMagnMin+1)* (iter->mMagnMax-iter->mMagnMin+1)*magnitude + iter->mMagnMin);
(static_cast<float> (std::rand()) / RAND_MAX) + iter->mMagnMin); }
add (*iter, param); add (*iter, param);
} }

View file

@ -67,7 +67,8 @@ namespace MWMechanics
void add (const EffectKey& key, const EffectParam& param); void add (const EffectKey& key, const EffectParam& param);
void add (const ESM::EffectList& list); void add (const ESM::EffectList& list, float magnitude = -1);
///< \param magnitude normalised magnitude (-1: random)
MagicEffects& operator+= (const MagicEffects& effects); MagicEffects& operator+= (const MagicEffects& effects);

View file

@ -1,22 +1,19 @@
#include "spells.hpp" #include "spells.hpp"
#include "../mwworld/esmstore.hpp" #include <cstdlib>
#include <components/esm/loadspel.hpp> #include <components/esm/loadspel.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp"
#include "magiceffects.hpp" #include "magiceffects.hpp"
namespace MWMechanics namespace MWMechanics
{ {
void Spells::addSpell (const ESM::Spell *spell, MagicEffects& effects) const
{
effects.add (spell->mEffects);
}
Spells::TIterator Spells::begin() const Spells::TIterator Spells::begin() const
{ {
return mSpells.begin(); return mSpells.begin();
@ -29,13 +26,13 @@ namespace MWMechanics
void Spells::add (const std::string& spellId) void Spells::add (const std::string& spellId)
{ {
if (std::find (mSpells.begin(), mSpells.end(), spellId)==mSpells.end()) if (mSpells.find (spellId)==mSpells.end())
mSpells.push_back (spellId); mSpells.insert (std::make_pair (spellId, static_cast<float> (std::rand()) / RAND_MAX));
} }
void Spells::remove (const std::string& spellId) void Spells::remove (const std::string& spellId)
{ {
TContainer::iterator iter = std::find (mSpells.begin(), mSpells.end(), spellId); TContainer::iterator iter = mSpells.find (spellId);
if (iter!=mSpells.end()) if (iter!=mSpells.end())
mSpells.erase (iter); mSpells.erase (iter);
@ -51,11 +48,11 @@ namespace MWMechanics
for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter)
{ {
const ESM::Spell *spell = const ESM::Spell *spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (*iter); MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || if (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight ||
spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse) spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse)
addSpell (spell, effects); effects.add (spell->mEffects, iter->second);
} }
return effects; return effects;
@ -81,7 +78,7 @@ namespace MWMechanics
for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter)
{ {
const ESM::Spell *spell = const ESM::Spell *spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (*iter); MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mFlags & ESM::Spell::ST_Disease) if (spell->mData.mFlags & ESM::Spell::ST_Disease)
return true; return true;
@ -95,7 +92,7 @@ namespace MWMechanics
for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter)
{ {
const ESM::Spell *spell = const ESM::Spell *spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (*iter); MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (iter->first);
if (spell->mData.mFlags & ESM::Spell::ST_Blight) if (spell->mData.mFlags & ESM::Spell::ST_Blight)
return true; return true;

View file

@ -1,7 +1,7 @@
#ifndef GAME_MWMECHANICS_SPELLS_H #ifndef GAME_MWMECHANICS_SPELLS_H
#define GAME_MWMECHANICS_SPELLS_H #define GAME_MWMECHANICS_SPELLS_H
#include <vector> #include <map>
#include <string> #include <string>
namespace ESM namespace ESM
@ -21,16 +21,14 @@ namespace MWMechanics
{ {
public: public:
typedef std::vector<std::string> TContainer; typedef std::map<std::string, float> TContainer; // ID, normalised magnitude
typedef TContainer::const_iterator TIterator; typedef TContainer::const_iterator TIterator;
private: private:
std::vector<std::string> mSpells; TContainer mSpells;
std::string mSelectedSpell; std::string mSelectedSpell;
void addSpell (const ESM::Spell *, MagicEffects& effects) const;
public: public:
TIterator begin() const; TIterator begin() const;

View file

@ -181,10 +181,14 @@ namespace MWScript
runtime.pop(); runtime.pop();
std::vector<int> idleList; std::vector<int> idleList;
for (unsigned int i=0; i<arg0; ++i) { idleList.push_back (0); // why MW, why?
for (int i=2; i<10 && arg0; ++i)
{
Interpreter::Type_Integer idleValue = runtime[0].mFloat; Interpreter::Type_Integer idleValue = runtime[0].mFloat;
idleList.push_back(idleValue); idleList.push_back(idleValue);
runtime.pop(); runtime.pop();
--arg0;
} }
// discard additional arguments (reset), because we have no idea what they mean. // discard additional arguments (reset), because we have no idea what they mean.

View file

@ -311,4 +311,9 @@ op 0x20001f4: AddSoulGem, explicit reference
op 0x20001f5: RemoveSoulGem op 0x20001f5: RemoveSoulGem
op 0x20001f6: RemoveSoulGem, explicit reference op 0x20001f6: RemoveSoulGem, explicit reference
op 0x20001f7: PlayBink op 0x20001f7: PlayBink
opcodes 0x20001f8-0x3ffffff unused op 0x20001f8: Drop
op 0x20001f9: Drop, explicit reference
op 0x20001fa: DropSoulGem
op 0x20001fb: DropSoulGem, explicit reference
opcodes 0x20001fa-0x3ffffff unused

View file

@ -383,6 +383,88 @@ namespace MWScript
} }
}; };
template<class R>
class OpDrop : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
std::string item = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Integer amount = runtime[0].mInteger;
runtime.pop();
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
{
if (::Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item))
{
if(iter->getRefData().getCount() <= amount)
{
MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter);
iter->getRefData().setCount(0);
}
else
{
int original = iter->getRefData().getCount();
iter->getRefData().setCount(amount);
MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter);
iter->getRefData().setCount(original - amount);
}
break;
}
}
}
};
template<class R>
class OpDropSoulGem : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
std::string soul = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
{
if (::Misc::StringUtils::ciEqual(iter->getCellRef().mSoul, soul))
{
if(iter->getRefData().getCount() <= 1)
{
MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter);
iter->getRefData().setCount(0);
}
else
{
int original = iter->getRefData().getCount();
iter->getRefData().setCount(1);
MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter);
iter->getRefData().setCount(original - 1);
}
break;
}
}
}
};
template <class R> template <class R>
class OpGetAttacked : public Interpreter::Opcode0 class OpGetAttacked : public Interpreter::Opcode0
{ {
@ -495,6 +577,10 @@ namespace MWScript
const int opcodeAddSoulGemExplicit = 0x20001f4; const int opcodeAddSoulGemExplicit = 0x20001f4;
const int opcodeRemoveSoulGem = 0x20001f5; const int opcodeRemoveSoulGem = 0x20001f5;
const int opcodeRemoveSoulGemExplicit = 0x20001f6; const int opcodeRemoveSoulGemExplicit = 0x20001f6;
const int opcodeDrop = 0x20001f8;
const int opcodeDropExplicit = 0x20001f9;
const int opcodeDropSoulGem = 0x20001fa;
const int opcodeDropSoulGemExplicit = 0x20001fb;
const int opcodeGetAttacked = 0x20001d3; const int opcodeGetAttacked = 0x20001d3;
const int opcodeGetAttackedExplicit = 0x20001d4; const int opcodeGetAttackedExplicit = 0x20001d4;
const int opcodeGetWeaponDrawn = 0x20001d7; const int opcodeGetWeaponDrawn = 0x20001d7;
@ -538,6 +624,8 @@ namespace MWScript
extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit); extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit);
extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit);
extensions.registerInstruction ("removesoulgem", "c", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit); extensions.registerInstruction ("removesoulgem", "c", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit);
extensions.registerInstruction ("drop", "cl", opcodeDrop, opcodeDropExplicit);
extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit);
extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit);
extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit); extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit);
extensions.registerFunction ("getspelleffects", 'l', "c", opcodeGetSpellEffects, opcodeGetSpellEffectsExplicit); extensions.registerFunction ("getspelleffects", 'l', "c", opcodeGetSpellEffects, opcodeGetSpellEffectsExplicit);
@ -576,6 +664,10 @@ namespace MWScript
interpreter.installSegment5 (opcodeAddSoulGemExplicit, new OpAddSoulGem<ExplicitRef>); interpreter.installSegment5 (opcodeAddSoulGemExplicit, new OpAddSoulGem<ExplicitRef>);
interpreter.installSegment5 (opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>); interpreter.installSegment5 (opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>);
interpreter.installSegment5 (opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>); interpreter.installSegment5 (opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>);
interpreter.installSegment5 (opcodeDrop, new OpDrop<ImplicitRef>);
interpreter.installSegment5 (opcodeDropExplicit, new OpDrop<ExplicitRef>);
interpreter.installSegment5 (opcodeDropSoulGem, new OpDropSoulGem<ImplicitRef>);
interpreter.installSegment5 (opcodeDropSoulGemExplicit, new OpDropSoulGem<ExplicitRef>);
interpreter.installSegment5 (opcodeGetAttacked, new OpGetAttacked<ImplicitRef>); interpreter.installSegment5 (opcodeGetAttacked, new OpGetAttacked<ImplicitRef>);
interpreter.installSegment5 (opcodeGetAttackedExplicit, new OpGetAttacked<ExplicitRef>); interpreter.installSegment5 (opcodeGetAttackedExplicit, new OpGetAttacked<ExplicitRef>);
interpreter.installSegment5 (opcodeGetWeaponDrawn, new OpGetWeaponDrawn<ImplicitRef>); interpreter.installSegment5 (opcodeGetWeaponDrawn, new OpGetWeaponDrawn<ImplicitRef>);

View file

@ -485,7 +485,7 @@ namespace MWScript
for (MWMechanics::Spells::TIterator iter ( for (MWMechanics::Spells::TIterator iter (
MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().begin()); MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().begin());
iter!=MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().end(); ++iter) iter!=MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().end(); ++iter)
if (*iter==id) if (iter->first==id)
{ {
value = 1; value = 1;
break; break;

View file

@ -173,6 +173,8 @@ namespace MWWorld
void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos)
{ {
Nif::NIFFile::CacheLock cachelock;
mRendering.preCellChange(mCurrentCell); mRendering.preCellChange(mCurrentCell);
// remove active // remove active

View file

@ -1286,12 +1286,12 @@ namespace MWWorld
} }
} }
void World::dropObjectOnGround (const Ptr& object) void World::dropObjectOnGround (const Ptr& actor, const Ptr& object)
{ {
MWWorld::Ptr::CellStore* cell = getPlayer().getPlayer().getCell(); MWWorld::Ptr::CellStore* cell = actor.getCell();
ESM::Position pos = ESM::Position pos =
getPlayer().getPlayer().getRefData().getPosition(); actor.getRefData().getPosition();
Ogre::Vector3 orig = Ogre::Vector3 orig =
Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]); Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]);

View file

@ -311,7 +311,7 @@ namespace MWWorld
/// @param cursor Y (relative 0-1) /// @param cursor Y (relative 0-1)
/// @return true if the object was placed, or false if it was rejected because the position is too far away /// @return true if the object was placed, or false if it was rejected because the position is too far away
virtual void dropObjectOnGround (const Ptr& object); virtual void dropObjectOnGround (const Ptr& actor, const Ptr& object);
virtual bool canPlaceObject(float cursorX, float cursorY); virtual bool canPlaceObject(float cursorX, float cursorY);
///< @return true if it is possible to place on object at specified cursor location ///< @return true if it is possible to place on object at specified cursor location

View file

@ -6,11 +6,6 @@
namespace Files { namespace Files {
bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::Root &ogreRoot) { bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::Root &ogreRoot) {
// Append plugin suffix if debugging.
#if defined(DEBUG)
pluginName = pluginName + OGRE_PLUGIN_DEBUG_SUFFIX;
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
std::ostringstream verStream; std::ostringstream verStream;
verStream << "." << OGRE_VERSION_MAJOR << "." << OGRE_VERSION_MINOR << "." << OGRE_VERSION_PATCH; verStream << "." << OGRE_VERSION_MAJOR << "." << OGRE_VERSION_MINOR << "." << OGRE_VERSION_PATCH;
@ -28,7 +23,22 @@ bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::
pluginExt = ".so"; pluginExt = ".so";
#endif #endif
std::string pluginPath = pluginDir + "/" + pluginName + pluginExt; // Append plugin suffix if debugging.
std::string pluginPath;
#if defined(DEBUG)
pluginPath = pluginDir + "/" + pluginName + OGRE_PLUGIN_DEBUG_SUFFIX + pluginExt;
if (boost::filesystem::exists(pluginPath)) {
ogreRoot.loadPlugin(pluginPath);
return true;
}
else {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
return false;
#endif //OGRE_PLATFORM == OGRE_PLATFORM_WIN32
}
#endif //defined(DEBUG)
pluginPath = pluginDir + "/" + pluginName + pluginExt;
if (boost::filesystem::exists(pluginPath)) { if (boost::filesystem::exists(pluginPath)) {
ogreRoot.loadPlugin(pluginPath); ogreRoot.loadPlugin(pluginPath);
return true; return true;

View file

@ -34,9 +34,159 @@
#include "controller.hpp" #include "controller.hpp"
#include <iostream> #include <iostream>
using namespace std;
using namespace Nif; //TODO: when threading is needed, enable these
using namespace Misc; //#include <boost/mutex.hpp>
//#include <boost/thread/locks.hpp>
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)
: filename(name)
{
inp = Ogre::ResourceGroupManager::getSingleton().openResource(name);
parse();
// Make sure to close the file after it was loaded into memory
inp.setNull();
}
NIFFile::~NIFFile()
{
LoadedCache::release (this);
for(std::size_t i=0; i<records.size(); i++)
delete records[i];
}
/* This file implements functions from the NIFFile class. It is also /* This file implements functions from the NIFFile class. It is also
where we stash all the functions we couldn't add as inline where we stash all the functions we couldn't add as inline
@ -56,7 +206,7 @@ void NIFFile::parse()
fail("Unsupported NIF version"); fail("Unsupported NIF version");
// Number of records // Number of records
int recNum = getInt(); size_t recNum = getInt();
records.resize(recNum); records.resize(recNum);
/* The format for 10.0.1.0 seems to be a bit different. After the /* The format for 10.0.1.0 seems to be a bit different. After the
@ -68,7 +218,7 @@ void NIFFile::parse()
we do not support or plan to support other versions yet. we do not support or plan to support other versions yet.
*/ */
for(int i=0;i<recNum;i++) for(size_t i = 0;i < recNum;i++)
{ {
std::string rec = getString(); std::string rec = getString();
//cout << i << ": " << rec.toString() << endl; //cout << i << ": " << rec.toString() << endl;
@ -160,6 +310,7 @@ void NIFFile::parse()
assert(r != NULL); assert(r != NULL);
assert(r->recType != RC_MISSING); assert(r->recType != RC_MISSING);
r->recName = rec; r->recName = rec;
r->recIndex = i;
records[i] = r; records[i] = r;
r->read(this); r->read(this);
@ -178,11 +329,8 @@ void NIFFile::parse()
tree, but for the moment we ignore it. tree, but for the moment we ignore it.
*/ */
// TODO: Set up kf file here first, if applicable. It needs its own
// code to link it up with the main NIF structure.
// Once parsing is done, do post-processing. // Once parsing is done, do post-processing.
for(int i=0; i<recNum; i++) for(size_t i=0; i<recNum; i++)
records[i]->post(this); records[i]->post(this);
} }
@ -211,16 +359,18 @@ void NiSkinInstance::post(NIFFile *nif)
} }
} }
Ogre::Matrix4 Node::getLocalTransform() Ogre::Matrix4 Node::getLocalTransform() const
{ {
Ogre::Matrix4 mat4(Ogre::Matrix4::IDENTITY); Ogre::Matrix4 mat4(Ogre::Matrix4::IDENTITY);
mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation)); mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation));
return mat4; return mat4;
} }
Ogre::Matrix4 Node::getWorldTransform() Ogre::Matrix4 Node::getWorldTransform() const
{ {
if(parent != NULL) if(parent != NULL)
return parent->getWorldTransform() * getLocalTransform(); return parent->getWorldTransform() * getLocalTransform();
return getLocalTransform(); return getLocalTransform();
} }
}

View file

@ -37,6 +37,11 @@
#include <vector> #include <vector>
#include <cassert> #include <cassert>
#include <boost/weak_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/detail/endian.hpp>
#include <libs/platform/stdint.h> #include <libs/platform/stdint.h>
#include "record.hpp" #include "record.hpp"
@ -93,6 +98,14 @@ class NIFFile
return u.f; return u.f;
} }
class LoadedCache;
friend class LoadedCache;
// attempt to protect NIFFile from misuse...
struct psudo_private_modifier {}; // this dirty little trick should optimize out
NIFFile (NIFFile const &);
void operator = (NIFFile const &);
public: public:
/// Used for error handling /// Used for error handling
void fail(const std::string &msg) void fail(const std::string &msg)
@ -108,19 +121,21 @@ public:
<< "File: "<<filename <<std::endl; << "File: "<<filename <<std::endl;
} }
/// Open a NIF stream. The name is used for error messages. typedef boost::shared_ptr <NIFFile> ptr;
NIFFile(const std::string &name)
: filename(name)
{
inp = Ogre::ResourceGroupManager::getSingleton().openResource(name);
parse();
}
~NIFFile() /// Open a NIF stream. The name is used for error messages.
NIFFile(const std::string &name, psudo_private_modifier);
~NIFFile();
static ptr create (const std::string &name);
static void lockCache ();
static void unlockCache ();
struct CacheLock
{ {
for(std::size_t i=0; i<records.size(); i++) CacheLock () { lockCache (); }
delete records[i]; ~CacheLock () { unlockCache (); }
} };
/// Get a given record /// Get a given record
Record *getRecord(size_t index) Record *getRecord(size_t index)
@ -131,7 +146,7 @@ public:
} }
/// Number of records /// Number of records
int numRecords() { return records.size(); } size_t numRecords() { return records.size(); }
/************************************************* /*************************************************
Parser functions Parser functions

View file

@ -111,8 +111,8 @@ public:
boneIndex = ind; boneIndex = ind;
} }
Ogre::Matrix4 getLocalTransform(); Ogre::Matrix4 getLocalTransform() const;
Ogre::Matrix4 getWorldTransform(); Ogre::Matrix4 getWorldTransform() const;
}; };
struct NiNode : Node struct NiNode : Node

View file

@ -91,8 +91,9 @@ struct Record
// Record type and type name // Record type and type name
int recType; int recType;
std::string recName; std::string recName;
size_t recIndex;
Record() : recType(RC_MISSING) {} Record() : recType(RC_MISSING), recIndex(~(size_t)0) {}
/// Parses the record from file /// Parses the record from file
virtual void read(NIFFile *nif) = 0; virtual void read(NIFFile *nif) = 0;

View file

@ -51,7 +51,7 @@ ManualBulletShapeLoader::~ManualBulletShapeLoader()
} }
btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 &m) btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 const &m)
{ {
Ogre::Quaternion oquat(m); Ogre::Quaternion oquat(m);
btQuaternion quat; btQuaternion quat;
@ -62,7 +62,7 @@ btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 &m)
return quat; return quat;
} }
btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 &v) btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v)
{ {
return btVector3(v[0], v[1], v[2]); return btVector3(v[0], v[1], v[2]);
} }
@ -82,7 +82,8 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
// of the early stages of development. Right now we WANT to catch // of the early stages of development. Right now we WANT to catch
// every error as early and intrusively as possible, as it's most // every error as early and intrusively as possible, as it's most
// likely a sign of incomplete code rather than faulty input. // likely a sign of incomplete code rather than faulty input.
Nif::NIFFile nif(resourceName.substr(0, resourceName.length()-7)); Nif::NIFFile::ptr pnif (Nif::NIFFile::create (resourceName.substr(0, resourceName.length()-7)));
Nif::NIFFile & nif = *pnif.get ();
if (nif.numRecords() < 1) if (nif.numRecords() < 1)
{ {
warn("Found no records in NIF."); warn("Found no records in NIF.");
@ -138,7 +139,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
} }
} }
bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node) bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node)
{ {
if (node->recType == Nif::RC_NiNode) if (node->recType == Nif::RC_NiNode)
{ {
@ -164,8 +165,8 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node)
return false; return false;
} }
void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags,
const Nif::Transformation *trafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) const Nif::Transformation *parentTrafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly)
{ {
// Accumulate the flags from all the child nodes. This works for all // Accumulate the flags from all the child nodes. This works for all
@ -181,7 +182,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
} }
// Check for extra data // Check for extra data
Nif::Extra *e = node; Nif::Extra const *e = node;
while (!e->extra.empty()) while (!e->extra.empty())
{ {
// Get the next extra data in the list // Get the next extra data in the list
@ -208,23 +209,23 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
} }
} }
Nif::Transformation childTrafo = node->trafo;
if (trafo) if (parentTrafo)
{ {
// Get a non-const reference to the node's data, since we're // Get a non-const reference to the node's data, since we're
// overwriting it. TODO: Is this necessary? // overwriting it. TODO: Is this necessary?
Nif::Transformation &final = node->trafo;
// For both position and rotation we have that: // For both position and rotation we have that:
// final_vector = old_vector + old_rotation*new_vector*old_scale // final_vector = old_vector + old_rotation*new_vector*old_scale
final.pos = trafo->pos + trafo->rotation*final.pos*trafo->scale; childTrafo.pos = parentTrafo->pos + parentTrafo->rotation*childTrafo.pos*parentTrafo->scale;
// Merge the rotations together // Merge the rotations together
final.rotation = trafo->rotation * final.rotation; childTrafo.rotation = parentTrafo->rotation * childTrafo.rotation;
// Scale // Scale
final.scale *= trafo->scale; childTrafo.scale *= parentTrafo->scale;
} }
@ -232,7 +233,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
{ {
btVector3 boxsize = getbtVector((node->boundXYZ)); btVector3 boxsize = getbtVector(node->boundXYZ);
cShape->boxTranslation = node->boundPos; cShape->boxTranslation = node->boundPos;
cShape->boxRotation = node->boundRot; cShape->boxRotation = node->boundRot;
@ -243,20 +244,20 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
// For NiNodes, loop through children // For NiNodes, loop through children
if (node->recType == Nif::RC_NiNode) if (node->recType == Nif::RC_NiNode)
{ {
Nif::NodeList &list = ((Nif::NiNode*)node)->children; Nif::NodeList const &list = ((Nif::NiNode const *)node)->children;
int n = list.length(); int n = list.length();
for (int i=0; i<n; i++) for (int i=0; i<n; i++)
{ {
if (!list[i].empty()) if (!list[i].empty())
{ {
handleNode(list[i].getPtr(), flags,&node->trafo,hasCollisionNode,isCollisionNode,raycastingOnly); handleNode(list[i].getPtr(), flags,&childTrafo,hasCollisionNode,isCollisionNode,raycastingOnly);
} }
} }
} }
else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode))
{ {
cShape->mCollide = !(flags&0x800); cShape->mCollide = !(flags&0x800);
handleNiTriShape(dynamic_cast<Nif::NiTriShape*>(node), flags,node->trafo.rotation,node->trafo.pos,node->trafo.scale,raycastingOnly); handleNiTriShape(dynamic_cast<Nif::NiTriShape const *>(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly);
} }
else if(node->recType == Nif::RC_RootCollisionNode) else if(node->recType == Nif::RC_RootCollisionNode)
{ {
@ -265,12 +266,12 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
for (int i=0; i<n; i++) for (int i=0; i<n; i++)
{ {
if (!list[i].empty()) if (!list[i].empty())
handleNode(list[i].getPtr(), flags,&node->trafo, hasCollisionNode,true,raycastingOnly); handleNode(list[i].getPtr(), flags,&childTrafo, hasCollisionNode,true,raycastingOnly);
} }
} }
} }
void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale,
bool raycastingOnly) bool raycastingOnly)
{ {
assert(shape != NULL); assert(shape != NULL);

View file

@ -79,25 +79,25 @@ public:
void load(const std::string &name,const std::string &group); void load(const std::string &name,const std::string &group);
private: private:
btQuaternion getbtQuat(Ogre::Matrix3 &m); btQuaternion getbtQuat(Ogre::Matrix3 const &m);
btVector3 getbtVector(Ogre::Vector3 &v); btVector3 getbtVector(Ogre::Vector3 const &v);
/** /**
*Parse a node. *Parse a node.
*/ */
void handleNode(Nif::Node *node, int flags, void handleNode(Nif::Node const *node, int flags,
const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly); const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly);
/** /**
*Helper function *Helper function
*/ */
bool hasRootCollisionNode(Nif::Node* node); bool hasRootCollisionNode(Nif::Node const * node);
/** /**
*convert a NiTriShape to a bullet trishape. *convert a NiTriShape to a bullet trishape.
*/ */
void handleNiTriShape(Nif::NiTriShape *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); void handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly);
std::string resourceName; std::string resourceName;
std::string resourceGroup; std::string resourceGroup;

View file

@ -167,16 +167,16 @@ static void fail(const std::string &msg)
} }
static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector<Nif::NiKeyframeController*> &ctrls, const std::vector<std::string> &targets, float startTime, float stopTime) static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector<const Nif::NiKeyframeController*> &ctrls, const std::vector<std::string> &targets, float startTime, float stopTime)
{ {
Ogre::Animation *anim = skel->createAnimation(name, stopTime-startTime); Ogre::Animation *anim = skel->createAnimation(name, stopTime-startTime);
for(size_t i = 0;i < ctrls.size();i++) for(size_t i = 0;i < ctrls.size();i++)
{ {
Nif::NiKeyframeController *kfc = ctrls[i]; const Nif::NiKeyframeController *kfc = ctrls[i];
if(kfc->data.empty()) if(kfc->data.empty())
continue; continue;
Nif::NiKeyframeData *kf = kfc->data.getPtr(); const Nif::NiKeyframeData *kf = kfc->data.getPtr();
/* Get the keyframes and make sure they're sorted first to last */ /* Get the keyframes and make sure they're sorted first to last */
const Nif::QuaternionKeyList &quatkeys = kf->mRotations; const Nif::QuaternionKeyList &quatkeys = kf->mRotations;
@ -308,7 +308,7 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk)
} }
void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector<Nif::NiKeyframeController*> &ctrls, Ogre::Bone *parent=NULL) void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector<Nif::NiKeyframeController const*> &ctrls, Ogre::Bone *parent=NULL)
{ {
if(node->recType == Nif::RC_NiTriShape) if(node->recType == Nif::RC_NiTriShape)
return; return;
@ -377,10 +377,11 @@ void loadResource(Ogre::Resource *resource)
Ogre::Skeleton *skel = dynamic_cast<Ogre::Skeleton*>(resource); Ogre::Skeleton *skel = dynamic_cast<Ogre::Skeleton*>(resource);
OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!");
Nif::NIFFile nif(skel->getName()); Nif::NIFFile::ptr pnif(Nif::NIFFile::create (skel->getName()));
Nif::NIFFile & nif = *pnif.get ();
const Nif::Node *node = dynamic_cast<const Nif::Node*>(nif.getRecord(0)); const Nif::Node *node = dynamic_cast<const Nif::Node*>(nif.getRecord(0));
std::vector<Nif::NiKeyframeController*> ctrls; std::vector<const Nif::NiKeyframeController*> ctrls;
try { try {
buildBones(skel, node, ctrls); buildBones(skel, node, ctrls);
} }
@ -398,7 +399,7 @@ void loadResource(Ogre::Resource *resource)
float maxtime = 0.0f; float maxtime = 0.0f;
for(size_t i = 0;i < ctrls.size();i++) for(size_t i = 0;i < ctrls.size();i++)
{ {
Nif::NiKeyframeController *ctrl = ctrls[i]; const Nif::NiKeyframeController *ctrl = ctrls[i];
maxtime = std::max(maxtime, ctrl->timeStop); maxtime = std::max(maxtime, ctrl->timeStop);
Nif::Named *target = dynamic_cast<Nif::Named*>(ctrl->target.getPtr()); Nif::Named *target = dynamic_cast<Nif::Named*>(ctrl->target.getPtr());
if(target != NULL) if(target != NULL)
@ -764,9 +765,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
{ {
std::string mName; std::string mName;
std::string mGroup; std::string mGroup;
std::string mShapeName; size_t mShapeIndex;
std::string mMaterialName;
std::string mSkelName; std::string mSkelName;
std::string mMaterialName;
std::string mShapeName;
void warn(const std::string &msg) void warn(const std::string &msg)
{ {
@ -781,7 +783,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
// Convert NiTriShape to Ogre::SubMesh // Convert NiTriShape to Ogre::SubMesh
void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape *shape) void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape)
{ {
Ogre::SkeletonPtr skel; Ogre::SkeletonPtr skel;
const Nif::NiTriShapeData *data = shape->data.getPtr(); const Nif::NiTriShapeData *data = shape->data.getPtr();
@ -871,7 +873,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
Ogre::VertexDeclaration *decl; Ogre::VertexDeclaration *decl;
int nextBuf = 0; int nextBuf = 0;
Ogre::SubMesh *sub = mesh->createSubMesh(shape->name); Ogre::SubMesh *sub = ((mShapeName.length() > 0) ? mesh->createSubMesh(mShapeName) :
mesh->createSubMesh());
// Add vertices // Add vertices
sub->useSharedVertices = false; sub->useSharedVertices = false;
@ -976,18 +979,18 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
sub->setMaterialName(mMaterialName); sub->setMaterialName(mMaterialName);
} }
bool findTriShape(Ogre::Mesh *mesh, Nif::Node *node) bool findTriShape(Ogre::Mesh *mesh, Nif::Node const *node)
{ {
if(node->recType == Nif::RC_NiTriShape && mShapeName == node->name) if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex)
{ {
handleNiTriShape(mesh, dynamic_cast<Nif::NiTriShape*>(node)); handleNiTriShape(mesh, dynamic_cast<const Nif::NiTriShape*>(node));
return true; return true;
} }
Nif::NiNode *ninode = dynamic_cast<Nif::NiNode*>(node); const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
if(ninode) if(ninode)
{ {
Nif::NodeList &children = ninode->children; Nif::NodeList const &children = ninode->children;
for(size_t i = 0;i < children.length();i++) for(size_t i = 0;i < children.length();i++)
{ {
if(!children[i].empty()) if(!children[i].empty())
@ -1008,7 +1011,7 @@ public:
NIFMeshLoader() NIFMeshLoader()
{ } { }
NIFMeshLoader(const std::string &name, const std::string &group, const std::string skelName) NIFMeshLoader(const std::string &name, const std::string &group, const std::string skelName)
: mName(name), mGroup(group), mSkelName(skelName) : mName(name), mGroup(group), mShapeIndex(~(size_t)0), mSkelName(skelName)
{ } { }
virtual void loadResource(Ogre::Resource *resource) virtual void loadResource(Ogre::Resource *resource)
@ -1016,15 +1019,14 @@ public:
Ogre::Mesh *mesh = dynamic_cast<Ogre::Mesh*>(resource); Ogre::Mesh *mesh = dynamic_cast<Ogre::Mesh*>(resource);
OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!");
if(!mShapeName.length()) Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName);
if(mShapeIndex >= nif->numRecords())
{ {
if(mSkelName.length() > 0)
mesh->setSkeletonName(mSkelName); mesh->setSkeletonName(mSkelName);
return; return;
} }
Nif::NIFFile nif(mName); Nif::Node const *node = dynamic_cast<const Nif::Node*>(nif->getRecord(mShapeIndex));
Nif::Node *node = dynamic_cast<Nif::Node*>(nif.getRecord(0));
findTriShape(mesh, node); findTriShape(mesh, node);
} }
@ -1065,9 +1067,12 @@ public:
if(node->recType == Nif::RC_NiTriShape) if(node->recType == Nif::RC_NiTriShape)
{ {
const Nif::NiTriShape *shape = dynamic_cast<const Nif::NiTriShape*>(node); const Nif::NiTriShape *shape = dynamic_cast<const Nif::NiTriShape*>(node);
mShapeName = shape->name;
Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton();
std::string fullname = mName+"@shape="+shape->name; std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex);
if(mShapeName.length() > 0)
fullname += "@shape="+mShapeName;
if(mSkelName.length() > 0 && mName != mSkelName) if(mSkelName.length() > 0 && mName != mSkelName)
fullname += "@skel="+mSkelName; fullname += "@skel="+mSkelName;
@ -1079,7 +1084,7 @@ public:
*loader = *this; *loader = *this;
if(!(flags&0x01)) // Not hidden if(!(flags&0x01)) // Not hidden
{ {
loader->mShapeName = shape->name; loader->mShapeIndex = shape->recIndex;
loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup);
} }
@ -1119,18 +1124,19 @@ MeshInfoList Loader::load(const std::string &name, const std::string &skelName,
return meshiter->second; return meshiter->second;
MeshInfoList &meshes = sMeshInfoMap[name+"@skel="+skelName]; MeshInfoList &meshes = sMeshInfoMap[name+"@skel="+skelName];
Nif::NIFFile nif(name); Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name);
if (nif.numRecords() < 1) Nif::NIFFile &nif = *pnif.get();
if(nif.numRecords() < 1)
{ {
nif.warn("Found no NIF records in "+name+"."); nif.warn("Found no NIF records in "+name+".");
return meshes; return meshes;
} }
// The first record is assumed to be the root node // The first record is assumed to be the root node
Nif::Record *r = nif.getRecord(0); Nif::Record const *r = nif.getRecord(0);
assert(r != NULL); assert(r != NULL);
Nif::Node *node = dynamic_cast<Nif::Node*>(r); Nif::Node const *node = dynamic_cast<Nif::Node const *>(r);
if(node == NULL) if(node == NULL)
{ {
nif.warn("First record in "+name+" was not a node, but a "+ nif.warn("First record in "+name+" was not a node, but a "+

View file

@ -118,5 +118,5 @@ for the open-source EB Garamond fontface.
Thanks to Dongle, Thanks to Dongle,
for his Daedric fontface, see Daedric Font License.txt for his license terms. for his Daedric fontface, see Daedric Font License.txt for his license terms.
Thanks to Bitstream Inc. Thanks to DejaVu team,
for their Bitstream Vera fontface, see Bitstream Vera License.txt for their license terms. for their DejaVuLGCSansMono fontface, see Dejavu_lgc_font_license.txt for their license terms.

View file

@ -80,7 +80,7 @@ set(MYGUI_FILES
openmw_travel_window.layout openmw_travel_window.layout
openmw_persuasion_dialog.layout openmw_persuasion_dialog.layout
smallbars.png smallbars.png
VeraMono.ttf DejaVuLGCSansMono.ttf
markers.png markers.png
) )

Binary file not shown.

Binary file not shown.

View file

@ -35,7 +35,7 @@
</Resource> </Resource>
<Resource type="ResourceTrueTypeFont" name="MonoFont"> <Resource type="ResourceTrueTypeFont" name="MonoFont">
<Property key="Source" value="VeraMono.ttf"/> <Property key="Source" value="DejaVuLGCSansMono.ttf"/>
<Property key="Size" value="18"/> <Property key="Size" value="18"/>
<Property key="Resolution" value="50"/> <Property key="Resolution" value="50"/>
<Property key="Antialias" value="false"/> <Property key="Antialias" value="false"/>