diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ddeaeff3..3629f91db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,11 +11,14 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) set(BSA bsa/bsa_archive.cpp bsa/bsa_file.cpp) set(BSA_HEADER bsa/bsa_archive.hpp bsa/bsa_file.hpp) -set(NIF nif/nif_file.cpp nifogre/ogre_nif_loader.cpp) +set(NIF nif/nif_file.cpp) set(NIF_HEADER nif/controlled.hpp nif/effect.hpp nif/nif_types.hpp nif/record.hpp nif/controller.hpp nif/extra.hpp nif/node.hpp nif/record_ptr.hpp nif/data.hpp nif/nif_file.hpp nif/property.hpp) - + +set(NIFOGRE nifogre/ogre_nif_loader.cpp) +set(NIFOGRE_HEADER nifogre/ogre_nif_loader.hpp) + set(TOOLS tools/stringops.cpp tools/fileops.cpp) set(TOOLS_HEADER tools/fileops.hpp tools/slice_array.hpp tools/stringops.hpp) @@ -30,7 +33,7 @@ set(INPUT_HEADER input/oismanager.hpp input/listener.hpp) set(GAME game/main.cpp game/esm_store/store.cpp game/cell_store.cpp) set(GAME_HEADER game/cell_store.hpp game/esm_store/reclists.hpp game/esm_store/store.hpp) -set(GAMEREND game/render/mwscene.cpp) +set(GAMEREND game/render/mwscene.cpp game/render/cell.cpp) set(GAMEREND_HEADER game/render/cell.hpp game/render/mwscene.hpp) # Platform specific @@ -70,6 +73,9 @@ add_executable(openmw ${TOOLS} ${TOOLS_HEADER} ${OGRE} ${OGRE_HEADER} ${INPUT} ${INPUT_HEADER} + ${NIF} ${NIF_HEADER} + ${NIFOGRE} ${NIFOGRE_HEADER} + ${MANGLE_VFS} ${GAME} ${GAME_HEADER} ${GAMEREND} ${GAMEREND_HEADER}) diff --git a/game/cell_store.hpp b/game/cell_store.hpp index 40580de49..571631091 100644 --- a/game/cell_store.hpp +++ b/game/cell_store.hpp @@ -42,7 +42,8 @@ namespace ESMS struct CellRefList { typedef LiveCellRef LiveRef; - std::list list; + typedef std::list List; + List list; // Search for the given reference in the given reclist from // ESMStore. Insert the reference into the list if a match is diff --git a/game/esm_store/reclists.hpp b/game/esm_store/reclists.hpp index e02bc95b6..ca0e47767 100644 --- a/game/esm_store/reclists.hpp +++ b/game/esm_store/reclists.hpp @@ -21,15 +21,24 @@ namespace ESMS template struct RecListT : RecList { - typedef std::map MapType; + typedef std::map MapType; MapType list; // Load one object of this type void load(ESMReader &esm, const std::string &id) { - X &ref = list[id]; - ref.load(esm); + X *ref; + + if(list.find(id) == list.end()) + { + ref = new X; + list[id] = ref; + } + else + ref = list[id]; + + ref->load(esm); } // Find the given object ID, or return NULL if not found. @@ -37,7 +46,7 @@ namespace ESMS { if(list.find(id) == list.end()) return NULL; - return &list.find(id)->second; + return list.find(id)->second; } int getSize() { return list.size(); } @@ -49,15 +58,24 @@ namespace ESMS template struct RecIDListT : RecList { - typedef std::map MapType; + typedef std::map MapType; MapType list; void load(ESMReader &esm, const std::string &id) { - X &ref = list[id]; - ref.id = id; - ref.load(esm); + X *ref; + + if(list.find(id) == list.end()) + { + ref = new X; + list[id] = ref; + } + else + ref = list[id]; + + ref->id = id; + ref->load(esm); } int getSize() { return list.size(); } @@ -73,11 +91,11 @@ namespace ESMS int getSize() { return count; } // List of interior cells. Indexed by cell name. - typedef std::map IntCells; + typedef std::map IntCells; IntCells intCells; // List of exterior cells. Indexed as extCells[gridX][gridY]. - typedef std::map > ExtCells; + typedef std::map > ExtCells; ExtCells extCells; const Cell* findInt(const std::string &id) const @@ -87,7 +105,7 @@ namespace ESMS if(it == intCells.end()) return NULL; - return &it->second; + return it->second; } void load(ESMReader &esm, const std::string &id) @@ -97,13 +115,13 @@ namespace ESMS count++; // All cells have a name record, even nameless exterior cells. - Cell cell; - cell.name = id; + Cell *cell = new Cell; + cell->name = id; // The cell itself takes care of all the hairy details - cell.load(esm); + cell->load(esm); - if(cell.data.flags & Cell::Interior) + if(cell->data.flags & Cell::Interior) { // Store interior cell by name intCells[id] = cell; @@ -111,7 +129,7 @@ namespace ESMS else { // Store exterior cells by grid position - extCells[cell.data.gridX][cell.data.gridY] = cell; + extCells[cell->data.gridX][cell->data.gridY] = cell; } } }; diff --git a/game/main.cpp b/game/main.cpp index 34b961503..ccae5461e 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -35,18 +35,22 @@ void maintest() // This parses the ESM file and loads a sample cell esm.open(esmFile); store.load(esm); + cell.loadInt("Beshara", store, esm); // Create the window ogre.createWindow("OpenMW"); - cout << "\nSetting up cell rendering (not done)\n"; + cout << "\nSetting up cell rendering\n"; // Sets up camera, scene manager etc Render::MWScene scene(ogre); - // This doesn't do anything yet. - Render::CellRender rend(cell); + // This connects the cell data with the rendering scene. + Render::CellRender rend(cell, scene); + + // Load the cell and insert it into the renderer + rend.show(); cout << "Setting up input system\n"; diff --git a/game/render/cell.cpp b/game/render/cell.cpp new file mode 100644 index 000000000..ebb766cc3 --- /dev/null +++ b/game/render/cell.cpp @@ -0,0 +1,129 @@ +#include "cell.hpp" + +#include + +#include "nifogre/ogre_nif_loader.hpp" + +using namespace Render; +using namespace Ogre; +using namespace ESMS; + +// Inserts one mesh into the scene +static void insertObj(SceneNode *base, // Parent scene node + SceneManager *mgr, // Scene manager + const std::string mesh, // NIF file + const CellRef &ref) // Reference information +{ + // 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 = mgr->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 statics in the cell + CellRefList::List::const_iterator it; + for(it = cell.statics.list.begin(); + it != cell.statics.list.end(); + it++) + { + assert(it->base != NULL); + insertObj(base, scene.getMgr(), + "meshes\\" + it->base->model, + it->ref); + } + + /* + // Containers + CellRefList::List::const_iterator it; + + for(it = cell.containers.list.begin(); + it != cell.containers.list.end(); + it++) + { + assert(it->base != NULL); + + cout << "refID = " << it->ref.refID << " x" << it->ref.scale << endl; + cout << "flags = " << it->base->flags << endl; + } + */ +} + +void CellRender::hide() +{ + if(base) + base->setVisible(false); +} + +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/render/cell.hpp b/game/render/cell.hpp index a1022a1a5..391613cb4 100644 --- a/game/render/cell.hpp +++ b/game/render/cell.hpp @@ -2,16 +2,40 @@ #define _GAME_RENDER_CELL_H #include "../cell_store.hpp" +#include "mwscene.hpp" namespace Render { + /** + This class is responsible for inserting meshes and other + rendering objects from the given cell into the given rendering + scene. + + */ class CellRender { - const ESMS::CellStore *cell; + const ESMS::CellStore &cell; + MWScene &scene; + + /// The scene node that contains all objects belonging to this + /// cell. + Ogre::SceneNode *base; public: - CellRender(const ESMS::CellStore &_cell) - : cell(&_cell) {} + CellRender(const ESMS::CellStore &_cell, + MWScene &_scene) + : cell(_cell), scene(_scene), base(NULL) {} + ~CellRender() { 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(); }; } diff --git a/game/render/mwscene.hpp b/game/render/mwscene.hpp index 47d13e328..6cbab7243 100644 --- a/game/render/mwscene.hpp +++ b/game/render/mwscene.hpp @@ -32,6 +32,9 @@ namespace Render public: MWScene(OgreRenderer &_rend); + + Ogre::SceneNode *getRoot() { return mwRoot; } + Ogre::SceneManager *getMgr() { return sceneMgr; } }; } diff --git a/nifogre/ogre_nif_loader.cpp b/nifogre/ogre_nif_loader.cpp index 1a2ef56b7..da4d6843f 100644 --- a/nifogre/ogre_nif_loader.cpp +++ b/nifogre/ogre_nif_loader.cpp @@ -46,13 +46,13 @@ using namespace Mangle::VFS; // tell Ogre to look (eg. in zip or rar files.) It's also used to // check for the existence of texture files, so we can exchange the // extension from .tga to .dds if the texture is missing. -OgreVFS *vfs; +static OgreVFS *vfs; // Singleton instance used by load() static NIFLoader g_sing; +// Makeshift error reporting system static string errName; - static void warn(const string &msg) { cout << "WARNING (NIF:" << errName << "): " << msg << endl; @@ -615,12 +615,13 @@ void NIFLoader::loadResource(Resource *resource) mesh->_setBoundingSphereRadius(10); } -MeshPtr NIFLoader::load(const char* name, const char* group) +MeshPtr NIFLoader::load(const std::string &name, + const std::string &group) { MeshManager *m = MeshManager::getSingletonPtr(); // Check if the resource already exists - ResourcePtr ptr = m->getByName(name/*, group*/); + ResourcePtr ptr = m->getByName(name, group); if(!ptr.isNull()) return MeshPtr(ptr); diff --git a/nifogre/ogre_nif_loader.hpp b/nifogre/ogre_nif_loader.hpp index 8d03118e7..96b746e16 100644 --- a/nifogre/ogre_nif_loader.hpp +++ b/nifogre/ogre_nif_loader.hpp @@ -47,7 +47,8 @@ struct NIFLoader : Ogre::ManualResourceLoader { void loadResource(Ogre::Resource *resource); - static Ogre::MeshPtr load(const char* name, const char* group="General"); + static Ogre::MeshPtr load(const std::string &name, + const std::string &group="General"); }; #endif