diff --git a/CMakeLists.txt b/CMakeLists.txt index 220ae7ca8..4f063e261 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,8 +36,9 @@ set(GAME_HEADER game/mwinput/inputmanager.hpp) set(ESM_STORE esm_store/store.cpp esm_store/cell_store.cpp) set(ESM_STORE_HEADER esm_store/cell_store.hpp esm_store/reclists.hpp esm_store/store.hpp) -set(GAMEREND game/mwrender/mwscene.cpp game/mwrender/cell.cpp) -set(GAMEREND_HEADER game/mwrender/cell.hpp game/mwrender/mwscene.hpp) +set(GAMEREND game/mwrender/mwscene.cpp game/mwrender/cell.cpp game/mwrender/interior.cpp) +set(GAMEREND_HEADER game/mwrender/cell.hpp game/mwrender/mwscene.hpp + game/mwrender/interior.hpp) set(ESM_HEADER esm/defs.hpp esm/loadcell.hpp esm/loadfact.hpp esm/loadltex.hpp esm/loadskil.hpp diff --git a/game/main.cpp b/game/main.cpp index fadb037fd..5ebd093a4 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -10,7 +10,7 @@ #include "ogre/renderer.hpp" #include "tools/fileops.hpp" -#include "mwrender/cell.hpp" +#include "mwrender/interior.hpp" #include "mwrender/mwscene.hpp" #include "mwinput/inputmanager.hpp" @@ -59,7 +59,7 @@ void maintest (std::string dataDir, const std::string& cellName) MWRender::MWScene scene(ogre); // This connects the cell data with the rendering scene. - MWRender::CellRender rend(cell, scene); + MWRender::InteriorCellRender rend(cell, scene); // Load the cell and insert it into the renderer rend.show(); diff --git a/game/mwrender/cell.cpp b/game/mwrender/cell.cpp index 07ed1af0f..1a39922de 100644 --- a/game/mwrender/cell.cpp +++ b/game/mwrender/cell.cpp @@ -1,122 +1,42 @@ #include "cell.hpp" -#include - -#include "nifogre/ogre_nif_loader.hpp" - using namespace MWRender; -using namespace Ogre; -using namespace ESMS; -// Inserts one mesh into the scene -void CellRender::insertMesh(const std::string &mesh, // NIF file - const CellRef &ref) // Reference information +void CellRender::insertCell(const ESMS::CellStore &cell) { - // Create and place scene node for this object - SceneNode *node = base->createChildSceneNode(); - - const float *f = ref.pos.pos; - node->setPosition(f[0], f[1], f[2]); - node->setScale(ref.scale, ref.scale, ref.scale); - - // Convert MW rotation to a quaternion: - f = ref.pos.rot; - - // Rotate around X axis - Quaternion xr(Radian(-f[0]), Vector3::UNIT_X); - - // Rotate around Y axis - Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y); - - // Rotate around Z axis - Quaternion zr(Radian(-f[2]), Vector3::UNIT_Z); - - // Rotates first around z, then y, then x - node->setOrientation(xr*yr*zr); - - // Finally, load the NIF mesh and attach it to the node - NIFLoader::load(mesh); - MovableObject *ent = scene.getMgr()->createEntity(mesh); - node->attachObject(ent); -} - -void CellRender::show() -{ - // If already loaded, just make the cell visible. - if(base) - { - base->setVisible(true); - return; - } - - base = scene.getRoot()->createChildSceneNode(); - // Loop through all references in the cell - insertCellRefList (cell.activators); - insertCellRefList (cell.potions); - insertCellRefList (cell.appas); - insertCellRefList (cell.armors); - insertCellRefList (cell.books); - insertCellRefList (cell.clothes); - insertCellRefList (cell.containers); - insertCellRefList (cell.creatures); - insertCellRefList (cell.doors); - insertCellRefList (cell.ingreds); -// insertCellRefList (cell.creatureLists); -// insertCellRefList (cell.itemLists); - insertCellRefList (cell.lights); - insertCellRefList (cell.lockpicks); - insertCellRefList (cell.miscItems); - insertCellRefList (cell.npcs); - insertCellRefList (cell.probes); - insertCellRefList (cell.repairs); - insertCellRefList (cell.statics); - insertCellRefList (cell.weapons); + insertCellRefList (*this, cell.activators); + insertCellRefList (*this, cell.potions); + insertCellRefList (*this, cell.appas); + insertCellRefList (*this, cell.armors); + insertCellRefList (*this, cell.books); + insertCellRefList (*this, cell.clothes); + insertCellRefList (*this, cell.containers); + insertCellRefList (*this, cell.creatures); + insertCellRefList (*this, cell.doors); + insertCellRefList (*this, cell.ingreds); +// insertCellRefList (*this, cell.creatureLists); +// insertCellRefList (*this, cell.itemLists); + insertCellRefList (*this, cell.lights); + insertCellRefList (*this, cell.lockpicks); + insertCellRefList (*this, cell.miscItems); + insertCellRefList (*this, cell.npcs); + insertCellRefList (*this, cell.probes); + insertCellRefList (*this, cell.repairs); + insertCellRefList (*this, cell.statics); + insertCellRefList (*this, cell.weapons); } -void CellRender::hide() +template<> +void MWRender::insertObj(CellRender& cellRender, const ESMS::LiveCellRef& liveRef) { - if(base) - base->setVisible(false); + assert (liveRef.base != NULL); + const std::string &model = liveRef.base->model; + if(!model.empty()) + { + cellRender.insertBegin (liveRef.ref); + cellRender.insertMesh ("meshes\\" + model); + cellRender.insertEnd(); + } } -void CellRender::destroy() -{ - if(base) - { - base->removeAndDestroyAllChildren(); - scene.getMgr()->destroySceneNode(base); - } - - base = NULL; -} - -// Magic function from the internets. Might need this later. -/* -void Scene::DestroyAllAttachedMovableObjects( SceneNode* i_pSceneNode ) -{ - if ( !i_pSceneNode ) - { - ASSERT( false ); - return; - } - - // Destroy all the attached objects - SceneNode::ObjectIterator itObject = i_pSceneNode->getAttachedObjectIterator(); - - while ( itObject.hasMoreElements() ) - { - MovableObject* pObject = static_cast(itObject.getNext()); - i_pSceneNode->getCreator()->destroyMovableObject( pObject ); - } - - // Recurse to child SceneNodes - SceneNode::ChildNodeIterator itChild = i_pSceneNode->getChildIterator(); - - while ( itChild.hasMoreElements() ) - { - SceneNode* pChildNode = static_cast(itChild.getNext()); - DestroyAllAttachedMovableObjects( pChildNode ); - } -} -*/ diff --git a/game/mwrender/cell.hpp b/game/mwrender/cell.hpp index 3a2bae286..3bc0846c0 100644 --- a/game/mwrender/cell.hpp +++ b/game/mwrender/cell.hpp @@ -8,60 +8,52 @@ namespace MWRender { - /** - This class is responsible for inserting meshes and other - rendering objects from the given cell into the given rendering - scene. + /// Base class for cell render, that implements inserting references into a cell in a + /// cell type- and render-engine-independent way. - TODO FIXME: Doesn't do full cleanup yet. - */ class CellRender { - const ESMS::CellStore &cell; - MWScene &scene; - - /// The scene node that contains all objects belonging to this - /// cell. - Ogre::SceneNode *base; - - void insertMesh(const std::string &mesh, // NIF file - const ESMS::CellRef &ref); // Reference information - - template - void insertObj(const T& liveRef) - { - assert (liveRef.base != NULL); - const std::string &model = liveRef.base->model; - if(!model.empty()) - insertMesh ("meshes\\" + model, liveRef.ref); - } - - template - void insertCellRefList (const T& cellRefList) - { - for(typename T::List::const_iterator it = cellRefList.list.begin(); - it != cellRefList.list.end(); it++) - { - insertObj (*it); - } - } - public: - CellRender(const ESMS::CellStore &_cell, - MWScene &_scene) - : cell(_cell), scene(_scene), base(NULL) {} - ~CellRender() { destroy(); } + CellRender() {} + virtual ~CellRender() {} - /// Make the cell visible. Load the cell if necessary. - void show(); + /// start inserting a new reference. + virtual void insertBegin (const ESMS::CellRef &ref) = 0; - /// Remove the cell from rendering, but don't remove it from - /// memory. - void hide(); - - /// Destroy all rendering objects connected with this cell. - void destroy(); + /// insert a mesh related to the most recent insertBegin call. + virtual void insertMesh(const std::string &mesh) = 0; + + /// finish inserting a new reference and return a handle to it. + virtual std::string insertEnd() = 0; + + void insertCell(const ESMS::CellStore &cell); }; + + template + void insertObj(CellRender& cellRender, const T& liveRef) + { + assert (liveRef.base != NULL); + const std::string &model = liveRef.base->model; + if(!model.empty()) + { + cellRender.insertBegin (liveRef.ref); + cellRender.insertMesh ("meshes\\" + model); + cellRender.insertEnd(); + } + } + + template<> + void insertObj(CellRender& cellRender, const ESMS::LiveCellRef& liveRef); + + template + void insertCellRefList (CellRender& cellRender, const T& cellRefList) + { + for(typename T::List::const_iterator it = cellRefList.list.begin(); + it != cellRefList.list.end(); it++) + { + insertObj (cellRender, *it); + } + } } #endif diff --git a/game/mwrender/interior.cpp b/game/mwrender/interior.cpp new file mode 100644 index 000000000..bb152c4c7 --- /dev/null +++ b/game/mwrender/interior.cpp @@ -0,0 +1,124 @@ +#include "interior.hpp" + + +#include + +#include "nifogre/ogre_nif_loader.hpp" + +using namespace MWRender; +using namespace Ogre; +using namespace ESMS; + +// start inserting a new reference. + +void InteriorCellRender::insertBegin (const ESMS::CellRef &ref) +{ + assert (!insert); + + // Create and place scene node for this object + insert = base->createChildSceneNode(); + + const float *f = ref.pos.pos; + insert->setPosition(f[0], f[1], f[2]); + insert->setScale(ref.scale, ref.scale, ref.scale); + + // Convert MW rotation to a quaternion: + f = ref.pos.rot; + + // Rotate around X axis + Quaternion xr(Radian(-f[0]), Vector3::UNIT_X); + + // Rotate around Y axis + Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y); + + // Rotate around Z axis + Quaternion zr(Radian(-f[2]), Vector3::UNIT_Z); + + // Rotates first around z, then y, then x + insert->setOrientation(xr*yr*zr); +} + +// insert a mesh related to the most recent insertBegin call. + +void InteriorCellRender::insertMesh(const std::string &mesh) +{ + assert (insert); + + NIFLoader::load(mesh); + MovableObject *ent = scene.getMgr()->createEntity(mesh); + insert->attachObject(ent); +} + +// finish inserting a new reference and return a handle to it. + +std::string InteriorCellRender::insertEnd() +{ + assert (insert); + + std::string handle = insert->getName(); + + insert = 0; + + return handle; +} + +void InteriorCellRender::show() +{ + // If already loaded, just make the cell visible. + if(base) + { + base->setVisible(true); + return; + } + + base = scene.getRoot()->createChildSceneNode(); + + insertCell(cell); +} + +void InteriorCellRender::hide() +{ + if(base) + base->setVisible(false); +} + +void InteriorCellRender::destroy() +{ + if(base) + { + base->removeAndDestroyAllChildren(); + scene.getMgr()->destroySceneNode(base); + } + + base = NULL; +} + +// Magic function from the internets. Might need this later. +/* +void Scene::DestroyAllAttachedMovableObjects( SceneNode* i_pSceneNode ) +{ + if ( !i_pSceneNode ) + { + ASSERT( false ); + return; + } + + // Destroy all the attached objects + SceneNode::ObjectIterator itObject = i_pSceneNode->getAttachedObjectIterator(); + + while ( itObject.hasMoreElements() ) + { + MovableObject* pObject = static_cast(itObject.getNext()); + i_pSceneNode->getCreator()->destroyMovableObject( pObject ); + } + + // Recurse to child SceneNodes + SceneNode::ChildNodeIterator itChild = i_pSceneNode->getChildIterator(); + + while ( itChild.hasMoreElements() ) + { + SceneNode* pChildNode = static_cast(itChild.getNext()); + DestroyAllAttachedMovableObjects( pChildNode ); + } +} +*/ diff --git a/game/mwrender/interior.hpp b/game/mwrender/interior.hpp new file mode 100644 index 000000000..413be3a7b --- /dev/null +++ b/game/mwrender/interior.hpp @@ -0,0 +1,75 @@ +#ifndef _GAME_RENDER_INTERIOR_H +#define _GAME_RENDER_INTERIOR_H + +#include "cell.hpp" + +namespace MWRender +{ + /** + This class is responsible for inserting meshes and other + rendering objects from the given cell into the given rendering + scene. + + TODO FIXME: Doesn't do full cleanup yet. + */ + + class InteriorCellRender : private CellRender + { + const ESMS::CellStore &cell; + MWScene &scene; + + /// The scene node that contains all objects belonging to this + /// cell. + Ogre::SceneNode *base; + + Ogre::SceneNode *insert; + + /// start inserting a new reference. + virtual void insertBegin (const ESMS::CellRef &ref); + + /// insert a mesh related to the most recent insertBegin call. + virtual void insertMesh(const std::string &mesh); + + /// finish inserting a new reference and return a handle to it. + virtual std::string insertEnd(); + + template + void insertObj(const T& liveRef) + { + assert (liveRef.base != NULL); + const std::string &model = liveRef.base->model; + if(!model.empty()) + insertMesh ("meshes\\" + model, liveRef.ref); + } + + template + void insertCellRefList (const T& cellRefList) + { + for(typename T::List::const_iterator it = cellRefList.list.begin(); + it != cellRefList.list.end(); it++) + { + insertObj (*it); + } + } + + public: + + InteriorCellRender(const ESMS::CellStore &_cell, MWScene &_scene) + : cell(_cell), scene(_scene), base(NULL), insert(NULL) {} + + virtual ~InteriorCellRender() { destroy(); } + + /// Make the cell visible. Load the cell if necessary. + void show(); + + /// Remove the cell from rendering, but don't remove it from + /// memory. + void hide(); + + /// Destroy all rendering objects connected with this cell. + void destroy(); + }; +} + +#endif +