diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c2f5a29a..c66c62f6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,6 +143,7 @@ endif (USE_MPG123) # Platform specific if (WIN32) + set(Boost_USE_STATIC_LIBS ON) set(PLATFORM_INCLUDE_DIR "platform") add_definitions(-DBOOST_ALL_NO_LIB) else (WIN32) @@ -309,7 +310,7 @@ if(DPKG_PROGRAM) Data files from the original game is required to run it.") SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") - SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher") + SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") SET(CPACK_DEBIAN_PACKAGE_DEPENDS "nvidia-cg-toolkit (>= 2.1), libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)") SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") @@ -395,6 +396,11 @@ if (BUILD_LAUNCHER) add_subdirectory( apps/launcher ) endif() +option(BUILD_MWINIIMPORTER "build MWiniImporter inspector" ON) +if (BUILD_MWINIIMPORTER) + add_subdirectory( apps/mwiniimporter ) +endif() + if (WIN32) if (MSVC) if (USE_DEBUG_CONSOLE) diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt new file mode 100644 index 000000000..2a8c0f5fe --- /dev/null +++ b/apps/mwiniimporter/CMakeLists.txt @@ -0,0 +1,20 @@ +set(MWINIIMPORT + main.cpp + importer.cpp +) + +set(MWINIIMPORT_HEADER + importer.hpp +) + +source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER}) + +add_executable(mwiniimport + ${MWINIIMPORT} +) + +target_link_libraries(mwiniimport + ${Boost_LIBRARIES} + components +) + diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp new file mode 100644 index 000000000..08b05f417 --- /dev/null +++ b/apps/mwiniimporter/importer.cpp @@ -0,0 +1,184 @@ +#include "importer.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +MwIniImporter::MwIniImporter() { + const char *map[][2] = + { + { "fps", "General:Show FPS" }, + { 0, 0 } + }; + + for(int i=0; map[i][0]; i++) { + mMergeMap.insert(std::make_pair(map[i][0], map[i][1])); + } +} + +void MwIniImporter::setVerbose(bool verbose) { + mVerbose = verbose; +} + +std::string MwIniImporter::numberToString(int n) { + std::stringstream str; + str << n; + return str.str(); +} + +MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) { + std::cout << "load ini file: " << filename << std::endl; + + std::string section(""); + MwIniImporter::multistrmap map; + boost::iostreams::streamfile(filename.c_str()); + + std::string line; + while (std::getline(file, line)) { + + if(line[0] == '[') { + if(line.length() > 2) { + section = line.substr(1, line.length()-3); + } + continue; + } + + int comment_pos = line.find(";"); + if(comment_pos > 0) { + line = line.substr(0,comment_pos); + } + + if(line.empty()) { + continue; + } + + int pos = line.find("="); + if(pos < 1) { + continue; + } + + std::string key(section + ":" + line.substr(0,pos)); + std::string value(line.substr(pos+1)); + + multistrmap::iterator it; + if((it = map.find(key)) == map.end()) { + map.insert( std::make_pair > (key, std::vector() ) ); + } + map[key].push_back(value); + } + + return map; +} + +MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) { + std::cout << "load cfg file: " << filename << std::endl; + + MwIniImporter::multistrmap map; + boost::iostreams::streamfile(filename.c_str()); + + std::string line; + while (std::getline(file, line)) { + + // we cant say comment by only looking at first char anymore + int comment_pos = line.find("#"); + if(comment_pos > 0) { + line = line.substr(0,comment_pos); + } + + if(line.empty()) { + continue; + } + + int pos = line.find("="); + if(pos < 1) { + continue; + } + + std::string key(line.substr(0,pos)); + std::string value(line.substr(pos+1)); + + multistrmap::iterator it; + if((it = map.find(key)) == map.end()) { + map.insert( std::make_pair > (key, std::vector() ) ); + } + map[key].push_back(value); + } + + return map; +} + +void MwIniImporter::merge(multistrmap &cfg, multistrmap &ini) { + multistrmap::iterator cfgIt; + multistrmap::iterator iniIt; + for(strmap::iterator it=mMergeMap.begin(); it!=mMergeMap.end(); it++) { + if((iniIt = ini.find(it->second)) != ini.end()) { + cfg.erase(it->first); + if(!this->specialMerge(it->first, it->second, cfg, ini)) { + cfg.insert(std::make_pair >(it->first, iniIt->second)); + } + } + } +} + +bool MwIniImporter::specialMerge(std::string cfgKey, std::string iniKey, multistrmap &cfg, multistrmap &ini) { + return false; +} + +void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { + std::vector esmFiles; + std::vector espFiles; + std::string baseGameFile("Game Files:GameFile"); + std::string gameFile(""); + + multistrmap::iterator it = ini.begin(); + for(int i=0; it != ini.end(); i++) { + gameFile = baseGameFile; + gameFile.append(this->numberToString(i)); + + it = ini.find(gameFile); + if(it == ini.end()) { + break; + } + + for(std::vector::iterator entry = it->second.begin(); entry!=it->second.end(); entry++) { + std::string filetype(entry->substr(entry->length()-4, 3)); + std::transform(filetype.begin(), filetype.end(), filetype.begin(), ::tolower); + + if(filetype.compare("esm") == 0) { + esmFiles.push_back(*entry); + } + else if(filetype.compare("esp") == 0) { + espFiles.push_back(*entry); + } + } + + gameFile = ""; + } + + cfg.erase("master"); + cfg.insert( std::make_pair > ("master", std::vector() ) ); + + for(std::vector::iterator it=esmFiles.begin(); it!=esmFiles.end(); it++) { + cfg["master"].push_back(*it); + } + + cfg.erase("plugin"); + cfg.insert( std::make_pair > ("plugin", std::vector() ) ); + + for(std::vector::iterator it=espFiles.begin(); it!=espFiles.end(); it++) { + cfg["plugin"].push_back(*it); + } +} + +void MwIniImporter::writeToFile(boost::iostreams::stream &out, multistrmap &cfg) { + + for(multistrmap::iterator it=cfg.begin(); it != cfg.end(); it++) { + for(std::vector::iterator entry=it->second.begin(); entry != it->second.end(); entry++) { + out << (it->first) << "=" << (*entry) << std::endl; + } + } +} diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp new file mode 100644 index 000000000..988f10255 --- /dev/null +++ b/apps/mwiniimporter/importer.hpp @@ -0,0 +1,32 @@ +#ifndef MWINIIMPORTER_IMPORTER +#define MWINIIMPORTER_IMPORTER 1 + +#include +#include +#include +#include +#include +#include + +class MwIniImporter { + public: + typedef std::map strmap; + typedef std::map > multistrmap; + + MwIniImporter(); + void setVerbose(bool verbose); + multistrmap loadIniFile(std::string filename); + multistrmap loadCfgFile(std::string filename); + void merge(multistrmap &cfg, multistrmap &ini); + void importGameFiles(multistrmap &cfg, multistrmap &ini); + void writeToFile(boost::iostreams::stream &out, multistrmap &cfg); + + private: + bool specialMerge(std::string cfgKey, std::string iniKey, multistrmap &cfg, multistrmap &ini); + std::string numberToString(int n); + bool mVerbose; + strmap mMergeMap; +}; + + +#endif diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp new file mode 100644 index 000000000..9a6e61645 --- /dev/null +++ b/apps/mwiniimporter/main.cpp @@ -0,0 +1,79 @@ +#include "importer.hpp" + +#include +#include +#include +#include + +namespace bpo = boost::program_options; + +int main(int argc, char *argv[]) { + + bpo::options_description desc("Syntax: mwiniimporter \nAllowed options"); + desc.add_options() + ("help,h", "produce help message") + ("verbose,v", "verbose output") + ("ini,i", bpo::value(), "morrowind.ini file") + ("cfg,c", bpo::value(), "openmw.cfg file") + ("output,o", bpo::value()->default_value(""), "openmw.cfg file") + ("game-files,g", "import esm and esp files") + ; + + bpo::variables_map vm; + try { + bpo::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + + // parse help before calling notify because we dont want it to throw an error if help is set + if(vm.count("help")) { + std::cout << desc; + return 0; + } + + bpo::notify(vm); + + } + catch(std::exception& e) { + std::cerr << "Error:" << e.what() << std::endl; + return -1; + } + catch(...) { + std::cerr << "Error" << std::endl; + return -2; + } + + std::string iniFile = vm["ini"].as(); + std::string cfgFile = vm["cfg"].as(); + + // if no output is given, write back to cfg file + std::string outputFile(vm["output"].as()); + if(vm["output"].defaulted()) { + outputFile = vm["cfg"].as(); + } + + if(!boost::filesystem::exists(iniFile)) { + std::cerr << "ini file does not exist" << std::endl; + return -3; + } + if(!boost::filesystem::exists(cfgFile)) { + std::cerr << "cfg file does not exist" << std::endl; + return -4; + } + + MwIniImporter importer; + importer.setVerbose(vm.count("verbose")); + boost::iostreams::stream file(outputFile); + + MwIniImporter::multistrmap ini = importer.loadIniFile(iniFile); + MwIniImporter::multistrmap cfg = importer.loadCfgFile(cfgFile); + + importer.merge(cfg, ini); + + if(vm.count("game-files")) { + importer.importGameFiles(cfg, ini); + } + + std::cout << "write to: " << outputFile << std::endl; + importer.writeToFile(file, cfg); + + return 0; +} diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index cc3464c64..29cfe33fe 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -12,7 +12,8 @@ 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), - mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mDoQuery2(false) + mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mDoQuery2(false), + mBBNode(0) { mRendering = renderer; mSunNode = sunNode; @@ -52,7 +53,8 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod matQueryVisible->setCullingMode(CULL_NONE); matQueryVisible->setManualCullingMode(MANUAL_CULL_NONE); - mBBNode = mSunNode->getParentSceneNode()->createChildSceneNode(); + if (sunNode) + mBBNode = mSunNode->getParentSceneNode()->createChildSceneNode(); mObjectNode = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); @@ -182,10 +184,13 @@ void OcclusionQuery::update(float duration) if (dist==0) dist = 10000000; dist -= 1000; // bias dist /= 1000.f; - mBBNode->setPosition(mSunNode->getPosition() * dist); - mBBNode->setScale(dist, dist, dist); - mBBNodeReal->setPosition(mBBNode->_getDerivedPosition()); - mBBNodeReal->setScale(mBBNode->getScale()); + if (mBBNode) + { + mBBNode->setPosition(mSunNode->getPosition() * dist); + mBBNode->setScale(dist, dist, dist); + mBBNodeReal->setPosition(mBBNode->_getDerivedPosition()); + mBBNodeReal->setScale(mBBNode->getScale()); + } // Stop occlusion queries until we get their information // (may not happen on the same frame they are requested in) @@ -245,6 +250,13 @@ bool OcclusionQuery::occlusionTestPending() return (mQuerySingleObjectRequested || mQuerySingleObjectStarted); } +void OcclusionQuery::setSunNode(Ogre::SceneNode* node) +{ + mSunNode = node; + if (!mBBNode) + mBBNode = node->getParentSceneNode()->createChildSceneNode(); +} + bool OcclusionQuery::getTestResult() { assert( !occlusionTestPending() diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp index ebdc51311..b655c8e46 100644 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ b/apps/openmw/mwrender/occlusionquery.hpp @@ -53,6 +53,8 @@ namespace MWRender float getSunVisibility() const {return mSunVisibility;}; + void setSunNode(Ogre::SceneNode* node); + private: Ogre::HardwareOcclusionQuery* mSunTotalAreaQuery; Ogre::HardwareOcclusionQuery* mSunVisibleAreaQuery; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3d715b3d3..bbddd325a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -201,6 +201,8 @@ void RenderingManager::skyEnable () { if(mSkyManager) mSkyManager->enable(); + + mOcclusionQuery->setSunNode(mSkyManager->getSunNode()); } void RenderingManager::skyDisable () diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 265008e34..2fdf9b2cd 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -325,14 +325,17 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen , mSunEnabled(true) , mMasserEnabled(true) , mSecundaEnabled(true) + , mCreated(false) { - mViewport = pCamera->getViewport(); mSceneMgr = pMwRoot->getCreator(); mRootNode = pCamera->getParentSceneNode()->createChildSceneNode(); mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates mRootNode->setInheritOrientation(false); +} +void SkyManager::create() +{ /// \todo preload all the textures and meshes that are used for sky rendering // Create overlay used for thunderstorm @@ -533,7 +536,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen " uniform float4 emissive \n" ") \n" "{ \n" - " uv += float2(1,0) * time * speed * 0.003; \n" // Scroll in x direction + " uv += float2(0,1) * time * speed * 0.003; \n" // Scroll in y direction " float4 tex = lerp(tex2D(texture, uv), tex2D(secondTexture, uv), transitionFactor); \n" " oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n" "}"; @@ -562,6 +565,8 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(""); + + mCreated = true; } SkyManager::~SkyManager() @@ -574,11 +579,13 @@ SkyManager::~SkyManager() int SkyManager::getMasserPhase() const { + if (!mCreated) return 0; return mMasser->getPhaseInt(); } int SkyManager::getSecundaPhase() const { + if (!mCreated) return 0; return mSecunda->getPhaseInt(); } @@ -631,6 +638,9 @@ void SkyManager::update(float duration) void SkyManager::enable() { + if (!mCreated) + create(); + mRootNode->setVisible(true); mEnabled = true; } @@ -654,6 +664,7 @@ void SkyManager::setCloudsOpacity(float opacity) void SkyManager::setWeather(const MWWorld::WeatherResult& weather) { + if (!mCreated) return; if (mClouds != weather.mCloudTexture) { mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("textures\\"+weather.mCloudTexture); @@ -750,17 +761,20 @@ void SkyManager::sunDisable() void SkyManager::setSunDirection(const Vector3& direction) { + if (!mCreated) return; mSun->setPosition(direction); mSunGlare->setPosition(direction); } void SkyManager::setMasserDirection(const Vector3& direction) { + if (!mCreated) return; mMasser->setPosition(direction); } void SkyManager::setSecundaDirection(const Vector3& direction) { + if (!mCreated) return; mSecunda->setPosition(direction); } @@ -786,6 +800,7 @@ void SkyManager::secundaDisable() void SkyManager::setThunder(const float factor) { + if (!mCreated) return; if (factor > 0.f) { mThunderOverlay->show(); @@ -818,5 +833,6 @@ void SkyManager::setDate(int day, int month) Ogre::SceneNode* SkyManager::getSunNode() { + if (!mCreated) return 0; return mSun->getNode(); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 508af7673..baf5933cb 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -112,6 +112,9 @@ namespace MWRender void update(float duration); + void create(); + ///< no need to call this, automatically done on first enable() + void enable(); void disable(); @@ -164,8 +167,10 @@ namespace MWRender void setGlare(const float glare); Ogre::Vector3 getRealSunPos(); - + private: + bool mCreated; + MWWorld::Environment* mEnvironment; float mHour; int mDay; diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index e57c1a709..610a797a2 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -261,7 +261,16 @@ bool OpenAL_SoundStream::isPlaying() void OpenAL_SoundStream::update() { - alSourcef(mSource, AL_GAIN, mVolume*mBaseVolume); + ALfloat gain = mVolume*mBaseVolume; + ALfloat pitch = mPitch; + if(!(mFlags&Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(mSource, AL_GAIN, gain); + alSourcef(mSource, AL_PITCH, pitch); alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]); alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); @@ -389,7 +398,16 @@ bool OpenAL_Sound::isPlaying() void OpenAL_Sound::update() { - alSourcef(mSource, AL_GAIN, mVolume*mBaseVolume); + ALfloat gain = mVolume*mBaseVolume; + ALfloat pitch = mPitch; + if(!(mFlags&Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(mSource, AL_GAIN, gain); + alSourcef(mSource, AL_PITCH, pitch); alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]); alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); @@ -398,10 +416,18 @@ void OpenAL_Sound::update() void OpenAL_Sound3D::update() { + ALfloat gain = mVolume*mBaseVolume; + ALfloat pitch = mPitch; if(mPos.squaredDistance(mOutput.mPos) > mMaxDistance*mMaxDistance) - alSourcef(mSource, AL_GAIN, 0.0f); - else - alSourcef(mSource, AL_GAIN, mVolume*mBaseVolume); + gain = 0.0f; + else if(!(mFlags&Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + + alSourcef(mSource, AL_GAIN, gain); + alSourcef(mSource, AL_PITCH, pitch); alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]); alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); @@ -639,6 +665,11 @@ SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float alSourcef(src, AL_MAX_DISTANCE, 1000.0f); alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); + if(!(flags&Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + volume *= 0.9f; + pitch *= 0.7f; + } alSourcef(src, AL_GAIN, volume); alSourcef(src, AL_PITCH, pitch); @@ -686,6 +717,11 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector alSourcef(src, AL_MAX_DISTANCE, max); alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f); + if(!(flags&Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + volume *= 0.9f; + pitch *= 0.7f; + } alSourcef(src, AL_GAIN, (pos.squaredDistance(mPos) > max*max) ? 0.0f : volume); alSourcef(src, AL_PITCH, pitch); @@ -702,7 +738,7 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector } -SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch) +SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch, int flags) { boost::shared_ptr sound; ALuint src; @@ -714,6 +750,8 @@ SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, floa try { + if((flags&Play_Loop)) + std::cout <<"Warning: cannot loop stream "<open(fname); sound.reset(new OpenAL_SoundStream(*this, src, decoder)); @@ -732,6 +770,11 @@ SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, floa alSourcef(src, AL_MAX_DISTANCE, 1000.0f); alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); + if(!(flags&Play_NoEnv) && mLastEnvironment == Env_Underwater) + { + volume *= 0.9f; + pitch *= 0.7f; + } alSourcef(src, AL_GAIN, volume); alSourcef(src, AL_PITCH, pitch); @@ -744,9 +787,10 @@ SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, floa } -void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir) +void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) { mPos = pos; + mLastEnvironment = env; if(mContext) { @@ -763,7 +807,7 @@ void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 OpenAL_Output::OpenAL_Output(SoundManager &mgr) : Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0), - mStreamThread(new StreamThread) + mLastEnvironment(Env_Normal), mStreamThread(new StreamThread) { } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index a709576ba..d62d20286 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -36,6 +36,8 @@ namespace MWSound ALuint getBuffer(const std::string &fname); void bufferFinished(ALuint buffer); + Environment mLastEnvironment; + virtual std::vector enumerate(); virtual void init(const std::string &devname=""); virtual void deinit(); @@ -43,9 +45,9 @@ namespace MWSound virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags); virtual SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float volume, float pitch, float min, float max, int flags); - virtual SoundPtr streamSound(const std::string &fname, float volume, float pitch); + virtual SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags); - virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir); + virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env); OpenAL_Output& operator=(const OpenAL_Output &rhs); OpenAL_Output(const OpenAL_Output &rhs); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index ca12ec557..a33892548 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -16,6 +16,7 @@ namespace MWSound Ogre::Vector3 mPos; float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */ float mBaseVolume; + float mPitch; float mMinDistance; float mMaxDistance; int mFlags; @@ -29,6 +30,7 @@ namespace MWSound Sound() : mPos(0.0f, 0.0f, 0.0f) , mVolume(1.0f) , mBaseVolume(1.0f) + , mPitch(1.0f) , mMinDistance(20.0f) /* 1 * min_range_scale */ , mMaxDistance(12750.0f) /* 255 * max_range_scale */ , mFlags(Play_Normal) diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 1507e1847..774e42efa 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -27,9 +27,9 @@ namespace MWSound virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags) = 0; virtual SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float volume, float pitch, float min, float max, int flags) = 0; - virtual SoundPtr streamSound(const std::string &fname, float volume, float pitch) = 0; + virtual SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags) = 0; - virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir) = 0; + virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0; Sound_Output& operator=(const Sound_Output &rhs); Sound_Output(const Sound_Output &rhs); diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 2c2e6e9f9..a96aac6c5 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -88,10 +88,7 @@ namespace MWSound if(snd == NULL) throw std::runtime_error(std::string("Failed to lookup sound ")+soundId); - if(snd->data.volume == 0) - volume = 0.0f; - else - volume *= pow(10.0, (snd->data.volume/255.0f*3348.0 - 3348.0) / 2000.0); + volume *= pow(10.0, (snd->data.volume/255.0*3348.0 - 3348.0) / 2000.0); if(snd->data.minRange == 0 && snd->data.maxRange == 0) { @@ -135,10 +132,10 @@ namespace MWSound std::cout <<"Playing "<stop(); - mMusic = mOutput->streamSound(filename, 0.4f, 1.0f); + stopMusic(); + mMusic = mOutput->streamSound(filename, 0.4f, 1.0f, Play_NoEnv); mMusic->mBaseVolume = 0.4f; + mMusic->mFlags = Play_NoEnv; } catch(std::exception &e) { @@ -215,6 +212,7 @@ namespace MWSound sound = mOutput->playSound(file, volume*basevol, pitch, mode); sound->mVolume = volume; sound->mBaseVolume = basevol; + sound->mPitch = pitch; sound->mMinDistance = min; sound->mMaxDistance = max; sound->mFlags = mode; @@ -245,6 +243,7 @@ namespace MWSound sound->mPos = objpos; sound->mVolume = volume; sound->mBaseVolume = basevol; + sound->mPitch = pitch; sound->mMinDistance = min; sound->mMaxDistance = max; sound->mFlags = mode; @@ -408,19 +407,25 @@ namespace MWSound if(!isMusicPlaying()) startRandomTitle(); + MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell(); Ogre::Camera *cam = mEnvironment.mWorld->getPlayer().getRenderer()->getCamera(); Ogre::Vector3 nPos, nDir, nUp; nPos = cam->getRealPosition(); nDir = cam->getRealDirection(); nUp = cam->getRealUp(); + Environment env = Env_Normal; + if(nPos.y < current->cell->water) + env = Env_Underwater; + // The output handler is expecting vectors oriented like the game // (that is, -Z goes down, +Y goes forward), but that's not what we // get from Ogre's camera, so we have to convert. const Ogre::Vector3 pos(nPos[0], -nPos[2], nPos[1]); const Ogre::Vector3 at(nDir[0], -nDir[2], nDir[1]); const Ogre::Vector3 up(nUp[0], -nUp[2], nUp[1]); - mOutput->updateListener(pos, at, up); + + mOutput->updateListener(pos, at, up, env); // Check if any sounds are finished playing, and trash them SoundMap::iterator snditer = mActiveSounds.begin(); diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index de5cca839..cad5f6187 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -43,6 +43,11 @@ namespace MWSound static inline int operator&(const PlayMode &a, const PlayMode &b) { return (int)a & (int)b; } + enum Environment { + Env_Normal, + Env_Underwater, + }; + class SoundManager { Ogre::ResourceGroupManager& mResourceMgr; diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 6f03fa37f..a48cc7e72 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -146,10 +146,10 @@ namespace MWWorld mRendering->skySetDate (mGlobalVariables->getInt ("day"), mGlobalVariables->getInt ("month")); - mRendering->getSkyManager()->enable(); + mRendering->skyEnable(); } else - mRendering->getSkyManager()->disable(); + mRendering->skyDisable(); } World::World (OEngine::Render::OgreRenderer& renderer, diff --git a/cmake/FindBullet.cmake b/cmake/FindBullet.cmake index 7bdf75a0a..552a0651a 100644 --- a/cmake/FindBullet.cmake +++ b/cmake/FindBullet.cmake @@ -51,13 +51,13 @@ find_path(BULLET_INCLUDE_DIR NAMES btBulletCollisionCommon.h # Find the libraries _FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY BulletDynamics) -_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY_DEBUG BulletDynamics_d) +_FIND_BULLET_LIBRARY(BULLET_DYNAMICS_LIBRARY_DEBUG BulletDynamics_Debug BulletDynamics_d) _FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY BulletCollision) -_FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY_DEBUG BulletCollision_d) -_FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY LinearMath BulletMath) -_FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY_DEBUG LinearMath_d BulletMath_d) +_FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY_DEBUG BulletCollision_Debug BulletCollision_d) +_FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY BulletMath LinearMath) +_FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY_DEBUG BulletMath_Debug BulletMath_d LinearMath_debug LinearMath_d) _FIND_BULLET_LIBRARY(BULLET_SOFTBODY_LIBRARY BulletSoftBody) -_FIND_BULLET_LIBRARY(BULLET_SOFTBODY_LIBRARY_DEBUG BulletSoftBody_d) +_FIND_BULLET_LIBRARY(BULLET_SOFTBODY_LIBRARY_DEBUG BulletSoftBody_Debug BulletSoftBody_d) # handle the QUIETLY and REQUIRED arguments and set BULLET_FOUND to TRUE if diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index f4f4b898c..0e3563b26 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -41,21 +41,21 @@ struct ciLessBoost : std::binary_function { bool operator() (const std::string & s1, const std::string & s2) const { //case insensitive version of is_less - return lexicographical_compare(s1, s2, boost::algorithm::is_iless()); + return boost::ilexicographical_compare(s1, s2); } }; struct pathComparer { private: - int m_start, m_size; + std::string find; public: - pathComparer(int start, int size) : m_start(start), m_size(size) { } + pathComparer(const std::string& toFind) : find(toFind) { } - bool operator() (const std::string& first, const std::string& other) + bool operator() (const std::string& other) { - return lexicographical_compare(first.substr(m_start,m_size), other.substr(m_start,m_size), boost::algorithm::is_iless()); + return boost::iequals(find, other); } }; @@ -71,9 +71,6 @@ class DirArchive: public Ogre::FileSystemArchive bool findFile(const String& filename, std::string& copy) const { - if (filename.find(".tga") != std::string::npos) - return false; - { String passed = filename; if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<' @@ -116,10 +113,13 @@ class DirArchive: public Ogre::FileSystemArchive current = found->second; } - pathComparer comp(delimiter, copy.size() - delimiter-1); - std::vector::iterator find = std::lower_bound(current.begin(), current.end(), copy, comp); - if (find != current.end() && !comp(copy, current.front())) + std::vector::iterator find = std::lower_bound(current.begin(), current.end(), copy, ciLessBoost()); + if (find != current.end() && !ciLessBoost()(copy, current.front())) { + if (!boost::iequals(copy, *find)) + if ((find = std::find_if(current.begin(), current.end(), pathComparer(copy))) == current.end()) //\todo Check if this line is actually needed + return false; + copy = *find; return true; }