diff --git a/CMakeLists.txt b/CMakeLists.txt index 538e6a2fb..071784c73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries # Sound source selection option(USE_FFMPEG "use ffmpeg for sound" OFF) +option(USE_AUDIERE "use audiere for sound" OFF) option(USE_MPG123 "use mpg123 + libsndfile for sound" ON) find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems") @@ -133,6 +134,13 @@ if (USE_FFMPEG) set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG) endif (USE_FFMPEG) +if (USE_AUDIERE) + find_package(Audiere REQUIRED) + set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${AUDIERE_INCLUDE_DIR}) + set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${AUDIERE_LIBRARY}) + set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_AUDIERE) +endif (USE_AUDIERE) + if (USE_MPG123) find_package(MPG123 REQUIRED) find_package(SNDFILE REQUIRED) @@ -241,8 +249,14 @@ if (APPLE) "${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY) # prepare plugins - if (${CMAKE_BUILD_TYPE} MATCHES "Release" OR - ${CMAKE_BUILD_TYPE} MATCHES "RelWithDebugInfo") + if (${CMAKE_BUILD_TYPE} MATCHES "Release") + set(OPENMW_RELEASE_BUILD 1) + endif() + if (${CMAKE_BUILD_TYPE} MATCHES "RelWithDebugInfo") + set(OPENMW_RELEASE_BUILD 1) + endif() + + if (${OPENMW_RELEASE_BUILD}) set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) else() set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3dabc9ac8..873c23a9b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -39,7 +39,7 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanager openal_output mpgsnd_decoder ffmpeg_decoder + soundmanager openal_output audiere_decoder mpgsnd_decoder ffmpeg_decoder ) add_openmw_dir (mwworld diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 38050e53b..2dab53ecc 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -82,12 +82,20 @@ void OMW::Engine::updateFocusReport (float duration) if (!handle.empty()) { - MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); + // the faced handle is not updated immediately, so on a cell change it might + // point to an object that doesn't exist anymore + // therefore, we are catching the "Unknown Ogre handle" exception that occurs in this case + try + { + MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); - if (!ptr.isEmpty()){ - name = MWWorld::Class::get (ptr).getName (ptr); + if (!ptr.isEmpty()){ + name = MWWorld::Class::get (ptr).getName (ptr); + } } + catch (std::runtime_error& e) + {} } if (name!=mFocusName) @@ -420,10 +428,21 @@ void OMW::Engine::activate() if (handle.empty()) return; - MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); + // the faced handle is not updated immediately, so on a cell change it might + // point to an object that doesn't exist anymore + // therefore, we are catching the "Unknown Ogre handle" exception that occurs in this case + MWWorld::Ptr ptr; + try + { + ptr = mEnvironment.mWorld->getPtrViaHandle (handle); - if (ptr.isEmpty()) + if (ptr.isEmpty()) + return; + } + catch (std::runtime_error&) + { return; + } MWScript::InterpreterContext interpreterContext (mEnvironment, &ptr.getRefData().getLocals(), ptr); diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 422185273..d42672179 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -2,33 +2,283 @@ #include -#include "OgreRoot.h" -#include "OgreRenderWindow.h" -#include "OgreSceneManager.h" -#include "OgreViewport.h" -#include "OgreCamera.h" -#include "OgreTextureManager.h" +#include +#include +#include +#include #include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone +#include "../mwworld/environment.hpp" #include "../mwworld/ptr.hpp" #include +#include #include "player.hpp" -using namespace MWRender; using namespace Ogre; -Debugging::Debugging(OEngine::Physic::PhysicEngine* engine){ - eng = engine; +namespace MWRender +{ + +static const std::string PATHGRID_POINT_MATERIAL = "pathgridPointMaterial"; +static const std::string PATHGRID_LINE_MATERIAL = "pathgridLineMaterial"; +static const std::string DEBUGGING_GROUP = "debugging"; +static const int POINT_MESH_BASE = 35; + +void Debugging::createGridMaterials() +{ + if (mGridMatsCreated) return; + + if (MaterialManager::getSingleton().getByName(PATHGRID_LINE_MATERIAL, DEBUGGING_GROUP).isNull()) + { + MaterialPtr lineMatPtr = MaterialManager::getSingleton().create(PATHGRID_LINE_MATERIAL, DEBUGGING_GROUP); + lineMatPtr->setReceiveShadows(false); + lineMatPtr->getTechnique(0)->setLightingEnabled(true); + lineMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,1,0,0); + lineMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,1,0); + lineMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,1,0); + } + + if (MaterialManager::getSingleton().getByName(PATHGRID_POINT_MATERIAL, DEBUGGING_GROUP).isNull()) + { + MaterialPtr pointMatPtr = MaterialManager::getSingleton().create(PATHGRID_POINT_MATERIAL, DEBUGGING_GROUP); + pointMatPtr->setReceiveShadows(false); + pointMatPtr->getTechnique(0)->setLightingEnabled(true); + pointMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,0,0,0); + pointMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,0,0); + pointMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,0,0); + } + mGridMatsCreated = true; +} + +void Debugging::destroyGridMaterials() +{ + if (mGridMatsCreated) + { + MaterialManager::getSingleton().remove(PATHGRID_POINT_MATERIAL); + MaterialManager::getSingleton().remove(PATHGRID_LINE_MATERIAL); + mGridMatsCreated = false; + } +} + +ManualObject *Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) +{ + ManualObject *result = mSceneMgr->createManualObject(); + + result->begin(PATHGRID_LINE_MATERIAL, RenderOperation::OT_LINE_LIST); + for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid->edges.begin(); + it != pathgrid->edges.end(); + it++) + { + const ESM::Pathgrid::Edge &edge = *it; + const ESM::Pathgrid::Point &p1 = pathgrid->points[edge.v0], &p2 = pathgrid->points[edge.v1]; + Vector3 direction = (Vector3(p2.x, p2.y, p2.z) - Vector3(p1.x, p1.y, p1.z)); + Vector3 lineDisplacement = direction.crossProduct(Vector3::UNIT_Z).normalisedCopy(); + lineDisplacement = lineDisplacement * POINT_MESH_BASE + + Vector3(0, 0, 10); // move lines up a little, so they will be less covered by meshes/landscape + result->position(Vector3(p1.x, p1.y, p1.z) + lineDisplacement); + result->position(Vector3(p2.x, p2.y, p2.z) + lineDisplacement); + } + result->end(); + + return result; +} + +ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) +{ + ManualObject *result = mSceneMgr->createManualObject(); + const float height = POINT_MESH_BASE * sqrtf(2); + + result->begin(PATHGRID_POINT_MATERIAL, RenderOperation::OT_TRIANGLE_STRIP); + + bool first = true; + uint32 startIndex = 0; + for(ESM::Pathgrid::PointList::const_iterator it = pathgrid->points.begin(); + it != pathgrid->points.end(); + it++, startIndex += 6) + { + Vector3 pointPos(it->x, it->y, it->z); + + if (!first) + { + // degenerate triangle from previous octahedron + result->index(startIndex - 4); // 2nd point of previous octahedron + result->index(startIndex); // start point of current octahedron + } + + result->position(pointPos + Vector3(0, 0, height)); // 0 + result->position(pointPos + Vector3(-POINT_MESH_BASE, -POINT_MESH_BASE, 0)); // 1 + result->position(pointPos + Vector3(POINT_MESH_BASE, -POINT_MESH_BASE, 0)); // 2 + result->position(pointPos + Vector3(POINT_MESH_BASE, POINT_MESH_BASE, 0)); // 3 + result->position(pointPos + Vector3(-POINT_MESH_BASE, POINT_MESH_BASE, 0)); // 4 + result->position(pointPos + Vector3(0, 0, -height)); // 5 + + result->index(startIndex + 0); + result->index(startIndex + 1); + result->index(startIndex + 2); + result->index(startIndex + 5); + result->index(startIndex + 3); + result->index(startIndex + 4); + // degenerates + result->index(startIndex + 4); + result->index(startIndex + 5); + result->index(startIndex + 5); + // end degenerates + result->index(startIndex + 1); + result->index(startIndex + 4); + result->index(startIndex + 0); + result->index(startIndex + 3); + result->index(startIndex + 2); + + first = false; + } + + result->end(); + + return result; +} + +Debugging::Debugging(SceneNode *mwRoot, MWWorld::Environment &env, OEngine::Physic::PhysicEngine *engine) : + mMwRoot(mwRoot), mEnvironment(env), mEngine(engine), + mSceneMgr(mwRoot->getCreator()), + mPathgridEnabled(false), + mInteriorPathgridNode(NULL), mPathGridRoot(NULL), + mGridMatsCreated(false) +{ + ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP); +} + +Debugging::~Debugging() +{ + if (mPathgridEnabled) + { + togglePathgrid(); + } + + ResourceGroupManager::getSingleton().destroyResourceGroup(DEBUGGING_GROUP); } bool Debugging::toggleRenderMode (int mode){ - switch (mode) + switch (mode) { case MWWorld::World::Render_CollisionDebug: - return eng->toggleDebugRendering(); + + return mEngine->toggleDebugRendering(); + + case MWWorld::World::Render_Pathgrid: + togglePathgrid(); + return mPathgridEnabled; } return false; } + +void Debugging::cellAdded(MWWorld::Ptr::CellStore *store) +{ + mActiveCells.push_back(store); + if (mPathgridEnabled) + enableCellPathgrid(store); +} + +void Debugging::cellRemoved(MWWorld::Ptr::CellStore *store) +{ + mActiveCells.erase(std::remove(mActiveCells.begin(), mActiveCells.end(), store), mActiveCells.end()); + if (mPathgridEnabled) + disableCellPathgrid(store); +} + +void Debugging::togglePathgrid() +{ + mPathgridEnabled = !mPathgridEnabled; + if (mPathgridEnabled) + { + createGridMaterials(); + + // add path grid meshes to already loaded cells + mPathGridRoot = mMwRoot->createChildSceneNode(); + for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); it++) + { + enableCellPathgrid(*it); + } + } + else + { + // remove path grid meshes from already loaded cells + for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); it++) + { + disableCellPathgrid(*it); + } + mPathGridRoot->removeAndDestroyAllChildren(); + mSceneMgr->destroySceneNode(mPathGridRoot); + mPathGridRoot = NULL; + destroyGridMaterials(); + } +} + +void Debugging::enableCellPathgrid(MWWorld::Ptr::CellStore *store) +{ + ESM::Pathgrid *pathgrid = mEnvironment.mWorld->getStore().pathgrids.search(*store->cell); + if (!pathgrid) return; + + Vector3 cellPathGridPos(0, 0, 0); + if (store->cell->isExterior()) + { + cellPathGridPos.x = store->cell->data.gridX * ESM::Land::REAL_SIZE; + cellPathGridPos.y = store->cell->data.gridY * ESM::Land::REAL_SIZE; + } + SceneNode *cellPathGrid = mPathGridRoot->createChildSceneNode(cellPathGridPos); + cellPathGrid->attachObject(createPathgridLines(pathgrid)); + cellPathGrid->attachObject(createPathgridPoints(pathgrid)); + + if (store->cell->isExterior()) + { + mExteriorPathgridNodes[std::make_pair(store->cell->data.gridX, store->cell->data.gridY)] = cellPathGrid; + } + else + { + assert(mInteriorPathgridNode == NULL); + mInteriorPathgridNode = cellPathGrid; + } +} + +void Debugging::disableCellPathgrid(MWWorld::Ptr::CellStore *store) +{ + if (store->cell->isExterior()) + { + ExteriorPathgridNodes::iterator it = + mExteriorPathgridNodes.find(std::make_pair(store->cell->data.gridX, store->cell->data.gridY)); + if (it != mExteriorPathgridNodes.end()) + { + destroyCellPathgridNode(it->second); + mExteriorPathgridNodes.erase(it); + } + } + else + { + if (mInteriorPathgridNode) + { + destroyCellPathgridNode(mInteriorPathgridNode); + mInteriorPathgridNode = NULL; + } + } +} + +void Debugging::destroyCellPathgridNode(SceneNode *node) +{ + mPathGridRoot->removeChild(node); + destroyAttachedObjects(node); + mSceneMgr->destroySceneNode(node); +} + +void Debugging::destroyAttachedObjects(SceneNode *node) +{ + SceneNode::ObjectIterator objIt = node->getAttachedObjectIterator(); + while (objIt.hasMoreElements()) + { + MovableObject *mesh = static_cast(objIt.getNext()); + mSceneMgr->destroyMovableObject(mesh); + } +} + +} diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index b48cfaee2..ebf3884dc 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -4,6 +4,7 @@ #include #include #include +#include "../mwworld/ptr.hpp" #include #include @@ -22,20 +23,58 @@ namespace Ogre namespace MWWorld { class World; + class Environment; } namespace MWRender { class Player; - class Debugging{ - OEngine::Physic::PhysicEngine* eng; + class Debugging + { + OEngine::Physic::PhysicEngine* mEngine; + Ogre::SceneManager *mSceneMgr; + MWWorld::Environment& mEnvironment; + // Path grid stuff + bool mPathgridEnabled; - public: - Debugging(OEngine::Physic::PhysicEngine* engine); - bool toggleRenderMode (int mode); - }; + void togglePathgrid(); + + typedef std::vector CellList; + CellList mActiveCells; + + Ogre::SceneNode *mMwRoot; + + Ogre::SceneNode *mPathGridRoot; + + typedef std::map, Ogre::SceneNode *> ExteriorPathgridNodes; + ExteriorPathgridNodes mExteriorPathgridNodes; + Ogre::SceneNode *mInteriorPathgridNode; + + void enableCellPathgrid(MWWorld::Ptr::CellStore *store); + void disableCellPathgrid(MWWorld::Ptr::CellStore *store); + + // utility + void destroyCellPathgridNode(Ogre::SceneNode *node); + void destroyAttachedObjects(Ogre::SceneNode *node); + + // materials + bool mGridMatsCreated; + void createGridMaterials(); + void destroyGridMaterials(); + + // path grid meshes + Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid); + Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid); + public: + Debugging(Ogre::SceneNode* mwRoot, MWWorld::Environment &env, OEngine::Physic::PhysicEngine *engine); + ~Debugging(); + bool toggleRenderMode (int mode); + + void cellAdded(MWWorld::Ptr::CellStore* store); + void cellRemoved(MWWorld::Ptr::CellStore* store); + }; } diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 29cfe33fe..781b522b6 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -5,13 +5,14 @@ #include #include #include +#include using namespace MWRender; using namespace Ogre; OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) : mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mSingleObjectQuery(0), mActiveQuery(0), - mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false), + mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false), mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mDoQuery2(false), mBBNode(0) { @@ -84,7 +85,6 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mRendering->getScene()->addRenderObjectListener(this); mRendering->getScene()->addRenderQueueListener(this); mDoQuery = true; - mDoQuery2 = true; } OcclusionQuery::~OcclusionQuery() @@ -100,7 +100,7 @@ bool OcclusionQuery::supported() return mSupported; } -void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, +void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, const LightList* pLightList, bool suppressRenderStateChanges) { // The following code activates and deactivates the occlusion queries @@ -134,7 +134,7 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass mActiveQuery = mSingleObjectQuery; mObjectWasVisible = true; } - + if (mActiveQuery != NULL) mActiveQuery->beginOcclusionQuery(); } @@ -195,7 +195,6 @@ void OcclusionQuery::update(float duration) // Stop occlusion queries until we get their information // (may not happen on the same frame they are requested in) mDoQuery = false; - mDoQuery2 = false; if (!mSunTotalAreaQuery->isStillOutstanding() && !mSunVisibleAreaQuery->isStillOutstanding() @@ -264,3 +263,40 @@ bool OcclusionQuery::getTestResult() return mTestResult; } + +bool OcclusionQuery::isPotentialOccluder(Ogre::SceneNode* node) +{ + bool result = false; + for (unsigned int i=0; i < node->numAttachedObjects(); ++i) + { + MovableObject* ob = node->getAttachedObject(i); + std::string type = ob->getMovableType(); + if (type == "Entity") + { + Entity* ent = static_cast(ob); + for (unsigned int j=0; j < ent->getNumSubEntities(); ++j) + { + // if any sub entity has a material with depth write off, + // consider the object as not an occluder + MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); + + Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements()) + { + Technique* tech = techIt.getNext(); + Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements()) + { + Pass* pass = passIt.getNext(); + + if (pass->getDepthWriteEnabled() == false) + return false; + else + result = true; + } + } + } + } + } + return result; +} diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp index b655c8e46..c76fcccd0 100644 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ b/apps/openmw/mwrender/occlusionquery.hpp @@ -46,6 +46,14 @@ namespace MWRender */ bool occlusionTestPending(); + /** + * Checks if the objects held by this scenenode + * can be considered as potential occluders + * (which might not be the case when transparency is involved) + * @param Scene node + */ + bool isPotentialOccluder(Ogre::SceneNode* node); + /** * @return true if the object tested in the last request was occluded */ diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6cdd8eb57..18675203c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -20,7 +20,7 @@ using namespace Ogre; namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment) -:mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0), mDebugging(engine) + :mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0) { mRendering.createScene("PlayerCam", 55, 5); mTerrainManager = new TerrainManager(mRendering.getScene(), @@ -52,7 +52,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const Ogre::SceneNode *cameraYawNode = playerNode->createChildSceneNode(); Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode(); cameraPitchNode->attachObject(mRendering.getCamera()); - + //mSkyManager = 0; mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment); @@ -63,6 +63,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mSun = 0; + mDebugging = new Debugging(mMwRoot, environment, engine); mLocalMap = new MWRender::LocalMap(&mRendering, &environment); } @@ -71,6 +72,7 @@ RenderingManager::~RenderingManager () //TODO: destroy mSun? delete mPlayer; delete mSkyManager; + delete mDebugging; delete mTerrainManager; delete mLocalMap; delete mOcclusionQuery; @@ -101,6 +103,7 @@ void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store) { mObjects.removeCell(store); mActors.removeCell(store); + mDebugging->cellRemoved(store); if (store->cell->isExterior()) mTerrainManager->cellRemoved(store); } @@ -122,6 +125,7 @@ void RenderingManager::toggleWater() void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) { mObjects.buildStaticGeometry (*store); + mDebugging->cellAdded(store); if (store->cell->isExterior()) mTerrainManager->cellAdded(store); } @@ -188,7 +192,7 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ } else removeWater(); - + } void RenderingManager::setWaterHeight(const float height) @@ -226,7 +230,7 @@ void RenderingManager::skySetDate (int day, int month) int RenderingManager::skyGetMasserPhase() const { - + return mSkyManager->getMasserPhase(); } @@ -242,8 +246,8 @@ void RenderingManager::skySetMoonColour (bool red){ bool RenderingManager::toggleRenderMode(int mode) { - if (mode == MWWorld::World::Render_CollisionDebug) - return mDebugging.toggleRenderMode(mode); + if (mode != MWWorld::World::Render_Wireframe) + return mDebugging->toggleRenderMode(mode); else // if (mode == MWWorld::World::Render_Wireframe) { if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) @@ -268,10 +272,10 @@ void RenderingManager::configureFog(ESMS::CellStore &mCell) } void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) -{ +{ /// \todo make the viewing distance and fog start/end configurable - // right now we load 3x3 cells, so the maximum viewing distance we + // right now we load 3x3 cells, so the maximum viewing distance we // can allow (to prevent objects suddenly popping up) equals: // 8192 * 0.69 // ^ cell size ^ minimum density value used (clear weather) @@ -279,7 +283,7 @@ void RenderingManager::configureFog(const float density, const Ogre::ColourValue float high = 5652.48 / density; mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high); - + mRendering.getCamera()->setFarClipDistance ( high ); mRendering.getViewport()->setBackgroundColour (colour); } @@ -382,10 +386,10 @@ void RenderingManager::sunDisable() void RenderingManager::setSunDirection(const Ogre::Vector3& direction) { - // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), + // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), // then convert from MW to ogre coordinates (swap y,z and make y negative) if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.z, direction.y)); - + mSkyManager->setSunDirection(direction); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 01decf57c..81907a938 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -174,7 +174,8 @@ class RenderingManager: private RenderingInterface { OEngine::Physic::PhysicEngine* mPhysicsEngine; MWRender::Player *mPlayer; - MWRender::Debugging mDebugging; + + MWRender::Debugging *mDebugging; MWRender::LocalMap* mLocalMap; }; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index eede88ca7..df955ec19 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -128,4 +128,5 @@ op 0x2000142: SetWaterLevel op 0x2000143: ModWaterLevel op 0x2000144: ToggleWater, twa op 0x2000145: ToggleFogOfWar (tfow) -opcodes 0x2000146-0x3ffffff unused +op 0x2000146: TogglePathgrid +opcodes 0x2000147-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 5109319ed..a0770b9a8 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -106,7 +106,7 @@ namespace MWScript "Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); } }; - + class OpToggleWireframe : public Interpreter::Opcode0 { public: @@ -123,7 +123,23 @@ namespace MWScript "Wireframe Rendering -> On" : "Wireframe Rendering -> Off"); } }; - + + class OpTogglePathgrid : public Interpreter::Opcode0 + { + public: + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = + static_cast (runtime.getContext()); + + bool enabled = + context.getWorld().toggleRenderMode (MWWorld::World::Render_Pathgrid); + + context.report (enabled ? + "Path Grid rendering -> On" : "Path Grid Rendering -> Off"); + } + }; + class OpFadeIn : public Interpreter::Opcode0 { public: @@ -135,11 +151,11 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - + context.getWorld().getFader()->fadeIn(time); } }; - + class OpFadeOut : public Interpreter::Opcode0 { public: @@ -151,11 +167,11 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - + context.getWorld().getFader()->fadeOut(time); } }; - + class OpFadeTo : public Interpreter::Opcode0 { public: @@ -167,10 +183,10 @@ namespace MWScript Interpreter::Type_Float alpha = runtime[0].mFloat; runtime.pop(); - + Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - + context.getWorld().getFader()->fadeTo(alpha, time); } }; @@ -201,6 +217,7 @@ namespace MWScript const int opcodeFadeOut = 0x200013d; const int opcodeFadeTo = 0x200013e; const int opcodeToggleWater = 0x2000144; + const int opcodeTogglePathgrid = 0x2000146; void registerExtensions (Compiler::Extensions& extensions) { @@ -220,6 +237,8 @@ namespace MWScript extensions.registerInstruction ("fadeto", "ff", opcodeFadeTo); extensions.registerInstruction ("togglewater", "", opcodeToggleWater); extensions.registerInstruction ("twa", "", opcodeToggleWater); + extensions.registerInstruction ("togglepathgrid", "", opcodeTogglePathgrid); + extensions.registerInstruction ("tpg", "", opcodeTogglePathgrid); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -236,6 +255,7 @@ namespace MWScript interpreter.installSegment5 (opcodeFadeIn, new OpFadeIn); interpreter.installSegment5 (opcodeFadeOut, new OpFadeOut); interpreter.installSegment5 (opcodeFadeTo, new OpFadeTo); + interpreter.installSegment5 (opcodeTogglePathgrid, new OpTogglePathgrid); interpreter.installSegment5 (opcodeToggleWater, new OpToggleWater); } } diff --git a/apps/openmw/mwsound/audiere_decoder.cpp b/apps/openmw/mwsound/audiere_decoder.cpp new file mode 100644 index 000000000..acc2e5283 --- /dev/null +++ b/apps/openmw/mwsound/audiere_decoder.cpp @@ -0,0 +1,122 @@ +#ifdef OPENMW_USE_AUDIERE + +#include +#include + +#include "audiere_decoder.hpp" + + +static void fail(const std::string &msg) +{ throw std::runtime_error("Audiere exception: "+msg); } + +namespace MWSound +{ + +class OgreFile : public audiere::File +{ + Ogre::DataStreamPtr mStream; + + ADR_METHOD(int) read(void* buffer, int size) + { + return mStream->read(buffer, size); + } + + ADR_METHOD(bool) seek(int position, SeekMode mode) + { + if(mode == CURRENT) + mStream->seek(mStream->tell()+position); + else if(mode == BEGIN) + mStream->seek(position); + else if(mode == END) + mStream->seek(mStream->size()+position); + else + return false; + + return true; + } + + ADR_METHOD(int) tell() + { + return mStream->tell(); + } + + size_t refs; + virtual void ref() { ++refs; } + virtual void unref() + { + if(--refs == 0) + delete this; + } + +public: + OgreFile(const Ogre::DataStreamPtr &stream) + : mStream(stream), refs(1) + { } + virtual ~OgreFile() { } +}; + + +void Audiere_Decoder::open(const std::string &fname) +{ + close(); + + audiere::FilePtr file(new OgreFile(mResourceMgr.openResource(fname))); + mSoundSource = audiere::OpenSampleSource(file); + + int channels, srate; + audiere::SampleFormat format; + + mSoundSource->getFormat(channels, srate, format); + if(format == audiere::SF_S16) + mSampleType = SampleType_Int16; + else if(format == audiere::SF_U8) + mSampleType = SampleType_UInt8; + else + fail("Unsupported sample type"); + + if(channels == 1) + mChannelConfig = ChannelConfig_Mono; + else if(channels == 2) + mChannelConfig = ChannelConfig_Stereo; + else + fail("Unsupported channel count"); + + mSampleRate = srate; +} + +void Audiere_Decoder::close() +{ + mSoundSource = NULL; +} + +void Audiere_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) +{ + *samplerate = mSampleRate; + *chans = mChannelConfig; + *type = mSampleType; +} + +size_t Audiere_Decoder::read(char *buffer, size_t bytes) +{ + int size = bytesToFrames(bytes, mChannelConfig, mSampleType); + size = mSoundSource->read(size, buffer); + return framesToBytes(size, mChannelConfig, mSampleType); +} + +void Audiere_Decoder::rewind() +{ + mSoundSource->reset(); +} + +Audiere_Decoder::Audiere_Decoder() +{ +} + +Audiere_Decoder::~Audiere_Decoder() +{ + close(); +} + +} + +#endif diff --git a/apps/openmw/mwsound/audiere_decoder.hpp b/apps/openmw/mwsound/audiere_decoder.hpp new file mode 100644 index 000000000..0ad026d51 --- /dev/null +++ b/apps/openmw/mwsound/audiere_decoder.hpp @@ -0,0 +1,42 @@ +#ifndef GAME_SOUND_AUDIERE_DECODER_H +#define GAME_SOUND_AUDIERE_DECODER_H + +#include + +#include "audiere.h" + +#include "sound_decoder.hpp" + + +namespace MWSound +{ + class Audiere_Decoder : public Sound_Decoder + { + audiere::SampleSourcePtr mSoundSource; + int mSampleRate; + SampleType mSampleType; + ChannelConfig mChannelConfig; + + virtual void open(const std::string &fname); + virtual void close(); + + virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); + + virtual size_t read(char *buffer, size_t bytes); + virtual void rewind(); + + Audiere_Decoder& operator=(const Audiere_Decoder &rhs); + Audiere_Decoder(const Audiere_Decoder &rhs); + + Audiere_Decoder(); + public: + virtual ~Audiere_Decoder(); + + friend class SoundManager; + }; +#ifndef DEFAULT_DECODER +#define DEFAULT_DECODER (::MWSound::Audiere_Decoder) +#endif +}; + +#endif diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index a96aac6c5..145390e3e 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -18,8 +18,8 @@ #include "openal_output.hpp" #define SOUND_OUT "OpenAL" -/* Set up the sound manager to use FFMPEG or MPG123+libsndfile for input. The - * OPENMW_USE_x macros are set in CMakeLists.txt. +/* Set up the sound manager to use FFMPEG, MPG123+libsndfile, or Audiere for + * input. The OPENMW_USE_x macros are set in CMakeLists.txt. */ #ifdef OPENMW_USE_FFMPEG #include "ffmpeg_decoder.hpp" @@ -28,6 +28,13 @@ #endif #endif +#ifdef OPENMW_USE_AUDIERE +#include "audiere_decoder.hpp" +#ifndef SOUND_IN +#define SOUND_IN "Audiere" +#endif +#endif + #ifdef OPENMW_USE_MPG123 #include "mpgsnd_decoder.hpp" #ifndef SOUND_IN @@ -407,7 +414,7 @@ namespace MWSound if(!isMusicPlaying()) startRandomTitle(); - MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell(); + const ESM::Cell *cell = mEnvironment.mWorld->getPlayer().getPlayer().getCell()->cell; Ogre::Camera *cam = mEnvironment.mWorld->getPlayer().getRenderer()->getCamera(); Ogre::Vector3 nPos, nDir, nUp; nPos = cam->getRealPosition(); @@ -415,7 +422,7 @@ namespace MWSound nUp = cam->getRealUp(); Environment env = Env_Normal; - if(nPos.y < current->cell->water) + if((cell->data.flags&cell->HasWater) && nPos.y < cell->water) env = Env_Underwater; // The output handler is expecting vectors oriented like the game diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 9a918c2fb..09fd20076 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -34,7 +34,7 @@ const float WeatherGlobals::mThunderFrequency = .4; const float WeatherGlobals::mThunderThreshold = 0.6; const float WeatherGlobals::mThunderSoundDelay = 0.25; -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environment* env) : +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Environment* env) : mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0) { diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index efa9da38f..a7252353d 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -543,7 +543,7 @@ namespace MWWorld if (ptr==mPlayer->getPlayer()) { //std::cout << "X:" << ptr.getRefData().getPosition().pos[0] << " Z: " << ptr.getRefData().getPosition().pos[1] << "\n"; - + Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); if (currentCell) { @@ -750,15 +750,16 @@ namespace MWWorld // figure out which object we want to test against std::vector < std::pair < float, std::string > > results = mPhysics->getFacedObjects(); - // ignore the player - for (std::vector < std::pair < float, std::string > >::iterator it = results.begin(); - it != results.end(); ++it) + // ignore the player and other things we're not interested in + std::vector < std::pair < float, std::string > >::iterator it = results.begin(); + while (it != results.end()) { - if ( (*it).second == mPlayer->getPlayer().getRefData().getHandle() ) + if ( getPtrViaHandle((*it).second) == mPlayer->getPlayer() ) { - results.erase(it); - break; + it = results.erase(it); } + else + ++it; } if (results.size() == 0) @@ -774,6 +775,10 @@ namespace MWWorld btVector3 p = mPhysics->getRayPoint(results.front().first); Ogre::Vector3 pos(p.x(), p.z(), -p.y()); Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); + + //std::cout << "Num facing 1 : " << mFaced1Name << std::endl; + //std::cout << "Type 1 " << mFaced1.getTypeName() << std::endl; + query->occlusionTest(pos, node); } else @@ -786,8 +791,33 @@ namespace MWWorld btVector3 p = mPhysics->getRayPoint(results[1].first); Ogre::Vector3 pos(p.x(), p.z(), -p.y()); - Ogre::SceneNode* node = mFaced2.getRefData().getBaseNode(); - query->occlusionTest(pos, node); + Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); + Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); + + // no need to test if the first node is not occluder + if (!query->isPotentialOccluder(node1) && (mFaced1.getTypeName().find("Static") == std::string::npos)) + { + mFacedHandle = mFaced1Name; + //std::cout << "node1 Not an occluder" << std::endl; + return; + } + + // no need to test if the second object is static (thus cannot be activated) + if (mFaced2.getTypeName().find("Static") != std::string::npos) + { + mFacedHandle = mFaced1Name; + return; + } + + // work around door problems + if (mFaced1.getTypeName().find("Static") != std::string::npos + && mFaced2.getTypeName().find("Door") != std::string::npos) + { + mFacedHandle = mFaced2Name; + return; + } + + query->occlusionTest(pos, node2); } } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 57b537bfa..92540f82b 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -63,13 +63,14 @@ namespace MWWorld enum RenderMode { Render_CollisionDebug, - Render_Wireframe + Render_Wireframe, + Render_Pathgrid }; private: MWRender::RenderingManager* mRendering; - + MWWorld::WeatherManager* mWeatherManager; MWWorld::Scene *mWorldScene; @@ -112,7 +113,7 @@ namespace MWWorld Environment& environment, const std::string& encoding); ~World(); - + OEngine::Render::Fader* getFader(); Ptr::CellStore *getExterior (int x, int y); @@ -121,7 +122,7 @@ namespace MWWorld void setWaterHeight(const float height); void toggleWater(); - + void adjustSky(); MWWorld::Player& getPlayer(); @@ -134,7 +135,7 @@ namespace MWWorld bool hasCellChanged() const; ///< Has the player moved to a different cell, since the last frame? - + bool isCellExterior() const; bool isCellQuasiExterior() const; @@ -175,9 +176,9 @@ namespace MWWorld bool toggleSky(); ///< \return Resulting mode - + void changeWeather(const std::string& region, const unsigned int id); - + int getCurrentWeather() const; int getMasserPhase() const; diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index 16d37bec7..d7a4100aa 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -457,7 +457,7 @@ namespace ESMS } } - Pathgrid *find(int cellX, int cellY, std::string cellName) const + Pathgrid *find(int cellX, int cellY, const std::string &cellName) const { Pathgrid *result = search(cellX, cellY, cellName); if (!result) @@ -467,7 +467,7 @@ namespace ESMS return result; } - Pathgrid *search(int cellX, int cellY, std::string cellName) const + Pathgrid *search(int cellX, int cellY, const std::string &cellName) const { Pathgrid *result = NULL; if (cellX == 0 && cellY == 0) // possibly interior