1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-04-01 07:06:43 +00:00

Merge branch 'master' into saveOnClose

This commit is contained in:
graffy76 2013-03-02 09:24:42 -06:00
commit 9193ddc9d3
161 changed files with 4224 additions and 5385 deletions

View file

@ -74,7 +74,6 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)
set(OENGINE_OGRE set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/renderer.cpp
${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/fader.cpp
${LIBDIR}/openengine/ogre/imagerotate.cpp
${LIBDIR}/openengine/ogre/selectionbuffer.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp
) )
set(OENGINE_GUI set(OENGINE_GUI
@ -94,8 +93,6 @@ set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/physic.hpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.h ${LIBDIR}/openengine/bullet/BulletShapeLoader.h
${LIBDIR}/openengine/bullet/pmove.cpp
${LIBDIR}/openengine/bullet/pmove.h
${LIBDIR}/openengine/bullet/trace.cpp ${LIBDIR}/openengine/bullet/trace.cpp
${LIBDIR}/openengine/bullet/trace.h ${LIBDIR}/openengine/bullet/trace.h
@ -299,7 +296,7 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg.install") "${OpenMW_BINARY_DIR}/openmw.cfg.install")
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (NOT WIN32 AND NOT APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
"${OpenMW_BINARY_DIR}/openmw.desktop") "${OpenMW_BINARY_DIR}/openmw.desktop")
endif() endif()
@ -380,7 +377,7 @@ if(WIN32)
"${OpenMW_SOURCE_DIR}/readme.txt" "${OpenMW_SOURCE_DIR}/readme.txt"
"${OpenMW_SOURCE_DIR}/GPL3.txt" "${OpenMW_SOURCE_DIR}/GPL3.txt"
"${OpenMW_SOURCE_DIR}/OFL.txt" "${OpenMW_SOURCE_DIR}/OFL.txt"
"${OpenMW_SOURCE_DIR}/Bitstream Vera License.txt" "${OpenMW_SOURCE_DIR}/DejaVu Font License.txt"
"${OpenMW_SOURCE_DIR}/Daedric Font License.txt" "${OpenMW_SOURCE_DIR}/Daedric Font License.txt"
"${OpenMW_BINARY_DIR}/launcher.qss" "${OpenMW_BINARY_DIR}/launcher.qss"
"${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/settings-default.cfg"
@ -391,7 +388,7 @@ if(WIN32)
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
SET(CPACK_GENERATOR "NSIS") SET(CPACK_GENERATOR "NSIS")
SET(CPACK_PACKAGE_NAME "OpenMW ${OPENMW_VERSION}") SET(CPACK_PACKAGE_NAME "OpenMW")
SET(CPACK_PACKAGE_VENDOR "OpenMW.org") SET(CPACK_PACKAGE_VENDOR "OpenMW.org")
SET(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) SET(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
@ -406,7 +403,7 @@ if(WIN32)
SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/readme.txt") SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/readme.txt")
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt")
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
SET(CPACK_NSIS_DISPLAY_NAME "OpenMW") SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}")
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe") SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe")
@ -529,6 +526,8 @@ if (WIN32)
set(WARNINGS "${WARNINGS} /wd${d}") set(WARNINGS "${WARNINGS} /wd${d}")
endforeach(d) endforeach(d)
set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS})
if (BUILD_LAUNCHER) if (BUILD_LAUNCHER)
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
@ -657,10 +656,18 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE)
# Install binaries # Install binaries
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) IF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" )
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) ENDIF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) IF(BUILD_ESMTOOL)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" )
ENDIF(BUILD_ESMTOOL)
IF(BUILD_MWINIIMPORTER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" )
ENDIF(BUILD_MWINIIMPORTER)
IF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" )
ENDIF(BUILD_OPENCS)
# Install icon and .desktop # Install icon and .desktop
INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "${ICONDIR}") INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "${ICONDIR}")
@ -674,5 +681,7 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE)
# Install resources # Install resources
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" ) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" )
INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" ) IF(BUILD_LAUNCHER)
INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" )
ENDIF(BUILD_LAUNCHER)
endif(NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) endif(NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE)

View file

@ -20,6 +20,7 @@ void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_i
getData().loadFile (*end2, false); getData().loadFile (*end2, false);
addOptionalGmsts(); addOptionalGmsts();
addOptionalGlobals();
} }
void CSMDoc::Document::addOptionalGmsts() void CSMDoc::Document::addOptionalGmsts()
@ -139,6 +140,26 @@ void CSMDoc::Document::addOptionalGmsts()
} }
} }
void CSMDoc::Document::addOptionalGlobals()
{
static const char *sGlobals[] =
{
"dayspassed",
"pcwerewolf",
"pcyear",
0
};
for (int i=0; sGlobals[i]; ++i)
{
ESM::Global global;
global.mId = sGlobals[i];
global.mType = ESM::VT_Int;
global.mValue = 0;
addOptionalGlobal (global);
}
}
void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst)
{ {
if (getData().getGmsts().searchId (gmst.mId)==-1) if (getData().getGmsts().searchId (gmst.mId)==-1)
@ -150,6 +171,17 @@ void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst)
} }
} }
void CSMDoc::Document::addOptionalGlobal (const ESM::Global& global)
{
if (getData().getGlobals().searchId (global.mId)==-1)
{
CSMWorld::Record<ESM::Global> record;
record.mBase = global;
record.mState = CSMWorld::RecordBase::State_BaseOnly;
getData().getGlobals().appendRecord (record);
}
}
void CSMDoc::Document::createBase() void CSMDoc::Document::createBase()
{ {
static const char *sGlobals[] = static const char *sGlobals[] =

View file

@ -20,6 +20,7 @@ class QAbstractItemModel;
namespace ESM namespace ESM
{ {
struct GameSetting; struct GameSetting;
struct Global;
} }
namespace CSMDoc namespace CSMDoc
@ -53,8 +54,12 @@ namespace CSMDoc
void addOptionalGmsts(); void addOptionalGmsts();
void addOptionalGlobals();
void addOptionalGmst (const ESM::GameSetting& gmst); void addOptionalGmst (const ESM::GameSetting& gmst);
void addOptionalGlobal (const ESM::Global& global);
public: public:
Document (const std::vector<boost::filesystem::path>& files, bool new_); Document (const std::vector<boost::filesystem::path>& files, bool new_);

View file

@ -171,7 +171,7 @@ namespace CSMWorld
record2.mModified = record; record2.mModified = record;
mRecords.push_back (record2); mRecords.push_back (record2);
mIndex.insert (std::make_pair (id, mRecords.size()-1)); mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), mRecords.size()-1));
} }
else else
{ {
@ -306,7 +306,7 @@ namespace CSMWorld
void IdCollection<ESXRecordT>::appendRecord (const RecordBase& record) void IdCollection<ESXRecordT>::appendRecord (const RecordBase& record)
{ {
mRecords.push_back (dynamic_cast<const Record<ESXRecordT>&> (record)); mRecords.push_back (dynamic_cast<const Record<ESXRecordT>&> (record));
mIndex.insert (std::make_pair (getId (record), mRecords.size()-1)); mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (getId (record)), mRecords.size()-1));
} }
template<typename ESXRecordT> template<typename ESXRecordT>

View file

@ -16,7 +16,7 @@ CSVDoc::Operations::Operations()
widgetContainer->setLayout (mLayout); widgetContainer->setLayout (mLayout);
setWidget (widgetContainer); setWidget (widgetContainer);
setVisible (false);
setFixedHeight (widgetContainer->height()); setFixedHeight (widgetContainer->height());
setTitleBarWidget (new QWidget (this)); setTitleBarWidget (new QWidget (this));
} }
@ -42,6 +42,8 @@ void CSVDoc::Operations::setProgress (int current, int max, int type, int thread
if ( oldCount > 0) if ( oldCount > 0)
setFixedHeight (height()/oldCount * newCount); setFixedHeight (height()/oldCount * newCount);
setVisible (true);
} }
void CSVDoc::Operations::quitOperation (int type) void CSVDoc::Operations::quitOperation (int type)
@ -59,6 +61,8 @@ void CSVDoc::Operations::quitOperation (int type)
if (oldCount > 1) if (oldCount > 1)
setFixedHeight (height() / oldCount * newCount); setFixedHeight (height() / oldCount * newCount);
else
setVisible (false);
break; break;
} }

View file

@ -242,7 +242,6 @@ void CSVDoc::View::addGmstsSubView()
void CSVDoc::View::abortOperation (int type) void CSVDoc::View::abortOperation (int type)
{ {
mDocument->abortOperation (type); mDocument->abortOperation (type);
mOperations->quitOperation (type);
updateActions(); updateActions();
} }

View file

@ -14,8 +14,8 @@ set(GAME_HEADER
source_group(game FILES ${GAME} ${GAME_HEADER}) source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderingmanager debugging sky player animation npcanimation creatureanimation activatoranimation
renderinginterface localmap occlusionquery terrain terrainmaterial water shadows actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows
compositors characterpreview externalrendering globalmap videoplayer compositors characterpreview externalrendering globalmap videoplayer
) )
@ -26,11 +26,11 @@ add_openmw_dir (mwinput
add_openmw_dir (mwgui add_openmw_dir (mwgui
text_input widgets race class birth review windowmanagerimp console dialogue text_input widgets race class birth review windowmanagerimp console dialogue
dialogue_history window_base stats_window messagebox journalwindow charactercreation dialogue_history window_base stats_window messagebox journalwindow charactercreation
map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list map_window window_pinnable_base tooltips scrollwindow bookwindow list
formatting inventorywindow container hud countdialog tradewindow settingswindow formatting inventorywindow container hud countdialog tradewindow settingswindow
confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor
) )
add_openmw_dir (mwdialogue add_openmw_dir (mwdialogue
@ -62,8 +62,9 @@ add_openmw_dir (mwclass
) )
add_openmw_dir (mwmechanics add_openmw_dir (mwmechanics
mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators
activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
aiescort aiactivate
) )
add_openmw_dir (mwbase add_openmw_dir (mwbase

View file

@ -9,6 +9,7 @@
#include <components/bsa/bsa_archive.hpp> #include <components/bsa/bsa_archive.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/translation/translation.hpp> #include <components/translation/translation.hpp>
#include <components/nif/nif_file.hpp>
#include <components/nifoverrides/nifoverrides.hpp> #include <components/nifoverrides/nifoverrides.hpp>
#include <components/nifbullet/bullet_nif_loader.hpp> #include <components/nifbullet/bullet_nif_loader.hpp>
@ -17,7 +18,6 @@
#include "mwinput/inputmanagerimp.hpp" #include "mwinput/inputmanagerimp.hpp"
#include "mwgui/windowmanagerimp.hpp" #include "mwgui/windowmanagerimp.hpp"
#include "mwgui/cursorreplace.hpp"
#include "mwscript/scriptmanagerimp.hpp" #include "mwscript/scriptmanagerimp.hpp"
#include "mwscript/extensions.hpp" #include "mwscript/extensions.hpp"
@ -66,14 +66,15 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
{ {
try try
{ {
mEnvironment.setFrameDuration (evt.timeSinceLastFrame); float frametime = std::min(evt.timeSinceLastFrame, 0.2f);
mEnvironment.setFrameDuration(frametime);
// update input // update input
MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame, false); MWBase::Environment::get().getInputManager()->update(frametime, false);
// sound // sound
if (mUseSound) if (mUseSound)
MWBase::Environment::get().getSoundManager()->update (evt.timeSinceLastFrame); MWBase::Environment::get().getSoundManager()->update(frametime);
// global scripts // global scripts
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
@ -87,23 +88,19 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
// passing of time // passing of time
if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
MWBase::Environment::get().getWorld()->advanceTime ( MWBase::Environment::get().getWorld()->advanceTime(
mEnvironment.getFrameDuration()*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
if (changed) // keep change flag for another frame, if cell changed happend in local script if (changed) // keep change flag for another frame, if cell changed happend in local script
MWBase::Environment::get().getWorld()->markCellAsUnchanged(); MWBase::Environment::get().getWorld()->markCellAsUnchanged();
// update actors // update actors
std::vector<std::pair<std::string, Ogre::Vector3> > movement; MWBase::Environment::get().getMechanicsManager()->update(frametime,
MWBase::Environment::get().getMechanicsManager()->update (movement, mEnvironment.getFrameDuration(),
MWBase::Environment::get().getWindowManager()->isGuiMode()); MWBase::Environment::get().getWindowManager()->isGuiMode());
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
MWBase::Environment::get().getWorld()->doPhysics (movement, mEnvironment.getFrameDuration());
// update world // update world
MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame, MWBase::Environment::get().getWindowManager()->isGuiMode()); MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode());
// update GUI // update GUI
Ogre::RenderWindow* window = mOgre->getWindow(); Ogre::RenderWindow* window = mOgre->getWindow();
@ -111,7 +108,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch);
MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch);
MWBase::Environment::get().getWindowManager()->onFrame(evt.timeSinceLastFrame); MWBase::Environment::get().getWindowManager()->onFrame(frametime);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -335,9 +332,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
loadBSA(); loadBSA();
// cursor replacer (converts the cursor from the bsa so they can be used by mygui)
MWGui::CursorReplace replacer;
// Create the world // Create the world
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins,
mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap,

View file

@ -37,24 +37,24 @@ namespace MWBase
virtual ~MechanicsManager() {} virtual ~MechanicsManager() {}
virtual void addActor (const MWWorld::Ptr& ptr) = 0; virtual void add (const MWWorld::Ptr& ptr) = 0;
///< Register an actor for stats management ///< Register an object for management
///
/// \note Dead actors are ignored.
virtual void removeActor (const MWWorld::Ptr& ptr) = 0; virtual void remove (const MWWorld::Ptr& ptr) = 0;
///< Deregister an actor for stats management ///< Deregister an object for management
virtual void dropActors (const MWWorld::CellStore *cellStore) = 0; virtual void updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) = 0;
///< Deregister all actors in the given cell. ///< Moves an object to a new cell
virtual void drop (const MWWorld::CellStore *cellStore) = 0;
///< Deregister all objects in the given cell.
virtual void watchActor (const MWWorld::Ptr& ptr) = 0; virtual void watchActor (const MWWorld::Ptr& ptr) = 0;
///< On each update look for changes in a previously registered actor and update the ///< On each update look for changes in a previously registered actor and update the
/// GUI accordingly. /// GUI accordingly.
virtual void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement, virtual void update (float duration, bool paused) = 0;
float duration, bool paused) = 0; ///< Update objects
///< Update actor stats and store desired velocity vectors in \a movement
/// ///
/// \param paused In game type does not currently advance (this usually means some GUI /// \param paused In game type does not currently advance (this usually means some GUI
/// component is up). /// component is up).
@ -98,6 +98,17 @@ namespace MWBase
virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type,
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0;
///< Perform a persuasion action on NPC ///< Perform a persuasion action on NPC
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0;
///< Run animation for a MW-reference. Calls to this function for references that are currently not
/// in the scene should be ignored.
///
/// \param mode 0 normal, 1 immediate start, 2 immediate loop
/// \param count How many times the animation should be run
virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0;
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
/// references that are currently not in the scene should be ignored.
}; };
} }

View file

@ -198,7 +198,7 @@ namespace MWBase
virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0; virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0;
///< Hides dialog and schedules dialog to be deleted. ///< Hides dialog and schedules dialog to be deleted.
virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons) = 0; virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>()) = 0;
virtual void enterPressed () = 0; virtual void enterPressed () = 0;
virtual int readPressedButton() = 0; virtual int readPressedButton() = 0;
///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)

View file

@ -6,6 +6,7 @@
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include "../mwworld/globals.hpp" #include "../mwworld/globals.hpp"
#include "../mwworld/ptr.hpp"
namespace Ogre namespace Ogre
{ {
@ -19,6 +20,11 @@ namespace OEngine
{ {
class Fader; class Fader;
} }
namespace Physic
{
class PhysicEngine;
}
} }
namespace ESM namespace ESM
@ -35,6 +41,7 @@ namespace ESM
namespace MWRender namespace MWRender
{ {
class ExternalRendering; class ExternalRendering;
class Animation;
} }
namespace MWWorld namespace MWWorld
@ -42,10 +49,11 @@ namespace MWWorld
class CellStore; class CellStore;
class Player; class Player;
class LocalScripts; class LocalScripts;
class Ptr;
class TimeStamp; class TimeStamp;
class ESMStore; class ESMStore;
class RefData; class RefData;
typedef std::vector<std::pair<MWWorld::Ptr,Ogre::Vector3> > PtrMovementList;
} }
namespace MWBase namespace MWBase
@ -227,8 +235,7 @@ namespace MWBase
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0; virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0;
///< Convert position to cell numbers ///< Convert position to cell numbers
virtual void doPhysics (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors, virtual void doPhysics (const MWWorld::PtrMovementList &actors, float duration) = 0;
float duration) = 0;
///< Run physics simulation and modify \a world accordingly. ///< Run physics simulation and modify \a world accordingly.
virtual bool toggleCollisionMode() = 0; virtual bool toggleCollisionMode() = 0;
@ -263,18 +270,6 @@ namespace MWBase
///< Create a new recrod (of type npc) in the ESM store. ///< Create a new recrod (of type npc) in the ESM store.
/// \return pointer to created record /// \return pointer to created record
virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName,
int mode, int number = 1) = 0;
///< Run animation for a MW-reference. Calls to this function for references that are
/// currently not in the rendered scene should be ignored.
///
/// \param mode: 0 normal, 1 immediate start, 2 immediate loop
/// \param number How offen the animation should be run
virtual void skipAnimation (const MWWorld::Ptr& ptr) = 0;
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
/// references that are currently not in the rendered scene should be ignored.
virtual void update (float duration, bool paused) = 0; virtual void update (float duration, bool paused) = 0;
virtual bool placeObject(const MWWorld::Ptr& object, float cursorX, float cursorY) = 0; virtual bool placeObject(const MWWorld::Ptr& object, float cursorX, float cursorY) = 0;
@ -291,8 +286,10 @@ namespace MWBase
virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0;
virtual bool isSwimming(const MWWorld::Ptr &object) = 0; virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0;
virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
virtual void togglePOV() = 0; virtual void togglePOV() = 0;
virtual void togglePreviewMode(bool enable) = 0; virtual void togglePreviewMode(bool enable) = 0;
@ -311,6 +308,8 @@ namespace MWBase
/// 2 - player is underwater \n /// 2 - player is underwater \n
/// 3 - enemies are nearby (not implemented) /// 3 - enemies are nearby (not implemented)
/// \todo Probably shouldn't be here
virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0;
/// \todo this does not belong here /// \todo this does not belong here
virtual void playVideo(const std::string& name, bool allowSkipping) = 0; virtual void playVideo(const std::string& name, bool allowSkipping) = 0;

View file

@ -5,12 +5,13 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld//cellstore.hpp" #include "../mwworld//cellstore.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwrender/objects.hpp" #include "../mwrender/actors.hpp"
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
@ -21,9 +22,8 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if (!model.empty()) { if (!model.empty()) {
MWRender::Objects& objects = renderingInterface.getObjects(); MWRender::Actors& actors = renderingInterface.getActors();
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); actors.insertActivator(ptr);
objects.insertMesh(ptr, model);
} }
} }
@ -32,6 +32,7 @@ namespace MWClass
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr);
MWBase::Environment::get().getMechanicsManager()->add(ptr);
} }
std::string Activator::getModel(const MWWorld::Ptr &ptr) const std::string Activator::getModel(const MWWorld::Ptr &ptr) const

View file

@ -18,6 +18,7 @@
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
#include "../mwrender/actors.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
@ -96,7 +97,7 @@ namespace MWClass
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addActor(ptr); physics.addActor(ptr);
MWBase::Environment::get().getMechanicsManager()->addActor (ptr); MWBase::Environment::get().getMechanicsManager()->add(ptr);
} }
std::string Creature::getModel(const MWWorld::Ptr &ptr) const std::string Creature::getModel(const MWWorld::Ptr &ptr) const

View file

@ -1,9 +1,7 @@
#ifndef GAME_MWCLASS_CREATURE_H #ifndef GAME_MWCLASS_CREATURE_H
#define GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H
#include "../mwrender/renderinginterface.hpp" #include "../mwworld/class.hpp"
#include "../mwrender/actors.hpp"
namespace MWClass namespace MWClass
{ {

View file

@ -36,14 +36,9 @@ namespace MWClass
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
if (!model.empty()) if (!model.empty())
objects.insertMesh(ptr, "meshes\\" + model); objects.insertMesh(ptr, "meshes\\" + model, true);
else
const int color = ref->mBase->mData.mColor; objects.insertLight(ptr);
const float r = ((color >> 0) & 0xFF) / 255.0f;
const float g = ((color >> 8) & 0xFF) / 255.0f;
const float b = ((color >> 16) & 0xFF) / 255.0f;
const float radius = float (ref->mBase->mData.mRadius);
objects.insertLight (ptr, r, g, b, radius);
} }
void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const

View file

@ -55,9 +55,35 @@ namespace MWClass
{ {
void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const
{ {
static bool inited = false;
if(!inited)
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
fMinWalkSpeed = gmst.find("fMinWalkSpeed");
fMaxWalkSpeed = gmst.find("fMaxWalkSpeed");
fEncumberedMoveEffect = gmst.find("fEncumberedMoveEffect");
fSneakSpeedMultiplier = gmst.find("fSneakSpeedMultiplier");
fAthleticsRunBonus = gmst.find("fAthleticsRunBonus");
fBaseRunMultiplier = gmst.find("fBaseRunMultiplier");
fMinFlySpeed = gmst.find("fMinFlySpeed");
fMaxFlySpeed = gmst.find("fMaxFlySpeed");
fSwimRunBase = gmst.find("fSwimRunBase");
fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult");
fJumpEncumbranceBase = gmst.find("fJumpEncumbranceBase");
fJumpEncumbranceMultiplier = gmst.find("fJumpEncumbranceMultiplier");
fJumpAcrobaticsBase = gmst.find("fJumpAcrobaticsBase");
fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier");
fJumpRunMultiplier = gmst.find("fJumpRunMultiplier");
// Added in Tribunal/Bloodmoon, may not exist
fWereWolfRunMult = gmst.search("fWereWolfRunMult");
inited = true;
}
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
{ {
std::auto_ptr<CustomData> data (new CustomData); std::auto_ptr<CustomData> data(new CustomData);
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>(); MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
@ -142,7 +168,7 @@ namespace MWClass
void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
{ {
physics.addActor(ptr); physics.addActor(ptr);
MWBase::Environment::get().getMechanicsManager()->addActor(ptr); MWBase::Environment::get().getMechanicsManager()->add(ptr);
} }
std::string Npc::getModel(const MWWorld::Ptr &ptr) const std::string Npc::getModel(const MWWorld::Ptr &ptr) const
@ -297,9 +323,88 @@ namespace MWClass
return false; return false;
} }
float Npc::getSpeed (const MWWorld::Ptr& ptr) const float Npc::getSpeed(const MWWorld::Ptr& ptr) const
{ {
return getStance (ptr, Run) ? 600 : 300; // TODO calculate these values from stats const MWBase::World *world = MWBase::Environment::get().getWorld();
const CustomData *npcdata = static_cast<const CustomData*>(ptr.getRefData().getCustomData());
const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects();
const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr);
float walkSpeed = fMinWalkSpeed->getFloat() + 0.01f*npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified()*
(fMaxWalkSpeed->getFloat() - fMinWalkSpeed->getFloat());
walkSpeed *= 1.0f - fEncumberedMoveEffect->getFloat()*normalizedEncumbrance;
walkSpeed = std::max(0.0f, walkSpeed);
if(Npc::getStance(ptr, Sneak, false))
walkSpeed *= fSneakSpeedMultiplier->getFloat();
float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() *
fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat());
if(npcdata->mNpcStats.isWerewolf())
runSpeed *= fWereWolfRunMult->getFloat();
float moveSpeed;
if(normalizedEncumbrance >= 1.0f)
moveSpeed = 0.0f;
else if(mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0)
{
float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() +
mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude);
flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat());
flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
flySpeed = std::max(0.0f, flySpeed);
moveSpeed = flySpeed;
}
else if(world->isSwimming(ptr))
{
float swimSpeed = walkSpeed;
if(Npc::getStance(ptr, Run, false))
swimSpeed = runSpeed;
swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1/*swift swim*/)).mMagnitude;
swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()*
fSwimRunAthleticsMult->getFloat();
moveSpeed = swimSpeed;
}
else if(Npc::getStance(ptr, Run, false))
moveSpeed = runSpeed;
else
moveSpeed = walkSpeed;
if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0)
moveSpeed *= 0.75f;
return moveSpeed;
}
float Npc::getJump(const MWWorld::Ptr &ptr) const
{
const CustomData *npcdata = static_cast<const CustomData*>(ptr.getRefData().getCustomData());
const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects();
const float encumbranceTerm = fJumpEncumbranceBase->getFloat() +
fJumpEncumbranceMultiplier->getFloat() *
(1.0f - Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr));
float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified();
float b = 0.0f;
if(a > 50.0f)
{
b = a - 50.0f;
a = 50.0f;
}
float x = fJumpAcrobaticsBase->getFloat() +
std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat());
x += 3 * b * fJumpAcroMultiplier->getFloat();
x += mageffects.get(MWMechanics::EffectKey(9/*jump*/)).mMagnitude * 64;
x *= encumbranceTerm;
if(Npc::getStance(ptr, Run, false))
x *= fJumpRunMultiplier->getFloat();
x *= 1.25f;//fatigueTerm;
x -= -627.2/*gravity constant*/;
x /= 3;
return x;
} }
MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const
@ -311,14 +416,10 @@ namespace MWClass
Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const
{ {
Ogre::Vector3 vector (0, 0, 0); Ogre::Vector3 vector;
vector.x = getMovementSettings(ptr).mLeftRight;
vector.x = getMovementSettings (ptr).mLeftRight * 127; vector.y = getMovementSettings(ptr).mForwardBackward;
vector.y = getMovementSettings (ptr).mForwardBackward * 127; vector.z = getMovementSettings(ptr).mUpDown;
vector.z = getMovementSettings(ptr).mUpDown * 127;
//if (getStance (ptr, Run, false))
// vector *= 2;
return vector; return vector;
} }
@ -420,4 +521,21 @@ namespace MWClass
return MWWorld::Ptr(&cell.mNpcs.insert(*ref), &cell); return MWWorld::Ptr(&cell.mNpcs.insert(*ref), &cell);
} }
const ESM::GameSetting *Npc::fMinWalkSpeed;
const ESM::GameSetting *Npc::fMaxWalkSpeed;
const ESM::GameSetting *Npc::fEncumberedMoveEffect;
const ESM::GameSetting *Npc::fSneakSpeedMultiplier;
const ESM::GameSetting *Npc::fAthleticsRunBonus;
const ESM::GameSetting *Npc::fBaseRunMultiplier;
const ESM::GameSetting *Npc::fMinFlySpeed;
const ESM::GameSetting *Npc::fMaxFlySpeed;
const ESM::GameSetting *Npc::fSwimRunBase;
const ESM::GameSetting *Npc::fSwimRunAthleticsMult;
const ESM::GameSetting *Npc::fJumpEncumbranceBase;
const ESM::GameSetting *Npc::fJumpEncumbranceMultiplier;
const ESM::GameSetting *Npc::fJumpAcrobaticsBase;
const ESM::GameSetting *Npc::fJumpAcroMultiplier;
const ESM::GameSetting *Npc::fJumpRunMultiplier;
const ESM::GameSetting *Npc::fWereWolfRunMult;
} }

View file

@ -3,6 +3,11 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
namespace ESM
{
class GameSetting;
}
namespace MWClass namespace MWClass
{ {
class Npc : public MWWorld::Class class Npc : public MWWorld::Class
@ -12,6 +17,23 @@ namespace MWClass
virtual MWWorld::Ptr virtual MWWorld::Ptr
copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const;
static const ESM::GameSetting *fMinWalkSpeed;
static const ESM::GameSetting *fMaxWalkSpeed;
static const ESM::GameSetting *fEncumberedMoveEffect;
static const ESM::GameSetting *fSneakSpeedMultiplier;
static const ESM::GameSetting *fAthleticsRunBonus;
static const ESM::GameSetting *fBaseRunMultiplier;
static const ESM::GameSetting *fMinFlySpeed;
static const ESM::GameSetting *fMaxFlySpeed;
static const ESM::GameSetting *fSwimRunBase;
static const ESM::GameSetting *fSwimRunAthleticsMult;
static const ESM::GameSetting *fJumpEncumbranceBase;
static const ESM::GameSetting *fJumpEncumbranceMultiplier;
static const ESM::GameSetting *fJumpAcrobaticsBase;
static const ESM::GameSetting *fJumpAcroMultiplier;
static const ESM::GameSetting *fJumpRunMultiplier;
static const ESM::GameSetting *fWereWolfRunMult;
public: public:
virtual std::string getId (const MWWorld::Ptr& ptr) const; virtual std::string getId (const MWWorld::Ptr& ptr) const;
@ -64,6 +86,9 @@ namespace MWClass
virtual float getSpeed (const MWWorld::Ptr& ptr) const; virtual float getSpeed (const MWWorld::Ptr& ptr) const;
///< Return movement speed. ///< Return movement speed.
virtual float getJump(const MWWorld::Ptr &ptr) const;
///< Return jump velocity (not accounting for movement)
virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const;
///< Return desired movement. ///< Return desired movement.

View file

@ -2,6 +2,7 @@
#include "dialoguemanagerimp.hpp" #include "dialoguemanagerimp.hpp"
#include <cctype> #include <cctype>
#include <cstdlib>
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
@ -251,8 +252,12 @@ namespace MWDialogue
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
if (const ESM::DialInfo *info = filter.search (dialogue, true)) std::vector<const ESM::DialInfo *> infos = filter.list (dialogue, true, true);
if (!infos.empty())
{ {
const ESM::DialInfo* info = infos[std::rand() % infos.size()];
parseText (info->mResponse); parseText (info->mResponse);
if (dialogue.mType==ESM::Dialogue::Persuasion) if (dialogue.mType==ESM::Dialogue::Persuasion)

View file

@ -289,7 +289,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
case SelectWrapper::Function_PcGender: case SelectWrapper::Function_PcGender:
return player.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female ? 0 : 1; return player.get<ESM::NPC>()->mBase->isMale() ? 0 : 1;
case SelectWrapper::Function_PcClothingModifier: case SelectWrapper::Function_PcClothingModifier:
{ {
@ -559,8 +559,21 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo
: mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) : mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer)
{} {}
const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const
{ {
std::vector<const ESM::DialInfo *> suitableInfos = list (dialogue, fallbackToInfoRefusal, false);
if (suitableInfos.empty())
return NULL;
else
return suitableInfos[0];
}
std::vector<const ESM::DialInfo *> MWDialogue::Filter::list (const ESM::Dialogue& dialogue,
bool fallbackToInfoRefusal, bool searchAll) const
{
std::vector<const ESM::DialInfo *> infos;
bool infoRefusal = false; bool infoRefusal = false;
// Iterate over topic responses to find a matching one // Iterate over topic responses to find a matching one
@ -569,14 +582,17 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue,
{ {
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter))
{ {
if (testDisposition (*iter)) if (testDisposition (*iter)) {
return &*iter; infos.push_back(&*iter);
if (!searchAll)
break;
}
else else
infoRefusal = true; infoRefusal = true;
} }
} }
if (infoRefusal && fallbackToInfoRefusal) if (infos.empty() && infoRefusal && fallbackToInfoRefusal)
{ {
// No response is valid because of low NPC disposition, // No response is valid because of low NPC disposition,
// search a response in the topic "Info Refusal" // search a response in the topic "Info Refusal"
@ -588,11 +604,14 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue,
for (std::vector<ESM::DialInfo>::const_iterator iter = infoRefusalDialogue.mInfo.begin(); for (std::vector<ESM::DialInfo>::const_iterator iter = infoRefusalDialogue.mInfo.begin();
iter!=infoRefusalDialogue.mInfo.end(); ++iter) iter!=infoRefusalDialogue.mInfo.end(); ++iter)
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) {
return &*iter; infos.push_back(&*iter);
if (!searchAll)
break;
}
} }
return 0; return infos;
} }
bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const

View file

@ -1,6 +1,8 @@
#ifndef GAME_MWDIALOGUE_FILTER_H #ifndef GAME_MWDIALOGUE_FILTER_H
#define GAME_MWDIALOGUE_FILTER_H #define GAME_MWDIALOGUE_FILTER_H
#include <vector>
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
namespace ESM namespace ESM
@ -51,7 +53,10 @@ namespace MWDialogue
Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
const ESM::DialInfo *search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; std::vector<const ESM::DialInfo *> list (const ESM::Dialogue& dialogue,
bool fallbackToInfoRefusal, bool searchAll) const;
const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const;
///< Get a matching response for the requested dialogue. ///< Get a matching response for the requested dialogue.
/// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition. /// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition.

View file

@ -25,7 +25,7 @@ bool sortBirthSigns(const std::pair<std::string, const ESM::BirthSign*>& left, c
} }
BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager)
: WindowBase("openmw_chargen_birth.layout", parWindowManager) : WindowModal("openmw_chargen_birth.layout", parWindowManager)
{ {
// Centre dialog // Centre dialog
center(); center();
@ -66,7 +66,7 @@ void BirthDialog::setNextButtonShow(bool shown)
void BirthDialog::open() void BirthDialog::open()
{ {
WindowBase::open(); WindowModal::open();
updateBirths(); updateBirths();
updateSpells(); updateSpells();
} }

View file

@ -10,7 +10,7 @@
namespace MWGui namespace MWGui
{ {
class BirthDialog : public WindowBase class BirthDialog : public WindowModal
{ {
public: public:
BirthDialog(MWBase::WindowManager& parWindowManager); BirthDialog(MWBase::WindowManager& parWindowManager);

View file

@ -21,7 +21,7 @@ using namespace MWGui;
/* GenerateClassResultDialog */ /* GenerateClassResultDialog */
GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parWindowManager) GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parWindowManager)
: WindowBase("openmw_chargen_generate_class_result.layout", parWindowManager) : WindowModal("openmw_chargen_generate_class_result.layout", parWindowManager)
{ {
// Centre dialog // Centre dialog
center(); center();
@ -68,7 +68,7 @@ void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender)
/* PickClassDialog */ /* PickClassDialog */
PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager)
: WindowBase("openmw_chargen_class.layout", parWindowManager) : WindowModal("openmw_chargen_class.layout", parWindowManager)
{ {
// Centre dialog // Centre dialog
center(); center();
@ -122,6 +122,7 @@ void PickClassDialog::setNextButtonShow(bool shown)
void PickClassDialog::open() void PickClassDialog::open()
{ {
WindowModal::open ();
updateClasses(); updateClasses();
updateStats(); updateStats();
} }
@ -276,7 +277,7 @@ void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin)
} }
InfoBoxDialog::InfoBoxDialog(MWBase::WindowManager& parWindowManager) InfoBoxDialog::InfoBoxDialog(MWBase::WindowManager& parWindowManager)
: WindowBase("openmw_infobox.layout", parWindowManager) : WindowModal("openmw_infobox.layout", parWindowManager)
, mCurrentButton(-1) , mCurrentButton(-1)
{ {
getWidget(mTextBox, "TextBox"); getWidget(mTextBox, "TextBox");
@ -327,6 +328,7 @@ void InfoBoxDialog::setButtons(ButtonList &buttons)
void InfoBoxDialog::open() void InfoBoxDialog::open()
{ {
WindowModal::open();
// Fix layout // Fix layout
layoutVertically(mTextBox, 4); layoutVertically(mTextBox, 4);
layoutVertically(mButtonBar, 6); layoutVertically(mButtonBar, 6);
@ -373,7 +375,7 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager)
/* CreateClassDialog */ /* CreateClassDialog */
CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager)
: WindowBase("openmw_chargen_create_class.layout", parWindowManager) : WindowModal("openmw_chargen_create_class.layout", parWindowManager)
, mSpecDialog(nullptr) , mSpecDialog(nullptr)
, mAttribDialog(nullptr) , mAttribDialog(nullptr)
, mSkillDialog(nullptr) , mSkillDialog(nullptr)

View file

@ -12,7 +12,7 @@
namespace MWGui namespace MWGui
{ {
class InfoBoxDialog : public WindowBase class InfoBoxDialog : public WindowModal
{ {
public: public:
InfoBoxDialog(MWBase::WindowManager& parWindowManager); InfoBoxDialog(MWBase::WindowManager& parWindowManager);
@ -63,7 +63,7 @@ namespace MWGui
ClassChoiceDialog(MWBase::WindowManager& parWindowManager); ClassChoiceDialog(MWBase::WindowManager& parWindowManager);
}; };
class GenerateClassResultDialog : public WindowBase class GenerateClassResultDialog : public WindowModal
{ {
public: public:
GenerateClassResultDialog(MWBase::WindowManager& parWindowManager); GenerateClassResultDialog(MWBase::WindowManager& parWindowManager);
@ -90,7 +90,7 @@ namespace MWGui
std::string mCurrentClassId; std::string mCurrentClassId;
}; };
class PickClassDialog : public WindowBase class PickClassDialog : public WindowModal
{ {
public: public:
PickClassDialog(MWBase::WindowManager& parWindowManager); PickClassDialog(MWBase::WindowManager& parWindowManager);
@ -238,7 +238,7 @@ namespace MWGui
MyGUI::EditPtr mTextEdit; MyGUI::EditPtr mTextEdit;
}; };
class CreateClassDialog : public WindowBase class CreateClassDialog : public WindowModal
{ {
public: public:
CreateClassDialog(MWBase::WindowManager& parWindowManager); CreateClassDialog(MWBase::WindowManager& parWindowManager);

View file

@ -0,0 +1,130 @@
#include "cursor.hpp"
#include <MyGUI_PointerManager.h>
#include <MyGUI_InputManager.h>
#include <MyGUI_RenderManager.h>
#include <MyGUI_RotatingSkin.h>
#include <MyGUI_Gui.h>
#include <OgreMath.h>
namespace MWGui
{
ResourceImageSetPointerFix::ResourceImageSetPointerFix() :
mImageSet(nullptr)
{
}
ResourceImageSetPointerFix::~ResourceImageSetPointerFix()
{
}
void ResourceImageSetPointerFix::deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version)
{
Base::deserialization(_node, _version);
MyGUI::xml::ElementEnumerator info = _node->getElementEnumerator();
while (info.next("Property"))
{
const std::string& key = info->findAttribute("key");
const std::string& value = info->findAttribute("value");
if (key == "Point")
mPoint = MyGUI::IntPoint::parse(value);
else if (key == "Size")
mSize = MyGUI::IntSize::parse(value);
else if (key == "Rotation")
mRotation = MyGUI::utility::parseInt(value);
else if (key == "Resource")
mImageSet = MyGUI::ResourceManager::getInstance().getByName(value)->castType<MyGUI::ResourceImageSet>();
}
}
int ResourceImageSetPointerFix::getRotation()
{
return mRotation;
}
void ResourceImageSetPointerFix::setImage(MyGUI::ImageBox* _image)
{
if (mImageSet != nullptr)
_image->setItemResourceInfo(mImageSet->getIndexInfo(0, 0));
}
void ResourceImageSetPointerFix::setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point)
{
_image->setCoord(_point.left - mPoint.left, _point.top - mPoint.top, mSize.width, mSize.height);
}
MyGUI::ResourceImageSetPtr ResourceImageSetPointerFix:: getImageSet()
{
return mImageSet;
}
MyGUI::IntPoint ResourceImageSetPointerFix::getHotSpot()
{
return mPoint;
}
MyGUI::IntSize ResourceImageSetPointerFix::getSize()
{
return mSize;
}
// ----------------------------------------------------------------------------------------
Cursor::Cursor()
{
// hide mygui's pointer since we're rendering it ourselves (because mygui's pointer doesn't support rotation)
MyGUI::PointerManager::getInstance().setVisible(false);
MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &Cursor::onCursorChange);
mWidget = MyGUI::Gui::getInstance().createWidget<MyGUI::ImageBox>("RotatingSkin",0,0,0,0,MyGUI::Align::Default,"Pointer","");
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
}
Cursor::~Cursor()
{
}
void Cursor::onCursorChange(const std::string &name)
{
ResourceImageSetPointerFix* imgSetPtr = dynamic_cast<ResourceImageSetPointerFix*>(
MyGUI::PointerManager::getInstance().getByName(name));
assert(imgSetPtr != NULL);
MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet();
std::string texture = imgSet->getIndexInfo(0,0).texture;
mSize = imgSetPtr->getSize();
mHotSpot = imgSetPtr->getHotSpot();
int rotation = imgSetPtr->getRotation();
mWidget->setImageTexture(texture);
MyGUI::ISubWidget* main = mWidget->getSubWidgetMain();
MyGUI::RotatingSkin* rotatingSubskin = main->castType<MyGUI::RotatingSkin>();
rotatingSubskin->setCenter(MyGUI::IntPoint(mSize.width/2,mSize.height/2));
rotatingSubskin->setAngle(Ogre::Degree(rotation).valueRadians());
}
void Cursor::update()
{
MyGUI::IntPoint position = MyGUI::InputManager::getInstance().getMousePosition();
mWidget->setPosition(position - mHotSpot);
mWidget->setSize(mSize);
}
void Cursor::setVisible(bool visible)
{
mWidget->setVisible(visible);
}
}

View file

@ -0,0 +1,62 @@
#ifndef MWGUI_CURSOR_H
#define MWGUI_CURSOR_H
#include <MyGUI_IPointer.h>
#include <MyGUI_ResourceImageSet.h>
#include <MyGUI_RTTI.h>
namespace MWGui
{
/// \brief Allows us to get the members of
/// ResourceImageSetPointer that we need.
/// \example MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer");
/// MyGUI::ResourceManager::getInstance().load("core.xml");
class ResourceImageSetPointerFix :
public MyGUI::IPointer
{
MYGUI_RTTI_DERIVED( ResourceImageSetPointerFix )
public:
ResourceImageSetPointerFix();
virtual ~ResourceImageSetPointerFix();
virtual void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version);
virtual void setImage(MyGUI::ImageBox* _image);
virtual void setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point);
//and now for the whole point of this class, allow us to get
//the hot spot, the image and the size of the cursor.
virtual MyGUI::ResourceImageSetPtr getImageSet();
virtual MyGUI::IntPoint getHotSpot();
virtual MyGUI::IntSize getSize();
virtual int getRotation();
private:
MyGUI::IntPoint mPoint;
MyGUI::IntSize mSize;
MyGUI::ResourceImageSetPtr mImageSet;
int mRotation; // rotation in degrees
};
class Cursor
{
public:
Cursor();
~Cursor();
void update ();
void setVisible (bool visible);
void onCursorChange (const std::string& name);
private:
MyGUI::ImageBox* mWidget;
MyGUI::IntSize mSize;
MyGUI::IntPoint mHotSpot;
};
}
#endif

View file

@ -1,16 +0,0 @@
#include "cursorreplace.hpp"
#include <boost/filesystem.hpp>
#include <openengine/ogre/imagerotate.hpp>
#include <OgreResourceGroupManager.h>
#include <OgreRoot.h>
using namespace MWGui;
CursorReplace::CursorReplace()
{
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90);
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45);
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45);
}

View file

@ -1,16 +0,0 @@
#ifndef GAME_CURSORREPLACE_H
#define GAME_CURSORREPLACE_H
#include <string>
namespace MWGui
{
/// \brief MyGUI does not support rotating cursors, so we have to do it manually
class CursorReplace
{
public:
CursorReplace();
};
}
#endif

View file

@ -106,7 +106,7 @@ namespace MWGui
float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading); float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading);
assert(progress <= 1 && progress >= 0); assert(progress <= 1 && progress >= 0);
mLoadingText->setCaption(stage + "... "); mLoadingText->setCaption(stage);
mProgressBar->setProgressPosition (static_cast<size_t>(progress * 1000)); mProgressBar->setProgressPosition (static_cast<size_t>(progress * 1000));
static float loadingScreenFps = 30.f; static float loadingScreenFps = 30.f;

View file

@ -5,6 +5,7 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp"
namespace MWGui namespace MWGui
{ {
@ -65,6 +66,7 @@ namespace MWGui
void MainMenu::onButtonClicked(MyGUI::Widget *sender) void MainMenu::onButtonClicked(MyGUI::Widget *sender)
{ {
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
if (sender == mButtons["return"]) if (sender == mButtons["return"])
MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu);
else if (sender == mButtons["options"]) else if (sender == mButtons["options"])

View file

@ -6,6 +6,8 @@
#include <OgreTextureManager.h> #include <OgreTextureManager.h>
#include <OgreSceneNode.h> #include <OgreSceneNode.h>
#include <MyGUI_Gui.h>
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -13,6 +15,8 @@
#include "../mwrender/globalmap.hpp" #include "../mwrender/globalmap.hpp"
#include "widgets.hpp"
using namespace MWGui; using namespace MWGui;
LocalMapBase::LocalMapBase() LocalMapBase::LocalMapBase()
@ -88,7 +92,7 @@ void LocalMapBase::applyFogOfWar()
+ boost::lexical_cast<std::string>(my); + boost::lexical_cast<std::string>(my);
std::string image = mPrefix+"_"+ boost::lexical_cast<std::string>(mCurX + (mx-1)) + "_" std::string image = mPrefix+"_"+ boost::lexical_cast<std::string>(mCurX + (mx-1)) + "_"
+ boost::lexical_cast<std::string>(mCurY + (mInterior ? (my-1) : -1*(my-1))); + boost::lexical_cast<std::string>(mCurY + (-1*(my-1)));
MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx];
fog->setImageTexture(mFogOfWar ? fog->setImageTexture(mFogOfWar ?
((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog"
@ -96,6 +100,7 @@ void LocalMapBase::applyFogOfWar()
: ""); : "");
} }
} }
notifyMapChanged ();
} }
void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
@ -127,7 +132,7 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior)
{ {
// map // map
std::string image = mPrefix+"_"+ boost::lexical_cast<std::string>(x + (mx-1)) + "_" std::string image = mPrefix+"_"+ boost::lexical_cast<std::string>(x + (mx-1)) + "_"
+ boost::lexical_cast<std::string>(y + (interior ? (my-1) : -1*(my-1))); + boost::lexical_cast<std::string>(y + (-1*(my-1)));
std::string name = "Map_" + boost::lexical_cast<std::string>(mx) + "_" std::string name = "Map_" + boost::lexical_cast<std::string>(mx) + "_"
+ boost::lexical_cast<std::string>(my); + boost::lexical_cast<std::string>(my);
@ -173,7 +178,7 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior)
} }
else else
{ {
Ogre::Vector2 position (marker.x, -marker.y); Ogre::Vector2 position (marker.x, marker.y);
MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy);
widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8);
@ -394,10 +399,10 @@ void MapWindow::globalMapUpdatePlayer ()
{ {
Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition ();
Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation ();
Ogre::Vector2 dir (orient.yAxis ().x, -orient.yAxis().z); Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y);
float worldX, worldY; float worldX, worldY;
mGlobalMapRender->worldPosToImageSpace (pos.x, pos.z, worldX, worldY); mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY);
worldX *= mGlobalMapRender->getWidth(); worldX *= mGlobalMapRender->getWidth();
worldY *= mGlobalMapRender->getHeight(); worldY *= mGlobalMapRender->getHeight();
@ -425,3 +430,17 @@ void MapWindow::notifyPlayerUpdate ()
{ {
globalMapUpdatePlayer (); globalMapUpdatePlayer ();
} }
void MapWindow::notifyMapChanged ()
{
// workaround to prevent the map from drawing on top of the button
MyGUI::IntCoord oldCoord = mButton->getCoord ();
MyGUI::Gui::getInstance().destroyWidget (mButton);
mButton = mMainWidget->createWidget<MWGui::Widgets::AutoSizedButton>("MW_Button",
oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right);
mButton->setProperty ("ExpandDirection", "Left");
mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked);
mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" :
"#{sWorld}");
}

View file

@ -50,6 +50,7 @@ namespace MWGui
void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2);
virtual void notifyPlayerUpdate() {} virtual void notifyPlayerUpdate() {}
virtual void notifyMapChanged() {}
OEngine::GUI::Layout* mLayout; OEngine::GUI::Layout* mLayout;
@ -99,6 +100,8 @@ namespace MWGui
virtual void onPinToggled(); virtual void onPinToggled();
virtual void notifyPlayerUpdate(); virtual void notifyPlayerUpdate();
virtual void notifyMapChanged();
}; };
} }
#endif #endif

View file

@ -1,6 +1,8 @@
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include "messagebox.hpp" #include "messagebox.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"
using namespace MWGui; using namespace MWGui;
@ -375,6 +377,7 @@ void InteractiveMessageBox::enterPressed()
if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok)
{ {
buttonActivated(*button); buttonActivated(*button);
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
break; break;
} }
} }

View file

@ -20,7 +20,7 @@ using namespace MWGui;
using namespace Widgets; using namespace Widgets;
RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager)
: WindowBase("openmw_chargen_race.layout", parWindowManager) : WindowModal("openmw_chargen_race.layout", parWindowManager)
, mGenderIndex(0) , mGenderIndex(0)
, mFaceIndex(0) , mFaceIndex(0)
, mHairIndex(0) , mHairIndex(0)
@ -61,7 +61,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager)
prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair);
nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair);
setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu4", "Race")); setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu5", "Race"));
getWidget(mRaceList, "RaceList"); getWidget(mRaceList, "RaceList");
mRaceList->setScrollVisible(true); mRaceList->setScrollVisible(true);
mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
@ -100,6 +100,8 @@ void RaceDialog::setNextButtonShow(bool shown)
void RaceDialog::open() void RaceDialog::open()
{ {
WindowModal::open();
updateRaces(); updateRaces();
updateSkills(); updateSkills();
updateSpellPowers(); updateSpellPowers();

View file

@ -23,7 +23,7 @@ namespace MWGui
namespace MWGui namespace MWGui
{ {
class RaceDialog : public WindowBase class RaceDialog : public WindowModal
{ {
public: public:
RaceDialog(MWBase::WindowManager& parWindowManager); RaceDialog(MWBase::WindowManager& parWindowManager);

View file

@ -23,7 +23,7 @@ using namespace Widgets;
const int ReviewDialog::sLineHeight = 18; const int ReviewDialog::sLineHeight = 18;
ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager)
: WindowBase("openmw_chargen_review.layout", parWindowManager) : WindowModal("openmw_chargen_review.layout", parWindowManager)
, mLastPos(0) , mLastPos(0)
{ {
// Centre dialog // Centre dialog
@ -97,6 +97,7 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager)
void ReviewDialog::open() void ReviewDialog::open()
{ {
WindowModal::open();
updateSkillArea(); updateSkillArea();
} }

View file

@ -17,7 +17,7 @@ Layout is defined by resources/mygui/openmw_chargen_review.layout.
namespace MWGui namespace MWGui
{ {
class ReviewDialog : public WindowBase class ReviewDialog : public WindowModal
{ {
public: public:
enum Dialogs { enum Dialogs {

View file

@ -5,7 +5,7 @@
using namespace MWGui; using namespace MWGui;
TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager)
: WindowBase("openmw_text_input.layout", parWindowManager) : WindowModal("openmw_text_input.layout", parWindowManager)
{ {
// Centre dialog // Centre dialog
center(); center();
@ -39,6 +39,7 @@ void TextInputDialog::setTextLabel(const std::string &label)
void TextInputDialog::open() void TextInputDialog::open()
{ {
WindowModal::open();
// Make sure the edit box has focus // Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
} }

View file

@ -13,7 +13,7 @@ namespace MWGui
namespace MWGui namespace MWGui
{ {
class TextInputDialog : public WindowBase class TextInputDialog : public WindowModal
{ {
public: public:
TextInputDialog(MWBase::WindowManager& parWindowManager); TextInputDialog(MWBase::WindowManager& parWindowManager);

View file

@ -19,11 +19,11 @@
#include "inventorywindow.hpp" #include "inventorywindow.hpp"
static const float BALANCE_CHANGE_INITIAL_PAUSE = 0.5; // in seconds
static const float BALANCE_CHANGE_INTERVAL = 0.1; // in seconds
namespace MWGui namespace MWGui
{ {
const float TradeWindow::sBalanceChangeInitialPause = 0.5;
const float TradeWindow::sBalanceChangeInterval = 0.1;
TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) :
WindowBase("openmw_trade_window.layout", parWindowManager) WindowBase("openmw_trade_window.layout", parWindowManager)
, ContainerBase(NULL) // no drag&drop , ContainerBase(NULL) // no drag&drop
@ -157,7 +157,7 @@ namespace MWGui
mBalanceChangePause -= frameDuration; mBalanceChangePause -= frameDuration;
if (mBalanceChangePause < 0.0) { if (mBalanceChangePause < 0.0) {
mBalanceChangePause += BALANCE_CHANGE_INTERVAL; mBalanceChangePause += sBalanceChangeInterval;
if (mBalanceButtonsState == BBS_Increase) if (mBalanceButtonsState == BBS_Increase)
onIncreaseButtonTriggered(); onIncreaseButtonTriggered();
else if (mBalanceButtonsState == BBS_Decrease) else if (mBalanceButtonsState == BBS_Decrease)
@ -296,14 +296,14 @@ namespace MWGui
void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
{ {
mBalanceButtonsState = BBS_Increase; mBalanceButtonsState = BBS_Increase;
mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; mBalanceChangePause = sBalanceChangeInitialPause;
onIncreaseButtonTriggered(); onIncreaseButtonTriggered();
} }
void TradeWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) void TradeWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
{ {
mBalanceButtonsState = BBS_Decrease; mBalanceButtonsState = BBS_Decrease;
mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; mBalanceChangePause = sBalanceChangeInitialPause;
onDecreaseButtonTriggered(); onDecreaseButtonTriggered();
} }

View file

@ -37,6 +37,9 @@ namespace MWGui
void onFrame(float frameDuration); void onFrame(float frameDuration);
protected: protected:
static const float sBalanceChangeInitialPause; // in seconds
static const float sBalanceChangeInterval; // in seconds
MyGUI::Button* mFilterAll; MyGUI::Button* mFilterAll;
MyGUI::Button* mFilterWeapon; MyGUI::Button* mFilterWeapon;
MyGUI::Button* mFilterApparel; MyGUI::Button* mFilterApparel;

View file

@ -95,31 +95,46 @@ namespace MWGui
// http://www.uesp.net/wiki/Lore:Calendar // http://www.uesp.net/wiki/Lore:Calendar
std::string month; std::string month;
int m = MWBase::Environment::get().getWorld ()->getMonth (); int m = MWBase::Environment::get().getWorld ()->getMonth ();
if (m == 0) switch (m) {
month = "#{sMonthMorningstar}"; case 0:
else if (m == 1) month = "#{sMonthMorningstar}";
month = "#{sMonthSunsdawn}"; break;
else if (m == 2) case 1:
month = "#{sMonthFirstseed}"; month = "#{sMonthSunsdawn}";
else if (m == 3) break;
month = "#{sMonthRainshand}"; case 2:
else if (m == 4) month = "#{sMonthFirstseed}";
month = "#{sMonthSecondseed}"; break;
else if (m == 5) case 3:
month = "#{sMonthMidyear}"; month = "#{sMonthRainshand}";
else if (m == 6) break;
month = "#{sMonthSunsheight}"; case 4:
else if (m == 7) month = "#{sMonthSecondseed}";
month = "#{sMonthLastseed}"; break;
else if (m == 8) case 5:
month = "#{sMonthHeartfire}"; month = "#{sMonthMidyear}";
else if (m == 9) break;
month = "#{sMonthFrostfall}"; case 6:
else if (m == 10) month = "#{sMonthSunsheight}";
month = "#{sMonthSunsdusk}"; break;
else if (m == 11) case 7:
month = "#{sMonthEveningstar}"; month = "#{sMonthLastseed}";
break;
case 8:
month = "#{sMonthHeartfire}";
break;
case 9:
month = "#{sMonthFrostfall}";
break;
case 10:
month = "#{sMonthSunsdusk}";
break;
case 11:
month = "#{sMonthEveningstar}";
break;
default:
break;
}
int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour ();
bool pm = hour >= 12; bool pm = hour >= 12;
if (hour >= 13) hour -= 12; if (hour >= 13) hour -= 12;

View file

@ -53,6 +53,7 @@
#include "trainingwindow.hpp" #include "trainingwindow.hpp"
#include "imagebutton.hpp" #include "imagebutton.hpp"
#include "exposedwindow.hpp" #include "exposedwindow.hpp"
#include "cursor.hpp"
using namespace MWGui; using namespace MWGui;
@ -130,6 +131,9 @@ WindowManager::WindowManager(
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ImageButton>("Widget"); MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ImageButton>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ExposedWindow>("Widget"); MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ExposedWindow>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer");
MyGUI::ResourceManager::getInstance().load("core.xml");
MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag);
// Get size info from the Gui object // Get size info from the Gui object
@ -178,6 +182,8 @@ WindowManager::WindowManager(
mInputBlocker = mGui->createWidget<MyGUI::Widget>("",0,0,w,h,MyGUI::Align::Default,"Windows",""); mInputBlocker = mGui->createWidget<MyGUI::Widget>("",0,0,w,h,MyGUI::Align::Default,"Windows","");
mCursor = new Cursor();
// The HUD is always on // The HUD is always on
mHud->setVisible(true); mHud->setVisible(true);
@ -236,6 +242,7 @@ WindowManager::~WindowManager()
delete mTrainingWindow; delete mTrainingWindow;
delete mCountDialog; delete mCountDialog;
delete mQuickKeysMenu; delete mQuickKeysMenu;
delete mCursor;
cleanupGarbage(); cleanupGarbage();
@ -262,6 +269,8 @@ void WindowManager::update()
mHud->setFPS(mFPS); mHud->setFPS(mFPS);
mHud->setTriangleCount(mTriangleCount); mHud->setTriangleCount(mTriangleCount);
mHud->setBatchCount(mBatchCount); mHud->setBatchCount(mBatchCount);
mCursor->update();
} }
void WindowManager::updateVisible() void WindowManager::updateVisible()
@ -293,7 +302,7 @@ void WindowManager::updateVisible()
mHud->setVisible(true); mHud->setVisible(true);
// Mouse is visible whenever we're not in game mode // Mouse is visible whenever we're not in game mode
MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); mCursor->setVisible(isGuiMode());
bool gameMode = !isGuiMode(); bool gameMode = !isGuiMode();
@ -421,13 +430,19 @@ void WindowManager::updateVisible()
break; break;
case GM_LoadingWallpaper: case GM_LoadingWallpaper:
mHud->setVisible(false); mHud->setVisible(false);
MyGUI::PointerManager::getInstance().setVisible(false); mCursor->setVisible(false);
break; break;
case GM_Loading: case GM_Loading:
MyGUI::PointerManager::getInstance().setVisible(false); // Show the pinned windows
mMap->setVisible(mMap->pinned());
mStatsWindow->setVisible(mStatsWindow->pinned());
mInventoryWindow->setVisible(mInventoryWindow->pinned());
mSpellWindow->setVisible(mSpellWindow->pinned());
mCursor->setVisible(false);
break; break;
case GM_Video: case GM_Video:
MyGUI::PointerManager::getInstance().setVisible(false); mCursor->setVisible(false);
mHud->setVisible(false); mHud->setVisible(false);
break; break;
default: default:
@ -749,7 +764,7 @@ void WindowManager::setSpellVisibility(bool visible)
void WindowManager::setMouseVisible(bool visible) void WindowManager::setMouseVisible(bool visible)
{ {
MyGUI::PointerManager::getInstance().setVisible(visible); mCursor->setVisible(visible);
} }
void WindowManager::setDragDrop(bool dragDrop) void WindowManager::setDragDrop(bool dragDrop)

View file

@ -72,6 +72,7 @@ namespace MWGui
class SpellCreationDialog; class SpellCreationDialog;
class EnchantingDialog; class EnchantingDialog;
class TrainingWindow; class TrainingWindow;
class Cursor;
class WindowManager : public MWBase::WindowManager class WindowManager : public MWBase::WindowManager
{ {
@ -188,7 +189,7 @@ namespace MWGui
virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted.
virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons); virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>());
virtual void enterPressed (); virtual void enterPressed ();
virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
@ -260,6 +261,7 @@ namespace MWGui
EnchantingDialog* mEnchantingDialog; EnchantingDialog* mEnchantingDialog;
TrainingWindow* mTrainingWindow; TrainingWindow* mTrainingWindow;
Translation::Storage& mTranslationDataStorage; Translation::Storage& mTranslationDataStorage;
Cursor* mCursor;
CharacterCreation* mCharGen; CharacterCreation* mCharGen;

View file

@ -21,6 +21,7 @@
#include "../engine.hpp" #include "../engine.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "../mwworld/class.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
@ -51,6 +52,7 @@ namespace MWInput
, mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input"))
, mPreviewPOVDelay(0.f) , mPreviewPOVDelay(0.f)
, mTimeIdle(0.f) , mTimeIdle(0.f)
, mOverencumberedMessageDelay(0.f)
{ {
Ogre::RenderWindow* window = ogre.getWindow (); Ogre::RenderWindow* window = ogre.getWindow ();
size_t windowHnd; size_t windowHnd;
@ -85,10 +87,12 @@ namespace MWInput
std::string("false"))); std::string("false")));
pl.insert(std::make_pair(std::string("x11_keyboard_grab"), pl.insert(std::make_pair(std::string("x11_keyboard_grab"),
std::string("false"))); std::string("false")));
pl.insert(std::make_pair(std::string("XAutoRepeatOn"),
std::string("true")));
#endif #endif
} }
#if defined OIS_LINUX_PLATFORM
pl.insert(std::make_pair(std::string("XAutoRepeatOn"),
std::string("true")));
#endif
#if defined(__APPLE__) && !defined(__LP64__) #if defined(__APPLE__) && !defined(__LP64__)
// Give the application window focus to receive input events // Give the application window focus to receive input events
@ -175,6 +179,11 @@ namespace MWInput
case A_Activate: case A_Activate:
resetIdleTime(); resetIdleTime();
activate(); activate();
if( MWBase::Environment::get().getWindowManager()->isGuiMode()
&& MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) {
// Pressing the activation key when a messagebox is prompting for "ok" will activate the ok button
MWBase::Environment::get().getWindowManager()->enterPressed();
}
break; break;
case A_Journal: case A_Journal:
toggleJournal (); toggleJournal ();
@ -268,26 +277,29 @@ namespace MWInput
// be done in the physics system. // be done in the physics system.
if (mControlSwitch["playercontrols"]) if (mControlSwitch["playercontrols"])
{ {
bool triedToMove = false;
if (actionIsActive(A_MoveLeft)) if (actionIsActive(A_MoveLeft))
{ {
mPlayer.setAutoMove (false); triedToMove = true;
mPlayer.setLeftRight (1); mPlayer.setLeftRight (-1);
} }
else if (actionIsActive(A_MoveRight)) else if (actionIsActive(A_MoveRight))
{ {
mPlayer.setAutoMove (false); triedToMove = true;
mPlayer.setLeftRight (-1); mPlayer.setLeftRight (1);
} }
else else
mPlayer.setLeftRight (0); mPlayer.setLeftRight (0);
if (actionIsActive(A_MoveForward)) if (actionIsActive(A_MoveForward))
{ {
triedToMove = true;
mPlayer.setAutoMove (false); mPlayer.setAutoMove (false);
mPlayer.setForwardBackward (1); mPlayer.setForwardBackward (1);
} }
else if (actionIsActive(A_MoveBackward)) else if (actionIsActive(A_MoveBackward))
{ {
triedToMove = true;
mPlayer.setAutoMove (false); mPlayer.setAutoMove (false);
mPlayer.setForwardBackward (-1); mPlayer.setForwardBackward (-1);
} }
@ -295,12 +307,35 @@ namespace MWInput
mPlayer.setForwardBackward (0); mPlayer.setForwardBackward (0);
if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"])
{
mPlayer.setUpDown (1); mPlayer.setUpDown (1);
triedToMove = true;
}
else if (actionIsActive(A_Crouch)) else if (actionIsActive(A_Crouch))
mPlayer.setUpDown (-1); mPlayer.setUpDown (-1);
else else
mPlayer.setUpDown (0); mPlayer.setUpDown (0);
if(actionIsActive(A_Run))
mPlayer.setRunState(true);
else
mPlayer.setRunState(false);
// if player tried to start moving, but can't (due to being overencumbered), display a notification.
if (triedToMove)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ();
mOverencumberedMessageDelay -= dt;
if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player))
{
if (mOverencumberedMessageDelay <= 0)
{
MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}");
mOverencumberedMessageDelay = 1.0;
}
}
}
if (mControlSwitch["playerviewswitch"]) { if (mControlSwitch["playerviewswitch"]) {
// work around preview mode toggle when pressing Alt+Tab // work around preview mode toggle when pressing Alt+Tab
@ -521,6 +556,9 @@ namespace MWInput
void InputManager::toggleMainMenu() void InputManager::toggleMainMenu()
{ {
if (MyGUI::InputManager::getInstance ().isModalAny())
return;
if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings))
mWindows.popGuiMode(); mWindows.popGuiMode();
else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video)
@ -599,6 +637,9 @@ namespace MWInput
void InputManager::toggleConsole() void InputManager::toggleConsole()
{ {
if (MyGUI::InputManager::getInstance ().isModalAny())
return;
bool gameMode = !mWindows.isGuiMode(); bool gameMode = !mWindows.isGuiMode();
// Switch to console mode no matter what mode we are currently // Switch to console mode no matter what mode we are currently
@ -705,6 +746,7 @@ namespace MWInput
defaultKeyBindings[A_ToggleSpell] = OIS::KC_R; defaultKeyBindings[A_ToggleSpell] = OIS::KC_R;
defaultKeyBindings[A_QuickKeysMenu] = OIS::KC_F1; defaultKeyBindings[A_QuickKeysMenu] = OIS::KC_F1;
defaultKeyBindings[A_Console] = OIS::KC_F2; defaultKeyBindings[A_Console] = OIS::KC_F2;
defaultKeyBindings[A_Run] = OIS::KC_LSHIFT;
defaultKeyBindings[A_Crouch] = OIS::KC_LCONTROL; defaultKeyBindings[A_Crouch] = OIS::KC_LCONTROL;
defaultKeyBindings[A_AutoMove] = OIS::KC_Q; defaultKeyBindings[A_AutoMove] = OIS::KC_Q;
defaultKeyBindings[A_Jump] = OIS::KC_E; defaultKeyBindings[A_Jump] = OIS::KC_E;
@ -771,6 +813,7 @@ namespace MWInput
descriptions[A_ToggleWeapon] = "sReady_Weapon"; descriptions[A_ToggleWeapon] = "sReady_Weapon";
descriptions[A_ToggleSpell] = "sReady_Magic"; descriptions[A_ToggleSpell] = "sReady_Magic";
descriptions[A_Console] = "sConsoleTitle"; descriptions[A_Console] = "sConsoleTitle";
descriptions[A_Run] = "sRun";
descriptions[A_Crouch] = "sCrouch_Sneak"; descriptions[A_Crouch] = "sCrouch_Sneak";
descriptions[A_AutoMove] = "sAuto_Run"; descriptions[A_AutoMove] = "sAuto_Run";
descriptions[A_Jump] = "sJump"; descriptions[A_Jump] = "sJump";
@ -819,6 +862,7 @@ namespace MWInput
ret.push_back(A_MoveLeft); ret.push_back(A_MoveLeft);
ret.push_back(A_MoveRight); ret.push_back(A_MoveRight);
ret.push_back(A_TogglePOV); ret.push_back(A_TogglePOV);
ret.push_back(A_Run);
ret.push_back(A_Crouch); ret.push_back(A_Crouch);
ret.push_back(A_Activate); ret.push_back(A_Activate);
ret.push_back(A_ToggleWeapon); ret.push_back(A_ToggleWeapon);

View file

@ -145,6 +145,8 @@ namespace MWInput
bool mMouseLookEnabled; bool mMouseLookEnabled;
bool mGuiCursorEnabled; bool mGuiCursorEnabled;
float mOverencumberedMessageDelay;
float mMouseX; float mMouseX;
float mMouseY; float mMouseY;
int mMouseWheel; int mMouseWheel;
@ -207,7 +209,7 @@ namespace MWInput
A_Journal, //Journal A_Journal, //Journal
A_Weapon, //Draw/Sheath weapon A_Weapon, //Draw/Sheath weapon
A_Spell, //Ready/Unready Casting A_Spell, //Ready/Unready Casting
A_AlwaysRun, //Toggle Always Run A_Run, //Run when held
A_CycleSpellLeft, //cycling through spells A_CycleSpellLeft, //cycling through spells
A_CycleSpellRight, A_CycleSpellRight,
A_CycleWeaponLeft,//Cycling through weapons A_CycleWeaponLeft,//Cycling through weapons

View file

@ -0,0 +1,76 @@
#include "activators.hpp"
#include <OgreVector3.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
namespace MWMechanics
{
Activators::Activators()
{
}
void Activators::addActivator(const MWWorld::Ptr& ptr)
{
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
if(anim != NULL)
mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true)));
}
void Activators::removeActivator (const MWWorld::Ptr& ptr)
{
PtrControllerMap::iterator iter = mActivators.find(ptr);
if(iter != mActivators.end())
mActivators.erase(iter);
}
void Activators::updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
{
PtrControllerMap::iterator iter = mActivators.find(old);
if(iter != mActivators.end())
{
CharacterController ctrl = iter->second;
mActivators.erase(iter);
ctrl.updatePtr(ptr);
mActivators.insert(std::make_pair(ptr, ctrl));
}
}
void Activators::dropActivators (const MWWorld::Ptr::CellStore *cellStore)
{
PtrControllerMap::iterator iter = mActivators.begin();
while(iter != mActivators.end())
{
if(iter->first.getCell()==cellStore)
mActivators.erase(iter++);
else
++iter;
}
}
void Activators::update(float duration, bool paused)
{
if(!paused)
{
for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter)
iter->second.update(duration);
}
}
void Activators::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
{
PtrControllerMap::iterator iter = mActivators.find(ptr);
if(iter != mActivators.end())
iter->second.playGroup(groupName, mode, number);
}
void Activators::skipAnimation(const MWWorld::Ptr& ptr)
{
PtrControllerMap::iterator iter = mActivators.find(ptr);
if(iter != mActivators.end())
iter->second.skipAnim();
}
}

View file

@ -0,0 +1,45 @@
#ifndef GAME_MWMECHANICS_ACTIVATORS_H
#define GAME_MWMECHANICS_ACTOVATRS_H
#include <string>
#include <map>
#include "character.hpp"
namespace MWWorld
{
class Ptr;
class CellStore;
}
namespace MWMechanics
{
class Activators
{
typedef std::map<MWWorld::Ptr,CharacterController> PtrControllerMap;
PtrControllerMap mActivators;
public:
Activators();
void addActivator (const MWWorld::Ptr& ptr);
///< Register an animated activator
void removeActivator (const MWWorld::Ptr& ptr);
///< Deregister an activator
void updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr);
///< Updates an activator with a new Ptr
void dropActivators (const MWWorld::CellStore *cellStore);
///< Deregister all activators in the given cell.
void update (float duration, bool paused);
///< Update activator animations
void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
void skipAnimation(const MWWorld::Ptr& ptr);
};
}
#endif

View file

@ -165,35 +165,46 @@ namespace MWMechanics
void Actors::addActor (const MWWorld::Ptr& ptr) void Actors::addActor (const MWWorld::Ptr& ptr)
{ {
if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
mActors.insert (ptr); if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead())
mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true)));
else else
MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Death1, false)));
} }
void Actors::removeActor (const MWWorld::Ptr& ptr) void Actors::removeActor (const MWWorld::Ptr& ptr)
{ {
std::set<MWWorld::Ptr>::iterator iter = mActors.find (ptr); PtrControllerMap::iterator iter = mActors.find(ptr);
if(iter != mActors.end())
mActors.erase(iter);
}
if (iter!=mActors.end()) void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
mActors.erase (iter); {
PtrControllerMap::iterator iter = mActors.find(old);
if(iter != mActors.end())
{
CharacterController ctrl = iter->second;
mActors.erase(iter);
ctrl.updatePtr(ptr);
mActors.insert(std::make_pair(ptr, ctrl));
}
} }
void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore) void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore)
{ {
std::set<MWWorld::Ptr>::iterator iter = mActors.begin(); PtrControllerMap::iterator iter = mActors.begin();
while(iter != mActors.end())
while (iter!=mActors.end()) {
if (iter->getCell()==cellStore) if(iter->first.getCell()==cellStore)
{ mActors.erase(iter++);
mActors.erase (iter++);
}
else else
++iter; ++iter;
}
} }
void Actors::update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement, float duration, void Actors::update (float duration, bool paused)
bool paused)
{ {
mDuration += duration; mDuration += duration;
@ -201,79 +212,91 @@ namespace MWMechanics
{ {
float totalDuration = mDuration; float totalDuration = mDuration;
mDuration = 0; mDuration = 0;
std::set<MWWorld::Ptr>::iterator iter (mActors.begin());
while (iter!=mActors.end()) for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++)
{ {
if (!MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead()) if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead())
{ {
updateActor (*iter, totalDuration); if(iter->second.getState() >= CharState_Death1)
iter->second.setState(CharState_Idle, true);
if (iter->getTypeName()==typeid (ESM::NPC).name()) updateActor(iter->first, totalDuration);
updateNpc (*iter, totalDuration, paused); if(iter->first.getTypeName() == typeid(ESM::NPC).name())
updateNpc(iter->first, totalDuration, paused);
if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead())
continue;
} }
if (MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead()) // workaround: always keep player alive for now
// \todo remove workaround, once player death can be handled
if(iter->first.getRefData().getHandle()=="player")
{ {
// workaround: always keep player alive for now MWMechanics::DynamicStat<float> stat (
// \todo remove workaround, once player death can be handled MWWorld::Class::get(iter->first).getCreatureStats(iter->first).getHealth());
if (iter->getRefData().getHandle()=="player")
{
MWMechanics::DynamicStat<float> stat (
MWWorld::Class::get (*iter).getCreatureStats (*iter).getHealth());
if (stat.getModified()<1)
{
stat.setModified (1, 0);
MWWorld::Class::get (*iter).getCreatureStats (*iter).setHealth (stat);
}
MWWorld::Class::get (*iter).getCreatureStats (*iter).resurrect(); if (stat.getModified()<1)
++iter; {
continue; stat.setModified (1, 0);
MWWorld::Class::get(iter->first).getCreatureStats(iter->first).setHealth(stat);
} }
++mDeathCount[MWWorld::Class::get (*iter).getId (*iter)]; MWWorld::Class::get(iter->first).getCreatureStats(iter->first).resurrect();
continue;
MWBase::Environment::get().getWorld()->playAnimationGroup (*iter, "death1", 0);
if (MWWorld::Class::get (*iter).isEssential (*iter))
MWBase::Environment::get().getWindowManager()->messageBox (
"#{sKilledEssential}", std::vector<std::string>());
mActors.erase (iter++);
} }
else
++iter; if(iter->second.getState() >= CharState_Death1)
continue;
iter->second.setState(CharState_Death1, false);
++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)];
if(MWWorld::Class::get(iter->first).isEssential(iter->first))
MWBase::Environment::get().getWindowManager()->messageBox(
"#{sKilledEssential}", std::vector<std::string>());
} }
} }
for (std::set<MWWorld::Ptr>::iterator iter (mActors.begin()); iter!=mActors.end(); if(!paused)
++iter)
{ {
Ogre::Vector3 vector = MWWorld::Class::get (*iter).getMovementVector (*iter); mMovement.reserve(mActors.size());
if (vector!=Ogre::Vector3::ZERO) for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
movement.push_back (std::make_pair (iter->getRefData().getHandle(), vector)); {
Ogre::Vector3 movement = iter->second.update(duration);
mMovement.push_back(std::make_pair(iter->first, movement));
}
MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration);
mMovement.clear();
} }
} }
void Actors::restoreDynamicStats() void Actors::restoreDynamicStats()
{ {
for (std::set<MWWorld::Ptr>::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter) for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{ calculateRestoration(iter->first, 3600);
calculateRestoration (*iter, 3600);
}
} }
int Actors::countDeaths (const std::string& id) const int Actors::countDeaths (const std::string& id) const
{ {
std::map<std::string, int>::const_iterator iter = mDeathCount.find (id); std::map<std::string, int>::const_iterator iter = mDeathCount.find(id);
if(iter != mDeathCount.end())
if (iter!=mDeathCount.end())
return iter->second; return iter->second;
return 0; return 0;
} }
void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
{
PtrControllerMap::iterator iter = mActors.find(ptr);
if(iter != mActors.end())
iter->second.playGroup(groupName, mode, number);
}
void Actors::skipAnimation(const MWWorld::Ptr& ptr)
{
PtrControllerMap::iterator iter = mActors.find(ptr);
if(iter != mActors.end())
iter->second.skipAnim();
}
} }

View file

@ -6,6 +6,9 @@
#include <string> #include <string>
#include <map> #include <map>
#include "character.hpp"
#include "../mwbase/world.hpp"
namespace Ogre namespace Ogre
{ {
class Vector3; class Vector3;
@ -21,9 +24,14 @@ namespace MWMechanics
{ {
class Actors class Actors
{ {
std::set<MWWorld::Ptr> mActors; typedef std::map<MWWorld::Ptr,CharacterController> PtrControllerMap;
float mDuration; PtrControllerMap mActors;
std::map<std::string, int> mDeathCount;
MWWorld::PtrMovementList mMovement;
std::map<std::string, int> mDeathCount;
float mDuration;
void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused);
@ -50,11 +58,13 @@ namespace MWMechanics
/// ///
/// \note Ignored, if \a ptr is not a registered actor. /// \note Ignored, if \a ptr is not a registered actor.
void updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr);
///< Updates an actor with a new Ptr
void dropActors (const MWWorld::CellStore *cellStore); void dropActors (const MWWorld::CellStore *cellStore);
///< Deregister all actors in the given cell. ///< Deregister all actors in the given cell.
void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement, void update (float duration, bool paused);
float duration, bool paused);
///< Update actor stats and store desired velocity vectors in \a movement ///< Update actor stats and store desired velocity vectors in \a movement
void updateActor (const MWWorld::Ptr& ptr, float duration); void updateActor (const MWWorld::Ptr& ptr, float duration);
@ -66,6 +76,9 @@ namespace MWMechanics
int countDeaths (const std::string& id) const; int countDeaths (const std::string& id) const;
///< Return the number of deaths for actors with the given ID. ///< Return the number of deaths for actors with the given ID.
void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
void skipAnimation(const MWWorld::Ptr& ptr);
}; };
} }

View file

@ -0,0 +1,296 @@
/*
* OpenMW - The completely unofficial reimplementation of Morrowind
*
* This file (character.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 "character.hpp"
#include <OgreStringConverter.h>
#include "../mwrender/animation.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
namespace MWMechanics
{
static const struct {
CharacterState state;
const char groupname[32];
} sStateList[] = {
{ CharState_Idle, "idle" },
{ CharState_Idle2, "idle2" },
{ CharState_Idle3, "idle3" },
{ CharState_Idle4, "idle4" },
{ CharState_Idle5, "idle5" },
{ CharState_Idle6, "idle6" },
{ CharState_Idle7, "idle7" },
{ CharState_Idle8, "idle8" },
{ CharState_Idle9, "idle9" },
{ CharState_IdleSwim, "idleswim" },
{ CharState_WalkForward, "walkforward" },
{ CharState_WalkBack, "walkback" },
{ CharState_WalkLeft, "walkleft" },
{ CharState_WalkRight, "walkright" },
{ CharState_SwimWalkForward, "swimwalkforward" },
{ CharState_SwimWalkBack, "swimwalkback" },
{ CharState_SwimWalkLeft, "swimwalkleft" },
{ CharState_SwimWalkRight, "swimwalkright" },
{ CharState_RunForward, "runforward" },
{ CharState_RunBack, "runback" },
{ CharState_RunLeft, "runleft" },
{ CharState_RunRight, "runright" },
{ CharState_SwimRunForward, "swimrunforward" },
{ CharState_SwimRunBack, "swimrunback" },
{ CharState_SwimRunLeft, "swimrunleft" },
{ CharState_SwimRunRight, "swimrunright" },
{ CharState_Jump, "jump" },
{ CharState_Death1, "death1" },
{ CharState_Death2, "death2" },
{ CharState_Death3, "death3" },
{ CharState_Death4, "death4" },
{ CharState_Death5, "death5" },
};
static const size_t sStateListSize = sizeof(sStateList)/sizeof(sStateList[0]);
static void getStateInfo(CharacterState state, std::string *group)
{
for(size_t i = 0;i < sStateListSize;i++)
{
if(sStateList[i].state == state)
{
*group = sStateList[i].groupname;
return;
}
}
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(state));
}
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop)
: mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false)
{
if(!mAnimation)
return;
mAnimation->setController(this);
getStateInfo(mState, &mCurrentGroup);
if(ptr.getTypeName() == typeid(ESM::Activator).name())
{
/* Don't accumulate with activators (they don't get moved). */
mAnimation->setAccumulation(Ogre::Vector3::ZERO);
}
else
{
/* Accumulate along X/Y only for now, until we can figure out how we should
* handle knockout and death which moves the character down. */
mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f));
}
if(mAnimation->hasAnimation(mCurrentGroup))
mAnimation->play(mCurrentGroup, "stop", "stop", loop);
}
CharacterController::CharacterController(const CharacterController &rhs)
: mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue)
, mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState)
, mSkipAnim(rhs.mSkipAnim)
{
if(!mAnimation)
return;
/* We've been copied. Update the animation with the new controller. */
mAnimation->setController(this);
}
CharacterController::~CharacterController()
{
}
void CharacterController::updatePtr(const MWWorld::Ptr &ptr)
{
mPtr = ptr;
}
void CharacterController::markerEvent(float time, const std::string &evt)
{
if(evt == "stop")
{
if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1])
{
mAnimQueue.pop_front();
mAnimation->play(mCurrentGroup, "loop start", "stop", false);
}
else if(mAnimQueue.size() > 0)
{
mAnimQueue.pop_front();
if(mAnimQueue.size() > 0)
{
mCurrentGroup = mAnimQueue.front();
mAnimation->play(mCurrentGroup, "start", "stop", false);
}
}
return;
}
std::cerr<< "Unhandled animation event: "<<evt <<std::endl;
}
Ogre::Vector3 CharacterController::update(float duration)
{
Ogre::Vector3 movement(0.0f);
float speed = 0.0f;
if(!(getState() >= CharState_Death1))
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
const Ogre::Vector3 &vec = cls.getMovementVector(mPtr);
bool onground = world->isOnGround(mPtr);
bool inwater = world->isSwimming(mPtr);
bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run);
speed = cls.getSpeed(mPtr);
/* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except
* for the initial thrust (which would be carried by "physics" until landing). */
if(onground && vec.z > 0.0f)
{
float x = cls.getJump(mPtr);
if(vec.x == 0 && vec.y == 0)
movement.z += x*duration;
else
{
/* FIXME: this would be more correct if we were going into a jumping state,
* rather than normal walking/idle states. */
//Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy();
//movement += Ogre::Vector3(lat.x, lat.y, 1.0f) * x * 0.707f * duration;
movement.z += x * 0.707f * duration;
}
//decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult;
}
if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f)
{
if(vec.x > 0.0f)
setState(isrunning ?
(inwater ? CharState_SwimRunRight : CharState_RunRight) :
(inwater ? CharState_SwimWalkRight : CharState_WalkRight), true);
else if(vec.x < 0.0f)
setState(isrunning ?
(inwater ? CharState_SwimRunLeft: CharState_RunLeft) :
(inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true);
// Apply any forward/backward movement manually
movement.y += vec.y * (speed*duration);
}
else if(vec.y != 0.0f && speed > 0.0f)
{
if(vec.y > 0.0f)
setState(isrunning ?
(inwater ? CharState_SwimRunForward : CharState_RunForward) :
(inwater ? CharState_SwimWalkForward : CharState_WalkForward), true);
else if(vec.y < 0.0f)
setState(isrunning ?
(inwater ? CharState_SwimRunBack : CharState_RunBack) :
(inwater ? CharState_SwimWalkBack : CharState_WalkBack), true);
// Apply any sideways movement manually
movement.x += vec.x * (speed*duration);
}
else if(mAnimQueue.size() == 0)
setState((inwater ? CharState_IdleSwim : CharState_Idle), true);
}
if(mAnimation && !mSkipAnim)
{
mAnimation->setSpeed(speed);
movement += mAnimation->runAnimation(duration);
}
mSkipAnim = false;
return movement;
}
void CharacterController::playGroup(const std::string &groupname, int mode, int count)
{
if(!mAnimation || !mAnimation->hasAnimation(groupname))
std::cerr<< "Animation "<<groupname<<" not found" <<std::endl;
else
{
count = std::max(count, 1);
if(mode != 0 || mAnimQueue.size() == 0)
{
mAnimQueue.clear();
while(count-- > 0)
mAnimQueue.push_back(groupname);
mCurrentGroup = groupname;
mState = CharState_SpecialIdle;
mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", false);
}
else if(mode == 0)
{
mAnimQueue.resize(1);
while(count-- > 0)
mAnimQueue.push_back(groupname);
}
}
}
void CharacterController::skipAnim()
{
mSkipAnim = true;
}
void CharacterController::setState(CharacterState state, bool loop)
{
if(mState == state)
{
if(mAnimation)
mAnimation->setLooping(loop);
return;
}
mState = state;
if(!mAnimation)
return;
mAnimQueue.clear();
std::string anim;
getStateInfo(mState, &anim);
if(mAnimation->hasAnimation(anim))
{
mCurrentGroup = anim;
mAnimation->play(mCurrentGroup, "start", "stop", loop);
}
}
}

View file

@ -0,0 +1,96 @@
#ifndef GAME_MWMECHANICS_CHARACTER_HPP
#define GAME_MWMECHANICS_CHARACTER_HPP
#include <OgreVector3.h>
#include "../mwworld/ptr.hpp"
namespace MWRender
{
class Animation;
}
namespace MWMechanics
{
enum CharacterState {
CharState_SpecialIdle,
CharState_Idle,
CharState_Idle2,
CharState_Idle3,
CharState_Idle4,
CharState_Idle5,
CharState_Idle6,
CharState_Idle7,
CharState_Idle8,
CharState_Idle9,
CharState_IdleSwim,
CharState_WalkForward,
CharState_WalkBack,
CharState_WalkLeft,
CharState_WalkRight,
CharState_SwimWalkForward,
CharState_SwimWalkBack,
CharState_SwimWalkLeft,
CharState_SwimWalkRight,
CharState_RunForward,
CharState_RunBack,
CharState_RunLeft,
CharState_RunRight,
CharState_SwimRunForward,
CharState_SwimRunBack,
CharState_SwimRunLeft,
CharState_SwimRunRight,
CharState_Jump,
/* Death states must be last! */
CharState_Death1,
CharState_Death2,
CharState_Death3,
CharState_Death4,
CharState_Death5
};
class CharacterController
{
MWWorld::Ptr mPtr;
MWRender::Animation *mAnimation;
typedef std::deque<std::string> AnimationQueue;
AnimationQueue mAnimQueue;
std::string mCurrentGroup;
CharacterState mState;
bool mSkipAnim;
protected:
/* Called by the animation whenever a new text key is reached. */
void markerEvent(float time, const std::string &evt);
friend class MWRender::Animation;
public:
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop);
CharacterController(const CharacterController &rhs);
virtual ~CharacterController();
void updatePtr(const MWWorld::Ptr &ptr);
Ogre::Vector3 update(float duration);
void playGroup(const std::string &groupname, int mode, int count);
void skipAnim();
void setState(CharacterState state, bool loop);
CharacterState getState() const
{ return mState; }
};
}
#endif /* GAME_MWMECHANICS_CHARACTER_HPP */

View file

@ -175,34 +175,47 @@ namespace MWMechanics
buildPlayer(); buildPlayer();
} }
void MechanicsManager::addActor (const MWWorld::Ptr& ptr) void MechanicsManager::add(const MWWorld::Ptr& ptr)
{ {
mActors.addActor (ptr); if(ptr.getTypeName() == typeid(ESM::Activator).name())
mActivators.addActivator(ptr);
else
mActors.addActor(ptr);
} }
void MechanicsManager::removeActor (const MWWorld::Ptr& ptr) void MechanicsManager::remove(const MWWorld::Ptr& ptr)
{ {
if (ptr==mWatched) if(ptr == mWatched)
mWatched = MWWorld::Ptr();
mActors.removeActor(ptr);
mActivators.removeActivator(ptr);
}
void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
{
if(ptr.getTypeName() == typeid(ESM::Activator).name())
mActivators.updateActivator(old, ptr);
else
mActors.updateActor(old, ptr);
}
void MechanicsManager::drop(const MWWorld::CellStore *cellStore)
{
if(!mWatched.isEmpty() && mWatched.getCell() == cellStore)
mWatched = MWWorld::Ptr(); mWatched = MWWorld::Ptr();
mActors.removeActor (ptr); mActors.dropActors(cellStore);
mActivators.dropActivators(cellStore);
} }
void MechanicsManager::dropActors (const MWWorld::Ptr::CellStore *cellStore)
{
if (!mWatched.isEmpty() && mWatched.getCell()==cellStore)
mWatched = MWWorld::Ptr();
mActors.dropActors (cellStore); void MechanicsManager::watchActor(const MWWorld::Ptr& ptr)
}
void MechanicsManager::watchActor (const MWWorld::Ptr& ptr)
{ {
mWatched = ptr; mWatched = ptr;
} }
void MechanicsManager::update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement, void MechanicsManager::update(float duration, bool paused)
float duration, bool paused)
{ {
if (!mWatched.isEmpty()) if (!mWatched.isEmpty())
{ {
@ -296,9 +309,16 @@ namespace MWMechanics
} }
winMgr->configureSkills (majorSkills, minorSkills); winMgr->configureSkills (majorSkills, minorSkills);
// HACK? The player has been changed, so a new Animation object may
// have been made for them. Make sure they're properly updated.
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
mActors.removeActor(ptr);
mActors.addActor(ptr);
} }
mActors.update (movement, duration, paused); mActors.update(duration, paused);
mActivators.update(duration, paused);
} }
void MechanicsManager::restoreDynamicStats() void MechanicsManager::restoreDynamicStats()
@ -471,8 +491,10 @@ namespace MWMechanics
if(buying) x = buyTerm; if(buying) x = buyTerm;
else x = std::min(buyTerm, sellTerm); else x = std::min(buyTerm, sellTerm);
int offerPrice; int offerPrice;
if (x < 1) offerPrice = int(x * basePrice); if (x < 1)
if (x >= 1) offerPrice = basePrice + int((x - 1) * basePrice); offerPrice = int(x * basePrice);
else
offerPrice = basePrice + int((x - 1) * basePrice);
offerPrice = std::max(1, offerPrice); offerPrice = std::max(1, offerPrice);
return offerPrice; return offerPrice;
} }
@ -535,7 +557,8 @@ namespace MWMechanics
float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat();
float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); float fPerTempMult = gmst.find("fPerTempMult")->getFloat();
float x,y; float x = 0;
float y = 0;
float roll = static_cast<float> (std::rand()) / RAND_MAX * 100; float roll = static_cast<float> (std::rand()) / RAND_MAX * 100;
@ -629,4 +652,20 @@ namespace MWMechanics
permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y; permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y;
} }
} }
void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
{
if(ptr.getTypeName() == typeid(ESM::Activator).name())
mActivators.playAnimationGroup(ptr, groupName, mode, number);
else
mActors.playAnimationGroup(ptr, groupName, mode, number);
}
void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr)
{
if(ptr.getTypeName() == typeid(ESM::Activator).name())
mActivators.skipAnimation(ptr);
else
mActors.skipAnimation(ptr);
}
} }

View file

@ -7,6 +7,7 @@
#include "creaturestats.hpp" #include "creaturestats.hpp"
#include "npcstats.hpp" #include "npcstats.hpp"
#include "activators.hpp"
#include "actors.hpp" #include "actors.hpp"
namespace Ogre namespace Ogre
@ -29,6 +30,8 @@ namespace MWMechanics
bool mUpdatePlayer; bool mUpdatePlayer;
bool mClassSelected; bool mClassSelected;
bool mRaceSelected; bool mRaceSelected;
Activators mActivators;
Actors mActors; Actors mActors;
void buildPlayer(); void buildPlayer();
@ -39,24 +42,24 @@ namespace MWMechanics
MechanicsManager(); MechanicsManager();
virtual void addActor (const MWWorld::Ptr& ptr); virtual void add (const MWWorld::Ptr& ptr);
///< Register an actor for stats management ///< Register an object for management
///
/// \note Dead actors are ignored.
virtual void removeActor (const MWWorld::Ptr& ptr); virtual void remove (const MWWorld::Ptr& ptr);
///< Deregister an actor for stats management ///< Deregister an object for management
virtual void dropActors (const MWWorld::CellStore *cellStore); virtual void updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr);
///< Deregister all actors in the given cell. ///< Moves an object to a new cell
virtual void watchActor (const MWWorld::Ptr& ptr); virtual void drop(const MWWorld::CellStore *cellStore);
///< Deregister all objects in the given cell.
virtual void watchActor(const MWWorld::Ptr& ptr);
///< On each update look for changes in a previously registered actor and update the ///< On each update look for changes in a previously registered actor and update the
/// GUI accordingly. /// GUI accordingly.
virtual void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement, virtual void update (float duration, bool paused);
float duration, bool paused); ///< Update objects
///< Update actor stats and store desired velocity vectors in \a movement
/// ///
/// \param paused In game type does not currently advance (this usually means some GUI /// \param paused In game type does not currently advance (this usually means some GUI
/// component is up). /// component is up).
@ -92,6 +95,9 @@ namespace MWMechanics
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange); float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange);
void toLower(std::string npcFaction); void toLower(std::string npcFaction);
///< Perform a persuasion action on NPC ///< Perform a persuasion action on NPC
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
virtual void skipAnimation(const MWWorld::Ptr& ptr);
}; };
} }

View file

@ -0,0 +1,56 @@
#include "activatoranimation.hpp"
#include <OgreEntity.h>
#include <OgreSceneManager.h>
#include <OgreSubEntity.h>
#include "renderconst.hpp"
#include "../mwbase/world.hpp"
namespace MWRender
{
ActivatorAnimation::~ActivatorAnimation()
{
}
ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr)
: Animation(ptr)
{
MWWorld::LiveCellRef<ESM::Activator> *ref = mPtr.get<ESM::Activator>();
assert (ref->mBase != NULL);
if(!ref->mBase->mModel.empty())
{
std::string mesh = "meshes\\" + ref->mBase->mModel;
createEntityList(mPtr.getRefData().getBaseNode(), mesh);
for(size_t i = 0;i < mEntityList.mEntities.size();i++)
{
Ogre::Entity *ent = mEntityList.mEntities[i];
bool transparent = false;
for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j)
{
Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial();
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while(!transparent && techIt.hasMoreElements())
{
Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while(!transparent && passIt.hasMoreElements())
{
Ogre::Pass* pass = passIt.getNext();
transparent = pass->isTransparent();
}
}
}
ent->setVisibilityFlags(RV_Misc);
ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
}
setAnimationSource(mesh);
}
}
}

View file

@ -0,0 +1,21 @@
#ifndef _GAME_RENDER_ACTIVATORANIMATION_H
#define _GAME_RENDER_ACTIVATORANIMATION_H
#include "animation.hpp"
namespace MWWorld
{
class Ptr;
}
namespace MWRender
{
class ActivatorAnimation : public Animation
{
public:
ActivatorAnimation(const MWWorld::Ptr& ptr);
virtual ~ActivatorAnimation();
};
}
#endif

View file

@ -3,14 +3,23 @@
#include <OgreSceneNode.h> #include <OgreSceneNode.h>
#include <OgreSceneManager.h> #include <OgreSceneManager.h>
#include "../mwworld/ptr.hpp"
#include "../mwworld/class.hpp"
#include "animation.hpp"
#include "activatoranimation.hpp"
#include "creatureanimation.hpp"
#include "npcanimation.hpp"
#include "renderconst.hpp" #include "renderconst.hpp"
namespace MWRender namespace MWRender
{ {
using namespace Ogre;
Actors::~Actors(){ Actors::~Actors()
{
PtrAnimationMap::iterator it = mAllActors.begin(); PtrAnimationMap::iterator it = mAllActors.begin();
for(;it != mAllActors.end();++it) for(;it != mAllActors.end();++it)
{ {
@ -19,18 +28,10 @@ Actors::~Actors(){
} }
} }
void Actors::setMwRoot(Ogre::SceneNode* root) void Actors::setRootNode(Ogre::SceneNode* root)
{ mMwRoot = root; } { mRootNode = root; }
void Actors::insertNPC(const MWWorld::Ptr &ptr, MWWorld::InventoryStore &inv) void Actors::insertBegin(const MWWorld::Ptr &ptr)
{
insertBegin(ptr, true, true);
NpcAnimation* anim = new MWRender::NpcAnimation(ptr, ptr.getRefData ().getBaseNode (), inv, RV_Actors);
mAllActors[ptr] = anim;
}
void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
{ {
Ogre::SceneNode* cellnode; Ogre::SceneNode* cellnode;
CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(ptr.getCell()); CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(ptr.getCell());
@ -39,7 +40,7 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
else else
{ {
//Create the scenenode and put it in the map //Create the scenenode and put it in the map
cellnode = mMwRoot->createChildSceneNode(); cellnode = mRootNode->createChildSceneNode();
mCellSceneNodes[ptr.getCell()] = cellnode; mCellSceneNodes[ptr.getCell()] = cellnode;
} }
@ -62,17 +63,27 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
// Rotates first around z, then y, then x // Rotates first around z, then y, then x
insert->setOrientation(xr*yr*zr); insert->setOrientation(xr*yr*zr);
if (!enabled)
insert->setVisible (false);
ptr.getRefData().setBaseNode(insert); ptr.getRefData().setBaseNode(insert);
} }
void Actors::insertCreature (const MWWorld::Ptr& ptr){
insertBegin(ptr, true, true);
CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr);
void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv)
{
insertBegin(ptr);
NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), inv, RV_Actors);
delete mAllActors[ptr];
mAllActors[ptr] = anim;
}
void Actors::insertCreature (const MWWorld::Ptr& ptr)
{
insertBegin(ptr);
CreatureAnimation* anim = new CreatureAnimation(ptr);
delete mAllActors[ptr];
mAllActors[ptr] = anim;
}
void Actors::insertActivator (const MWWorld::Ptr& ptr)
{
insertBegin(ptr);
ActivatorAnimation* anim = new ActivatorAnimation(ptr);
delete mAllActors[ptr]; delete mAllActors[ptr];
mAllActors[ptr] = anim; mAllActors[ptr] = anim;
} }
@ -125,47 +136,41 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store)
} }
} }
void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
{
PtrAnimationMap::const_iterator iter = mAllActors.find(ptr);
if(iter != mAllActors.end())
iter->second->playGroup(groupName, mode, number);
}
void Actors::skipAnimation (const MWWorld::Ptr& ptr)
{
PtrAnimationMap::const_iterator iter = mAllActors.find(ptr);
if(iter != mAllActors.end())
iter->second->skipAnim();
}
void Actors::update (float duration) void Actors::update (float duration)
{ {
for(PtrAnimationMap::const_iterator iter = mAllActors.begin();iter != mAllActors.end();iter++) // Nothing to do
iter->second->runAnimation(duration);
} }
void Actors::updateObjectCell(const MWWorld::Ptr &ptr) Animation* Actors::getAnimation(const MWWorld::Ptr &ptr)
{
PtrAnimationMap::const_iterator iter = mAllActors.find(ptr);
if(iter != mAllActors.end())
return iter->second;
return NULL;
}
void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur)
{ {
Ogre::SceneNode *node; Ogre::SceneNode *node;
MWWorld::CellStore *newCell = ptr.getCell(); MWWorld::CellStore *newCell = cur.getCell();
CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell); CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell);
if(celliter != mCellSceneNodes.end()) if(celliter != mCellSceneNodes.end())
node = celliter->second; node = celliter->second;
else else
{ {
node = mMwRoot->createChildSceneNode(); node = mRootNode->createChildSceneNode();
mCellSceneNodes[newCell] = node; mCellSceneNodes[newCell] = node;
} }
node->addChild(ptr.getRefData().getBaseNode()); node->addChild(cur.getRefData().getBaseNode());
PtrAnimationMap::iterator iter = mAllActors.find(ptr); PtrAnimationMap::iterator iter = mAllActors.find(old);
if(iter != mAllActors.end()) if(iter != mAllActors.end())
{ {
/// \note Update key (Ptr's are compared only with refdata so mCell
/// on key is outdated), maybe redundant
Animation *anim = iter->second; Animation *anim = iter->second;
mAllActors.erase(iter); mAllActors.erase(iter);
mAllActors[ptr] = anim; anim->updatePtr(cur);
mAllActors[cur] = anim;
} }
} }

View file

@ -1,24 +1,27 @@
#ifndef _GAME_RENDER_ACTORS_H #ifndef _GAME_RENDER_ACTORS_H
#define _GAME_RENDER_ACTORS_H #define _GAME_RENDER_ACTORS_H
#include "npcanimation.hpp" #include <openengine/ogre/renderer.hpp>
#include "creatureanimation.hpp"
namespace MWWorld namespace MWWorld
{ {
class Ptr; class Ptr;
class CellStore; class CellStore;
class InventoryStore;
} }
namespace MWRender namespace MWRender
{ {
class Animation;
class Actors class Actors
{ {
typedef std::map<MWWorld::CellStore*,Ogre::SceneNode*> CellSceneNodeMap; typedef std::map<MWWorld::CellStore*,Ogre::SceneNode*> CellSceneNodeMap;
typedef std::map<MWWorld::Ptr,Animation*> PtrAnimationMap; typedef std::map<MWWorld::Ptr,Animation*> PtrAnimationMap;
OEngine::Render::OgreRenderer &mRend; OEngine::Render::OgreRenderer &mRend;
Ogre::SceneNode* mMwRoot; Ogre::SceneNode* mRootNode;
CellSceneNodeMap mCellSceneNodes; CellSceneNodeMap mCellSceneNodes;
PtrAnimationMap mAllActors; PtrAnimationMap mAllActors;
@ -26,31 +29,22 @@ namespace MWRender
Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {}
~Actors(); ~Actors();
void setMwRoot(Ogre::SceneNode* root); void setRootNode(Ogre::SceneNode* root);
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertBegin (const MWWorld::Ptr& ptr);
void insertCreature (const MWWorld::Ptr& ptr);
void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv);
void insertCreature (const MWWorld::Ptr& ptr);
void insertActivator (const MWWorld::Ptr& ptr);
bool deleteObject (const MWWorld::Ptr& ptr); bool deleteObject (const MWWorld::Ptr& ptr);
///< \return found? ///< \return found?
void removeCell(MWWorld::CellStore* store); void removeCell(MWWorld::CellStore* store);
void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode,
int number = 1);
///< Run animation for a MW-reference. Calls to this function for references that are currently not
/// in the rendered scene should be ignored.
///
/// \param mode: 0 normal, 1 immediate start, 2 immediate loop
/// \param number How offen the animation should be run
void skipAnimation (const MWWorld::Ptr& ptr);
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
/// references that are currently not in the rendered scene should be ignored.
void update (float duration); void update (float duration);
/// Updates containing cell for object rendering data /// Updates containing cell for object rendering data
void updateObjectCell(const MWWorld::Ptr &ptr); void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur);
Animation* getAnimation(const MWWorld::Ptr &ptr);
}; };
} }
#endif #endif

View file

@ -1,148 +1,453 @@
#include "animation.hpp" #include "animation.hpp"
#include <OgreHardwarePixelBuffer.h> #include <OgreSkeletonManager.h>
#include <OgreSkeletonInstance.h> #include <OgreSkeletonInstance.h>
#include <OgreEntity.h> #include <OgreEntity.h>
#include <OgreBone.h> #include <OgreBone.h>
#include <OgreSubMesh.h> #include <OgreSubMesh.h>
#include <OgreSceneManager.h> #include <OgreSceneManager.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwmechanics/character.hpp"
namespace MWRender namespace MWRender
{ {
Animation::Animation() Animation::Animation(const MWWorld::Ptr &ptr)
: mInsert(NULL) : mPtr(ptr)
, mTime(0.0f) , mController(NULL)
, mSkipFrame(false) , mInsert(NULL)
, mAccumRoot(NULL)
, mNonAccumRoot(NULL)
, mAccumulate(Ogre::Vector3::ZERO)
, mLastPosition(0.0f)
, mCurrentKeys(NULL)
, mCurrentAnim(NULL)
, mCurrentTime(0.0f)
, mStopTime(0.0f)
, mPlaying(false)
, mLooping(false)
, mAnimVelocity(0.0f)
, mAnimSpeedMult(1.0f)
{ {
} }
Animation::~Animation() Animation::~Animation()
{ {
Ogre::SceneManager *sceneMgr = mInsert->getCreator(); if(mInsert)
for(size_t i = 0;i < mEntityList.mEntities.size();i++) {
sceneMgr->destroyEntity(mEntityList.mEntities[i]); Ogre::SceneManager *sceneMgr = mInsert->getCreator();
for(size_t i = 0;i < mEntityList.mEntities.size();i++)
sceneMgr->destroyEntity(mEntityList.mEntities[i]);
}
mEntityList.mEntities.clear(); mEntityList.mEntities.clear();
mEntityList.mSkelBase = NULL;
} }
struct checklow { void Animation::setAnimationSources(const std::vector<std::string> &names)
bool operator()(const char &a, const char &b) const
{
return ::tolower(a) == ::tolower(b);
}
};
bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times)
{ {
const std::string &start = groupname+": start"; if(!mEntityList.mSkelBase)
const std::string &startloop = groupname+": loop start"; return;
const std::string &stop = groupname+": stop";
const std::string &stoploop = groupname+": loop stop";
NifOgre::TextKeyMap::const_iterator iter; mCurrentAnim = NULL;
for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) mCurrentKeys = NULL;
mAnimVelocity = 0.0f;
mAccumRoot = NULL;
mNonAccumRoot = NULL;
mSkeletonSources.clear();
std::vector<std::string>::const_iterator nameiter;
for(nameiter = names.begin();nameiter != names.end();nameiter++)
{ {
if(times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f) Ogre::SkeletonPtr skel = NifOgre::Loader::getSkeleton(*nameiter);
return true; if(skel.isNull())
{
std::cerr<< "Failed to get skeleton source "<<*nameiter <<std::endl;
continue;
}
skel->touch();
std::string::const_iterator strpos = iter->second.begin(); Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator();
std::string::const_iterator strend = iter->second.end(); while(boneiter.hasMoreElements())
size_t strlen = strend-strpos; {
Ogre::Bone *bone = boneiter.getNext();
Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings();
const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID);
if(data.isEmpty() || !Ogre::any_cast<bool>(data))
continue;
if(!mNonAccumRoot)
{
mAccumRoot = mInsert;
mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getName());
}
mSkeletonSources.push_back(skel);
for(int i = 0;i < skel->getNumAnimations();i++)
{
Ogre::Animation *anim = skel->getAnimation(i);
const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+
"@"+anim->getName());
if(!groupdata.isEmpty())
mTextKeys[anim->getName()] = Ogre::any_cast<NifOgre::TextKeyMap>(groupdata);
}
if(start.size() <= strlen && std::mismatch(strpos, strend, start.begin(), checklow()).first == strend)
{
times->mStart = iter->first;
times->mLoopStart = iter->first;
}
else if(startloop.size() <= strlen && std::mismatch(strpos, strend, startloop.begin(), checklow()).first == strend)
{
times->mLoopStart = iter->first;
}
else if(stoploop.size() <= strlen && std::mismatch(strpos, strend, stoploop.begin(), checklow()).first == strend)
{
times->mLoopStop = iter->first;
}
else if(stop.size() <= strlen && std::mismatch(strpos, strend, stop.begin(), checklow()).first == strend)
{
times->mStop = iter->first;
if(times->mLoopStop < 0.0f)
times->mLoopStop = iter->first;
break; break;
} }
} }
}
return (times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f); void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model)
{
mInsert = node->createChildSceneNode();
assert(mInsert);
mEntityList = NifOgre::Loader::createEntities(mInsert, model);
if(mEntityList.mSkelBase)
{
Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates();
Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator();
while(asiter.hasMoreElements())
{
Ogre::AnimationState *state = asiter.getNext();
state->setEnabled(false);
state->setLoop(false);
}
// Set the bones as manually controlled since we're applying the
// transformations manually (needed if we want to apply an animation
// from one skeleton onto another).
Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton();
Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator();
while(boneiter.hasMoreElements())
boneiter.getNext()->setManuallyControlled(true);
}
} }
void Animation::playGroup(std::string groupname, int mode, int loops) bool Animation::hasAnimation(const std::string &anim)
{ {
GroupTimes times; for(std::vector<Ogre::SkeletonPtr>::const_iterator iter(mSkeletonSources.begin());iter != mSkeletonSources.end();iter++)
times.mLoops = loops;
if(groupname == "all")
{ {
times.mStart = times.mLoopStart = 0.0f; if((*iter)->hasAnimation(anim))
times.mLoopStop = times.mStop = 0.0f; return true;
NifOgre::TextKeyMap::const_reverse_iterator iter = mTextKeys.rbegin();
if(iter != mTextKeys.rend())
times.mLoopStop = times.mStop = iter->first;
} }
else if(!findGroupTimes(groupname, &times)) return false;
throw std::runtime_error("Failed to find animation group "+groupname); }
if(mode == 0 && mCurGroup.mLoops > 0)
mNextGroup = times; void Animation::setController(MWMechanics::CharacterController *controller)
{
mController = controller;
}
void Animation::setAccumulation(const Ogre::Vector3 &accum)
{
mAccumulate = accum;
}
void Animation::setSpeed(float speed)
{
mAnimSpeedMult = 1.0f;
if(mAnimVelocity > 1.0f && speed > 0.0f)
mAnimSpeedMult = speed / mAnimVelocity;
}
void Animation::setLooping(bool loop)
{
mLooping = loop;
}
void Animation::updatePtr(const MWWorld::Ptr &ptr)
{
mPtr = ptr;
}
void Animation::calcAnimVelocity()
{
const Ogre::NodeAnimationTrack *track = 0;
Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator();
while(!track && trackiter.hasMoreElements())
{
const Ogre::NodeAnimationTrack *cur = trackiter.getNext();
if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName())
track = cur;
}
if(track && track->getNumKeyFrames() > 1)
{
float loopstarttime = 0.0f;
float loopstoptime = mCurrentAnim->getLength();
NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin();
while(keyiter != mCurrentKeys->end())
{
if(keyiter->second == "loop start")
loopstarttime = keyiter->first;
else if(keyiter->second == "loop stop")
{
loopstoptime = keyiter->first;
break;
}
keyiter++;
}
if(loopstoptime > loopstarttime)
{
Ogre::TransformKeyFrame startkf(0, loopstarttime);
Ogre::TransformKeyFrame endkf(0, loopstoptime);
track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf);
track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf);
mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) /
(loopstoptime-loopstarttime);
}
}
}
void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel)
{
Ogre::TimeIndex timeindex = anim->_getTimeIndex(time);
Ogre::Animation::NodeTrackIterator tracks = anim->getNodeTrackIterator();
while(tracks.hasMoreElements())
{
Ogre::NodeAnimationTrack *track = tracks.getNext();
const Ogre::String &targetname = track->getAssociatedNode()->getName();
if(!skel->hasBone(targetname))
continue;
Ogre::Bone *bone = skel->getBone(targetname);
bone->setOrientation(Ogre::Quaternion::IDENTITY);
bone->setPosition(Ogre::Vector3::ZERO);
bone->setScale(Ogre::Vector3::UNIT_SCALE);
track->applyToNode(bone, timeindex);
}
// HACK: Dirty the animation state set so that Ogre will apply the
// transformations to entities this skeleton instance is shared with.
mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty();
}
static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone)
{
if(skelsrc->hasBone(bone->getName()))
{
Ogre::Bone *srcbone = skelsrc->getBone(bone->getName());
if(!srcbone->getParent() || !bone->getParent())
{
bone->setOrientation(srcbone->getOrientation());
bone->setPosition(srcbone->getPosition());
bone->setScale(srcbone->getScale());
}
else
{
bone->_setDerivedOrientation(srcbone->_getDerivedOrientation());
bone->_setDerivedPosition(srcbone->_getDerivedPosition());
bone->setScale(Ogre::Vector3::UNIT_SCALE);
}
}
else else
{ {
mCurGroup = times; // No matching bone in the source. Make sure it stays properly offset
mNextGroup = GroupTimes(); // from its parent.
mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart); bone->resetToInitialState();
} }
Ogre::Node::ChildNodeIterator boneiter = bone->getChildIterator();
while(boneiter.hasMoreElements())
updateBoneTree(skelsrc, static_cast<Ogre::Bone*>(boneiter.getNext()));
} }
void Animation::skipAnim() void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel)
{ {
mSkipFrame = true; Ogre::Skeleton::BoneIterator boneiter = skel->getRootBoneIterator();
while(boneiter.hasMoreElements())
updateBoneTree(skelsrc, boneiter.getNext());
} }
void Animation::runAnimation(float timepassed)
Ogre::Vector3 Animation::updatePosition(float time)
{ {
if(mCurGroup.mLoops > 0 && !mSkipFrame) if(mLooping)
mCurrentTime = std::fmod(std::max(time, 0.0f), mCurrentAnim->getLength());
else
mCurrentTime = std::min(mCurrentAnim->getLength(), std::max(time, 0.0f));
applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton());
Ogre::Vector3 posdiff = Ogre::Vector3::ZERO;
if(mNonAccumRoot)
{ {
mTime += timepassed; /* Get the non-accumulation root's difference from the last update. */
if(mTime >= mCurGroup.mLoopStop) posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate;
/* Translate the accumulation root back to compensate for the move. */
mLastPosition += posdiff;
mAccumRoot->setPosition(-mLastPosition);
}
return posdiff;
}
void Animation::reset(const std::string &start, const std::string &stop)
{
mNextKey = mCurrentKeys->begin();
while(mNextKey != mCurrentKeys->end() && mNextKey->second != start)
mNextKey++;
if(mNextKey != mCurrentKeys->end())
mCurrentTime = mNextKey->first;
else
{
mNextKey = mCurrentKeys->begin();
mCurrentTime = 0.0f;
}
if(stop.length() > 0)
{
NifOgre::TextKeyMap::const_iterator stopKey = mNextKey;
while(stopKey != mCurrentKeys->end() && stopKey->second != stop)
stopKey++;
if(stopKey != mCurrentKeys->end())
mStopTime = stopKey->first;
else
mStopTime = mCurrentAnim->getLength();
}
if(mNonAccumRoot)
{
const Ogre::NodeAnimationTrack *track = 0;
Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator();
while(!track && trackiter.hasMoreElements())
{ {
if(mCurGroup.mLoops > 1) const Ogre::NodeAnimationTrack *cur = trackiter.getNext();
{ if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName())
mCurGroup.mLoops--; track = cur;
mTime = mTime - mCurGroup.mLoopStop + mCurGroup.mLoopStart;
}
else if(mTime >= mCurGroup.mStop)
{
if(mNextGroup.mLoops > 0)
mTime = mTime - mCurGroup.mStop + mNextGroup.mStart;
else
mTime = mCurGroup.mStop;
mCurGroup = mNextGroup;
mNextGroup = GroupTimes();
}
} }
if(mEntityList.mSkelBase) if(track)
{ {
Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); Ogre::TransformKeyFrame kf(0, mCurrentTime);
Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf);
while(as.hasMoreElements()) mLastPosition = kf.getTranslate() * mAccumulate;
{
Ogre::AnimationState *state = as.getNext();
state->setTimePosition(mTime);
}
} }
} }
mSkipFrame = false; }
bool Animation::handleEvent(float time, const std::string &evt)
{
if(evt == "start" || evt == "loop start")
{
/* Do nothing */
return true;
}
if(evt.compare(0, 7, "sound: ") == 0)
{
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f);
return true;
}
if(evt.compare(0, 10, "soundgen: ") == 0)
{
// FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds
// to this actor type
return true;
}
if(evt == "loop stop")
{
if(mLooping)
{
reset("loop start", "");
if(mCurrentTime >= time)
return false;
}
return true;
}
if(evt == "stop")
{
if(mLooping)
{
reset("loop start", "");
if(mCurrentTime >= time)
return false;
return true;
}
// fall-through
}
if(mController)
mController->markerEvent(time, evt);
return true;
}
void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop)
{
try {
bool found = false;
/* Look in reverse; last-inserted source has priority. */
for(std::vector<Ogre::SkeletonPtr>::const_reverse_iterator iter(mSkeletonSources.rbegin());iter != mSkeletonSources.rend();iter++)
{
if((*iter)->hasAnimation(groupname))
{
mCurrentAnim = (*iter)->getAnimation(groupname);
mCurrentKeys = &mTextKeys[groupname];
mAnimVelocity = 0.0f;
if(mNonAccumRoot)
calcAnimVelocity();
found = true;
break;
}
}
if(!found)
throw std::runtime_error("Failed to find animation "+groupname);
reset(start, stop);
setLooping(loop);
mPlaying = true;
}
catch(std::exception &e) {
std::cerr<< e.what() <<std::endl;
}
}
Ogre::Vector3 Animation::runAnimation(float timepassed)
{
Ogre::Vector3 movement = Ogre::Vector3::ZERO;
timepassed *= mAnimSpeedMult;
while(mCurrentAnim && mPlaying)
{
float targetTime = std::min(mStopTime, mCurrentTime+timepassed);
if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime)
{
movement += updatePosition(targetTime);
mPlaying = (mLooping || mStopTime > targetTime);
break;
}
float time = mNextKey->first;
const std::string &evt = mNextKey->second;
mNextKey++;
movement += updatePosition(time);
mPlaying = (mLooping || mStopTime > time);
timepassed = targetTime - time;
if(!handleEvent(time, evt))
break;
}
return movement;
} }
} }

View file

@ -1,55 +1,99 @@
#ifndef _GAME_RENDER_ANIMATION_H #ifndef _GAME_RENDER_ANIMATION_H
#define _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H
#include <vector>
#include <components/nifogre/ogre_nif_loader.hpp> #include <components/nifogre/ogre_nif_loader.hpp>
#include <openengine/ogre/renderer.hpp>
#include "../mwworld/actiontalk.hpp"
#include <components/nif/node.hpp>
#include <openengine/bullet/physic.hpp>
#include "../mwworld/ptr.hpp"
namespace MWMechanics
{
class CharacterController;
}
namespace MWRender
{
namespace MWRender { class Animation
{
class Animation {
struct GroupTimes {
float mStart;
float mStop;
float mLoopStart;
float mLoopStop;
size_t mLoops;
GroupTimes()
: mStart(-1.0f), mStop(-1.0f), mLoopStart(-1.0f), mLoopStop(-1.0f),
mLoops(0)
{ }
};
protected: protected:
MWWorld::Ptr mPtr;
MWMechanics::CharacterController *mController;
Ogre::SceneNode* mInsert; Ogre::SceneNode* mInsert;
float mTime;
GroupTimes mCurGroup;
GroupTimes mNextGroup;
bool mSkipFrame;
NifOgre::EntityList mEntityList; NifOgre::EntityList mEntityList;
NifOgre::TextKeyMap mTextKeys; std::map<std::string,NifOgre::TextKeyMap> mTextKeys;
Ogre::Node *mAccumRoot;
Ogre::Bone *mNonAccumRoot;
Ogre::Vector3 mAccumulate;
Ogre::Vector3 mLastPosition;
bool findGroupTimes(const std::string &groupname, GroupTimes *times); std::vector<Ogre::SkeletonPtr> mSkeletonSources;
NifOgre::TextKeyMap *mCurrentKeys;
NifOgre::TextKeyMap::const_iterator mNextKey;
Ogre::Animation *mCurrentAnim;
float mCurrentTime;
float mStopTime;
bool mPlaying;
bool mLooping;
float mAnimVelocity;
float mAnimSpeedMult;
void calcAnimVelocity();
/* Applies the given animation to the given skeleton instance, using the specified time. */
void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel);
/* Updates a skeleton instance so that all bones matching the source skeleton (based on
* bone names) are positioned identically. */
void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel);
/* Updates the animation to the specified time, and returns the movement
* vector since the last update or reset. */
Ogre::Vector3 updatePosition(float time);
/* Resets the animation to the time of the specified start marker, without
* moving anything, and set the end time to the specified stop marker. If
* the marker is not found, it resets to the beginning or end respectively.
*/
void reset(const std::string &start, const std::string &stop);
bool handleEvent(float time, const std::string &evt);
/* Specifies a list of skeleton names to use as animation sources. */
void setAnimationSources(const std::vector<std::string> &names);
/* Specifies a single skeleton name to use as an animation source. */
void setAnimationSource(const std::string &name)
{
std::vector<std::string> names(1, name);
setAnimationSources(names);
}
void createEntityList(Ogre::SceneNode *node, const std::string &model);
public: public:
Animation(); Animation(const MWWorld::Ptr &ptr);
virtual ~Animation(); virtual ~Animation();
void playGroup(std::string groupname, int mode, int loops); void setController(MWMechanics::CharacterController *controller);
void skipAnim();
virtual void runAnimation(float timepassed); void updatePtr(const MWWorld::Ptr &ptr);
bool hasAnimation(const std::string &anim);
// Specifies the axis' to accumulate on. Non-accumulated axis will just
// move visually, but not affect the actual movement. Each x/y/z value
// should be on the scale of 0 to 1.
void setAccumulation(const Ogre::Vector3 &accum);
void setSpeed(float speed);
void setLooping(bool loop);
void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop);
virtual Ogre::Vector3 runAnimation(float timepassed);
}; };
} }

View file

@ -11,6 +11,7 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "../mwworld/class.hpp"
#include "renderconst.hpp" #include "renderconst.hpp"
#include "npcanimation.hpp" #include "npcanimation.hpp"
@ -120,7 +121,8 @@ namespace MWRender
void InventoryPreview::update(int sizeX, int sizeY) void InventoryPreview::update(int sizeX, int sizeY)
{ {
mAnimation->forceUpdate (); mAnimation->forceUpdate();
mAnimation->runAnimation(0.0f);
mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024))); mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024)));
@ -143,8 +145,7 @@ namespace MWRender
{ {
mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview);
mAnimation->playGroup ("inventoryhandtohand", 0, 1); mAnimation->play("inventoryhandtohand", "start", "stop", false);
mAnimation->runAnimation (0);
} }
// -------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------
@ -160,6 +161,7 @@ namespace MWRender
void RaceSelectionPreview::update(float angle) void RaceSelectionPreview::update(float angle)
{ {
mAnimation->runAnimation(0.0f);
mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL); mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL);
mNode->setVisible (true); mNode->setVisible (true);
@ -174,4 +176,9 @@ namespace MWRender
rebuild(); rebuild();
update(0); update(0);
} }
void RaceSelectionPreview::onSetup ()
{
mAnimation->play("idle", "start", "stop", false);
}
} }

View file

@ -85,6 +85,8 @@ namespace MWRender
public: public:
RaceSelectionPreview(); RaceSelectionPreview();
virtual void onSetup();
void update(float angle); void update(float angle);
const ESM::NPC &getPrototype() const { const ESM::NPC &getPrototype() const {

View file

@ -8,70 +8,54 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
using namespace Ogre; namespace MWRender
using namespace NifOgre; {
namespace MWRender{
CreatureAnimation::~CreatureAnimation() CreatureAnimation::~CreatureAnimation()
{ {
} }
CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr)
: Animation(ptr)
{ {
mInsert = ptr.getRefData().getBaseNode(); MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
assert (ref->mBase != NULL); assert (ref->mBase != NULL);
if(!ref->mBase->mModel.empty()) if(!ref->mBase->mModel.empty())
{ {
std::string mesh = "meshes\\" + ref->mBase->mModel; std::string model = "meshes\\"+ref->mBase->mModel;
mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, mesh); createEntityList(mPtr.getRefData().getBaseNode(), model);
for(size_t i = 0;i < mEntityList.mEntities.size();i++) for(size_t i = 0;i < mEntityList.mEntities.size();i++)
{ {
Ogre::Entity *ent = mEntityList.mEntities[i]; Ogre::Entity *ent = mEntityList.mEntities[i];
ent->setVisibilityFlags(RV_Actors); ent->setVisibilityFlags(RV_Actors);
bool transparent = false; bool transparent = false;
for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j)
{ {
Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial();
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while (techIt.hasMoreElements() && !transparent) while(!transparent && techIt.hasMoreElements())
{ {
Ogre::Technique* tech = techIt.getNext(); Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator(); Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while (passIt.hasMoreElements() && !transparent) while(!transparent && passIt.hasMoreElements())
{ {
Ogre::Pass* pass = passIt.getNext(); Ogre::Pass* pass = passIt.getNext();
transparent = pass->isTransparent();
if (pass->getDepthWriteEnabled() == false)
transparent = true;
} }
} }
} }
ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
} }
if(mEntityList.mSkelBase) std::vector<std::string> names;
{ if((ref->mBase->mFlags&ESM::Creature::Biped))
Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); names.push_back("meshes\\base_anim.nif");
Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); names.push_back(model);
while(as.hasMoreElements()) setAnimationSources(names);
{
Ogre::AnimationState *state = as.getNext();
state->setEnabled(true);
state->setLoop(false);
}
}
} }
} }
void CreatureAnimation::runAnimation(float timepassed)
{
// Placeholder
Animation::runAnimation(timepassed);
}
} }

View file

@ -3,18 +3,19 @@
#include "animation.hpp" #include "animation.hpp"
#include "components/nifogre/ogre_nif_loader.hpp" namespace MWWorld
{
class Ptr;
}
namespace MWRender
namespace MWRender{ {
class CreatureAnimation : public Animation
class CreatureAnimation: public Animation
{ {
public: public:
virtual ~CreatureAnimation();
CreatureAnimation(const MWWorld::Ptr& ptr); CreatureAnimation(const MWWorld::Ptr& ptr);
virtual void runAnimation(float timepassed); virtual ~CreatureAnimation();
}; };
} }
#endif #endif

View file

@ -8,6 +8,8 @@
#include <OgreMaterialManager.h> #include <OgreMaterialManager.h>
#include <OgreManualObject.h> #include <OgreManualObject.h>
#include <openengine/bullet/physic.hpp>
#include <components/esm/loadstat.hpp> #include <components/esm/loadstat.hpp>
#include <components/esm/loadpgrd.hpp> #include <components/esm/loadpgrd.hpp>
@ -148,9 +150,9 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid)
return result; return result;
} }
Debugging::Debugging(SceneNode *mwRoot, OEngine::Physic::PhysicEngine *engine) : Debugging::Debugging(SceneNode *root, OEngine::Physic::PhysicEngine *engine) :
mMwRoot(mwRoot), mEngine(engine), mRootNode(root), mEngine(engine),
mSceneMgr(mwRoot->getCreator()), mSceneMgr(root->getCreator()),
mPathgridEnabled(false), mPathgridEnabled(false),
mInteriorPathgridNode(NULL), mPathGridRoot(NULL), mInteriorPathgridNode(NULL), mPathGridRoot(NULL),
mGridMatsCreated(false) mGridMatsCreated(false)
@ -206,7 +208,7 @@ void Debugging::togglePathgrid()
createGridMaterials(); createGridMaterials();
// add path grid meshes to already loaded cells // add path grid meshes to already loaded cells
mPathGridRoot = mMwRoot->createChildSceneNode(); mPathGridRoot = mRootNode->createChildSceneNode();
for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it)
{ {
enableCellPathgrid(*it); enableCellPathgrid(*it);

View file

@ -3,7 +3,6 @@
#include <utility> #include <utility>
#include <openengine/ogre/renderer.hpp> #include <openengine/ogre/renderer.hpp>
#include <openengine/bullet/physic.hpp>
#include <vector> #include <vector>
#include <string> #include <string>
@ -13,6 +12,14 @@ namespace ESM
struct Pathgrid; struct Pathgrid;
} }
namespace OEngine
{
namespace Physic
{
class PhysicEngine;
}
}
namespace Ogre namespace Ogre
{ {
class Camera; class Camera;
@ -47,7 +54,7 @@ namespace MWRender
typedef std::vector<MWWorld::CellStore *> CellList; typedef std::vector<MWWorld::CellStore *> CellList;
CellList mActiveCells; CellList mActiveCells;
Ogre::SceneNode *mMwRoot; Ogre::SceneNode *mRootNode;
Ogre::SceneNode *mPathGridRoot; Ogre::SceneNode *mPathGridRoot;
@ -71,7 +78,7 @@ namespace MWRender
Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid); Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid);
Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid); Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid);
public: public:
Debugging(Ogre::SceneNode* mwRoot, OEngine::Physic::PhysicEngine *engine); Debugging(Ogre::SceneNode* root, OEngine::Physic::PhysicEngine *engine);
~Debugging(); ~Debugging();
bool toggleRenderMode (int mode); bool toggleRenderMode (int mode);

View file

@ -190,7 +190,7 @@ namespace MWRender
{ {
imageX = float(x / 8192.f - mMinX) / (mMaxX - mMinX + 1); imageX = float(x / 8192.f - mMinX) / (mMaxX - mMinX + 1);
imageY = 1.f-float(-z / 8192.f - mMinY) / (mMaxY - mMinY + 1); imageY = 1.f-float(z / 8192.f - mMinY) / (mMaxY - mMinY + 1);
} }
void GlobalMap::cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY) void GlobalMap::cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY)

View file

@ -28,9 +28,6 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag
mCellCamera = mRendering->getScene()->createCamera("CellCamera"); mCellCamera = mRendering->getScene()->createCamera("CellCamera");
mCellCamera->setProjectionType(PT_ORTHOGRAPHIC); mCellCamera->setProjectionType(PT_ORTHOGRAPHIC);
// look down -y
const float sqrt0pt5 = 0.707106781;
mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0));
mCameraNode->attachObject(mCellCamera); mCameraNode->attachObject(mCellCamera);
} }
@ -82,8 +79,8 @@ void LocalMap::saveFogOfWar(MWWorld::Ptr::CellStore* cell)
} }
else else
{ {
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y);
Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z); Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y);
Vector2 length = max-min; Vector2 length = max-min;
// divide into segments // divide into segments
@ -107,6 +104,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell)
mInterior = false; mInterior = false;
mCameraRotNode->setOrientation(Quaternion::IDENTITY); mCameraRotNode->setOrientation(Quaternion::IDENTITY);
mCellCamera->setOrientation(Quaternion(Ogre::Math::Cos(Ogre::Degree(0)/2.f), 0, 0, -Ogre::Math::Sin(Ogre::Degree(0)/2.f)));
int x = cell->mCell->getGridX(); int x = cell->mCell->getGridX();
int y = cell->mCell->getGridY(); int y = cell->mCell->getGridY();
@ -115,49 +113,60 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell)
mCameraPosNode->setPosition(Vector3(0,0,0)); mCameraPosNode->setPosition(Vector3(0,0,0));
render((x+0.5)*sSize, (-y-0.5)*sSize, -10000, 10000, sSize, sSize, name); render((x+0.5)*sSize, (y+0.5)*sSize, -10000, 10000, sSize, sSize, name);
} }
void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell,
AxisAlignedBox bounds) AxisAlignedBox bounds)
{ {
// if we're in an empty cell, don't bother rendering anything
if (bounds.isNull ())
return;
mInterior = true; mInterior = true;
mBounds = bounds; mBounds = bounds;
Vector2 z(mBounds.getMaximum().y, mBounds.getMinimum().y); float zMin = mBounds.getMinimum().z;
float zMax = mBounds.getMaximum().z;
const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell); const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell);
Radian angle(std::atan2(-north.x, -north.y)); Radian angle = Ogre::Math::ATan2 (north.x, north.y);
mAngle = angle.valueRadians(); mAngle = angle.valueRadians();
mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, Math::Sin(angle/2.f), 0));
mCellCamera->setOrientation(Quaternion::IDENTITY);
mCameraRotNode->setOrientation(Quaternion(Math::Cos(mAngle/2.f), 0, 0, -Math::Sin(mAngle/2.f)));
// rotate the cell and merge the rotated corners to the bounding box // rotate the cell and merge the rotated corners to the bounding box
Vector2 _center(bounds.getCenter().x, bounds.getCenter().z); Vector2 _center(bounds.getCenter().x, bounds.getCenter().y);
Vector3 _c1 = bounds.getCorner(AxisAlignedBox::NEAR_LEFT_BOTTOM); Vector3 _c1 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM);
Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM); Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM);
Vector3 _c3 = bounds.getCorner(AxisAlignedBox::NEAR_RIGHT_BOTTOM); Vector3 _c3 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_TOP);
Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM); Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_TOP);
Vector2 c1(_c1.x, _c1.z);
Vector2 c2(_c2.x, _c2.z); Vector2 c1(_c1.x, _c1.y);
Vector2 c3(_c3.x, _c3.z); Vector2 c2(_c2.x, _c2.y);
Vector2 c4(_c4.x, _c4.z); Vector2 c3(_c3.x, _c3.y);
Vector2 c4(_c4.x, _c4.y);
c1 = rotatePoint(c1, _center, mAngle); c1 = rotatePoint(c1, _center, mAngle);
c2 = rotatePoint(c2, _center, mAngle); c2 = rotatePoint(c2, _center, mAngle);
c3 = rotatePoint(c3, _center, mAngle); c3 = rotatePoint(c3, _center, mAngle);
c4 = rotatePoint(c4, _center, mAngle); c4 = rotatePoint(c4, _center, mAngle);
mBounds.merge(Vector3(c1.x, 0, c1.y)); mBounds.merge(Vector3(c1.x, c1.y, 0));
mBounds.merge(Vector3(c2.x, 0, c2.y)); mBounds.merge(Vector3(c2.x, c2.y, 0));
mBounds.merge(Vector3(c3.x, 0, c3.y)); mBounds.merge(Vector3(c3.x, c3.y, 0));
mBounds.merge(Vector3(c4.x, 0, c4.y)); mBounds.merge(Vector3(c4.x, c4.y, 0));
Vector2 center(mBounds.getCenter().x, mBounds.getCenter().z); // apply a little padding
mBounds.scale ((mBounds.getSize ()+Ogre::Vector3(1000,1000,0)) / mBounds.getSize ());
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y);
Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z);
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y);
Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y);
Vector2 length = max-min; Vector2 length = max-min;
mCameraPosNode->setPosition(Vector3(center.x, 0, center.y)); mCameraPosNode->setPosition(Vector3(center.x, center.y, 0));
// divide into segments // divide into segments
const int segsX = std::ceil( length.x / sSize ); const int segsX = std::ceil( length.x / sSize );
@ -172,7 +181,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell,
Vector2 start = min + Vector2(sSize*x,sSize*y); Vector2 start = min + Vector2(sSize*x,sSize*y);
Vector2 newcenter = start + 4096; Vector2 newcenter = start + 4096;
render(newcenter.x - center.x, newcenter.y - center.y, z.y, z.x, sSize, sSize, render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, sSize, sSize,
cell->mCell->mName + "_" + coordStr(x,y)); cell->mCell->mName + "_" + coordStr(x,y));
} }
} }
@ -193,7 +202,7 @@ void LocalMap::render(const float x, const float y,
mRendering->getScene()->setAmbientLight(ColourValue(1,1,1)); mRendering->getScene()->setAmbientLight(ColourValue(1,1,1));
mRenderingManager->disableLights(); mRenderingManager->disableLights();
mCameraNode->setPosition(Vector3(x, zhigh+100000, y)); mCameraNode->setPosition(Vector3(x, y, zhigh+100000));
//mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 );
mCellCamera->setFarClipDistance(0); // infinite mCellCamera->setFarClipDistance(0); // infinite
@ -272,15 +281,15 @@ void LocalMap::render(const float x, const float y,
void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y)
{ {
pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().z), mAngle); pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), mAngle);
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y);
x = std::ceil((pos.x - min.x)/sSize)-1; x = std::ceil((pos.x - min.x)/sSize)-1;
y = std::ceil((pos.y - min.y)/sSize)-1; y = std::ceil((pos.y - min.y)/sSize)-1;
nX = (pos.x - min.x - sSize*x)/sSize; nX = (pos.x - min.x - sSize*x)/sSize;
nY = (pos.y - min.y - sSize*y)/sSize; nY = 1.0-(pos.y - min.y - sSize*y)/sSize;
} }
bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior)
@ -311,19 +320,19 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
int x,y; int x,y;
float u,v; float u,v;
Vector2 pos(position.x, position.z); Vector2 pos(position.x, position.y);
if (mInterior) if (mInterior)
getInteriorMapPosition(pos, u,v, x,y); getInteriorMapPosition(pos, u,v, x,y);
Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).zAxis(); Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis();
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y);
if (!mInterior) if (!mInterior)
{ {
x = std::ceil(pos.x / sSize)-1; x = std::ceil(pos.x / sSize)-1;
y = std::ceil(-pos.y / sSize)-1; y = std::ceil(pos.y / sSize)-1;
mCellX = x; mCellX = x;
mCellY = y; mCellY = y;
} }
@ -337,7 +346,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
if (!mInterior) if (!mInterior)
{ {
u = std::abs((pos.x - (sSize*x))/sSize); u = std::abs((pos.x - (sSize*x))/sSize);
v = 1-std::abs((pos.y + (sSize*y))/sSize); v = 1.0-std::abs((pos.y - (sSize*y))/sSize);
texBaseName = "Cell_"; texBaseName = "Cell_";
} }
else else
@ -346,15 +355,13 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
} }
MWBase::Environment::get().getWindowManager()->setPlayerPos(u, v); MWBase::Environment::get().getWindowManager()->setPlayerPos(u, v);
MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, -playerdirection.z); MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y);
// explore radius (squared) // explore radius (squared)
const float sqrExploreRadius = (mInterior ? 0.01 : 0.09) * sFogOfWarResolution*sFogOfWarResolution; const float sqrExploreRadius = (mInterior ? 0.01 : 0.09) * sFogOfWarResolution*sFogOfWarResolution;
const float exploreRadius = (mInterior ? 0.1 : 0.3) * sFogOfWarResolution; // explore radius from 0 to sFogOfWarResolution const float exploreRadius = (mInterior ? 0.1 : 0.3) * sFogOfWarResolution; // explore radius from 0 to sFogOfWarResolution
const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space)
int intExtMult = mInterior ? 1 : -1; // interior and exterior have reversed Y coordinates (interior: top to bottom)
// change the affected fog of war textures (in a 3x3 grid around the player) // change the affected fog of war textures (in a 3x3 grid around the player)
for (int mx = -1; mx<2; ++mx) for (int mx = -1; mx<2; ++mx)
{ {
@ -375,7 +382,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
if (!affected) if (!affected)
continue; continue;
std::string texName = texBaseName + coordStr(x+mx,y+my*intExtMult); std::string texName = texBaseName + coordStr(x+mx,y+my*-1);
TexturePtr tex = TextureManager::getSingleton().getByName(texName+"_fog"); TexturePtr tex = TextureManager::getSingleton().getByName(texName+"_fog");
if (!tex.isNull()) if (!tex.isNull())

View file

@ -5,295 +5,257 @@
#include <OgreSubEntity.h> #include <OgreSubEntity.h>
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "renderconst.hpp" #include "renderconst.hpp"
using namespace Ogre;
using namespace NifOgre;
namespace MWRender{ namespace MWRender
{
const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = {
{ ESM::PRT_Head, "Head" },
{ ESM::PRT_Hair, "Head" },
{ ESM::PRT_Neck, "Neck" },
{ ESM::PRT_Cuirass, "Chest" },
{ ESM::PRT_Groin, "Groin" },
{ ESM::PRT_Skirt, "Groin" },
{ ESM::PRT_RHand, "Right Hand" },
{ ESM::PRT_LHand, "Left Hand" },
{ ESM::PRT_RWrist, "Right Wrist" },
{ ESM::PRT_LWrist, "Left Wrist" },
{ ESM::PRT_Shield, "Shield" },
{ ESM::PRT_RForearm, "Right Forearm" },
{ ESM::PRT_LForearm, "Left Forearm" },
{ ESM::PRT_RUpperarm, "Right Upper Arm" },
{ ESM::PRT_LUpperarm, "Left Upper Arm" },
{ ESM::PRT_RFoot, "Right Foot" },
{ ESM::PRT_LFoot, "Left Foot" },
{ ESM::PRT_RAnkle, "Right Ankle" },
{ ESM::PRT_LAnkle, "Left Ankle" },
{ ESM::PRT_RKnee, "Right Knee" },
{ ESM::PRT_LKnee, "Left Knee" },
{ ESM::PRT_RLeg, "Right Upper Leg" },
{ ESM::PRT_LLeg, "Left Upper Leg" },
{ ESM::PRT_RPauldron, "Right Clavicle" },
{ ESM::PRT_LPauldron, "Left Clavicle" },
{ ESM::PRT_Weapon, "Weapon" },
{ ESM::PRT_Tail, "Tail" }
};
NpcAnimation::~NpcAnimation() NpcAnimation::~NpcAnimation()
{ {
removeEntities(mHead); for(size_t i = 0;i < sPartListSize;i++)
removeEntities(mHair); removeEntities(mEntityParts[i]);
removeEntities(mNeck);
removeEntities(mChest);
removeEntities(mGroin);
removeEntities(mSkirt);
removeEntities(mHandL);
removeEntities(mHandR);
removeEntities(mWristL);
removeEntities(mWristR);
removeEntities(mForearmL);
removeEntities(mForearmR);
removeEntities(mUpperArmL);
removeEntities(mUpperArmR);
removeEntities(mFootL);
removeEntities(mFootR);
removeEntities(mAnkleL);
removeEntities(mAnkleR);
removeEntities(mKneeL);
removeEntities(mKneeR);
removeEntities(mUpperLegL);
removeEntities(mUpperLegR);
removeEntities(mClavicleL);
removeEntities(mClavicleR);
removeEntities(mTail);
} }
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags)
: Animation(), : Animation(ptr),
mStateID(-1), mStateID(-1),
mInv(inv),
mTimeToChange(0), mTimeToChange(0),
mVisibilityFlags(visibilityFlags), mVisibilityFlags(visibilityFlags),
mRobe(mInv.end()), mRobe(inv.end()),
mHelmet(mInv.end()), mHelmet(inv.end()),
mShirt(mInv.end()), mShirt(inv.end()),
mCuirass(mInv.end()), mCuirass(inv.end()),
mGreaves(mInv.end()), mGreaves(inv.end()),
mPauldronL(mInv.end()), mPauldronL(inv.end()),
mPauldronR(mInv.end()), mPauldronR(inv.end()),
mBoots(mInv.end()), mBoots(inv.end()),
mPants(mInv.end()), mPants(inv.end()),
mGloveL(mInv.end()), mGloveL(inv.end()),
mGloveR(mInv.end()), mGloveR(inv.end()),
mSkirtIter(mInv.end()) mSkirtIter(inv.end())
{ {
mNpc = ptr.get<ESM::NPC>()->mBase; mNpc = mPtr.get<ESM::NPC>()->mBase;
for (int init = 0; init < 27; init++) for(size_t i = 0;i < sPartListSize;i++)
{ {
mPartslots[init] = -1; //each slot is empty mPartslots[i] = -1; //each slot is empty
mPartPriorities[init] = 0; mPartPriorities[i] = 0;
} }
const MWWorld::ESMStore &store = const MWWorld::ESMStore &store =
MWBase::Environment::get().getWorld()->getStore(); MWBase::Environment::get().getWorld()->getStore();
const ESM::Race *race = store.get<ESM::Race>().find(mNpc->mRace); const ESM::Race *race = store.get<ESM::Race>().find(mNpc->mRace);
float scale = race->mData.mHeight.mMale;
if(!mNpc->isMale())
scale = race->mData.mHeight.mFemale;
node->scale(Ogre::Vector3(scale));
mHeadModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHead)->mModel; mHeadModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHead)->mModel;
mHairModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHair)->mModel; mHairModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHair)->mModel;
mBodyPrefix = "b_n_" + mNpc->mRace; mBodyPrefix = "b_n_" + mNpc->mRace;
Misc::StringUtils::toLower(mBodyPrefix); Misc::StringUtils::toLower(mBodyPrefix);
mInsert = node;
assert(mInsert);
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif");
mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, smodel); createEntityList(node, smodel);
for(size_t i = 0;i < mEntityList.mEntities.size();i++) for(size_t i = 0;i < mEntityList.mEntities.size();i++)
{ {
Ogre::Entity *base = mEntityList.mEntities[i]; Ogre::Entity *base = mEntityList.mEntities[i];
base->getUserObjectBindings ().setUserAny (Ogre::Any(-1)); base->getUserObjectBindings().setUserAny(Ogre::Any(-1));
base->setVisibilityFlags(mVisibilityFlags); base->setVisibilityFlags(mVisibilityFlags);
bool transparent = false; bool transparent = false;
for(unsigned int j=0;j < base->getNumSubEntities();++j) for(unsigned int j=0;!transparent && j < base->getNumSubEntities();++j)
{ {
Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial(); Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial();
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while (techIt.hasMoreElements()) while(!transparent && techIt.hasMoreElements())
{ {
Ogre::Technique* tech = techIt.getNext(); Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator(); Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while (passIt.hasMoreElements()) while(!transparent && passIt.hasMoreElements())
{ {
Ogre::Pass* pass = passIt.getNext(); Ogre::Pass* pass = passIt.getNext();
if (pass->getDepthWriteEnabled() == false) transparent = pass->isTransparent();
transparent = true;
} }
} }
} }
base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
} }
if(mEntityList.mSkelBase) std::vector<std::string> skelnames(1, smodel);
{ if(!mNpc->isMale() && !isBeast)
Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); skelnames.push_back("meshes\\base_anim_female.nif");
Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); else if(mBodyPrefix.find("argonian") != std::string::npos)
while(as.hasMoreElements()) skelnames.push_back("meshes\\argonian_swimkna.nif");
{ if(mNpc->mModel.length() > 0)
Ogre::AnimationState *state = as.getNext(); skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel));
state->setEnabled(true); setAnimationSources(skelnames);
state->setLoop(false);
}
}
float scale = race->mData.mHeight.mMale; updateParts(true);
if (!mNpc->isMale()) {
scale = race->mData.mHeight.mFemale;
}
mInsert->scale(scale, scale, scale);
updateParts();
} }
void NpcAnimation::updateParts() void NpcAnimation::updateParts(bool forceupdate)
{ {
bool apparelChanged = false; static const struct {
int numRemoveParts; // Max: 1
ESM::PartReferenceType removeParts[1];
const struct { MWWorld::ContainerStoreIterator NpcAnimation::*part;
MWWorld::ContainerStoreIterator *iter;
int slot; int slot;
int numReserveParts; // Max: 12
ESM::PartReferenceType reserveParts[12];
} slotlist[] = { } slotlist[] = {
{ &mRobe, MWWorld::InventoryStore::Slot_Robe }, { 0, { },
{ &mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe,
{ &mHelmet, MWWorld::InventoryStore::Slot_Helmet }, 12, { ESM::PRT_Groin, ESM::PRT_Skirt, ESM::PRT_RLeg, ESM::PRT_LLeg,
{ &mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, ESM::PRT_RUpperarm, ESM::PRT_LUpperarm, ESM::PRT_RKnee, ESM::PRT_LKnee,
{ &mGreaves, MWWorld::InventoryStore::Slot_Greaves }, ESM::PRT_RForearm, ESM::PRT_LForearm, ESM::PRT_RPauldron, ESM::PRT_LPauldron }
{ &mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, },
{ &mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron },
{ &mBoots, MWWorld::InventoryStore::Slot_Boots }, { 0, { },
{ &mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt,
{ &mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, 3, { ESM::PRT_Groin, ESM::PRT_RLeg, ESM::PRT_LLeg }
{ &mShirt, MWWorld::InventoryStore::Slot_Shirt }, },
{ &mPants, MWWorld::InventoryStore::Slot_Pants },
{ 1, { ESM::PRT_Hair },
&NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet,
0, { }
},
{ 0, { },
&NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass,
0, { }
},
{ 0, { },
&NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves,
0, { }
},
{ 0, { },
&NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron,
0, { }
},
{ 0, { },
&NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron,
0, { }
},
{ 0, { },
&NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots,
0, { }
},
{ 0, { },
&NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet,
0, { }
},
{ 0, { },
&NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet,
0, { }
},
{ 0, { },
&NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt,
0, { }
},
{ 0, { },
&NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants,
0, { }
},
}; };
for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]);
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
for(size_t i = 0;!forceupdate && i < slotlistsize;i++)
{ {
MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot);
if(*slotlist[i].iter != iter) if(this->*slotlist[i].part != iter)
{ {
*slotlist[i].iter = iter; forceupdate = true;
removePartGroup(slotlist[i].slot); break;
apparelChanged = true;
} }
} }
if(!forceupdate)
return;
if(apparelChanged) for(size_t i = 0;i < slotlistsize;i++)
{ {
if(mRobe != mInv.end()) MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot);
{
MWWorld::Ptr ptr = *mRobe;
const ESM::Clothing *clothes = (ptr.get<ESM::Clothing>())->mBase; this->*slotlist[i].part = iter;
std::vector<ESM::PartReference> parts = clothes->mParts.mParts; removePartGroup(slotlist[i].slot);
addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts);
reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Robe, 5); if(this->*slotlist[i].part == inv.end())
reserveIndividualPart(ESM::PRT_Skirt, MWWorld::InventoryStore::Slot_Robe, 5); continue;
reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Robe, 5);
reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Robe, 5); for(int rem = 0;rem < slotlist[i].numRemoveParts;rem++)
reserveIndividualPart(ESM::PRT_RUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); removeIndividualPart(slotlist[i].removeParts[rem]);
reserveIndividualPart(ESM::PRT_LUpperarm, MWWorld::InventoryStore::Slot_Robe, 5);
reserveIndividualPart(ESM::PRT_RKnee, MWWorld::InventoryStore::Slot_Robe, 5); int prio = 1;
reserveIndividualPart(ESM::PRT_LKnee, MWWorld::InventoryStore::Slot_Robe, 5); MWWorld::ContainerStoreIterator &store = this->*slotlist[i].part;
reserveIndividualPart(ESM::PRT_RForearm, MWWorld::InventoryStore::Slot_Robe, 5); if(store->getTypeName() == typeid(ESM::Clothing).name())
reserveIndividualPart(ESM::PRT_LForearm, MWWorld::InventoryStore::Slot_Robe, 5); {
reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); prio = ((slotlist[i].numReserveParts+1)<<1) + 0;
reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); const ESM::Clothing *clothes = store->get<ESM::Clothing>()->mBase;
addPartGroup(slotlist[i].slot, prio, clothes->mParts.mParts);
} }
if(mSkirtIter != mInv.end()) else if(store->getTypeName() == typeid(ESM::Armor).name())
{ {
MWWorld::Ptr ptr = *mSkirtIter; prio = ((slotlist[i].numReserveParts+1)<<1) + 1;
const ESM::Armor *armor = store->get<ESM::Armor>()->mBase;
const ESM::Clothing *clothes = (ptr.get<ESM::Clothing>())->mBase; addPartGroup(slotlist[i].slot, prio, armor->mParts.mParts);
std::vector<ESM::PartReference> parts = clothes->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_Skirt, 4, parts);
reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Skirt, 4);
reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Skirt, 4);
reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4);
} }
if(mHelmet != mInv.end()) for(int res = 0;res < slotlist[i].numReserveParts;res++)
{ reserveIndividualPart(slotlist[i].reserveParts[res], slotlist[i].slot, prio);
removeIndividualPart(ESM::PRT_Hair);
const ESM::Armor *armor = (mHelmet->get<ESM::Armor>())->mBase;
std::vector<ESM::PartReference> parts = armor->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts);
}
if(mCuirass != mInv.end())
{
const ESM::Armor *armor = (mCuirass->get<ESM::Armor>())->mBase;
std::vector<ESM::PartReference> parts = armor->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts);
}
if(mGreaves != mInv.end())
{
const ESM::Armor *armor = (mGreaves->get<ESM::Armor>())->mBase;
std::vector<ESM::PartReference> parts = armor->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts);
}
if(mPauldronL != mInv.end())
{
const ESM::Armor *armor = (mPauldronL->get<ESM::Armor>())->mBase;
std::vector<ESM::PartReference> parts = armor->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts);
}
if(mPauldronR != mInv.end())
{
const ESM::Armor *armor = (mPauldronR->get<ESM::Armor>())->mBase;
std::vector<ESM::PartReference> parts = armor->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts);
}
if(mBoots != mInv.end())
{
if(mBoots->getTypeName() == typeid(ESM::Clothing).name())
{
const ESM::Clothing *clothes = (mBoots->get<ESM::Clothing>())->mBase;
std::vector<ESM::PartReference> parts = clothes->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts);
}
else if(mBoots->getTypeName() == typeid(ESM::Armor).name())
{
const ESM::Armor *armor = (mBoots->get<ESM::Armor>())->mBase;
std::vector<ESM::PartReference> parts = armor->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts);
}
}
if(mGloveL != mInv.end())
{
if(mGloveL->getTypeName() == typeid(ESM::Clothing).name())
{
const ESM::Clothing *clothes = (mGloveL->get<ESM::Clothing>())->mBase;
std::vector<ESM::PartReference> parts = clothes->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts);
}
else
{
const ESM::Armor *armor = (mGloveL->get<ESM::Armor>())->mBase;
std::vector<ESM::PartReference> parts = armor->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts);
}
}
if(mGloveR != mInv.end())
{
if(mGloveR->getTypeName() == typeid(ESM::Clothing).name())
{
const ESM::Clothing *clothes = (mGloveR->get<ESM::Clothing>())->mBase;
std::vector<ESM::PartReference> parts = clothes->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts);
}
else
{
const ESM::Armor *armor = (mGloveR->get<ESM::Armor>())->mBase;
std::vector<ESM::PartReference> parts = armor->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts);
}
}
if(mShirt != mInv.end())
{
const ESM::Clothing *clothes = (mShirt->get<ESM::Clothing>())->mBase;
std::vector<ESM::PartReference> parts = clothes->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts);
}
if(mPants != mInv.end())
{
const ESM::Clothing *clothes = (mPants->get<ESM::Clothing>())->mBase;
std::vector<ESM::PartReference> parts = clothes->mParts.mParts;
addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts);
}
} }
if(mPartPriorities[ESM::PRT_Head] < 1) if(mPartPriorities[ESM::PRT_Head] < 1)
@ -333,21 +295,18 @@ void NpcAnimation::updateParts()
if(mPartPriorities[PartTypeList[i].type] < 1) if(mPartPriorities[PartTypeList[i].type] < 1)
{ {
const ESM::BodyPart *part = NULL; const ESM::BodyPart *part = NULL;
const MWWorld::Store<ESM::BodyPart> &partStore = const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
store.get<ESM::BodyPart>();
if (!mNpc->isMale()) { if(!mNpc->isMale())
{
part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]); part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]);
if (part == 0) { if(part == 0)
part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]); part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]);
}
} }
if (part == 0) { if(part == 0)
part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]); part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]);
} if(part == 0)
if (part == 0) {
part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]); part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]);
}
if(part) if(part)
addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel);
@ -357,27 +316,69 @@ void NpcAnimation::updateParts()
NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int group, const std::string &bonename) NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int group, const std::string &bonename)
{ {
NifOgre::EntityList entities = NIFLoader::createEntities(mEntityList.mSkelBase, bonename, NifOgre::EntityList entities = NifOgre::Loader::createEntities(mEntityList.mSkelBase, bonename,
mInsert, mesh); mInsert, mesh);
std::vector<Ogre::Entity*> &parts = entities.mEntities; std::vector<Ogre::Entity*> &parts = entities.mEntities;
for(size_t i = 0;i < parts.size();i++) for(size_t i = 0;i < parts.size();i++)
{ {
parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
parts[i]->setVisibilityFlags(mVisibilityFlags); parts[i]->setVisibilityFlags(mVisibilityFlags);
parts[i]->getUserObjectBindings ().setUserAny (Ogre::Any(group));
bool transparent = false;
for(unsigned int j=0;!transparent && j < parts[i]->getNumSubEntities();++j)
{
Ogre::MaterialPtr mat = parts[i]->getSubEntity(j)->getMaterial();
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while(!transparent && techIt.hasMoreElements())
{
Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while(!transparent && passIt.hasMoreElements())
{
Ogre::Pass* pass = passIt.getNext();
transparent = pass->isTransparent();
}
}
}
parts[i]->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
}
if(entities.mSkelBase)
{
Ogre::AnimationStateSet *aset = entities.mSkelBase->getAllAnimationStates();
Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator();
while(asiter.hasMoreElements())
{
Ogre::AnimationState *state = asiter.getNext();
state->setEnabled(false);
state->setLoop(false);
}
Ogre::SkeletonInstance *skelinst = entities.mSkelBase->getSkeleton();
Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator();
while(boneiter.hasMoreElements())
boneiter.getNext()->setManuallyControlled(true);
} }
return entities; return entities;
} }
void NpcAnimation::runAnimation(float timepassed) Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
{ {
if(mTimeToChange > .2) if(mTimeToChange <= 0.0f)
{ {
mTimeToChange = 0; mTimeToChange = 0.2f;
updateParts(); updateParts();
} }
mTimeToChange += timepassed; mTimeToChange -= timepassed;
Animation::runAnimation(timepassed); Ogre::Vector3 ret = Animation::runAnimation(timepassed);
const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton();
for(size_t i = 0;i < sPartListSize;i++)
{
Ogre::Entity *ent = mEntityParts[i].mSkelBase;
if(!ent) continue;
updateSkeletonInstance(skelsrc, ent->getSkeleton());
ent->getAllAnimationStates()->_notifyDirty();
}
return ret;
} }
void NpcAnimation::removeEntities(NifOgre::EntityList &entities) void NpcAnimation::removeEntities(NifOgre::EntityList &entities)
@ -399,62 +400,14 @@ void NpcAnimation::removeIndividualPart(int type)
mPartPriorities[type] = 0; mPartPriorities[type] = 0;
mPartslots[type] = -1; mPartslots[type] = -1;
if(type == ESM::PRT_Head) //0 for(size_t i = 0;i < sPartListSize;i++)
removeEntities(mHead);
else if(type == ESM::PRT_Hair) //1
removeEntities(mHair);
else if(type == ESM::PRT_Neck) //2
removeEntities(mNeck);
else if(type == ESM::PRT_Cuirass)//3
removeEntities(mChest);
else if(type == ESM::PRT_Groin)//4
removeEntities(mGroin);
else if(type == ESM::PRT_Skirt)//5
removeEntities(mSkirt);
else if(type == ESM::PRT_RHand)//6
removeEntities(mHandR);
else if(type == ESM::PRT_LHand)//7
removeEntities(mHandL);
else if(type == ESM::PRT_RWrist)//8
removeEntities(mWristR);
else if(type == ESM::PRT_LWrist) //9
removeEntities(mWristL);
else if(type == ESM::PRT_Shield) //10
{ {
if(type == sPartList[i].type)
{
removeEntities(mEntityParts[i]);
break;
}
} }
else if(type == ESM::PRT_RForearm) //11
removeEntities(mForearmR);
else if(type == ESM::PRT_LForearm) //12
removeEntities(mForearmL);
else if(type == ESM::PRT_RUpperarm) //13
removeEntities(mUpperArmR);
else if(type == ESM::PRT_LUpperarm) //14
removeEntities(mUpperArmL);
else if(type == ESM::PRT_RFoot) //15
removeEntities(mFootR);
else if(type == ESM::PRT_LFoot) //16
removeEntities(mFootL);
else if(type == ESM::PRT_RAnkle) //17
removeEntities(mAnkleR);
else if(type == ESM::PRT_LAnkle) //18
removeEntities(mAnkleL);
else if(type == ESM::PRT_RKnee) //19
removeEntities(mKneeR);
else if(type == ESM::PRT_LKnee) //20
removeEntities(mKneeL);
else if(type == ESM::PRT_RLeg) //21
removeEntities(mUpperLegR);
else if(type == ESM::PRT_LLeg) //22
removeEntities(mUpperLegL);
else if(type == ESM::PRT_RPauldron) //23
removeEntities(mClavicleR);
else if(type == ESM::PRT_LPauldron) //24
removeEntities(mClavicleL);
else if(type == ESM::PRT_Weapon) //25
{
}
else if(type == ESM::PRT_Tail) //26
removeEntities(mTail);
} }
void NpcAnimation::reserveIndividualPart(int type, int group, int priority) void NpcAnimation::reserveIndividualPart(int type, int group, int priority)
@ -484,96 +437,23 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority,
removeIndividualPart(type); removeIndividualPart(type);
mPartslots[type] = group; mPartslots[type] = group;
mPartPriorities[type] = priority; mPartPriorities[type] = priority;
switch(type)
for(size_t i = 0;i < sPartListSize;i++)
{ {
case ESM::PRT_Head: //0 if(type == sPartList[i].type)
mHead = insertBoundedPart(mesh, group, "Head"); {
break; mEntityParts[i] = insertBoundedPart(mesh, group, sPartList[i].name);
case ESM::PRT_Hair: //1
mHair = insertBoundedPart(mesh, group, "Head");
break;
case ESM::PRT_Neck: //2
mNeck = insertBoundedPart(mesh, group, "Neck");
break;
case ESM::PRT_Cuirass: //3
mChest = insertBoundedPart(mesh, group, "Chest");
break;
case ESM::PRT_Groin: //4
mGroin = insertBoundedPart(mesh, group, "Groin");
break;
case ESM::PRT_Skirt: //5
mSkirt = insertBoundedPart(mesh, group, "Groin");
break;
case ESM::PRT_RHand: //6
mHandR = insertBoundedPart(mesh, group, "Right Hand");
break;
case ESM::PRT_LHand: //7
mHandL = insertBoundedPart(mesh, group, "Left Hand");
break;
case ESM::PRT_RWrist: //8
mWristR = insertBoundedPart(mesh, group, "Right Wrist");
break;
case ESM::PRT_LWrist: //9
mWristL = insertBoundedPart(mesh, group, "Left Wrist");
break;
case ESM::PRT_Shield: //10
break;
case ESM::PRT_RForearm: //11
mForearmR = insertBoundedPart(mesh, group, "Right Forearm");
break;
case ESM::PRT_LForearm: //12
mForearmL = insertBoundedPart(mesh, group, "Left Forearm");
break;
case ESM::PRT_RUpperarm: //13
mUpperArmR = insertBoundedPart(mesh, group, "Right Upper Arm");
break;
case ESM::PRT_LUpperarm: //14
mUpperArmL = insertBoundedPart(mesh, group, "Left Upper Arm");
break;
case ESM::PRT_RFoot: //15
mFootR = insertBoundedPart(mesh, group, "Right Foot");
break;
case ESM::PRT_LFoot: //16
mFootL = insertBoundedPart(mesh, group, "Left Foot");
break;
case ESM::PRT_RAnkle: //17
mAnkleR = insertBoundedPart(mesh, group, "Right Ankle");
break;
case ESM::PRT_LAnkle: //18
mAnkleL = insertBoundedPart(mesh, group, "Left Ankle");
break;
case ESM::PRT_RKnee: //19
mKneeR = insertBoundedPart(mesh, group, "Right Knee");
break;
case ESM::PRT_LKnee: //20
mKneeL = insertBoundedPart(mesh, group, "Left Knee");
break;
case ESM::PRT_RLeg: //21
mUpperLegR = insertBoundedPart(mesh, group, "Right Upper Leg");
break;
case ESM::PRT_LLeg: //22
mUpperLegL = insertBoundedPart(mesh, group, "Left Upper Leg");
break;
case ESM::PRT_RPauldron: //23
mClavicleR = insertBoundedPart(mesh , group, "Right Clavicle");
break;
case ESM::PRT_LPauldron: //24
mClavicleL = insertBoundedPart(mesh, group, "Left Clavicle");
break;
case ESM::PRT_Weapon: //25
break;
case ESM::PRT_Tail: //26
mTail = insertBoundedPart(mesh, group, "Tail");
break; break;
}
} }
return true; return true;
} }
void NpcAnimation::addPartGroup(int group, int priority, std::vector<ESM::PartReference> &parts) void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts)
{ {
for(std::size_t i = 0; i < parts.size(); i++) for(std::size_t i = 0; i < parts.size(); i++)
{ {
ESM::PartReference &part = parts[i]; const ESM::PartReference &part = parts[i];
const MWWorld::Store<ESM::BodyPart> &partStore = const MWWorld::Store<ESM::BodyPart> &partStore =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>(); MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
@ -585,15 +465,10 @@ void NpcAnimation::addPartGroup(int group, int priority, std::vector<ESM::PartRe
bodypart = partStore.search(part.mMale); bodypart = partStore.search(part.mMale);
if(bodypart) if(bodypart)
addOrReplaceIndividualPart(part.mPart, group, priority,"meshes\\" + bodypart->mModel); addOrReplaceIndividualPart(part.mPart, group, priority, "meshes\\"+bodypart->mModel);
else else
reserveIndividualPart(part.mPart, group, priority); reserveIndividualPart(part.mPart, group, priority);
} }
} }
void NpcAnimation::forceUpdate ()
{
updateParts();
}
} }

View file

@ -3,9 +3,6 @@
#include "animation.hpp" #include "animation.hpp"
#include "components/nifogre/ogre_nif_loader.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwclass/npc.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
namespace ESM namespace ESM
@ -13,49 +10,36 @@ namespace ESM
struct NPC; struct NPC;
} }
namespace MWRender{ namespace MWWorld
{
class InventoryStore;
}
namespace MWRender
{
class NpcAnimation : public Animation
{
public:
struct PartInfo {
ESM::PartReferenceType type;
const char name[32];
};
class NpcAnimation: public Animation{
private: private:
MWWorld::InventoryStore& mInv; static const size_t sPartListSize = 27;
static const PartInfo sPartList[sPartListSize];
int mStateID; int mStateID;
int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty // Bounded Parts
int mPartPriorities[27]; NifOgre::EntityList mEntityParts[sPartListSize];
//Bounded Parts
NifOgre::EntityList mClavicleL;
NifOgre::EntityList mClavicleR;
NifOgre::EntityList mUpperArmL;
NifOgre::EntityList mUpperArmR;
NifOgre::EntityList mUpperLegL;
NifOgre::EntityList mUpperLegR;
NifOgre::EntityList mForearmL;
NifOgre::EntityList mForearmR;
NifOgre::EntityList mWristL;
NifOgre::EntityList mWristR;
NifOgre::EntityList mKneeR;
NifOgre::EntityList mKneeL;
NifOgre::EntityList mNeck;
NifOgre::EntityList mAnkleL;
NifOgre::EntityList mAnkleR;
NifOgre::EntityList mGroin;
NifOgre::EntityList mSkirt;
NifOgre::EntityList mFootL;
NifOgre::EntityList mFootR;
NifOgre::EntityList mHair;
NifOgre::EntityList mHandL;
NifOgre::EntityList mHandR;
NifOgre::EntityList mHead;
NifOgre::EntityList mChest;
NifOgre::EntityList mTail;
const ESM::NPC *mNpc; const ESM::NPC *mNpc;
std::string mHeadModel; std::string mHeadModel;
std::string mHairModel; std::string mHairModel;
std::string mBodyPrefix; std::string mBodyPrefix;
float mTimeToChange; float mTimeToChange;
MWWorld::ContainerStoreIterator mRobe; MWWorld::ContainerStoreIterator mRobe;
MWWorld::ContainerStoreIterator mHelmet; MWWorld::ContainerStoreIterator mHelmet;
@ -72,23 +56,32 @@ private:
int mVisibilityFlags; int mVisibilityFlags;
public: int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty
NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int mPartPriorities[sPartListSize];
MWWorld::InventoryStore& inv, int visibilityFlags);
virtual ~NpcAnimation();
NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename);
virtual void runAnimation(float timepassed);
void updateParts(); void updateParts(bool forceupdate = false);
void removeEntities(NifOgre::EntityList &entities); void removeEntities(NifOgre::EntityList &entities);
void removeIndividualPart(int type); void removeIndividualPart(int type);
void reserveIndividualPart(int type, int group, int priority); void reserveIndividualPart(int type, int group, int priority);
bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh);
void removePartGroup(int group); void removePartGroup(int group);
void addPartGroup(int group, int priority, std::vector<ESM::PartReference>& parts); void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts);
void forceUpdate(); public:
NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node,
MWWorld::InventoryStore& inv, int visibilityFlags);
virtual ~NpcAnimation();
virtual Ogre::Vector3 runAnimation(float timepassed);
void forceUpdate()
{ updateParts(true); }
}; };
} }
#endif #endif

View file

@ -34,19 +34,37 @@ void Objects::clearSceneNode (Ogre::SceneNode *node)
for (int i=node->numAttachedObjects()-1; i>=0; --i) for (int i=node->numAttachedObjects()-1; i>=0; --i)
{ {
Ogre::MovableObject *object = node->getAttachedObject (i); Ogre::MovableObject *object = node->getAttachedObject (i);
// for entities, destroy any objects attached to bones
if (object->getTypeFlags () == Ogre::SceneManager::ENTITY_TYPE_MASK)
{
Ogre::Entity* ent = static_cast<Ogre::Entity*>(object);
Ogre::Entity::ChildObjectListIterator children = ent->getAttachedObjectIterator ();
while (children.hasMoreElements())
{
mRenderer.getScene ()->destroyMovableObject (children.getNext ());
}
}
node->detachObject (object); node->detachObject (object);
mRenderer.getScene()->destroyMovableObject (object); mRenderer.getScene()->destroyMovableObject (object);
} }
Ogre::Node::ChildNodeIterator it = node->getChildIterator ();
while (it.hasMoreElements ())
{
clearSceneNode(static_cast<Ogre::SceneNode*>(it.getNext ()));
}
} }
void Objects::setMwRoot(Ogre::SceneNode* root) void Objects::setRootNode(Ogre::SceneNode* root)
{ {
mMwRoot = root; mRootNode = root;
} }
void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
{ {
Ogre::SceneNode* root = mMwRoot; Ogre::SceneNode* root = mRootNode;
Ogre::SceneNode* cellnode; Ogre::SceneNode* cellnode;
if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end())
{ {
@ -87,20 +105,16 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
mIsStatic = static_; mIsStatic = static_;
} }
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light)
{ {
Ogre::SceneNode* insert = ptr.getRefData().getBaseNode(); Ogre::SceneNode* insert = ptr.getRefData().getBaseNode();
assert(insert); assert(insert);
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, NULL, mesh); NifOgre::EntityList entities = NifOgre::Loader::createEntities(insert, mesh);
for(size_t i = 0;i < entities.mEntities.size();i++) for(size_t i = 0;i < entities.mEntities.size();i++)
{ bounds.merge(entities.mEntities[i]->getWorldBoundingBox(true));
const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox();
bounds.merge(Ogre::AxisAlignedBox(insert->_getDerivedPosition() + tmp.getMinimum(),
insert->_getDerivedPosition() + tmp.getMaximum())
);
}
Ogre::Vector3 extents = bounds.getSize(); Ogre::Vector3 extents = bounds.getSize();
extents *= insert->getScale(); extents *= insert->getScale();
float size = std::max(std::max(extents.x, extents.y), extents.z); float size = std::max(std::max(extents.x, extents.y), extents.z);
@ -116,23 +130,21 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
mBounds[ptr.getCell()].merge(bounds); mBounds[ptr.getCell()].merge(bounds);
bool transparent = false; bool transparent = false;
for(size_t i = 0;i < entities.mEntities.size();i++) for(size_t i = 0;!transparent && i < entities.mEntities.size();i++)
{ {
Ogre::Entity *ent = entities.mEntities[i]; Ogre::Entity *ent = entities.mEntities[i];
for (unsigned int i=0; i<ent->getNumSubEntities(); ++i) for(unsigned int i=0;!transparent && i < ent->getNumSubEntities(); ++i)
{ {
Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial();
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while (techIt.hasMoreElements()) while(!transparent && techIt.hasMoreElements())
{ {
Ogre::Technique* tech = techIt.getNext(); Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator(); Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while (passIt.hasMoreElements()) while(!transparent && passIt.hasMoreElements())
{ {
Ogre::Pass* pass = passIt.getNext(); Ogre::Pass* pass = passIt.getNext();
transparent = pass->isTransparent();
if (pass->getDepthWriteEnabled() == false)
transparent = true;
} }
} }
} }
@ -193,26 +205,40 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
for(size_t i = 0;i < entities.mEntities.size();i++) std::vector<Ogre::Entity*>::reverse_iterator iter = entities.mEntities.rbegin();
while(iter != entities.mEntities.rend())
{ {
Ogre::Entity *ent = entities.mEntities[i]; Ogre::Node *node = (*iter)->getParentNode();
insert->detachObject(ent); sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale());
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
mRenderer.getScene()->destroyEntity(ent); (*iter)->detachFromParent();
mRenderer.getScene()->destroyEntity(*iter);
iter++;
} }
} }
if (light)
{
insertLight(ptr, entities.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition());
}
} }
void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius) void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter)
{ {
Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle()); Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle());
assert(insert); assert(insert);
Ogre::Light *light = mRenderer.getScene()->createLight();
light->setDiffuseColour (r, g, b);
MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>(); MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
const int color = ref->mBase->mData.mColor;
const float r = ((color >> 0) & 0xFF) / 255.0f;
const float g = ((color >> 8) & 0xFF) / 255.0f;
const float b = ((color >> 16) & 0xFF) / 255.0f;
const float radius = float (ref->mBase->mData.mRadius);
Ogre::Light *light = mRenderer.getScene()->createLight();
light->setDiffuseColour (r, g, b);
LightInfo info; LightInfo info;
info.name = light->getName(); info.name = light->getName();
info.radius = radius; info.radius = radius;
@ -263,7 +289,17 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f
light->setAttenuation(r*10, 0, 0, attenuation); light->setAttenuation(r*10, 0, 0, attenuation);
} }
insert->attachObject(light); // If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node
if (skelBase && skelBase->getSkeleton ()->hasBone ("AttachLight"))
{
skelBase->attachObjectToBone ("AttachLight", light);
}
else
{
Ogre::SceneNode* childNode = insert->createChildSceneNode (fallbackCenter);
childNode->attachObject(light);
}
mLights.push_back(info); mLights.push_back(info);
} }
@ -348,9 +384,9 @@ void Objects::enableLights()
std::vector<LightInfo>::iterator it = mLights.begin(); std::vector<LightInfo>::iterator it = mLights.begin();
while (it != mLights.end()) while (it != mLights.end())
{ {
if (mMwRoot->getCreator()->hasLight(it->name)) if (mRootNode->getCreator()->hasLight(it->name))
{ {
mMwRoot->getCreator()->getLight(it->name)->setVisible(true); mRootNode->getCreator()->getLight(it->name)->setVisible(true);
++it; ++it;
} }
else else
@ -363,9 +399,9 @@ void Objects::disableLights()
std::vector<LightInfo>::iterator it = mLights.begin(); std::vector<LightInfo>::iterator it = mLights.begin();
while (it != mLights.end()) while (it != mLights.end())
{ {
if (mMwRoot->getCreator()->hasLight(it->name)) if (mRootNode->getCreator()->hasLight(it->name))
{ {
mMwRoot->getCreator()->getLight(it->name)->setVisible(false); mRootNode->getCreator()->getLight(it->name)->setVisible(false);
++it; ++it;
} }
else else
@ -418,9 +454,9 @@ void Objects::update(const float dt)
std::vector<LightInfo>::iterator it = mLights.begin(); std::vector<LightInfo>::iterator it = mLights.begin();
while (it != mLights.end()) while (it != mLights.end())
{ {
if (mMwRoot->getCreator()->hasLight(it->name)) if (mRootNode->getCreator()->hasLight(it->name))
{ {
Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name); Ogre::Light* light = mRootNode->getCreator()->getLight(it->name);
float brightness; float brightness;
float cycle_time; float cycle_time;
@ -502,21 +538,17 @@ void Objects::rebuildStaticGeometry()
} }
} }
void Objects::updateObjectCell(const MWWorld::Ptr &ptr) void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur)
{ {
Ogre::SceneNode *node; Ogre::SceneNode *node;
MWWorld::CellStore *newCell = ptr.getCell(); MWWorld::CellStore *newCell = cur.getCell();
if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) {
node = mMwRoot->createChildSceneNode(); node = mRootNode->createChildSceneNode();
mCellSceneNodes[newCell] = node; mCellSceneNodes[newCell] = node;
} else { } else {
node = mCellSceneNodes[newCell]; node = mCellSceneNodes[newCell];
} }
node->addChild(ptr.getRefData().getBaseNode()); node->addChild(cur.getRefData().getBaseNode());
/// \note Still unaware how to move aabb and static w/o full rebuild,
/// moving static objects may cause problems
insertMesh(ptr, MWWorld::Class::get(ptr).getModel(ptr));
} }

View file

@ -2,6 +2,7 @@
#define _GAME_RENDER_OBJECTS_H #define _GAME_RENDER_OBJECTS_H
#include <OgreColourValue.h> #include <OgreColourValue.h>
#include <OgreAxisAlignedBox.h>
#include <openengine/ogre/renderer.hpp> #include <openengine/ogre/renderer.hpp>
@ -52,7 +53,7 @@ class Objects{
std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall; std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall;
std::map<MWWorld::CellStore *, Ogre::AxisAlignedBox> mBounds; std::map<MWWorld::CellStore *, Ogre::AxisAlignedBox> mBounds;
std::vector<LightInfo> mLights; std::vector<LightInfo> mLights;
Ogre::SceneNode* mMwRoot; Ogre::SceneNode* mRootNode;
bool mIsStatic; bool mIsStatic;
static int uniqueID; static int uniqueID;
@ -72,8 +73,8 @@ public:
Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mIsStatic(false) {} Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mIsStatic(false) {}
~Objects(){} ~Objects(){}
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false);
void insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius); void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity *skelBase=0, Ogre::Vector3 fallbackCenter=Ogre::Vector3(0.0f));
void enableLights(); void enableLights();
void disableLights(); void disableLights();
@ -89,12 +90,12 @@ public:
void removeCell(MWWorld::CellStore* store); void removeCell(MWWorld::CellStore* store);
void buildStaticGeometry(MWWorld::CellStore &cell); void buildStaticGeometry(MWWorld::CellStore &cell);
void setMwRoot(Ogre::SceneNode* root); void setRootNode(Ogre::SceneNode* root);
void rebuildStaticGeometry(); void rebuildStaticGeometry();
/// Updates containing cell for object rendering data /// Updates containing cell for object rendering data
void updateObjectCell(const MWWorld::Ptr &ptr); void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur);
}; };
} }
#endif #endif

View file

@ -113,11 +113,6 @@ namespace MWRender
Ogre::Vector3 dir = mCamera->getRealDirection(); Ogre::Vector3 dir = mCamera->getRealDirection();
Ogre::Vector3 up = mCamera->getRealUp(); Ogre::Vector3 up = mCamera->getRealUp();
Ogre::Real xch;
xch = pos.y, pos.y = -pos.z, pos.z = xch;
xch = dir.y, dir.y = -dir.z, dir.z = xch;
xch = up.y, up.y = -up.z, up.z = xch;
MWBase::Environment::get().getSoundManager()->setListenerPosDir(pos, dir, up); MWBase::Environment::get().getSoundManager()->setListenerPosDir(pos, dir, up);
} }
@ -129,14 +124,8 @@ namespace MWRender
MWBase::Environment::get().getWindowManager ()->showCrosshair MWBase::Environment::get().getWindowManager ()->showCrosshair
(!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode));
if (mAnimation) { /// \fixme We shouldn't hide the whole model, just certain components of the character (head, chest, feet, etc)
mAnimation->runAnimation(duration); mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView);
}
mPlayerNode->setVisible(
mVanity.enabled || mPreviewMode || !mFirstPersonView,
false
);
if (mFirstPersonView && !mVanity.enabled) { if (mFirstPersonView && !mVanity.enabled) {
return; return;
} }
@ -313,10 +302,7 @@ namespace MWRender
delete mAnimation; delete mAnimation;
mAnimation = anim; mAnimation = anim;
mPlayerNode->setVisible( mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView);
mVanity.enabled || mPreviewMode || !mFirstPersonView,
false
);
} }
void Player::setHeight(float height) void Player::setHeight(float height)
@ -332,10 +318,8 @@ namespace MWRender
bool Player::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera) bool Player::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera)
{ {
float xch;
mCamera->getParentSceneNode ()->needUpdate(true); mCamera->getParentSceneNode ()->needUpdate(true);
camera = mCamera->getRealPosition(); camera = mCamera->getRealPosition();
xch = camera.z, camera.z = camera.y, camera.y = -xch;
player = mPlayerNode->getPosition(); player = mPlayerNode->getPosition();
return mFirstPersonView && !mVanity.enabled && !mPreviewMode; return mFirstPersonView && !mVanity.enabled && !mPreviewMode;

View file

@ -95,7 +95,9 @@ namespace MWRender
/// Restore default camera distance for current mode. /// Restore default camera distance for current mode.
void setCameraDistance(); void setCameraDistance();
void setAnimation(MWRender::NpcAnimation *anim); void setAnimation(NpcAnimation *anim);
NpcAnimation *getAnimation() const
{ return mAnimation; }
void setHeight(float height); void setHeight(float height);
float getHeight(); float getHeight();

View file

@ -18,9 +18,12 @@
#include <extern/shiny/Main/Factory.hpp> #include <extern/shiny/Main/Factory.hpp>
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp> #include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
#include <openengine/bullet/physic.hpp>
#include <components/esm/loadstat.hpp> #include <components/esm/loadstat.hpp>
#include "../mwworld/esmstore.hpp"
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -138,26 +141,20 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
applyCompositors(); applyCompositors();
// Turn the entire scene (represented by the 'root' node) -90
// degrees around the x axis. This makes Z go upwards, and Y go into
// the screen (when x is to the right.) This is the orientation that
// Morrowind uses, and it automagically makes everything work as it
// should.
SceneNode *rt = mRendering.getScene()->getRootSceneNode(); SceneNode *rt = mRendering.getScene()->getRootSceneNode();
mMwRoot = rt->createChildSceneNode("mwRoot"); mRootNode = rt;
mMwRoot->pitch(Degree(-90));
mObjects.setMwRoot(mMwRoot); mObjects.setRootNode(mRootNode);
mActors.setMwRoot(mMwRoot); mActors.setRootNode(mRootNode);
Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player"); Ogre::SceneNode *playerNode = mRootNode->createChildSceneNode ("player");
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
mShadows = new Shadows(&mRendering); mShadows = new Shadows(&mRendering);
mTerrainManager = new TerrainManager(mRendering.getScene(), this); mTerrainManager = new TerrainManager(mRendering.getScene(), this);
mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera()); mSkyManager = new SkyManager(mRootNode, mRendering.getCamera());
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
@ -166,7 +163,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
mSun = 0; mSun = 0;
mDebugging = new Debugging(mMwRoot, engine); mDebugging = new Debugging(mRootNode, engine);
mLocalMap = new MWRender::LocalMap(&mRendering, this); mLocalMap = new MWRender::LocalMap(&mRendering, this);
setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI"));
@ -252,8 +249,7 @@ void RenderingManager::removeObject (const MWWorld::Ptr& ptr)
void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position) void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position)
{ {
/// \todo move this to the rendering-subsystems /// \todo move this to the rendering-subsystems
mRendering.getScene()->getSceneNode (ptr.getRefData().getHandle())-> ptr.getRefData().getBaseNode()->setPosition(position);
setPosition (position);
} }
void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale) void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale)
@ -300,23 +296,19 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot
} }
void void
RenderingManager::moveObjectToCell( RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur)
const MWWorld::Ptr& ptr,
const Ogre::Vector3& pos,
MWWorld::CellStore *store)
{ {
Ogre::SceneNode *child = Ogre::SceneNode *child =
mRendering.getScene()->getSceneNode(ptr.getRefData().getHandle()); mRendering.getScene()->getSceneNode(old.getRefData().getHandle());
Ogre::SceneNode *parent = child->getParentSceneNode(); Ogre::SceneNode *parent = child->getParentSceneNode();
parent->removeChild(child); parent->removeChild(child);
if (MWWorld::Class::get(ptr).isActor()) { if (MWWorld::Class::get(old).isActor()) {
mActors.updateObjectCell(ptr); mActors.updateObjectCell(old, cur);
} else { } else {
mObjects.updateObjectCell(ptr); mObjects.updateObjectCell(old, cur);
} }
child->setPosition(pos);
} }
void RenderingManager::update (float duration, bool paused) void RenderingManager::update (float duration, bool paused)
@ -324,7 +316,7 @@ void RenderingManager::update (float duration, bool paused)
Ogre::Vector3 orig, dest; Ogre::Vector3 orig, dest;
mPlayer->setCameraDistance(); mPlayer->setCameraDistance();
if (!mPlayer->getPosition(orig, dest)) { if (!mPlayer->getPosition(orig, dest)) {
orig.z += mPlayer->getHeight() * mMwRoot->getScale().z; orig.z += mPlayer->getHeight() * mRootNode->getScale().z;
btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btOrig(orig.x, orig.y, orig.z);
btVector3 btDest(dest.x, dest.y, dest.z); btVector3 btDest(dest.x, dest.y, dest.z);
@ -368,11 +360,13 @@ void RenderingManager::update (float duration, bool paused)
float *fpos = data.getPosition().pos; float *fpos = data.getPosition().pos;
// only for LocalMap::updatePlayer() // only for LocalMap::updatePlayer()
Ogre::Vector3 pos(fpos[0], -fpos[2], -fpos[1]); Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]);
Ogre::SceneNode *node = data.getBaseNode(); Ogre::SceneNode *node = data.getBaseNode();
//Ogre::Quaternion orient =
//node->convertLocalToWorldOrientation(node->_getDerivedOrientation());
Ogre::Quaternion orient = Ogre::Quaternion orient =
node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); node->_getDerivedOrientation();
mLocalMap->updatePlayer(pos, orient); mLocalMap->updatePlayer(pos, orient);
@ -383,8 +377,8 @@ void RenderingManager::update (float duration, bool paused)
mWater->updateUnderwater( mWater->updateUnderwater(
world->isUnderwater( world->isUnderwater(
*world->getPlayer().getPlayer().getCell()->mCell, world->getPlayer().getPlayer().getCell(),
Ogre::Vector3(cam.x, -cam.z, cam.y)) cam)
); );
mWater->update(duration); mWater->update(duration);
} }
@ -580,17 +574,6 @@ void RenderingManager::toggleLight()
setAmbientMode(); setAmbientMode();
} }
void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName,
int mode, int number)
{
mActors.playAnimationGroup(ptr, groupName, mode, number);
}
void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr)
{
mActors.skipAnimation(ptr);
}
void RenderingManager::setSunColour(const Ogre::ColourValue& colour) void RenderingManager::setSunColour(const Ogre::ColourValue& colour)
{ {
if (!mSunEnabled) return; if (!mSunEnabled) return;
@ -627,8 +610,7 @@ void RenderingManager::sunDisable()
void RenderingManager::setSunDirection(const Ogre::Vector3& direction) void RenderingManager::setSunDirection(const Ogre::Vector3& direction)
{ {
// direction * -1 (because 'direction' is camera to sun vector and not sun to camera), // direction * -1 (because 'direction' is camera to sun vector and not sun to camera),
// then convert from MW to ogre coordinates (swap y,z and make y negative) if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z));
if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.z, direction.y));
mSkyManager->setSunDirection(direction); mSkyManager->setSunDirection(direction);
} }
@ -929,6 +911,15 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend
rendering.setup (mRendering.getScene()); rendering.setup (mRendering.getScene());
} }
Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr)
{
Animation *anim = mActors.getAnimation(ptr);
if(!anim && ptr.getRefData().getHandle() == "player")
anim = mPlayer->getAnimation();
return anim;
}
void RenderingManager::playVideo(const std::string& name, bool allowSkipping) void RenderingManager::playVideo(const std::string& name, bool allowSkipping)
{ {
mVideoPlayer->playVideo ("video/" + name, allowSkipping); mVideoPlayer->playVideo ("video/" + name, allowSkipping);

View file

@ -46,6 +46,7 @@ namespace MWRender
class ExternalRendering; class ExternalRendering;
class GlobalMap; class GlobalMap;
class VideoPlayer; class VideoPlayer;
class Animation;
class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener {
@ -122,9 +123,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
void setWaterHeight(const float height); void setWaterHeight(const float height);
void toggleWater(); void toggleWater();
/// Moves object rendering part to proper container /// Updates object rendering after cell change
/// \param store Cell the object was in previously (\a ptr has already been updated to the new cell). /// \param old Object reference in previous cell
void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::CellStore *store); /// \param cur Object reference in new cell
void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur);
void update (float duration, bool paused); void update (float duration, bool paused);
@ -166,18 +168,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
/// configure fog manually /// configure fog manually
void configureFog(const float density, const Ogre::ColourValue& colour); void configureFog(const float density, const Ogre::ColourValue& colour);
void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode,
int number = 1);
///< Run animation for a MW-reference. Calls to this function for references that are currently not
/// in the rendered scene should be ignored.
///
/// \param mode: 0 normal, 1 immediate start, 2 immediate loop
/// \param number How offen the animation should be run
void skipAnimation (const MWWorld::Ptr& ptr);
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
/// references that are currently not in the rendered scene should be ignored.
Ogre::Vector4 boundingBoxToScreen(Ogre::AxisAlignedBox bounds); Ogre::Vector4 boundingBoxToScreen(Ogre::AxisAlignedBox bounds);
///< transform the specified bounding box (in world coordinates) into screen coordinates. ///< transform the specified bounding box (in world coordinates) into screen coordinates.
/// @return packed vector4 (min_x, min_y, max_x, max_y) /// @return packed vector4 (min_x, min_y, max_x, max_y)
@ -196,6 +186,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
void setupExternalRendering (MWRender::ExternalRendering& rendering); void setupExternalRendering (MWRender::ExternalRendering& rendering);
Animation* getAnimation(const MWWorld::Ptr &ptr);
void playVideo(const std::string& name, bool allowSkipping); void playVideo(const std::string& name, bool allowSkipping);
void stopVideo(); void stopVideo();
@ -236,10 +228,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
Ogre::ColourValue mAmbientColor; Ogre::ColourValue mAmbientColor;
Ogre::Light* mSun; Ogre::Light* mSun;
/// Root node for all objects added to the scene. This is rotated so Ogre::SceneNode *mRootNode;
/// that the OGRE coordinate system matches that used internally in
/// Morrowind.
Ogre::SceneNode *mMwRoot;
OEngine::Physic::PhysicEngine* mPhysicsEngine; OEngine::Physic::PhysicEngine* mPhysicsEngine;

View file

@ -110,7 +110,7 @@ void BillboardObject::setPosition(const Vector3& pPosition)
Vector3 BillboardObject::getPosition() const Vector3 BillboardObject::getPosition() const
{ {
Vector3 p = mNode->_getDerivedPosition() - mNode->getParentSceneNode()->_getDerivedPosition(); Vector3 p = mNode->_getDerivedPosition() - mNode->getParentSceneNode()->_getDerivedPosition();
return Vector3(p.x, -p.z, p.y); return p;
} }
void BillboardObject::setVisibilityFlags(int flags) void BillboardObject::setVisibilityFlags(int flags)
@ -203,7 +203,7 @@ unsigned int Moon::getPhaseInt() const
return 0; return 0;
} }
SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) SkyManager::SkyManager (SceneNode* root, Camera* pCamera)
: mHour(0.0f) : mHour(0.0f)
, mDay(0) , mDay(0)
, mMonth(0) , mMonth(0)
@ -234,9 +234,8 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera)
, mCloudAnimationTimer(0.f) , mCloudAnimationTimer(0.f)
, mMoonRed(false) , mMoonRed(false)
{ {
mSceneMgr = pMwRoot->getCreator(); mSceneMgr = root->getCreator();
mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates
mRootNode->setInheritOrientation(false); mRootNode->setInheritOrientation(false);
} }
@ -282,7 +281,7 @@ void SkyManager::create()
// Stars // Stars
mAtmosphereNight = mRootNode->createChildSceneNode(); mAtmosphereNight = mRootNode->createChildSceneNode();
NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, NULL, "meshes\\sky_night_01.nif"); NifOgre::EntityList entities = NifOgre::Loader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif");
for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++)
{ {
Entity* night1_ent = entities.mEntities[i]; Entity* night1_ent = entities.mEntities[i];
@ -307,26 +306,28 @@ void SkyManager::create()
// Atmosphere (day) // Atmosphere (day)
mAtmosphereDay = mRootNode->createChildSceneNode(); mAtmosphereDay = mRootNode->createChildSceneNode();
entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, NULL, "meshes\\sky_atmosphere.nif"); entities = NifOgre::Loader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif");
for(size_t i = 0;i < entities.mEntities.size();i++) for(size_t i = 0;i < entities.mEntities.size();i++)
{ {
Entity* atmosphere_ent = entities.mEntities[i]; Entity* atmosphere_ent = entities.mEntities[i];
atmosphere_ent->setCastShadows(false); atmosphere_ent->setCastShadows(false);
atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly);
atmosphere_ent->setVisibilityFlags(RV_Sky); atmosphere_ent->setVisibilityFlags(RV_Sky);
atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere"); for(unsigned int j = 0;j < atmosphere_ent->getNumSubEntities();j++)
atmosphere_ent->getSubEntity (j)->setMaterialName("openmw_atmosphere");
} }
// Clouds // Clouds
SceneNode* clouds_node = mRootNode->createChildSceneNode(); SceneNode* clouds_node = mRootNode->createChildSceneNode();
entities = NifOgre::NIFLoader::createEntities(clouds_node, NULL, "meshes\\sky_clouds_01.nif"); entities = NifOgre::Loader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif");
for(size_t i = 0;i < entities.mEntities.size();i++) for(size_t i = 0;i < entities.mEntities.size();i++)
{ {
Entity* clouds_ent = entities.mEntities[i]; Entity* clouds_ent = entities.mEntities[i];
clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setVisibilityFlags(RV_Sky);
clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5);
clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++)
clouds_ent->getSubEntity(j)->setMaterialName("openmw_clouds");
clouds_ent->setCastShadows(false); clouds_ent->setCastShadows(false);
} }
@ -389,7 +390,6 @@ void SkyManager::update(float duration)
// increase the strength of the sun glare effect depending // increase the strength of the sun glare effect depending
// on how directly the player is looking at the sun // on how directly the player is looking at the sun
Vector3 sun = mSunGlare->getPosition(); Vector3 sun = mSunGlare->getPosition();
sun = Vector3(sun.x, sun.z, -sun.y);
Vector3 cam = mCamera->getRealDirection(); Vector3 cam = mCamera->getRealDirection();
const Degree angle = sun.angleBetween( cam ); const Degree angle = sun.angleBetween( cam );
float val = 1- (angle.valueDegrees() / 180.f); float val = 1- (angle.valueDegrees() / 180.f);

View file

@ -112,7 +112,7 @@ namespace MWRender
class SkyManager class SkyManager
{ {
public: public:
SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera); SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera);
~SkyManager(); ~SkyManager();
void update(float duration); void update(float duration);

View file

@ -26,7 +26,7 @@ namespace MWRender
//---------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------
TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend) : TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend) :
mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend) mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Y, mLandSize, mWorldSize)), mRendering(rend)
{ {
mTerrainGlobals = OGRE_NEW TerrainGlobalOptions(); mTerrainGlobals = OGRE_NEW TerrainGlobalOptions();
@ -54,8 +54,8 @@ namespace MWRender
mTerrainGlobals->setCompositeMapDistance(mWorldSize*2); mTerrainGlobals->setCompositeMapDistance(mWorldSize*2);
mTerrainGroup.setOrigin(Vector3(mWorldSize/2, mTerrainGroup.setOrigin(Vector3(mWorldSize/2,
0, mWorldSize/2,
-mWorldSize/2)); 0));
Terrain::ImportData& importSettings = mTerrainGroup.getDefaultImportSettings(); Terrain::ImportData& importSettings = mTerrainGroup.getDefaultImportSettings();

View file

@ -404,6 +404,8 @@ public:
*type = MWSound::SampleType_UInt8; *type = MWSound::SampleType_UInt8;
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16) else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16)
*type = MWSound::SampleType_Int16; *type = MWSound::SampleType_Int16;
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT)
*type = MWSound::SampleType_Float32;
else else
fail(std::string("Unsupported sample format: ")+ fail(std::string("Unsupported sample format: ")+
av_get_sample_fmt_name(mAVStream->codec->sample_fmt)); av_get_sample_fmt_name(mAVStream->codec->sample_fmt));

View file

@ -42,9 +42,9 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel
mIsUnderwater = false; mIsUnderwater = false;
mWaterPlane = Plane(Vector3::UNIT_Y, 0); mWaterPlane = Plane(Vector3::UNIT_Z, 0);
MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Z); MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Y);
mWater = mSceneManager->createEntity("water"); mWater = mSceneManager->createEntity("water");
mWater->setVisibilityFlags(RV_Water); mWater->setVisibilityFlags(RV_Water);
@ -168,12 +168,12 @@ void Water::setHeight(const float height)
{ {
mTop = height; mTop = height;
mWaterPlane = Plane(Vector3::UNIT_Y, height); mWaterPlane = Plane(Vector3::UNIT_Z, height);
// small error due to reflection texture size & reflection distortion // small error due to reflection texture size & reflection distortion
mErrorPlane = Plane(Vector3::UNIT_Y, height - 5); mErrorPlane = Plane(Vector3::UNIT_Z, height - 5);
mWaterNode->setPosition(0, height, 0); mWaterNode->setPosition(0, 0, height);
sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(height))); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(height)));
} }
@ -199,7 +199,7 @@ Water::updateUnderwater(bool underwater)
Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY)
{ {
return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), gridY * CELL_SIZE + (CELL_SIZE / 2), mTop);
} }
void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
@ -216,7 +216,7 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
mReflectionRenderActive = true; mReflectionRenderActive = true;
Vector3 pos = mCamera->getRealPosition(); Vector3 pos = mCamera->getRealPosition();
pos.y = mTop*2 - pos.y; pos.z = mTop*2 - pos.z;
mSky->setSkyPosition(pos); mSky->setSkyPosition(pos);
mReflectionCamera->enableReflection(mWaterPlane); mReflectionCamera->enableReflection(mWaterPlane);
} }

View file

@ -9,7 +9,7 @@
#include <components/interpreter/runtime.hpp> #include <components/interpreter/runtime.hpp>
#include <components/interpreter/opcodes.hpp> #include <components/interpreter/opcodes.hpp>
#include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "interpretercontext.hpp" #include "interpretercontext.hpp"
#include "ref.hpp" #include "ref.hpp"
@ -27,7 +27,7 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
MWBase::Environment::get().getWorld()->skipAnimation (ptr); MWBase::Environment::get().getMechanicsManager()->skipAnimation (ptr);
} }
}; };
@ -54,7 +54,7 @@ namespace MWScript
throw std::runtime_error ("animation mode out of range"); throw std::runtime_error ("animation mode out of range");
} }
MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, 1); MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, 1);
} }
}; };
@ -87,7 +87,7 @@ namespace MWScript
throw std::runtime_error ("animation mode out of range"); throw std::runtime_error ("animation mode out of range");
} }
MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, loops); MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, loops);
} }
}; };

View file

@ -140,25 +140,42 @@ namespace MWScript
Compiler::Locals& ScriptManager::getLocals (const std::string& name) Compiler::Locals& ScriptManager::getLocals (const std::string& name)
{ {
ScriptCollection::iterator iter = mScripts.find (name);
if (iter==mScripts.end())
{ {
if (!compile (name)) ScriptCollection::iterator iter = mScripts.find (name);
{
/// \todo Handle case of cyclic member variable access. Currently this could look up
/// the whole application in an endless recursion.
// failed -> ignore script from now on. if (iter!=mScripts.end())
std::vector<Interpreter::Type_Code> empty; return iter->second.second;
mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals())));
throw std::runtime_error ("failed to compile script " + name);
}
iter = mScripts.find (name);
} }
return iter->second.second; {
std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name);
if (iter!=mOtherLocals.end())
return iter->second;
}
Compiler::Locals locals;
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
{
int index = 0;
for (int i=0; i<script->mData.mNumShorts; ++i)
locals.declare ('s', script->mVarNames[index++]);
for (int i=0; i<script->mData.mNumLongs; ++i)
locals.declare ('l', script->mVarNames[index++]);
for (int i=0; i<script->mData.mNumFloats; ++i)
locals.declare ('f', script->mVarNames[index++]);
std::map<std::string, Compiler::Locals>::iterator iter =
mOtherLocals.insert (std::make_pair (name, locals)).first;
return iter->second;
}
throw std::logic_error ("script " + name + " does not exist");
} }
GlobalScripts& ScriptManager::getGlobalScripts() GlobalScripts& ScriptManager::getGlobalScripts()

View file

@ -47,6 +47,7 @@ namespace MWScript
ScriptCollection mScripts; ScriptCollection mScripts;
GlobalScripts mGlobalScripts; GlobalScripts mGlobalScripts;
std::map<std::string, Compiler::Locals> mOtherLocals;
public: public:

View file

@ -134,6 +134,18 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length)
return dec; return dec;
} }
static AVSampleFormat ffmpegNonPlanarSampleFormat (AVSampleFormat format)
{
switch (format)
{
case AV_SAMPLE_FMT_U8P: return AV_SAMPLE_FMT_U8;
case AV_SAMPLE_FMT_S16P: return AV_SAMPLE_FMT_S16;
case AV_SAMPLE_FMT_S32P: return AV_SAMPLE_FMT_S32;
case AV_SAMPLE_FMT_FLTP: return AV_SAMPLE_FMT_FLT;
case AV_SAMPLE_FMT_DBLP: return AV_SAMPLE_FMT_DBL;
default:return format;
}
}
void FFmpeg_Decoder::open(const std::string &fname) void FFmpeg_Decoder::open(const std::string &fname)
{ {
@ -160,7 +172,6 @@ void FFmpeg_Decoder::open(const std::string &fname)
{ {
if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{ {
mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16;
mStream = &mFormatCtx->streams[j]; mStream = &mFormatCtx->streams[j];
break; break;
} }
@ -168,6 +179,8 @@ void FFmpeg_Decoder::open(const std::string &fname)
if(!mStream) if(!mStream)
fail("No audio streams in "+fname); fail("No audio streams in "+fname);
(*mStream)->codec->request_sample_fmt = ffmpegNonPlanarSampleFormat ((*mStream)->codec->sample_fmt);
AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id); AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id);
if(!codec) if(!codec)
{ {
@ -220,6 +233,8 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *
*type = SampleType_UInt8; *type = SampleType_UInt8;
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16) else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16)
*type = SampleType_Int16; *type = SampleType_Int16;
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT)
*type = SampleType_Float32;
else else
fail(std::string("Unsupported sample format: ")+ fail(std::string("Unsupported sample format: ")+
av_get_sample_fmt_name((*mStream)->codec->sample_fmt)); av_get_sample_fmt_name((*mStream)->codec->sample_fmt));

View file

@ -88,6 +88,51 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
} }
} }
} }
if(alIsExtensionPresent("AL_EXT_FLOAT32"))
{
static const struct {
char name[32];
ChannelConfig chans;
SampleType type;
} fltfmtlist[] = {
{ "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 },
{ "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 },
};
static const size_t fltfmtlistsize = sizeof(fltfmtlist)/sizeof(fltfmtlist[0]);
for(size_t i = 0;i < fltfmtlistsize;i++)
{
if(fltfmtlist[i].chans == chans && fltfmtlist[i].type == type)
{
ALenum format = alGetEnumValue(fltfmtlist[i].name);
if(format != 0 && format != -1)
return format;
}
}
if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{
static const struct {
char name[32];
ChannelConfig chans;
SampleType type;
} fltmcfmtlist[] = {
{ "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 },
{ "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 },
{ "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 },
};
static const size_t fltmcfmtlistsize = sizeof(fltmcfmtlist)/sizeof(fltmcfmtlist[0]);
for(size_t i = 0;i < fltmcfmtlistsize;i++)
{
if(fltmcfmtlist[i].chans == chans && fltmcfmtlist[i].type == type)
{
ALenum format = alGetEnumValue(fltmcfmtlist[i].name);
if(format != 0 && format != -1)
return format;
}
}
}
}
fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")");
return AL_NONE; return AL_NONE;

View file

@ -9,7 +9,8 @@ namespace MWSound
{ {
enum SampleType { enum SampleType {
SampleType_UInt8, SampleType_UInt8,
SampleType_Int16 SampleType_Int16,
SampleType_Float32
}; };
const char *getSampleTypeName(SampleType type); const char *getSampleTypeName(SampleType type);

View file

@ -607,6 +607,7 @@ namespace MWSound
{ {
case SampleType_UInt8: return "U8"; case SampleType_UInt8: return "U8";
case SampleType_Int16: return "S16"; case SampleType_Int16: return "S16";
case SampleType_Float32: return "Float32";
} }
return "(unknown sample type)"; return "(unknown sample type)";
} }
@ -638,6 +639,7 @@ namespace MWSound
{ {
case SampleType_UInt8: frames *= 1; break; case SampleType_UInt8: frames *= 1; break;
case SampleType_Int16: frames *= 2; break; case SampleType_Int16: frames *= 2; break;
case SampleType_Float32: frames *= 4; break;
} }
return frames; return frames;
} }

View file

@ -86,7 +86,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS
MWWorld::Cells::Cells (const MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& reader) MWWorld::Cells::Cells (const MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& reader)
: mStore (store), mReader (reader), : mStore (store), mReader (reader),
mIdCache (20, std::pair<std::string, Ptr::CellStore *> ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable mIdCache (40, std::pair<std::string, Ptr::CellStore *> ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable
mIdCacheIndex (0) mIdCacheIndex (0)
{} {}

View file

@ -122,6 +122,11 @@ namespace MWWorld
return 0; return 0;
} }
float Class::getJump (const Ptr& ptr) const
{
return 0;
}
MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const
{ {
throw std::runtime_error ("movement settings not supported by class"); throw std::runtime_error ("movement settings not supported by class");

View file

@ -140,6 +140,9 @@ namespace MWWorld
virtual float getSpeed (const Ptr& ptr) const; virtual float getSpeed (const Ptr& ptr) const;
///< Return movement speed. ///< Return movement speed.
virtual float getJump(const MWWorld::Ptr &ptr) const;
///< Return jump velocity (not accounting for movement)
virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const;
///< Return desired movement. ///< Return desired movement.

View file

@ -9,6 +9,10 @@
#include <OgreCamera.h> #include <OgreCamera.h>
#include <OgreTextureManager.h> #include <OgreTextureManager.h>
#include <openengine/bullet/trace.h>
#include <openengine/bullet/physic.hpp>
#include <openengine/ogre/renderer.hpp>
#include <components/nifbullet/bullet_nif_loader.hpp> #include <components/nifbullet/bullet_nif_loader.hpp>
//#include "../mwbase/world.hpp" // FIXME //#include "../mwbase/world.hpp" // FIXME
@ -21,23 +25,191 @@ using namespace Ogre;
namespace MWWorld namespace MWWorld
{ {
PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : static const float sMaxSlope = 60.0f;
mRender(_rend), mEngine(0), mFreeFly (true) static const float sStepSize = 30.0f;
{ // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
static const int sMaxIterations = 50;
playerphysics = new playerMove; class MovementSolver
{
private:
static bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime,
const Ogre::Vector3 &halfExtents, bool isInterior,
OEngine::Physic::PhysicEngine *engine)
{
traceResults trace; // no initialization needed
newtrace(&trace, position, position+Ogre::Vector3(0.0f,0.0f,sStepSize),
halfExtents, isInterior, engine);
if(trace.fraction == 0.0f)
return false;
newtrace(&trace, trace.endpos, trace.endpos + velocity*remainingTime,
halfExtents, isInterior, engine);
if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope))
return false;
newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, isInterior, engine);
if(getSlope(trace.planenormal) <= sMaxSlope)
{
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
position = trace.endpos;
return true;
}
return false;
}
static void clipVelocity(Ogre::Vector3& inout, const Ogre::Vector3& normal, float overbounce=1.0f)
{
//Math stuff. Basically just project the velocity vector onto the plane represented by the normal.
//More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity.
float backoff = inout.dotProduct(normal);
if(backoff < 0.0f)
backoff *= overbounce;
else
backoff /= overbounce;
inout -= normal*backoff;
}
static void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction)
{
Ogre::Vector3 normalizedDirection(direction);
normalizedDirection.normalise();
// no divide by normalizedDirection.length necessary because it's normalized
velocity = normalizedDirection * velocity.dotProduct(normalizedDirection);
}
static float getSlope(const Ogre::Vector3 &normal)
{
return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees();
}
public:
static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time,
bool gravity, OEngine::Physic::PhysicEngine *engine)
{
const ESM::Position &refpos = ptr.getRefData().getPosition();
Ogre::Vector3 position(refpos.pos);
/* Anything to collide with? */
OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
if(!physicActor || !physicActor->getCollisionMode())
{
// FIXME: This works, but it's inconcsistent with how the rotations are applied elsewhere. Why?
return position + (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)*
Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)*
Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) *
movement;
}
traceResults trace; //no initialization needed
bool onground = false;
float remainingTime = time;
bool isInterior = !ptr.getCell()->isExterior();
Ogre::Vector3 halfExtents = physicActor->getHalfExtents();
Ogre::Vector3 velocity;
if(!gravity)
{
velocity = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)*
Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)*
Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) *
movement / time;
}
else
{
if(!(movement.z > 0.0f))
{
newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, isInterior, engine);
if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope)
onground = true;
}
velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) *
movement / time;
velocity.z += physicActor->getVerticalForce();
}
Ogre::Vector3 clippedVelocity(velocity);
if(onground)
{
// if we're on the ground, force velocity to track it
clippedVelocity.z = velocity.z = std::max(0.0f, velocity.z);
clipVelocity(clippedVelocity, trace.planenormal);
}
const Ogre::Vector3 up(0.0f, 0.0f, 1.0f);
Ogre::Vector3 newPosition = position;
int iterations = 0;
do {
// trace to where character would go if there were no obstructions
newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine);
newPosition = trace.endpos;
remainingTime = remainingTime * (1.0f-trace.fraction);
// check for obstructions
if(trace.fraction < 1.0f)
{
//std::cout<<"angle: "<<getSlope(trace.planenormal)<<"\n";
if(getSlope(trace.planenormal) <= sMaxSlope)
{
// We hit a slope we can walk on. Update velocity accordingly.
clipVelocity(clippedVelocity, trace.planenormal);
// We're only on the ground if gravity is affecting us
onground = gravity;
}
else
{
// Can't walk on this. Try to step up onto it.
if((gravity && !onground) ||
!stepMove(newPosition, velocity, remainingTime, halfExtents, isInterior, engine))
{
Ogre::Vector3 resultantDirection = trace.planenormal.crossProduct(up);
resultantDirection.normalise();
clippedVelocity = velocity;
projectVelocity(clippedVelocity, resultantDirection);
// just this isn't enough sometimes. It's the same problem that causes steps to be necessary on even uphill terrain.
clippedVelocity += trace.planenormal*clippedVelocity.length()/50.0f;
}
}
}
iterations++;
} while(iterations < sMaxIterations && remainingTime > 0.0f);
if(onground)
{
newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, isInterior, engine);
if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope)
newPosition.z = trace.endpos.z + 2.0f;
else
onground = false;
}
physicActor->setOnGround(onground);
physicActor->setVerticalForce(!onground ? clippedVelocity.z - time*627.2f : 0.0f);
return newPosition;
}
};
PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) :
mRender(_rend), mEngine(0)
{
// Create physics. shapeLoader is deleted by the physic engine // Create physics. shapeLoader is deleted by the physic engine
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
playerphysics->mEngine = mEngine;
} }
PhysicsSystem::~PhysicsSystem() PhysicsSystem::~PhysicsSystem()
{ {
delete mEngine; delete mEngine;
delete playerphysics;
} }
OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine()
{ {
return mEngine; return mEngine;
@ -92,9 +264,8 @@ namespace MWWorld
Ogre::Vector3 to = ray.getPoint(queryDistance); Ogre::Vector3 to = ray.getPoint(queryDistance);
btVector3 _from, _to; btVector3 _from, _to;
// OGRE to MW coordinates _from = btVector3(from.x, from.y, from.z);
_from = btVector3(from.x, -from.z, from.y); _to = btVector3(to.x, to.y, to.z);
_to = btVector3(to.x, -to.z, to.y);
std::vector < std::pair <float, std::string> > results; std::vector < std::pair <float, std::string> > results;
/* auto */ results = mEngine->rayTest2(_from,_to); /* auto */ results = mEngine->rayTest2(_from,_to);
@ -106,15 +277,7 @@ namespace MWWorld
void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight) void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight)
{ {
playerphysics->hasWater = hasWater; // TODO: store and use
if(hasWater){
playerphysics->waterHeight = waterHeight;
}
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{
it->second->setCurrentWater(hasWater, waterHeight);
}
} }
btVector3 PhysicsSystem::getRayPoint(float extent) btVector3 PhysicsSystem::getRayPoint(float extent)
@ -123,7 +286,7 @@ namespace MWWorld
Ray centerRay = mRender.getCamera()->getCameraToViewportRay( Ray centerRay = mRender.getCamera()->getCameraToViewportRay(
mRender.getViewport()->getWidth()/2, mRender.getViewport()->getWidth()/2,
mRender.getViewport()->getHeight()/2); mRender.getViewport()->getHeight()/2);
btVector3 result(centerRay.getPoint(extent).x,-centerRay.getPoint(extent).z,centerRay.getPoint(extent).y); btVector3 result(centerRay.getPoint(extent).x,centerRay.getPoint(extent).y,centerRay.getPoint(extent).z);
return result; return result;
} }
@ -131,7 +294,7 @@ namespace MWWorld
{ {
//get a ray pointing to the center of the viewport //get a ray pointing to the center of the viewport
Ray centerRay = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); Ray centerRay = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY);
btVector3 result(centerRay.getPoint(extent).x,-centerRay.getPoint(extent).z,centerRay.getPoint(extent).y); btVector3 result(centerRay.getPoint(extent).x,centerRay.getPoint(extent).y,centerRay.getPoint(extent).z);
return result; return result;
} }
@ -171,9 +334,8 @@ namespace MWWorld
Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable
btVector3 _from, _to; btVector3 _from, _to;
// OGRE to MW coordinates _from = btVector3(from.x, from.y, from.z);
_from = btVector3(from.x, -from.z, from.y); _to = btVector3(to.x, to.y, to.z);
_to = btVector3(to.x, -to.z, to.y);
std::pair<std::string, float> result = mEngine->rayTest(_from, _to); std::pair<std::string, float> result = mEngine->rayTest(_from, _to);
@ -185,71 +347,11 @@ namespace MWWorld
} }
} }
void PhysicsSystem::doPhysics(float dt, const std::vector<std::pair<std::string, Ogre::Vector3> >& actors) Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity)
{ {
//set the DebugRenderingMode. To disable it,set it to 0 return MovementSolver::move(ptr, movement, time, gravity, mEngine);
//eng->setDebugRenderingMode(1);
//set the movement keys to 0 (no movement) for every actor)
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{
OEngine::Physic::PhysicActor* act = it->second;
act->setMovement(0,0,0);
}
playerMove::playercmd& pm_ref = playerphysics->cmd;
pm_ref.rightmove = 0;
pm_ref.forwardmove = 0;
pm_ref.upmove = 0;
//playerphysics->ps.move_type = PM_NOCLIP;
for (std::vector<std::pair<std::string, Ogre::Vector3> >::const_iterator iter (actors.begin());
iter!=actors.end(); ++iter)
{
//dirty stuff to get the camera orientation. Must be changed!
if (iter->first == "player") {
playerphysics->ps.viewangles.x =
Ogre::Radian(mPlayerData.pitch).valueDegrees();
playerphysics->ps.viewangles.y =
Ogre::Radian(mPlayerData.yaw).valueDegrees() + 90;
pm_ref.rightmove = iter->second.x;
pm_ref.forwardmove = -iter->second.y;
pm_ref.upmove = iter->second.z;
}
}
mEngine->stepSimulation(dt);
} }
std::vector< std::pair<std::string, Ogre::Vector3> > PhysicsSystem::doPhysicsFixed (
const std::vector<std::pair<std::string, Ogre::Vector3> >& actors)
{
Pmove(playerphysics);
std::vector< std::pair<std::string, Ogre::Vector3> > response;
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{
Ogre::Vector3 coord = it->second->getPosition();
if(it->first == "player"){
coord = playerphysics->ps.origin ;
}
response.push_back(std::pair<std::string, Ogre::Vector3>(it->first, coord));
}
return response;
}
void PhysicsSystem::addHeightField (float* heights, void PhysicsSystem::addHeightField (float* heights,
int x, int y, float yoffset, int x, int y, float yoffset,
@ -291,46 +393,20 @@ namespace MWWorld
void PhysicsSystem::moveObject (const Ptr& ptr) void PhysicsSystem::moveObject (const Ptr& ptr)
{ {
Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); Ogre::SceneNode *node = ptr.getRefData().getBaseNode();
std::string handle = node->getName(); const std::string &handle = node->getName();
Ogre::Vector3 position = node->getPosition(); const Ogre::Vector3 &position = node->getPosition();
if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle))
{ body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z));
// TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow else if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle))
// start positions others than 0, 0, 0 physact->setPosition(position);
if(dynamic_cast<btBoxShape*>(body->getCollisionShape()) == NULL){
btTransform tr = body->getWorldTransform();
tr.setOrigin(btVector3(position.x,position.y,position.z));
body->setWorldTransform(tr);
}
else{
//For objects that contain a box shape.
//Do any such objects exist? Perhaps animated objects?
mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation());
}
}
if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle))
{
// TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow
// start positions others than 0, 0, 0
if (handle == "player")
{
playerphysics->ps.origin = position;
}
else
{
act->setPosition(position);
}
}
} }
void PhysicsSystem::rotateObject (const Ptr& ptr) void PhysicsSystem::rotateObject (const Ptr& ptr)
{ {
Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
std::string handle = node->getName(); const std::string &handle = node->getName();
Ogre::Quaternion rotation = node->getOrientation(); const Ogre::Quaternion &rotation = node->getOrientation();
if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle))
{ {
//Needs to be changed //Needs to be changed
@ -348,7 +424,7 @@ namespace MWWorld
void PhysicsSystem::scaleObject (const Ptr& ptr) void PhysicsSystem::scaleObject (const Ptr& ptr)
{ {
Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
std::string handle = node->getName(); const std::string &handle = node->getName();
if(handleToMesh.find(handle) != handleToMesh.end()) if(handleToMesh.find(handle) != handleToMesh.end())
{ {
removeObject(handle); removeObject(handle);
@ -361,7 +437,6 @@ namespace MWWorld
bool PhysicsSystem::toggleCollisionMode() bool PhysicsSystem::toggleCollisionMode()
{ {
playerphysics->ps.move_type = (playerphysics->ps.move_type == PM_NOCLIP ? PM_NORMAL : PM_NOCLIP);
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{ {
if (it->first=="player") if (it->first=="player")
@ -372,12 +447,10 @@ namespace MWWorld
if(cmode) if(cmode)
{ {
act->enableCollisions(false); act->enableCollisions(false);
mFreeFly = true;
return false; return false;
} }
else else
{ {
mFreeFly = false;
act->enableCollisions(true); act->enableCollisions(true);
return true; return true;
} }

View file

@ -1,12 +1,27 @@
#ifndef GAME_MWWORLD_PHYSICSSYSTEM_H #ifndef GAME_MWWORLD_PHYSICSSYSTEM_H
#define GAME_MWWORLD_PHYSICSSYSTEM_H #define GAME_MWWORLD_PHYSICSSYSTEM_H
#include <openengine/ogre/renderer.hpp> #include <OgreVector3.h>
#include "ptr.hpp"
#include <openengine/bullet/pmove.h> #include <btBulletCollisionCommon.h>
namespace OEngine
{
namespace Render
{
class OgreRenderer;
}
namespace Physic
{
class PhysicEngine;
}
}
namespace MWWorld namespace MWWorld
{ {
class World;
class Ptr;
class PhysicsSystem class PhysicsSystem
{ {
@ -14,12 +29,6 @@ namespace MWWorld
PhysicsSystem (OEngine::Render::OgreRenderer &_rend); PhysicsSystem (OEngine::Render::OgreRenderer &_rend);
~PhysicsSystem (); ~PhysicsSystem ();
void doPhysics(float duration, const std::vector<std::pair<std::string, Ogre::Vector3> >& actors);
///< do physics with dt - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed
std::vector< std::pair<std::string, Ogre::Vector3> > doPhysicsFixed (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors);
///< do physics with fixed timestep - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed
void addObject (const MWWorld::Ptr& ptr); void addObject (const MWWorld::Ptr& ptr);
void addActor (const MWWorld::Ptr& ptr); void addActor (const MWWorld::Ptr& ptr);
@ -41,6 +50,8 @@ namespace MWWorld
bool toggleCollisionMode(); bool toggleCollisionMode();
Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity);
std::pair<float, std::string> getFacedHandle (MWWorld::World& world, float queryDistance); std::pair<float, std::string> getFacedHandle (MWWorld::World& world, float queryDistance);
std::vector < std::pair <float, std::string> > getFacedHandles (float queryDistance); std::vector < std::pair <float, std::string> > getFacedHandles (float queryDistance);
std::vector < std::pair <float, std::string> > getFacedHandles (float mouseX, float mouseY, float queryDistance); std::vector < std::pair <float, std::string> > getFacedHandles (float mouseX, float mouseY, float queryDistance);
@ -74,8 +85,6 @@ namespace MWWorld
OEngine::Render::OgreRenderer &mRender; OEngine::Render::OgreRenderer &mRender;
OEngine::Physic::PhysicEngine* mEngine; OEngine::Physic::PhysicEngine* mEngine;
bool mFreeFly;
playerMove* playerphysics;
std::map<std::string, std::string> handleToMesh; std::map<std::string, std::string> handleToMesh;
PhysicsSystem (const PhysicsSystem&); PhysicsSystem (const PhysicsSystem&);

View file

@ -71,6 +71,12 @@ namespace MWWorld
MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value; MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value;
} }
void Player::setRunState(bool run)
{
MWWorld::Ptr ptr = getPlayer();
MWWorld::Class::get(ptr).setStance(ptr, MWWorld::Class::Run, run);
}
void Player::toggleRunning() void Player::toggleRunning()
{ {
MWWorld::Ptr ptr = getPlayer(); MWWorld::Ptr ptr = getPlayer();

View file

@ -65,6 +65,7 @@ namespace MWWorld
void setForwardBackward (int value); void setForwardBackward (int value);
void setUpDown(int value); void setUpDown(int value);
void setRunState(bool run);
void toggleRunning(); void toggleRunning();
}; };
} }

View file

@ -1,5 +1,6 @@
#include "scene.hpp" #include "scene.hpp"
#include <components/nif/nif_file.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" /// FIXME #include "../mwbase/world.hpp" /// FIXME
@ -7,9 +8,11 @@
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "physicssystem.hpp"
#include "player.hpp" #include "player.hpp"
#include "localscripts.hpp" #include "localscripts.hpp"
#include "esmstore.hpp" #include "esmstore.hpp"
#include "class.hpp"
#include "cellfunctors.hpp" #include "cellfunctors.hpp"
@ -24,13 +27,10 @@ namespace
{ {
const MWWorld::Class& class_ = const MWWorld::Class& class_ =
MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell));
int numRefs = cellRefList.mList.size();
int current = 0; int current = 0;
for (typename T::List::iterator it = cellRefList.mList.begin(); for (typename T::List::iterator it = cellRefList.mList.begin();
it != cellRefList.mList.end(); it++) it != cellRefList.mList.end(); it++)
{ {
MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs);
++current; ++current;
if (it->mData.getCount() || it->mData.isEnabled()) if (it->mData.getCount() || it->mData.isEnabled())
@ -52,10 +52,6 @@ namespace
} }
} }
} }
else
{
MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, 0, 1);
}
} }
} }
@ -98,7 +94,7 @@ namespace MWWorld
//mPhysics->removeObject("Unnamed_43"); //mPhysics->removeObject("Unnamed_43");
MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter);
MWBase::Environment::get().getMechanicsManager()->dropActors (*iter); MWBase::Environment::get().getMechanicsManager()->drop (*iter);
MWBase::Environment::get().getSoundManager()->stopSound (*iter); MWBase::Environment::get().getSoundManager()->stopSound (*iter);
mActiveCells.erase(*iter); mActiveCells.erase(*iter);
} }
@ -164,7 +160,7 @@ namespace MWWorld
MWBase::MechanicsManager *mechMgr = MWBase::MechanicsManager *mechMgr =
MWBase::Environment::get().getMechanicsManager(); MWBase::Environment::get().getMechanicsManager();
mechMgr->addActor(player); mechMgr->add(player);
mechMgr->watchActor(player); mechMgr->watchActor(player);
MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell);
@ -173,11 +169,17 @@ 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; Nif::NIFFile::CacheLock cachelock;
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
mRendering.preCellChange(mCurrentCell); mRendering.preCellChange(mCurrentCell);
// remove active // remove active
MWBase::Environment::get().getMechanicsManager()->removeActor (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); MWBase::Environment::get().getMechanicsManager()->remove(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
std::string loadingExteriorText;
loadingExteriorText = gmst.find ("sLoadingMessage3")->getString();
CellStoreCollection::iterator active = mActiveCells.begin(); CellStoreCollection::iterator active = mActiveCells.begin();
@ -213,8 +215,6 @@ namespace MWWorld
continue; continue;
} }
} }
MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload);
unloadCell (active++); unloadCell (active++);
++current; ++current;
} }
@ -263,7 +263,9 @@ namespace MWWorld
{ {
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, current, numLoad); //Loading Exterior loading text
MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingExteriorText, 0, current, numLoad);
loadCell (cell); loadCell (cell);
++current; ++current;
} }
@ -322,6 +324,13 @@ namespace MWWorld
void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position)
{ {
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
std::string loadingInteriorText;
loadingInteriorText = gmst.find ("sLoadingMessage2")->getString();
CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName);
bool loadcell = (mCurrentCell == NULL); bool loadcell = (mCurrentCell == NULL);
if(!loadcell) if(!loadcell)
@ -357,8 +366,6 @@ namespace MWWorld
active = mActiveCells.begin(); active = mActiveCells.begin();
while (active!=mActiveCells.end()) while (active!=mActiveCells.end())
{ {
MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload);
unloadCell (active++); unloadCell (active++);
++current; ++current;
} }
@ -366,7 +373,9 @@ namespace MWWorld
// Load cell. // Load cell.
std::cout << "cellName: " << cell->mCell->mName << std::endl; std::cout << "cellName: " << cell->mCell->mName << std::endl;
MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, 0, 1); //Loading Interior loading text
MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingInteriorText, 0, 0, 1);
loadCell (cell); loadCell (cell);
mCurrentCell = cell; mCurrentCell = cell;
@ -441,7 +450,7 @@ namespace MWWorld
void Scene::removeObjectFromScene (const Ptr& ptr) void Scene::removeObjectFromScene (const Ptr& ptr)
{ {
MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); MWBase::Environment::get().getMechanicsManager()->remove (ptr);
MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr);
mPhysics->removeObject (ptr.getRefData().getHandle()); mPhysics->removeObject (ptr.getRefData().getHandle());
mRendering.removeObject (ptr); mRendering.removeObject (ptr);

View file

@ -3,7 +3,7 @@
#include "../mwrender/renderingmanager.hpp" #include "../mwrender/renderingmanager.hpp"
#include "physicssystem.hpp" #include "ptr.hpp"
#include "globals.hpp" #include "globals.hpp"
namespace Ogre namespace Ogre
@ -34,9 +34,9 @@ namespace MWRender
namespace MWWorld namespace MWWorld
{ {
class PhysicsSystem;
class Player; class Player;
class CellStore; class CellStore;
class Ptr;
class Scene class Scene
{ {

View file

@ -17,9 +17,9 @@ namespace MWWorld
virtual void setUp() {} virtual void setUp() {}
virtual void listIdentifier(std::vector<std::string> &list) const {} virtual void listIdentifier(std::vector<std::string> &list) const {}
virtual int getSize() const = 0; virtual size_t getSize() const = 0;
virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; virtual void load(ESM::ESMReader &esm, const std::string &id) = 0;
virtual bool eraseStatic(const std::string &id) {return false;} virtual bool eraseStatic(const std::string &id) {return false;}
}; };
@ -110,7 +110,7 @@ namespace MWWorld
item.mId = Misc::StringUtils::lowerCase(id); item.mId = Misc::StringUtils::lowerCase(id);
typename std::map<std::string, T>::const_iterator it = mStatic.find(item.mId); typename std::map<std::string, T>::const_iterator it = mStatic.find(item.mId);
if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) {
return &(it->second); return &(it->second);
} }
@ -158,7 +158,7 @@ namespace MWWorld
return mShared.end(); return mShared.end();
} }
int getSize() const { size_t getSize() const {
return mShared.size(); return mShared.size();
} }
@ -188,14 +188,14 @@ namespace MWWorld
item.mId = Misc::StringUtils::lowerCase(id); item.mId = Misc::StringUtils::lowerCase(id);
typename std::map<std::string, T>::iterator it = mStatic.find(item.mId); typename std::map<std::string, T>::iterator it = mStatic.find(item.mId);
if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) {
mStatic.erase(it); mStatic.erase(it);
} }
return true; return true;
} }
bool erase(const std::string &id) { bool erase(const std::string &id) {
std::string key = Misc::StringUtils::lowerCase(id); std::string key = Misc::StringUtils::lowerCase(id);
typename Dynamic::iterator it = mDynamic.find(key); typename Dynamic::iterator it = mDynamic.find(key);
@ -220,9 +220,15 @@ namespace MWWorld
template <> template <>
inline void Store<ESM::Dialogue>::load(ESM::ESMReader &esm, const std::string &id) { inline void Store<ESM::Dialogue>::load(ESM::ESMReader &esm, const std::string &id) {
std::string idLower = Misc::StringUtils::lowerCase(id); std::string idLower = Misc::StringUtils::lowerCase(id);
mStatic[idLower] = ESM::Dialogue();
mStatic[idLower].mId = id; // don't smash case here, as this line is printed... I think std::map<std::string, ESM::Dialogue>::iterator it = mStatic.find(idLower);
mStatic[idLower].load(esm); if (it == mStatic.end()) {
it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first;
it->second.mId = id; // don't smash case here, as this line is printed... I think
}
//I am not sure is it need to load the dialog from a plugin if it was already loaded from prevois plugins
it->second.load(esm);
} }
template <> template <>
@ -269,11 +275,11 @@ namespace MWWorld
return ptr; return ptr;
} }
int getSize() const { size_t getSize() const {
return mStatic.size(); return mStatic.size();
} }
int getSize(size_t plugin) const { size_t getSize(size_t plugin) const {
assert(plugin < mStatic.size()); assert(plugin < mStatic.size());
return mStatic[plugin].size(); return mStatic[plugin].size();
} }
@ -338,7 +344,7 @@ namespace MWWorld
} }
int getSize() const { size_t getSize() const {
return mStatic.size(); return mStatic.size();
} }
@ -409,7 +415,7 @@ namespace MWWorld
DynamicInt mDynamicInt; DynamicInt mDynamicInt;
DynamicExt mDynamicExt; DynamicExt mDynamicExt;
const ESM::Cell *search(const ESM::Cell &cell) const { const ESM::Cell *search(const ESM::Cell &cell) const {
if (cell.isExterior()) { if (cell.isExterior()) {
return search(cell.getGridX(), cell.getGridY()); return search(cell.getGridX(), cell.getGridY());
@ -481,7 +487,7 @@ namespace MWWorld
newCell->mData.mY = y; newCell->mData.mY = y;
mExt[std::make_pair(x, y)] = *newCell; mExt[std::make_pair(x, y)] = *newCell;
delete newCell; delete newCell;
return &mExt[std::make_pair(x, y)]; return &mExt[std::make_pair(x, y)];
} }
@ -528,7 +534,7 @@ namespace MWWorld
// There some nasty three-way cyclic header dependency involved, which I could only fix by moving // There some nasty three-way cyclic header dependency involved, which I could only fix by moving
// this method. // this method.
void load(ESM::ESMReader &esm, const std::string &id); void load(ESM::ESMReader &esm, const std::string &id);
iterator intBegin() const { iterator intBegin() const {
return iterator(mSharedInt.begin()); return iterator(mSharedInt.begin());
} }
@ -567,7 +573,7 @@ namespace MWWorld
return 0; return 0;
} }
int getSize() const { size_t getSize() const {
return mSharedInt.size() + mSharedExt.size(); return mSharedInt.size() + mSharedExt.size();
} }
@ -701,7 +707,7 @@ namespace MWWorld
mStatic.back().load(esm); mStatic.back().load(esm);
} }
int getSize() const { size_t getSize() const {
return mStatic.size(); return mStatic.size();
} }
@ -930,7 +936,7 @@ namespace MWWorld
} }
} }
int getSize() const { size_t getSize() const {
return mStatic.size(); return mStatic.size();
} }

View file

@ -1,5 +1,7 @@
#include "worldimp.hpp" #include "worldimp.hpp"
#include <libs/openengine/bullet/physic.hpp>
#include <components/bsa/bsa_archive.hpp> #include <components/bsa/bsa_archive.hpp>
#include <components/files/collections.hpp> #include <components/files/collections.hpp>
#include <components/compiler/locals.hpp> #include <components/compiler/locals.hpp>
@ -10,6 +12,8 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/scriptmanager.hpp" #include "../mwbase/scriptmanager.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwrender/sky.hpp" #include "../mwrender/sky.hpp"
#include "../mwrender/player.hpp" #include "../mwrender/player.hpp"
@ -18,6 +22,7 @@
#include "player.hpp" #include "player.hpp"
#include "manualref.hpp" #include "manualref.hpp"
#include "cellfunctors.hpp" #include "cellfunctors.hpp"
#include "containerstore.hpp"
using namespace Ogre; using namespace Ogre;
@ -183,6 +188,8 @@ namespace MWWorld
mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine); mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine);
mPhysEngine->setSceneManager(renderer.getScene());
mWeatherManager = new MWWorld::WeatherManager(mRendering); mWeatherManager = new MWWorld::WeatherManager(mRendering);
int idx = 0; int idx = 0;
@ -732,6 +739,7 @@ namespace MWWorld
removeContainerScripts(ptr); removeContainerScripts(ptr);
if (isPlayer) if (isPlayer)
{
if (!newCell.isExterior()) if (!newCell.isExterior())
changeToInteriorCell(Misc::StringUtils::lowerCase(newCell.mCell->mName), pos); changeToInteriorCell(Misc::StringUtils::lowerCase(newCell.mCell->mName), pos);
else else
@ -740,13 +748,18 @@ namespace MWWorld
int cellY = newCell.mCell->getGridY(); int cellY = newCell.mCell->getGridY();
mWorldScene->changeCell(cellX, cellY, pos, false); mWorldScene->changeCell(cellX, cellY, pos, false);
} }
}
else else
{ {
if (!mWorldScene->isCellActive(*currCell)) if (!mWorldScene->isCellActive(*currCell))
copyObjectToCell(ptr, newCell, pos); copyObjectToCell(ptr, newCell, pos);
else if (!mWorldScene->isCellActive(newCell)) else if (!mWorldScene->isCellActive(newCell))
{ {
MWWorld::Class::get(ptr).copyToCell(ptr, newCell); MWWorld::Class::get(ptr)
.copyToCell(ptr, newCell)
.getRefData()
.setBaseNode(0);
mWorldScene->removeObjectFromScene(ptr); mWorldScene->removeObjectFromScene(ptr);
mLocalScripts.remove(ptr); mLocalScripts.remove(ptr);
removeContainerScripts (ptr); removeContainerScripts (ptr);
@ -757,7 +770,10 @@ namespace MWWorld
MWWorld::Ptr copy = MWWorld::Ptr copy =
MWWorld::Class::get(ptr).copyToCell(ptr, newCell); MWWorld::Class::get(ptr).copyToCell(ptr, newCell);
mRendering->moveObjectToCell(copy, vec, currCell); mRendering->updateObjectCell(ptr, copy);
MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager();
mechMgr->updateCell(ptr, copy);
std::string script = std::string script =
MWWorld::Class::get(ptr).getScript(ptr); MWWorld::Class::get(ptr).getScript(ptr);
@ -768,15 +784,6 @@ namespace MWWorld
mLocalScripts.add(script, copy); mLocalScripts.add(script, copy);
addContainerScripts (copy, &newCell); addContainerScripts (copy, &newCell);
} }
if (MWWorld::Class::get(ptr).isActor())
{
MWBase::MechanicsManager *mechMgr =
MWBase::Environment::get().getMechanicsManager();
mechMgr->removeActor(ptr);
mechMgr->addActor(copy);
}
} }
ptr.getRefData().setCount(0); ptr.getRefData().setCount(0);
} }
@ -825,16 +832,16 @@ namespace MWWorld
rot.y = Ogre::Degree(y).valueRadians(); rot.y = Ogre::Degree(y).valueRadians();
rot.z = Ogre::Degree(z).valueRadians(); rot.z = Ogre::Degree(z).valueRadians();
float *objRot = ptr.getRefData().getPosition().rot; if (mRendering->rotateObject(ptr, rot, adjust))
if(ptr.getRefData().getBaseNode() == 0 || !mRendering->rotateObject(ptr, rot, adjust))
{ {
objRot[0] = (adjust ? objRot[0] + rot.x : rot.x), objRot[1] = (adjust ? objRot[1] + rot.y : rot.y), objRot[2] = (adjust ? objRot[2] + rot.z : rot.z); // rotate physically iff renderer confirm so
return; float *objRot = ptr.getRefData().getPosition().rot;
} objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z;
// do this after rendering rotated the object so it gets changed by Class->adjustRotation if (ptr.getRefData().getBaseNode() != 0) {
objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; mPhysics->rotateObject(ptr);
mPhysics->rotateObject(ptr); }
}
} }
void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos)
@ -871,53 +878,33 @@ namespace MWWorld
--cellY; --cellY;
} }
void World::doPhysics (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors, void World::doPhysics(const PtrMovementList &actors, float duration)
float duration)
{ {
mPhysics->doPhysics(duration, actors); /* No duration? Shouldn't be any movement, then. */
if(duration <= 0.0f)
return;
const int tick = 16; // 16 ms ^= 60 Hz PtrMovementList::const_iterator player(actors.end());
for(PtrMovementList::const_iterator iter(actors.begin());iter != actors.end();iter++)
// Game clock part of the loop, contains everything that has to be executed in a fixed timestep
long long dt = mTimer.getMilliseconds() - lastTick;
if (dt >= 100)
{ {
// throw away wall clock time if necessary to keep the framerate above the minimum of 10 fps if(iter->first.getRefData().getHandle() == "player")
lastTick += (dt - 100); {
dt = 100; /* Handle player last, in case a cell transition occurs */
player = iter;
continue;
}
Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration,
!isSwimming(iter->first) && !isFlying(iter->first));
moveObjectImp(iter->first, vec.x, vec.y, vec.z);
} }
while (dt >= tick) if(player != actors.end())
{ {
dt -= tick; Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration,
lastTick += tick; !isSwimming(player->first) && !isFlying(player->first));
moveObjectImp(player->first, vec.x, vec.y, vec.z);
std::vector< std::pair<std::string, Ogre::Vector3> > vectors = mPhysics->doPhysicsFixed (actors);
std::vector< std::pair<std::string, Ogre::Vector3> >::iterator player = vectors.end();
for (std::vector< std::pair<std::string, Ogre::Vector3> >::iterator it = vectors.begin();
it!= vectors.end(); ++it)
{
if (it->first=="player")
{
player = it;
}
else
{
MWWorld::Ptr ptr = getPtrViaHandle (it->first);
moveObjectImp (ptr, it->second.x, it->second.y, it->second.z);
}
}
// Make sure player is moved last (otherwise the cell might change in the middle of an update
// loop)
if (player!=vectors.end())
{
if (moveObjectImp (getPtrViaHandle (player->first),
player->second.x, player->second.y, player->second.z) == true)
return; // abort the current loop if the cell has changed
}
} }
// the only purpose this has currently is to update the debug drawer
mPhysEngine->stepSimulation (duration);
} }
bool World::toggleCollisionMode() bool World::toggleCollisionMode()
@ -985,17 +972,6 @@ namespace MWWorld
return ret; return ret;
} }
void World::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode,
int number)
{
mRendering->playAnimationGroup (ptr, groupName, mode, number);
}
void World::skipAnimation (const MWWorld::Ptr& ptr)
{
mRendering->skipAnimation (ptr);
}
void World::update (float duration, bool paused) void World::update (float duration, bool paused)
{ {
mWorldScene->update (duration, paused); mWorldScene->update (duration, paused);
@ -1048,7 +1024,6 @@ namespace MWWorld
// currently its here because we need to access the physics system // currently its here because we need to access the physics system
float* p = mPlayer->getPlayer().getRefData().getPosition().pos; float* p = mPlayer->getPlayer().getRefData().getPosition().pos;
Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); Vector3 sun = mRendering->getSkyManager()->getRealSunPos();
sun = Vector3(sun.x, -sun.z, sun.y);
mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun));
} }
@ -1146,7 +1121,7 @@ namespace MWWorld
} }
else else
p = mPhysics->getRayPoint(results.front().first); p = mPhysics->getRayPoint(results.front().first);
Ogre::Vector3 pos(p.x(), p.z(), -p.y()); Ogre::Vector3 pos(p.x(), p.y(), p.z());
Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode();
//std::cout << "Num facing 1 : " << mFaced1Name << std::endl; //std::cout << "Num facing 1 : " << mFaced1Name << std::endl;
@ -1174,7 +1149,7 @@ namespace MWWorld
} }
else else
p = mPhysics->getRayPoint(results.at (1).first); p = mPhysics->getRayPoint(results.at (1).first);
Ogre::Vector3 pos(p.x(), p.z(), -p.y()); Ogre::Vector3 pos(p.x(), p.y(), p.z());
Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode();
Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode();
@ -1252,8 +1227,8 @@ namespace MWWorld
if (!ref) if (!ref)
return Vector2(0, 1); return Vector2(0, 1);
Ogre::SceneNode* node = ref->mData.getBaseNode(); Ogre::SceneNode* node = ref->mData.getBaseNode();
Vector3 dir = node->_getDerivedOrientation().yAxis(); Vector3 dir = node->_getDerivedOrientation() * Ogre::Vector3(0,1,0);
Vector2 d = Vector2(dir.x, dir.z); Vector2 d = Vector2(dir.x, dir.y);
return d; return d;
} }
@ -1323,7 +1298,7 @@ namespace MWWorld
if (isCellExterior()) if (isCellExterior())
{ {
int cellX, cellY; int cellX, cellY;
positionToIndex(result.second[0], -result.second[2], cellX, cellY); positionToIndex(result.second[0], result.second[1], cellX, cellY);
cell = mCells.getExterior(cellX, cellY); cell = mCells.getExterior(cellX, cellY);
} }
else else
@ -1331,8 +1306,8 @@ namespace MWWorld
ESM::Position pos = getPlayer().getPlayer().getRefData().getPosition(); ESM::Position pos = getPlayer().getPlayer().getRefData().getPosition();
pos.pos[0] = result.second[0]; pos.pos[0] = result.second[0];
pos.pos[1] = -result.second[2]; pos.pos[1] = result.second[1];
pos.pos[2] = result.second[1]; pos.pos[2] = result.second[2];
Ptr dropped = copyObjectToCell(object, *cell, pos); Ptr dropped = copyObjectToCell(object, *cell, pos);
PCDropped(dropped); PCDropped(dropped);
@ -1416,25 +1391,42 @@ namespace MWWorld
} }
bool bool
World::isSwimming(const MWWorld::Ptr &object) World::isFlying(const MWWorld::Ptr &ptr) const
{
const MWWorld::Class &cls = MWWorld::Class::get(ptr);
if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0)
return true;
return false;
}
bool
World::isSwimming(const MWWorld::Ptr &object) const
{ {
/// \todo add check ifActor() - only actors can swim /// \todo add check ifActor() - only actors can swim
float *fpos = object.getRefData().getPosition().pos; float *fpos = object.getRefData().getPosition().pos;
Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]);
/// \fixme should rely on object height /// \fixme 3/4ths submerged?
pos.z += 30; const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle());
if(actor) pos.z += actor->getHalfExtents().z * 1.5;
return isUnderwater(*object.getCell()->mCell, pos); return isUnderwater(object.getCell(), pos);
} }
bool bool
World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) World::isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const
{ {
if (!(cell.mData.mFlags & ESM::Cell::HasWater)) { if (!(cell->mCell->mData.mFlags & ESM::Cell::HasWater)) {
return false; return false;
} }
return pos.z < cell.mWater; return pos.z < cell->mWaterLevel;
}
bool World::isOnGround(const MWWorld::Ptr &ptr) const
{
RefData &refdata = ptr.getRefData();
const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle());
return physactor && physactor->getOnGround();
} }
void World::renderPlayer() void World::renderPlayer()
@ -1451,24 +1443,21 @@ namespace MWWorld
{ {
Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); Ptr::CellStore *currentCell = mWorldScene->getCurrentCell();
Ogre::Vector3 playerPos; RefData &refdata = mPlayer->getPlayer().getRefData();
float* pos = mPlayer->getPlayer ().getRefData ().getPosition ().pos; Ogre::Vector3 playerPos(refdata.getPosition().pos);
playerPos.x = pos[0];
playerPos.y = pos[1];
playerPos.z = pos[2];
std::pair<bool, Ogre::Vector3> hit = const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle());
mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); if(!physactor->getOnGround() || isUnderwater(currentCell, playerPos))
bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false);
if (!isOnGround || isUnderwater (*currentCell->mCell, playerPos))
return 2; return 2;
if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep))
if (currentCell->mCell->mData.mFlags & ESM::Cell::NoSleep)
return 1; return 1;
return 0; return 0;
}
MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr)
{
return mRendering->getAnimation(ptr);
} }
void World::playVideo (const std::string &name, bool allowSkipping) void World::playVideo (const std::string &name, bool allowSkipping)

View file

@ -37,6 +37,7 @@ namespace MWRender
{ {
class SkyManager; class SkyManager;
class CellRender; class CellRender;
class Animation;
} }
namespace MWWorld namespace MWWorld
@ -264,8 +265,7 @@ namespace MWWorld
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const; virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const;
///< Convert position to cell numbers ///< Convert position to cell numbers
virtual void doPhysics (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors, virtual void doPhysics(const PtrMovementList &actors, float duration);
float duration);
///< Run physics simulation and modify \a world accordingly. ///< Run physics simulation and modify \a world accordingly.
virtual bool toggleCollisionMode(); virtual bool toggleCollisionMode();
@ -298,18 +298,6 @@ namespace MWWorld
/// \return pointer to created record /// \return pointer to created record
virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName,
int mode, int number = 1);
///< Run animation for a MW-reference. Calls to this function for references that are
/// currently not in the rendered scene should be ignored.
///
/// \param mode: 0 normal, 1 immediate start, 2 immediate loop
/// \param number How offen the animation should be run
virtual void skipAnimation (const MWWorld::Ptr& ptr);
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
/// references that are currently not in the rendered scene should be ignored.
virtual void update (float duration, bool paused); virtual void update (float duration, bool paused);
virtual bool placeObject (const Ptr& object, float cursorX, float cursorY); virtual bool placeObject (const Ptr& object, float cursorX, float cursorY);
@ -326,8 +314,10 @@ namespace MWWorld
virtual void processChangedSettings(const Settings::CategorySettingVector& settings); virtual void processChangedSettings(const Settings::CategorySettingVector& settings);
virtual bool isSwimming(const MWWorld::Ptr &object); virtual bool isFlying(const MWWorld::Ptr &ptr) const;
virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos); virtual bool isSwimming(const MWWorld::Ptr &object) const;
virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const;
virtual bool isOnGround(const MWWorld::Ptr &ptr) const;
virtual void togglePOV() { virtual void togglePOV() {
mRendering->togglePOV(); mRendering->togglePOV();
@ -360,6 +350,9 @@ namespace MWWorld
/// 2 - player is underwater \n /// 2 - player is underwater \n
/// 3 - enemies are nearby (not implemented) /// 3 - enemies are nearby (not implemented)
/// \todo Probably shouldn't be here
virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr);
/// \todo this does not belong here /// \todo this does not belong here
virtual void playVideo(const std::string& name, bool allowSkipping); virtual void playVideo(const std::string& name, bool allowSkipping);
virtual void stopVideo(); virtual void stopVideo();

Some files were not shown because too many files have changed in this diff Show more