diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 2e9784d46f..8b542af591 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,16 +1,5 @@ #include "scene.hpp" - #include "world.hpp" -#include "ptr.hpp" -#include "environment.hpp" -#include "class.hpp" -#include "player.hpp" - -#include "refdata.hpp" -#include "globals.hpp" -#include "doingphysics.hpp" -#include "cellfunctors.hpp" -#include "environment.hpp" #include #include @@ -36,7 +25,29 @@ #include "doingphysics.hpp" #include "cellfunctors.hpp" -namespace { +namespace +{ + template + void listCellScripts (const ESMS::ESMStore& store, + ESMS::CellRefList& cellRefList, MWWorld::Scene::ScriptList& scriptList, + MWWorld::Ptr::CellStore *cell) + { + for (typename ESMS::CellRefList::List::iterator iter ( + cellRefList.list.begin()); + iter!=cellRefList.list.end(); ++iter) + { + if (!iter->base->script.empty() && iter->mData.getCount()) + { + if (const ESM::Script *script = store.scripts.find (iter->base->script)) + { + iter->mData.setLocals (*script); + + scriptList.push_back ( + std::make_pair (iter->base->script, MWWorld::Ptr (&*iter, cell))); + } + } + } + } template ESMS::LiveCellRef *searchViaHandle (const std::string& handle, @@ -56,15 +67,30 @@ namespace { } } - namespace MWWorld { - Scene::Scene(Environment& environment, World *world, MWRender::MWScene scene) : - mEnvironment(environment), mWorld(world), mScene(scene) + void Scene::insertInteriorScripts (ESMS::CellStore& cell) { + listCellScripts (mWorld->getStore(), cell.activators, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.potions, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.appas, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.armors, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.books, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.clothes, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.containers, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.creatures, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.doors, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.ingreds, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.lights, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.lockpicks, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.miscItems, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.npcs, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.probes, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.repairs, mLocalScripts, &cell); + listCellScripts (mWorld->getStore(), cell.weapons, mLocalScripts, &cell); } - + Ptr Scene::getPtr (const std::string& name, Ptr::CellStore& cell) { if (ESMS::LiveCellRef *ref = cell.activators.find (name)) @@ -129,8 +155,6 @@ namespace MWWorld return Ptr(); } - - Ptr Scene::getPtrViaHandle (const std::string& handle, Ptr::CellStore& cell) { @@ -203,10 +227,50 @@ namespace MWWorld { return iter->second; } + else + { + iter = mBufferedCells.find (store); + if (iter!=mBufferedCells.end()) + return iter->second; + } return 0; } - + + int Scene::getDaysPerMonth (int month) const + { + switch (month) + { + case 0: return 31; + case 1: return 28; + case 2: return 31; + case 3: return 30; + case 4: return 31; + case 5: return 30; + case 6: return 31; + case 7: return 31; + case 8: return 30; + case 9: return 31; + case 10: return 30; + case 11: return 31; + } + + throw std::runtime_error ("month out of range"); + } + + void Scene::removeScripts (Ptr::CellStore *cell) + { + ScriptList::iterator iter = mLocalScripts.begin(); + + while (iter!=mLocalScripts.end()) + { + if (iter->second.getCell()==cell) + mLocalScripts.erase (iter++); + else + ++iter; + } + } + void Scene::unloadCell (CellRenderCollection::iterator iter) { ListHandles functor; @@ -215,21 +279,20 @@ namespace MWWorld { // silence annoying g++ warning for (std::vector::const_iterator iter (functor.mHandles.begin()); iter!=functor.mHandles.end(); ++iter) - { - mScene.removeObject (*iter); // FIXME - } + mScene.removeObject (*iter); } + removeScripts (iter->first); mEnvironment.mMechanicsManager->dropActors (iter->first); mEnvironment.mSoundManager->stopSound (iter->first); delete iter->second; mActiveCells.erase (iter); } - + void Scene::loadCell (Ptr::CellStore *cell, MWRender::CellRender *render) { // register local scripts - mWorld->insertInteriorScripts (*cell); // FIXME + insertInteriorScripts (*cell); // This connects the cell data with the rendering scene. std::pair result = @@ -240,9 +303,20 @@ namespace MWWorld // Load the cell and insert it into the renderer result.first->second->show(); } - } - + + void Scene::playerCellChange (Ptr::CellStore *cell, const ESM::Position& position, + bool adjustPlayerPos) + { + if (adjustPlayerPos) + mWorld->getPlayer().setPos (position.pos[0], position.pos[1], position.pos[2], false); + + mWorld->getPlayer().setCell (cell); + // TODO orientation + mEnvironment.mMechanicsManager->addActor (mWorld->getPlayer().getPlayer()); + mEnvironment.mMechanicsManager->watchActor (mWorld->getPlayer().getPlayer()); + } + void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) { SuppressDoingPhysics scopeGuard; @@ -287,7 +361,7 @@ namespace MWWorld if (iter==mActiveCells.end()) { - mExteriors[std::make_pair (x, y)].loadExt (x, y, mWorld->getStore(), mWorld->getEsmReader()); + mExteriors[std::make_pair (x, y)].loadExt (x, y, mWorld->getStore(), mEsm); Ptr::CellStore *cell = &mExteriors[std::make_pair (x, y)]; loadCell (cell, new MWRender::ExteriorCellRender (*cell, mEnvironment, mScene)); @@ -316,12 +390,59 @@ namespace MWWorld playerCellChange (&mExteriors[std::make_pair (X, Y)], position, adjustPlayerPos); // Sky system - mWorld->adjustSky(); // FIXME + mWorld->adjustSky(); mCellChanged = true; - } - + + Scene::Scene (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, + const Files::Collections& fileCollections, + const std::string& master, const boost::filesystem::path& resDir, + bool newGame, Environment& environment, const std::string& encoding, World *world, MWRender::MWScene& scene) + : mSkyManager (0), mScene (scene), mCurrentCell (0), mGlobalVariables (0), + mSky (false), mCellChanged (false), mEnvironment (environment), mNextDynamicRecord (0), mWorld(world) + { + } + + Scene::~Scene() + { + for (CellRenderCollection::iterator iter (mActiveCells.begin()); + iter!=mActiveCells.end(); ++iter) + delete iter->second; + + for (CellRenderCollection::iterator iter (mBufferedCells.begin()); + iter!=mBufferedCells.end(); ++iter) + delete iter->second; + + delete mSkyManager; + delete mGlobalVariables; + } + + const Scene::ScriptList& Scene::getLocalScripts() const + { + return mLocalScripts; + } + + bool Scene::hasCellChanged() const + { + return mCellChanged; + } + + Globals::Data& Scene::getGlobalVariable (const std::string& name) + { + return (*mGlobalVariables)[name]; + } + + Globals::Data Scene::getGlobalVariable (const std::string& name) const + { + return (*mGlobalVariables)[name]; + } + + char Scene::getGlobalVariableType (const std::string& name) const + { + return mGlobalVariables->getType (name); + } + Ptr Scene::getPtr (const std::string& name, bool activeOnly) { // the player is always in an active cell. @@ -346,9 +467,8 @@ namespace MWWorld } throw std::runtime_error ("unknown ID: " + name); - } - + Ptr Scene::getPtrViaHandle (const std::string& handle) { if (mWorld->getPlayer().getPlayer().getRefData().getHandle()==handle) @@ -364,22 +484,8 @@ namespace MWWorld } throw std::runtime_error ("unknown Ogre handle: " + handle); - } - - void Scene::playerCellChange (Ptr::CellStore *cell, const ESM::Position& position, - bool adjustPlayerPos) - { - if (adjustPlayerPos) - mWorld->getPlayer().setPos (position.pos[0], position.pos[1], position.pos[2], false); - mWorld->getPlayer().setCell (cell); - // TODO orientation - mEnvironment.mMechanicsManager->addActor (mWorld->getPlayer().getPlayer()); - mEnvironment.mMechanicsManager->watchActor (mWorld->getPlayer().getPlayer()); - - } - void Scene::enable (Ptr reference) { if (!reference.getRefData().isEnabled()) @@ -391,13 +497,11 @@ namespace MWWorld render->enable (reference.getRefData().getHandle()); if (mActiveCells.find (reference.getCell())!=mActiveCells.end()) - { - Class::get (reference).enable (reference, mEnvironment); //FIXME - } + Class::get (reference).enable (reference, mEnvironment); } } } - + void Scene::disable (Ptr reference) { if (reference.getRefData().isEnabled()) @@ -416,7 +520,8 @@ namespace MWWorld } } } - + + void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { SuppressDoingPhysics scopeGuard; @@ -430,32 +535,32 @@ namespace MWWorld } // Load cell. - mInteriors[cellName].loadInt (cellName, mWorld->getStore(), mWorld->getEsmReader()); + mInteriors[cellName].loadInt (cellName, mWorld->getStore(), mEsm); Ptr::CellStore *cell = &mInteriors[cellName]; loadCell (cell, new MWRender::InteriorCellRender (*cell, mEnvironment, mScene)); // adjust player mCurrentCell = cell; - playerCellChange (cell, position, true); // FIXME + playerCellChange (cell, position); // Sky system - mWorld->adjustSky(); // FIXME + mWorld->adjustSky(); mCellChanged = true; //currentRegion->name = ""; } - + void Scene::changeToExteriorCell (const ESM::Position& position) { int x = 0; int y = 0; - mWorld->positionToIndex (position.pos[0], position.pos[1], x, y); + positionToIndex (position.pos[0], position.pos[1], x, y); changeCell (x, y, position, true); } - + const ESM::Cell *Scene::getExterior (const std::string& cellName) const { // first try named cells @@ -479,7 +584,25 @@ namespace MWWorld return 0; } - + + void Scene::markCellAsUnchanged() + { + mCellChanged = false; + } + + std::string Scene::getFacedHandle() + { + // FIXME + /*std::pair result = mScene.getFacedHandle (*this); + + if (result.first.empty() || + result.second>getStore().gameSettings.find ("iMaxActivateDist")->i) + return ""; + + return result.first;*/ + return std::string(""); + } + void Scene::deleteObject (Ptr ptr) { if (ptr.getRefData().getCount()>0) @@ -502,7 +625,7 @@ namespace MWWorld } } } - + void Scene::moveObject (Ptr ptr, float x, float y, float z) { ptr.getCellRef().pos.pos[0] = x; @@ -519,7 +642,7 @@ namespace MWWorld int cellX = 0; int cellY = 0; - mWorld->positionToIndex (x, y, cellX, cellY); + positionToIndex (x, y, cellX, cellY); if (mCurrentCell->cell->data.gridX!=cellX || mCurrentCell->cell->data.gridY!=cellY) { @@ -536,4 +659,50 @@ namespace MWWorld // TODO cell change for non-player ref } + void Scene::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const + { + const int cellSize = 8192; + + x = cellSize * cellX; + y = cellSize * cellY; + + if (centre) + { + x += cellSize/2; + y += cellSize/2; + } + } + + void Scene::positionToIndex (float x, float y, int &cellX, int &cellY) const + { + const int cellSize = 8192; + + cellX = static_cast (x/cellSize); + + if (x<0) + --cellX; + + cellY = static_cast (y/cellSize); + + if (y<0) + --cellY; + } + + void Scene::doPhysics (const std::vector >& actors, + float duration) + { + // FIXME + // mScene.doPhysics (duration, *this, actors); + } + + bool Scene::toggleCollisionMode() + { + return mScene.toggleCollisionMode(); + } + + bool Scene::toggleRenderMode (RenderMode mode) + { + return mScene.toggleRenderMode (mode); + } } + diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 97c04ebcf0..3533ee532e 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -1,11 +1,36 @@ #ifndef GAME_MWWORLD_SCENE_H #define GAME_MWWORLD_SCENE_H +#include +#include + +#include + #include -#include "ptr.hpp" -#include "environment.hpp" + #include "../mwrender/mwscene.hpp" +#include "refdata.hpp" +#include "ptr.hpp" +#include "globals.hpp" + +#include + +namespace Ogre +{ + class Vector3; +} + +namespace ESM +{ + struct Position; +} + +namespace Files +{ + class Collections; +} + namespace Render { class OgreRenderer; @@ -19,47 +44,145 @@ namespace MWRender namespace MWWorld { + class Environment; + class Player; + + /// \brief The game world and its visual representation class Scene { + public: - Scene(Environment& environment, World *world, MWRender::MWScene scene); - + typedef std::list > ScriptList; + + enum RenderMode + { + Render_CollisionDebug + }; + private: - + typedef std::map CellRenderCollection; - - CellRenderCollection mActiveCells; + + MWRender::SkyManager* mSkyManager; + MWRender::MWScene mScene; Ptr::CellStore *mCurrentCell; // the cell, the player is in + CellRenderCollection mActiveCells; + CellRenderCollection mBufferedCells; // loaded, but not active (buffering not implementd yet) + ESM::ESMReader mEsm; + ESMS::ESMStore mStore; std::map mInteriors; std::map, Ptr::CellStore> mExteriors; - Environment& mEnvironment; - World *mWorld; - MWRender::MWScene mScene; + ScriptList mLocalScripts; + MWWorld::Globals *mGlobalVariables; + bool mSky; bool mCellChanged; - - Ptr getPtr (const std::string& name, Ptr::CellStore& cell); - Ptr getPtrViaHandle (const std::string& handle, Ptr::CellStore& cell); - - public: - - MWRender::CellRender *searchRender (Ptr::CellStore *store); - - void unloadCell (CellRenderCollection::iterator iter); - void loadCell (Ptr::CellStore *cell, MWRender::CellRender *render); - void changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos); - Ptr getPtr (const std::string& name, bool activeOnly); - Ptr getPtrViaHandle (const std::string& handle); - void playerCellChange (Ptr::CellStore *cell, const ESM::Position& position, bool adjustPlayerPos); - void enable (Ptr reference); - void disable (Ptr reference); - void changeToInteriorCell (const std::string& cellName, const ESM::Position& position); - void changeToExteriorCell (const ESM::Position& position); - const ESM::Cell *getExterior (const std::string& cellName) const; - void deleteObject (Ptr ptr); - void moveObject (Ptr ptr, float x, float y, float z); - }; + Environment& mEnvironment; + int mNextDynamicRecord; + World *mWorld; + OEngine::Physic::PhysicEngine* mPhysEngine; + + // not implemented + Scene (const Scene&); + Scene& operator= (const Scene&); + + Ptr getPtr (const std::string& name, Ptr::CellStore& cellStore); + + Ptr getPtrViaHandle (const std::string& handle, Ptr::CellStore& cellStore); + + MWRender::CellRender *searchRender (Ptr::CellStore *store); + + int getDaysPerMonth (int month) const; + + void removeScripts (Ptr::CellStore *cell); + + void unloadCell (CellRenderCollection::iterator iter); + + void loadCell (Ptr::CellStore *cell, MWRender::CellRender *render); + + void playerCellChange (Ptr::CellStore *cell, const ESM::Position& position, + bool adjustPlayerPos = true); + + void changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos); + ///< Move from exterior to interior or from interior cell to a different + /// interior cell. + public: + + Scene (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, + const Files::Collections& fileCollections, + const std::string& master, const boost::filesystem::path& resDir, bool newGame, + Environment& environment, const std::string& encoding, World* world, MWRender::MWScene& scene); + + ~Scene(); + + void insertInteriorScripts (ESMS::CellStore& cell); + + MWWorld::Player& getPlayer(); + + const ESMS::ESMStore& getStore() const; + + const ScriptList& getLocalScripts() const; + ///< Names and local variable state of all local scripts in active cells. + + bool hasCellChanged() const; + ///< Has the player moved to a different cell, since the last frame? + + Globals::Data& getGlobalVariable (const std::string& name); + + Globals::Data getGlobalVariable (const std::string& name) const; + + char getGlobalVariableType (const std::string& name) const; + ///< Return ' ', if there is no global variable with this name. + + Ptr getPtr (const std::string& name, bool activeOnly); + ///< Return a pointer to a liveCellRef with the given name. + /// \param activeOnly do non search inactive cells. + + Ptr getPtrViaHandle (const std::string& handle); + ///< Return a pointer to a liveCellRef with the given Ogre handle. + + void enable (Ptr reference); + + void disable (Ptr reference); + + void changeToInteriorCell (const std::string& cellName, const ESM::Position& position); // FIXME: YEAH! + ///< Move to interior cell. + + void changeToExteriorCell (const ESM::Position& position); // FIXME: YEAH! + ///< Move to exterior cell. + + const ESM::Cell *getExterior (const std::string& cellName) const; // FIXME: YEAH! + ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. + + void markCellAsUnchanged(); // FIXME: YEAH! + + std::string getFacedHandle(); + ///< Return handle of the object the player is looking at + + void deleteObject (Ptr ptr); // FIXME: DONT KNOW + + void moveObject (Ptr ptr, float x, float y, float z); // FIXME: DONT KNOW + + void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const; + ///< Convert cell numbers to position. + + void positionToIndex (float x, float y, int &cellX, int &cellY) const; + ///< Convert position to cell numbers + + void doPhysics (const std::vector >& actors, + float duration); + ///< Run physics simulation and modify \a world accordingly. + + bool toggleCollisionMode(); + ///< Toggle collision mode for player. If disabled player object should ignore + /// collisions and gravity. + ///< \return Resulting mode + + bool toggleRenderMode (RenderMode mode); + ///< Toggle a render mode. + ///< \return Resulting mode + }; } #endif diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 75d9f35bc1..9c2e071758 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -18,7 +18,6 @@ #include "environment.hpp" #include "class.hpp" #include "player.hpp" -#include "scene.hpp" #include "refdata.hpp" #include "globals.hpp" @@ -221,7 +220,6 @@ namespace MWWorld MWRender::CellRender *World::searchRender (Ptr::CellStore *store) { - return mWorldScene->searchRender(store); CellRenderCollection::iterator iter = mActiveCells.find (store); if (iter!=mActiveCells.end()) @@ -274,7 +272,6 @@ namespace MWWorld void World::unloadCell (CellRenderCollection::iterator iter) { - return mWorldScene->unloadCell(iter); ListHandles functor; iter->first->forEach(functor); @@ -293,7 +290,6 @@ namespace MWWorld void World::loadCell (Ptr::CellStore *cell, MWRender::CellRender *render) { - return mWorldScene->loadCell(cell, render); // register local scripts insertInteriorScripts (*cell); @@ -333,7 +329,6 @@ namespace MWWorld void World::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) { - return mWorldScene->changeCell(X, Y, position, adjustPlayerPos); SuppressDoingPhysics scopeGuard; // remove active @@ -417,7 +412,6 @@ namespace MWWorld : mSkyManager (0), mScene (renderer,physEng), mPlayer (0), mCurrentCell (0), mGlobalVariables (0), mSky (false), mCellChanged (false), mEnvironment (environment), mNextDynamicRecord (0) { - mWorldScene = new Scene(environment, this, mScene); mPhysEngine = physEng; boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master)); @@ -445,6 +439,8 @@ namespace MWWorld MWRender::SkyManager::create(renderer.getWindow(), mScene.getCamera(), resDir); mPhysEngine = physEng; + + mWorldScene = new Scene(renderer, physEng, fileCollections, master, resDir, newGame, environment, encoding, this, mScene); } World::~World() @@ -504,7 +500,6 @@ namespace MWWorld Ptr World::getPtr (const std::string& name, bool activeOnly) { - return mWorldScene->getPtr(name, activeOnly); // the player is always in an active cell. if (name=="player") { @@ -531,7 +526,6 @@ namespace MWWorld Ptr World::getPtrViaHandle (const std::string& handle) { - return mWorldScene->getPtrViaHandle(handle); if (mPlayer->getPlayer().getRefData().getHandle()==handle) return mPlayer->getPlayer(); @@ -549,7 +543,6 @@ namespace MWWorld void World::enable (Ptr reference) { - return mWorldScene->enable(reference); if (!reference.getRefData().isEnabled()) { reference.getRefData().enable(); @@ -566,7 +559,6 @@ namespace MWWorld void World::disable (Ptr reference) { - return mWorldScene->disable(reference); if (reference.getRefData().isEnabled()) { reference.getRefData().disable(); @@ -708,7 +700,6 @@ namespace MWWorld void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { - return mWorldScene->changeToInteriorCell(cellName, position); SuppressDoingPhysics scopeGuard; // remove active @@ -738,7 +729,6 @@ namespace MWWorld void World::changeToExteriorCell (const ESM::Position& position) { - return mWorldScene->changeToExteriorCell(position); int x = 0; int y = 0; @@ -749,7 +739,6 @@ namespace MWWorld const ESM::Cell *World::getExterior (const std::string& cellName) const { - return mWorldScene->getExterior(cellName); // first try named cells if (const ESM::Cell *cell = mStore.cells.searchExtByName (cellName)) return cell; @@ -790,7 +779,6 @@ namespace MWWorld void World::deleteObject (Ptr ptr) { - return mWorldScene->deleteObject(ptr); if (ptr.getRefData().getCount()>0) { ptr.getRefData().setCount (0); @@ -814,7 +802,6 @@ namespace MWWorld void World::moveObject (Ptr ptr, float x, float y, float z) { - return mWorldScene->moveObject(ptr, x, y, z); ptr.getCellRef().pos.pos[0] = x; ptr.getCellRef().pos.pos[1] = y; ptr.getCellRef().pos.pos[2] = z;