forked from teamnwah/openmw-tes3coop
Merge branch 'master' into saveOnClose
This commit is contained in:
commit
9193ddc9d3
161 changed files with 4224 additions and 5385 deletions
|
@ -74,7 +74,6 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)
|
|||
set(OENGINE_OGRE
|
||||
${LIBDIR}/openengine/ogre/renderer.cpp
|
||||
${LIBDIR}/openengine/ogre/fader.cpp
|
||||
${LIBDIR}/openengine/ogre/imagerotate.cpp
|
||||
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
|
||||
)
|
||||
set(OENGINE_GUI
|
||||
|
@ -94,8 +93,6 @@ set(OENGINE_BULLET
|
|||
${LIBDIR}/openengine/bullet/physic.hpp
|
||||
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
|
||||
${LIBDIR}/openengine/bullet/BulletShapeLoader.h
|
||||
${LIBDIR}/openengine/bullet/pmove.cpp
|
||||
${LIBDIR}/openengine/bullet/pmove.h
|
||||
${LIBDIR}/openengine/bullet/trace.cpp
|
||||
${LIBDIR}/openengine/bullet/trace.h
|
||||
|
||||
|
@ -299,7 +296,7 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
|||
"${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
|
||||
"${OpenMW_BINARY_DIR}/openmw.desktop")
|
||||
endif()
|
||||
|
@ -380,7 +377,7 @@ if(WIN32)
|
|||
"${OpenMW_SOURCE_DIR}/readme.txt"
|
||||
"${OpenMW_SOURCE_DIR}/GPL3.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_BINARY_DIR}/launcher.qss"
|
||||
"${OpenMW_BINARY_DIR}/settings-default.cfg"
|
||||
|
@ -391,7 +388,7 @@ if(WIN32)
|
|||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
|
||||
|
||||
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_VERSION ${OPENMW_VERSION})
|
||||
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_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt")
|
||||
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_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
|
||||
SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe")
|
||||
|
@ -529,6 +526,8 @@ if (WIN32)
|
|||
set(WARNINGS "${WARNINGS} /wd${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})
|
||||
if (BUILD_LAUNCHER)
|
||||
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(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" )
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" )
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" )
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" )
|
||||
IF(BUILD_LAUNCHER)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" )
|
||||
ENDIF(BUILD_LAUNCHER)
|
||||
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(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(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)
|
||||
|
|
|
@ -20,6 +20,7 @@ void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_i
|
|||
getData().loadFile (*end2, false);
|
||||
|
||||
addOptionalGmsts();
|
||||
addOptionalGlobals();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
static const char *sGlobals[] =
|
||||
|
|
|
@ -20,6 +20,7 @@ class QAbstractItemModel;
|
|||
namespace ESM
|
||||
{
|
||||
struct GameSetting;
|
||||
struct Global;
|
||||
}
|
||||
|
||||
namespace CSMDoc
|
||||
|
@ -53,8 +54,12 @@ namespace CSMDoc
|
|||
|
||||
void addOptionalGmsts();
|
||||
|
||||
void addOptionalGlobals();
|
||||
|
||||
void addOptionalGmst (const ESM::GameSetting& gmst);
|
||||
|
||||
void addOptionalGlobal (const ESM::Global& global);
|
||||
|
||||
public:
|
||||
|
||||
Document (const std::vector<boost::filesystem::path>& files, bool new_);
|
||||
|
|
|
@ -171,7 +171,7 @@ namespace CSMWorld
|
|||
record2.mModified = record;
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -306,7 +306,7 @@ namespace CSMWorld
|
|||
void IdCollection<ESXRecordT>::appendRecord (const RecordBase& 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>
|
||||
|
|
|
@ -16,7 +16,7 @@ CSVDoc::Operations::Operations()
|
|||
|
||||
widgetContainer->setLayout (mLayout);
|
||||
setWidget (widgetContainer);
|
||||
|
||||
setVisible (false);
|
||||
setFixedHeight (widgetContainer->height());
|
||||
setTitleBarWidget (new QWidget (this));
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ void CSVDoc::Operations::setProgress (int current, int max, int type, int thread
|
|||
|
||||
if ( oldCount > 0)
|
||||
setFixedHeight (height()/oldCount * newCount);
|
||||
|
||||
setVisible (true);
|
||||
}
|
||||
|
||||
void CSVDoc::Operations::quitOperation (int type)
|
||||
|
@ -59,6 +61,8 @@ void CSVDoc::Operations::quitOperation (int type)
|
|||
|
||||
if (oldCount > 1)
|
||||
setFixedHeight (height() / oldCount * newCount);
|
||||
else
|
||||
setVisible (false);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -242,7 +242,6 @@ void CSVDoc::View::addGmstsSubView()
|
|||
void CSVDoc::View::abortOperation (int type)
|
||||
{
|
||||
mDocument->abortOperation (type);
|
||||
mOperations->quitOperation (type);
|
||||
updateActions();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ set(GAME_HEADER
|
|||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||
|
||||
add_openmw_dir (mwrender
|
||||
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
|
||||
renderinginterface localmap occlusionquery terrain terrainmaterial water shadows
|
||||
renderingmanager debugging sky player animation npcanimation creatureanimation activatoranimation
|
||||
actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows
|
||||
compositors characterpreview externalrendering globalmap videoplayer
|
||||
)
|
||||
|
||||
|
@ -26,11 +26,11 @@ add_openmw_dir (mwinput
|
|||
add_openmw_dir (mwgui
|
||||
text_input widgets race class birth review windowmanagerimp console dialogue
|
||||
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
|
||||
confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu
|
||||
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
|
||||
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow
|
||||
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor
|
||||
)
|
||||
|
||||
add_openmw_dir (mwdialogue
|
||||
|
@ -62,8 +62,9 @@ add_openmw_dir (mwclass
|
|||
)
|
||||
|
||||
add_openmw_dir (mwmechanics
|
||||
mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells
|
||||
activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate
|
||||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators
|
||||
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
||||
aiescort aiactivate
|
||||
)
|
||||
|
||||
add_openmw_dir (mwbase
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <components/bsa/bsa_archive.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/translation/translation.hpp>
|
||||
#include <components/nif/nif_file.hpp>
|
||||
#include <components/nifoverrides/nifoverrides.hpp>
|
||||
|
||||
#include <components/nifbullet/bullet_nif_loader.hpp>
|
||||
|
@ -17,7 +18,6 @@
|
|||
#include "mwinput/inputmanagerimp.hpp"
|
||||
|
||||
#include "mwgui/windowmanagerimp.hpp"
|
||||
#include "mwgui/cursorreplace.hpp"
|
||||
|
||||
#include "mwscript/scriptmanagerimp.hpp"
|
||||
#include "mwscript/extensions.hpp"
|
||||
|
@ -66,14 +66,15 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
{
|
||||
try
|
||||
{
|
||||
mEnvironment.setFrameDuration (evt.timeSinceLastFrame);
|
||||
float frametime = std::min(evt.timeSinceLastFrame, 0.2f);
|
||||
mEnvironment.setFrameDuration(frametime);
|
||||
|
||||
// update input
|
||||
MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame, false);
|
||||
MWBase::Environment::get().getInputManager()->update(frametime, false);
|
||||
|
||||
// sound
|
||||
if (mUseSound)
|
||||
MWBase::Environment::get().getSoundManager()->update (evt.timeSinceLastFrame);
|
||||
MWBase::Environment::get().getSoundManager()->update(frametime);
|
||||
|
||||
// global scripts
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||
|
@ -87,23 +88,19 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
|
||||
// passing of time
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
MWBase::Environment::get().getWorld()->advanceTime (
|
||||
mEnvironment.getFrameDuration()*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
|
||||
MWBase::Environment::get().getWorld()->advanceTime(
|
||||
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
|
||||
|
||||
|
||||
if (changed) // keep change flag for another frame, if cell changed happend in local script
|
||||
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||
|
||||
// update actors
|
||||
std::vector<std::pair<std::string, Ogre::Vector3> > movement;
|
||||
MWBase::Environment::get().getMechanicsManager()->update (movement, mEnvironment.getFrameDuration(),
|
||||
MWBase::Environment::get().getMechanicsManager()->update(frametime,
|
||||
MWBase::Environment::get().getWindowManager()->isGuiMode());
|
||||
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
MWBase::Environment::get().getWorld()->doPhysics (movement, mEnvironment.getFrameDuration());
|
||||
|
||||
// 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
|
||||
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().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch);
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->onFrame(evt.timeSinceLastFrame);
|
||||
MWBase::Environment::get().getWindowManager()->onFrame(frametime);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
@ -335,9 +332,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
|
||||
loadBSA();
|
||||
|
||||
// cursor replacer (converts the cursor from the bsa so they can be used by mygui)
|
||||
MWGui::CursorReplace replacer;
|
||||
|
||||
// Create the world
|
||||
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins,
|
||||
mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap,
|
||||
|
|
|
@ -37,24 +37,24 @@ namespace MWBase
|
|||
|
||||
virtual ~MechanicsManager() {}
|
||||
|
||||
virtual void addActor (const MWWorld::Ptr& ptr) = 0;
|
||||
///< Register an actor for stats management
|
||||
///
|
||||
/// \note Dead actors are ignored.
|
||||
virtual void add (const MWWorld::Ptr& ptr) = 0;
|
||||
///< Register an object for management
|
||||
|
||||
virtual void removeActor (const MWWorld::Ptr& ptr) = 0;
|
||||
///< Deregister an actor for stats management
|
||||
virtual void remove (const MWWorld::Ptr& ptr) = 0;
|
||||
///< Deregister an object for management
|
||||
|
||||
virtual void dropActors (const MWWorld::CellStore *cellStore) = 0;
|
||||
///< Deregister all actors in the given cell.
|
||||
virtual void updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) = 0;
|
||||
///< 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;
|
||||
///< On each update look for changes in a previously registered actor and update the
|
||||
/// GUI accordingly.
|
||||
|
||||
virtual void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement,
|
||||
float duration, bool paused) = 0;
|
||||
///< Update actor stats and store desired velocity vectors in \a movement
|
||||
virtual void update (float duration, bool paused) = 0;
|
||||
///< Update objects
|
||||
///
|
||||
/// \param paused In game type does not currently advance (this usually means some GUI
|
||||
/// component is up).
|
||||
|
@ -98,6 +98,17 @@ namespace MWBase
|
|||
virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type,
|
||||
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0;
|
||||
///< 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.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ namespace MWBase
|
|||
virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0;
|
||||
///< 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 int readPressedButton() = 0;
|
||||
///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include "../mwworld/globals.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
|
@ -19,6 +20,11 @@ namespace OEngine
|
|||
{
|
||||
class Fader;
|
||||
}
|
||||
|
||||
namespace Physic
|
||||
{
|
||||
class PhysicEngine;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ESM
|
||||
|
@ -35,6 +41,7 @@ namespace ESM
|
|||
namespace MWRender
|
||||
{
|
||||
class ExternalRendering;
|
||||
class Animation;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -42,10 +49,11 @@ namespace MWWorld
|
|||
class CellStore;
|
||||
class Player;
|
||||
class LocalScripts;
|
||||
class Ptr;
|
||||
class TimeStamp;
|
||||
class ESMStore;
|
||||
class RefData;
|
||||
|
||||
typedef std::vector<std::pair<MWWorld::Ptr,Ogre::Vector3> > PtrMovementList;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
|
@ -227,8 +235,7 @@ namespace MWBase
|
|||
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0;
|
||||
///< Convert position to cell numbers
|
||||
|
||||
virtual void doPhysics (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors,
|
||||
float duration) = 0;
|
||||
virtual void doPhysics (const MWWorld::PtrMovementList &actors, float duration) = 0;
|
||||
///< Run physics simulation and modify \a world accordingly.
|
||||
|
||||
virtual bool toggleCollisionMode() = 0;
|
||||
|
@ -263,18 +270,6 @@ namespace MWBase
|
|||
///< Create a new recrod (of type npc) in the ESM store.
|
||||
/// \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 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 bool isSwimming(const MWWorld::Ptr &object) = 0;
|
||||
virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) = 0;
|
||||
virtual bool isFlying(const MWWorld::Ptr &ptr) const = 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 togglePreviewMode(bool enable) = 0;
|
||||
|
@ -311,6 +308,8 @@ namespace MWBase
|
|||
/// 2 - player is underwater \n
|
||||
/// 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
|
||||
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld//cellstore.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
#include "../mwrender/actors.hpp"
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
@ -21,9 +22,8 @@ namespace MWClass
|
|||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
MWRender::Objects& objects = renderingInterface.getObjects();
|
||||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
objects.insertMesh(ptr, model);
|
||||
MWRender::Actors& actors = renderingInterface.getActors();
|
||||
actors.insertActivator(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ namespace MWClass
|
|||
const std::string model = getModel(ptr);
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||
}
|
||||
|
||||
std::string Activator::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "../mwworld/physicssystem.hpp"
|
||||
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
#include "../mwrender/actors.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
|
@ -96,7 +97,7 @@ namespace MWClass
|
|||
const std::string model = getModel(ptr);
|
||||
if(!model.empty())
|
||||
physics.addActor(ptr);
|
||||
MWBase::Environment::get().getMechanicsManager()->addActor (ptr);
|
||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||
}
|
||||
|
||||
std::string Creature::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#ifndef GAME_MWCLASS_CREATURE_H
|
||||
#define GAME_MWCLASS_CREATURE_H
|
||||
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
#include "../mwrender/actors.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
|
|
@ -36,14 +36,9 @@ namespace MWClass
|
|||
objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false);
|
||||
|
||||
if (!model.empty())
|
||||
objects.insertMesh(ptr, "meshes\\" + model);
|
||||
|
||||
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);
|
||||
objects.insertLight (ptr, r, g, b, radius);
|
||||
objects.insertMesh(ptr, "meshes\\" + model, true);
|
||||
else
|
||||
objects.insertLight(ptr);
|
||||
}
|
||||
|
||||
void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
|
|
|
@ -55,9 +55,35 @@ namespace MWClass
|
|||
{
|
||||
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())
|
||||
{
|
||||
std::auto_ptr<CustomData> data (new CustomData);
|
||||
std::auto_ptr<CustomData> data(new CustomData);
|
||||
|
||||
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
|
||||
{
|
||||
physics.addActor(ptr);
|
||||
MWBase::Environment::get().getMechanicsManager()->addActor(ptr);
|
||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||
}
|
||||
|
||||
std::string Npc::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
@ -297,9 +323,88 @@ namespace MWClass
|
|||
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
|
||||
|
@ -311,14 +416,10 @@ namespace MWClass
|
|||
|
||||
Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
Ogre::Vector3 vector (0, 0, 0);
|
||||
|
||||
vector.x = getMovementSettings (ptr).mLeftRight * 127;
|
||||
vector.y = getMovementSettings (ptr).mForwardBackward * 127;
|
||||
vector.z = getMovementSettings(ptr).mUpDown * 127;
|
||||
|
||||
//if (getStance (ptr, Run, false))
|
||||
// vector *= 2;
|
||||
Ogre::Vector3 vector;
|
||||
vector.x = getMovementSettings(ptr).mLeftRight;
|
||||
vector.y = getMovementSettings(ptr).mForwardBackward;
|
||||
vector.z = getMovementSettings(ptr).mUpDown;
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
@ -420,4 +521,21 @@ namespace MWClass
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class GameSetting;
|
||||
}
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
class Npc : public MWWorld::Class
|
||||
|
@ -12,6 +17,23 @@ namespace MWClass
|
|||
virtual MWWorld::Ptr
|
||||
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:
|
||||
|
||||
virtual std::string getId (const MWWorld::Ptr& ptr) const;
|
||||
|
@ -64,6 +86,9 @@ namespace MWClass
|
|||
virtual float getSpeed (const MWWorld::Ptr& ptr) const;
|
||||
///< 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;
|
||||
///< Return desired movement.
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "dialoguemanagerimp.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
|
@ -251,8 +252,12 @@ namespace MWDialogue
|
|||
|
||||
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);
|
||||
|
||||
if (dialogue.mType==ESM::Dialogue::Persuasion)
|
||||
|
|
|
@ -289,7 +289,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
|
|||
|
||||
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:
|
||||
{
|
||||
|
@ -559,8 +559,21 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo
|
|||
: 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;
|
||||
|
||||
// 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 (testDisposition (*iter))
|
||||
return &*iter;
|
||||
if (testDisposition (*iter)) {
|
||||
infos.push_back(&*iter);
|
||||
if (!searchAll)
|
||||
break;
|
||||
}
|
||||
else
|
||||
infoRefusal = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (infoRefusal && fallbackToInfoRefusal)
|
||||
if (infos.empty() && infoRefusal && fallbackToInfoRefusal)
|
||||
{
|
||||
// No response is valid because of low NPC disposition,
|
||||
// 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();
|
||||
iter!=infoRefusalDialogue.mInfo.end(); ++iter)
|
||||
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter))
|
||||
return &*iter;
|
||||
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) {
|
||||
infos.push_back(&*iter);
|
||||
if (!searchAll)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return infos;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef GAME_MWDIALOGUE_FILTER_H
|
||||
#define GAME_MWDIALOGUE_FILTER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace ESM
|
||||
|
@ -51,7 +53,10 @@ namespace MWDialogue
|
|||
|
||||
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.
|
||||
/// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition.
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ bool sortBirthSigns(const std::pair<std::string, const ESM::BirthSign*>& left, c
|
|||
}
|
||||
|
||||
BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_chargen_birth.layout", parWindowManager)
|
||||
: WindowModal("openmw_chargen_birth.layout", parWindowManager)
|
||||
{
|
||||
// Centre dialog
|
||||
center();
|
||||
|
@ -66,7 +66,7 @@ void BirthDialog::setNextButtonShow(bool shown)
|
|||
|
||||
void BirthDialog::open()
|
||||
{
|
||||
WindowBase::open();
|
||||
WindowModal::open();
|
||||
updateBirths();
|
||||
updateSpells();
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
class BirthDialog : public WindowBase
|
||||
class BirthDialog : public WindowModal
|
||||
{
|
||||
public:
|
||||
BirthDialog(MWBase::WindowManager& parWindowManager);
|
||||
|
|
|
@ -21,7 +21,7 @@ using namespace MWGui;
|
|||
/* GenerateClassResultDialog */
|
||||
|
||||
GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_chargen_generate_class_result.layout", parWindowManager)
|
||||
: WindowModal("openmw_chargen_generate_class_result.layout", parWindowManager)
|
||||
{
|
||||
// Centre dialog
|
||||
center();
|
||||
|
@ -68,7 +68,7 @@ void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender)
|
|||
/* PickClassDialog */
|
||||
|
||||
PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_chargen_class.layout", parWindowManager)
|
||||
: WindowModal("openmw_chargen_class.layout", parWindowManager)
|
||||
{
|
||||
// Centre dialog
|
||||
center();
|
||||
|
@ -122,6 +122,7 @@ void PickClassDialog::setNextButtonShow(bool shown)
|
|||
|
||||
void PickClassDialog::open()
|
||||
{
|
||||
WindowModal::open ();
|
||||
updateClasses();
|
||||
updateStats();
|
||||
}
|
||||
|
@ -276,7 +277,7 @@ void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin)
|
|||
}
|
||||
|
||||
InfoBoxDialog::InfoBoxDialog(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_infobox.layout", parWindowManager)
|
||||
: WindowModal("openmw_infobox.layout", parWindowManager)
|
||||
, mCurrentButton(-1)
|
||||
{
|
||||
getWidget(mTextBox, "TextBox");
|
||||
|
@ -327,6 +328,7 @@ void InfoBoxDialog::setButtons(ButtonList &buttons)
|
|||
|
||||
void InfoBoxDialog::open()
|
||||
{
|
||||
WindowModal::open();
|
||||
// Fix layout
|
||||
layoutVertically(mTextBox, 4);
|
||||
layoutVertically(mButtonBar, 6);
|
||||
|
@ -373,7 +375,7 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager)
|
|||
/* CreateClassDialog */
|
||||
|
||||
CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_chargen_create_class.layout", parWindowManager)
|
||||
: WindowModal("openmw_chargen_create_class.layout", parWindowManager)
|
||||
, mSpecDialog(nullptr)
|
||||
, mAttribDialog(nullptr)
|
||||
, mSkillDialog(nullptr)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
class InfoBoxDialog : public WindowBase
|
||||
class InfoBoxDialog : public WindowModal
|
||||
{
|
||||
public:
|
||||
InfoBoxDialog(MWBase::WindowManager& parWindowManager);
|
||||
|
@ -63,7 +63,7 @@ namespace MWGui
|
|||
ClassChoiceDialog(MWBase::WindowManager& parWindowManager);
|
||||
};
|
||||
|
||||
class GenerateClassResultDialog : public WindowBase
|
||||
class GenerateClassResultDialog : public WindowModal
|
||||
{
|
||||
public:
|
||||
GenerateClassResultDialog(MWBase::WindowManager& parWindowManager);
|
||||
|
@ -90,7 +90,7 @@ namespace MWGui
|
|||
std::string mCurrentClassId;
|
||||
};
|
||||
|
||||
class PickClassDialog : public WindowBase
|
||||
class PickClassDialog : public WindowModal
|
||||
{
|
||||
public:
|
||||
PickClassDialog(MWBase::WindowManager& parWindowManager);
|
||||
|
@ -238,7 +238,7 @@ namespace MWGui
|
|||
MyGUI::EditPtr mTextEdit;
|
||||
};
|
||||
|
||||
class CreateClassDialog : public WindowBase
|
||||
class CreateClassDialog : public WindowModal
|
||||
{
|
||||
public:
|
||||
CreateClassDialog(MWBase::WindowManager& parWindowManager);
|
||||
|
|
130
apps/openmw/mwgui/cursor.cpp
Normal file
130
apps/openmw/mwgui/cursor.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
62
apps/openmw/mwgui/cursor.hpp
Normal file
62
apps/openmw/mwgui/cursor.hpp
Normal 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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -106,7 +106,7 @@ namespace MWGui
|
|||
float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading);
|
||||
assert(progress <= 1 && progress >= 0);
|
||||
|
||||
mLoadingText->setCaption(stage + "... ");
|
||||
mLoadingText->setCaption(stage);
|
||||
mProgressBar->setProgressPosition (static_cast<size_t>(progress * 1000));
|
||||
|
||||
static float loadingScreenFps = 30.f;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
@ -65,6 +66,7 @@ namespace MWGui
|
|||
|
||||
void MainMenu::onButtonClicked(MyGUI::Widget *sender)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
|
||||
if (sender == mButtons["return"])
|
||||
MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu);
|
||||
else if (sender == mButtons["options"])
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <OgreTextureManager.h>
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include <MyGUI_Gui.h>
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -13,6 +15,8 @@
|
|||
|
||||
#include "../mwrender/globalmap.hpp"
|
||||
|
||||
#include "widgets.hpp"
|
||||
|
||||
using namespace MWGui;
|
||||
|
||||
LocalMapBase::LocalMapBase()
|
||||
|
@ -88,7 +92,7 @@ void LocalMapBase::applyFogOfWar()
|
|||
+ boost::lexical_cast<std::string>(my);
|
||||
|
||||
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];
|
||||
fog->setImageTexture(mFogOfWar ?
|
||||
((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)
|
||||
|
@ -127,7 +132,7 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior)
|
|||
{
|
||||
// map
|
||||
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) + "_"
|
||||
+ boost::lexical_cast<std::string>(my);
|
||||
|
@ -173,7 +178,7 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior)
|
|||
}
|
||||
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);
|
||||
|
||||
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::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;
|
||||
mGlobalMapRender->worldPosToImageSpace (pos.x, pos.z, worldX, worldY);
|
||||
mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY);
|
||||
worldX *= mGlobalMapRender->getWidth();
|
||||
worldY *= mGlobalMapRender->getHeight();
|
||||
|
||||
|
@ -425,3 +430,17 @@ void MapWindow::notifyPlayerUpdate ()
|
|||
{
|
||||
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}");
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace MWGui
|
|||
void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2);
|
||||
|
||||
virtual void notifyPlayerUpdate() {}
|
||||
virtual void notifyMapChanged() {}
|
||||
|
||||
OEngine::GUI::Layout* mLayout;
|
||||
|
||||
|
@ -99,6 +100,8 @@ namespace MWGui
|
|||
virtual void onPinToggled();
|
||||
|
||||
virtual void notifyPlayerUpdate();
|
||||
virtual void notifyMapChanged();
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "messagebox.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
||||
using namespace MWGui;
|
||||
|
||||
|
@ -375,6 +377,7 @@ void InteractiveMessageBox::enterPressed()
|
|||
if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok)
|
||||
{
|
||||
buttonActivated(*button);
|
||||
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ using namespace MWGui;
|
|||
using namespace Widgets;
|
||||
|
||||
RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_chargen_race.layout", parWindowManager)
|
||||
: WindowModal("openmw_chargen_race.layout", parWindowManager)
|
||||
, mGenderIndex(0)
|
||||
, mFaceIndex(0)
|
||||
, mHairIndex(0)
|
||||
|
@ -61,7 +61,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager)
|
|||
prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair);
|
||||
nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair);
|
||||
|
||||
setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu4", "Race"));
|
||||
setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu5", "Race"));
|
||||
getWidget(mRaceList, "RaceList");
|
||||
mRaceList->setScrollVisible(true);
|
||||
mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
|
||||
|
@ -100,6 +100,8 @@ void RaceDialog::setNextButtonShow(bool shown)
|
|||
|
||||
void RaceDialog::open()
|
||||
{
|
||||
WindowModal::open();
|
||||
|
||||
updateRaces();
|
||||
updateSkills();
|
||||
updateSpellPowers();
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace MWGui
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
class RaceDialog : public WindowBase
|
||||
class RaceDialog : public WindowModal
|
||||
{
|
||||
public:
|
||||
RaceDialog(MWBase::WindowManager& parWindowManager);
|
||||
|
|
|
@ -23,7 +23,7 @@ using namespace Widgets;
|
|||
const int ReviewDialog::sLineHeight = 18;
|
||||
|
||||
ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_chargen_review.layout", parWindowManager)
|
||||
: WindowModal("openmw_chargen_review.layout", parWindowManager)
|
||||
, mLastPos(0)
|
||||
{
|
||||
// Centre dialog
|
||||
|
@ -97,6 +97,7 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager)
|
|||
|
||||
void ReviewDialog::open()
|
||||
{
|
||||
WindowModal::open();
|
||||
updateSkillArea();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ Layout is defined by resources/mygui/openmw_chargen_review.layout.
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
class ReviewDialog : public WindowBase
|
||||
class ReviewDialog : public WindowModal
|
||||
{
|
||||
public:
|
||||
enum Dialogs {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
using namespace MWGui;
|
||||
|
||||
TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_text_input.layout", parWindowManager)
|
||||
: WindowModal("openmw_text_input.layout", parWindowManager)
|
||||
{
|
||||
// Centre dialog
|
||||
center();
|
||||
|
@ -39,6 +39,7 @@ void TextInputDialog::setTextLabel(const std::string &label)
|
|||
|
||||
void TextInputDialog::open()
|
||||
{
|
||||
WindowModal::open();
|
||||
// Make sure the edit box has focus
|
||||
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace MWGui
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
class TextInputDialog : public WindowBase
|
||||
class TextInputDialog : public WindowModal
|
||||
{
|
||||
public:
|
||||
TextInputDialog(MWBase::WindowManager& parWindowManager);
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
#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
|
||||
{
|
||||
const float TradeWindow::sBalanceChangeInitialPause = 0.5;
|
||||
const float TradeWindow::sBalanceChangeInterval = 0.1;
|
||||
|
||||
TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) :
|
||||
WindowBase("openmw_trade_window.layout", parWindowManager)
|
||||
, ContainerBase(NULL) // no drag&drop
|
||||
|
@ -157,7 +157,7 @@ namespace MWGui
|
|||
|
||||
mBalanceChangePause -= frameDuration;
|
||||
if (mBalanceChangePause < 0.0) {
|
||||
mBalanceChangePause += BALANCE_CHANGE_INTERVAL;
|
||||
mBalanceChangePause += sBalanceChangeInterval;
|
||||
if (mBalanceButtonsState == BBS_Increase)
|
||||
onIncreaseButtonTriggered();
|
||||
else if (mBalanceButtonsState == BBS_Decrease)
|
||||
|
@ -296,14 +296,14 @@ namespace MWGui
|
|||
void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
|
||||
{
|
||||
mBalanceButtonsState = BBS_Increase;
|
||||
mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE;
|
||||
mBalanceChangePause = sBalanceChangeInitialPause;
|
||||
onIncreaseButtonTriggered();
|
||||
}
|
||||
|
||||
void TradeWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
|
||||
{
|
||||
mBalanceButtonsState = BBS_Decrease;
|
||||
mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE;
|
||||
mBalanceChangePause = sBalanceChangeInitialPause;
|
||||
onDecreaseButtonTriggered();
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@ namespace MWGui
|
|||
void onFrame(float frameDuration);
|
||||
|
||||
protected:
|
||||
static const float sBalanceChangeInitialPause; // in seconds
|
||||
static const float sBalanceChangeInterval; // in seconds
|
||||
|
||||
MyGUI::Button* mFilterAll;
|
||||
MyGUI::Button* mFilterWeapon;
|
||||
MyGUI::Button* mFilterApparel;
|
||||
|
|
|
@ -95,31 +95,46 @@ namespace MWGui
|
|||
// http://www.uesp.net/wiki/Lore:Calendar
|
||||
std::string month;
|
||||
int m = MWBase::Environment::get().getWorld ()->getMonth ();
|
||||
if (m == 0)
|
||||
month = "#{sMonthMorningstar}";
|
||||
else if (m == 1)
|
||||
month = "#{sMonthSunsdawn}";
|
||||
else if (m == 2)
|
||||
month = "#{sMonthFirstseed}";
|
||||
else if (m == 3)
|
||||
month = "#{sMonthRainshand}";
|
||||
else if (m == 4)
|
||||
month = "#{sMonthSecondseed}";
|
||||
else if (m == 5)
|
||||
month = "#{sMonthMidyear}";
|
||||
else if (m == 6)
|
||||
month = "#{sMonthSunsheight}";
|
||||
else if (m == 7)
|
||||
month = "#{sMonthLastseed}";
|
||||
else if (m == 8)
|
||||
month = "#{sMonthHeartfire}";
|
||||
else if (m == 9)
|
||||
month = "#{sMonthFrostfall}";
|
||||
else if (m == 10)
|
||||
month = "#{sMonthSunsdusk}";
|
||||
else if (m == 11)
|
||||
month = "#{sMonthEveningstar}";
|
||||
|
||||
switch (m) {
|
||||
case 0:
|
||||
month = "#{sMonthMorningstar}";
|
||||
break;
|
||||
case 1:
|
||||
month = "#{sMonthSunsdawn}";
|
||||
break;
|
||||
case 2:
|
||||
month = "#{sMonthFirstseed}";
|
||||
break;
|
||||
case 3:
|
||||
month = "#{sMonthRainshand}";
|
||||
break;
|
||||
case 4:
|
||||
month = "#{sMonthSecondseed}";
|
||||
break;
|
||||
case 5:
|
||||
month = "#{sMonthMidyear}";
|
||||
break;
|
||||
case 6:
|
||||
month = "#{sMonthSunsheight}";
|
||||
break;
|
||||
case 7:
|
||||
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 ();
|
||||
bool pm = hour >= 12;
|
||||
if (hour >= 13) hour -= 12;
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "trainingwindow.hpp"
|
||||
#include "imagebutton.hpp"
|
||||
#include "exposedwindow.hpp"
|
||||
#include "cursor.hpp"
|
||||
|
||||
using namespace MWGui;
|
||||
|
||||
|
@ -130,6 +131,9 @@ WindowManager::WindowManager(
|
|||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ImageButton>("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);
|
||||
|
||||
// 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","");
|
||||
|
||||
mCursor = new Cursor();
|
||||
|
||||
// The HUD is always on
|
||||
mHud->setVisible(true);
|
||||
|
||||
|
@ -236,6 +242,7 @@ WindowManager::~WindowManager()
|
|||
delete mTrainingWindow;
|
||||
delete mCountDialog;
|
||||
delete mQuickKeysMenu;
|
||||
delete mCursor;
|
||||
|
||||
cleanupGarbage();
|
||||
|
||||
|
@ -262,6 +269,8 @@ void WindowManager::update()
|
|||
mHud->setFPS(mFPS);
|
||||
mHud->setTriangleCount(mTriangleCount);
|
||||
mHud->setBatchCount(mBatchCount);
|
||||
|
||||
mCursor->update();
|
||||
}
|
||||
|
||||
void WindowManager::updateVisible()
|
||||
|
@ -293,7 +302,7 @@ void WindowManager::updateVisible()
|
|||
mHud->setVisible(true);
|
||||
|
||||
// Mouse is visible whenever we're not in game mode
|
||||
MyGUI::PointerManager::getInstance().setVisible(isGuiMode());
|
||||
mCursor->setVisible(isGuiMode());
|
||||
|
||||
bool gameMode = !isGuiMode();
|
||||
|
||||
|
@ -421,13 +430,19 @@ void WindowManager::updateVisible()
|
|||
break;
|
||||
case GM_LoadingWallpaper:
|
||||
mHud->setVisible(false);
|
||||
MyGUI::PointerManager::getInstance().setVisible(false);
|
||||
mCursor->setVisible(false);
|
||||
break;
|
||||
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;
|
||||
case GM_Video:
|
||||
MyGUI::PointerManager::getInstance().setVisible(false);
|
||||
mCursor->setVisible(false);
|
||||
mHud->setVisible(false);
|
||||
break;
|
||||
default:
|
||||
|
@ -749,7 +764,7 @@ void WindowManager::setSpellVisibility(bool visible)
|
|||
|
||||
void WindowManager::setMouseVisible(bool visible)
|
||||
{
|
||||
MyGUI::PointerManager::getInstance().setVisible(visible);
|
||||
mCursor->setVisible(visible);
|
||||
}
|
||||
|
||||
void WindowManager::setDragDrop(bool dragDrop)
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace MWGui
|
|||
class SpellCreationDialog;
|
||||
class EnchantingDialog;
|
||||
class TrainingWindow;
|
||||
class Cursor;
|
||||
|
||||
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 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 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;
|
||||
TrainingWindow* mTrainingWindow;
|
||||
Translation::Storage& mTranslationDataStorage;
|
||||
Cursor* mCursor;
|
||||
|
||||
CharacterCreation* mCharGen;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "../engine.hpp"
|
||||
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
@ -51,6 +52,7 @@ namespace MWInput
|
|||
, mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input"))
|
||||
, mPreviewPOVDelay(0.f)
|
||||
, mTimeIdle(0.f)
|
||||
, mOverencumberedMessageDelay(0.f)
|
||||
{
|
||||
Ogre::RenderWindow* window = ogre.getWindow ();
|
||||
size_t windowHnd;
|
||||
|
@ -85,10 +87,12 @@ namespace MWInput
|
|||
std::string("false")));
|
||||
pl.insert(std::make_pair(std::string("x11_keyboard_grab"),
|
||||
std::string("false")));
|
||||
pl.insert(std::make_pair(std::string("XAutoRepeatOn"),
|
||||
std::string("true")));
|
||||
#endif
|
||||
}
|
||||
#if defined OIS_LINUX_PLATFORM
|
||||
pl.insert(std::make_pair(std::string("XAutoRepeatOn"),
|
||||
std::string("true")));
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && !defined(__LP64__)
|
||||
// Give the application window focus to receive input events
|
||||
|
@ -175,6 +179,11 @@ namespace MWInput
|
|||
case A_Activate:
|
||||
resetIdleTime();
|
||||
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;
|
||||
case A_Journal:
|
||||
toggleJournal ();
|
||||
|
@ -268,26 +277,29 @@ namespace MWInput
|
|||
// be done in the physics system.
|
||||
if (mControlSwitch["playercontrols"])
|
||||
{
|
||||
bool triedToMove = false;
|
||||
if (actionIsActive(A_MoveLeft))
|
||||
{
|
||||
mPlayer.setAutoMove (false);
|
||||
mPlayer.setLeftRight (1);
|
||||
triedToMove = true;
|
||||
mPlayer.setLeftRight (-1);
|
||||
}
|
||||
else if (actionIsActive(A_MoveRight))
|
||||
{
|
||||
mPlayer.setAutoMove (false);
|
||||
mPlayer.setLeftRight (-1);
|
||||
triedToMove = true;
|
||||
mPlayer.setLeftRight (1);
|
||||
}
|
||||
else
|
||||
mPlayer.setLeftRight (0);
|
||||
|
||||
if (actionIsActive(A_MoveForward))
|
||||
{
|
||||
triedToMove = true;
|
||||
mPlayer.setAutoMove (false);
|
||||
mPlayer.setForwardBackward (1);
|
||||
}
|
||||
else if (actionIsActive(A_MoveBackward))
|
||||
{
|
||||
triedToMove = true;
|
||||
mPlayer.setAutoMove (false);
|
||||
mPlayer.setForwardBackward (-1);
|
||||
}
|
||||
|
@ -295,12 +307,35 @@ namespace MWInput
|
|||
mPlayer.setForwardBackward (0);
|
||||
|
||||
if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"])
|
||||
{
|
||||
mPlayer.setUpDown (1);
|
||||
triedToMove = true;
|
||||
}
|
||||
else if (actionIsActive(A_Crouch))
|
||||
mPlayer.setUpDown (-1);
|
||||
else
|
||||
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"]) {
|
||||
|
||||
// work around preview mode toggle when pressing Alt+Tab
|
||||
|
@ -521,6 +556,9 @@ namespace MWInput
|
|||
|
||||
void InputManager::toggleMainMenu()
|
||||
{
|
||||
if (MyGUI::InputManager::getInstance ().isModalAny())
|
||||
return;
|
||||
|
||||
if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings))
|
||||
mWindows.popGuiMode();
|
||||
else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video)
|
||||
|
@ -599,6 +637,9 @@ namespace MWInput
|
|||
|
||||
void InputManager::toggleConsole()
|
||||
{
|
||||
if (MyGUI::InputManager::getInstance ().isModalAny())
|
||||
return;
|
||||
|
||||
bool gameMode = !mWindows.isGuiMode();
|
||||
|
||||
// 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_QuickKeysMenu] = OIS::KC_F1;
|
||||
defaultKeyBindings[A_Console] = OIS::KC_F2;
|
||||
defaultKeyBindings[A_Run] = OIS::KC_LSHIFT;
|
||||
defaultKeyBindings[A_Crouch] = OIS::KC_LCONTROL;
|
||||
defaultKeyBindings[A_AutoMove] = OIS::KC_Q;
|
||||
defaultKeyBindings[A_Jump] = OIS::KC_E;
|
||||
|
@ -771,6 +813,7 @@ namespace MWInput
|
|||
descriptions[A_ToggleWeapon] = "sReady_Weapon";
|
||||
descriptions[A_ToggleSpell] = "sReady_Magic";
|
||||
descriptions[A_Console] = "sConsoleTitle";
|
||||
descriptions[A_Run] = "sRun";
|
||||
descriptions[A_Crouch] = "sCrouch_Sneak";
|
||||
descriptions[A_AutoMove] = "sAuto_Run";
|
||||
descriptions[A_Jump] = "sJump";
|
||||
|
@ -819,6 +862,7 @@ namespace MWInput
|
|||
ret.push_back(A_MoveLeft);
|
||||
ret.push_back(A_MoveRight);
|
||||
ret.push_back(A_TogglePOV);
|
||||
ret.push_back(A_Run);
|
||||
ret.push_back(A_Crouch);
|
||||
ret.push_back(A_Activate);
|
||||
ret.push_back(A_ToggleWeapon);
|
||||
|
|
|
@ -145,6 +145,8 @@ namespace MWInput
|
|||
bool mMouseLookEnabled;
|
||||
bool mGuiCursorEnabled;
|
||||
|
||||
float mOverencumberedMessageDelay;
|
||||
|
||||
float mMouseX;
|
||||
float mMouseY;
|
||||
int mMouseWheel;
|
||||
|
@ -207,7 +209,7 @@ namespace MWInput
|
|||
A_Journal, //Journal
|
||||
A_Weapon, //Draw/Sheath weapon
|
||||
A_Spell, //Ready/Unready Casting
|
||||
A_AlwaysRun, //Toggle Always Run
|
||||
A_Run, //Run when held
|
||||
A_CycleSpellLeft, //cycling through spells
|
||||
A_CycleSpellRight,
|
||||
A_CycleWeaponLeft,//Cycling through weapons
|
||||
|
|
76
apps/openmw/mwmechanics/activators.cpp
Normal file
76
apps/openmw/mwmechanics/activators.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
45
apps/openmw/mwmechanics/activators.hpp
Normal file
45
apps/openmw/mwmechanics/activators.hpp
Normal 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
|
|
@ -165,35 +165,46 @@ namespace MWMechanics
|
|||
|
||||
void Actors::addActor (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead())
|
||||
mActors.insert (ptr);
|
||||
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
||||
if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead())
|
||||
mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true)));
|
||||
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)
|
||||
{
|
||||
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())
|
||||
mActors.erase (iter);
|
||||
void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
||||
{
|
||||
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)
|
||||
{
|
||||
std::set<MWWorld::Ptr>::iterator iter = mActors.begin();
|
||||
|
||||
while (iter!=mActors.end())
|
||||
if (iter->getCell()==cellStore)
|
||||
{
|
||||
mActors.erase (iter++);
|
||||
}
|
||||
PtrControllerMap::iterator iter = mActors.begin();
|
||||
while(iter != mActors.end())
|
||||
{
|
||||
if(iter->first.getCell()==cellStore)
|
||||
mActors.erase(iter++);
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement, float duration,
|
||||
bool paused)
|
||||
void Actors::update (float duration, bool paused)
|
||||
{
|
||||
mDuration += duration;
|
||||
|
||||
|
@ -201,79 +212,91 @@ namespace MWMechanics
|
|||
{
|
||||
float totalDuration = mDuration;
|
||||
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())
|
||||
updateNpc (*iter, totalDuration, paused);
|
||||
updateActor(iter->first, totalDuration);
|
||||
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
|
||||
// \todo remove workaround, once player death can be handled
|
||||
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);
|
||||
}
|
||||
MWMechanics::DynamicStat<float> stat (
|
||||
MWWorld::Class::get(iter->first).getCreatureStats(iter->first).getHealth());
|
||||
|
||||
MWWorld::Class::get (*iter).getCreatureStats (*iter).resurrect();
|
||||
++iter;
|
||||
continue;
|
||||
if (stat.getModified()<1)
|
||||
{
|
||||
stat.setModified (1, 0);
|
||||
MWWorld::Class::get(iter->first).getCreatureStats(iter->first).setHealth(stat);
|
||||
}
|
||||
|
||||
++mDeathCount[MWWorld::Class::get (*iter).getId (*iter)];
|
||||
|
||||
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++);
|
||||
MWWorld::Class::get(iter->first).getCreatureStats(iter->first).resurrect();
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
++iter)
|
||||
if(!paused)
|
||||
{
|
||||
Ogre::Vector3 vector = MWWorld::Class::get (*iter).getMovementVector (*iter);
|
||||
mMovement.reserve(mActors.size());
|
||||
|
||||
if (vector!=Ogre::Vector3::ZERO)
|
||||
movement.push_back (std::make_pair (iter->getRefData().getHandle(), vector));
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
{
|
||||
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()
|
||||
{
|
||||
for (std::set<MWWorld::Ptr>::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter)
|
||||
{
|
||||
calculateRestoration (*iter, 3600);
|
||||
}
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
calculateRestoration(iter->first, 3600);
|
||||
}
|
||||
|
||||
int Actors::countDeaths (const std::string& id) const
|
||||
{
|
||||
std::map<std::string, int>::const_iterator iter = mDeathCount.find (id);
|
||||
|
||||
if (iter!=mDeathCount.end())
|
||||
std::map<std::string, int>::const_iterator iter = mDeathCount.find(id);
|
||||
if(iter != mDeathCount.end())
|
||||
return iter->second;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "character.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
class Vector3;
|
||||
|
@ -21,9 +24,14 @@ namespace MWMechanics
|
|||
{
|
||||
class Actors
|
||||
{
|
||||
std::set<MWWorld::Ptr> mActors;
|
||||
float mDuration;
|
||||
std::map<std::string, int> mDeathCount;
|
||||
typedef std::map<MWWorld::Ptr,CharacterController> PtrControllerMap;
|
||||
PtrControllerMap mActors;
|
||||
|
||||
MWWorld::PtrMovementList mMovement;
|
||||
|
||||
std::map<std::string, int> mDeathCount;
|
||||
|
||||
float mDuration;
|
||||
|
||||
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.
|
||||
|
||||
void updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr);
|
||||
///< Updates an actor with a new Ptr
|
||||
|
||||
void dropActors (const MWWorld::CellStore *cellStore);
|
||||
///< Deregister all actors in the given cell.
|
||||
|
||||
void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement,
|
||||
float duration, bool paused);
|
||||
void update (float duration, bool paused);
|
||||
///< Update actor stats and store desired velocity vectors in \a movement
|
||||
|
||||
void updateActor (const MWWorld::Ptr& ptr, float duration);
|
||||
|
@ -66,6 +76,9 @@ namespace MWMechanics
|
|||
|
||||
int countDeaths (const std::string& id) const;
|
||||
///< 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);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
296
apps/openmw/mwmechanics/character.cpp
Normal file
296
apps/openmw/mwmechanics/character.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
96
apps/openmw/mwmechanics/character.hpp
Normal file
96
apps/openmw/mwmechanics/character.hpp
Normal 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 */
|
|
@ -175,34 +175,47 @@ namespace MWMechanics
|
|||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void MechanicsManager::update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement,
|
||||
float duration, bool paused)
|
||||
void MechanicsManager::update(float duration, bool paused)
|
||||
{
|
||||
if (!mWatched.isEmpty())
|
||||
{
|
||||
|
@ -296,9 +309,16 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
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()
|
||||
|
@ -471,8 +491,10 @@ namespace MWMechanics
|
|||
if(buying) x = buyTerm;
|
||||
else x = std::min(buyTerm, sellTerm);
|
||||
int offerPrice;
|
||||
if (x < 1) offerPrice = int(x * basePrice);
|
||||
if (x >= 1) offerPrice = basePrice + int((x - 1) * basePrice);
|
||||
if (x < 1)
|
||||
offerPrice = int(x * basePrice);
|
||||
else
|
||||
offerPrice = basePrice + int((x - 1) * basePrice);
|
||||
offerPrice = std::max(1, offerPrice);
|
||||
return offerPrice;
|
||||
}
|
||||
|
@ -535,7 +557,8 @@ namespace MWMechanics
|
|||
float fPerDieRollMult = gmst.find("fPerDieRollMult")->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;
|
||||
|
||||
|
@ -629,4 +652,20 @@ namespace MWMechanics
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "creaturestats.hpp"
|
||||
#include "npcstats.hpp"
|
||||
#include "activators.hpp"
|
||||
#include "actors.hpp"
|
||||
|
||||
namespace Ogre
|
||||
|
@ -29,6 +30,8 @@ namespace MWMechanics
|
|||
bool mUpdatePlayer;
|
||||
bool mClassSelected;
|
||||
bool mRaceSelected;
|
||||
|
||||
Activators mActivators;
|
||||
Actors mActors;
|
||||
|
||||
void buildPlayer();
|
||||
|
@ -39,24 +42,24 @@ namespace MWMechanics
|
|||
|
||||
MechanicsManager();
|
||||
|
||||
virtual void addActor (const MWWorld::Ptr& ptr);
|
||||
///< Register an actor for stats management
|
||||
///
|
||||
/// \note Dead actors are ignored.
|
||||
virtual void add (const MWWorld::Ptr& ptr);
|
||||
///< Register an object for management
|
||||
|
||||
virtual void removeActor (const MWWorld::Ptr& ptr);
|
||||
///< Deregister an actor for stats management
|
||||
virtual void remove (const MWWorld::Ptr& ptr);
|
||||
///< Deregister an object for management
|
||||
|
||||
virtual void dropActors (const MWWorld::CellStore *cellStore);
|
||||
///< Deregister all actors in the given cell.
|
||||
virtual void updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr);
|
||||
///< 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
|
||||
/// GUI accordingly.
|
||||
|
||||
virtual void update (std::vector<std::pair<std::string, Ogre::Vector3> >& movement,
|
||||
float duration, bool paused);
|
||||
///< Update actor stats and store desired velocity vectors in \a movement
|
||||
virtual void update (float duration, bool paused);
|
||||
///< Update objects
|
||||
///
|
||||
/// \param paused In game type does not currently advance (this usually means some GUI
|
||||
/// component is up).
|
||||
|
@ -92,6 +95,9 @@ namespace MWMechanics
|
|||
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange);
|
||||
void toLower(std::string npcFaction);
|
||||
///< 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);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
56
apps/openmw/mwrender/activatoranimation.cpp
Normal file
56
apps/openmw/mwrender/activatoranimation.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
21
apps/openmw/mwrender/activatoranimation.hpp
Normal file
21
apps/openmw/mwrender/activatoranimation.hpp
Normal 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
|
|
@ -3,14 +3,23 @@
|
|||
#include <OgreSceneNode.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"
|
||||
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
using namespace Ogre;
|
||||
|
||||
Actors::~Actors(){
|
||||
|
||||
Actors::~Actors()
|
||||
{
|
||||
PtrAnimationMap::iterator it = mAllActors.begin();
|
||||
for(;it != mAllActors.end();++it)
|
||||
{
|
||||
|
@ -19,18 +28,10 @@ Actors::~Actors(){
|
|||
}
|
||||
}
|
||||
|
||||
void Actors::setMwRoot(Ogre::SceneNode* root)
|
||||
{ mMwRoot = root; }
|
||||
void Actors::setRootNode(Ogre::SceneNode* root)
|
||||
{ mRootNode = root; }
|
||||
|
||||
void Actors::insertNPC(const MWWorld::Ptr &ptr, MWWorld::InventoryStore &inv)
|
||||
{
|
||||
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_)
|
||||
void Actors::insertBegin(const MWWorld::Ptr &ptr)
|
||||
{
|
||||
Ogre::SceneNode* cellnode;
|
||||
CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(ptr.getCell());
|
||||
|
@ -39,7 +40,7 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
|
|||
else
|
||||
{
|
||||
//Create the scenenode and put it in the map
|
||||
cellnode = mMwRoot->createChildSceneNode();
|
||||
cellnode = mRootNode->createChildSceneNode();
|
||||
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
|
||||
insert->setOrientation(xr*yr*zr);
|
||||
if (!enabled)
|
||||
insert->setVisible (false);
|
||||
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];
|
||||
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)
|
||||
{
|
||||
for(PtrAnimationMap::const_iterator iter = mAllActors.begin();iter != mAllActors.end();iter++)
|
||||
iter->second->runAnimation(duration);
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
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;
|
||||
MWWorld::CellStore *newCell = ptr.getCell();
|
||||
MWWorld::CellStore *newCell = cur.getCell();
|
||||
|
||||
CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell);
|
||||
if(celliter != mCellSceneNodes.end())
|
||||
node = celliter->second;
|
||||
else
|
||||
{
|
||||
node = mMwRoot->createChildSceneNode();
|
||||
node = mRootNode->createChildSceneNode();
|
||||
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())
|
||||
{
|
||||
/// \note Update key (Ptr's are compared only with refdata so mCell
|
||||
/// on key is outdated), maybe redundant
|
||||
Animation *anim = iter->second;
|
||||
mAllActors.erase(iter);
|
||||
mAllActors[ptr] = anim;
|
||||
anim->updatePtr(cur);
|
||||
mAllActors[cur] = anim;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
#ifndef _GAME_RENDER_ACTORS_H
|
||||
#define _GAME_RENDER_ACTORS_H
|
||||
|
||||
#include "npcanimation.hpp"
|
||||
#include "creatureanimation.hpp"
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Ptr;
|
||||
class CellStore;
|
||||
class InventoryStore;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class Animation;
|
||||
|
||||
class Actors
|
||||
{
|
||||
typedef std::map<MWWorld::CellStore*,Ogre::SceneNode*> CellSceneNodeMap;
|
||||
typedef std::map<MWWorld::Ptr,Animation*> PtrAnimationMap;
|
||||
|
||||
OEngine::Render::OgreRenderer &mRend;
|
||||
Ogre::SceneNode* mMwRoot;
|
||||
Ogre::SceneNode* mRootNode;
|
||||
|
||||
CellSceneNodeMap mCellSceneNodes;
|
||||
PtrAnimationMap mAllActors;
|
||||
|
||||
|
@ -26,31 +29,22 @@ namespace MWRender
|
|||
Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {}
|
||||
~Actors();
|
||||
|
||||
void setMwRoot(Ogre::SceneNode* root);
|
||||
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
||||
void insertCreature (const MWWorld::Ptr& ptr);
|
||||
void setRootNode(Ogre::SceneNode* root);
|
||||
void insertBegin (const MWWorld::Ptr& ptr);
|
||||
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);
|
||||
///< \return found?
|
||||
|
||||
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);
|
||||
|
||||
/// 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
|
||||
|
|
|
@ -1,148 +1,453 @@
|
|||
#include "animation.hpp"
|
||||
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreSkeletonManager.h>
|
||||
#include <OgreSkeletonInstance.h>
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreBone.h>
|
||||
#include <OgreSubMesh.h>
|
||||
#include <OgreSceneManager.h>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwmechanics/character.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
Animation::Animation()
|
||||
: mInsert(NULL)
|
||||
, mTime(0.0f)
|
||||
, mSkipFrame(false)
|
||||
Animation::Animation(const MWWorld::Ptr &ptr)
|
||||
: mPtr(ptr)
|
||||
, mController(NULL)
|
||||
, 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()
|
||||
{
|
||||
Ogre::SceneManager *sceneMgr = mInsert->getCreator();
|
||||
for(size_t i = 0;i < mEntityList.mEntities.size();i++)
|
||||
sceneMgr->destroyEntity(mEntityList.mEntities[i]);
|
||||
if(mInsert)
|
||||
{
|
||||
Ogre::SceneManager *sceneMgr = mInsert->getCreator();
|
||||
for(size_t i = 0;i < mEntityList.mEntities.size();i++)
|
||||
sceneMgr->destroyEntity(mEntityList.mEntities[i]);
|
||||
}
|
||||
mEntityList.mEntities.clear();
|
||||
mEntityList.mSkelBase = NULL;
|
||||
}
|
||||
|
||||
|
||||
struct checklow {
|
||||
bool operator()(const char &a, const char &b) const
|
||||
{
|
||||
return ::tolower(a) == ::tolower(b);
|
||||
}
|
||||
};
|
||||
|
||||
bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times)
|
||||
void Animation::setAnimationSources(const std::vector<std::string> &names)
|
||||
{
|
||||
const std::string &start = groupname+": start";
|
||||
const std::string &startloop = groupname+": loop start";
|
||||
const std::string &stop = groupname+": stop";
|
||||
const std::string &stoploop = groupname+": loop stop";
|
||||
if(!mEntityList.mSkelBase)
|
||||
return;
|
||||
|
||||
NifOgre::TextKeyMap::const_iterator iter;
|
||||
for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++)
|
||||
mCurrentAnim = NULL;
|
||||
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)
|
||||
return true;
|
||||
Ogre::SkeletonPtr skel = NifOgre::Loader::getSkeleton(*nameiter);
|
||||
if(skel.isNull())
|
||||
{
|
||||
std::cerr<< "Failed to get skeleton source "<<*nameiter <<std::endl;
|
||||
continue;
|
||||
}
|
||||
skel->touch();
|
||||
|
||||
std::string::const_iterator strpos = iter->second.begin();
|
||||
std::string::const_iterator strend = iter->second.end();
|
||||
size_t strlen = strend-strpos;
|
||||
Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator();
|
||||
while(boneiter.hasMoreElements())
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
times.mLoops = loops;
|
||||
|
||||
if(groupname == "all")
|
||||
for(std::vector<Ogre::SkeletonPtr>::const_iterator iter(mSkeletonSources.begin());iter != mSkeletonSources.end();iter++)
|
||||
{
|
||||
times.mStart = times.mLoopStart = 0.0f;
|
||||
times.mLoopStop = times.mStop = 0.0f;
|
||||
|
||||
NifOgre::TextKeyMap::const_reverse_iterator iter = mTextKeys.rbegin();
|
||||
if(iter != mTextKeys.rend())
|
||||
times.mLoopStop = times.mStop = iter->first;
|
||||
if((*iter)->hasAnimation(anim))
|
||||
return true;
|
||||
}
|
||||
else if(!findGroupTimes(groupname, ×))
|
||||
throw std::runtime_error("Failed to find animation group "+groupname);
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
mCurGroup = times;
|
||||
mNextGroup = GroupTimes();
|
||||
mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart);
|
||||
// No matching bone in the source. Make sure it stays properly offset
|
||||
// from its parent.
|
||||
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;
|
||||
if(mTime >= mCurGroup.mLoopStop)
|
||||
/* Get the non-accumulation root's difference from the last update. */
|
||||
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)
|
||||
{
|
||||
mCurGroup.mLoops--;
|
||||
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();
|
||||
}
|
||||
const Ogre::NodeAnimationTrack *cur = trackiter.getNext();
|
||||
if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName())
|
||||
track = cur;
|
||||
}
|
||||
|
||||
if(mEntityList.mSkelBase)
|
||||
if(track)
|
||||
{
|
||||
Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates();
|
||||
Ogre::AnimationStateIterator as = aset->getAnimationStateIterator();
|
||||
while(as.hasMoreElements())
|
||||
{
|
||||
Ogre::AnimationState *state = as.getNext();
|
||||
state->setTimePosition(mTime);
|
||||
}
|
||||
Ogre::TransformKeyFrame kf(0, mCurrentTime);
|
||||
track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf);
|
||||
mLastPosition = kf.getTranslate() * mAccumulate;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,55 +1,99 @@
|
|||
#ifndef _GAME_RENDER_ANIMATION_H
|
||||
#define _GAME_RENDER_ANIMATION_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#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 {
|
||||
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)
|
||||
{ }
|
||||
};
|
||||
|
||||
class Animation
|
||||
{
|
||||
protected:
|
||||
MWWorld::Ptr mPtr;
|
||||
MWMechanics::CharacterController *mController;
|
||||
|
||||
Ogre::SceneNode* mInsert;
|
||||
|
||||
float mTime;
|
||||
GroupTimes mCurGroup;
|
||||
GroupTimes mNextGroup;
|
||||
|
||||
bool mSkipFrame;
|
||||
|
||||
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:
|
||||
Animation();
|
||||
Animation(const MWWorld::Ptr &ptr);
|
||||
virtual ~Animation();
|
||||
|
||||
void playGroup(std::string groupname, int mode, int loops);
|
||||
void skipAnim();
|
||||
virtual void runAnimation(float timepassed);
|
||||
void setController(MWMechanics::CharacterController *controller);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "renderconst.hpp"
|
||||
#include "npcanimation.hpp"
|
||||
|
@ -120,7 +121,8 @@ namespace MWRender
|
|||
|
||||
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)));
|
||||
|
||||
|
@ -143,8 +145,7 @@ namespace MWRender
|
|||
{
|
||||
mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview);
|
||||
|
||||
mAnimation->playGroup ("inventoryhandtohand", 0, 1);
|
||||
mAnimation->runAnimation (0);
|
||||
mAnimation->play("inventoryhandtohand", "start", "stop", false);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
@ -160,6 +161,7 @@ namespace MWRender
|
|||
|
||||
void RaceSelectionPreview::update(float angle)
|
||||
{
|
||||
mAnimation->runAnimation(0.0f);
|
||||
mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL);
|
||||
|
||||
mNode->setVisible (true);
|
||||
|
@ -174,4 +176,9 @@ namespace MWRender
|
|||
rebuild();
|
||||
update(0);
|
||||
}
|
||||
|
||||
void RaceSelectionPreview::onSetup ()
|
||||
{
|
||||
mAnimation->play("idle", "start", "stop", false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,8 @@ namespace MWRender
|
|||
public:
|
||||
RaceSelectionPreview();
|
||||
|
||||
virtual void onSetup();
|
||||
|
||||
void update(float angle);
|
||||
|
||||
const ESM::NPC &getPrototype() const {
|
||||
|
|
|
@ -8,70 +8,54 @@
|
|||
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace NifOgre;
|
||||
namespace MWRender{
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
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 = ptr.get<ESM::Creature>();
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
||||
|
||||
assert (ref->mBase != NULL);
|
||||
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++)
|
||||
{
|
||||
Ogre::Entity *ent = mEntityList.mEntities[i];
|
||||
ent->setVisibilityFlags(RV_Actors);
|
||||
|
||||
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::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
|
||||
while (techIt.hasMoreElements() && !transparent)
|
||||
while(!transparent && techIt.hasMoreElements())
|
||||
{
|
||||
Ogre::Technique* tech = techIt.getNext();
|
||||
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
|
||||
while (passIt.hasMoreElements() && !transparent)
|
||||
while(!transparent && passIt.hasMoreElements())
|
||||
{
|
||||
Ogre::Pass* pass = passIt.getNext();
|
||||
|
||||
if (pass->getDepthWriteEnabled() == false)
|
||||
transparent = true;
|
||||
transparent = pass->isTransparent();
|
||||
}
|
||||
}
|
||||
}
|
||||
ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
|
||||
}
|
||||
|
||||
if(mEntityList.mSkelBase)
|
||||
{
|
||||
Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates();
|
||||
Ogre::AnimationStateIterator as = aset->getAnimationStateIterator();
|
||||
while(as.hasMoreElements())
|
||||
{
|
||||
Ogre::AnimationState *state = as.getNext();
|
||||
state->setEnabled(true);
|
||||
state->setLoop(false);
|
||||
}
|
||||
}
|
||||
std::vector<std::string> names;
|
||||
if((ref->mBase->mFlags&ESM::Creature::Biped))
|
||||
names.push_back("meshes\\base_anim.nif");
|
||||
names.push_back(model);
|
||||
setAnimationSources(names);
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureAnimation::runAnimation(float timepassed)
|
||||
{
|
||||
// Placeholder
|
||||
|
||||
Animation::runAnimation(timepassed);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,18 +3,19 @@
|
|||
|
||||
#include "animation.hpp"
|
||||
|
||||
#include "components/nifogre/ogre_nif_loader.hpp"
|
||||
namespace MWWorld
|
||||
{
|
||||
class Ptr;
|
||||
}
|
||||
|
||||
|
||||
namespace MWRender{
|
||||
|
||||
class CreatureAnimation: public Animation
|
||||
namespace MWRender
|
||||
{
|
||||
class CreatureAnimation : public Animation
|
||||
{
|
||||
public:
|
||||
virtual ~CreatureAnimation();
|
||||
CreatureAnimation(const MWWorld::Ptr& ptr);
|
||||
virtual void runAnimation(float timepassed);
|
||||
|
||||
virtual ~CreatureAnimation();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <OgreMaterialManager.h>
|
||||
#include <OgreManualObject.h>
|
||||
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
|
||||
#include <components/esm/loadstat.hpp>
|
||||
#include <components/esm/loadpgrd.hpp>
|
||||
|
||||
|
@ -148,9 +150,9 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid)
|
|||
return result;
|
||||
}
|
||||
|
||||
Debugging::Debugging(SceneNode *mwRoot, OEngine::Physic::PhysicEngine *engine) :
|
||||
mMwRoot(mwRoot), mEngine(engine),
|
||||
mSceneMgr(mwRoot->getCreator()),
|
||||
Debugging::Debugging(SceneNode *root, OEngine::Physic::PhysicEngine *engine) :
|
||||
mRootNode(root), mEngine(engine),
|
||||
mSceneMgr(root->getCreator()),
|
||||
mPathgridEnabled(false),
|
||||
mInteriorPathgridNode(NULL), mPathGridRoot(NULL),
|
||||
mGridMatsCreated(false)
|
||||
|
@ -206,7 +208,7 @@ void Debugging::togglePathgrid()
|
|||
createGridMaterials();
|
||||
|
||||
// add path grid meshes to already loaded cells
|
||||
mPathGridRoot = mMwRoot->createChildSceneNode();
|
||||
mPathGridRoot = mRootNode->createChildSceneNode();
|
||||
for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it)
|
||||
{
|
||||
enableCellPathgrid(*it);
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include <utility>
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
@ -13,6 +12,14 @@ namespace ESM
|
|||
struct Pathgrid;
|
||||
}
|
||||
|
||||
namespace OEngine
|
||||
{
|
||||
namespace Physic
|
||||
{
|
||||
class PhysicEngine;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
class Camera;
|
||||
|
@ -47,7 +54,7 @@ namespace MWRender
|
|||
typedef std::vector<MWWorld::CellStore *> CellList;
|
||||
CellList mActiveCells;
|
||||
|
||||
Ogre::SceneNode *mMwRoot;
|
||||
Ogre::SceneNode *mRootNode;
|
||||
|
||||
Ogre::SceneNode *mPathGridRoot;
|
||||
|
||||
|
@ -71,7 +78,7 @@ namespace MWRender
|
|||
Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid);
|
||||
Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid);
|
||||
public:
|
||||
Debugging(Ogre::SceneNode* mwRoot, OEngine::Physic::PhysicEngine *engine);
|
||||
Debugging(Ogre::SceneNode* root, OEngine::Physic::PhysicEngine *engine);
|
||||
~Debugging();
|
||||
bool toggleRenderMode (int mode);
|
||||
|
||||
|
|
|
@ -190,7 +190,7 @@ namespace MWRender
|
|||
{
|
||||
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)
|
||||
|
|
|
@ -28,9 +28,6 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag
|
|||
|
||||
mCellCamera = mRendering->getScene()->createCamera("CellCamera");
|
||||
mCellCamera->setProjectionType(PT_ORTHOGRAPHIC);
|
||||
// look down -y
|
||||
const float sqrt0pt5 = 0.707106781;
|
||||
mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0));
|
||||
|
||||
mCameraNode->attachObject(mCellCamera);
|
||||
}
|
||||
|
@ -82,8 +79,8 @@ void LocalMap::saveFogOfWar(MWWorld::Ptr::CellStore* cell)
|
|||
}
|
||||
else
|
||||
{
|
||||
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z);
|
||||
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;
|
||||
|
||||
// divide into segments
|
||||
|
@ -107,6 +104,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell)
|
|||
mInterior = false;
|
||||
|
||||
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 y = cell->mCell->getGridY();
|
||||
|
@ -115,49 +113,60 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell)
|
|||
|
||||
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,
|
||||
AxisAlignedBox bounds)
|
||||
{
|
||||
// if we're in an empty cell, don't bother rendering anything
|
||||
if (bounds.isNull ())
|
||||
return;
|
||||
|
||||
mInterior = true;
|
||||
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);
|
||||
Radian angle(std::atan2(-north.x, -north.y));
|
||||
Radian angle = Ogre::Math::ATan2 (north.x, north.y);
|
||||
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
|
||||
Vector2 _center(bounds.getCenter().x, bounds.getCenter().z);
|
||||
Vector3 _c1 = bounds.getCorner(AxisAlignedBox::NEAR_LEFT_BOTTOM);
|
||||
Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM);
|
||||
Vector3 _c3 = bounds.getCorner(AxisAlignedBox::NEAR_RIGHT_BOTTOM);
|
||||
Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM);
|
||||
Vector2 c1(_c1.x, _c1.z);
|
||||
Vector2 c2(_c2.x, _c2.z);
|
||||
Vector2 c3(_c3.x, _c3.z);
|
||||
Vector2 c4(_c4.x, _c4.z);
|
||||
Vector2 _center(bounds.getCenter().x, bounds.getCenter().y);
|
||||
Vector3 _c1 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM);
|
||||
Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM);
|
||||
Vector3 _c3 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_TOP);
|
||||
Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_TOP);
|
||||
|
||||
Vector2 c1(_c1.x, _c1.y);
|
||||
Vector2 c2(_c2.x, _c2.y);
|
||||
Vector2 c3(_c3.x, _c3.y);
|
||||
Vector2 c4(_c4.x, _c4.y);
|
||||
c1 = rotatePoint(c1, _center, mAngle);
|
||||
c2 = rotatePoint(c2, _center, mAngle);
|
||||
c3 = rotatePoint(c3, _center, mAngle);
|
||||
c4 = rotatePoint(c4, _center, mAngle);
|
||||
mBounds.merge(Vector3(c1.x, 0, c1.y));
|
||||
mBounds.merge(Vector3(c2.x, 0, c2.y));
|
||||
mBounds.merge(Vector3(c3.x, 0, c3.y));
|
||||
mBounds.merge(Vector3(c4.x, 0, c4.y));
|
||||
mBounds.merge(Vector3(c1.x, c1.y, 0));
|
||||
mBounds.merge(Vector3(c2.x, c2.y, 0));
|
||||
mBounds.merge(Vector3(c3.x, c3.y, 0));
|
||||
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 max(mBounds.getMaximum().x, mBounds.getMaximum().z);
|
||||
Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y);
|
||||
|
||||
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y);
|
||||
Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y);
|
||||
|
||||
Vector2 length = max-min;
|
||||
|
||||
mCameraPosNode->setPosition(Vector3(center.x, 0, center.y));
|
||||
mCameraPosNode->setPosition(Vector3(center.x, center.y, 0));
|
||||
|
||||
// divide into segments
|
||||
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 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));
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +202,7 @@ void LocalMap::render(const float x, const float y,
|
|||
mRendering->getScene()->setAmbientLight(ColourValue(1,1,1));
|
||||
mRenderingManager->disableLights();
|
||||
|
||||
mCameraNode->setPosition(Vector3(x, zhigh+100000, y));
|
||||
mCameraNode->setPosition(Vector3(x, y, zhigh+100000));
|
||||
//mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 );
|
||||
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)
|
||||
{
|
||||
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;
|
||||
y = std::ceil((pos.y - min.y)/sSize)-1;
|
||||
|
||||
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)
|
||||
|
@ -311,19 +320,19 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
|
|||
int x,y;
|
||||
float u,v;
|
||||
|
||||
Vector2 pos(position.x, position.z);
|
||||
Vector2 pos(position.x, position.y);
|
||||
|
||||
if (mInterior)
|
||||
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)
|
||||
{
|
||||
x = std::ceil(pos.x / sSize)-1;
|
||||
y = std::ceil(-pos.y / sSize)-1;
|
||||
y = std::ceil(pos.y / sSize)-1;
|
||||
mCellX = x;
|
||||
mCellY = y;
|
||||
}
|
||||
|
@ -337,7 +346,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
|
|||
if (!mInterior)
|
||||
{
|
||||
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_";
|
||||
}
|
||||
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()->setPlayerDir(playerdirection.x, -playerdirection.z);
|
||||
MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y);
|
||||
|
||||
// explore radius (squared)
|
||||
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 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)
|
||||
for (int mx = -1; mx<2; ++mx)
|
||||
{
|
||||
|
@ -375,7 +382,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
|
|||
if (!affected)
|
||||
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");
|
||||
if (!tex.isNull())
|
||||
|
|
|
@ -5,295 +5,257 @@
|
|||
#include <OgreSubEntity.h>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.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()
|
||||
{
|
||||
removeEntities(mHead);
|
||||
removeEntities(mHair);
|
||||
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);
|
||||
for(size_t i = 0;i < sPartListSize;i++)
|
||||
removeEntities(mEntityParts[i]);
|
||||
}
|
||||
|
||||
|
||||
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags)
|
||||
: Animation(),
|
||||
: Animation(ptr),
|
||||
mStateID(-1),
|
||||
mInv(inv),
|
||||
mTimeToChange(0),
|
||||
mVisibilityFlags(visibilityFlags),
|
||||
mRobe(mInv.end()),
|
||||
mHelmet(mInv.end()),
|
||||
mShirt(mInv.end()),
|
||||
mCuirass(mInv.end()),
|
||||
mGreaves(mInv.end()),
|
||||
mPauldronL(mInv.end()),
|
||||
mPauldronR(mInv.end()),
|
||||
mBoots(mInv.end()),
|
||||
mPants(mInv.end()),
|
||||
mGloveL(mInv.end()),
|
||||
mGloveR(mInv.end()),
|
||||
mSkirtIter(mInv.end())
|
||||
mRobe(inv.end()),
|
||||
mHelmet(inv.end()),
|
||||
mShirt(inv.end()),
|
||||
mCuirass(inv.end()),
|
||||
mGreaves(inv.end()),
|
||||
mPauldronL(inv.end()),
|
||||
mPauldronR(inv.end()),
|
||||
mBoots(inv.end()),
|
||||
mPants(inv.end()),
|
||||
mGloveL(inv.end()),
|
||||
mGloveR(inv.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
|
||||
mPartPriorities[init] = 0;
|
||||
mPartslots[i] = -1; //each slot is empty
|
||||
mPartPriorities[i] = 0;
|
||||
}
|
||||
|
||||
const MWWorld::ESMStore &store =
|
||||
MWBase::Environment::get().getWorld()->getStore();
|
||||
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;
|
||||
mHairModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHair)->mModel;
|
||||
|
||||
mBodyPrefix = "b_n_" + mNpc->mRace;
|
||||
Misc::StringUtils::toLower(mBodyPrefix);
|
||||
|
||||
mInsert = node;
|
||||
assert(mInsert);
|
||||
|
||||
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
||||
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++)
|
||||
{
|
||||
Ogre::Entity *base = mEntityList.mEntities[i];
|
||||
|
||||
base->getUserObjectBindings ().setUserAny (Ogre::Any(-1));
|
||||
|
||||
base->getUserObjectBindings().setUserAny(Ogre::Any(-1));
|
||||
base->setVisibilityFlags(mVisibilityFlags);
|
||||
|
||||
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::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
|
||||
while (techIt.hasMoreElements())
|
||||
while(!transparent && techIt.hasMoreElements())
|
||||
{
|
||||
Ogre::Technique* tech = techIt.getNext();
|
||||
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
|
||||
while (passIt.hasMoreElements())
|
||||
while(!transparent && passIt.hasMoreElements())
|
||||
{
|
||||
Ogre::Pass* pass = passIt.getNext();
|
||||
if (pass->getDepthWriteEnabled() == false)
|
||||
transparent = true;
|
||||
transparent = pass->isTransparent();
|
||||
}
|
||||
}
|
||||
}
|
||||
base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
|
||||
}
|
||||
|
||||
if(mEntityList.mSkelBase)
|
||||
{
|
||||
Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates();
|
||||
Ogre::AnimationStateIterator as = aset->getAnimationStateIterator();
|
||||
while(as.hasMoreElements())
|
||||
{
|
||||
Ogre::AnimationState *state = as.getNext();
|
||||
state->setEnabled(true);
|
||||
state->setLoop(false);
|
||||
}
|
||||
}
|
||||
std::vector<std::string> skelnames(1, smodel);
|
||||
if(!mNpc->isMale() && !isBeast)
|
||||
skelnames.push_back("meshes\\base_anim_female.nif");
|
||||
else if(mBodyPrefix.find("argonian") != std::string::npos)
|
||||
skelnames.push_back("meshes\\argonian_swimkna.nif");
|
||||
if(mNpc->mModel.length() > 0)
|
||||
skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel));
|
||||
setAnimationSources(skelnames);
|
||||
|
||||
float scale = race->mData.mHeight.mMale;
|
||||
if (!mNpc->isMale()) {
|
||||
scale = race->mData.mHeight.mFemale;
|
||||
}
|
||||
mInsert->scale(scale, scale, scale);
|
||||
|
||||
updateParts();
|
||||
updateParts(true);
|
||||
}
|
||||
|
||||
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 *iter;
|
||||
MWWorld::ContainerStoreIterator NpcAnimation::*part;
|
||||
int slot;
|
||||
|
||||
int numReserveParts; // Max: 12
|
||||
ESM::PartReferenceType reserveParts[12];
|
||||
} slotlist[] = {
|
||||
{ &mRobe, MWWorld::InventoryStore::Slot_Robe },
|
||||
{ &mSkirtIter, MWWorld::InventoryStore::Slot_Skirt },
|
||||
{ &mHelmet, MWWorld::InventoryStore::Slot_Helmet },
|
||||
{ &mCuirass, MWWorld::InventoryStore::Slot_Cuirass },
|
||||
{ &mGreaves, MWWorld::InventoryStore::Slot_Greaves },
|
||||
{ &mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron },
|
||||
{ &mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron },
|
||||
{ &mBoots, MWWorld::InventoryStore::Slot_Boots },
|
||||
{ &mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet },
|
||||
{ &mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet },
|
||||
{ &mShirt, MWWorld::InventoryStore::Slot_Shirt },
|
||||
{ &mPants, MWWorld::InventoryStore::Slot_Pants },
|
||||
{ 0, { },
|
||||
&NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe,
|
||||
12, { ESM::PRT_Groin, ESM::PRT_Skirt, ESM::PRT_RLeg, ESM::PRT_LLeg,
|
||||
ESM::PRT_RUpperarm, ESM::PRT_LUpperarm, ESM::PRT_RKnee, ESM::PRT_LKnee,
|
||||
ESM::PRT_RForearm, ESM::PRT_LForearm, ESM::PRT_RPauldron, ESM::PRT_LPauldron }
|
||||
},
|
||||
|
||||
{ 0, { },
|
||||
&NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt,
|
||||
3, { ESM::PRT_Groin, ESM::PRT_RLeg, ESM::PRT_LLeg }
|
||||
},
|
||||
|
||||
{ 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);
|
||||
if(*slotlist[i].iter != iter)
|
||||
MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot);
|
||||
if(this->*slotlist[i].part != iter)
|
||||
{
|
||||
*slotlist[i].iter = iter;
|
||||
removePartGroup(slotlist[i].slot);
|
||||
apparelChanged = true;
|
||||
forceupdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!forceupdate)
|
||||
return;
|
||||
|
||||
if(apparelChanged)
|
||||
for(size_t i = 0;i < slotlistsize;i++)
|
||||
{
|
||||
if(mRobe != mInv.end())
|
||||
{
|
||||
MWWorld::Ptr ptr = *mRobe;
|
||||
MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot);
|
||||
|
||||
const ESM::Clothing *clothes = (ptr.get<ESM::Clothing>())->mBase;
|
||||
std::vector<ESM::PartReference> parts = clothes->mParts.mParts;
|
||||
addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts);
|
||||
reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_Skirt, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_RUpperarm, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_LUpperarm, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_RKnee, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_LKnee, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_RForearm, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_LForearm, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5);
|
||||
this->*slotlist[i].part = iter;
|
||||
removePartGroup(slotlist[i].slot);
|
||||
|
||||
if(this->*slotlist[i].part == inv.end())
|
||||
continue;
|
||||
|
||||
for(int rem = 0;rem < slotlist[i].numRemoveParts;rem++)
|
||||
removeIndividualPart(slotlist[i].removeParts[rem]);
|
||||
|
||||
int prio = 1;
|
||||
MWWorld::ContainerStoreIterator &store = this->*slotlist[i].part;
|
||||
if(store->getTypeName() == typeid(ESM::Clothing).name())
|
||||
{
|
||||
prio = ((slotlist[i].numReserveParts+1)<<1) + 0;
|
||||
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;
|
||||
|
||||
const ESM::Clothing *clothes = (ptr.get<ESM::Clothing>())->mBase;
|
||||
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);
|
||||
prio = ((slotlist[i].numReserveParts+1)<<1) + 1;
|
||||
const ESM::Armor *armor = store->get<ESM::Armor>()->mBase;
|
||||
addPartGroup(slotlist[i].slot, prio, armor->mParts.mParts);
|
||||
}
|
||||
|
||||
if(mHelmet != mInv.end())
|
||||
{
|
||||
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);
|
||||
}
|
||||
for(int res = 0;res < slotlist[i].numReserveParts;res++)
|
||||
reserveIndividualPart(slotlist[i].reserveParts[res], slotlist[i].slot, prio);
|
||||
}
|
||||
|
||||
if(mPartPriorities[ESM::PRT_Head] < 1)
|
||||
|
@ -333,21 +295,18 @@ void NpcAnimation::updateParts()
|
|||
if(mPartPriorities[PartTypeList[i].type] < 1)
|
||||
{
|
||||
const ESM::BodyPart *part = NULL;
|
||||
const MWWorld::Store<ESM::BodyPart> &partStore =
|
||||
store.get<ESM::BodyPart>();
|
||||
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
|
||||
|
||||
if (!mNpc->isMale()) {
|
||||
if(!mNpc->isMale())
|
||||
{
|
||||
part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]);
|
||||
if (part == 0) {
|
||||
if(part == 0)
|
||||
part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]);
|
||||
}
|
||||
}
|
||||
if (part == 0) {
|
||||
if(part == 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]);
|
||||
}
|
||||
|
||||
if(part)
|
||||
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 entities = NIFLoader::createEntities(mEntityList.mSkelBase, bonename,
|
||||
mInsert, mesh);
|
||||
NifOgre::EntityList entities = NifOgre::Loader::createEntities(mEntityList.mSkelBase, bonename,
|
||||
mInsert, mesh);
|
||||
std::vector<Ogre::Entity*> &parts = entities.mEntities;
|
||||
for(size_t i = 0;i < parts.size();i++)
|
||||
{
|
||||
parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
||||
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;
|
||||
}
|
||||
|
||||
void NpcAnimation::runAnimation(float timepassed)
|
||||
Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
||||
{
|
||||
if(mTimeToChange > .2)
|
||||
if(mTimeToChange <= 0.0f)
|
||||
{
|
||||
mTimeToChange = 0;
|
||||
mTimeToChange = 0.2f;
|
||||
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)
|
||||
|
@ -399,62 +400,14 @@ void NpcAnimation::removeIndividualPart(int type)
|
|||
mPartPriorities[type] = 0;
|
||||
mPartslots[type] = -1;
|
||||
|
||||
if(type == ESM::PRT_Head) //0
|
||||
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
|
||||
for(size_t i = 0;i < sPartListSize;i++)
|
||||
{
|
||||
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)
|
||||
|
@ -484,96 +437,23 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority,
|
|||
removeIndividualPart(type);
|
||||
mPartslots[type] = group;
|
||||
mPartPriorities[type] = priority;
|
||||
switch(type)
|
||||
|
||||
for(size_t i = 0;i < sPartListSize;i++)
|
||||
{
|
||||
case ESM::PRT_Head: //0
|
||||
mHead = insertBoundedPart(mesh, group, "Head");
|
||||
break;
|
||||
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");
|
||||
if(type == sPartList[i].type)
|
||||
{
|
||||
mEntityParts[i] = insertBoundedPart(mesh, group, sPartList[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
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++)
|
||||
{
|
||||
ESM::PartReference &part = parts[i];
|
||||
const ESM::PartReference &part = parts[i];
|
||||
|
||||
const MWWorld::Store<ESM::BodyPart> &partStore =
|
||||
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);
|
||||
|
||||
if(bodypart)
|
||||
addOrReplaceIndividualPart(part.mPart, group, priority,"meshes\\" + bodypart->mModel);
|
||||
addOrReplaceIndividualPart(part.mPart, group, priority, "meshes\\"+bodypart->mModel);
|
||||
else
|
||||
reserveIndividualPart(part.mPart, group, priority);
|
||||
}
|
||||
}
|
||||
|
||||
void NpcAnimation::forceUpdate ()
|
||||
{
|
||||
updateParts();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
|
||||
#include "animation.hpp"
|
||||
|
||||
#include "components/nifogre/ogre_nif_loader.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwclass/npc.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
|
||||
namespace ESM
|
||||
|
@ -13,49 +10,36 @@ namespace ESM
|
|||
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:
|
||||
MWWorld::InventoryStore& mInv;
|
||||
static const size_t sPartListSize = 27;
|
||||
static const PartInfo sPartList[sPartListSize];
|
||||
|
||||
int mStateID;
|
||||
|
||||
int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty
|
||||
int mPartPriorities[27];
|
||||
|
||||
//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;
|
||||
// Bounded Parts
|
||||
NifOgre::EntityList mEntityParts[sPartListSize];
|
||||
|
||||
const ESM::NPC *mNpc;
|
||||
std::string mHeadModel;
|
||||
std::string mHairModel;
|
||||
std::string mBodyPrefix;
|
||||
|
||||
|
||||
float mTimeToChange;
|
||||
MWWorld::ContainerStoreIterator mRobe;
|
||||
MWWorld::ContainerStoreIterator mHelmet;
|
||||
|
@ -72,23 +56,32 @@ private:
|
|||
|
||||
int mVisibilityFlags;
|
||||
|
||||
public:
|
||||
NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node,
|
||||
MWWorld::InventoryStore& inv, int visibilityFlags);
|
||||
virtual ~NpcAnimation();
|
||||
int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty
|
||||
int mPartPriorities[sPartListSize];
|
||||
|
||||
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 removeIndividualPart(int type);
|
||||
void reserveIndividualPart(int type, int group, int priority);
|
||||
|
||||
bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh);
|
||||
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
|
||||
|
|
|
@ -34,19 +34,37 @@ void Objects::clearSceneNode (Ogre::SceneNode *node)
|
|||
for (int i=node->numAttachedObjects()-1; i>=0; --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);
|
||||
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_)
|
||||
{
|
||||
Ogre::SceneNode* root = mMwRoot;
|
||||
Ogre::SceneNode* root = mRootNode;
|
||||
Ogre::SceneNode* cellnode;
|
||||
if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end())
|
||||
{
|
||||
|
@ -87,20 +105,16 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool 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();
|
||||
assert(insert);
|
||||
|
||||
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++)
|
||||
{
|
||||
const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox();
|
||||
bounds.merge(Ogre::AxisAlignedBox(insert->_getDerivedPosition() + tmp.getMinimum(),
|
||||
insert->_getDerivedPosition() + tmp.getMaximum())
|
||||
);
|
||||
}
|
||||
bounds.merge(entities.mEntities[i]->getWorldBoundingBox(true));
|
||||
|
||||
Ogre::Vector3 extents = bounds.getSize();
|
||||
extents *= insert->getScale();
|
||||
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);
|
||||
|
||||
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];
|
||||
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::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
|
||||
while (techIt.hasMoreElements())
|
||||
while(!transparent && techIt.hasMoreElements())
|
||||
{
|
||||
Ogre::Technique* tech = techIt.getNext();
|
||||
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
|
||||
while (passIt.hasMoreElements())
|
||||
while(!transparent && passIt.hasMoreElements())
|
||||
{
|
||||
Ogre::Pass* pass = passIt.getNext();
|
||||
|
||||
if (pass->getDepthWriteEnabled() == false)
|
||||
transparent = true;
|
||||
transparent = pass->isTransparent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -193,26 +205,40 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
|
|||
|
||||
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];
|
||||
insert->detachObject(ent);
|
||||
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
|
||||
Ogre::Node *node = (*iter)->getParentNode();
|
||||
sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_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());
|
||||
assert(insert);
|
||||
Ogre::Light *light = mRenderer.getScene()->createLight();
|
||||
light->setDiffuseColour (r, g, b);
|
||||
|
||||
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;
|
||||
info.name = light->getName();
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -348,9 +384,9 @@ void Objects::enableLights()
|
|||
std::vector<LightInfo>::iterator it = mLights.begin();
|
||||
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;
|
||||
}
|
||||
else
|
||||
|
@ -363,9 +399,9 @@ void Objects::disableLights()
|
|||
std::vector<LightInfo>::iterator it = mLights.begin();
|
||||
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;
|
||||
}
|
||||
else
|
||||
|
@ -418,9 +454,9 @@ void Objects::update(const float dt)
|
|||
std::vector<LightInfo>::iterator it = mLights.begin();
|
||||
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 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;
|
||||
MWWorld::CellStore *newCell = ptr.getCell();
|
||||
MWWorld::CellStore *newCell = cur.getCell();
|
||||
|
||||
if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) {
|
||||
node = mMwRoot->createChildSceneNode();
|
||||
node = mRootNode->createChildSceneNode();
|
||||
mCellSceneNodes[newCell] = node;
|
||||
} else {
|
||||
node = mCellSceneNodes[newCell];
|
||||
}
|
||||
node->addChild(ptr.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));
|
||||
node->addChild(cur.getRefData().getBaseNode());
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _GAME_RENDER_OBJECTS_H
|
||||
|
||||
#include <OgreColourValue.h>
|
||||
#include <OgreAxisAlignedBox.h>
|
||||
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
|
||||
|
@ -52,7 +53,7 @@ class Objects{
|
|||
std::map<MWWorld::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall;
|
||||
std::map<MWWorld::CellStore *, Ogre::AxisAlignedBox> mBounds;
|
||||
std::vector<LightInfo> mLights;
|
||||
Ogre::SceneNode* mMwRoot;
|
||||
Ogre::SceneNode* mRootNode;
|
||||
bool mIsStatic;
|
||||
static int uniqueID;
|
||||
|
||||
|
@ -72,8 +73,8 @@ public:
|
|||
Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mIsStatic(false) {}
|
||||
~Objects(){}
|
||||
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
||||
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||
void insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius);
|
||||
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false);
|
||||
void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity *skelBase=0, Ogre::Vector3 fallbackCenter=Ogre::Vector3(0.0f));
|
||||
|
||||
void enableLights();
|
||||
void disableLights();
|
||||
|
@ -89,12 +90,12 @@ public:
|
|||
|
||||
void removeCell(MWWorld::CellStore* store);
|
||||
void buildStaticGeometry(MWWorld::CellStore &cell);
|
||||
void setMwRoot(Ogre::SceneNode* root);
|
||||
void setRootNode(Ogre::SceneNode* root);
|
||||
|
||||
void rebuildStaticGeometry();
|
||||
|
||||
/// Updates containing cell for object rendering data
|
||||
void updateObjectCell(const MWWorld::Ptr &ptr);
|
||||
void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -113,11 +113,6 @@ namespace MWRender
|
|||
Ogre::Vector3 dir = mCamera->getRealDirection();
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -129,14 +124,8 @@ namespace MWRender
|
|||
MWBase::Environment::get().getWindowManager ()->showCrosshair
|
||||
(!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode));
|
||||
|
||||
if (mAnimation) {
|
||||
mAnimation->runAnimation(duration);
|
||||
}
|
||||
mPlayerNode->setVisible(
|
||||
mVanity.enabled || mPreviewMode || !mFirstPersonView,
|
||||
false
|
||||
);
|
||||
|
||||
/// \fixme We shouldn't hide the whole model, just certain components of the character (head, chest, feet, etc)
|
||||
mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView);
|
||||
if (mFirstPersonView && !mVanity.enabled) {
|
||||
return;
|
||||
}
|
||||
|
@ -313,10 +302,7 @@ namespace MWRender
|
|||
delete mAnimation;
|
||||
mAnimation = anim;
|
||||
|
||||
mPlayerNode->setVisible(
|
||||
mVanity.enabled || mPreviewMode || !mFirstPersonView,
|
||||
false
|
||||
);
|
||||
mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView);
|
||||
}
|
||||
|
||||
void Player::setHeight(float height)
|
||||
|
@ -332,10 +318,8 @@ namespace MWRender
|
|||
|
||||
bool Player::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera)
|
||||
{
|
||||
float xch;
|
||||
mCamera->getParentSceneNode ()->needUpdate(true);
|
||||
camera = mCamera->getRealPosition();
|
||||
xch = camera.z, camera.z = camera.y, camera.y = -xch;
|
||||
player = mPlayerNode->getPosition();
|
||||
|
||||
return mFirstPersonView && !mVanity.enabled && !mPreviewMode;
|
||||
|
|
|
@ -95,7 +95,9 @@ namespace MWRender
|
|||
/// Restore default camera distance for current mode.
|
||||
void setCameraDistance();
|
||||
|
||||
void setAnimation(MWRender::NpcAnimation *anim);
|
||||
void setAnimation(NpcAnimation *anim);
|
||||
NpcAnimation *getAnimation() const
|
||||
{ return mAnimation; }
|
||||
|
||||
void setHeight(float height);
|
||||
float getHeight();
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
#include <extern/shiny/Main/Factory.hpp>
|
||||
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
|
||||
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
|
||||
#include <components/esm/loadstat.hpp>
|
||||
#include "../mwworld/esmstore.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/environment.hpp"
|
||||
|
@ -138,26 +141,20 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
|||
|
||||
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();
|
||||
mMwRoot = rt->createChildSceneNode("mwRoot");
|
||||
mMwRoot->pitch(Degree(-90));
|
||||
mRootNode = rt;
|
||||
|
||||
mObjects.setMwRoot(mMwRoot);
|
||||
mActors.setMwRoot(mMwRoot);
|
||||
mObjects.setRootNode(mRootNode);
|
||||
mActors.setRootNode(mRootNode);
|
||||
|
||||
Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player");
|
||||
Ogre::SceneNode *playerNode = mRootNode->createChildSceneNode ("player");
|
||||
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
||||
|
||||
mShadows = new Shadows(&mRendering);
|
||||
|
||||
mTerrainManager = new TerrainManager(mRendering.getScene(), this);
|
||||
|
||||
mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera());
|
||||
mSkyManager = new SkyManager(mRootNode, mRendering.getCamera());
|
||||
|
||||
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
|
||||
|
||||
|
@ -166,7 +163,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
|||
|
||||
mSun = 0;
|
||||
|
||||
mDebugging = new Debugging(mMwRoot, engine);
|
||||
mDebugging = new Debugging(mRootNode, engine);
|
||||
mLocalMap = new MWRender::LocalMap(&mRendering, this);
|
||||
|
||||
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)
|
||||
{
|
||||
/// \todo move this to the rendering-subsystems
|
||||
mRendering.getScene()->getSceneNode (ptr.getRefData().getHandle())->
|
||||
setPosition (position);
|
||||
ptr.getRefData().getBaseNode()->setPosition(position);
|
||||
}
|
||||
|
||||
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
|
||||
RenderingManager::moveObjectToCell(
|
||||
const MWWorld::Ptr& ptr,
|
||||
const Ogre::Vector3& pos,
|
||||
MWWorld::CellStore *store)
|
||||
RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur)
|
||||
{
|
||||
Ogre::SceneNode *child =
|
||||
mRendering.getScene()->getSceneNode(ptr.getRefData().getHandle());
|
||||
mRendering.getScene()->getSceneNode(old.getRefData().getHandle());
|
||||
|
||||
Ogre::SceneNode *parent = child->getParentSceneNode();
|
||||
parent->removeChild(child);
|
||||
|
||||
if (MWWorld::Class::get(ptr).isActor()) {
|
||||
mActors.updateObjectCell(ptr);
|
||||
if (MWWorld::Class::get(old).isActor()) {
|
||||
mActors.updateObjectCell(old, cur);
|
||||
} else {
|
||||
mObjects.updateObjectCell(ptr);
|
||||
mObjects.updateObjectCell(old, cur);
|
||||
}
|
||||
child->setPosition(pos);
|
||||
}
|
||||
|
||||
void RenderingManager::update (float duration, bool paused)
|
||||
|
@ -324,7 +316,7 @@ void RenderingManager::update (float duration, bool paused)
|
|||
Ogre::Vector3 orig, dest;
|
||||
mPlayer->setCameraDistance();
|
||||
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 btDest(dest.x, dest.y, dest.z);
|
||||
|
@ -368,11 +360,13 @@ void RenderingManager::update (float duration, bool paused)
|
|||
float *fpos = data.getPosition().pos;
|
||||
|
||||
// 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::Quaternion orient =
|
||||
//node->convertLocalToWorldOrientation(node->_getDerivedOrientation());
|
||||
Ogre::Quaternion orient =
|
||||
node->convertLocalToWorldOrientation(node->_getDerivedOrientation());
|
||||
node->_getDerivedOrientation();
|
||||
|
||||
mLocalMap->updatePlayer(pos, orient);
|
||||
|
||||
|
@ -383,8 +377,8 @@ void RenderingManager::update (float duration, bool paused)
|
|||
|
||||
mWater->updateUnderwater(
|
||||
world->isUnderwater(
|
||||
*world->getPlayer().getPlayer().getCell()->mCell,
|
||||
Ogre::Vector3(cam.x, -cam.z, cam.y))
|
||||
world->getPlayer().getPlayer().getCell(),
|
||||
cam)
|
||||
);
|
||||
mWater->update(duration);
|
||||
}
|
||||
|
@ -580,17 +574,6 @@ void RenderingManager::toggleLight()
|
|||
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)
|
||||
{
|
||||
if (!mSunEnabled) return;
|
||||
|
@ -627,8 +610,7 @@ void RenderingManager::sunDisable()
|
|||
void RenderingManager::setSunDirection(const Ogre::Vector3& direction)
|
||||
{
|
||||
// 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.z, direction.y));
|
||||
if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z));
|
||||
|
||||
mSkyManager->setSunDirection(direction);
|
||||
}
|
||||
|
@ -929,6 +911,15 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend
|
|||
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)
|
||||
{
|
||||
mVideoPlayer->playVideo ("video/" + name, allowSkipping);
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace MWRender
|
|||
class ExternalRendering;
|
||||
class GlobalMap;
|
||||
class VideoPlayer;
|
||||
class Animation;
|
||||
|
||||
class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener {
|
||||
|
||||
|
@ -122,9 +123,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
|
|||
void setWaterHeight(const float height);
|
||||
void toggleWater();
|
||||
|
||||
/// Moves object rendering part to proper container
|
||||
/// \param store Cell the object was in previously (\a ptr has already been updated to the new cell).
|
||||
void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::CellStore *store);
|
||||
/// Updates object rendering after cell change
|
||||
/// \param old Object reference in previous cell
|
||||
/// \param cur Object reference in new cell
|
||||
void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur);
|
||||
|
||||
void update (float duration, bool paused);
|
||||
|
||||
|
@ -166,18 +168,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
|
|||
/// configure fog manually
|
||||
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);
|
||||
///< transform the specified bounding box (in world coordinates) into screen coordinates.
|
||||
/// @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);
|
||||
|
||||
Animation* getAnimation(const MWWorld::Ptr &ptr);
|
||||
|
||||
void playVideo(const std::string& name, bool allowSkipping);
|
||||
void stopVideo();
|
||||
|
||||
|
@ -236,10 +228,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
|
|||
Ogre::ColourValue mAmbientColor;
|
||||
Ogre::Light* mSun;
|
||||
|
||||
/// Root node for all objects added to the scene. This is rotated so
|
||||
/// that the OGRE coordinate system matches that used internally in
|
||||
/// Morrowind.
|
||||
Ogre::SceneNode *mMwRoot;
|
||||
Ogre::SceneNode *mRootNode;
|
||||
|
||||
OEngine::Physic::PhysicEngine* mPhysicsEngine;
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ void BillboardObject::setPosition(const Vector3& pPosition)
|
|||
Vector3 BillboardObject::getPosition() const
|
||||
{
|
||||
Vector3 p = mNode->_getDerivedPosition() - mNode->getParentSceneNode()->_getDerivedPosition();
|
||||
return Vector3(p.x, -p.z, p.y);
|
||||
return p;
|
||||
}
|
||||
|
||||
void BillboardObject::setVisibilityFlags(int flags)
|
||||
|
@ -203,7 +203,7 @@ unsigned int Moon::getPhaseInt() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera)
|
||||
SkyManager::SkyManager (SceneNode* root, Camera* pCamera)
|
||||
: mHour(0.0f)
|
||||
, mDay(0)
|
||||
, mMonth(0)
|
||||
|
@ -234,9 +234,8 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera)
|
|||
, mCloudAnimationTimer(0.f)
|
||||
, mMoonRed(false)
|
||||
{
|
||||
mSceneMgr = pMwRoot->getCreator();
|
||||
mSceneMgr = root->getCreator();
|
||||
mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates
|
||||
mRootNode->setInheritOrientation(false);
|
||||
}
|
||||
|
||||
|
@ -282,7 +281,7 @@ void SkyManager::create()
|
|||
|
||||
// Stars
|
||||
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++)
|
||||
{
|
||||
Entity* night1_ent = entities.mEntities[i];
|
||||
|
@ -307,26 +306,28 @@ void SkyManager::create()
|
|||
|
||||
// Atmosphere (day)
|
||||
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++)
|
||||
{
|
||||
Entity* atmosphere_ent = entities.mEntities[i];
|
||||
atmosphere_ent->setCastShadows(false);
|
||||
atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly);
|
||||
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
|
||||
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++)
|
||||
{
|
||||
Entity* clouds_ent = entities.mEntities[i];
|
||||
clouds_ent->setVisibilityFlags(RV_Sky);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -389,7 +390,6 @@ void SkyManager::update(float duration)
|
|||
// increase the strength of the sun glare effect depending
|
||||
// on how directly the player is looking at the sun
|
||||
Vector3 sun = mSunGlare->getPosition();
|
||||
sun = Vector3(sun.x, sun.z, -sun.y);
|
||||
Vector3 cam = mCamera->getRealDirection();
|
||||
const Degree angle = sun.angleBetween( cam );
|
||||
float val = 1- (angle.valueDegrees() / 180.f);
|
||||
|
|
|
@ -112,7 +112,7 @@ namespace MWRender
|
|||
class SkyManager
|
||||
{
|
||||
public:
|
||||
SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera);
|
||||
SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera);
|
||||
~SkyManager();
|
||||
|
||||
void update(float duration);
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace MWRender
|
|||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
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();
|
||||
|
||||
|
@ -54,8 +54,8 @@ namespace MWRender
|
|||
mTerrainGlobals->setCompositeMapDistance(mWorldSize*2);
|
||||
|
||||
mTerrainGroup.setOrigin(Vector3(mWorldSize/2,
|
||||
0,
|
||||
-mWorldSize/2));
|
||||
mWorldSize/2,
|
||||
0));
|
||||
|
||||
Terrain::ImportData& importSettings = mTerrainGroup.getDefaultImportSettings();
|
||||
|
||||
|
|
|
@ -404,6 +404,8 @@ public:
|
|||
*type = MWSound::SampleType_UInt8;
|
||||
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16)
|
||||
*type = MWSound::SampleType_Int16;
|
||||
else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT)
|
||||
*type = MWSound::SampleType_Float32;
|
||||
else
|
||||
fail(std::string("Unsupported sample format: ")+
|
||||
av_get_sample_fmt_name(mAVStream->codec->sample_fmt));
|
||||
|
|
|
@ -42,9 +42,9 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel
|
|||
|
||||
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->setVisibilityFlags(RV_Water);
|
||||
|
@ -168,12 +168,12 @@ void Water::setHeight(const float height)
|
|||
{
|
||||
mTop = height;
|
||||
|
||||
mWaterPlane = Plane(Vector3::UNIT_Y, height);
|
||||
mWaterPlane = Plane(Vector3::UNIT_Z, height);
|
||||
|
||||
// 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)));
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ Water::updateUnderwater(bool underwater)
|
|||
|
||||
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)
|
||||
|
@ -216,7 +216,7 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
|
|||
mReflectionRenderActive = true;
|
||||
|
||||
Vector3 pos = mCamera->getRealPosition();
|
||||
pos.y = mTop*2 - pos.y;
|
||||
pos.z = mTop*2 - pos.z;
|
||||
mSky->setSkyPosition(pos);
|
||||
mReflectionCamera->enableReflection(mWaterPlane);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <components/interpreter/runtime.hpp>
|
||||
#include <components/interpreter/opcodes.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "interpretercontext.hpp"
|
||||
#include "ref.hpp"
|
||||
|
@ -27,7 +27,7 @@ namespace MWScript
|
|||
{
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, loops);
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, loops);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -140,25 +140,42 @@ namespace MWScript
|
|||
|
||||
Compiler::Locals& ScriptManager::getLocals (const std::string& name)
|
||||
{
|
||||
ScriptCollection::iterator iter = mScripts.find (name);
|
||||
|
||||
if (iter==mScripts.end())
|
||||
{
|
||||
if (!compile (name))
|
||||
{
|
||||
/// \todo Handle case of cyclic member variable access. Currently this could look up
|
||||
/// the whole application in an endless recursion.
|
||||
ScriptCollection::iterator iter = mScripts.find (name);
|
||||
|
||||
// failed -> ignore script from now on.
|
||||
std::vector<Interpreter::Type_Code> empty;
|
||||
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);
|
||||
if (iter!=mScripts.end())
|
||||
return iter->second.second;
|
||||
}
|
||||
|
||||
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()
|
||||
|
|
|
@ -47,6 +47,7 @@ namespace MWScript
|
|||
|
||||
ScriptCollection mScripts;
|
||||
GlobalScripts mGlobalScripts;
|
||||
std::map<std::string, Compiler::Locals> mOtherLocals;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -134,6 +134,18 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length)
|
|||
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)
|
||||
{
|
||||
|
@ -160,7 +172,6 @@ void FFmpeg_Decoder::open(const std::string &fname)
|
|||
{
|
||||
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];
|
||||
break;
|
||||
}
|
||||
|
@ -168,6 +179,8 @@ void FFmpeg_Decoder::open(const std::string &fname)
|
|||
if(!mStream)
|
||||
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);
|
||||
if(!codec)
|
||||
{
|
||||
|
@ -220,6 +233,8 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *
|
|||
*type = SampleType_UInt8;
|
||||
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16)
|
||||
*type = SampleType_Int16;
|
||||
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT)
|
||||
*type = SampleType_Float32;
|
||||
else
|
||||
fail(std::string("Unsupported sample format: ")+
|
||||
av_get_sample_fmt_name((*mStream)->codec->sample_fmt));
|
||||
|
|
|
@ -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)+")");
|
||||
return AL_NONE;
|
||||
|
|
|
@ -9,7 +9,8 @@ namespace MWSound
|
|||
{
|
||||
enum SampleType {
|
||||
SampleType_UInt8,
|
||||
SampleType_Int16
|
||||
SampleType_Int16,
|
||||
SampleType_Float32
|
||||
};
|
||||
const char *getSampleTypeName(SampleType type);
|
||||
|
||||
|
|
|
@ -607,6 +607,7 @@ namespace MWSound
|
|||
{
|
||||
case SampleType_UInt8: return "U8";
|
||||
case SampleType_Int16: return "S16";
|
||||
case SampleType_Float32: return "Float32";
|
||||
}
|
||||
return "(unknown sample type)";
|
||||
}
|
||||
|
@ -638,6 +639,7 @@ namespace MWSound
|
|||
{
|
||||
case SampleType_UInt8: frames *= 1; break;
|
||||
case SampleType_Int16: frames *= 2; break;
|
||||
case SampleType_Float32: frames *= 4; break;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
: 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)
|
||||
{}
|
||||
|
||||
|
|
|
@ -122,6 +122,11 @@ namespace MWWorld
|
|||
return 0;
|
||||
}
|
||||
|
||||
float Class::getJump (const Ptr& ptr) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const
|
||||
{
|
||||
throw std::runtime_error ("movement settings not supported by class");
|
||||
|
|
|
@ -140,6 +140,9 @@ namespace MWWorld
|
|||
virtual float getSpeed (const Ptr& ptr) const;
|
||||
///< 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;
|
||||
///< Return desired movement.
|
||||
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#include <OgreCamera.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 "../mwbase/world.hpp" // FIXME
|
||||
|
@ -21,23 +25,191 @@ using namespace Ogre;
|
|||
namespace MWWorld
|
||||
{
|
||||
|
||||
PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) :
|
||||
mRender(_rend), mEngine(0), mFreeFly (true)
|
||||
{
|
||||
static const float sMaxSlope = 60.0f;
|
||||
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
|
||||
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
|
||||
mEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
|
||||
playerphysics->mEngine = mEngine;
|
||||
}
|
||||
|
||||
PhysicsSystem::~PhysicsSystem()
|
||||
{
|
||||
delete mEngine;
|
||||
delete playerphysics;
|
||||
|
||||
}
|
||||
|
||||
OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine()
|
||||
{
|
||||
return mEngine;
|
||||
|
@ -92,9 +264,8 @@ namespace MWWorld
|
|||
Ogre::Vector3 to = ray.getPoint(queryDistance);
|
||||
|
||||
btVector3 _from, _to;
|
||||
// OGRE to MW coordinates
|
||||
_from = btVector3(from.x, -from.z, from.y);
|
||||
_to = btVector3(to.x, -to.z, to.y);
|
||||
_from = btVector3(from.x, from.y, from.z);
|
||||
_to = btVector3(to.x, to.y, to.z);
|
||||
|
||||
std::vector < std::pair <float, std::string> > results;
|
||||
/* auto */ results = mEngine->rayTest2(_from,_to);
|
||||
|
@ -106,15 +277,7 @@ namespace MWWorld
|
|||
|
||||
void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight)
|
||||
{
|
||||
playerphysics->hasWater = hasWater;
|
||||
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);
|
||||
}
|
||||
|
||||
// TODO: store and use
|
||||
}
|
||||
|
||||
btVector3 PhysicsSystem::getRayPoint(float extent)
|
||||
|
@ -123,7 +286,7 @@ namespace MWWorld
|
|||
Ray centerRay = mRender.getCamera()->getCameraToViewportRay(
|
||||
mRender.getViewport()->getWidth()/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;
|
||||
}
|
||||
|
||||
|
@ -131,7 +294,7 @@ namespace MWWorld
|
|||
{
|
||||
//get a ray pointing to the center of the viewport
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -171,9 +334,8 @@ namespace MWWorld
|
|||
Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable
|
||||
|
||||
btVector3 _from, _to;
|
||||
// OGRE to MW coordinates
|
||||
_from = btVector3(from.x, -from.z, from.y);
|
||||
_to = btVector3(to.x, -to.z, to.y);
|
||||
_from = btVector3(from.x, from.y, from.z);
|
||||
_to = btVector3(to.x, to.y, to.z);
|
||||
|
||||
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
|
||||
//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);
|
||||
return MovementSolver::move(ptr, movement, time, gravity, mEngine);
|
||||
}
|
||||
|
||||
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,
|
||||
int x, int y, float yoffset,
|
||||
|
@ -291,46 +393,20 @@ namespace MWWorld
|
|||
|
||||
void PhysicsSystem::moveObject (const Ptr& ptr)
|
||||
{
|
||||
Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
|
||||
std::string handle = node->getName();
|
||||
Ogre::Vector3 position = node->getPosition();
|
||||
if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle))
|
||||
{
|
||||
// TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow
|
||||
// start positions others than 0, 0, 0
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
Ogre::SceneNode *node = ptr.getRefData().getBaseNode();
|
||||
const std::string &handle = node->getName();
|
||||
const Ogre::Vector3 &position = node->getPosition();
|
||||
if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle))
|
||||
body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z));
|
||||
else if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle))
|
||||
physact->setPosition(position);
|
||||
}
|
||||
|
||||
void PhysicsSystem::rotateObject (const Ptr& ptr)
|
||||
{
|
||||
Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
|
||||
std::string handle = node->getName();
|
||||
Ogre::Quaternion rotation = node->getOrientation();
|
||||
const std::string &handle = node->getName();
|
||||
const Ogre::Quaternion &rotation = node->getOrientation();
|
||||
if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle))
|
||||
{
|
||||
//Needs to be changed
|
||||
|
@ -348,7 +424,7 @@ namespace MWWorld
|
|||
void PhysicsSystem::scaleObject (const Ptr& ptr)
|
||||
{
|
||||
Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
|
||||
std::string handle = node->getName();
|
||||
const std::string &handle = node->getName();
|
||||
if(handleToMesh.find(handle) != handleToMesh.end())
|
||||
{
|
||||
removeObject(handle);
|
||||
|
@ -361,7 +437,6 @@ namespace MWWorld
|
|||
|
||||
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++)
|
||||
{
|
||||
if (it->first=="player")
|
||||
|
@ -372,12 +447,10 @@ namespace MWWorld
|
|||
if(cmode)
|
||||
{
|
||||
act->enableCollisions(false);
|
||||
mFreeFly = true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mFreeFly = false;
|
||||
act->enableCollisions(true);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,27 @@
|
|||
#ifndef GAME_MWWORLD_PHYSICSSYSTEM_H
|
||||
#define GAME_MWWORLD_PHYSICSSYSTEM_H
|
||||
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
#include "ptr.hpp"
|
||||
#include <openengine/bullet/pmove.h>
|
||||
#include <OgreVector3.h>
|
||||
|
||||
#include <btBulletCollisionCommon.h>
|
||||
|
||||
|
||||
namespace OEngine
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
class OgreRenderer;
|
||||
}
|
||||
namespace Physic
|
||||
{
|
||||
class PhysicEngine;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class World;
|
||||
class Ptr;
|
||||
|
||||
class PhysicsSystem
|
||||
{
|
||||
|
@ -14,12 +29,6 @@ namespace MWWorld
|
|||
PhysicsSystem (OEngine::Render::OgreRenderer &_rend);
|
||||
~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 addActor (const MWWorld::Ptr& ptr);
|
||||
|
@ -41,6 +50,8 @@ namespace MWWorld
|
|||
|
||||
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::vector < std::pair <float, std::string> > getFacedHandles (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::Physic::PhysicEngine* mEngine;
|
||||
bool mFreeFly;
|
||||
playerMove* playerphysics;
|
||||
std::map<std::string, std::string> handleToMesh;
|
||||
|
||||
PhysicsSystem (const PhysicsSystem&);
|
||||
|
|
|
@ -71,6 +71,12 @@ namespace MWWorld
|
|||
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()
|
||||
{
|
||||
MWWorld::Ptr ptr = getPlayer();
|
||||
|
|
|
@ -65,6 +65,7 @@ namespace MWWorld
|
|||
void setForwardBackward (int value);
|
||||
void setUpDown(int value);
|
||||
|
||||
void setRunState(bool run);
|
||||
void toggleRunning();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "scene.hpp"
|
||||
|
||||
#include <components/nif/nif_file.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp" /// FIXME
|
||||
|
@ -7,9 +8,11 @@
|
|||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "physicssystem.hpp"
|
||||
#include "player.hpp"
|
||||
#include "localscripts.hpp"
|
||||
#include "esmstore.hpp"
|
||||
#include "class.hpp"
|
||||
|
||||
#include "cellfunctors.hpp"
|
||||
|
||||
|
@ -24,13 +27,10 @@ namespace
|
|||
{
|
||||
const MWWorld::Class& class_ =
|
||||
MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell));
|
||||
|
||||
int numRefs = cellRefList.mList.size();
|
||||
int current = 0;
|
||||
for (typename T::List::iterator it = cellRefList.mList.begin();
|
||||
it != cellRefList.mList.end(); it++)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs);
|
||||
++current;
|
||||
|
||||
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");
|
||||
|
||||
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);
|
||||
mActiveCells.erase(*iter);
|
||||
}
|
||||
|
@ -164,7 +160,7 @@ namespace MWWorld
|
|||
MWBase::MechanicsManager *mechMgr =
|
||||
MWBase::Environment::get().getMechanicsManager();
|
||||
|
||||
mechMgr->addActor(player);
|
||||
mechMgr->add(player);
|
||||
mechMgr->watchActor(player);
|
||||
|
||||
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)
|
||||
{
|
||||
Nif::NIFFile::CacheLock cachelock;
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
mRendering.preCellChange(mCurrentCell);
|
||||
|
||||
// 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();
|
||||
|
||||
|
@ -213,8 +215,6 @@ namespace MWWorld
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload);
|
||||
unloadCell (active++);
|
||||
++current;
|
||||
}
|
||||
|
@ -263,7 +263,9 @@ namespace MWWorld
|
|||
{
|
||||
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);
|
||||
++current;
|
||||
}
|
||||
|
@ -322,6 +324,13 @@ namespace MWWorld
|
|||
|
||||
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);
|
||||
bool loadcell = (mCurrentCell == NULL);
|
||||
if(!loadcell)
|
||||
|
@ -357,8 +366,6 @@ namespace MWWorld
|
|||
active = mActiveCells.begin();
|
||||
while (active!=mActiveCells.end())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload);
|
||||
|
||||
unloadCell (active++);
|
||||
++current;
|
||||
}
|
||||
|
@ -366,7 +373,9 @@ namespace MWWorld
|
|||
// Load cell.
|
||||
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);
|
||||
|
||||
mCurrentCell = cell;
|
||||
|
@ -441,7 +450,7 @@ namespace MWWorld
|
|||
|
||||
void Scene::removeObjectFromScene (const Ptr& ptr)
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->removeActor (ptr);
|
||||
MWBase::Environment::get().getMechanicsManager()->remove (ptr);
|
||||
MWBase::Environment::get().getSoundManager()->stopSound3D (ptr);
|
||||
mPhysics->removeObject (ptr.getRefData().getHandle());
|
||||
mRendering.removeObject (ptr);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "../mwrender/renderingmanager.hpp"
|
||||
|
||||
#include "physicssystem.hpp"
|
||||
#include "ptr.hpp"
|
||||
#include "globals.hpp"
|
||||
|
||||
namespace Ogre
|
||||
|
@ -34,9 +34,9 @@ namespace MWRender
|
|||
|
||||
namespace MWWorld
|
||||
{
|
||||
class PhysicsSystem;
|
||||
class Player;
|
||||
class CellStore;
|
||||
class Ptr;
|
||||
|
||||
class Scene
|
||||
{
|
||||
|
|
|
@ -17,9 +17,9 @@ namespace MWWorld
|
|||
virtual void setUp() {}
|
||||
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 bool eraseStatic(const std::string &id) {return false;}
|
||||
};
|
||||
|
||||
|
@ -110,7 +110,7 @@ namespace MWWorld
|
|||
item.mId = Misc::StringUtils::lowerCase(id);
|
||||
|
||||
typename std::map<std::string, T>::const_iterator it = mStatic.find(item.mId);
|
||||
|
||||
|
||||
if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) {
|
||||
return &(it->second);
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ namespace MWWorld
|
|||
return mShared.end();
|
||||
}
|
||||
|
||||
int getSize() const {
|
||||
size_t getSize() const {
|
||||
return mShared.size();
|
||||
}
|
||||
|
||||
|
@ -188,14 +188,14 @@ namespace MWWorld
|
|||
item.mId = Misc::StringUtils::lowerCase(id);
|
||||
|
||||
typename std::map<std::string, T>::iterator it = mStatic.find(item.mId);
|
||||
|
||||
|
||||
if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) {
|
||||
mStatic.erase(it);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool erase(const std::string &id) {
|
||||
std::string key = Misc::StringUtils::lowerCase(id);
|
||||
typename Dynamic::iterator it = mDynamic.find(key);
|
||||
|
@ -220,9 +220,15 @@ namespace MWWorld
|
|||
template <>
|
||||
inline void Store<ESM::Dialogue>::load(ESM::ESMReader &esm, const std::string &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
|
||||
mStatic[idLower].load(esm);
|
||||
|
||||
std::map<std::string, ESM::Dialogue>::iterator it = mStatic.find(idLower);
|
||||
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 <>
|
||||
|
@ -269,11 +275,11 @@ namespace MWWorld
|
|||
return ptr;
|
||||
}
|
||||
|
||||
int getSize() const {
|
||||
size_t getSize() const {
|
||||
return mStatic.size();
|
||||
}
|
||||
|
||||
int getSize(size_t plugin) const {
|
||||
size_t getSize(size_t plugin) const {
|
||||
assert(plugin < mStatic.size());
|
||||
return mStatic[plugin].size();
|
||||
}
|
||||
|
@ -338,7 +344,7 @@ namespace MWWorld
|
|||
|
||||
}
|
||||
|
||||
int getSize() const {
|
||||
size_t getSize() const {
|
||||
return mStatic.size();
|
||||
}
|
||||
|
||||
|
@ -409,7 +415,7 @@ namespace MWWorld
|
|||
|
||||
DynamicInt mDynamicInt;
|
||||
DynamicExt mDynamicExt;
|
||||
|
||||
|
||||
const ESM::Cell *search(const ESM::Cell &cell) const {
|
||||
if (cell.isExterior()) {
|
||||
return search(cell.getGridX(), cell.getGridY());
|
||||
|
@ -481,7 +487,7 @@ namespace MWWorld
|
|||
newCell->mData.mY = y;
|
||||
mExt[std::make_pair(x, y)] = *newCell;
|
||||
delete newCell;
|
||||
|
||||
|
||||
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
|
||||
// this method.
|
||||
void load(ESM::ESMReader &esm, const std::string &id);
|
||||
|
||||
|
||||
iterator intBegin() const {
|
||||
return iterator(mSharedInt.begin());
|
||||
}
|
||||
|
@ -567,7 +573,7 @@ namespace MWWorld
|
|||
return 0;
|
||||
}
|
||||
|
||||
int getSize() const {
|
||||
size_t getSize() const {
|
||||
return mSharedInt.size() + mSharedExt.size();
|
||||
}
|
||||
|
||||
|
@ -701,7 +707,7 @@ namespace MWWorld
|
|||
mStatic.back().load(esm);
|
||||
}
|
||||
|
||||
int getSize() const {
|
||||
size_t getSize() const {
|
||||
return mStatic.size();
|
||||
}
|
||||
|
||||
|
@ -930,7 +936,7 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
|
||||
int getSize() const {
|
||||
size_t getSize() const {
|
||||
return mStatic.size();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "worldimp.hpp"
|
||||
|
||||
#include <libs/openengine/bullet/physic.hpp>
|
||||
|
||||
#include <components/bsa/bsa_archive.hpp>
|
||||
#include <components/files/collections.hpp>
|
||||
#include <components/compiler/locals.hpp>
|
||||
|
@ -10,6 +12,8 @@
|
|||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/scriptmanager.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
#include "../mwrender/sky.hpp"
|
||||
#include "../mwrender/player.hpp"
|
||||
|
||||
|
@ -18,6 +22,7 @@
|
|||
#include "player.hpp"
|
||||
#include "manualref.hpp"
|
||||
#include "cellfunctors.hpp"
|
||||
#include "containerstore.hpp"
|
||||
|
||||
using namespace Ogre;
|
||||
|
||||
|
@ -183,6 +188,8 @@ namespace MWWorld
|
|||
|
||||
mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine);
|
||||
|
||||
mPhysEngine->setSceneManager(renderer.getScene());
|
||||
|
||||
mWeatherManager = new MWWorld::WeatherManager(mRendering);
|
||||
|
||||
int idx = 0;
|
||||
|
@ -732,6 +739,7 @@ namespace MWWorld
|
|||
removeContainerScripts(ptr);
|
||||
|
||||
if (isPlayer)
|
||||
{
|
||||
if (!newCell.isExterior())
|
||||
changeToInteriorCell(Misc::StringUtils::lowerCase(newCell.mCell->mName), pos);
|
||||
else
|
||||
|
@ -740,13 +748,18 @@ namespace MWWorld
|
|||
int cellY = newCell.mCell->getGridY();
|
||||
mWorldScene->changeCell(cellX, cellY, pos, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mWorldScene->isCellActive(*currCell))
|
||||
copyObjectToCell(ptr, newCell, pos);
|
||||
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);
|
||||
mLocalScripts.remove(ptr);
|
||||
removeContainerScripts (ptr);
|
||||
|
@ -757,7 +770,10 @@ namespace MWWorld
|
|||
MWWorld::Ptr copy =
|
||||
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 =
|
||||
MWWorld::Class::get(ptr).getScript(ptr);
|
||||
|
@ -768,15 +784,6 @@ namespace MWWorld
|
|||
mLocalScripts.add(script, copy);
|
||||
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);
|
||||
}
|
||||
|
@ -825,16 +832,16 @@ namespace MWWorld
|
|||
rot.y = Ogre::Degree(y).valueRadians();
|
||||
rot.z = Ogre::Degree(z).valueRadians();
|
||||
|
||||
float *objRot = ptr.getRefData().getPosition().rot;
|
||||
if(ptr.getRefData().getBaseNode() == 0 || !mRendering->rotateObject(ptr, rot, adjust))
|
||||
if (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);
|
||||
return;
|
||||
}
|
||||
// rotate physically iff renderer confirm so
|
||||
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
|
||||
objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z;
|
||||
mPhysics->rotateObject(ptr);
|
||||
if (ptr.getRefData().getBaseNode() != 0) {
|
||||
mPhysics->rotateObject(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos)
|
||||
|
@ -871,53 +878,33 @@ namespace MWWorld
|
|||
--cellY;
|
||||
}
|
||||
|
||||
void World::doPhysics (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors,
|
||||
float duration)
|
||||
void World::doPhysics(const PtrMovementList &actors, 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
|
||||
|
||||
// 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)
|
||||
PtrMovementList::const_iterator player(actors.end());
|
||||
for(PtrMovementList::const_iterator iter(actors.begin());iter != actors.end();iter++)
|
||||
{
|
||||
// throw away wall clock time if necessary to keep the framerate above the minimum of 10 fps
|
||||
lastTick += (dt - 100);
|
||||
dt = 100;
|
||||
if(iter->first.getRefData().getHandle() == "player")
|
||||
{
|
||||
/* 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;
|
||||
lastTick += tick;
|
||||
|
||||
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
|
||||
}
|
||||
Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration,
|
||||
!isSwimming(player->first) && !isFlying(player->first));
|
||||
moveObjectImp(player->first, vec.x, vec.y, vec.z);
|
||||
}
|
||||
// the only purpose this has currently is to update the debug drawer
|
||||
mPhysEngine->stepSimulation (duration);
|
||||
}
|
||||
|
||||
bool World::toggleCollisionMode()
|
||||
|
@ -985,17 +972,6 @@ namespace MWWorld
|
|||
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)
|
||||
{
|
||||
mWorldScene->update (duration, paused);
|
||||
|
@ -1048,7 +1024,6 @@ namespace MWWorld
|
|||
// currently its here because we need to access the physics system
|
||||
float* p = mPlayer->getPlayer().getRefData().getPosition().pos;
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -1146,7 +1121,7 @@ namespace MWWorld
|
|||
}
|
||||
else
|
||||
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();
|
||||
|
||||
//std::cout << "Num facing 1 : " << mFaced1Name << std::endl;
|
||||
|
@ -1174,7 +1149,7 @@ namespace MWWorld
|
|||
}
|
||||
else
|
||||
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* node2 = mFaced2.getRefData().getBaseNode();
|
||||
|
||||
|
@ -1252,8 +1227,8 @@ namespace MWWorld
|
|||
if (!ref)
|
||||
return Vector2(0, 1);
|
||||
Ogre::SceneNode* node = ref->mData.getBaseNode();
|
||||
Vector3 dir = node->_getDerivedOrientation().yAxis();
|
||||
Vector2 d = Vector2(dir.x, dir.z);
|
||||
Vector3 dir = node->_getDerivedOrientation() * Ogre::Vector3(0,1,0);
|
||||
Vector2 d = Vector2(dir.x, dir.y);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
@ -1323,7 +1298,7 @@ namespace MWWorld
|
|||
if (isCellExterior())
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
|
@ -1331,8 +1306,8 @@ namespace MWWorld
|
|||
|
||||
ESM::Position pos = getPlayer().getPlayer().getRefData().getPosition();
|
||||
pos.pos[0] = result.second[0];
|
||||
pos.pos[1] = -result.second[2];
|
||||
pos.pos[2] = result.second[1];
|
||||
pos.pos[1] = result.second[1];
|
||||
pos.pos[2] = result.second[2];
|
||||
|
||||
Ptr dropped = copyObjectToCell(object, *cell, pos);
|
||||
PCDropped(dropped);
|
||||
|
@ -1416,25 +1391,42 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
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
|
||||
float *fpos = object.getRefData().getPosition().pos;
|
||||
Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]);
|
||||
|
||||
/// \fixme should rely on object height
|
||||
pos.z += 30;
|
||||
/// \fixme 3/4ths submerged?
|
||||
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
|
||||
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 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()
|
||||
|
@ -1451,24 +1443,21 @@ namespace MWWorld
|
|||
{
|
||||
Ptr::CellStore *currentCell = mWorldScene->getCurrentCell();
|
||||
|
||||
Ogre::Vector3 playerPos;
|
||||
float* pos = mPlayer->getPlayer ().getRefData ().getPosition ().pos;
|
||||
playerPos.x = pos[0];
|
||||
playerPos.y = pos[1];
|
||||
playerPos.z = pos[2];
|
||||
RefData &refdata = mPlayer->getPlayer().getRefData();
|
||||
Ogre::Vector3 playerPos(refdata.getPosition().pos);
|
||||
|
||||
std::pair<bool, Ogre::Vector3> hit =
|
||||
mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50);
|
||||
bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false);
|
||||
|
||||
if (!isOnGround || isUnderwater (*currentCell->mCell, playerPos))
|
||||
const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle());
|
||||
if(!physactor->getOnGround() || isUnderwater(currentCell, playerPos))
|
||||
return 2;
|
||||
|
||||
if (currentCell->mCell->mData.mFlags & ESM::Cell::NoSleep)
|
||||
if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr)
|
||||
{
|
||||
return mRendering->getAnimation(ptr);
|
||||
}
|
||||
|
||||
void World::playVideo (const std::string &name, bool allowSkipping)
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace MWRender
|
|||
{
|
||||
class SkyManager;
|
||||
class CellRender;
|
||||
class Animation;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -264,8 +265,7 @@ namespace MWWorld
|
|||
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const;
|
||||
///< Convert position to cell numbers
|
||||
|
||||
virtual void doPhysics (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors,
|
||||
float duration);
|
||||
virtual void doPhysics(const PtrMovementList &actors, float duration);
|
||||
///< Run physics simulation and modify \a world accordingly.
|
||||
|
||||
virtual bool toggleCollisionMode();
|
||||
|
@ -298,18 +298,6 @@ namespace MWWorld
|
|||
/// \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 bool placeObject (const Ptr& object, float cursorX, float cursorY);
|
||||
|
@ -326,8 +314,10 @@ namespace MWWorld
|
|||
|
||||
virtual void processChangedSettings(const Settings::CategorySettingVector& settings);
|
||||
|
||||
virtual bool isSwimming(const MWWorld::Ptr &object);
|
||||
virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos);
|
||||
virtual bool isFlying(const MWWorld::Ptr &ptr) const;
|
||||
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() {
|
||||
mRendering->togglePOV();
|
||||
|
@ -360,6 +350,9 @@ namespace MWWorld
|
|||
/// 2 - player is underwater \n
|
||||
/// 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
|
||||
virtual void playVideo(const std::string& name, bool allowSkipping);
|
||||
virtual void stopVideo();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue