mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 00:26:39 +00:00 
			
		
		
		
	Merge branch 'master' into globals
This commit is contained in:
		
						commit
						c0fb46384c
					
				
					 72 changed files with 3588 additions and 1220 deletions
				
			
		| 
						 | 
				
			
			@ -37,8 +37,8 @@ option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
 | 
			
		|||
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF)
 | 
			
		||||
 | 
			
		||||
# Sound source selection
 | 
			
		||||
option(USE_FFMPEG "use ffmpeg for sound" OFF)
 | 
			
		||||
option(USE_AUDIERE "use audiere for sound" OFF)
 | 
			
		||||
option(USE_FFMPEG "use ffmpeg for sound" ON)
 | 
			
		||||
option(USE_AUDIERE "use audiere for sound" ON)
 | 
			
		||||
option(USE_MPG123 "use mpg123 + libsndfile for sound" ON)
 | 
			
		||||
 | 
			
		||||
# OS X deployment
 | 
			
		||||
| 
						 | 
				
			
			@ -137,30 +137,54 @@ set(OPENMW_LIBS ${OENGINE_ALL})
 | 
			
		|||
set(OPENMW_LIBS_HEADER)
 | 
			
		||||
 | 
			
		||||
# Sound setup
 | 
			
		||||
set(GOT_SOUND_INPUT 0)
 | 
			
		||||
set(SOUND_INPUT_INCLUDES "")
 | 
			
		||||
set(SOUND_INPUT_LIBRARY "")
 | 
			
		||||
set(SOUND_DEFINE "")
 | 
			
		||||
if (USE_FFMPEG)
 | 
			
		||||
    find_package(FFMPEG REQUIRED)
 | 
			
		||||
    set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIR})
 | 
			
		||||
    set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES})
 | 
			
		||||
    set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG)
 | 
			
		||||
    set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
 | 
			
		||||
    find_package(FFmpeg)
 | 
			
		||||
    if (FFMPEG_FOUND)
 | 
			
		||||
        set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS})
 | 
			
		||||
        set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
 | 
			
		||||
        set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG)
 | 
			
		||||
        set(GOT_SOUND_INPUT 1)
 | 
			
		||||
    endif (FFMPEG_FOUND)
 | 
			
		||||
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_AUDIERE AND NOT GOT_SOUND_INPUT)
 | 
			
		||||
    find_package(Audiere)
 | 
			
		||||
    if (AUDIERE_FOUND)
 | 
			
		||||
        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)
 | 
			
		||||
        set(GOT_SOUND_INPUT 1)
 | 
			
		||||
    endif (AUDIERE_FOUND)
 | 
			
		||||
endif (USE_AUDIERE AND NOT GOT_SOUND_INPUT)
 | 
			
		||||
 | 
			
		||||
if (USE_MPG123)
 | 
			
		||||
if (USE_MPG123 AND NOT GOT_SOUND_INPUT)
 | 
			
		||||
    find_package(MPG123 REQUIRED)
 | 
			
		||||
    find_package(SNDFILE REQUIRED)
 | 
			
		||||
    set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
 | 
			
		||||
    set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
 | 
			
		||||
    set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123)
 | 
			
		||||
endif (USE_MPG123)
 | 
			
		||||
    if (MPG123_FOUND AND SNDFILE_FOUND)
 | 
			
		||||
        set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
 | 
			
		||||
        set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
 | 
			
		||||
        set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123)
 | 
			
		||||
        set(GOT_SOUND_INPUT 1)
 | 
			
		||||
    endif (MPG123_FOUND AND SNDFILE_FOUND)
 | 
			
		||||
endif (USE_MPG123 AND NOT GOT_SOUND_INPUT)
 | 
			
		||||
 | 
			
		||||
if (NOT GOT_SOUND_INPUT)
 | 
			
		||||
    message(WARNING "--------------------")
 | 
			
		||||
    message(WARNING "Failed to find any sound input packages")
 | 
			
		||||
    message(WARNING "--------------------")
 | 
			
		||||
endif (NOT GOT_SOUND_INPUT)
 | 
			
		||||
 | 
			
		||||
if (NOT FFMPEG_FOUND)
 | 
			
		||||
    message(WARNING "--------------------")
 | 
			
		||||
    message(WARNING "FFmpeg not found, video playback will be disabled")
 | 
			
		||||
    message(WARNING "--------------------")
 | 
			
		||||
endif (NOT FFMPEG_FOUND)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Platform specific
 | 
			
		||||
if (WIN32)
 | 
			
		||||
| 
						 | 
				
			
			@ -534,7 +558,9 @@ if (WIN32)
 | 
			
		|||
		set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
 | 
			
		||||
	endif (BUILD_LAUNCHER)
 | 
			
		||||
    set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS})
 | 
			
		||||
	set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
 | 
			
		||||
    if (BUILD_ESMTOOL)
 | 
			
		||||
        set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
 | 
			
		||||
    endif (BUILD_ESMTOOL)
 | 
			
		||||
  endif(MSVC)
 | 
			
		||||
 | 
			
		||||
  # Same for MinGW
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -165,23 +165,12 @@ bool parseOptions (int argc, char** argv, Arguments &info)
 | 
			
		|||
 | 
			
		||||
    // Font encoding settings
 | 
			
		||||
    info.encoding = variables["encoding"].as<std::string>();
 | 
			
		||||
    if (info.encoding == "win1250")
 | 
			
		||||
    if(info.encoding != "win1250" && info.encoding != "win1251" && info.encoding != "win1252")
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << "Using Central and Eastern European font encoding." << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
    else if (info.encoding == "win1251")
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << "Using Cyrillic font encoding." << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if(info.encoding != "win1252")
 | 
			
		||||
        {
 | 
			
		||||
            std::cout << info.encoding << " is not a valid encoding option." << std::endl;
 | 
			
		||||
            info.encoding = "win1252";
 | 
			
		||||
        }
 | 
			
		||||
        std::cout << "Using default (English) font encoding." << std::endl;
 | 
			
		||||
        std::cout << info.encoding << " is not a valid encoding option." << std::endl;
 | 
			
		||||
        info.encoding = "win1252";
 | 
			
		||||
    }
 | 
			
		||||
    std::cout << ToUTF8::encodingUsingMessage(info.encoding) << std::endl;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -262,7 +251,8 @@ void printRaw(ESM::ESMReader &esm)
 | 
			
		|||
int load(Arguments& info)
 | 
			
		||||
{
 | 
			
		||||
    ESM::ESMReader& esm = info.reader;
 | 
			
		||||
    esm.setEncoding(ToUTF8::calculateEncoding(info.encoding));
 | 
			
		||||
    ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
 | 
			
		||||
    esm.setEncoder(&encoder);
 | 
			
		||||
 | 
			
		||||
    std::string filename = info.filename;
 | 
			
		||||
    std::cout << "Loading file: " << filename << std::endl;
 | 
			
		||||
| 
						 | 
				
			
			@ -432,7 +422,8 @@ int clone(Arguments& info)
 | 
			
		|||
    std::cout << std::endl << "Saving records to: " << info.outname << "..." << std::endl;
 | 
			
		||||
 | 
			
		||||
    ESM::ESMWriter& esm = info.writer;
 | 
			
		||||
    esm.setEncoding(info.encoding);
 | 
			
		||||
    ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
 | 
			
		||||
    esm.setEncoder(&encoder);
 | 
			
		||||
    esm.setAuthor(info.data.author);
 | 
			
		||||
    esm.setDescription(info.data.description);
 | 
			
		||||
    esm.setVersion(info.data.version);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -272,7 +272,8 @@ void DataFilesModel::addMasters(const QString &path)
 | 
			
		|||
    foreach (const QString &path, dir.entryList()) {
 | 
			
		||||
        try {
 | 
			
		||||
            ESM::ESMReader fileReader;
 | 
			
		||||
            fileReader.setEncoding(ToUTF8::calculateEncoding(mEncoding.toStdString()));
 | 
			
		||||
            ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString()));
 | 
			
		||||
            fileReader.setEncoder(&encoder);
 | 
			
		||||
            fileReader.open(dir.absoluteFilePath(path).toStdString());
 | 
			
		||||
 | 
			
		||||
            ESM::ESMReader::MasterList mlist = fileReader.getMasters();
 | 
			
		||||
| 
						 | 
				
			
			@ -335,7 +336,8 @@ void DataFilesModel::addPlugins(const QString &path)
 | 
			
		|||
 | 
			
		||||
        try {
 | 
			
		||||
            ESM::ESMReader fileReader;
 | 
			
		||||
            fileReader.setEncoding(ToUTF8::calculateEncoding(mEncoding.toStdString()));
 | 
			
		||||
            ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString()));
 | 
			
		||||
            fileReader.setEncoder(&encoder);
 | 
			
		||||
            fileReader.open(dir.absoluteFilePath(path).toStdString());
 | 
			
		||||
 | 
			
		||||
            ESM::ESMReader::MasterList mlist = fileReader.getMasters();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -649,11 +649,12 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) {
 | 
			
		|||
    std::string section("");
 | 
			
		||||
    MwIniImporter::multistrmap map;
 | 
			
		||||
    boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str());
 | 
			
		||||
    ToUTF8::Utf8Encoder encoder(mEncoding);
 | 
			
		||||
 | 
			
		||||
    std::string line;
 | 
			
		||||
    while (std::getline(file, line)) {
 | 
			
		||||
 | 
			
		||||
        line = toUTF8(line);
 | 
			
		||||
        line = encoder.getUtf8(line);
 | 
			
		||||
 | 
			
		||||
        // unify Unix-style and Windows file ending
 | 
			
		||||
        if (!(line.empty()) && (line[line.length()-1]) == '\r') {
 | 
			
		||||
| 
						 | 
				
			
			@ -829,14 +830,6 @@ void MwIniImporter::writeToFile(boost::iostreams::stream<boost::iostreams::file_
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string MwIniImporter::toUTF8(const std::string &str) {
 | 
			
		||||
    char *ptr = ToUTF8::getBuffer(str.length());
 | 
			
		||||
    strncpy(ptr, str.c_str(), str.length());
 | 
			
		||||
 | 
			
		||||
    // Convert to UTF8 and return
 | 
			
		||||
    return ToUTF8::getUtf8(mEncoding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding)
 | 
			
		||||
{
 | 
			
		||||
  mEncoding = encoding;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@
 | 
			
		|||
#include <vector>
 | 
			
		||||
#include <exception>
 | 
			
		||||
 | 
			
		||||
#include "../../components/to_utf8/to_utf8.hpp"
 | 
			
		||||
#include <components/to_utf8/to_utf8.hpp>
 | 
			
		||||
 | 
			
		||||
class MwIniImporter {
 | 
			
		||||
  public:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
 | 
			
		|||
add_openmw_dir (mwrender
 | 
			
		||||
    renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
 | 
			
		||||
    renderinginterface localmap occlusionquery terrain terrainmaterial water shadows
 | 
			
		||||
    compositors characterpreview externalrendering globalmap
 | 
			
		||||
    compositors characterpreview externalrendering globalmap videoplayer
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
add_openmw_dir (mwinput
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -331,11 +331,15 @@ void OMW::Engine::go()
 | 
			
		|||
    // cursor replacer (converts the cursor from the bsa so they can be used by mygui)
 | 
			
		||||
    MWGui::CursorReplace replacer;
 | 
			
		||||
 | 
			
		||||
    // Create encoder
 | 
			
		||||
    ToUTF8::Utf8Encoder encoder (mEncoding);
 | 
			
		||||
 | 
			
		||||
    // Create the world
 | 
			
		||||
    mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster,
 | 
			
		||||
        mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap));
 | 
			
		||||
        mResDir, mCfgMgr.getCachePath(), mNewGame, &encoder, mFallbackMap));
 | 
			
		||||
 | 
			
		||||
    //Load translation data
 | 
			
		||||
    mTranslationDataStorage.setEncoder(&encoder);
 | 
			
		||||
    mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster);
 | 
			
		||||
 | 
			
		||||
    // Create window manager - this manages all the MW-specific GUI windows
 | 
			
		||||
| 
						 | 
				
			
			@ -494,7 +498,6 @@ void OMW::Engine::showFPS(int level)
 | 
			
		|||
void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding)
 | 
			
		||||
{
 | 
			
		||||
    mEncoding = encoding;
 | 
			
		||||
    mTranslationDataStorage.setEncoding (encoding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OMW::Engine::setFallbackValues(std::map<std::string,std::string> fallbackMap)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -128,12 +128,6 @@ float MWBase::Environment::getFrameDuration() const
 | 
			
		|||
 | 
			
		||||
void MWBase::Environment::cleanup()
 | 
			
		||||
{
 | 
			
		||||
    delete mInputManager;
 | 
			
		||||
    mInputManager = 0;
 | 
			
		||||
 | 
			
		||||
    delete mSoundManager;
 | 
			
		||||
    mSoundManager = 0;
 | 
			
		||||
 | 
			
		||||
    delete mMechanicsManager;
 | 
			
		||||
    mMechanicsManager = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -146,11 +140,17 @@ void MWBase::Environment::cleanup()
 | 
			
		|||
    delete mScriptManager;
 | 
			
		||||
    mScriptManager = 0;
 | 
			
		||||
 | 
			
		||||
    delete mWorld;
 | 
			
		||||
    mWorld = 0;
 | 
			
		||||
 | 
			
		||||
    delete mSoundManager;
 | 
			
		||||
    mSoundManager = 0;
 | 
			
		||||
 | 
			
		||||
    delete mWindowManager;
 | 
			
		||||
    mWindowManager = 0;
 | 
			
		||||
 | 
			
		||||
    delete mWorld;
 | 
			
		||||
    mWorld = 0;
 | 
			
		||||
    delete mInputManager;
 | 
			
		||||
    mInputManager = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MWBase::Environment& MWBase::Environment::get()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,8 @@ namespace MWWorld
 | 
			
		|||
namespace MWSound
 | 
			
		||||
{
 | 
			
		||||
    class Sound;
 | 
			
		||||
    class Sound_Decoder;
 | 
			
		||||
    typedef boost::shared_ptr<Sound_Decoder> DecoderPtr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace MWBase
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +34,7 @@ namespace MWBase
 | 
			
		|||
    class SoundManager
 | 
			
		||||
    {
 | 
			
		||||
        public:
 | 
			
		||||
 | 
			
		||||
            /* These must all fit together */
 | 
			
		||||
            enum PlayMode {
 | 
			
		||||
                Play_Normal  = 0, /* tracked, non-looping, multi-instance, environment */
 | 
			
		||||
                Play_Loop    = 1<<0, /* Sound will continually loop until explicitly stopped */
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +43,13 @@ namespace MWBase
 | 
			
		|||
                                      * but do not keep it updated (the sound will not move with
 | 
			
		||||
                                      * the object and will not stop when the object is deleted. */
 | 
			
		||||
            };
 | 
			
		||||
            enum PlayType {
 | 
			
		||||
                Play_TypeSfx   = 1<<3, /* Normal SFX sound */
 | 
			
		||||
                Play_TypeVoice = 1<<4, /* Voice sound */
 | 
			
		||||
                Play_TypeMusic = 1<<5, /* Music track */
 | 
			
		||||
                Play_TypeMovie = 1<<6, /* Movie audio track */
 | 
			
		||||
                Play_TypeMask  = Play_TypeSfx|Play_TypeVoice|Play_TypeMusic|Play_TypeMovie
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -89,12 +98,15 @@ namespace MWBase
 | 
			
		|||
            virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0;
 | 
			
		||||
            ///< Stop an actor speaking
 | 
			
		||||
 | 
			
		||||
            virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0;
 | 
			
		||||
            ///< Play a 2D audio track, using a custom decoder
 | 
			
		||||
 | 
			
		||||
            virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch,
 | 
			
		||||
                int mode=Play_Normal) = 0;
 | 
			
		||||
                                       PlayMode mode=Play_Normal) = 0;
 | 
			
		||||
            ///< Play a sound, independently of 3D-position
 | 
			
		||||
 | 
			
		||||
            virtual SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId,
 | 
			
		||||
                                 float volume, float pitch, int mode=Play_Normal) = 0;
 | 
			
		||||
                                         float volume, float pitch, PlayMode mode=Play_Normal) = 0;
 | 
			
		||||
            ///< Play a sound from an object
 | 
			
		||||
 | 
			
		||||
            virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId) = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -112,15 +124,16 @@ namespace MWBase
 | 
			
		|||
            virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const = 0;
 | 
			
		||||
            ///< Is the given sound currently playing on the given object?
 | 
			
		||||
 | 
			
		||||
            virtual void pauseSounds(int types=Play_TypeMask) = 0;
 | 
			
		||||
            ///< Pauses all currently playing sounds, including music.
 | 
			
		||||
 | 
			
		||||
            virtual void resumeSounds(int types=Play_TypeMask) = 0;
 | 
			
		||||
            ///< Resumes all previously paused sounds.
 | 
			
		||||
 | 
			
		||||
            virtual void update(float duration) = 0;
 | 
			
		||||
 | 
			
		||||
            virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    inline int operator|(SoundManager::PlayMode a, SoundManager::PlayMode b)
 | 
			
		||||
    { return static_cast<int> (a) | static_cast<int> (b); }
 | 
			
		||||
    inline int operator&(SoundManager::PlayMode a, SoundManager::PlayMode b)
 | 
			
		||||
    { return static_cast<int> (a) & static_cast<int> (b); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -306,6 +306,11 @@ namespace MWBase
 | 
			
		|||
            /// 1 - only waiting \n
 | 
			
		||||
            /// 2 - player is underwater \n
 | 
			
		||||
            /// 3 - enemies are nearby (not implemented)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            /// \todo this does not belong here
 | 
			
		||||
            virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
 | 
			
		||||
            virtual void stopVideo() = 0;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -213,22 +213,26 @@ namespace MWGui
 | 
			
		|||
 | 
			
		||||
    void LoadingScreen::changeWallpaper ()
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<std::string> splash;
 | 
			
		||||
 | 
			
		||||
        Ogre::StringVectorPtr resources = Ogre::ResourceGroupManager::getSingleton ().listResourceNames ("General", false);
 | 
			
		||||
        for (Ogre::StringVector::const_iterator it = resources->begin(); it != resources->end(); ++it)
 | 
			
		||||
        if (mResources.isNull ())
 | 
			
		||||
        {
 | 
			
		||||
            if (it->size() < 6)
 | 
			
		||||
                continue;
 | 
			
		||||
            std::string start = it->substr(0, 6);
 | 
			
		||||
            boost::to_lower(start);
 | 
			
		||||
            mResources = Ogre::StringVectorPtr (new Ogre::StringVector);
 | 
			
		||||
 | 
			
		||||
            if (start == "splash")
 | 
			
		||||
                splash.push_back (*it);
 | 
			
		||||
            Ogre::StringVectorPtr resources = Ogre::ResourceGroupManager::getSingleton ().listResourceNames ("General", false);
 | 
			
		||||
            for (Ogre::StringVector::const_iterator it = resources->begin(); it != resources->end(); ++it)
 | 
			
		||||
            {
 | 
			
		||||
                if (it->size() < 6)
 | 
			
		||||
                    continue;
 | 
			
		||||
                std::string start = it->substr(0, 6);
 | 
			
		||||
                boost::to_lower(start);
 | 
			
		||||
 | 
			
		||||
                if (start == "splash")
 | 
			
		||||
                    mResources->push_back (*it);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (splash.size())
 | 
			
		||||
 | 
			
		||||
        if (mResources->size())
 | 
			
		||||
        {
 | 
			
		||||
            std::string randomSplash = splash[rand() % splash.size()];
 | 
			
		||||
            std::string randomSplash = mResources->at (rand() % mResources->size());
 | 
			
		||||
 | 
			
		||||
            Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General");
 | 
			
		||||
            mBackgroundImage->setImageTexture (randomSplash);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,6 +42,7 @@ namespace MWGui
 | 
			
		|||
        Ogre::Rectangle2D* mRectangle;
 | 
			
		||||
        Ogre::MaterialPtr mBackgroundMaterial;
 | 
			
		||||
 | 
			
		||||
        Ogre::StringVectorPtr mResources;
 | 
			
		||||
 | 
			
		||||
        bool mLoadingOn;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,9 @@ namespace MWGui
 | 
			
		|||
      GM_Loading,
 | 
			
		||||
      GM_LoadingWallpaper,
 | 
			
		||||
 | 
			
		||||
      GM_QuickKeysMenu
 | 
			
		||||
      GM_QuickKeysMenu,
 | 
			
		||||
 | 
			
		||||
      GM_Video
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
  // Windows shown in inventory mode
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -230,6 +230,8 @@ WindowManager::~WindowManager()
 | 
			
		|||
    delete mSpellCreationDialog;
 | 
			
		||||
    delete mEnchantingDialog;
 | 
			
		||||
    delete mTrainingWindow;
 | 
			
		||||
    delete mCountDialog;
 | 
			
		||||
    delete mQuickKeysMenu;
 | 
			
		||||
 | 
			
		||||
    cleanupGarbage();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -407,6 +409,10 @@ void WindowManager::updateVisible()
 | 
			
		|||
        case GM_Loading:
 | 
			
		||||
            MyGUI::PointerManager::getInstance().setVisible(false);
 | 
			
		||||
            break;
 | 
			
		||||
        case GM_Video:
 | 
			
		||||
            MyGUI::PointerManager::getInstance().setVisible(false);
 | 
			
		||||
            mHud->setVisible(false);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            // Unsupported mode, switch back to game
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -515,6 +515,8 @@ namespace MWInput
 | 
			
		|||
    {
 | 
			
		||||
        if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings))
 | 
			
		||||
            mWindows.popGuiMode();
 | 
			
		||||
        else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video)
 | 
			
		||||
            MWBase::Environment::get().getWorld ()->stopVideo ();
 | 
			
		||||
        else
 | 
			
		||||
            mWindows.pushGuiMode (MWGui::GM_MainMenu);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@
 | 
			
		|||
 | 
			
		||||
using namespace MWRender;
 | 
			
		||||
 | 
			
		||||
// These are the Morrowind.ini defaults
 | 
			
		||||
/// \todo Replace these, once fallback values from the ini file are available.
 | 
			
		||||
float Objects::lightLinearValue = 3;
 | 
			
		||||
float Objects::lightLinearRadiusMult = 1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +31,6 @@ int Objects::uniqueID = 0;
 | 
			
		|||
 | 
			
		||||
void Objects::clearSceneNode (Ogre::SceneNode *node)
 | 
			
		||||
{
 | 
			
		||||
    /// \todo This should probably be moved into OpenEngine at some point.
 | 
			
		||||
    for (int i=node->numAttachedObjects()-1; i>=0; --i)
 | 
			
		||||
    {
 | 
			
		||||
        Ogre::MovableObject *object = node->getAttachedObject (i);
 | 
			
		||||
| 
						 | 
				
			
			@ -235,8 +234,9 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f
 | 
			
		|||
    else
 | 
			
		||||
        info.type = LT_Normal;
 | 
			
		||||
 | 
			
		||||
    // random starting phase for the animation
 | 
			
		||||
    info.time = Ogre::Math::RangeRandom(0, 2 * Ogre::Math::PI);
 | 
			
		||||
    // randomize lights animations
 | 
			
		||||
    info.time = Ogre::Math::RangeRandom(-500, +500);
 | 
			
		||||
    info.phase = Ogre::Math::RangeRandom(-500, +500);
 | 
			
		||||
 | 
			
		||||
    // adjust the lights depending if we're in an interior or exterior cell
 | 
			
		||||
    // quadratic means the light intensity falls off quite fast, resulting in a
 | 
			
		||||
| 
						 | 
				
			
			@ -373,6 +373,46 @@ void Objects::disableLights()
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace MWRender
 | 
			
		||||
{
 | 
			
		||||
    namespace Pulse
 | 
			
		||||
    {
 | 
			
		||||
        static float amplitude (float phase)
 | 
			
		||||
        {
 | 
			
		||||
            return sin (phase);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    namespace Flicker
 | 
			
		||||
    {
 | 
			
		||||
        static const float fa = 0.785398f;
 | 
			
		||||
        static const float fb = 1.17024f;
 | 
			
		||||
 | 
			
		||||
        static const float tdo = 0.94f;
 | 
			
		||||
        static const float tdm = 2.48f;
 | 
			
		||||
 | 
			
		||||
        static const float f [3] = { 1.5708f,   4.18774f, 5.19934f };
 | 
			
		||||
        static const float o [3] = { 0.804248f, 2.11115f, 3.46832f };
 | 
			
		||||
        static const float m [3] = { 1.0f,      0.785f,   0.876f   };
 | 
			
		||||
        static const float s = 0.394f;
 | 
			
		||||
 | 
			
		||||
        static const float phase_wavelength = 120.0f * 3.14159265359f / fa;
 | 
			
		||||
 | 
			
		||||
        static float frequency (float x)
 | 
			
		||||
        {
 | 
			
		||||
            return tdo + tdm * sin (fa * x);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static float amplitude (float x)
 | 
			
		||||
        {
 | 
			
		||||
            float v = 0.0f;
 | 
			
		||||
            for (int i = 0; i < 3; ++i)
 | 
			
		||||
                v += sin (fb*x*f[i] + o[1])*m[i];
 | 
			
		||||
            return v * s;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Objects::update(const float dt)
 | 
			
		||||
{
 | 
			
		||||
    std::vector<LightInfo>::iterator it = mLights.begin();
 | 
			
		||||
| 
						 | 
				
			
			@ -382,77 +422,63 @@ void Objects::update(const float dt)
 | 
			
		|||
        {
 | 
			
		||||
            Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name);
 | 
			
		||||
 | 
			
		||||
            // Light animation (pulse & flicker)
 | 
			
		||||
            it->time += dt;
 | 
			
		||||
            const float phase = std::fmod(static_cast<double> (it->time), static_cast<double>(32 * 2 * Ogre::Math::PI)) * 20;
 | 
			
		||||
            float pulseConstant;
 | 
			
		||||
            float brightness;
 | 
			
		||||
            float cycle_time;
 | 
			
		||||
            float time_distortion;
 | 
			
		||||
 | 
			
		||||
            if ((it->type == LT_Pulse) && (it->type == LT_PulseSlow))
 | 
			
		||||
            {
 | 
			
		||||
                cycle_time = 2 * Ogre::Math::PI;
 | 
			
		||||
                time_distortion = 20.0f;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                cycle_time = 500.0f;
 | 
			
		||||
                it->phase = fmod (it->phase + dt, Flicker::phase_wavelength);
 | 
			
		||||
                time_distortion = Flicker::frequency (it->phase);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            it->time += it->dir*dt*time_distortion;
 | 
			
		||||
            if (it->dir > 0 && it->time > +cycle_time)
 | 
			
		||||
            {
 | 
			
		||||
                it->dir = -1.0f;
 | 
			
		||||
                it->time = +2*cycle_time - it->time;
 | 
			
		||||
            }
 | 
			
		||||
            if (it->dir < 0 && it->time < -cycle_time)
 | 
			
		||||
            {
 | 
			
		||||
                it->dir = +1.0f;
 | 
			
		||||
                it->time = -2*cycle_time - it->time;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            static const float fast = 4.0f/1.0f;
 | 
			
		||||
            static const float slow = 1.0f/1.0f;
 | 
			
		||||
 | 
			
		||||
            // These formulas are just guesswork, but they work pretty well
 | 
			
		||||
            if (it->type == LT_Normal)
 | 
			
		||||
            {
 | 
			
		||||
                // Less than 1/255 light modifier for a constant light:
 | 
			
		||||
                pulseConstant = (const float)(1.0 + sin(phase) / 255.0 );
 | 
			
		||||
                brightness = (const float)(1.0 + Flicker::amplitude(it->time*slow) / 255.0 );
 | 
			
		||||
            }
 | 
			
		||||
            else if (it->type == LT_Flicker)
 | 
			
		||||
            {
 | 
			
		||||
                // Let's do a 50% -> 100% sine wave pulse over 1 second:
 | 
			
		||||
                // This is 75% +/- 25%
 | 
			
		||||
                pulseConstant = (const float)(0.75 + sin(phase) * 0.25);
 | 
			
		||||
 | 
			
		||||
                // Then add a 25% flicker variation:
 | 
			
		||||
                it->resetTime -= dt;
 | 
			
		||||
                if (it->resetTime < 0)
 | 
			
		||||
                {
 | 
			
		||||
                    it->flickerVariation = (rand() % 1000) / 1000 * 0.25;
 | 
			
		||||
                    it->resetTime = 0.5;
 | 
			
		||||
                }
 | 
			
		||||
                if (it->resetTime > 0.25)
 | 
			
		||||
                {
 | 
			
		||||
                    pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime * 2.0f) + pulseConstant * it->resetTime * 2.0f;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime * 2.0f) + pulseConstant * (1-it->resetTime * 2.0f);
 | 
			
		||||
                }
 | 
			
		||||
                brightness = (const float)(0.75 + Flicker::amplitude(it->time*fast) * 0.25);
 | 
			
		||||
            }
 | 
			
		||||
            else if (it->type == LT_FlickerSlow)
 | 
			
		||||
            {
 | 
			
		||||
                // Let's do a 50% -> 100% sine wave pulse over 1 second:
 | 
			
		||||
                // This is 75% +/- 25%
 | 
			
		||||
                pulseConstant = (const float)(0.75 + sin(phase / 4.0) * 0.25);
 | 
			
		||||
 | 
			
		||||
                // Then add a 25% flicker variation:
 | 
			
		||||
                it->resetTime -= dt;
 | 
			
		||||
                if (it->resetTime < 0)
 | 
			
		||||
                {
 | 
			
		||||
                    it->flickerVariation = (rand() % 1000) / 1000 * 0.25;
 | 
			
		||||
                    it->resetTime = 0.5;
 | 
			
		||||
                }
 | 
			
		||||
                if (it->resetTime > 0.5)
 | 
			
		||||
                {
 | 
			
		||||
                    pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime) + pulseConstant * it->resetTime;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime) + pulseConstant * (1-it->resetTime);
 | 
			
		||||
                }
 | 
			
		||||
                brightness = (const float)(0.75 + Flicker::amplitude(it->time*slow) * 0.25);
 | 
			
		||||
            }
 | 
			
		||||
            else if (it->type == LT_Pulse)
 | 
			
		||||
            {
 | 
			
		||||
                // Let's do a 75% -> 125% sine wave pulse over 1 second:
 | 
			
		||||
                // This is 100% +/- 25%
 | 
			
		||||
                pulseConstant = (const float)(1.0 + sin(phase) * 0.25);
 | 
			
		||||
                brightness = (const float)(1.0 + Pulse::amplitude (it->time*fast) * 0.25);
 | 
			
		||||
            }
 | 
			
		||||
            else if (it->type == LT_PulseSlow)
 | 
			
		||||
            {
 | 
			
		||||
                // Let's do a 75% -> 125% sine wave pulse over 1 second:
 | 
			
		||||
                // This is 100% +/- 25%
 | 
			
		||||
                pulseConstant = (const float)(1.0 + sin(phase / 4.0) * 0.25);
 | 
			
		||||
                brightness = (const float)(1.0 + Pulse::amplitude (it->time*slow) * 0.25);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                assert(0 && "Invalid light type");
 | 
			
		||||
 | 
			
		||||
            light->setDiffuseColour( it->colour * pulseConstant );
 | 
			
		||||
            light->setDiffuseColour(it->colour * brightness);
 | 
			
		||||
 | 
			
		||||
            ++it;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -476,8 +502,7 @@ void Objects::rebuildStaticGeometry()
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
Objects::updateObjectCell(const MWWorld::Ptr &ptr)
 | 
			
		||||
void Objects::updateObjectCell(const MWWorld::Ptr &ptr)
 | 
			
		||||
{
 | 
			
		||||
    Ogre::SceneNode *node;
 | 
			
		||||
    MWWorld::CellStore *newCell = ptr.getCell();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,16 +34,13 @@ struct LightInfo
 | 
			
		|||
    LightType type;
 | 
			
		||||
 | 
			
		||||
    // Runtime variables
 | 
			
		||||
	float flickerVariation; // 25% flicker variation, reset once every 0.5 seconds
 | 
			
		||||
	float flickerSlowVariation; // 25% flicker variation, reset once every 1.0 seconds
 | 
			
		||||
	float resetTime;
 | 
			
		||||
    long double time;
 | 
			
		||||
 | 
			
		||||
    float dir;   // direction time is running...
 | 
			
		||||
    float time;  // current time
 | 
			
		||||
    float phase; // current phase
 | 
			
		||||
 | 
			
		||||
    LightInfo() :
 | 
			
		||||
        flickerVariation(0), resetTime(0.5),
 | 
			
		||||
        flickerSlowVariation(0), time(0), interior(true),
 | 
			
		||||
        type(LT_Normal), radius(1.0)
 | 
			
		||||
        dir(1.0f), time(0.0f), phase (0.0f),
 | 
			
		||||
        interior(true), type(LT_Normal), radius(1.0)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,7 @@
 | 
			
		|||
#include "npcanimation.hpp"
 | 
			
		||||
#include "externalrendering.hpp"
 | 
			
		||||
#include "globalmap.hpp"
 | 
			
		||||
#include "videoplayer.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace MWRender;
 | 
			
		||||
using namespace Ogre;
 | 
			
		||||
| 
						 | 
				
			
			@ -160,6 +161,9 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
 | 
			
		|||
 | 
			
		||||
    mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
 | 
			
		||||
 | 
			
		||||
    mVideoPlayer = new VideoPlayer(mRendering.getScene ());
 | 
			
		||||
    mVideoPlayer->setResolution (Settings::Manager::getInt ("resolution x", "Video"), Settings::Manager::getInt ("resolution y", "Video"));
 | 
			
		||||
 | 
			
		||||
    mSun = 0;
 | 
			
		||||
 | 
			
		||||
    mDebugging = new Debugging(mMwRoot, engine);
 | 
			
		||||
| 
						 | 
				
			
			@ -181,7 +185,7 @@ RenderingManager::~RenderingManager ()
 | 
			
		|||
    delete mOcclusionQuery;
 | 
			
		||||
    delete mCompositors;
 | 
			
		||||
    delete mWater;
 | 
			
		||||
 | 
			
		||||
    delete mVideoPlayer;
 | 
			
		||||
    delete mFactory;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -332,6 +336,8 @@ void RenderingManager::update (float duration, bool paused)
 | 
			
		|||
    }
 | 
			
		||||
    mOcclusionQuery->update(duration);
 | 
			
		||||
    
 | 
			
		||||
    mVideoPlayer->update ();
 | 
			
		||||
 | 
			
		||||
    mRendering.update(duration);
 | 
			
		||||
 | 
			
		||||
    if(paused)
 | 
			
		||||
| 
						 | 
				
			
			@ -838,6 +844,8 @@ void RenderingManager::windowResized(Ogre::RenderWindow* rw)
 | 
			
		|||
    mCompositors->recreate();
 | 
			
		||||
    mWater->assignTextures();
 | 
			
		||||
 | 
			
		||||
    mVideoPlayer->setResolution (rw->getWidth(), rw->getHeight());
 | 
			
		||||
 | 
			
		||||
    const Settings::CategorySettingVector& changed = Settings::Manager::apply();
 | 
			
		||||
    MWBase::Environment::get().getInputManager()->processChangedSettings(changed); //FIXME
 | 
			
		||||
    MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); // FIXME
 | 
			
		||||
| 
						 | 
				
			
			@ -921,4 +929,14 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend
 | 
			
		|||
    rendering.setup (mRendering.getScene());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RenderingManager::playVideo(const std::string& name, bool allowSkipping)
 | 
			
		||||
{
 | 
			
		||||
    mVideoPlayer->playVideo ("video/" + name, allowSkipping);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RenderingManager::stopVideo()
 | 
			
		||||
{
 | 
			
		||||
    mVideoPlayer->stopVideo ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,7 @@ namespace MWRender
 | 
			
		|||
    class Compositors;
 | 
			
		||||
    class ExternalRendering;
 | 
			
		||||
    class GlobalMap;
 | 
			
		||||
    class VideoPlayer;
 | 
			
		||||
 | 
			
		||||
class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -195,6 +196,9 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
 | 
			
		|||
 | 
			
		||||
    void setupExternalRendering (MWRender::ExternalRendering& rendering);
 | 
			
		||||
 | 
			
		||||
    void playVideo(const std::string& name, bool allowSkipping);
 | 
			
		||||
    void stopVideo();
 | 
			
		||||
 | 
			
		||||
  protected:
 | 
			
		||||
	virtual void windowResized(Ogre::RenderWindow* rw);
 | 
			
		||||
    virtual void windowClosed(Ogre::RenderWindow* rw);
 | 
			
		||||
| 
						 | 
				
			
			@ -248,6 +252,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
 | 
			
		|||
    MWRender::Shadows* mShadows;
 | 
			
		||||
 | 
			
		||||
    MWRender::Compositors* mCompositors;
 | 
			
		||||
 | 
			
		||||
    VideoPlayer* mVideoPlayer;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1151
									
								
								apps/openmw/mwrender/videoplayer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1151
									
								
								apps/openmw/mwrender/videoplayer.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										52
									
								
								apps/openmw/mwrender/videoplayer.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								apps/openmw/mwrender/videoplayer.hpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
#ifndef VIDEOPLAYER_H
 | 
			
		||||
#define VIDEOPLAYER_H
 | 
			
		||||
 | 
			
		||||
#include <OgreMaterial.h>
 | 
			
		||||
 | 
			
		||||
namespace Ogre
 | 
			
		||||
{
 | 
			
		||||
    class SceneManager;
 | 
			
		||||
    class SceneNode;
 | 
			
		||||
    class Rectangle2D;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace MWRender
 | 
			
		||||
{
 | 
			
		||||
    struct VideoState;
 | 
			
		||||
 | 
			
		||||
    class VideoPlayer
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        VideoPlayer(Ogre::SceneManager* sceneMgr);
 | 
			
		||||
        ~VideoPlayer();
 | 
			
		||||
 | 
			
		||||
        void playVideo (const std::string& resourceName, bool allowSkipping);
 | 
			
		||||
 | 
			
		||||
        void update();
 | 
			
		||||
 | 
			
		||||
        void close();
 | 
			
		||||
        void stopVideo();
 | 
			
		||||
 | 
			
		||||
        bool isPlaying();
 | 
			
		||||
 | 
			
		||||
        void setResolution (int w, int h) { mWidth = w; mHeight = h; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        VideoState* mState;
 | 
			
		||||
 | 
			
		||||
        bool mAllowSkipping;
 | 
			
		||||
 | 
			
		||||
        Ogre::SceneManager* mSceneMgr;
 | 
			
		||||
        Ogre::MaterialPtr mVideoMaterial;
 | 
			
		||||
        Ogre::Rectangle2D* mRectangle;
 | 
			
		||||
        Ogre::Rectangle2D* mBackgroundRectangle;
 | 
			
		||||
        Ogre::SceneNode* mNode;
 | 
			
		||||
        Ogre::SceneNode* mBackgroundNode;
 | 
			
		||||
 | 
			
		||||
        int mWidth;
 | 
			
		||||
        int mHeight;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -301,10 +301,14 @@ op 0x20001ea: LowerRank
 | 
			
		|||
op 0x20001eb: LowerRank, explicit
 | 
			
		||||
op 0x20001ec: GetPCCrimeLevel
 | 
			
		||||
op 0x20001ed: SetPCCrimeLevel
 | 
			
		||||
op 0x20001ee: SetPCCrimeLevel
 | 
			
		||||
op 0x20001ee: ModPCCrimeLevel
 | 
			
		||||
op 0x20001ef: GetCurrentAIPackage
 | 
			
		||||
op 0x20001f0: GetCurrentAIPackage, explicit reference
 | 
			
		||||
op 0x20001f1: GetDetected
 | 
			
		||||
op 0x20001f2: GetDetected, explicit reference
 | 
			
		||||
 | 
			
		||||
opcodes 0x20001f3-0x3ffffff unused
 | 
			
		||||
op 0x20001f3: AddSoulGem
 | 
			
		||||
op 0x20001f4: AddSoulGem, explicit reference
 | 
			
		||||
op 0x20001f5: RemoveSoulGem
 | 
			
		||||
op 0x20001f6: RemoveSoulGem, explicit reference
 | 
			
		||||
op 0x20001f7: PlayBink
 | 
			
		||||
opcodes 0x20001f8-0x3ffffff unused
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,8 @@
 | 
			
		|||
 | 
			
		||||
#include "../mwworld/class.hpp"
 | 
			
		||||
#include "../mwworld/player.hpp"
 | 
			
		||||
#include "../mwworld/manualref.hpp"
 | 
			
		||||
#include "../mwworld/containerstore.hpp"
 | 
			
		||||
 | 
			
		||||
#include "../mwmechanics/npcstats.hpp"
 | 
			
		||||
#include "../mwmechanics/creaturestats.hpp"
 | 
			
		||||
| 
						 | 
				
			
			@ -25,6 +27,22 @@ namespace MWScript
 | 
			
		|||
{
 | 
			
		||||
    namespace Misc
 | 
			
		||||
    {
 | 
			
		||||
        class OpPlayBink : public Interpreter::Opcode0
 | 
			
		||||
        {
 | 
			
		||||
        public:
 | 
			
		||||
 | 
			
		||||
            virtual void execute (Interpreter::Runtime& runtime)
 | 
			
		||||
            {
 | 
			
		||||
                std::string name = runtime.getStringLiteral (runtime[0].mInteger);
 | 
			
		||||
                runtime.pop();
 | 
			
		||||
 | 
			
		||||
                bool allowSkipping = runtime[0].mInteger;
 | 
			
		||||
                runtime.pop();
 | 
			
		||||
 | 
			
		||||
                MWBase::Environment::get().getWorld ()->playVideo (name, allowSkipping);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        class OpGetPcSleep : public Interpreter::Opcode0
 | 
			
		||||
        {
 | 
			
		||||
        public:
 | 
			
		||||
| 
						 | 
				
			
			@ -255,7 +273,7 @@ namespace MWScript
 | 
			
		|||
            static bool sActivate;
 | 
			
		||||
 | 
			
		||||
        public:
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
            virtual void execute(Interpreter::Runtime &runtime)
 | 
			
		||||
            {
 | 
			
		||||
                InterpreterContext& context =
 | 
			
		||||
| 
						 | 
				
			
			@ -306,6 +324,65 @@ namespace MWScript
 | 
			
		|||
                }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        template<class R>
 | 
			
		||||
        class OpAddSoulGem : public Interpreter::Opcode0
 | 
			
		||||
        {
 | 
			
		||||
            public:
 | 
			
		||||
 | 
			
		||||
                virtual void execute (Interpreter::Runtime& runtime)
 | 
			
		||||
                {
 | 
			
		||||
                    MWWorld::Ptr ptr = R()(runtime);
 | 
			
		||||
 | 
			
		||||
                    std::string creature = runtime.getStringLiteral (runtime[0].mInteger);
 | 
			
		||||
                    runtime.pop();
 | 
			
		||||
 | 
			
		||||
                    std::string gem = runtime.getStringLiteral (runtime[0].mInteger);
 | 
			
		||||
                    runtime.pop();
 | 
			
		||||
 | 
			
		||||
                    const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
 | 
			
		||||
                    store.get<ESM::Creature>().find(creature); // This line throws an exception if it can't find the creature
 | 
			
		||||
 | 
			
		||||
                    MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), gem);
 | 
			
		||||
 | 
			
		||||
                    ref.getPtr().getRefData().setCount (1);
 | 
			
		||||
 | 
			
		||||
                    ref.getPtr().getCellRef().mSoul = creature;
 | 
			
		||||
 | 
			
		||||
                    MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr());
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        template<class R>
 | 
			
		||||
        class OpRemoveSoulGem : public Interpreter::Opcode0
 | 
			
		||||
        {
 | 
			
		||||
            public:
 | 
			
		||||
 | 
			
		||||
                virtual void execute (Interpreter::Runtime& runtime)
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                    MWWorld::Ptr ptr = R()(runtime);
 | 
			
		||||
 | 
			
		||||
                    std::string soul = runtime.getStringLiteral (runtime[0].mInteger);
 | 
			
		||||
                    runtime.pop();
 | 
			
		||||
 | 
			
		||||
                    MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (::Misc::StringUtils::ciEqual(iter->getCellRef().mSoul, soul))
 | 
			
		||||
                        {
 | 
			
		||||
                            if (iter->getRefData().getCount() <= 1)
 | 
			
		||||
                                iter->getRefData().setCount (0);
 | 
			
		||||
                            else
 | 
			
		||||
                                iter->getRefData().setCount (iter->getRefData().getCount() - 1);
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        template <class R>
 | 
			
		||||
        class OpGetAttacked : public Interpreter::Opcode0
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -414,6 +491,10 @@ namespace MWScript
 | 
			
		|||
        const int opcodeGetLockedExplicit = 0x20001c8;
 | 
			
		||||
        const int opcodeGetEffect = 0x20001cf;
 | 
			
		||||
        const int opcodeGetEffectExplicit = 0x20001d0;
 | 
			
		||||
        const int opcodeAddSoulGem = 0x20001f3;
 | 
			
		||||
        const int opcodeAddSoulGemExplicit = 0x20001f4;
 | 
			
		||||
        const int opcodeRemoveSoulGem = 0x20001f5;
 | 
			
		||||
        const int opcodeRemoveSoulGemExplicit = 0x20001f6;
 | 
			
		||||
        const int opcodeGetAttacked = 0x20001d3;
 | 
			
		||||
        const int opcodeGetAttackedExplicit = 0x20001d4;
 | 
			
		||||
        const int opcodeGetWeaponDrawn = 0x20001d7;
 | 
			
		||||
| 
						 | 
				
			
			@ -425,6 +506,8 @@ namespace MWScript
 | 
			
		|||
        const int opcodeSetDeleteExplicit = 0x20001e6;
 | 
			
		||||
        const int opcodeGetSquareRoot = 0x20001e7;
 | 
			
		||||
 | 
			
		||||
        const int opcodePlayBink = 0x20001f7;
 | 
			
		||||
 | 
			
		||||
        void registerExtensions (Compiler::Extensions& extensions)
 | 
			
		||||
        {
 | 
			
		||||
            extensions.registerFunction ("xbox", 'l', "", opcodeXBox);
 | 
			
		||||
| 
						 | 
				
			
			@ -450,8 +533,11 @@ namespace MWScript
 | 
			
		|||
            extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode);
 | 
			
		||||
            extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep);
 | 
			
		||||
            extensions.registerInstruction ("wakeuppc", "", opcodeWakeUpPc);
 | 
			
		||||
            extensions.registerInstruction ("playbink", "Sl", opcodePlayBink);
 | 
			
		||||
            extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit);
 | 
			
		||||
            extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit);
 | 
			
		||||
            extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit);
 | 
			
		||||
            extensions.registerInstruction ("removesoulgem", "c", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit);
 | 
			
		||||
            extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit);
 | 
			
		||||
            extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit);
 | 
			
		||||
            extensions.registerFunction ("getspelleffects", 'l', "c", opcodeGetSpellEffects, opcodeGetSpellEffectsExplicit);
 | 
			
		||||
| 
						 | 
				
			
			@ -481,10 +567,15 @@ namespace MWScript
 | 
			
		|||
            interpreter.installSegment5 (opcodeToggleVanityMode, new OpToggleVanityMode);
 | 
			
		||||
            interpreter.installSegment5 (opcodeGetPcSleep, new OpGetPcSleep);
 | 
			
		||||
            interpreter.installSegment5 (opcodeWakeUpPc, new OpWakeUpPc);
 | 
			
		||||
            interpreter.installSegment5 (opcodePlayBink, new OpPlayBink);
 | 
			
		||||
            interpreter.installSegment5 (opcodeGetLocked, new OpGetLocked<ImplicitRef>);
 | 
			
		||||
            interpreter.installSegment5 (opcodeGetLockedExplicit, new OpGetLocked<ExplicitRef>);
 | 
			
		||||
            interpreter.installSegment5 (opcodeGetEffect, new OpGetEffect<ImplicitRef>);
 | 
			
		||||
            interpreter.installSegment5 (opcodeGetEffectExplicit, new OpGetEffect<ExplicitRef>);
 | 
			
		||||
            interpreter.installSegment5 (opcodeAddSoulGem, new OpAddSoulGem<ImplicitRef>);
 | 
			
		||||
            interpreter.installSegment5 (opcodeAddSoulGemExplicit, new OpAddSoulGem<ExplicitRef>);
 | 
			
		||||
            interpreter.installSegment5 (opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>);
 | 
			
		||||
            interpreter.installSegment5 (opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>);
 | 
			
		||||
            interpreter.installSegment5 (opcodeGetAttacked, new OpGetAttacked<ImplicitRef>);
 | 
			
		||||
            interpreter.installSegment5 (opcodeGetAttackedExplicit, new OpGetAttacked<ExplicitRef>);
 | 
			
		||||
            interpreter.installSegment5 (opcodeGetWeaponDrawn, new OpGetWeaponDrawn<ImplicitRef>);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,7 +118,8 @@ namespace MWScript
 | 
			
		|||
                    std::string sound = runtime.getStringLiteral (runtime[0].mInteger);
 | 
			
		||||
                    runtime.pop();
 | 
			
		||||
 | 
			
		||||
                    MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWBase::SoundManager::Play_Loop : 0);
 | 
			
		||||
                    MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWBase::SoundManager::Play_Loop :
 | 
			
		||||
                                                                                                             MWBase::SoundManager::Play_Normal);
 | 
			
		||||
                }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -144,7 +145,8 @@ namespace MWScript
 | 
			
		|||
                    Interpreter::Type_Float pitch = runtime[0].mFloat;
 | 
			
		||||
                    runtime.pop();
 | 
			
		||||
 | 
			
		||||
                    MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, volume, pitch, mLoop ? MWBase::SoundManager::Play_Loop : 0);
 | 
			
		||||
                    MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, volume, pitch, mLoop ? MWBase::SoundManager::Play_Loop :
 | 
			
		||||
                                                                                                                  MWBase::SoundManager::Play_Normal);
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,6 +53,9 @@ public:
 | 
			
		|||
      : mStream(stream), refs(1)
 | 
			
		||||
    { }
 | 
			
		||||
    virtual ~OgreFile() { }
 | 
			
		||||
 | 
			
		||||
    Ogre::String getName()
 | 
			
		||||
    { return mStream->getName(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +63,7 @@ void Audiere_Decoder::open(const std::string &fname)
 | 
			
		|||
{
 | 
			
		||||
    close();
 | 
			
		||||
 | 
			
		||||
    audiere::FilePtr file(new OgreFile(mResourceMgr.openResource(fname)));
 | 
			
		||||
    mSoundFile = audiere::FilePtr(new OgreFile(mResourceMgr.openResource(fname)));
 | 
			
		||||
    mSoundSource = audiere::OpenSampleSource(file);
 | 
			
		||||
 | 
			
		||||
    int channels, srate;
 | 
			
		||||
| 
						 | 
				
			
			@ -86,9 +89,15 @@ void Audiere_Decoder::open(const std::string &fname)
 | 
			
		|||
 | 
			
		||||
void Audiere_Decoder::close()
 | 
			
		||||
{
 | 
			
		||||
    mSoundFile = NULL;
 | 
			
		||||
    mSoundSource = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string Audiere_Decoder::getName()
 | 
			
		||||
{
 | 
			
		||||
    return mSoundFile->getName();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Audiere_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
 | 
			
		||||
{
 | 
			
		||||
    *samplerate = mSampleRate;
 | 
			
		||||
| 
						 | 
				
			
			@ -108,6 +117,11 @@ void Audiere_Decoder::rewind()
 | 
			
		|||
    mSoundSource->reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t Audiere_Decoder::getSampleOffset()
 | 
			
		||||
{
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Audiere_Decoder::Audiere_Decoder()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,7 @@ namespace MWSound
 | 
			
		|||
{
 | 
			
		||||
    class Audiere_Decoder : public Sound_Decoder
 | 
			
		||||
    {
 | 
			
		||||
        audiere::FilePtr mSoundFile;
 | 
			
		||||
        audiere::SampleSourcePtr mSoundSource;
 | 
			
		||||
        int mSampleRate;
 | 
			
		||||
        SampleType mSampleType;
 | 
			
		||||
| 
						 | 
				
			
			@ -20,10 +21,12 @@ namespace MWSound
 | 
			
		|||
        virtual void open(const std::string &fname);
 | 
			
		||||
        virtual void close();
 | 
			
		||||
 | 
			
		||||
        virtual std::string getName();
 | 
			
		||||
        virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
 | 
			
		||||
 | 
			
		||||
        virtual size_t read(char *buffer, size_t bytes);
 | 
			
		||||
        virtual void rewind();
 | 
			
		||||
        virtual size_t getSampleOffset();
 | 
			
		||||
 | 
			
		||||
        Audiere_Decoder& operator=(const Audiere_Decoder &rhs);
 | 
			
		||||
        Audiere_Decoder(const Audiere_Decoder &rhs);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,28 +15,6 @@ static void fail(const std::string &msg)
 | 
			
		|||
{ throw std::runtime_error("FFmpeg exception: "+msg); }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct PacketList {
 | 
			
		||||
    AVPacket pkt;
 | 
			
		||||
    PacketList *next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FFmpeg_Decoder::MyStream {
 | 
			
		||||
    AVCodecContext *mCodecCtx;
 | 
			
		||||
    int mStreamIdx;
 | 
			
		||||
 | 
			
		||||
    PacketList *mPackets;
 | 
			
		||||
 | 
			
		||||
    char *mDecodedData;
 | 
			
		||||
    size_t mDecodedDataSize;
 | 
			
		||||
 | 
			
		||||
    FFmpeg_Decoder *mParent;
 | 
			
		||||
 | 
			
		||||
    void clearPackets();
 | 
			
		||||
    void *getAVAudioData(size_t *length);
 | 
			
		||||
    size_t readAVAudioData(void *data, size_t length);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size)
 | 
			
		||||
{
 | 
			
		||||
    Ogre::DataStreamPtr stream = static_cast<FFmpeg_Decoder*>(user_data)->mDataStream;
 | 
			
		||||
| 
						 | 
				
			
			@ -72,166 +50,84 @@ int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence)
 | 
			
		|||
/* Used by getAV*Data to search for more compressed data, and buffer it in the
 | 
			
		||||
 * correct stream. It won't buffer data for streams that the app doesn't have a
 | 
			
		||||
 * handle for. */
 | 
			
		||||
bool FFmpeg_Decoder::getNextPacket(int streamidx)
 | 
			
		||||
bool FFmpeg_Decoder::getNextPacket()
 | 
			
		||||
{
 | 
			
		||||
    PacketList *packet;
 | 
			
		||||
    if(!mStream)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    packet = (PacketList*)av_malloc(sizeof(*packet));
 | 
			
		||||
    packet->next = NULL;
 | 
			
		||||
 | 
			
		||||
next_packet:
 | 
			
		||||
    while(av_read_frame(mFormatCtx, &packet->pkt) >= 0)
 | 
			
		||||
    int stream_idx = mStream - mFormatCtx->streams;
 | 
			
		||||
    while(av_read_frame(mFormatCtx, &mPacket) >= 0)
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<MyStream*>::iterator iter = mStreams.begin();
 | 
			
		||||
 | 
			
		||||
        /* Check each stream the user has a handle for, looking for the one
 | 
			
		||||
         * this packet belongs to */
 | 
			
		||||
        while(iter != mStreams.end())
 | 
			
		||||
        /* Check if the packet belongs to this stream */
 | 
			
		||||
        if(stream_idx == mPacket.stream_index)
 | 
			
		||||
        {
 | 
			
		||||
            if((*iter)->mStreamIdx == packet->pkt.stream_index)
 | 
			
		||||
            {
 | 
			
		||||
                PacketList **last;
 | 
			
		||||
 | 
			
		||||
                last = &(*iter)->mPackets;
 | 
			
		||||
                while(*last != NULL)
 | 
			
		||||
                    last = &(*last)->next;
 | 
			
		||||
 | 
			
		||||
                *last = packet;
 | 
			
		||||
                if((*iter)->mStreamIdx == streamidx)
 | 
			
		||||
                    return true;
 | 
			
		||||
 | 
			
		||||
                packet = (PacketList*)av_malloc(sizeof(*packet));
 | 
			
		||||
                packet->next = NULL;
 | 
			
		||||
                goto next_packet;
 | 
			
		||||
            }
 | 
			
		||||
            iter++;
 | 
			
		||||
            if((uint64_t)mPacket.pts != AV_NOPTS_VALUE)
 | 
			
		||||
                mNextPts = av_q2d((*mStream)->time_base)*mPacket.pts;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Free the packet and look for another */
 | 
			
		||||
        av_free_packet(&packet->pkt);
 | 
			
		||||
        av_free_packet(&mPacket);
 | 
			
		||||
    }
 | 
			
		||||
    av_free(packet);
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FFmpeg_Decoder::MyStream::clearPackets()
 | 
			
		||||
bool FFmpeg_Decoder::getAVAudioData()
 | 
			
		||||
{
 | 
			
		||||
    while(mPackets)
 | 
			
		||||
    {
 | 
			
		||||
        PacketList *self = mPackets;
 | 
			
		||||
        mPackets = self->next;
 | 
			
		||||
    int got_frame, len;
 | 
			
		||||
 | 
			
		||||
        av_free_packet(&self->pkt);
 | 
			
		||||
        av_free(self);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    if((*mStream)->codec->codec_type != AVMEDIA_TYPE_AUDIO)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
void *FFmpeg_Decoder::MyStream::getAVAudioData(size_t *length)
 | 
			
		||||
{
 | 
			
		||||
    int size;
 | 
			
		||||
    int len;
 | 
			
		||||
    do {
 | 
			
		||||
        if(mPacket.size == 0 && !getNextPacket())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
    if(length) *length = 0;
 | 
			
		||||
    if(mCodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
 | 
			
		||||
        return NULL;
 | 
			
		||||
        /* Decode some data, and check for errors */
 | 
			
		||||
        if((len=avcodec_decode_audio4((*mStream)->codec, mFrame, &got_frame, &mPacket)) < 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
    mDecodedDataSize = 0;
 | 
			
		||||
 | 
			
		||||
next_packet:
 | 
			
		||||
    if(!mPackets && !mParent->getNextPacket(mStreamIdx))
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    /* Decode some data, and check for errors */
 | 
			
		||||
    size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
 | 
			
		||||
    while((len=avcodec_decode_audio3(mCodecCtx, (int16_t*)mDecodedData, &size,
 | 
			
		||||
                                     &mPackets->pkt)) == 0)
 | 
			
		||||
    {
 | 
			
		||||
        PacketList *self;
 | 
			
		||||
 | 
			
		||||
        if(size > 0)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        /* Packet went unread and no data was given? Drop it and try the next,
 | 
			
		||||
         * I guess... */
 | 
			
		||||
        self = mPackets;
 | 
			
		||||
        mPackets = self->next;
 | 
			
		||||
 | 
			
		||||
        av_free_packet(&self->pkt);
 | 
			
		||||
        av_free(self);
 | 
			
		||||
 | 
			
		||||
        if(!mPackets)
 | 
			
		||||
            goto next_packet;
 | 
			
		||||
 | 
			
		||||
        size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(len < 0)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    if(len < mPackets->pkt.size)
 | 
			
		||||
    {
 | 
			
		||||
        /* Move the unread data to the front and clear the end bits */
 | 
			
		||||
        int remaining = mPackets->pkt.size - len;
 | 
			
		||||
        memmove(mPackets->pkt.data, &mPackets->pkt.data[len], remaining);
 | 
			
		||||
        memset(&mPackets->pkt.data[remaining], 0, mPackets->pkt.size - remaining);
 | 
			
		||||
        mPackets->pkt.size -= len;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        PacketList *self;
 | 
			
		||||
        int remaining = mPacket.size - len;
 | 
			
		||||
        if(remaining <= 0)
 | 
			
		||||
            av_free_packet(&mPacket);
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            memmove(mPacket.data, &mPacket.data[len], remaining);
 | 
			
		||||
            av_shrink_packet(&mPacket, remaining);
 | 
			
		||||
        }
 | 
			
		||||
    } while(got_frame == 0 || mFrame->nb_samples == 0);
 | 
			
		||||
    mNextPts += (double)mFrame->nb_samples / (double)(*mStream)->codec->sample_rate;
 | 
			
		||||
 | 
			
		||||
        self = mPackets;
 | 
			
		||||
        mPackets = self->next;
 | 
			
		||||
 | 
			
		||||
        av_free_packet(&self->pkt);
 | 
			
		||||
        av_free(self);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(size == 0)
 | 
			
		||||
        goto next_packet;
 | 
			
		||||
 | 
			
		||||
    /* Set the output buffer size */
 | 
			
		||||
    mDecodedDataSize = size;
 | 
			
		||||
    if(length) *length = mDecodedDataSize;
 | 
			
		||||
 | 
			
		||||
    return mDecodedData;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length)
 | 
			
		||||
size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length)
 | 
			
		||||
{
 | 
			
		||||
    size_t dec = 0;
 | 
			
		||||
 | 
			
		||||
    while(dec < length)
 | 
			
		||||
    {
 | 
			
		||||
        /* If there's no decoded data, find some */
 | 
			
		||||
        if(mDecodedDataSize == 0)
 | 
			
		||||
        if(mFramePos >= mFrameSize)
 | 
			
		||||
        {
 | 
			
		||||
            if(getAVAudioData(NULL) == NULL)
 | 
			
		||||
            if(!getAVAudioData())
 | 
			
		||||
                break;
 | 
			
		||||
            mFramePos = 0;
 | 
			
		||||
            mFrameSize = mFrame->nb_samples * (*mStream)->codec->channels *
 | 
			
		||||
                         av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(mDecodedDataSize > 0)
 | 
			
		||||
        {
 | 
			
		||||
            /* Get the amount of bytes remaining to be written, and clamp to
 | 
			
		||||
             * the amount of decoded data we have */
 | 
			
		||||
            size_t rem = length-dec;
 | 
			
		||||
            if(rem > mDecodedDataSize)
 | 
			
		||||
                rem = mDecodedDataSize;
 | 
			
		||||
        /* Get the amount of bytes remaining to be written, and clamp to
 | 
			
		||||
         * the amount of decoded data we have */
 | 
			
		||||
        size_t rem = std::min<size_t>(length-dec, mFrameSize-mFramePos);
 | 
			
		||||
 | 
			
		||||
            /* Copy the data to the app's buffer and increment */
 | 
			
		||||
            if(data != NULL)
 | 
			
		||||
            {
 | 
			
		||||
                memcpy(data, mDecodedData, rem);
 | 
			
		||||
                data = (char*)data + rem;
 | 
			
		||||
            }
 | 
			
		||||
            dec += rem;
 | 
			
		||||
 | 
			
		||||
            /* If there's any decoded data left, move it to the front of the
 | 
			
		||||
             * buffer for next time */
 | 
			
		||||
            if(rem < mDecodedDataSize)
 | 
			
		||||
                memmove(mDecodedData, &mDecodedData[rem], mDecodedDataSize - rem);
 | 
			
		||||
            mDecodedDataSize -= rem;
 | 
			
		||||
        }
 | 
			
		||||
        /* Copy the data to the app's buffer and increment */
 | 
			
		||||
        memcpy(data, mFrame->data[0]+mFramePos, rem);
 | 
			
		||||
        data = (char*)data + rem;
 | 
			
		||||
        dec += rem;
 | 
			
		||||
        mFramePos += rem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Return the number of bytes we were able to get */
 | 
			
		||||
| 
						 | 
				
			
			@ -239,7 +135,6 @@ size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void FFmpeg_Decoder::open(const std::string &fname)
 | 
			
		||||
{
 | 
			
		||||
    close();
 | 
			
		||||
| 
						 | 
				
			
			@ -265,140 +160,155 @@ void FFmpeg_Decoder::open(const std::string &fname)
 | 
			
		|||
        {
 | 
			
		||||
            if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
 | 
			
		||||
            {
 | 
			
		||||
                std::auto_ptr<MyStream> stream(new MyStream);
 | 
			
		||||
                stream->mCodecCtx = mFormatCtx->streams[j]->codec;
 | 
			
		||||
                stream->mStreamIdx = j;
 | 
			
		||||
                stream->mPackets = NULL;
 | 
			
		||||
 | 
			
		||||
                AVCodec *codec = avcodec_find_decoder(stream->mCodecCtx->codec_id);
 | 
			
		||||
                if(!codec)
 | 
			
		||||
                {
 | 
			
		||||
                    std::stringstream ss("No codec found for id ");
 | 
			
		||||
                    ss << stream->mCodecCtx->codec_id;
 | 
			
		||||
                    fail(ss.str());
 | 
			
		||||
                }
 | 
			
		||||
                if(avcodec_open(stream->mCodecCtx, codec) < 0)
 | 
			
		||||
                    fail("Failed to open audio codec " + std::string(codec->long_name));
 | 
			
		||||
 | 
			
		||||
                stream->mDecodedData = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
 | 
			
		||||
                stream->mDecodedDataSize = 0;
 | 
			
		||||
 | 
			
		||||
                stream->mParent = this;
 | 
			
		||||
                mStreams.push_back(stream.release());
 | 
			
		||||
                mStream = &mFormatCtx->streams[j];
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if(mStreams.empty())
 | 
			
		||||
        if(!mStream)
 | 
			
		||||
            fail("No audio streams in "+fname);
 | 
			
		||||
 | 
			
		||||
        AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id);
 | 
			
		||||
        if(!codec)
 | 
			
		||||
        {
 | 
			
		||||
            std::stringstream ss("No codec found for id ");
 | 
			
		||||
            ss << (*mStream)->codec->codec_id;
 | 
			
		||||
            fail(ss.str());
 | 
			
		||||
        }
 | 
			
		||||
        if(avcodec_open2((*mStream)->codec, codec, NULL) < 0)
 | 
			
		||||
            fail("Failed to open audio codec " + std::string(codec->long_name));
 | 
			
		||||
 | 
			
		||||
        mFrame = avcodec_alloc_frame();
 | 
			
		||||
    }
 | 
			
		||||
    catch(std::exception &e)
 | 
			
		||||
    {
 | 
			
		||||
        av_close_input_file(mFormatCtx);
 | 
			
		||||
        mFormatCtx = NULL;
 | 
			
		||||
        avformat_close_input(&mFormatCtx);
 | 
			
		||||
        throw;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FFmpeg_Decoder::close()
 | 
			
		||||
{
 | 
			
		||||
    while(!mStreams.empty())
 | 
			
		||||
    {
 | 
			
		||||
        MyStream *stream = mStreams.front();
 | 
			
		||||
    if(mStream)
 | 
			
		||||
        avcodec_close((*mStream)->codec);
 | 
			
		||||
    mStream = NULL;
 | 
			
		||||
 | 
			
		||||
        stream->clearPackets();
 | 
			
		||||
        avcodec_close(stream->mCodecCtx);
 | 
			
		||||
        av_free(stream->mDecodedData);
 | 
			
		||||
        delete stream;
 | 
			
		||||
    av_free_packet(&mPacket);
 | 
			
		||||
    av_freep(&mFrame);
 | 
			
		||||
 | 
			
		||||
        mStreams.erase(mStreams.begin());
 | 
			
		||||
    }
 | 
			
		||||
    if(mFormatCtx)
 | 
			
		||||
    {
 | 
			
		||||
        AVIOContext* context = mFormatCtx->pb;
 | 
			
		||||
        avformat_close_input(&mFormatCtx);
 | 
			
		||||
        av_free(context);
 | 
			
		||||
        mFormatCtx->pb = NULL;
 | 
			
		||||
        av_close_input_file(mFormatCtx);
 | 
			
		||||
    }
 | 
			
		||||
    mFormatCtx = NULL;
 | 
			
		||||
 | 
			
		||||
    mDataStream.setNull();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string FFmpeg_Decoder::getName()
 | 
			
		||||
{
 | 
			
		||||
    return mFormatCtx->filename;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
 | 
			
		||||
{
 | 
			
		||||
    if(mStreams.empty())
 | 
			
		||||
    if(!mStream)
 | 
			
		||||
        fail("No audio stream info");
 | 
			
		||||
 | 
			
		||||
    MyStream *stream = mStreams[0];
 | 
			
		||||
    if(stream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8)
 | 
			
		||||
    if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8)
 | 
			
		||||
        *type = SampleType_UInt8;
 | 
			
		||||
    else if(stream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S16)
 | 
			
		||||
    else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16)
 | 
			
		||||
        *type = SampleType_Int16;
 | 
			
		||||
    else
 | 
			
		||||
        fail(std::string("Unsupported sample format: ")+
 | 
			
		||||
             av_get_sample_fmt_name(stream->mCodecCtx->sample_fmt));
 | 
			
		||||
             av_get_sample_fmt_name((*mStream)->codec->sample_fmt));
 | 
			
		||||
 | 
			
		||||
    if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO)
 | 
			
		||||
    if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_MONO)
 | 
			
		||||
        *chans = ChannelConfig_Mono;
 | 
			
		||||
    else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_STEREO)
 | 
			
		||||
    else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_STEREO)
 | 
			
		||||
        *chans = ChannelConfig_Stereo;
 | 
			
		||||
    else if(stream->mCodecCtx->channel_layout == 0)
 | 
			
		||||
    else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_QUAD)
 | 
			
		||||
        *chans = ChannelConfig_Quad;
 | 
			
		||||
    else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_5POINT1)
 | 
			
		||||
        *chans = ChannelConfig_5point1;
 | 
			
		||||
    else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_7POINT1)
 | 
			
		||||
        *chans = ChannelConfig_7point1;
 | 
			
		||||
    else if((*mStream)->codec->channel_layout == 0)
 | 
			
		||||
    {
 | 
			
		||||
        /* Unknown channel layout. Try to guess. */
 | 
			
		||||
        if(stream->mCodecCtx->channels == 1)
 | 
			
		||||
        if((*mStream)->codec->channels == 1)
 | 
			
		||||
            *chans = ChannelConfig_Mono;
 | 
			
		||||
        else if(stream->mCodecCtx->channels == 2)
 | 
			
		||||
        else if((*mStream)->codec->channels == 2)
 | 
			
		||||
            *chans = ChannelConfig_Stereo;
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            std::stringstream sstr("Unsupported raw channel count: ");
 | 
			
		||||
            sstr << stream->mCodecCtx->channels;
 | 
			
		||||
            sstr << (*mStream)->codec->channels;
 | 
			
		||||
            fail(sstr.str());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        char str[1024];
 | 
			
		||||
        av_get_channel_layout_string(str, sizeof(str), stream->mCodecCtx->channels,
 | 
			
		||||
                                     stream->mCodecCtx->channel_layout);
 | 
			
		||||
        av_get_channel_layout_string(str, sizeof(str), (*mStream)->codec->channels,
 | 
			
		||||
                                     (*mStream)->codec->channel_layout);
 | 
			
		||||
        fail(std::string("Unsupported channel layout: ")+str);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *samplerate = stream->mCodecCtx->sample_rate;
 | 
			
		||||
    *samplerate = (*mStream)->codec->sample_rate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FFmpeg_Decoder::read(char *buffer, size_t bytes)
 | 
			
		||||
{
 | 
			
		||||
    if(mStreams.empty())
 | 
			
		||||
        fail("No audio streams");
 | 
			
		||||
 | 
			
		||||
    return mStreams.front()->readAVAudioData(buffer, bytes);
 | 
			
		||||
    if(!mStream)
 | 
			
		||||
        fail("No audio stream");
 | 
			
		||||
    return readAVAudioData(buffer, bytes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FFmpeg_Decoder::readAll(std::vector<char> &output)
 | 
			
		||||
{
 | 
			
		||||
    if(mStreams.empty())
 | 
			
		||||
        fail("No audio streams");
 | 
			
		||||
    MyStream *stream = mStreams.front();
 | 
			
		||||
    char *inbuf;
 | 
			
		||||
    size_t got;
 | 
			
		||||
    if(!mStream)
 | 
			
		||||
        fail("No audio stream");
 | 
			
		||||
 | 
			
		||||
    while((inbuf=(char*)stream->getAVAudioData(&got)) != NULL && got > 0)
 | 
			
		||||
    while(getAVAudioData())
 | 
			
		||||
    {
 | 
			
		||||
        size_t got = mFrame->nb_samples * (*mStream)->codec->channels *
 | 
			
		||||
                     av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
 | 
			
		||||
        const char *inbuf = reinterpret_cast<char*>(mFrame->data[0]);
 | 
			
		||||
        output.insert(output.end(), inbuf, inbuf+got);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FFmpeg_Decoder::rewind()
 | 
			
		||||
{
 | 
			
		||||
    av_seek_frame(mFormatCtx, -1, 0, 0);
 | 
			
		||||
    std::for_each(mStreams.begin(), mStreams.end(), std::mem_fun(&MyStream::clearPackets));
 | 
			
		||||
    int stream_idx = mStream - mFormatCtx->streams;
 | 
			
		||||
    if(av_seek_frame(mFormatCtx, stream_idx, 0, 0) < 0)
 | 
			
		||||
        fail("Failed to seek in audio stream");
 | 
			
		||||
    av_free_packet(&mPacket);
 | 
			
		||||
    mFrameSize = mFramePos = 0;
 | 
			
		||||
    mNextPts = 0.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FFmpeg_Decoder::FFmpeg_Decoder() : mFormatCtx(NULL)
 | 
			
		||||
size_t FFmpeg_Decoder::getSampleOffset()
 | 
			
		||||
{
 | 
			
		||||
    static bool done_init = false;
 | 
			
		||||
    int delay = (mFrameSize-mFramePos) / (*mStream)->codec->channels /
 | 
			
		||||
                av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
 | 
			
		||||
    return (int)(mNextPts*(*mStream)->codec->sample_rate) - delay;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FFmpeg_Decoder::FFmpeg_Decoder()
 | 
			
		||||
  : mFormatCtx(NULL)
 | 
			
		||||
  , mStream(NULL)
 | 
			
		||||
  , mFrame(NULL)
 | 
			
		||||
  , mFrameSize(0)
 | 
			
		||||
  , mFramePos(0)
 | 
			
		||||
  , mNextPts(0.0)
 | 
			
		||||
{
 | 
			
		||||
    memset(&mPacket, 0, sizeof(mPacket));
 | 
			
		||||
 | 
			
		||||
    /* We need to make sure ffmpeg is initialized. Optionally silence warning
 | 
			
		||||
     * output from the lib */
 | 
			
		||||
    static bool done_init = false;
 | 
			
		||||
    if(!done_init)
 | 
			
		||||
    {
 | 
			
		||||
        av_register_all();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,8 +10,8 @@
 | 
			
		|||
#include <stdint.h>
 | 
			
		||||
extern "C"
 | 
			
		||||
{
 | 
			
		||||
#include <avcodec.h>
 | 
			
		||||
#include <avformat.h>
 | 
			
		||||
#include <libavcodec/avcodec.h>
 | 
			
		||||
#include <libavformat/avformat.h>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "sound_decoder.hpp"
 | 
			
		||||
| 
						 | 
				
			
			@ -22,25 +22,36 @@ namespace MWSound
 | 
			
		|||
    class FFmpeg_Decoder : public Sound_Decoder
 | 
			
		||||
    {
 | 
			
		||||
        AVFormatContext *mFormatCtx;
 | 
			
		||||
        AVStream **mStream;
 | 
			
		||||
 | 
			
		||||
        struct MyStream;
 | 
			
		||||
        std::vector<MyStream*> mStreams;
 | 
			
		||||
        AVPacket mPacket;
 | 
			
		||||
        AVFrame *mFrame;
 | 
			
		||||
 | 
			
		||||
        bool getNextPacket(int streamidx);
 | 
			
		||||
        int mFrameSize;
 | 
			
		||||
        int mFramePos;
 | 
			
		||||
 | 
			
		||||
        double mNextPts;
 | 
			
		||||
 | 
			
		||||
        bool getNextPacket();
 | 
			
		||||
 | 
			
		||||
        Ogre::DataStreamPtr mDataStream;
 | 
			
		||||
        static int readPacket(void *user_data, uint8_t *buf, int buf_size);
 | 
			
		||||
        static int writePacket(void *user_data, uint8_t *buf, int buf_size);
 | 
			
		||||
        static int64_t seek(void *user_data, int64_t offset, int whence);
 | 
			
		||||
 | 
			
		||||
        bool getAVAudioData();
 | 
			
		||||
        size_t readAVAudioData(void *data, size_t length);
 | 
			
		||||
 | 
			
		||||
        virtual void open(const std::string &fname);
 | 
			
		||||
        virtual void close();
 | 
			
		||||
 | 
			
		||||
        virtual std::string getName();
 | 
			
		||||
        virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
 | 
			
		||||
 | 
			
		||||
        virtual size_t read(char *buffer, size_t bytes);
 | 
			
		||||
        virtual void readAll(std::vector<char> &output);
 | 
			
		||||
        virtual void rewind();
 | 
			
		||||
        virtual size_t getSampleOffset();
 | 
			
		||||
 | 
			
		||||
        FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs);
 | 
			
		||||
        FFmpeg_Decoder(const FFmpeg_Decoder &rhs);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,6 +155,11 @@ void MpgSnd_Decoder::close()
 | 
			
		|||
    mDataStream.setNull();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string MpgSnd_Decoder::getName()
 | 
			
		||||
{
 | 
			
		||||
    return mDataStream->getName();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MpgSnd_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
 | 
			
		||||
{
 | 
			
		||||
    if(!mSndFile && !mMpgFile)
 | 
			
		||||
| 
						 | 
				
			
			@ -213,6 +218,11 @@ void MpgSnd_Decoder::rewind()
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t MpgSnd_Decoder::getSampleOffset()
 | 
			
		||||
{
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MpgSnd_Decoder::MpgSnd_Decoder()
 | 
			
		||||
    : mSndInfo()
 | 
			
		||||
    , mSndFile(NULL)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,11 +34,13 @@ namespace MWSound
 | 
			
		|||
        virtual void open(const std::string &fname);
 | 
			
		||||
        virtual void close();
 | 
			
		||||
 | 
			
		||||
        virtual std::string getName();
 | 
			
		||||
        virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
 | 
			
		||||
 | 
			
		||||
        virtual size_t read(char *buffer, size_t bytes);
 | 
			
		||||
        virtual void readAll(std::vector<char> &output);
 | 
			
		||||
        virtual void rewind();
 | 
			
		||||
        virtual size_t getSampleOffset();
 | 
			
		||||
 | 
			
		||||
        MpgSnd_Decoder& operator=(const MpgSnd_Decoder &rhs);
 | 
			
		||||
        MpgSnd_Decoder(const MpgSnd_Decoder &rhs);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,10 +61,50 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
 | 
			
		|||
        if(fmtlist[i].chans == chans && fmtlist[i].type == type)
 | 
			
		||||
            return fmtlist[i].format;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
 | 
			
		||||
    {
 | 
			
		||||
        static const struct {
 | 
			
		||||
            char name[32];
 | 
			
		||||
            ChannelConfig chans;
 | 
			
		||||
            SampleType type;
 | 
			
		||||
        } mcfmtlist[] = {
 | 
			
		||||
            { "AL_FORMAT_QUAD16",   ChannelConfig_Quad,    SampleType_Int16 },
 | 
			
		||||
            { "AL_FORMAT_QUAD8",    ChannelConfig_Quad,    SampleType_UInt8 },
 | 
			
		||||
            { "AL_FORMAT_51CHN16",  ChannelConfig_5point1, SampleType_Int16 },
 | 
			
		||||
            { "AL_FORMAT_51CHN8",   ChannelConfig_5point1, SampleType_UInt8 },
 | 
			
		||||
            { "AL_FORMAT_71CHN16",  ChannelConfig_7point1, SampleType_Int16 },
 | 
			
		||||
            { "AL_FORMAT_71CHN8",   ChannelConfig_7point1, SampleType_UInt8 },
 | 
			
		||||
        };
 | 
			
		||||
        static const size_t mcfmtlistsize = sizeof(mcfmtlist)/sizeof(mcfmtlist[0]);
 | 
			
		||||
 | 
			
		||||
        for(size_t i = 0;i < mcfmtlistsize;i++)
 | 
			
		||||
        {
 | 
			
		||||
            if(mcfmtlist[i].chans == chans && mcfmtlist[i].type == type)
 | 
			
		||||
            {
 | 
			
		||||
                ALenum format = alGetEnumValue(mcfmtlist[i].name);
 | 
			
		||||
                if(format != 0 && format != -1)
 | 
			
		||||
                    return format;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")");
 | 
			
		||||
    return AL_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ALint getBufferSampleCount(ALuint buf)
 | 
			
		||||
{
 | 
			
		||||
    ALint size, bits, channels;
 | 
			
		||||
 | 
			
		||||
    alGetBufferi(buf, AL_SIZE, &size);
 | 
			
		||||
    alGetBufferi(buf, AL_BITS, &bits);
 | 
			
		||||
    alGetBufferi(buf, AL_CHANNELS, &channels);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
 | 
			
		||||
    return size / channels * 8 / bits;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// A streaming OpenAL sound.
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			@ -82,19 +122,26 @@ class OpenAL_SoundStream : public Sound
 | 
			
		|||
    ALsizei mSampleRate;
 | 
			
		||||
    ALuint mBufferSize;
 | 
			
		||||
 | 
			
		||||
    ALuint mSamplesQueued;
 | 
			
		||||
 | 
			
		||||
    DecoderPtr mDecoder;
 | 
			
		||||
 | 
			
		||||
    volatile bool mIsFinished;
 | 
			
		||||
 | 
			
		||||
    void updateAll(bool local);
 | 
			
		||||
 | 
			
		||||
    OpenAL_SoundStream(const OpenAL_SoundStream &rhs);
 | 
			
		||||
    OpenAL_SoundStream& operator=(const OpenAL_SoundStream &rhs);
 | 
			
		||||
 | 
			
		||||
    friend class OpenAL_Output;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder);
 | 
			
		||||
    OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags);
 | 
			
		||||
    virtual ~OpenAL_SoundStream();
 | 
			
		||||
 | 
			
		||||
    virtual void stop();
 | 
			
		||||
    virtual bool isPlaying();
 | 
			
		||||
    virtual double getTimeOffset();
 | 
			
		||||
    virtual void update();
 | 
			
		||||
 | 
			
		||||
    void play();
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +156,7 @@ const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f;
 | 
			
		|||
struct OpenAL_Output::StreamThread {
 | 
			
		||||
    typedef std::vector<OpenAL_SoundStream*> StreamVec;
 | 
			
		||||
    StreamVec mStreams;
 | 
			
		||||
    boost::mutex mMutex;
 | 
			
		||||
    boost::recursive_mutex mMutex;
 | 
			
		||||
    boost::thread mThread;
 | 
			
		||||
 | 
			
		||||
    StreamThread()
 | 
			
		||||
| 
						 | 
				
			
			@ -170,8 +217,9 @@ private:
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder)
 | 
			
		||||
  : mOutput(output), mSource(src), mDecoder(decoder), mIsFinished(true)
 | 
			
		||||
OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags)
 | 
			
		||||
  : Sound(Ogre::Vector3(0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags)
 | 
			
		||||
  , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true)
 | 
			
		||||
{
 | 
			
		||||
    throwALerror();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -189,6 +237,8 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode
 | 
			
		|||
 | 
			
		||||
        mBufferSize = static_cast<ALuint>(sBufferLength*srate);
 | 
			
		||||
        mBufferSize = framesToBytes(mBufferSize, chans, type);
 | 
			
		||||
 | 
			
		||||
        mOutput.mActiveSounds.push_back(this);
 | 
			
		||||
    }
 | 
			
		||||
    catch(std::exception &e)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -209,22 +259,20 @@ OpenAL_SoundStream::~OpenAL_SoundStream()
 | 
			
		|||
    alGetError();
 | 
			
		||||
 | 
			
		||||
    mDecoder->close();
 | 
			
		||||
 | 
			
		||||
    mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(),
 | 
			
		||||
                                          mOutput.mActiveSounds.end(), this));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenAL_SoundStream::play()
 | 
			
		||||
{
 | 
			
		||||
    std::vector<char> data(mBufferSize);
 | 
			
		||||
 | 
			
		||||
    alSourceStop(mSource);
 | 
			
		||||
    alSourcei(mSource, AL_BUFFER, 0);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
    mSamplesQueued = 0;
 | 
			
		||||
 | 
			
		||||
    for(ALuint i = 0;i < sNumBuffers;i++)
 | 
			
		||||
    {
 | 
			
		||||
        size_t got;
 | 
			
		||||
        got = mDecoder->read(&data[0], data.size());
 | 
			
		||||
        alBufferData(mBuffers[i], mFormat, &data[0], got, mSampleRate);
 | 
			
		||||
    }
 | 
			
		||||
        alBufferData(mBuffers[i], mFormat, this, 0, mSampleRate);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
 | 
			
		||||
    alSourceQueueBuffers(mSource, sNumBuffers, mBuffers);
 | 
			
		||||
| 
						 | 
				
			
			@ -243,6 +291,7 @@ void OpenAL_SoundStream::stop()
 | 
			
		|||
    alSourceStop(mSource);
 | 
			
		||||
    alSourcei(mSource, AL_BUFFER, 0);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
    mSamplesQueued = 0;
 | 
			
		||||
 | 
			
		||||
    mDecoder->rewind();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -254,11 +303,49 @@ bool OpenAL_SoundStream::isPlaying()
 | 
			
		|||
    alGetSourcei(mSource, AL_SOURCE_STATE, &state);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
 | 
			
		||||
    if(state == AL_PLAYING)
 | 
			
		||||
    if(state == AL_PLAYING || state == AL_PAUSED)
 | 
			
		||||
        return true;
 | 
			
		||||
    return !mIsFinished;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double OpenAL_SoundStream::getTimeOffset()
 | 
			
		||||
{
 | 
			
		||||
    ALint state = AL_STOPPED;
 | 
			
		||||
    ALfloat offset = 0.0f;
 | 
			
		||||
    double t;
 | 
			
		||||
 | 
			
		||||
    mOutput.mStreamThread->mMutex.lock();
 | 
			
		||||
    alGetSourcef(mSource, AL_SEC_OFFSET, &offset);
 | 
			
		||||
    alGetSourcei(mSource, AL_SOURCE_STATE, &state);
 | 
			
		||||
    if(state == AL_PLAYING || state == AL_PAUSED)
 | 
			
		||||
        t = (double)(mDecoder->getSampleOffset() - mSamplesQueued)/(double)mSampleRate + offset;
 | 
			
		||||
    else
 | 
			
		||||
        t = (double)mDecoder->getSampleOffset() / (double)mSampleRate;
 | 
			
		||||
    mOutput.mStreamThread->mMutex.unlock();
 | 
			
		||||
 | 
			
		||||
    throwALerror();
 | 
			
		||||
    return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenAL_SoundStream::updateAll(bool local)
 | 
			
		||||
{
 | 
			
		||||
    alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance);
 | 
			
		||||
    alSourcef(mSource, AL_MAX_DISTANCE, mMaxDistance);
 | 
			
		||||
    if(local)
 | 
			
		||||
    {
 | 
			
		||||
        alSourcef(mSource, AL_ROLLOFF_FACTOR, 0.0f);
 | 
			
		||||
        alSourcei(mSource, AL_SOURCE_RELATIVE, AL_TRUE);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f);
 | 
			
		||||
        alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE);
 | 
			
		||||
    }
 | 
			
		||||
    alSourcei(mSource, AL_LOOPING, AL_FALSE);
 | 
			
		||||
 | 
			
		||||
    update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenAL_SoundStream::update()
 | 
			
		||||
{
 | 
			
		||||
    ALfloat gain = mVolume*mBaseVolume;
 | 
			
		||||
| 
						 | 
				
			
			@ -279,52 +366,58 @@ void OpenAL_SoundStream::update()
 | 
			
		|||
 | 
			
		||||
bool OpenAL_SoundStream::process()
 | 
			
		||||
{
 | 
			
		||||
    bool finished = mIsFinished;
 | 
			
		||||
    ALint processed, state;
 | 
			
		||||
    try {
 | 
			
		||||
        bool finished = mIsFinished;
 | 
			
		||||
        ALint processed, state;
 | 
			
		||||
 | 
			
		||||
    alGetSourcei(mSource, AL_SOURCE_STATE, &state);
 | 
			
		||||
    alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
 | 
			
		||||
    if(processed > 0)
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<char> data(mBufferSize);
 | 
			
		||||
        do {
 | 
			
		||||
            ALuint bufid;
 | 
			
		||||
            size_t got;
 | 
			
		||||
 | 
			
		||||
            alSourceUnqueueBuffers(mSource, 1, &bufid);
 | 
			
		||||
            processed--;
 | 
			
		||||
 | 
			
		||||
            if(finished)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            got = mDecoder->read(&data[0], data.size());
 | 
			
		||||
            finished = (got < data.size());
 | 
			
		||||
            if(got > 0)
 | 
			
		||||
            {
 | 
			
		||||
                alBufferData(bufid, mFormat, &data[0], got, mSampleRate);
 | 
			
		||||
                alSourceQueueBuffers(mSource, 1, &bufid);
 | 
			
		||||
            }
 | 
			
		||||
        } while(processed > 0);
 | 
			
		||||
        alGetSourcei(mSource, AL_SOURCE_STATE, &state);
 | 
			
		||||
        alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
 | 
			
		||||
        throwALerror();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(state != AL_PLAYING && state != AL_PAUSED)
 | 
			
		||||
    {
 | 
			
		||||
        ALint queued;
 | 
			
		||||
 | 
			
		||||
        alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
 | 
			
		||||
        throwALerror();
 | 
			
		||||
        if(queued > 0)
 | 
			
		||||
        if(processed > 0)
 | 
			
		||||
        {
 | 
			
		||||
            alSourcePlay(mSource);
 | 
			
		||||
            std::vector<char> data(mBufferSize);
 | 
			
		||||
            do {
 | 
			
		||||
                ALuint bufid = 0;
 | 
			
		||||
                size_t got;
 | 
			
		||||
 | 
			
		||||
                alSourceUnqueueBuffers(mSource, 1, &bufid);
 | 
			
		||||
                mSamplesQueued -= getBufferSampleCount(bufid);
 | 
			
		||||
                processed--;
 | 
			
		||||
 | 
			
		||||
                if(finished)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                got = mDecoder->read(&data[0], data.size());
 | 
			
		||||
                finished = (got < data.size());
 | 
			
		||||
                if(got > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    alBufferData(bufid, mFormat, &data[0], got, mSampleRate);
 | 
			
		||||
                    alSourceQueueBuffers(mSource, 1, &bufid);
 | 
			
		||||
                    mSamplesQueued += getBufferSampleCount(bufid);
 | 
			
		||||
                }
 | 
			
		||||
            } while(processed > 0);
 | 
			
		||||
            throwALerror();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mIsFinished = finished;
 | 
			
		||||
    return !finished;
 | 
			
		||||
        if(state != AL_PLAYING && state != AL_PAUSED)
 | 
			
		||||
        {
 | 
			
		||||
            ALint queued = 0;
 | 
			
		||||
 | 
			
		||||
            alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
 | 
			
		||||
            if(queued > 0)
 | 
			
		||||
                alSourcePlay(mSource);
 | 
			
		||||
            throwALerror();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        mIsFinished = finished;
 | 
			
		||||
    }
 | 
			
		||||
    catch(std::exception &e) {
 | 
			
		||||
        std::cout<< "Error updating stream \""<<mDecoder->getName()<<"\"" <<std::endl;
 | 
			
		||||
        mSamplesQueued = 0;
 | 
			
		||||
        mIsFinished = true;
 | 
			
		||||
    }
 | 
			
		||||
    return !mIsFinished;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			@ -338,16 +431,21 @@ protected:
 | 
			
		|||
    ALuint mSource;
 | 
			
		||||
    ALuint mBuffer;
 | 
			
		||||
 | 
			
		||||
    friend class OpenAL_Output;
 | 
			
		||||
 | 
			
		||||
    void updateAll(bool local);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    OpenAL_Sound(const OpenAL_Sound &rhs);
 | 
			
		||||
    OpenAL_Sound& operator=(const OpenAL_Sound &rhs);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf);
 | 
			
		||||
    OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags);
 | 
			
		||||
    virtual ~OpenAL_Sound();
 | 
			
		||||
 | 
			
		||||
    virtual void stop();
 | 
			
		||||
    virtual bool isPlaying();
 | 
			
		||||
    virtual double getTimeOffset();
 | 
			
		||||
    virtual void update();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -360,16 +458,18 @@ class OpenAL_Sound3D : public OpenAL_Sound
 | 
			
		|||
    OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf)
 | 
			
		||||
      : OpenAL_Sound(output, src, buf)
 | 
			
		||||
    OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
 | 
			
		||||
      : OpenAL_Sound(output, src, buf, pos, vol, basevol, pitch, mindist, maxdist, flags)
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
    virtual void update();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf)
 | 
			
		||||
  : mOutput(output), mSource(src), mBuffer(buf)
 | 
			
		||||
OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
 | 
			
		||||
  : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags)
 | 
			
		||||
  , mOutput(output), mSource(src), mBuffer(buf)
 | 
			
		||||
{
 | 
			
		||||
    mOutput.mActiveSounds.push_back(this);
 | 
			
		||||
}
 | 
			
		||||
OpenAL_Sound::~OpenAL_Sound()
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -378,6 +478,9 @@ OpenAL_Sound::~OpenAL_Sound()
 | 
			
		|||
 | 
			
		||||
    mOutput.mFreeSources.push_back(mSource);
 | 
			
		||||
    mOutput.bufferFinished(mBuffer);
 | 
			
		||||
 | 
			
		||||
    mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(),
 | 
			
		||||
                                          mOutput.mActiveSounds.end(), this));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenAL_Sound::stop()
 | 
			
		||||
| 
						 | 
				
			
			@ -393,13 +496,43 @@ bool OpenAL_Sound::isPlaying()
 | 
			
		|||
    alGetSourcei(mSource, AL_SOURCE_STATE, &state);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
 | 
			
		||||
    return state==AL_PLAYING;
 | 
			
		||||
    return state==AL_PLAYING || state==AL_PAUSED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double OpenAL_Sound::getTimeOffset()
 | 
			
		||||
{
 | 
			
		||||
    ALfloat t;
 | 
			
		||||
 | 
			
		||||
    alGetSourcef(mSource, AL_SEC_OFFSET, &t);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
 | 
			
		||||
    return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenAL_Sound::updateAll(bool local)
 | 
			
		||||
{
 | 
			
		||||
    alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance);
 | 
			
		||||
    alSourcef(mSource, AL_MAX_DISTANCE, mMaxDistance);
 | 
			
		||||
    if(local)
 | 
			
		||||
    {
 | 
			
		||||
        alSourcef(mSource, AL_ROLLOFF_FACTOR, 0.0f);
 | 
			
		||||
        alSourcei(mSource, AL_SOURCE_RELATIVE, AL_TRUE);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f);
 | 
			
		||||
        alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE);
 | 
			
		||||
    }
 | 
			
		||||
    alSourcei(mSource, AL_LOOPING, (mFlags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE);
 | 
			
		||||
 | 
			
		||||
    update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenAL_Sound::update()
 | 
			
		||||
{
 | 
			
		||||
    ALfloat gain = mVolume*mBaseVolume;
 | 
			
		||||
    ALfloat pitch = mPitch;
 | 
			
		||||
 | 
			
		||||
    if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater)
 | 
			
		||||
    {
 | 
			
		||||
        gain *= 0.9f;
 | 
			
		||||
| 
						 | 
				
			
			@ -521,11 +654,9 @@ void OpenAL_Output::deinit()
 | 
			
		|||
{
 | 
			
		||||
    mStreamThread->removeAll();
 | 
			
		||||
 | 
			
		||||
    while(!mFreeSources.empty())
 | 
			
		||||
    {
 | 
			
		||||
        alDeleteSources(1, &mFreeSources.front());
 | 
			
		||||
        mFreeSources.pop_front();
 | 
			
		||||
    }
 | 
			
		||||
    for(size_t i = 0;i < mFreeSources.size();i++)
 | 
			
		||||
        alDeleteSources(1, &mFreeSources[i]);
 | 
			
		||||
    mFreeSources.clear();
 | 
			
		||||
 | 
			
		||||
    mBufferRefs.clear();
 | 
			
		||||
    mUnusedBuffers.clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -642,7 +773,7 @@ void OpenAL_Output::bufferFinished(ALuint buf)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, int flags)
 | 
			
		||||
MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, float basevol, float pitch, int flags)
 | 
			
		||||
{
 | 
			
		||||
    boost::shared_ptr<OpenAL_Sound> sound;
 | 
			
		||||
    ALuint src=0, buf=0;
 | 
			
		||||
| 
						 | 
				
			
			@ -655,7 +786,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume
 | 
			
		|||
    try
 | 
			
		||||
    {
 | 
			
		||||
        buf = getBuffer(fname);
 | 
			
		||||
        sound.reset(new OpenAL_Sound(*this, src, buf));
 | 
			
		||||
        sound.reset(new OpenAL_Sound(*this, src, buf, Ogre::Vector3(0.0f), vol, basevol, pitch, 1.0f, 1000.0f, flags));
 | 
			
		||||
    }
 | 
			
		||||
    catch(std::exception &e)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -666,25 +797,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume
 | 
			
		|||
        throw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f);
 | 
			
		||||
    alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
 | 
			
		||||
    alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
    alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f);
 | 
			
		||||
    alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
 | 
			
		||||
    alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
 | 
			
		||||
 | 
			
		||||
    if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater)
 | 
			
		||||
    {
 | 
			
		||||
        volume *= 0.9f;
 | 
			
		||||
        pitch *= 0.7f;
 | 
			
		||||
    }
 | 
			
		||||
    alSourcef(src, AL_GAIN, volume);
 | 
			
		||||
    alSourcef(src, AL_PITCH, pitch);
 | 
			
		||||
 | 
			
		||||
    alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE);
 | 
			
		||||
    alSourcei(src, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
    sound->updateAll(true);
 | 
			
		||||
 | 
			
		||||
    alSourcei(src, AL_BUFFER, buf);
 | 
			
		||||
    alSourcePlay(src);
 | 
			
		||||
| 
						 | 
				
			
			@ -693,8 +806,8 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume
 | 
			
		|||
    return sound;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float volume, float pitch,
 | 
			
		||||
                                    float min, float max, int flags)
 | 
			
		||||
MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float vol, float basevol, float pitch,
 | 
			
		||||
                                            float min, float max, int flags)
 | 
			
		||||
{
 | 
			
		||||
    boost::shared_ptr<OpenAL_Sound> sound;
 | 
			
		||||
    ALuint src=0, buf=0;
 | 
			
		||||
| 
						 | 
				
			
			@ -707,7 +820,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre
 | 
			
		|||
    try
 | 
			
		||||
    {
 | 
			
		||||
        buf = getBuffer(fname);
 | 
			
		||||
        sound.reset(new OpenAL_Sound3D(*this, src, buf));
 | 
			
		||||
        sound.reset(new OpenAL_Sound3D(*this, src, buf, pos, vol, basevol, pitch, min, max, flags));
 | 
			
		||||
    }
 | 
			
		||||
    catch(std::exception &e)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -718,26 +831,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre
 | 
			
		|||
        throw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    alSource3f(src, AL_POSITION, pos.x, pos.z, -pos.y);
 | 
			
		||||
    alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
 | 
			
		||||
    alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
    alSourcef(src, AL_REFERENCE_DISTANCE, min);
 | 
			
		||||
    alSourcef(src, AL_MAX_DISTANCE, max);
 | 
			
		||||
    alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f);
 | 
			
		||||
 | 
			
		||||
    if(!(flags&MWBase::SoundManager::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);
 | 
			
		||||
 | 
			
		||||
    alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE);
 | 
			
		||||
    alSourcei(src, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
    sound->updateAll(false);
 | 
			
		||||
 | 
			
		||||
    alSourcei(src, AL_BUFFER, buf);
 | 
			
		||||
    alSourcePlay(src);
 | 
			
		||||
| 
						 | 
				
			
			@ -747,7 +841,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MWBase::SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch, int flags)
 | 
			
		||||
MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, float pitch, int flags)
 | 
			
		||||
{
 | 
			
		||||
    boost::shared_ptr<OpenAL_SoundStream> sound;
 | 
			
		||||
    ALuint src;
 | 
			
		||||
| 
						 | 
				
			
			@ -757,13 +851,11 @@ MWBase::SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volu
 | 
			
		|||
    src = mFreeSources.front();
 | 
			
		||||
    mFreeSources.pop_front();
 | 
			
		||||
 | 
			
		||||
    if((flags&MWBase::SoundManager::Play_Loop))
 | 
			
		||||
        std::cout <<"Warning: cannot loop stream \""<<decoder->getName()<<"\""<< std::endl;
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        if((flags&MWBase::SoundManager::Play_Loop))
 | 
			
		||||
            std::cout <<"Warning: cannot loop stream "<<fname<< std::endl;
 | 
			
		||||
        DecoderPtr decoder = mManager.getDecoder();
 | 
			
		||||
        decoder->open(fname);
 | 
			
		||||
        sound.reset(new OpenAL_SoundStream(*this, src, decoder));
 | 
			
		||||
        sound.reset(new OpenAL_SoundStream(*this, src, decoder, volume, pitch, flags));
 | 
			
		||||
    }
 | 
			
		||||
    catch(std::exception &e)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -771,25 +863,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volu
 | 
			
		|||
        throw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f);
 | 
			
		||||
    alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
 | 
			
		||||
    alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
    alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f);
 | 
			
		||||
    alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
 | 
			
		||||
    alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
 | 
			
		||||
 | 
			
		||||
    if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater)
 | 
			
		||||
    {
 | 
			
		||||
        volume *= 0.9f;
 | 
			
		||||
        pitch *= 0.7f;
 | 
			
		||||
    }
 | 
			
		||||
    alSourcef(src, AL_GAIN, volume);
 | 
			
		||||
    alSourcef(src, AL_PITCH, pitch);
 | 
			
		||||
 | 
			
		||||
    alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE);
 | 
			
		||||
    alSourcei(src, AL_LOOPING, AL_FALSE);
 | 
			
		||||
    throwALerror();
 | 
			
		||||
    sound->updateAll(true);
 | 
			
		||||
 | 
			
		||||
    sound->play();
 | 
			
		||||
    return sound;
 | 
			
		||||
| 
						 | 
				
			
			@ -814,6 +888,61 @@ void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void OpenAL_Output::pauseSounds(int types)
 | 
			
		||||
{
 | 
			
		||||
    std::vector<ALuint> sources;
 | 
			
		||||
    SoundVec::const_iterator iter = mActiveSounds.begin();
 | 
			
		||||
    while(iter != mActiveSounds.end())
 | 
			
		||||
    {
 | 
			
		||||
        const OpenAL_SoundStream *stream = dynamic_cast<OpenAL_SoundStream*>(*iter);
 | 
			
		||||
        if(stream)
 | 
			
		||||
        {
 | 
			
		||||
            if(stream->mSource && (stream->getPlayType()&types))
 | 
			
		||||
                sources.push_back(stream->mSource);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            const OpenAL_Sound *sound = dynamic_cast<OpenAL_Sound*>(*iter);
 | 
			
		||||
            if(sound && sound->mSource && (sound->getPlayType()&types))
 | 
			
		||||
                sources.push_back(sound->mSource);
 | 
			
		||||
        }
 | 
			
		||||
        iter++;
 | 
			
		||||
    }
 | 
			
		||||
    if(sources.size() > 0)
 | 
			
		||||
    {
 | 
			
		||||
        alSourcePausev(sources.size(), &sources[0]);
 | 
			
		||||
        throwALerror();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenAL_Output::resumeSounds(int types)
 | 
			
		||||
{
 | 
			
		||||
    std::vector<ALuint> sources;
 | 
			
		||||
    SoundVec::const_iterator iter = mActiveSounds.begin();
 | 
			
		||||
    while(iter != mActiveSounds.end())
 | 
			
		||||
    {
 | 
			
		||||
        const OpenAL_SoundStream *stream = dynamic_cast<OpenAL_SoundStream*>(*iter);
 | 
			
		||||
        if(stream)
 | 
			
		||||
        {
 | 
			
		||||
            if(stream->mSource && (stream->getPlayType()&types))
 | 
			
		||||
                sources.push_back(stream->mSource);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            const OpenAL_Sound *sound = dynamic_cast<OpenAL_Sound*>(*iter);
 | 
			
		||||
            if(sound && sound->mSource && (sound->getPlayType()&types))
 | 
			
		||||
                sources.push_back(sound->mSource);
 | 
			
		||||
        }
 | 
			
		||||
        iter++;
 | 
			
		||||
    }
 | 
			
		||||
    if(sources.size() > 0)
 | 
			
		||||
    {
 | 
			
		||||
        alSourcePlayv(sources.size(), &sources[0]);
 | 
			
		||||
        throwALerror();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
OpenAL_Output::OpenAL_Output(SoundManager &mgr)
 | 
			
		||||
  : Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0),
 | 
			
		||||
    mLastEnvironment(Env_Normal), mStreamThread(new StreamThread)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,9 @@ namespace MWSound
 | 
			
		|||
 | 
			
		||||
        uint64_t mBufferCacheMemSize;
 | 
			
		||||
 | 
			
		||||
        typedef std::vector<Sound*> SoundVec;
 | 
			
		||||
        SoundVec mActiveSounds;
 | 
			
		||||
 | 
			
		||||
        ALuint getBuffer(const std::string &fname);
 | 
			
		||||
        void bufferFinished(ALuint buffer);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -42,13 +45,16 @@ namespace MWSound
 | 
			
		|||
        virtual void init(const std::string &devname="");
 | 
			
		||||
        virtual void deinit();
 | 
			
		||||
 | 
			
		||||
        virtual MWBase::SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags);
 | 
			
		||||
        virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags);
 | 
			
		||||
        virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos,
 | 
			
		||||
                                     float volume, float pitch, float min, float max, int flags);
 | 
			
		||||
        virtual MWBase::SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags);
 | 
			
		||||
                                             float vol, float basevol, float pitch, float min, float max, int flags);
 | 
			
		||||
        virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags);
 | 
			
		||||
 | 
			
		||||
        virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env);
 | 
			
		||||
 | 
			
		||||
        virtual void pauseSounds(int types);
 | 
			
		||||
        virtual void resumeSounds(int types);
 | 
			
		||||
 | 
			
		||||
        OpenAL_Output& operator=(const OpenAL_Output &rhs);
 | 
			
		||||
        OpenAL_Output(const OpenAL_Output &rhs);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +70,7 @@ namespace MWSound
 | 
			
		|||
        friend class SoundManager;
 | 
			
		||||
    };
 | 
			
		||||
#ifndef DEFAULT_OUTPUT
 | 
			
		||||
#define DEFAULT_OUTPUT (::MWSound::OpenAL_Output)
 | 
			
		||||
#define DEFAULT_OUTPUT(x) ::MWSound::OpenAL_Output((x))
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,16 +26,22 @@ namespace MWSound
 | 
			
		|||
    public:
 | 
			
		||||
        virtual void stop() = 0;
 | 
			
		||||
        virtual bool isPlaying() = 0;
 | 
			
		||||
        virtual double getTimeOffset() = 0;
 | 
			
		||||
        void setPosition(const Ogre::Vector3 &pos) { mPos = pos; }
 | 
			
		||||
        void setVolume(float volume) { mVolume = volume; }
 | 
			
		||||
 | 
			
		||||
        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(MWBase::SoundManager::Play_Normal)
 | 
			
		||||
        MWBase::SoundManager::PlayType getPlayType() const
 | 
			
		||||
        { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Sound(const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags)
 | 
			
		||||
          : mPos(pos)
 | 
			
		||||
          , mVolume(vol)
 | 
			
		||||
          , mBaseVolume(basevol)
 | 
			
		||||
          , mPitch(pitch)
 | 
			
		||||
          , mMinDistance(mindist)
 | 
			
		||||
          , mMaxDistance(maxdist)
 | 
			
		||||
          , mFlags(flags)
 | 
			
		||||
        { }
 | 
			
		||||
        virtual ~Sound() { }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,10 @@ namespace MWSound
 | 
			
		|||
 | 
			
		||||
    enum ChannelConfig {
 | 
			
		||||
        ChannelConfig_Mono,
 | 
			
		||||
        ChannelConfig_Stereo
 | 
			
		||||
        ChannelConfig_Stereo,
 | 
			
		||||
        ChannelConfig_Quad,
 | 
			
		||||
        ChannelConfig_5point1,
 | 
			
		||||
        ChannelConfig_7point1
 | 
			
		||||
    };
 | 
			
		||||
    const char *getChannelConfigName(ChannelConfig config);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -29,11 +32,13 @@ namespace MWSound
 | 
			
		|||
        virtual void open(const std::string &fname) = 0;
 | 
			
		||||
        virtual void close() = 0;
 | 
			
		||||
 | 
			
		||||
        virtual std::string getName() = 0;
 | 
			
		||||
        virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0;
 | 
			
		||||
 | 
			
		||||
        virtual size_t read(char *buffer, size_t bytes) = 0;
 | 
			
		||||
        virtual void readAll(std::vector<char> &output);
 | 
			
		||||
        virtual void rewind() = 0;
 | 
			
		||||
        virtual size_t getSampleOffset() = 0;
 | 
			
		||||
 | 
			
		||||
        Sound_Decoder() : mResourceMgr(Ogre::ResourceGroupManager::getSingleton())
 | 
			
		||||
        { }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,13 +24,16 @@ namespace MWSound
 | 
			
		|||
        virtual void init(const std::string &devname="") = 0;
 | 
			
		||||
        virtual void deinit() = 0;
 | 
			
		||||
 | 
			
		||||
        virtual MWBase::SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags) = 0;
 | 
			
		||||
        virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags) = 0;
 | 
			
		||||
        virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos,
 | 
			
		||||
                                     float volume, float pitch, float min, float max, int flags) = 0;
 | 
			
		||||
        virtual MWBase::SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags) = 0;
 | 
			
		||||
                                             float vol, float basevol, float pitch, float min, float max, int flags) = 0;
 | 
			
		||||
        virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags) = 0;
 | 
			
		||||
 | 
			
		||||
        virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0;
 | 
			
		||||
 | 
			
		||||
        virtual void pauseSounds(int types) = 0;
 | 
			
		||||
        virtual void resumeSounds(int types) = 0;
 | 
			
		||||
 | 
			
		||||
        Sound_Output& operator=(const Sound_Output &rhs);
 | 
			
		||||
        Sound_Output(const Sound_Output &rhs);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,6 +52,7 @@ namespace MWSound
 | 
			
		|||
        , mMusicVolume(1.0f)
 | 
			
		||||
        , mFootstepsVolume(1.0f)
 | 
			
		||||
        , mVoiceVolume(1.0f)
 | 
			
		||||
        , mPausedSoundTypes(0)
 | 
			
		||||
    {
 | 
			
		||||
        if(!useSound)
 | 
			
		||||
            return;
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +87,7 @@ namespace MWSound
 | 
			
		|||
            {
 | 
			
		||||
                if(devname.empty())
 | 
			
		||||
                    throw;
 | 
			
		||||
                std::cout <<"Failed to open device \""<<devname<<"\", trying default."<< std::endl << "The error given was: " << e.what() << std::endl;
 | 
			
		||||
                std::cerr <<"Failed to open device \""<<devname<<"\": " << e.what() << std::endl;
 | 
			
		||||
                mOutput->init();
 | 
			
		||||
                Settings::Manager::setString("device", "Sound", "");
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -137,6 +138,27 @@ namespace MWSound
 | 
			
		|||
        return "Sound/"+snd->mSound;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Gets the combined volume settings for the given sound type
 | 
			
		||||
    float SoundManager::volumeFromType(PlayType type) const
 | 
			
		||||
    {
 | 
			
		||||
        float volume = mMasterVolume;
 | 
			
		||||
        switch(type)
 | 
			
		||||
        {
 | 
			
		||||
            case Play_TypeSfx:
 | 
			
		||||
                volume *= mSFXVolume;
 | 
			
		||||
                break;
 | 
			
		||||
            case Play_TypeVoice:
 | 
			
		||||
                volume *= mVoiceVolume;
 | 
			
		||||
                break;
 | 
			
		||||
            case Play_TypeMusic:
 | 
			
		||||
            case Play_TypeMovie:
 | 
			
		||||
                volume *= mMusicVolume;
 | 
			
		||||
                break;
 | 
			
		||||
            case Play_TypeMask:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        return volume;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -165,11 +187,13 @@ namespace MWSound
 | 
			
		|||
        std::cout <<"Playing "<<filename<< std::endl;
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            float basevol = mMasterVolume * mMusicVolume;
 | 
			
		||||
            stopMusic();
 | 
			
		||||
            mMusic = mOutput->streamSound(filename, basevol, 1.0f, Play_NoEnv);
 | 
			
		||||
            mMusic->mBaseVolume = basevol;
 | 
			
		||||
            mMusic->mFlags = Play_NoEnv;
 | 
			
		||||
 | 
			
		||||
            DecoderPtr decoder = getDecoder();
 | 
			
		||||
            decoder->open(filename);
 | 
			
		||||
 | 
			
		||||
            mMusic = mOutput->streamSound(decoder, volumeFromType(Play_TypeMusic),
 | 
			
		||||
                                          1.0f, Play_NoEnv|Play_TypeMusic);
 | 
			
		||||
        }
 | 
			
		||||
        catch(std::exception &e)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -212,16 +236,13 @@ namespace MWSound
 | 
			
		|||
        try
 | 
			
		||||
        {
 | 
			
		||||
            // The range values are not tested
 | 
			
		||||
            float basevol = mMasterVolume * mVoiceVolume;
 | 
			
		||||
            float basevol = volumeFromType(Play_TypeVoice);
 | 
			
		||||
            std::string filePath = "Sound/"+filename;
 | 
			
		||||
            const ESM::Position &pos = ptr.getRefData().getPosition();
 | 
			
		||||
            const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]);
 | 
			
		||||
 | 
			
		||||
            MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, basevol, 1.0f,
 | 
			
		||||
                                                  20.0f, 12750.0f, Play_Normal);
 | 
			
		||||
            sound->mPos = objpos;
 | 
			
		||||
            sound->mBaseVolume = basevol;
 | 
			
		||||
 | 
			
		||||
            MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f,
 | 
			
		||||
                                                          20.0f, 12750.0f, Play_Normal|Play_TypeVoice);
 | 
			
		||||
            mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound"));
 | 
			
		||||
        }
 | 
			
		||||
        catch(std::exception &e)
 | 
			
		||||
| 
						 | 
				
			
			@ -236,12 +257,10 @@ namespace MWSound
 | 
			
		|||
            return;
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            float basevol = mMasterVolume * mVoiceVolume;
 | 
			
		||||
            float basevol = volumeFromType(Play_TypeVoice);
 | 
			
		||||
            std::string filePath = "Sound/"+filename;
 | 
			
		||||
 | 
			
		||||
            MWBase::SoundPtr sound = mOutput->playSound(filePath, basevol, 1.0f, Play_Normal);
 | 
			
		||||
            sound->mBaseVolume = basevol;
 | 
			
		||||
 | 
			
		||||
            MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice);
 | 
			
		||||
            mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound"));
 | 
			
		||||
        }
 | 
			
		||||
        catch(std::exception &e)
 | 
			
		||||
| 
						 | 
				
			
			@ -271,26 +290,35 @@ namespace MWSound
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    MWBase::SoundPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type)
 | 
			
		||||
    {
 | 
			
		||||
        MWBase::SoundPtr track;
 | 
			
		||||
        if(!mOutput->isInitialized())
 | 
			
		||||
            return track;
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            track = mOutput->streamSound(decoder, volumeFromType(type), 1.0f, Play_NoEnv|type);
 | 
			
		||||
        }
 | 
			
		||||
        catch(std::exception &e)
 | 
			
		||||
        {
 | 
			
		||||
            std::cout <<"Sound Error: "<<e.what()<< std::endl;
 | 
			
		||||
        }
 | 
			
		||||
        return track;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, int mode)
 | 
			
		||||
 | 
			
		||||
    MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayMode mode)
 | 
			
		||||
    {
 | 
			
		||||
        MWBase::SoundPtr sound;
 | 
			
		||||
        if(!mOutput->isInitialized())
 | 
			
		||||
            return sound;
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            float basevol = mMasterVolume * mSFXVolume;
 | 
			
		||||
            float basevol = volumeFromType(Play_TypeSfx);
 | 
			
		||||
            float min, max;
 | 
			
		||||
            std::string file = lookup(soundId, basevol, min, max);
 | 
			
		||||
 | 
			
		||||
            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;
 | 
			
		||||
            std::string file = lookup(soundId, volume, min, max);
 | 
			
		||||
 | 
			
		||||
            sound = mOutput->playSound(file, volume, basevol, pitch, mode|Play_TypeSfx);
 | 
			
		||||
            mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId);
 | 
			
		||||
        }
 | 
			
		||||
        catch(std::exception &e)
 | 
			
		||||
| 
						 | 
				
			
			@ -301,7 +329,7 @@ namespace MWSound
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    MWBase::SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId,
 | 
			
		||||
                                       float volume, float pitch, int mode)
 | 
			
		||||
                                               float volume, float pitch, PlayMode mode)
 | 
			
		||||
    {
 | 
			
		||||
        MWBase::SoundPtr sound;
 | 
			
		||||
        if(!mOutput->isInitialized())
 | 
			
		||||
| 
						 | 
				
			
			@ -309,21 +337,13 @@ namespace MWSound
 | 
			
		|||
        try
 | 
			
		||||
        {
 | 
			
		||||
            // Look up the sound in the ESM data
 | 
			
		||||
            float basevol = mMasterVolume * mSFXVolume;
 | 
			
		||||
            float basevol = volumeFromType(Play_TypeSfx);
 | 
			
		||||
            float min, max;
 | 
			
		||||
            std::string file = lookup(soundId, basevol, min, max);
 | 
			
		||||
            std::string file = lookup(soundId, volume, min, max);
 | 
			
		||||
            const ESM::Position &pos = ptr.getRefData().getPosition();;
 | 
			
		||||
            const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]);
 | 
			
		||||
 | 
			
		||||
            sound = mOutput->playSound3D(file, objpos, volume*basevol, pitch, min, max, mode);
 | 
			
		||||
            sound->mPos = objpos;
 | 
			
		||||
            sound->mVolume = volume;
 | 
			
		||||
            sound->mBaseVolume = basevol;
 | 
			
		||||
            sound->mPitch = pitch;
 | 
			
		||||
            sound->mMinDistance = min;
 | 
			
		||||
            sound->mMaxDistance = max;
 | 
			
		||||
            sound->mFlags = mode;
 | 
			
		||||
 | 
			
		||||
            sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|Play_TypeSfx);
 | 
			
		||||
            if((mode&Play_NoTrack))
 | 
			
		||||
                mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId);
 | 
			
		||||
            else
 | 
			
		||||
| 
						 | 
				
			
			@ -404,6 +424,27 @@ namespace MWSound
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void SoundManager::pauseSounds(int types)
 | 
			
		||||
    {
 | 
			
		||||
        if(mOutput->isInitialized())
 | 
			
		||||
        {
 | 
			
		||||
            types &= Play_TypeMask;
 | 
			
		||||
            mOutput->pauseSounds(types);
 | 
			
		||||
            mPausedSoundTypes |= types;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void SoundManager::resumeSounds(int types)
 | 
			
		||||
    {
 | 
			
		||||
        if(mOutput->isInitialized())
 | 
			
		||||
        {
 | 
			
		||||
            types &= types&Play_TypeMask&mPausedSoundTypes;
 | 
			
		||||
            mOutput->resumeSounds(types);
 | 
			
		||||
            mPausedSoundTypes &= ~types;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void SoundManager::updateRegionSound(float duration)
 | 
			
		||||
    {
 | 
			
		||||
        MWWorld::Ptr::CellStore *current = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell();
 | 
			
		||||
| 
						 | 
				
			
			@ -525,24 +566,13 @@ namespace MWSound
 | 
			
		|||
        SoundMap::iterator snditer = mActiveSounds.begin();
 | 
			
		||||
        while(snditer != mActiveSounds.end())
 | 
			
		||||
        {
 | 
			
		||||
            if(snditer->second.second != "_say_sound")
 | 
			
		||||
            {
 | 
			
		||||
                float basevol = mMasterVolume * mSFXVolume;
 | 
			
		||||
                float min, max;
 | 
			
		||||
                lookup(snditer->second.second, basevol, min, max);
 | 
			
		||||
                snditer->first->mBaseVolume = basevol;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                float basevol = mMasterVolume * mVoiceVolume;
 | 
			
		||||
                snditer->first->mBaseVolume = basevol;
 | 
			
		||||
            }
 | 
			
		||||
            snditer->first->mBaseVolume = volumeFromType(snditer->first->getPlayType());
 | 
			
		||||
            snditer->first->update();
 | 
			
		||||
            snditer++;
 | 
			
		||||
        }
 | 
			
		||||
        if(mMusic)
 | 
			
		||||
        {
 | 
			
		||||
            mMusic->mBaseVolume = mMasterVolume * mMusicVolume;
 | 
			
		||||
            mMusic->mBaseVolume = volumeFromType(mMusic->getPlayType());
 | 
			
		||||
            mMusic->update();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -585,8 +615,11 @@ namespace MWSound
 | 
			
		|||
    {
 | 
			
		||||
        switch(config)
 | 
			
		||||
        {
 | 
			
		||||
            case ChannelConfig_Mono:   return "Mono";
 | 
			
		||||
            case ChannelConfig_Stereo: return "Stereo";
 | 
			
		||||
            case ChannelConfig_Mono:    return "Mono";
 | 
			
		||||
            case ChannelConfig_Stereo:  return "Stereo";
 | 
			
		||||
            case ChannelConfig_Quad:    return "Quad";
 | 
			
		||||
            case ChannelConfig_5point1: return "5.1 Surround";
 | 
			
		||||
            case ChannelConfig_7point1: return "7.1 Surround";
 | 
			
		||||
        }
 | 
			
		||||
        return "(unknown channel config)";
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -595,8 +628,11 @@ namespace MWSound
 | 
			
		|||
    {
 | 
			
		||||
        switch(config)
 | 
			
		||||
        {
 | 
			
		||||
            case ChannelConfig_Mono:   frames *= 1; break;
 | 
			
		||||
            case ChannelConfig_Stereo: frames *= 2; break;
 | 
			
		||||
            case ChannelConfig_Mono:    frames *= 1; break;
 | 
			
		||||
            case ChannelConfig_Stereo:  frames *= 2; break;
 | 
			
		||||
            case ChannelConfig_Quad:    frames *= 4; break;
 | 
			
		||||
            case ChannelConfig_5point1: frames *= 6; break;
 | 
			
		||||
            case ChannelConfig_7point1: frames *= 8; break;
 | 
			
		||||
        }
 | 
			
		||||
        switch(type)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,8 +22,6 @@ namespace MWSound
 | 
			
		|||
    struct Sound_Decoder;
 | 
			
		||||
    class Sound;
 | 
			
		||||
 | 
			
		||||
    typedef boost::shared_ptr<Sound_Decoder> DecoderPtr;
 | 
			
		||||
 | 
			
		||||
    enum Environment {
 | 
			
		||||
        Env_Normal,
 | 
			
		||||
        Env_Underwater
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +52,8 @@ namespace MWSound
 | 
			
		|||
        Ogre::Vector3 mListenerDir;
 | 
			
		||||
        Ogre::Vector3 mListenerUp;
 | 
			
		||||
 | 
			
		||||
        int mPausedSoundTypes;
 | 
			
		||||
 | 
			
		||||
        std::string lookup(const std::string &soundId,
 | 
			
		||||
                  float &volume, float &min, float &max);
 | 
			
		||||
        void streamMusicFull(const std::string& filename);
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +61,8 @@ namespace MWSound
 | 
			
		|||
        void updateSounds(float duration);
 | 
			
		||||
        void updateRegionSound(float duration);
 | 
			
		||||
 | 
			
		||||
        float volumeFromType(PlayType type) const;
 | 
			
		||||
 | 
			
		||||
        SoundManager(const SoundManager &rhs);
 | 
			
		||||
        SoundManager& operator=(const SoundManager &rhs);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -105,11 +107,14 @@ namespace MWSound
 | 
			
		|||
        virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr());
 | 
			
		||||
        ///< Stop an actor speaking
 | 
			
		||||
 | 
			
		||||
        virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal);
 | 
			
		||||
        virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type);
 | 
			
		||||
        ///< Play a 2D audio track, using a custom decoder
 | 
			
		||||
 | 
			
		||||
        virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal);
 | 
			
		||||
        ///< Play a sound, independently of 3D-position
 | 
			
		||||
 | 
			
		||||
        virtual MWBase::SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId,
 | 
			
		||||
                             float volume, float pitch, int mode=Play_Normal);
 | 
			
		||||
                                             float volume, float pitch, PlayMode mode=Play_Normal);
 | 
			
		||||
        ///< Play a sound from an object
 | 
			
		||||
 | 
			
		||||
        virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId);
 | 
			
		||||
| 
						 | 
				
			
			@ -127,6 +132,12 @@ namespace MWSound
 | 
			
		|||
        virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const;
 | 
			
		||||
        ///< Is the given sound currently playing on the given object?
 | 
			
		||||
 | 
			
		||||
        virtual void pauseSounds(int types=Play_TypeMask);
 | 
			
		||||
        ///< Pauses all currently playing sounds, including music.
 | 
			
		||||
 | 
			
		||||
        virtual void resumeSounds(int types=Play_TypeMask);
 | 
			
		||||
        ///< Resumes all previously paused sounds.
 | 
			
		||||
 | 
			
		||||
        virtual void update(float duration);
 | 
			
		||||
 | 
			
		||||
        virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -738,7 +738,7 @@ void WeatherManager::update(float duration)
 | 
			
		|||
        if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end())
 | 
			
		||||
        {
 | 
			
		||||
            mSoundsPlaying.push_back(ambientSnd);
 | 
			
		||||
            MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, true);
 | 
			
		||||
            MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, MWBase::SoundManager::Play_Loop);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -749,7 +749,7 @@ void WeatherManager::update(float duration)
 | 
			
		|||
        if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end())
 | 
			
		||||
        {
 | 
			
		||||
            mSoundsPlaying.push_back(rainSnd);
 | 
			
		||||
            MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, true);
 | 
			
		||||
            MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, MWBase::SoundManager::Play_Loop);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -170,7 +170,7 @@ namespace MWWorld
 | 
			
		|||
    World::World (OEngine::Render::OgreRenderer& renderer,
 | 
			
		||||
        const Files::Collections& fileCollections,
 | 
			
		||||
        const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame,
 | 
			
		||||
        const ToUTF8::FromType& encoding, std::map<std::string,std::string> fallbackMap)
 | 
			
		||||
        ToUTF8::Utf8Encoder* encoder, std::map<std::string,std::string> fallbackMap)
 | 
			
		||||
    : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0),
 | 
			
		||||
      mSky (true), mCells (mStore, mEsm),
 | 
			
		||||
      mNumFacing(0)
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +187,7 @@ namespace MWWorld
 | 
			
		|||
        std::cout << "Loading ESM " << masterPath.string() << "\n";
 | 
			
		||||
 | 
			
		||||
        // This parses the ESM file and loads a sample cell
 | 
			
		||||
        mEsm.setEncoding(encoding);
 | 
			
		||||
        mEsm.setEncoder(encoder);
 | 
			
		||||
        mEsm.open (masterPath.string());
 | 
			
		||||
        mStore.load (mEsm);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1300,4 +1300,14 @@ namespace MWWorld
 | 
			
		|||
        return 0;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void World::playVideo (const std::string &name, bool allowSkipping)
 | 
			
		||||
    {
 | 
			
		||||
        mRendering->playVideo(name, allowSkipping);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void World::stopVideo ()
 | 
			
		||||
    {
 | 
			
		||||
        mRendering->stopVideo();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,7 +95,7 @@ namespace MWWorld
 | 
			
		|||
            World (OEngine::Render::OgreRenderer& renderer,
 | 
			
		||||
                const Files::Collections& fileCollections,
 | 
			
		||||
                const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame,
 | 
			
		||||
                const ToUTF8::FromType& encoding, std::map<std::string,std::string> fallbackMap);
 | 
			
		||||
                ToUTF8::Utf8Encoder* encoder, std::map<std::string,std::string> fallbackMap);
 | 
			
		||||
 | 
			
		||||
            virtual ~World();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -336,6 +336,10 @@ namespace MWWorld
 | 
			
		|||
            /// 1 - only waiting \n
 | 
			
		||||
            /// 2 - player is underwater \n
 | 
			
		||||
            /// 3 - enemies are nearby (not implemented)
 | 
			
		||||
 | 
			
		||||
            /// \todo this does not belong here
 | 
			
		||||
            virtual void playVideo(const std::string& name, bool allowSkipping);
 | 
			
		||||
            virtual void stopVideo();
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,105 +0,0 @@
 | 
			
		|||
# Find the FFmpeg library
 | 
			
		||||
#
 | 
			
		||||
# Sets
 | 
			
		||||
#   FFMPEG_FOUND.  If false, don't try to use ffmpeg
 | 
			
		||||
#   FFMPEG_INCLUDE_DIR
 | 
			
		||||
#   FFMPEG_LIBRARIES
 | 
			
		||||
#
 | 
			
		||||
# Modified by Nicolay Korslund for OpenMW
 | 
			
		||||
 | 
			
		||||
SET( FFMPEG_FOUND "NO" )
 | 
			
		||||
 | 
			
		||||
FIND_PATH( FFMPEG_general_INCLUDE_DIR libavcodec/avcodec.h libavformat/avformat.h
 | 
			
		||||
  HINTS
 | 
			
		||||
  PATHS
 | 
			
		||||
  /usr/include
 | 
			
		||||
  /usr/local/include
 | 
			
		||||
  /usr/include/ffmpeg
 | 
			
		||||
  /usr/local/include/ffmpeg
 | 
			
		||||
  /usr/include/ffmpeg/libavcodec
 | 
			
		||||
  /usr/local/include/ffmpeg/libavcodec
 | 
			
		||||
  /usr/include/libavcodec
 | 
			
		||||
  /usr/local/include/libavcodec
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
FIND_PATH( FFMPEG_avcodec_INCLUDE_DIR avcodec.h
 | 
			
		||||
  HINTS
 | 
			
		||||
  PATHS
 | 
			
		||||
  ${FFMPEG_general_INCLUDE_DIR}/libavcodec
 | 
			
		||||
  /usr/include
 | 
			
		||||
  /usr/local/include
 | 
			
		||||
  /usr/include/ffmpeg
 | 
			
		||||
  /usr/local/include/ffmpeg
 | 
			
		||||
  /usr/include/ffmpeg/libavcodec
 | 
			
		||||
  /usr/local/include/ffmpeg/libavcodec
 | 
			
		||||
  /usr/include/libavcodec
 | 
			
		||||
  /usr/local/include/libavcodec
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
FIND_PATH( FFMPEG_avformat_INCLUDE_DIR avformat.h
 | 
			
		||||
  HINTS
 | 
			
		||||
  PATHS
 | 
			
		||||
  ${FFMPEG_general_INCLUDE_DIR}/libavformat
 | 
			
		||||
  /usr/include
 | 
			
		||||
  /usr/local/include
 | 
			
		||||
  /usr/include/ffmpeg
 | 
			
		||||
  /usr/local/include/ffmpeg
 | 
			
		||||
  /usr/include/ffmpeg/libavformat
 | 
			
		||||
  /usr/local/include/ffmpeg/libavformat
 | 
			
		||||
  /usr/include/libavformat
 | 
			
		||||
  /usr/local/include/libavformat
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(FFMPEG_INCLUDE_DIR ${FFMPEG_general_INCLUDE_DIR} ${FFMPEG_avcodec_INCLUDE_DIR} ${FFMPEG_avformat_INCLUDE_DIR})
 | 
			
		||||
 | 
			
		||||
IF( FFMPEG_INCLUDE_DIR )
 | 
			
		||||
 | 
			
		||||
FIND_PROGRAM( FFMPEG_CONFIG ffmpeg-config
 | 
			
		||||
  /usr/bin
 | 
			
		||||
  /usr/local/bin
 | 
			
		||||
  ${HOME}/bin
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
IF( FFMPEG_CONFIG )
 | 
			
		||||
  EXEC_PROGRAM( ${FFMPEG_CONFIG} ARGS "--libs avformat" OUTPUT_VARIABLE FFMPEG_LIBS )
 | 
			
		||||
  SET( FFMPEG_FOUND "YES" )
 | 
			
		||||
  SET( FFMPEG_LIBRARIES "${FFMPEG_LIBS}" )
 | 
			
		||||
  
 | 
			
		||||
ELSE( FFMPEG_CONFIG )
 | 
			
		||||
 | 
			
		||||
  FIND_LIBRARY( FFMPEG_avcodec_LIBRARY avcodec
 | 
			
		||||
    /usr/lib
 | 
			
		||||
    /usr/local/lib
 | 
			
		||||
    /usr/lib64
 | 
			
		||||
    /usr/local/lib64
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  FIND_LIBRARY( FFMPEG_avformat_LIBRARY avformat
 | 
			
		||||
    /usr/lib
 | 
			
		||||
    /usr/local/lib
 | 
			
		||||
    /usr/lib64
 | 
			
		||||
    /usr/local/lib64
 | 
			
		||||
  )
 | 
			
		||||
  
 | 
			
		||||
  FIND_LIBRARY( FFMPEG_avutil_LIBRARY avutil
 | 
			
		||||
    /usr/lib
 | 
			
		||||
    /usr/local/lib
 | 
			
		||||
    /usr/lib64
 | 
			
		||||
    /usr/local/lib64
 | 
			
		||||
  )
 | 
			
		||||
  
 | 
			
		||||
  IF( FFMPEG_avcodec_LIBRARY )
 | 
			
		||||
  IF( FFMPEG_avformat_LIBRARY )
 | 
			
		||||
 | 
			
		||||
    SET( FFMPEG_FOUND "YES" )
 | 
			
		||||
    SET( FFMPEG_LIBRARIES ${FFMPEG_avformat_LIBRARY} ${FFMPEG_avcodec_LIBRARY} )
 | 
			
		||||
    IF( FFMPEG_avutil_LIBRARY )
 | 
			
		||||
       SET( FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${FFMPEG_avutil_LIBRARY} )
 | 
			
		||||
    ENDIF( FFMPEG_avutil_LIBRARY )
 | 
			
		||||
 | 
			
		||||
  ENDIF( FFMPEG_avformat_LIBRARY )
 | 
			
		||||
  ENDIF( FFMPEG_avcodec_LIBRARY )
 | 
			
		||||
 | 
			
		||||
ENDIF( FFMPEG_CONFIG )
 | 
			
		||||
 | 
			
		||||
ENDIF( FFMPEG_INCLUDE_DIR )
 | 
			
		||||
							
								
								
									
										148
									
								
								cmake/FindFFmpeg.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								cmake/FindFFmpeg.cmake
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,148 @@
 | 
			
		|||
# vim: ts=2 sw=2
 | 
			
		||||
# - Try to find the required ffmpeg components(default: AVFORMAT, AVUTIL, AVCODEC)
 | 
			
		||||
#
 | 
			
		||||
# Once done this will define
 | 
			
		||||
#  FFMPEG_FOUND         - System has the all required components.
 | 
			
		||||
#  FFMPEG_INCLUDE_DIRS  - Include directory necessary for using the required components headers.
 | 
			
		||||
#  FFMPEG_LIBRARIES     - Link these to use the required ffmpeg components.
 | 
			
		||||
#  FFMPEG_DEFINITIONS   - Compiler switches required for using the required ffmpeg components.
 | 
			
		||||
#
 | 
			
		||||
# For each of the components it will additionaly set.
 | 
			
		||||
#   - AVCODEC
 | 
			
		||||
#   - AVDEVICE
 | 
			
		||||
#   - AVFORMAT
 | 
			
		||||
#   - AVUTIL
 | 
			
		||||
#   - POSTPROCESS
 | 
			
		||||
#   - SWSCALE
 | 
			
		||||
# the following variables will be defined
 | 
			
		||||
#  <component>_FOUND        - System has <component>
 | 
			
		||||
#  <component>_INCLUDE_DIRS - Include directory necessary for using the <component> headers
 | 
			
		||||
#  <component>_LIBRARIES    - Link these to use <component>
 | 
			
		||||
#  <component>_DEFINITIONS  - Compiler switches required for using <component>
 | 
			
		||||
#  <component>_VERSION      - The components version
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 2006, Matthias Kretz, <kretz@kde.org>
 | 
			
		||||
# Copyright (c) 2008, Alexander Neundorf, <neundorf@kde.org>
 | 
			
		||||
# Copyright (c) 2011, Michael Jansen, <kde@michael-jansen.biz>
 | 
			
		||||
#
 | 
			
		||||
# Redistribution and use is allowed according to the terms of the BSD license.
 | 
			
		||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
 | 
			
		||||
 | 
			
		||||
include(FindPackageHandleStandardArgs)
 | 
			
		||||
 | 
			
		||||
# The default components were taken from a survey over other FindFFMPEG.cmake files
 | 
			
		||||
if (NOT FFmpeg_FIND_COMPONENTS)
 | 
			
		||||
  set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
 | 
			
		||||
endif ()
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
### Macro: set_component_found
 | 
			
		||||
#
 | 
			
		||||
# Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present.
 | 
			
		||||
#
 | 
			
		||||
macro(set_component_found _component )
 | 
			
		||||
  if (${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS)
 | 
			
		||||
    # message(STATUS "  - ${_component} found.")
 | 
			
		||||
    set(${_component}_FOUND TRUE)
 | 
			
		||||
  else ()
 | 
			
		||||
    # message(STATUS "  - ${_component} not found.")
 | 
			
		||||
  endif ()
 | 
			
		||||
endmacro()
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
### Macro: find_component
 | 
			
		||||
#
 | 
			
		||||
# Checks for the given component by invoking pkgconfig and then looking up the libraries and
 | 
			
		||||
# include directories.
 | 
			
		||||
#
 | 
			
		||||
macro(find_component _component _pkgconfig _library _header)
 | 
			
		||||
 | 
			
		||||
  if (NOT WIN32)
 | 
			
		||||
     # use pkg-config to get the directories and then use these values
 | 
			
		||||
     # in the FIND_PATH() and FIND_LIBRARY() calls
 | 
			
		||||
     find_package(PkgConfig)
 | 
			
		||||
     if (PKG_CONFIG_FOUND)
 | 
			
		||||
       pkg_check_modules(PC_${_component} ${_pkgconfig})
 | 
			
		||||
     endif ()
 | 
			
		||||
  endif (NOT WIN32)
 | 
			
		||||
 | 
			
		||||
  find_path(${_component}_INCLUDE_DIRS ${_header}
 | 
			
		||||
    HINTS
 | 
			
		||||
      ${PC_LIB${_component}_INCLUDEDIR}
 | 
			
		||||
      ${PC_LIB${_component}_INCLUDE_DIRS}
 | 
			
		||||
    PATH_SUFFIXES
 | 
			
		||||
      ffmpeg
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  find_library(${_component}_LIBRARIES NAMES ${_library}
 | 
			
		||||
      HINTS
 | 
			
		||||
      ${PC_LIB${_component}_LIBDIR}
 | 
			
		||||
      ${PC_LIB${_component}_LIBRARY_DIRS}
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  set(${_component}_DEFINITIONS  ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.")
 | 
			
		||||
  set(${_component}_VERSION      ${PC_${_component}_VERSION}      CACHE STRING "The ${_component} version number.")
 | 
			
		||||
 | 
			
		||||
  set_component_found(${_component})
 | 
			
		||||
 | 
			
		||||
  mark_as_advanced(
 | 
			
		||||
    ${_component}_INCLUDE_DIRS
 | 
			
		||||
    ${_component}_LIBRARIES
 | 
			
		||||
    ${_component}_DEFINITIONS
 | 
			
		||||
    ${_component}_VERSION)
 | 
			
		||||
 | 
			
		||||
endmacro()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Check for cached results. If there are skip the costly part.
 | 
			
		||||
if (NOT FFMPEG_LIBRARIES)
 | 
			
		||||
 | 
			
		||||
  # Check for all possible component.
 | 
			
		||||
  find_component(AVCODEC  libavcodec  avcodec  libavcodec/avcodec.h)
 | 
			
		||||
  find_component(AVFORMAT libavformat avformat libavformat/avformat.h)
 | 
			
		||||
  find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h)
 | 
			
		||||
  find_component(AVUTIL   libavutil   avutil   libavutil/avutil.h)
 | 
			
		||||
  find_component(SWSCALE  libswscale  swscale  libswscale/swscale.h)
 | 
			
		||||
  find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h)
 | 
			
		||||
 | 
			
		||||
  # Check if the required components were found and add their stuff to the FFMPEG_* vars.
 | 
			
		||||
  foreach (_component ${FFmpeg_FIND_COMPONENTS})
 | 
			
		||||
    if (${_component}_FOUND)
 | 
			
		||||
      # message(STATUS "Required component ${_component} present.")
 | 
			
		||||
      set(FFMPEG_LIBRARIES   ${FFMPEG_LIBRARIES}   ${${_component}_LIBRARIES})
 | 
			
		||||
      set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} ${${_component}_DEFINITIONS})
 | 
			
		||||
      list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS})
 | 
			
		||||
    else ()
 | 
			
		||||
      # message(STATUS "Required component ${_component} missing.")
 | 
			
		||||
    endif ()
 | 
			
		||||
  endforeach ()
 | 
			
		||||
 | 
			
		||||
  # Build the include path with duplicates removed.
 | 
			
		||||
  if (FFMPEG_INCLUDE_DIRS)
 | 
			
		||||
    list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS)
 | 
			
		||||
  endif ()
 | 
			
		||||
 | 
			
		||||
  # cache the vars.
 | 
			
		||||
  set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE)
 | 
			
		||||
  set(FFMPEG_LIBRARIES    ${FFMPEG_LIBRARIES}    CACHE STRING "The FFmpeg libraries." FORCE)
 | 
			
		||||
  set(FFMPEG_DEFINITIONS  ${FFMPEG_DEFINITIONS}  CACHE STRING "The FFmpeg cflags." FORCE)
 | 
			
		||||
 | 
			
		||||
  mark_as_advanced(FFMPEG_INCLUDE_DIRS
 | 
			
		||||
                   FFMPEG_LIBRARIES
 | 
			
		||||
                   FFMPEG_DEFINITIONS)
 | 
			
		||||
 | 
			
		||||
endif ()
 | 
			
		||||
 | 
			
		||||
# Now set the noncached _FOUND vars for the components.
 | 
			
		||||
foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE)
 | 
			
		||||
  set_component_found(${_component})
 | 
			
		||||
endforeach ()
 | 
			
		||||
 | 
			
		||||
# Compile the list of required vars
 | 
			
		||||
set(_FFmpeg_REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS)
 | 
			
		||||
foreach (_component ${FFmpeg_FIND_COMPONENTS})
 | 
			
		||||
  list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS)
 | 
			
		||||
endforeach ()
 | 
			
		||||
 | 
			
		||||
# Give a nice error message if some of the required vars are missing.
 | 
			
		||||
find_package_handle_standard_args(FFmpeg DEFAULT_MSG ${_FFmpeg_REQUIRED_VARS})
 | 
			
		||||
							
								
								
									
										177
									
								
								cmake/FindSDL.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								cmake/FindSDL.cmake
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,177 @@
 | 
			
		|||
# Locate SDL library
 | 
			
		||||
# This module defines
 | 
			
		||||
# SDL_LIBRARY, the name of the library to link against
 | 
			
		||||
# SDL_FOUND, if false, do not try to link to SDL
 | 
			
		||||
# SDL_INCLUDE_DIR, where to find SDL.h
 | 
			
		||||
#
 | 
			
		||||
# This module responds to the the flag:
 | 
			
		||||
# SDL_BUILDING_LIBRARY
 | 
			
		||||
# If this is defined, then no SDL_main will be linked in because 
 | 
			
		||||
# only applications need main().
 | 
			
		||||
# Otherwise, it is assumed you are building an application and this
 | 
			
		||||
# module will attempt to locate and set the the proper link flags
 | 
			
		||||
# as part of the returned SDL_LIBRARY variable.
 | 
			
		||||
#
 | 
			
		||||
# Don't forget to include SDLmain.h and SDLmain.m your project for the 
 | 
			
		||||
# OS X framework based version. (Other versions link to -lSDLmain which
 | 
			
		||||
# this module will try to find on your behalf.) Also for OS X, this 
 | 
			
		||||
# module will automatically add the -framework Cocoa on your behalf.
 | 
			
		||||
#
 | 
			
		||||
#
 | 
			
		||||
# Additional Note: If you see an empty SDL_LIBRARY_TEMP in your configuration
 | 
			
		||||
# and no SDL_LIBRARY, it means CMake did not find your SDL library 
 | 
			
		||||
# (SDL.dll, libsdl.so, SDL.framework, etc). 
 | 
			
		||||
# Set SDL_LIBRARY_TEMP to point to your SDL library, and configure again. 
 | 
			
		||||
# Similarly, if you see an empty SDLMAIN_LIBRARY, you should set this value
 | 
			
		||||
# as appropriate. These values are used to generate the final SDL_LIBRARY
 | 
			
		||||
# variable, but when these values are unset, SDL_LIBRARY does not get created.
 | 
			
		||||
#
 | 
			
		||||
#
 | 
			
		||||
# $SDLDIR is an environment variable that would
 | 
			
		||||
# correspond to the ./configure --prefix=$SDLDIR
 | 
			
		||||
# used in building SDL.
 | 
			
		||||
# l.e.galup  9-20-02
 | 
			
		||||
#
 | 
			
		||||
# Modified by Eric Wing. 
 | 
			
		||||
# Added code to assist with automated building by using environmental variables
 | 
			
		||||
# and providing a more controlled/consistent search behavior.
 | 
			
		||||
# Added new modifications to recognize OS X frameworks and 
 | 
			
		||||
# additional Unix paths (FreeBSD, etc). 
 | 
			
		||||
# Also corrected the header search path to follow "proper" SDL guidelines.
 | 
			
		||||
# Added a search for SDLmain which is needed by some platforms.
 | 
			
		||||
# Added a search for threads which is needed by some platforms.
 | 
			
		||||
# Added needed compile switches for MinGW.
 | 
			
		||||
#
 | 
			
		||||
# On OSX, this will prefer the Framework version (if found) over others.
 | 
			
		||||
# People will have to manually change the cache values of 
 | 
			
		||||
# SDL_LIBRARY to override this selection or set the CMake environment
 | 
			
		||||
# CMAKE_INCLUDE_PATH to modify the search paths.
 | 
			
		||||
#
 | 
			
		||||
# Note that the header path has changed from SDL/SDL.h to just SDL.h
 | 
			
		||||
# This needed to change because "proper" SDL convention
 | 
			
		||||
# is #include "SDL.h", not <SDL/SDL.h>. This is done for portability
 | 
			
		||||
# reasons because not all systems place things in SDL/ (see FreeBSD).
 | 
			
		||||
 | 
			
		||||
#=============================================================================
 | 
			
		||||
# Copyright 2003-2009 Kitware, Inc.
 | 
			
		||||
#
 | 
			
		||||
# Distributed under the OSI-approved BSD License (the "License");
 | 
			
		||||
# see accompanying file Copyright.txt for details.
 | 
			
		||||
#
 | 
			
		||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
 | 
			
		||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | 
			
		||||
# See the License for more information.
 | 
			
		||||
#=============================================================================
 | 
			
		||||
# (To distribute this file outside of CMake, substitute the full
 | 
			
		||||
#  License text for the above reference.)
 | 
			
		||||
 | 
			
		||||
FIND_PATH(SDL_INCLUDE_DIR SDL.h
 | 
			
		||||
  HINTS
 | 
			
		||||
  $ENV{SDLDIR}
 | 
			
		||||
  PATH_SUFFIXES include/SDL include
 | 
			
		||||
  PATHS
 | 
			
		||||
  ~/Library/Frameworks
 | 
			
		||||
  /Library/Frameworks
 | 
			
		||||
  /usr/local/include/SDL12
 | 
			
		||||
  /usr/local/include/SDL11 # FreeBSD ports
 | 
			
		||||
  /usr/include/SDL12
 | 
			
		||||
  /usr/include/SDL11
 | 
			
		||||
  /sw # Fink
 | 
			
		||||
  /opt/local # DarwinPorts
 | 
			
		||||
  /opt/csw # Blastwave
 | 
			
		||||
  /opt
 | 
			
		||||
)
 | 
			
		||||
#MESSAGE("SDL_INCLUDE_DIR is ${SDL_INCLUDE_DIR}")
 | 
			
		||||
 | 
			
		||||
# SDL-1.1 is the name used by FreeBSD ports...
 | 
			
		||||
# don't confuse it for the version number.
 | 
			
		||||
FIND_LIBRARY(SDL_LIBRARY_TEMP 
 | 
			
		||||
  NAMES SDL SDL-1.1
 | 
			
		||||
  HINTS
 | 
			
		||||
  $ENV{SDLDIR}
 | 
			
		||||
  PATH_SUFFIXES lib64 lib
 | 
			
		||||
  PATHS
 | 
			
		||||
  /sw
 | 
			
		||||
  /opt/local
 | 
			
		||||
  /opt/csw
 | 
			
		||||
  /opt
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
#MESSAGE("SDL_LIBRARY_TEMP is ${SDL_LIBRARY_TEMP}")
 | 
			
		||||
 | 
			
		||||
IF(NOT SDL_BUILDING_LIBRARY)
 | 
			
		||||
  IF(NOT ${SDL_INCLUDE_DIR} MATCHES ".framework")
 | 
			
		||||
    # Non-OS X framework versions expect you to also dynamically link to 
 | 
			
		||||
    # SDLmain. This is mainly for Windows and OS X. Other (Unix) platforms 
 | 
			
		||||
    # seem to provide SDLmain for compatibility even though they don't
 | 
			
		||||
    # necessarily need it.
 | 
			
		||||
    FIND_LIBRARY(SDLMAIN_LIBRARY 
 | 
			
		||||
      NAMES SDLmain SDLmain-1.1
 | 
			
		||||
      HINTS
 | 
			
		||||
      $ENV{SDLDIR}
 | 
			
		||||
      PATH_SUFFIXES lib64 lib
 | 
			
		||||
      PATHS
 | 
			
		||||
      /sw
 | 
			
		||||
      /opt/local
 | 
			
		||||
      /opt/csw
 | 
			
		||||
      /opt
 | 
			
		||||
    )
 | 
			
		||||
  ENDIF(NOT ${SDL_INCLUDE_DIR} MATCHES ".framework")
 | 
			
		||||
ENDIF(NOT SDL_BUILDING_LIBRARY)
 | 
			
		||||
 | 
			
		||||
# SDL may require threads on your system.
 | 
			
		||||
# The Apple build may not need an explicit flag because one of the 
 | 
			
		||||
# frameworks may already provide it. 
 | 
			
		||||
# But for non-OSX systems, I will use the CMake Threads package.
 | 
			
		||||
IF(NOT APPLE)
 | 
			
		||||
  FIND_PACKAGE(Threads)
 | 
			
		||||
ENDIF(NOT APPLE)
 | 
			
		||||
 | 
			
		||||
# MinGW needs an additional library, mwindows
 | 
			
		||||
# It's total link flags should look like -lmingw32 -lSDLmain -lSDL -lmwindows
 | 
			
		||||
# (Actually on second look, I think it only needs one of the m* libraries.)
 | 
			
		||||
IF(MINGW)
 | 
			
		||||
  SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
 | 
			
		||||
ENDIF(MINGW)
 | 
			
		||||
 | 
			
		||||
SET(SDL_FOUND "NO")
 | 
			
		||||
IF(SDL_LIBRARY_TEMP)
 | 
			
		||||
  # For SDLmain
 | 
			
		||||
  IF(NOT SDL_BUILDING_LIBRARY)
 | 
			
		||||
    IF(SDLMAIN_LIBRARY)
 | 
			
		||||
      SET(SDL_LIBRARY_TEMP ${SDLMAIN_LIBRARY} ${SDL_LIBRARY_TEMP})
 | 
			
		||||
    ENDIF(SDLMAIN_LIBRARY)
 | 
			
		||||
  ENDIF(NOT SDL_BUILDING_LIBRARY)
 | 
			
		||||
 | 
			
		||||
  # For OS X, SDL uses Cocoa as a backend so it must link to Cocoa.
 | 
			
		||||
  # CMake doesn't display the -framework Cocoa string in the UI even 
 | 
			
		||||
  # though it actually is there if I modify a pre-used variable.
 | 
			
		||||
  # I think it has something to do with the CACHE STRING.
 | 
			
		||||
  # So I use a temporary variable until the end so I can set the 
 | 
			
		||||
  # "real" variable in one-shot.
 | 
			
		||||
  IF(APPLE)
 | 
			
		||||
    SET(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} "-framework Cocoa")
 | 
			
		||||
  ENDIF(APPLE)
 | 
			
		||||
    
 | 
			
		||||
  # For threads, as mentioned Apple doesn't need this.
 | 
			
		||||
  # In fact, there seems to be a problem if I used the Threads package
 | 
			
		||||
  # and try using this line, so I'm just skipping it entirely for OS X.
 | 
			
		||||
  IF(NOT APPLE)
 | 
			
		||||
    SET(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
 | 
			
		||||
  ENDIF(NOT APPLE)
 | 
			
		||||
 | 
			
		||||
  # For MinGW library
 | 
			
		||||
  IF(MINGW)
 | 
			
		||||
    SET(SDL_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL_LIBRARY_TEMP})
 | 
			
		||||
  ENDIF(MINGW)
 | 
			
		||||
 | 
			
		||||
  # Set the final string here so the GUI reflects the final state.
 | 
			
		||||
  SET(SDL_LIBRARY ${SDL_LIBRARY_TEMP} CACHE STRING "Where the SDL Library can be found")
 | 
			
		||||
  # Set the temp variable to INTERNAL so it is not seen in the CMake GUI
 | 
			
		||||
  SET(SDL_LIBRARY_TEMP "${SDL_LIBRARY_TEMP}" CACHE INTERNAL "")
 | 
			
		||||
 | 
			
		||||
  SET(SDL_FOUND "YES")
 | 
			
		||||
ENDIF(SDL_LIBRARY_TEMP)
 | 
			
		||||
 | 
			
		||||
#MESSAGE("SDL_LIBRARY is ${SDL_LIBRARY}")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ add_component_dir (misc
 | 
			
		|||
 | 
			
		||||
add_component_dir (files
 | 
			
		||||
    linuxpath windowspath macospath fixedpath multidircollection collections fileops configurationmanager
 | 
			
		||||
    filelibrary ogreplugin
 | 
			
		||||
    filelibrary ogreplugin constrainedfiledatastream lowlevelfile
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
add_component_dir (compiler
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,94 +23,15 @@
 | 
			
		|||
 | 
			
		||||
#include "bsa_file.hpp"
 | 
			
		||||
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
//#include <stdexcept>
 | 
			
		||||
//#include <cstdlib>
 | 
			
		||||
//#include <cassert>
 | 
			
		||||
 | 
			
		||||
#include <OgreDataStream.h>
 | 
			
		||||
#include "../files/constrainedfiledatastream.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
using namespace Bsa;
 | 
			
		||||
 | 
			
		||||
class ConstrainedDataStream : public Ogre::DataStream {
 | 
			
		||||
    std::ifstream mStream;
 | 
			
		||||
    const size_t mStart;
 | 
			
		||||
    size_t mPos;
 | 
			
		||||
    bool mIsEOF;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    ConstrainedDataStream(const Ogre::String &fname, size_t start, size_t length)
 | 
			
		||||
      : mStream(fname.c_str(), std::ios_base::binary), mStart(start), mPos(0), mIsEOF(false)
 | 
			
		||||
    {
 | 
			
		||||
        mSize = length;
 | 
			
		||||
        if(!mStream.seekg(mStart, std::ios_base::beg))
 | 
			
		||||
            throw std::runtime_error("Error seeking to start of BSA entry");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ConstrainedDataStream(const Ogre::String &name, const Ogre::String &fname,
 | 
			
		||||
                          size_t start, size_t length)
 | 
			
		||||
      : Ogre::DataStream(name), mStream(fname.c_str(), std::ios_base::binary),
 | 
			
		||||
        mStart(start), mPos(0), mIsEOF(false)
 | 
			
		||||
    {
 | 
			
		||||
        mSize = length;
 | 
			
		||||
        if(!mStream.seekg(mStart, std::ios_base::beg))
 | 
			
		||||
            throw std::runtime_error("Error seeking to start of BSA entry");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    virtual size_t read(void *buf, size_t count)
 | 
			
		||||
    {
 | 
			
		||||
        mStream.clear();
 | 
			
		||||
 | 
			
		||||
        if(count > mSize-mPos)
 | 
			
		||||
        {
 | 
			
		||||
            count = mSize-mPos;
 | 
			
		||||
            mIsEOF = true;
 | 
			
		||||
        }
 | 
			
		||||
        mStream.read(reinterpret_cast<char*>(buf), count);
 | 
			
		||||
 | 
			
		||||
        count = mStream.gcount();
 | 
			
		||||
        mPos += count;
 | 
			
		||||
        return count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual void skip(long count)
 | 
			
		||||
    {
 | 
			
		||||
        if((count >= 0 && (size_t)count <= mSize-mPos) ||
 | 
			
		||||
           (count < 0 && (size_t)-count <= mPos))
 | 
			
		||||
        {
 | 
			
		||||
            mStream.clear();
 | 
			
		||||
            if(mStream.seekg(count, std::ios_base::cur))
 | 
			
		||||
            {
 | 
			
		||||
                mPos += count;
 | 
			
		||||
                mIsEOF = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual void seek(size_t pos)
 | 
			
		||||
    {
 | 
			
		||||
        if(pos < mSize)
 | 
			
		||||
        {
 | 
			
		||||
            mStream.clear();
 | 
			
		||||
            if(mStream.seekg(pos+mStart, std::ios_base::beg))
 | 
			
		||||
            {
 | 
			
		||||
                mPos = pos;
 | 
			
		||||
                mIsEOF = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual size_t tell() const
 | 
			
		||||
    { return mPos; }
 | 
			
		||||
 | 
			
		||||
    virtual bool eof() const
 | 
			
		||||
    { return mIsEOF; }
 | 
			
		||||
 | 
			
		||||
    virtual void close()
 | 
			
		||||
    { mStream.close(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// Error handling
 | 
			
		||||
void BSAFile::fail(const string &msg)
 | 
			
		||||
| 
						 | 
				
			
			@ -253,5 +174,5 @@ Ogre::DataStreamPtr BSAFile::getFile(const char *file)
 | 
			
		|||
        fail("File not found: " + string(file));
 | 
			
		||||
 | 
			
		||||
    const FileStruct &fs = files[i];
 | 
			
		||||
    return Ogre::DataStreamPtr(new ConstrainedDataStream(filename, fs.offset, fs.fileSize));
 | 
			
		||||
	return openConstrainedFileDataStream (filename.c_str (), fs.offset, fs.fileSize);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
#include "esmreader.hpp"
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
#include "../files/constrainedfiledatastream.hpp"
 | 
			
		||||
 | 
			
		||||
namespace ESM
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +15,11 @@ ESM_Context ESMReader::getContext()
 | 
			
		|||
    return mCtx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ESMReader::ESMReader(void):
 | 
			
		||||
    mBuffer(50*1024)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESMReader::restoreContext(const ESM_Context &rc)
 | 
			
		||||
{
 | 
			
		||||
    // Reopen the file if necessary
 | 
			
		||||
| 
						 | 
				
			
			@ -108,16 +115,12 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name)
 | 
			
		|||
 | 
			
		||||
void ESMReader::open(const std::string &file)
 | 
			
		||||
{
 | 
			
		||||
    std::ifstream *stream = OGRE_NEW_T(std::ifstream, Ogre::MEMCATEGORY_GENERAL)(file.c_str(), std::ios_base::binary);
 | 
			
		||||
    // Ogre will delete the stream for us
 | 
			
		||||
    open(Ogre::DataStreamPtr(new Ogre::FileStreamDataStream(stream)), file);
 | 
			
		||||
    open (openConstrainedFileDataStream (file.c_str ()), file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESMReader::openRaw(const std::string &file)
 | 
			
		||||
{
 | 
			
		||||
    std::ifstream *stream = OGRE_NEW_T(std::ifstream, Ogre::MEMCATEGORY_GENERAL)(file.c_str(), std::ios_base::binary);
 | 
			
		||||
    // Ogre will delete the stream for us
 | 
			
		||||
    openRaw(Ogre::DataStreamPtr(new Ogre::FileStreamDataStream(stream)), file);
 | 
			
		||||
    openRaw (openConstrainedFileDataStream (file.c_str ()), file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t ESMReader::getHNLong(const char *name)
 | 
			
		||||
| 
						 | 
				
			
			@ -325,11 +328,21 @@ void ESMReader::getExact(void*x, int size)
 | 
			
		|||
 | 
			
		||||
std::string ESMReader::getString(int size)
 | 
			
		||||
{
 | 
			
		||||
    char *ptr = ToUTF8::getBuffer(size);
 | 
			
		||||
    mEsm->read(ptr, size);
 | 
			
		||||
    size_t s = size;
 | 
			
		||||
    if (mBuffer.size() <= s)
 | 
			
		||||
        // Add some extra padding to reduce the chance of having to resize
 | 
			
		||||
        // again later.
 | 
			
		||||
        mBuffer.resize(3*s);
 | 
			
		||||
 | 
			
		||||
    // And make sure the string is zero terminated
 | 
			
		||||
    mBuffer[s] = 0;
 | 
			
		||||
 | 
			
		||||
    // read ESM data
 | 
			
		||||
    char *ptr = &mBuffer[0];
 | 
			
		||||
    getExact(ptr, size);
 | 
			
		||||
 | 
			
		||||
    // Convert to UTF8 and return
 | 
			
		||||
    return ToUTF8::getUtf8(mEncoding);
 | 
			
		||||
    return mEncoder->getUtf8(ptr, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESMReader::fail(const std::string &msg)
 | 
			
		||||
| 
						 | 
				
			
			@ -347,9 +360,9 @@ void ESMReader::fail(const std::string &msg)
 | 
			
		|||
    throw std::runtime_error(ss.str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESMReader::setEncoding(const ToUTF8::FromType& encoding)
 | 
			
		||||
void ESMReader::setEncoder(ToUTF8::Utf8Encoder* encoder)
 | 
			
		||||
{
 | 
			
		||||
  mEncoding = encoding;
 | 
			
		||||
    mEncoder = encoder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,8 @@ class ESMReader
 | 
			
		|||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  ESMReader(void);
 | 
			
		||||
 | 
			
		||||
  /*************************************************************************
 | 
			
		||||
   *
 | 
			
		||||
   *  Public type definitions
 | 
			
		||||
| 
						 | 
				
			
			@ -233,8 +235,8 @@ public:
 | 
			
		|||
  /// Used for error handling
 | 
			
		||||
  void fail(const std::string &msg);
 | 
			
		||||
 | 
			
		||||
  /// Sets font encoding for ESM strings
 | 
			
		||||
  void setEncoding(const ToUTF8::FromType& encoding);
 | 
			
		||||
  /// Sets font encoder for ESM strings
 | 
			
		||||
  void setEncoder(ToUTF8::Utf8Encoder* encoder);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  Ogre::DataStreamPtr mEsm;
 | 
			
		||||
| 
						 | 
				
			
			@ -244,9 +246,12 @@ private:
 | 
			
		|||
  // Special file signifier (see SpecialFile enum above)
 | 
			
		||||
  int mSpf;
 | 
			
		||||
 | 
			
		||||
  // Buffer for ESM strings
 | 
			
		||||
  std::vector<char> mBuffer;
 | 
			
		||||
 | 
			
		||||
  SaveData mSaveData;
 | 
			
		||||
  MasterList mMasters;
 | 
			
		||||
  ToUTF8::FromType mEncoding;
 | 
			
		||||
  ToUTF8::Utf8Encoder* mEncoder;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -157,12 +157,8 @@ void ESMWriter::writeHString(const std::string& data)
 | 
			
		|||
        write("\0", 1);
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        char *ptr = ToUTF8::getBuffer(data.size()+1);
 | 
			
		||||
        strncpy(ptr, &data[0], data.size());
 | 
			
		||||
        ptr[data.size()] = '\0';
 | 
			
		||||
 | 
			
		||||
        // Convert to UTF8 and return
 | 
			
		||||
        std::string ascii = ToUTF8::getLegacyEnc(m_encoding);
 | 
			
		||||
        std::string ascii = m_encoder->getLegacyEnc(data);
 | 
			
		||||
 | 
			
		||||
        write(ascii.c_str(), ascii.size());
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -192,21 +188,9 @@ void ESMWriter::write(const char* data, int size)
 | 
			
		|||
    m_stream->write(data, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESMWriter::setEncoding(const std::string& encoding)
 | 
			
		||||
void ESMWriter::setEncoder(ToUTF8::Utf8Encoder* encoder)
 | 
			
		||||
{
 | 
			
		||||
    if (encoding == "win1250")
 | 
			
		||||
    {
 | 
			
		||||
        m_encoding = ToUTF8::WINDOWS_1250;
 | 
			
		||||
    }
 | 
			
		||||
    else if (encoding == "win1251")
 | 
			
		||||
    {
 | 
			
		||||
        m_encoding = ToUTF8::WINDOWS_1251;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        // Default Latin encoding
 | 
			
		||||
        m_encoding = ToUTF8::WINDOWS_1252;
 | 
			
		||||
    }
 | 
			
		||||
    m_encoder = encoder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include "esmcommon.hpp"
 | 
			
		||||
#include "../to_utf8/to_utf8.hpp"
 | 
			
		||||
#include <components/to_utf8/to_utf8.hpp>
 | 
			
		||||
 | 
			
		||||
namespace ESM {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ public:
 | 
			
		|||
    void setVersion(int ver);
 | 
			
		||||
    int getType();
 | 
			
		||||
    void setType(int type);
 | 
			
		||||
    void setEncoding(const std::string& encoding); // Write strings as UTF-8?
 | 
			
		||||
    void setEncoder(ToUTF8::Utf8Encoder *encoding); // Write strings as UTF-8?
 | 
			
		||||
    void setAuthor(const std::string& author);
 | 
			
		||||
    void setDescription(const std::string& desc);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -94,11 +94,10 @@ private:
 | 
			
		|||
    std::list<RecordData> m_records;
 | 
			
		||||
    std::ostream* m_stream;
 | 
			
		||||
    std::streampos m_headerPos;
 | 
			
		||||
    ToUTF8::FromType m_encoding;
 | 
			
		||||
    ToUTF8::Utf8Encoder* m_encoder;
 | 
			
		||||
    int m_recordCount;
 | 
			
		||||
 | 
			
		||||
    HEDRstruct m_header;
 | 
			
		||||
    SaveData m_saveData;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										175
									
								
								components/files/constrainedfiledatastream.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								components/files/constrainedfiledatastream.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,175 @@
 | 
			
		|||
#include "constrainedfiledatastream.hpp"
 | 
			
		||||
#include "lowlevelfile.hpp"
 | 
			
		||||
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#ifndef __clang__
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#else
 | 
			
		||||
#include <tr1/cstdint>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
class ConstrainedDataStream : public Ogre::DataStream {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	static const size_t sBufferSize = 4096; // somewhat arbitrary though 64KB buffers didn't seem to improve performance any
 | 
			
		||||
	static const size_t sBufferThreshold = 1024; // reads larger than this bypass buffering as cost of memcpy outweighs cost of system call
 | 
			
		||||
 | 
			
		||||
    ConstrainedDataStream(const Ogre::String &fname, size_t start, size_t length)
 | 
			
		||||
	{
 | 
			
		||||
		mFile.open (fname.c_str ());
 | 
			
		||||
		mSize  = length != 0xFFFFFFFF ? length : mFile.size () - start;
 | 
			
		||||
 | 
			
		||||
		mPos    = 0;
 | 
			
		||||
		mOrigin = start;
 | 
			
		||||
		mExtent = start + mSize;
 | 
			
		||||
 | 
			
		||||
		mBufferOrigin = 0;
 | 
			
		||||
		mBufferExtent = 0;
 | 
			
		||||
	}
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
	size_t read(void* buf, size_t count)
 | 
			
		||||
	{
 | 
			
		||||
		assert (mPos <= mSize);
 | 
			
		||||
 | 
			
		||||
		uint8_t * out = reinterpret_cast <uint8_t *> (buf);
 | 
			
		||||
 | 
			
		||||
		size_t posBeg = mOrigin + mPos;
 | 
			
		||||
		size_t posEnd = posBeg + count;
 | 
			
		||||
 | 
			
		||||
		if (posEnd > mExtent)
 | 
			
		||||
			posEnd = mExtent;
 | 
			
		||||
 | 
			
		||||
		size_t posCur = posBeg;
 | 
			
		||||
 | 
			
		||||
		while (posCur != posEnd)
 | 
			
		||||
		{
 | 
			
		||||
			size_t readLeft = posEnd - posCur;
 | 
			
		||||
 | 
			
		||||
			if (posCur < mBufferOrigin || posCur >= mBufferExtent)
 | 
			
		||||
			{
 | 
			
		||||
				if (readLeft >= sBufferThreshold || (posCur == mOrigin && posEnd == mExtent))
 | 
			
		||||
				{
 | 
			
		||||
					assert (mFile.tell () == mBufferExtent);
 | 
			
		||||
 | 
			
		||||
					if (posCur != mBufferExtent)
 | 
			
		||||
						mFile.seek (posCur);
 | 
			
		||||
 | 
			
		||||
					posCur += mFile.read (out, readLeft);
 | 
			
		||||
 | 
			
		||||
					mBufferOrigin = mBufferExtent = posCur;
 | 
			
		||||
 | 
			
		||||
					mPos = posCur - mOrigin;
 | 
			
		||||
 | 
			
		||||
					return posCur - posBeg;
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					size_t newBufferOrigin;
 | 
			
		||||
 | 
			
		||||
					if ((posCur < mBufferOrigin) && (mBufferOrigin - posCur < sBufferSize))
 | 
			
		||||
						newBufferOrigin = std::max (mOrigin, mBufferOrigin > sBufferSize ? mBufferOrigin - sBufferSize : 0);
 | 
			
		||||
					else
 | 
			
		||||
						newBufferOrigin = posCur;
 | 
			
		||||
 | 
			
		||||
					fill (newBufferOrigin);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			size_t xfer = std::min (readLeft, mBufferExtent - posCur);
 | 
			
		||||
 | 
			
		||||
			memcpy (out, mBuffer + (posCur - mBufferOrigin), xfer);
 | 
			
		||||
 | 
			
		||||
			posCur += xfer;
 | 
			
		||||
			out += xfer;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		count = posEnd - posBeg;
 | 
			
		||||
		mPos += count;
 | 
			
		||||
		return count;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    void skip(long count)
 | 
			
		||||
    {
 | 
			
		||||
		assert (mPos <= mSize);
 | 
			
		||||
 | 
			
		||||
        if((count >= 0 && (size_t)count <= mSize-mPos) ||
 | 
			
		||||
           (count < 0 && (size_t)-count <= mPos))
 | 
			
		||||
			mPos += count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void seek(size_t pos)
 | 
			
		||||
    {
 | 
			
		||||
		assert (mPos <= mSize);
 | 
			
		||||
 | 
			
		||||
        if (pos < mSize)
 | 
			
		||||
			mPos = pos;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual size_t tell() const
 | 
			
		||||
    {
 | 
			
		||||
		assert (mPos <= mSize);
 | 
			
		||||
 | 
			
		||||
		return mPos;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    virtual bool eof() const
 | 
			
		||||
    {
 | 
			
		||||
		assert (mPos <= mSize);
 | 
			
		||||
 | 
			
		||||
		return mPos == mSize;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    virtual void close()
 | 
			
		||||
    {
 | 
			
		||||
		mFile.close();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
	void fill (size_t newOrigin)
 | 
			
		||||
	{
 | 
			
		||||
		assert (mFile.tell () == mBufferExtent);
 | 
			
		||||
 | 
			
		||||
		size_t newExtent = newOrigin + sBufferSize;
 | 
			
		||||
 | 
			
		||||
		if (newExtent > mExtent)
 | 
			
		||||
			newExtent = mExtent;
 | 
			
		||||
 | 
			
		||||
		size_t oldExtent = mBufferExtent;
 | 
			
		||||
 | 
			
		||||
		if (newOrigin != oldExtent)
 | 
			
		||||
			mFile.seek (newOrigin);
 | 
			
		||||
 | 
			
		||||
		mBufferOrigin = mBufferExtent = newOrigin;
 | 
			
		||||
 | 
			
		||||
		size_t amountRequested = newExtent - newOrigin;
 | 
			
		||||
 | 
			
		||||
		size_t amountRead = mFile.read (mBuffer, amountRequested);
 | 
			
		||||
 | 
			
		||||
		if (amountRead != amountRequested)
 | 
			
		||||
			throw std::runtime_error ("An unexpected condition occurred while reading from a file.");
 | 
			
		||||
 | 
			
		||||
		mBufferExtent = newExtent;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LowLevelFile mFile;
 | 
			
		||||
 | 
			
		||||
	size_t mOrigin;
 | 
			
		||||
	size_t mExtent;
 | 
			
		||||
	size_t mPos;
 | 
			
		||||
 | 
			
		||||
	uint8_t mBuffer [sBufferSize];
 | 
			
		||||
	size_t mBufferOrigin;
 | 
			
		||||
	size_t mBufferExtent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // end of unnamed namespace
 | 
			
		||||
 | 
			
		||||
Ogre::DataStreamPtr openConstrainedFileDataStream (char const * filename, size_t offset, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	return Ogre::DataStreamPtr(new ConstrainedDataStream(filename, offset, length));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								components/files/constrainedfiledatastream.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								components/files/constrainedfiledatastream.hpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
#ifndef COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP
 | 
			
		||||
#define COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP
 | 
			
		||||
 | 
			
		||||
#include <OgreDataStream.h>
 | 
			
		||||
 | 
			
		||||
Ogre::DataStreamPtr openConstrainedFileDataStream (char const * filename, size_t offset = 0, size_t length = 0xFFFFFFFF);
 | 
			
		||||
 | 
			
		||||
#endif // COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP
 | 
			
		||||
							
								
								
									
										299
									
								
								components/files/lowlevelfile.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								components/files/lowlevelfile.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,299 @@
 | 
			
		|||
#include "lowlevelfile.hpp"
 | 
			
		||||
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
#if FILE_API == FILE_API_POSIX
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if FILE_API == FILE_API_STDIO
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 *	Implementation of LowLevelFile methods using c stdio
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
LowLevelFile::LowLevelFile ()
 | 
			
		||||
{
 | 
			
		||||
	mHandle = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LowLevelFile::~LowLevelFile ()
 | 
			
		||||
{
 | 
			
		||||
	if (mHandle != NULL)
 | 
			
		||||
		fclose (mHandle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LowLevelFile::open (char const * filename)
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle == NULL);
 | 
			
		||||
 | 
			
		||||
	mHandle = fopen (filename, "rb");
 | 
			
		||||
 | 
			
		||||
	if (mHandle == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		std::ostringstream os;
 | 
			
		||||
		os << "Failed to open '" << filename << "' for reading.";
 | 
			
		||||
		throw std::runtime_error (os.str ());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LowLevelFile::close ()
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != NULL);
 | 
			
		||||
 | 
			
		||||
	fclose (mHandle);
 | 
			
		||||
 | 
			
		||||
	mHandle = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t LowLevelFile::size ()
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != NULL);
 | 
			
		||||
 | 
			
		||||
	long oldPosition = ftell (mHandle);
 | 
			
		||||
 | 
			
		||||
	if (oldPosition == -1)
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	if (fseek (mHandle, 0, SEEK_END) != 0)
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	long Size = ftell (mHandle);
 | 
			
		||||
 | 
			
		||||
	if (Size == -1)
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	if (fseek (mHandle, oldPosition, SEEK_SET) != 0)
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	return size_t (Size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LowLevelFile::seek (size_t Position)
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != NULL);
 | 
			
		||||
 | 
			
		||||
	if (fseek (mHandle, Position, SEEK_SET) != 0)
 | 
			
		||||
		throw std::runtime_error ("A seek operation on a file failed.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t LowLevelFile::tell ()
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != NULL);
 | 
			
		||||
 | 
			
		||||
	long Position = ftell (mHandle);
 | 
			
		||||
 | 
			
		||||
	if (Position == -1)
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	return size_t (Position);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t LowLevelFile::read (void * data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != NULL);
 | 
			
		||||
 | 
			
		||||
	int amount = fread (data, 1, size, mHandle);
 | 
			
		||||
 | 
			
		||||
	if (amount == 0 && ferror (mHandle))
 | 
			
		||||
		throw std::runtime_error ("A read operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	return amount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif FILE_API == FILE_API_POSIX
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 *	Implementation of LowLevelFile methods using posix IO calls
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
LowLevelFile::LowLevelFile ()
 | 
			
		||||
{
 | 
			
		||||
	mHandle = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LowLevelFile::~LowLevelFile ()
 | 
			
		||||
{
 | 
			
		||||
	if (mHandle != -1)
 | 
			
		||||
		::close (mHandle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LowLevelFile::open (char const * filename)
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle == -1);
 | 
			
		||||
 | 
			
		||||
#ifdef O_BINARY
 | 
			
		||||
	static const int openFlags = O_RDONLY | O_BINARY;
 | 
			
		||||
#else
 | 
			
		||||
	static const int openFlags = O_RDONLY;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	mHandle = ::open (filename, openFlags, 0);
 | 
			
		||||
 | 
			
		||||
	if (mHandle == -1)
 | 
			
		||||
	{
 | 
			
		||||
		std::ostringstream os;
 | 
			
		||||
		os << "Failed to open '" << filename << "' for reading.";
 | 
			
		||||
		throw std::runtime_error (os.str ());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LowLevelFile::close ()
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != -1);
 | 
			
		||||
 | 
			
		||||
	::close (mHandle);
 | 
			
		||||
 | 
			
		||||
	mHandle = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t LowLevelFile::size ()
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != -1);
 | 
			
		||||
 | 
			
		||||
	size_t oldPosition = ::lseek (mHandle, 0, SEEK_CUR);
 | 
			
		||||
 | 
			
		||||
	if (oldPosition == size_t (-1))
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	size_t Size = ::lseek (mHandle, 0, SEEK_END);
 | 
			
		||||
 | 
			
		||||
	if (Size == size_t (-1))
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	if (lseek (mHandle, oldPosition, SEEK_SET) == -1)
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	return Size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LowLevelFile::seek (size_t Position)
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != -1);
 | 
			
		||||
 | 
			
		||||
	if (::lseek (mHandle, Position, SEEK_SET) == -1)
 | 
			
		||||
		throw std::runtime_error ("A seek operation on a file failed.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t LowLevelFile::tell ()
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != -1);
 | 
			
		||||
 | 
			
		||||
	size_t Position = ::lseek (mHandle, 0, SEEK_CUR);
 | 
			
		||||
 | 
			
		||||
	if (Position == size_t (-1))
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	return Position;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t LowLevelFile::read (void * data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != -1);
 | 
			
		||||
 | 
			
		||||
	int amount = ::read (mHandle, data, size);
 | 
			
		||||
 | 
			
		||||
	if (amount == -1)
 | 
			
		||||
		throw std::runtime_error ("A read operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	return amount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif FILE_API == FILE_API_WIN32
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 *	Implementation of LowLevelFile methods using Win32 API calls
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
LowLevelFile::LowLevelFile ()
 | 
			
		||||
{
 | 
			
		||||
	mHandle = INVALID_HANDLE_VALUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LowLevelFile::~LowLevelFile ()
 | 
			
		||||
{
 | 
			
		||||
	if (mHandle == INVALID_HANDLE_VALUE)
 | 
			
		||||
		CloseHandle (mHandle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LowLevelFile::open (char const * filename)
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle == INVALID_HANDLE_VALUE);
 | 
			
		||||
 | 
			
		||||
	HANDLE handle = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
 | 
			
		||||
 | 
			
		||||
	if (handle == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		std::ostringstream os;
 | 
			
		||||
		os << "Failed to open '" << filename << "' for reading.";
 | 
			
		||||
		throw std::runtime_error (os.str ());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mHandle = handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LowLevelFile::close ()
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != INVALID_HANDLE_VALUE);
 | 
			
		||||
 | 
			
		||||
	CloseHandle (mHandle);
 | 
			
		||||
 | 
			
		||||
	mHandle = INVALID_HANDLE_VALUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t LowLevelFile::size ()
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != INVALID_HANDLE_VALUE);
 | 
			
		||||
 | 
			
		||||
	BY_HANDLE_FILE_INFORMATION info;
 | 
			
		||||
 | 
			
		||||
	if (!GetFileInformationByHandle (mHandle, &info))
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	if (info.nFileSizeHigh != 0)
 | 
			
		||||
		throw std::runtime_error ("Files greater that 4GB are not supported.");
 | 
			
		||||
 | 
			
		||||
	return info.nFileSizeLow;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LowLevelFile::seek (size_t Position)
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != INVALID_HANDLE_VALUE);
 | 
			
		||||
 | 
			
		||||
	if (SetFilePointer (mHandle, Position, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER)
 | 
			
		||||
		if (GetLastError () != NO_ERROR)
 | 
			
		||||
			throw std::runtime_error ("A seek operation on a file failed.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t LowLevelFile::tell ()
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != INVALID_HANDLE_VALUE);
 | 
			
		||||
 | 
			
		||||
	DWORD value = SetFilePointer (mHandle, 0, NULL, SEEK_CUR);
 | 
			
		||||
 | 
			
		||||
	if (value == INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
 | 
			
		||||
		throw std::runtime_error ("A query operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t LowLevelFile::read (void * data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	assert (mHandle != INVALID_HANDLE_VALUE);
 | 
			
		||||
 | 
			
		||||
	DWORD read;
 | 
			
		||||
 | 
			
		||||
	if (!ReadFile (mHandle, data, size, &read, NULL))
 | 
			
		||||
		throw std::runtime_error ("A read operation on a file failed.");
 | 
			
		||||
 | 
			
		||||
	return read;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										56
									
								
								components/files/lowlevelfile.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								components/files/lowlevelfile.hpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
#ifndef COMPONENTS_FILES_LOWLEVELFILE_HPP
 | 
			
		||||
#define COMPONENTS_FILES_LOWLEVELFILE_HPP
 | 
			
		||||
 | 
			
		||||
#include <OgrePlatform.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
 | 
			
		||||
#define FILE_API_STDIO	0
 | 
			
		||||
#define FILE_API_POSIX	1
 | 
			
		||||
#define FILE_API_WIN32	2
 | 
			
		||||
 | 
			
		||||
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
 | 
			
		||||
#define FILE_API	FILE_API_POSIX
 | 
			
		||||
#elif OGRE_PLATFORM == OGRE_PLATFORM_WIN32
 | 
			
		||||
#define FILE_API	FILE_API_WIN32
 | 
			
		||||
#else
 | 
			
		||||
#define FILE_API	FILE_API_STDIO
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if FILE_API == FILE_API_STDIO
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#elif FILE_API == FILE_API_POSIX
 | 
			
		||||
#elif FILE_API == FILE_API_WIN32
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#else
 | 
			
		||||
#error Unsupported File API
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
class LowLevelFile
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	LowLevelFile ();
 | 
			
		||||
	~LowLevelFile ();
 | 
			
		||||
 | 
			
		||||
	void open (char const * filename);
 | 
			
		||||
	void close ();
 | 
			
		||||
 | 
			
		||||
	size_t size ();
 | 
			
		||||
 | 
			
		||||
	void seek (size_t Position);
 | 
			
		||||
	size_t tell ();
 | 
			
		||||
 | 
			
		||||
	size_t read (void * data, size_t size);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
#if FILE_API == FILE_API_STDIO
 | 
			
		||||
	FILE* mHandle;
 | 
			
		||||
#elif FILE_API == FILE_API_POSIX
 | 
			
		||||
	int mHandle;
 | 
			
		||||
#elif FILE_API == FILE_API_WIN32
 | 
			
		||||
	HANDLE mHandle;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -43,16 +43,26 @@
 | 
			
		|||
 | 
			
		||||
#include <extern/shiny/Main/Factory.hpp>
 | 
			
		||||
 | 
			
		||||
#include <components/nif/node.hpp>
 | 
			
		||||
#include <components/settings/settings.hpp>
 | 
			
		||||
#include <components/nifoverrides/nifoverrides.hpp>
 | 
			
		||||
 | 
			
		||||
typedef unsigned char ubyte;
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
using namespace Nif;
 | 
			
		||||
using namespace NifOgre;
 | 
			
		||||
namespace std
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
// These operators allow extra data types to be stored in an Ogre::Any
 | 
			
		||||
// object, which can then be stored in user object bindings on the nodes
 | 
			
		||||
 | 
			
		||||
// TODO: Do something useful
 | 
			
		||||
ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&)
 | 
			
		||||
{ return o; }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace NifOgre
 | 
			
		||||
{
 | 
			
		||||
// Helper class that computes the bounding box and of a mesh
 | 
			
		||||
class BoundsFinder
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +72,7 @@ class BoundsFinder
 | 
			
		|||
 | 
			
		||||
        MaxMinFinder()
 | 
			
		||||
        {
 | 
			
		||||
            min = numeric_limits<float>::infinity();
 | 
			
		||||
            min = std::numeric_limits<float>::infinity();
 | 
			
		||||
            max = -min;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -152,8 +162,9 @@ static void fail(const std::string &msg)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void insertTextKeys(const Nif::NiTextKeyExtraData *tk, TextKeyMap *textkeys)
 | 
			
		||||
static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk)
 | 
			
		||||
{
 | 
			
		||||
    TextKeyMap textkeys;
 | 
			
		||||
    for(size_t i = 0;i < tk->list.size();i++)
 | 
			
		||||
    {
 | 
			
		||||
        const std::string &str = tk->list[i].text;
 | 
			
		||||
| 
						 | 
				
			
			@ -166,11 +177,12 @@ static void insertTextKeys(const Nif::NiTextKeyExtraData *tk, TextKeyMap *textke
 | 
			
		|||
                break;
 | 
			
		||||
 | 
			
		||||
            std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos));
 | 
			
		||||
            textkeys->insert(std::make_pair(tk->list[i].time, str.substr(pos, nextpos-pos)));
 | 
			
		||||
            textkeys.insert(std::make_pair(tk->list[i].time, str.substr(pos, nextpos-pos)));
 | 
			
		||||
 | 
			
		||||
            pos = nextpos;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return textkeys;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +209,17 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector<Nif::Ni
 | 
			
		|||
        ctrl = ctrl->next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Nif::ExtraPtr e = node->extra;
 | 
			
		||||
    while(!e.empty())
 | 
			
		||||
    {
 | 
			
		||||
        if(e->recType == Nif::RC_NiTextKeyExtraData)
 | 
			
		||||
        {
 | 
			
		||||
            const Nif::NiTextKeyExtraData *tk = static_cast<const Nif::NiTextKeyExtraData*>(e.getPtr());
 | 
			
		||||
            bone->getUserObjectBindings().setUserAny("TextKeyExtraData", Ogre::Any(extractTextKeys(tk)));
 | 
			
		||||
        }
 | 
			
		||||
        e = e->extra;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
 | 
			
		||||
    if(ninode)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -219,7 +242,7 @@ struct KeyTimeSort
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef std::map<std::string,NIFSkeletonLoader,ciLessBoost> LoaderMap;
 | 
			
		||||
typedef std::map<std::string,NIFSkeletonLoader> LoaderMap;
 | 
			
		||||
static LoaderMap sLoaders;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
| 
						 | 
				
			
			@ -269,16 +292,16 @@ void loadResource(Ogre::Resource *resource)
 | 
			
		|||
        Nif::NiKeyframeData *kf = kfc->data.getPtr();
 | 
			
		||||
 | 
			
		||||
        /* Get the keyframes and make sure they're sorted first to last */
 | 
			
		||||
        QuaternionKeyList quatkeys = kf->mRotations;
 | 
			
		||||
        Vector3KeyList trankeys = kf->mTranslations;
 | 
			
		||||
        FloatKeyList scalekeys = kf->mScales;
 | 
			
		||||
        Nif::QuaternionKeyList quatkeys = kf->mRotations;
 | 
			
		||||
        Nif::Vector3KeyList trankeys = kf->mTranslations;
 | 
			
		||||
        Nif::FloatKeyList scalekeys = kf->mScales;
 | 
			
		||||
        std::sort(quatkeys.mKeys.begin(), quatkeys.mKeys.end(), KeyTimeSort<Ogre::Quaternion>());
 | 
			
		||||
        std::sort(trankeys.mKeys.begin(), trankeys.mKeys.end(), KeyTimeSort<Ogre::Vector3>());
 | 
			
		||||
        std::sort(scalekeys.mKeys.begin(), scalekeys.mKeys.end(), KeyTimeSort<float>());
 | 
			
		||||
 | 
			
		||||
        QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin();
 | 
			
		||||
        Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin();
 | 
			
		||||
        FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin();
 | 
			
		||||
        Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin();
 | 
			
		||||
        Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin();
 | 
			
		||||
        Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin();
 | 
			
		||||
 | 
			
		||||
        Ogre::Bone *bone = skel->getBone(targets[i]);
 | 
			
		||||
        const Ogre::Quaternion startquat = bone->getInitialOrientation();
 | 
			
		||||
| 
						 | 
				
			
			@ -346,7 +369,7 @@ void loadResource(Ogre::Resource *resource)
 | 
			
		|||
                kframe->setRotation(curquat);
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                QuaternionKeyList::VecType::const_iterator last = quatiter-1;
 | 
			
		||||
                Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1;
 | 
			
		||||
                float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime);
 | 
			
		||||
                kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat));
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -354,7 +377,7 @@ void loadResource(Ogre::Resource *resource)
 | 
			
		|||
                kframe->setTranslate(curtrans);
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                Vector3KeyList::VecType::const_iterator last = traniter-1;
 | 
			
		||||
                Nif::Vector3KeyList::VecType::const_iterator last = traniter-1;
 | 
			
		||||
                float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime);
 | 
			
		||||
                kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff));
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -362,7 +385,7 @@ void loadResource(Ogre::Resource *resource)
 | 
			
		|||
                kframe->setScale(curscale);
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                FloatKeyList::VecType::const_iterator last = scaleiter-1;
 | 
			
		||||
                Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1;
 | 
			
		||||
                float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime);
 | 
			
		||||
                kframe->setScale(lastscale + ((curscale-lastscale)*diff));
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -371,35 +394,18 @@ void loadResource(Ogre::Resource *resource)
 | 
			
		|||
    anim->optimise();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool createSkeleton(const std::string &name, const std::string &group, TextKeyMap *textkeys, const Nif::Node *node)
 | 
			
		||||
bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node)
 | 
			
		||||
{
 | 
			
		||||
    if(textkeys)
 | 
			
		||||
    {
 | 
			
		||||
        Nif::ExtraPtr e = node->extra;
 | 
			
		||||
        while(!e.empty())
 | 
			
		||||
        {
 | 
			
		||||
            if(e->recType == Nif::RC_NiTextKeyExtraData)
 | 
			
		||||
            {
 | 
			
		||||
                const Nif::NiTextKeyExtraData *tk = static_cast<const Nif::NiTextKeyExtraData*>(e.getPtr());
 | 
			
		||||
                insertTextKeys(tk, textkeys);
 | 
			
		||||
            }
 | 
			
		||||
            e = e->extra;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(node->boneTrafo != NULL)
 | 
			
		||||
    {
 | 
			
		||||
        Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton();
 | 
			
		||||
 | 
			
		||||
        Ogre::SkeletonPtr skel = skelMgr.getByName(name);
 | 
			
		||||
        if(skel.isNull())
 | 
			
		||||
        {
 | 
			
		||||
            NIFSkeletonLoader *loader = &sLoaders[name];
 | 
			
		||||
            skel = skelMgr.create(name, group, true, loader);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!textkeys || textkeys->size() > 0)
 | 
			
		||||
            return true;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
 | 
			
		||||
| 
						 | 
				
			
			@ -410,7 +416,7 @@ bool createSkeleton(const std::string &name, const std::string &group, TextKeyMa
 | 
			
		|||
        {
 | 
			
		||||
            if(!children[i].empty())
 | 
			
		||||
            {
 | 
			
		||||
                if(createSkeleton(name, group, textkeys, children[i].getPtr()))
 | 
			
		||||
                if(createSkeleton(name, group, children[i].getPtr()))
 | 
			
		||||
                    return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -484,7 +490,7 @@ static void fail(const std::string &msg)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
static Ogre::String getMaterial(const NiTriShape *shape, const Ogre::String &name, const Ogre::String &group)
 | 
			
		||||
static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group)
 | 
			
		||||
{
 | 
			
		||||
    Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton();
 | 
			
		||||
    Ogre::MaterialPtr material = matMgr.getByName(name);
 | 
			
		||||
| 
						 | 
				
			
			@ -504,24 +510,24 @@ static Ogre::String getMaterial(const NiTriShape *shape, const Ogre::String &nam
 | 
			
		|||
    bool vertexColour = (shape->data->colors.size() != 0);
 | 
			
		||||
 | 
			
		||||
    // These are set below if present
 | 
			
		||||
    const NiTexturingProperty *t = NULL;
 | 
			
		||||
    const NiMaterialProperty *m = NULL;
 | 
			
		||||
    const NiAlphaProperty *a = NULL;
 | 
			
		||||
    const Nif::NiTexturingProperty *t = NULL;
 | 
			
		||||
    const Nif::NiMaterialProperty *m = NULL;
 | 
			
		||||
    const Nif::NiAlphaProperty *a = NULL;
 | 
			
		||||
 | 
			
		||||
    // Scan the property list for material information
 | 
			
		||||
    const PropertyList &list = shape->props;
 | 
			
		||||
    const Nif::PropertyList &list = shape->props;
 | 
			
		||||
    for (size_t i = 0;i < list.length();i++)
 | 
			
		||||
    {
 | 
			
		||||
        // Entries may be empty
 | 
			
		||||
        if (list[i].empty()) continue;
 | 
			
		||||
 | 
			
		||||
        const Property *pr = list[i].getPtr();
 | 
			
		||||
        if (pr->recType == RC_NiTexturingProperty)
 | 
			
		||||
            t = static_cast<const NiTexturingProperty*>(pr);
 | 
			
		||||
        else if (pr->recType == RC_NiMaterialProperty)
 | 
			
		||||
            m = static_cast<const NiMaterialProperty*>(pr);
 | 
			
		||||
        else if (pr->recType == RC_NiAlphaProperty)
 | 
			
		||||
            a = static_cast<const NiAlphaProperty*>(pr);
 | 
			
		||||
        const Nif::Property *pr = list[i].getPtr();
 | 
			
		||||
        if (pr->recType == Nif::RC_NiTexturingProperty)
 | 
			
		||||
            t = static_cast<const Nif::NiTexturingProperty*>(pr);
 | 
			
		||||
        else if (pr->recType == Nif::RC_NiMaterialProperty)
 | 
			
		||||
            m = static_cast<const Nif::NiMaterialProperty*>(pr);
 | 
			
		||||
        else if (pr->recType == Nif::RC_NiAlphaProperty)
 | 
			
		||||
            a = static_cast<const Nif::NiAlphaProperty*>(pr);
 | 
			
		||||
        else
 | 
			
		||||
            warn("Skipped property type: "+pr->recName);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -529,18 +535,27 @@ static Ogre::String getMaterial(const NiTriShape *shape, const Ogre::String &nam
 | 
			
		|||
    // Texture
 | 
			
		||||
    if (t && t->textures[0].inUse)
 | 
			
		||||
    {
 | 
			
		||||
        NiSourceTexture *st = t->textures[0].texture.getPtr();
 | 
			
		||||
        Nif::NiSourceTexture *st = t->textures[0].texture.getPtr();
 | 
			
		||||
        if (st->external)
 | 
			
		||||
        {
 | 
			
		||||
            /* Bethesda at some at some point converted all their BSA
 | 
			
		||||
             * textures from tga to dds for increased load speed, but all
 | 
			
		||||
             * texture file name references were kept as .tga.
 | 
			
		||||
             */
 | 
			
		||||
            texName = "textures\\" + st->filename;
 | 
			
		||||
            if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName))
 | 
			
		||||
            static const char path[] = "textures\\";
 | 
			
		||||
 | 
			
		||||
            texName = path + st->filename;
 | 
			
		||||
            Ogre::String::size_type pos = texName.rfind('.');
 | 
			
		||||
            if(pos != Ogre::String::npos && texName.compare(pos, texName.length() - pos, ".dds") != 0)
 | 
			
		||||
            {
 | 
			
		||||
                Ogre::String::size_type pos = texName.rfind('.');
 | 
			
		||||
                // since we know all (GOTY edition or less) textures end
 | 
			
		||||
                // in .dds, we change the extension
 | 
			
		||||
                texName.replace(pos, texName.length(), ".dds");
 | 
			
		||||
 | 
			
		||||
                // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods)
 | 
			
		||||
                // verify, and revert if false (this call succeeds quickly, but fails slowly)
 | 
			
		||||
                if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName))
 | 
			
		||||
                    texName = path + st->filename;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else warn("Found internal texture, ignoring.");
 | 
			
		||||
| 
						 | 
				
			
			@ -918,7 +933,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    typedef std::map<std::string,NIFMeshLoader,ciLessBoost> LoaderMap;
 | 
			
		||||
    typedef std::map<std::string,NIFMeshLoader> LoaderMap;
 | 
			
		||||
    static LoaderMap sLoaders;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
| 
						 | 
				
			
			@ -981,7 +996,7 @@ public:
 | 
			
		|||
 | 
			
		||||
        if(node->recType == Nif::RC_NiTriShape)
 | 
			
		||||
        {
 | 
			
		||||
            const NiTriShape *shape = dynamic_cast<const NiTriShape*>(node);
 | 
			
		||||
            const Nif::NiTriShape *shape = dynamic_cast<const Nif::NiTriShape*>(node);
 | 
			
		||||
 | 
			
		||||
            Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton();
 | 
			
		||||
            std::string fullname = mName+"@shape="+shape->name;
 | 
			
		||||
| 
						 | 
				
			
			@ -1004,7 +1019,7 @@ public:
 | 
			
		|||
                mesh->setAutoBuildEdgeLists(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            meshes.push_back(std::make_pair(mesh, shape->name));
 | 
			
		||||
            meshes.push_back(std::make_pair(mesh->getName(), shape->name));
 | 
			
		||||
        }
 | 
			
		||||
        else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode &&
 | 
			
		||||
                node->recType != Nif::RC_NiRotatingParticles)
 | 
			
		||||
| 
						 | 
				
			
			@ -1025,13 +1040,19 @@ public:
 | 
			
		|||
NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MeshPairList NIFLoader::load(std::string name, std::string skelName, TextKeyMap *textkeys, const std::string &group)
 | 
			
		||||
{
 | 
			
		||||
    MeshPairList meshes;
 | 
			
		||||
typedef std::map<std::string,MeshPairList> MeshPairMap;
 | 
			
		||||
static MeshPairMap sMeshPairMap;
 | 
			
		||||
 | 
			
		||||
MeshPairList NIFLoader::load(std::string name, std::string skelName, const std::string &group)
 | 
			
		||||
{
 | 
			
		||||
    std::transform(name.begin(), name.end(), name.begin(), ::tolower);
 | 
			
		||||
    std::transform(skelName.begin(), skelName.end(), skelName.begin(), ::tolower);
 | 
			
		||||
 | 
			
		||||
    MeshPairMap::const_iterator meshiter = sMeshPairMap.find(name+"@skel="+skelName);
 | 
			
		||||
    if(meshiter != sMeshPairMap.end())
 | 
			
		||||
        return meshiter->second;
 | 
			
		||||
 | 
			
		||||
    MeshPairList &meshes = sMeshPairMap[name+"@skel="+skelName];
 | 
			
		||||
    Nif::NIFFile nif(name);
 | 
			
		||||
    if (nif.numRecords() < 1)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -1052,7 +1073,7 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, TextKeyMap
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    NIFSkeletonLoader skelldr;
 | 
			
		||||
    bool hasSkel = skelldr.createSkeleton(skelName, group, textkeys, node);
 | 
			
		||||
    bool hasSkel = skelldr.createSkeleton(name, group, node);
 | 
			
		||||
 | 
			
		||||
    NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string()));
 | 
			
		||||
    meshldr.createMeshes(node, meshes);
 | 
			
		||||
| 
						 | 
				
			
			@ -1064,19 +1085,37 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke
 | 
			
		|||
{
 | 
			
		||||
    EntityList entitylist;
 | 
			
		||||
 | 
			
		||||
    MeshPairList meshes = load(name, name, textkeys, group);
 | 
			
		||||
    MeshPairList meshes = load(name, name, group);
 | 
			
		||||
    if(meshes.size() == 0)
 | 
			
		||||
        return entitylist;
 | 
			
		||||
 | 
			
		||||
    Ogre::SceneManager *sceneMgr = parent->getCreator();
 | 
			
		||||
    for(size_t i = 0;i < meshes.size();i++)
 | 
			
		||||
    {
 | 
			
		||||
        entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first->getName()));
 | 
			
		||||
        entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first));
 | 
			
		||||
        Ogre::Entity *entity = entitylist.mEntities.back();
 | 
			
		||||
        if(!entitylist.mSkelBase && entity->hasSkeleton())
 | 
			
		||||
            entitylist.mSkelBase = entity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(entitylist.mSkelBase && textkeys)
 | 
			
		||||
    {
 | 
			
		||||
        // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr.
 | 
			
		||||
        Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton();
 | 
			
		||||
        Ogre::SkeletonPtr skel = skelMgr.getByName(entitylist.mSkelBase->getSkeleton()->getName());
 | 
			
		||||
        Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator();
 | 
			
		||||
        while(iter.hasMoreElements())
 | 
			
		||||
        {
 | 
			
		||||
            Ogre::Bone *bone = iter.getNext();
 | 
			
		||||
            const Ogre::Any &data = bone->getUserObjectBindings().getUserAny("TextKeyExtraData");
 | 
			
		||||
            if(!data.isEmpty())
 | 
			
		||||
            {
 | 
			
		||||
                *textkeys = Ogre::any_cast<TextKeyMap>(data);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(entitylist.mSkelBase)
 | 
			
		||||
    {
 | 
			
		||||
        parent->attachObject(entitylist.mSkelBase);
 | 
			
		||||
| 
						 | 
				
			
			@ -1101,13 +1140,6 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke
 | 
			
		|||
    return entitylist;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct checklow {
 | 
			
		||||
    bool operator()(const char &a, const char &b) const
 | 
			
		||||
    {
 | 
			
		||||
        return ::tolower(a) == ::tolower(b);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename,
 | 
			
		||||
                                     Ogre::SceneNode *parentNode,
 | 
			
		||||
                                     const std::string &name,
 | 
			
		||||
| 
						 | 
				
			
			@ -1115,23 +1147,24 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo
 | 
			
		|||
{
 | 
			
		||||
    EntityList entitylist;
 | 
			
		||||
 | 
			
		||||
    MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), NULL, group);
 | 
			
		||||
    MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), group);
 | 
			
		||||
    if(meshes.size() == 0)
 | 
			
		||||
        return entitylist;
 | 
			
		||||
 | 
			
		||||
    Ogre::SceneManager *sceneMgr = parentNode->getCreator();
 | 
			
		||||
    std::string filter = "Tri "+bonename;
 | 
			
		||||
    std::string filter = "tri "+bonename;
 | 
			
		||||
    std::transform(filter.begin()+4, filter.end(), filter.begin()+4, ::tolower);
 | 
			
		||||
    for(size_t i = 0;i < meshes.size();i++)
 | 
			
		||||
    {
 | 
			
		||||
        Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first->getName());
 | 
			
		||||
        Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first);
 | 
			
		||||
        if(ent->hasSkeleton())
 | 
			
		||||
        {
 | 
			
		||||
            std::transform(meshes[i].second.begin(), meshes[i].second.end(), meshes[i].second.begin(), ::tolower);
 | 
			
		||||
 | 
			
		||||
            if(meshes[i].second.length() < filter.length() ||
 | 
			
		||||
               std::mismatch(filter.begin(), filter.end(), meshes[i].second.begin(), checklow()).first != filter.end())
 | 
			
		||||
               meshes[i].second.compare(0, filter.length(), filter) != 0)
 | 
			
		||||
            {
 | 
			
		||||
                sceneMgr->destroyEntity(ent);
 | 
			
		||||
                meshes.erase(meshes.begin()+i);
 | 
			
		||||
                i--;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if(!entitylist.mSkelBase)
 | 
			
		||||
| 
						 | 
				
			
			@ -1216,3 +1249,5 @@ extern "C" void ogre_insertTexture(char* name, uint32_t width, uint32_t height,
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
} // nsmaepace NifOgre
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,23 +30,6 @@
 | 
			
		|||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <boost/algorithm/string.hpp>
 | 
			
		||||
 | 
			
		||||
#include "../nif/node.hpp"
 | 
			
		||||
 | 
			
		||||
#include <libs/platform/strings.h>
 | 
			
		||||
 | 
			
		||||
class BoundsFinder;
 | 
			
		||||
 | 
			
		||||
struct ciLessBoost : std::binary_function<std::string, std::string, bool>
 | 
			
		||||
{
 | 
			
		||||
    bool operator() (const std::string & s1, const std::string & s2) const
 | 
			
		||||
    {
 | 
			
		||||
        //case insensitive version of is_less
 | 
			
		||||
        return boost::algorithm::lexicographical_compare(s1, s2, boost::algorithm::is_iless());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace Nif
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -69,9 +52,8 @@ struct EntityList {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** This holds a list of meshes along with the names of their parent nodes
 | 
			
		||||
 */
 | 
			
		||||
typedef std::vector< std::pair<Ogre::MeshPtr,std::string> > MeshPairList;
 | 
			
		||||
/** This holds a list of mesh names along with the names of their parent nodes */
 | 
			
		||||
typedef std::vector< std::pair<std::string,std::string> > MeshPairList;
 | 
			
		||||
 | 
			
		||||
/** Manual resource loader for NIF meshes. This is the main class
 | 
			
		||||
    responsible for translating the internal NIF mesh structure into
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +69,7 @@ typedef std::vector< std::pair<Ogre::MeshPtr,std::string> > MeshPairList;
 | 
			
		|||
 */
 | 
			
		||||
class NIFLoader
 | 
			
		||||
{
 | 
			
		||||
    static MeshPairList load(std::string name, std::string skelName, TextKeyMap *textkeys, const std::string &group);
 | 
			
		||||
    static MeshPairList load(std::string name, std::string skelName, const std::string &group);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								components/to_utf8/tests/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								components/to_utf8/tests/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
*_test
 | 
			
		||||
							
								
								
									
										4
									
								
								components/to_utf8/tests/output/to_utf8_test.out
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								components/to_utf8/tests/output/to_utf8_test.out
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
original:  Без вопросов отдаете ему рулет, зная, что позже вы сможете привести с собой своих друзей и тогда он получит по заслугам?
 | 
			
		||||
converted: Без вопросов отдаете ему рулет, зная, что позже вы сможете привести с собой своих друзей и тогда он получит по заслугам?
 | 
			
		||||
original:  Vous lui donnez le gâteau sans protester avant d’aller chercher tous vos amis et de revenir vous venger.
 | 
			
		||||
converted: Vous lui donnez le gâteau sans protester avant d’aller chercher tous vos amis et de revenir vous venger.
 | 
			
		||||
							
								
								
									
										18
									
								
								components/to_utf8/tests/test.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										18
									
								
								components/to_utf8/tests/test.sh
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
make || exit
 | 
			
		||||
 | 
			
		||||
mkdir -p output
 | 
			
		||||
 | 
			
		||||
PROGS=*_test
 | 
			
		||||
 | 
			
		||||
for a in $PROGS; do
 | 
			
		||||
    if [ -f "output/$a.out" ]; then
 | 
			
		||||
        echo "Running $a:"
 | 
			
		||||
        ./$a | diff output/$a.out -
 | 
			
		||||
    else
 | 
			
		||||
        echo "Creating $a.out"
 | 
			
		||||
        ./$a > "output/$a.out"
 | 
			
		||||
        git add "output/$a.out"
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
							
								
								
									
										1
									
								
								components/to_utf8/tests/test_data/french-utf8.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								components/to_utf8/tests/test_data/french-utf8.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
Vous lui donnez le gâteau sans protester avant d’aller chercher tous vos amis et de revenir vous venger.
 | 
			
		||||
							
								
								
									
										1
									
								
								components/to_utf8/tests/test_data/french-win1252.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								components/to_utf8/tests/test_data/french-win1252.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
Vous lui donnez le gâteau sans protester avant d’aller chercher tous vos amis et de revenir vous venger.
 | 
			
		||||
							
								
								
									
										1
									
								
								components/to_utf8/tests/test_data/russian-utf8.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								components/to_utf8/tests/test_data/russian-utf8.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
Без вопросов отдаете ему рулет, зная, что позже вы сможете привести с собой своих друзей и тогда он получит по заслугам?
 | 
			
		||||
							
								
								
									
										1
									
								
								components/to_utf8/tests/test_data/russian-win1251.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								components/to_utf8/tests/test_data/russian-win1251.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
Без вопросов отдаете ему рулет, зная, что позже вы сможете привести с собой своих друзей и тогда он получит по заслугам?
 | 
			
		||||
							
								
								
									
										59
									
								
								components/to_utf8/tests/to_utf8_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								components/to_utf8/tests/to_utf8_test.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
#include <iostream>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
#include "../to_utf8.hpp"
 | 
			
		||||
 | 
			
		||||
std::string getFirstLine(const std::string &filename);
 | 
			
		||||
void testEncoder(ToUTF8::FromType encoding, const std::string &legacyEncFile,
 | 
			
		||||
                 const std::string &utf8File);
 | 
			
		||||
 | 
			
		||||
/// Test character encoding conversion to and from UTF-8
 | 
			
		||||
void testEncoder(ToUTF8::FromType encoding, const std::string &legacyEncFile,
 | 
			
		||||
                 const std::string &utf8File)
 | 
			
		||||
{
 | 
			
		||||
    // get some test data
 | 
			
		||||
    std::string legacyEncLine = getFirstLine(legacyEncFile);
 | 
			
		||||
    std::string utf8Line = getFirstLine(utf8File);
 | 
			
		||||
 | 
			
		||||
    // create an encoder for specified character encoding
 | 
			
		||||
    ToUTF8::Utf8Encoder encoder (encoding);
 | 
			
		||||
 | 
			
		||||
    // convert text to UTF-8
 | 
			
		||||
    std::string convertedUtf8Line = encoder.getUtf8(legacyEncLine);
 | 
			
		||||
 | 
			
		||||
    std::cout << "original:  " << utf8Line          << std::endl;
 | 
			
		||||
    std::cout << "converted: " << convertedUtf8Line << std::endl;
 | 
			
		||||
 | 
			
		||||
    // check correctness
 | 
			
		||||
    assert(convertedUtf8Line == utf8Line);
 | 
			
		||||
 | 
			
		||||
    // convert UTF-8 text to legacy encoding
 | 
			
		||||
    std::string convertedLegacyEncLine = encoder.getLegacyEnc(utf8Line);
 | 
			
		||||
    // check correctness
 | 
			
		||||
    assert(convertedLegacyEncLine == legacyEncLine);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string getFirstLine(const std::string &filename)
 | 
			
		||||
{
 | 
			
		||||
    std::string line;
 | 
			
		||||
    std::ifstream text (filename.c_str());
 | 
			
		||||
 | 
			
		||||
    if (!text.is_open())
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error("Unable to open file " + filename);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::getline(text, line);
 | 
			
		||||
    text.close();
 | 
			
		||||
 | 
			
		||||
    return line;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    testEncoder(ToUTF8::WINDOWS_1251, "test_data/russian-win1251.txt", "test_data/russian-utf8.txt");
 | 
			
		||||
    testEncoder(ToUTF8::WINDOWS_1252, "test_data/french-win1252.txt", "test_data/french-utf8.txt");
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,6 +2,8 @@
 | 
			
		|||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
 | 
			
		||||
/* This file contains the code to translate from WINDOWS-1252 (native
 | 
			
		||||
   charset used in English version of Morrowind) to UTF-8. The library
 | 
			
		||||
| 
						 | 
				
			
			@ -39,341 +41,298 @@
 | 
			
		|||
// Generated tables
 | 
			
		||||
#include "tables_gen.hpp"
 | 
			
		||||
 | 
			
		||||
// Shared global buffers, we love you. These initial sizes are large
 | 
			
		||||
// enough to hold the largest books in Morrowind.esm, but we will
 | 
			
		||||
// resize automaticall if necessary.
 | 
			
		||||
static std::vector<char> buf    (50*1024);
 | 
			
		||||
static std::vector<char> output (50*1024);
 | 
			
		||||
static int size;
 | 
			
		||||
using namespace ToUTF8;
 | 
			
		||||
 | 
			
		||||
// Make sure the given vector is large enough for 'size' bytes,
 | 
			
		||||
// including a terminating zero after it.
 | 
			
		||||
static void resize(std::vector<char> &buf, size_t size)
 | 
			
		||||
Utf8Encoder::Utf8Encoder(const FromType sourceEncoding):
 | 
			
		||||
    mOutput(50*1024)
 | 
			
		||||
{
 | 
			
		||||
  if(buf.size() <= size)
 | 
			
		||||
    // Add some extra padding to reduce the chance of having to resize
 | 
			
		||||
    // again later.
 | 
			
		||||
    buf.resize(3*size);
 | 
			
		||||
 | 
			
		||||
  // And make sure the string is zero terminated
 | 
			
		||||
  buf[size] = 0;
 | 
			
		||||
    switch (sourceEncoding)
 | 
			
		||||
    {
 | 
			
		||||
        case ToUTF8::WINDOWS_1252:
 | 
			
		||||
        {
 | 
			
		||||
            translationArray = ToUTF8::windows_1252;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case ToUTF8::WINDOWS_1250:
 | 
			
		||||
        {
 | 
			
		||||
            translationArray = ToUTF8::windows_1250;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case ToUTF8::WINDOWS_1251:
 | 
			
		||||
        {
 | 
			
		||||
            translationArray = ToUTF8::windows_1251;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
        {
 | 
			
		||||
            assert(0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is just used to spew out a reusable input buffer for the
 | 
			
		||||
// conversion process.
 | 
			
		||||
char *ToUTF8::getBuffer(int s)
 | 
			
		||||
std::string Utf8Encoder::getUtf8(const char* input, int size)
 | 
			
		||||
{
 | 
			
		||||
  // Remember the requested size
 | 
			
		||||
  size = s;
 | 
			
		||||
  resize(buf, size);
 | 
			
		||||
  return &buf[0];
 | 
			
		||||
    // Double check that the input string stops at some point (it might
 | 
			
		||||
    // contain zero terminators before this, inside its own data, which
 | 
			
		||||
    // is also ok.)
 | 
			
		||||
    assert(input[size] == 0);
 | 
			
		||||
 | 
			
		||||
    // TODO: The rest of this function is designed for single-character
 | 
			
		||||
    // input encodings only. It also assumes that the input the input
 | 
			
		||||
    // encoding shares its first 128 values (0-127) with ASCII. These
 | 
			
		||||
    // conditions must be checked again if you add more input encodings
 | 
			
		||||
    // later.
 | 
			
		||||
 | 
			
		||||
    // Compute output length, and check for pure ascii input at the same
 | 
			
		||||
    // time.
 | 
			
		||||
    bool ascii;
 | 
			
		||||
    size_t outlen = getLength(input, ascii);
 | 
			
		||||
 | 
			
		||||
    // If we're pure ascii, then don't bother converting anything.
 | 
			
		||||
    if(ascii)
 | 
			
		||||
        return std::string(input, outlen);
 | 
			
		||||
 | 
			
		||||
    // Make sure the output is large enough
 | 
			
		||||
    resize(outlen);
 | 
			
		||||
    char *out = &mOutput[0];
 | 
			
		||||
 | 
			
		||||
    // Translate
 | 
			
		||||
    while (*input)
 | 
			
		||||
        copyFromArray(*(input++), out);
 | 
			
		||||
 | 
			
		||||
    // Make sure that we wrote the correct number of bytes
 | 
			
		||||
    assert((out-&mOutput[0]) == (int)outlen);
 | 
			
		||||
 | 
			
		||||
    // And make extra sure the output is null terminated
 | 
			
		||||
    assert(mOutput.size() > outlen);
 | 
			
		||||
    assert(mOutput[outlen] == 0);
 | 
			
		||||
 | 
			
		||||
    // Return a string
 | 
			
		||||
    return std::string(&mOutput[0], outlen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string Utf8Encoder::getLegacyEnc(const char *input, int size)
 | 
			
		||||
{
 | 
			
		||||
    // Double check that the input string stops at some point (it might
 | 
			
		||||
    // contain zero terminators before this, inside its own data, which
 | 
			
		||||
    // is also ok.)
 | 
			
		||||
    assert(input[size] == 0);
 | 
			
		||||
 | 
			
		||||
    // TODO: The rest of this function is designed for single-character
 | 
			
		||||
    // input encodings only. It also assumes that the input the input
 | 
			
		||||
    // encoding shares its first 128 values (0-127) with ASCII. These
 | 
			
		||||
    // conditions must be checked again if you add more input encodings
 | 
			
		||||
    // later.
 | 
			
		||||
 | 
			
		||||
    // Compute output length, and check for pure ascii input at the same
 | 
			
		||||
    // time.
 | 
			
		||||
    bool ascii;
 | 
			
		||||
    size_t outlen = getLength2(input, ascii);
 | 
			
		||||
 | 
			
		||||
    // If we're pure ascii, then don't bother converting anything.
 | 
			
		||||
    if(ascii)
 | 
			
		||||
        return std::string(input, outlen);
 | 
			
		||||
 | 
			
		||||
    // Make sure the output is large enough
 | 
			
		||||
    resize(outlen);
 | 
			
		||||
    char *out = &mOutput[0];
 | 
			
		||||
 | 
			
		||||
    // Translate
 | 
			
		||||
    while(*input)
 | 
			
		||||
        copyFromArray2(input, out);
 | 
			
		||||
 | 
			
		||||
    // Make sure that we wrote the correct number of bytes
 | 
			
		||||
    assert((out-&mOutput[0]) == (int)outlen);
 | 
			
		||||
 | 
			
		||||
    // And make extra sure the output is null terminated
 | 
			
		||||
    assert(mOutput.size() > outlen);
 | 
			
		||||
    assert(mOutput[outlen] == 0);
 | 
			
		||||
 | 
			
		||||
    // Return a string
 | 
			
		||||
    return std::string(&mOutput[0], outlen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Make sure the output vector is large enough for 'size' bytes,
 | 
			
		||||
// including a terminating zero after it.
 | 
			
		||||
void Utf8Encoder::resize(size_t size)
 | 
			
		||||
{
 | 
			
		||||
    if (mOutput.size() <= size)
 | 
			
		||||
        // Add some extra padding to reduce the chance of having to resize
 | 
			
		||||
        // again later.
 | 
			
		||||
        mOutput.resize(3*size);
 | 
			
		||||
 | 
			
		||||
    // And make sure the string is zero terminated
 | 
			
		||||
    mOutput[size] = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Get the total length length needed to decode the given string with
 | 
			
		||||
    the given translation array. The arrays are encoded with 6 bytes
 | 
			
		||||
    per character, with the first giving the length and the next 5 the
 | 
			
		||||
    actual data.
 | 
			
		||||
  the given translation array. The arrays are encoded with 6 bytes
 | 
			
		||||
  per character, with the first giving the length and the next 5 the
 | 
			
		||||
  actual data.
 | 
			
		||||
 | 
			
		||||
    The function serves a dual purpose for optimization reasons: it
 | 
			
		||||
    checks if the input is pure ascii (all values are <= 127). If this
 | 
			
		||||
    is the case, then the ascii parameter is set to true, and the
 | 
			
		||||
    caller can optimize for this case.
 | 
			
		||||
  The function serves a dual purpose for optimization reasons: it
 | 
			
		||||
  checks if the input is pure ascii (all values are <= 127). If this
 | 
			
		||||
  is the case, then the ascii parameter is set to true, and the
 | 
			
		||||
  caller can optimize for this case.
 | 
			
		||||
 */
 | 
			
		||||
static size_t getLength(const char *arr, const char* input, bool &ascii)
 | 
			
		||||
size_t Utf8Encoder::getLength(const char* input, bool &ascii)
 | 
			
		||||
{
 | 
			
		||||
  ascii = true;
 | 
			
		||||
  size_t len = 0;
 | 
			
		||||
  const char* ptr = input;
 | 
			
		||||
  unsigned char inp = *ptr;
 | 
			
		||||
    ascii = true;
 | 
			
		||||
    size_t len = 0;
 | 
			
		||||
    const char* ptr = input;
 | 
			
		||||
    unsigned char inp = *ptr;
 | 
			
		||||
 | 
			
		||||
  // Do away with the ascii part of the string first (this is almost
 | 
			
		||||
  // always the entire string.)
 | 
			
		||||
  while(inp && inp < 128)
 | 
			
		||||
    inp = *(++ptr);
 | 
			
		||||
  len += (ptr-input);
 | 
			
		||||
    // Do away with the ascii part of the string first (this is almost
 | 
			
		||||
    // always the entire string.)
 | 
			
		||||
    while (inp && inp < 128)
 | 
			
		||||
        inp = *(++ptr);
 | 
			
		||||
    len += (ptr-input);
 | 
			
		||||
 | 
			
		||||
  // If we're not at the null terminator at this point, then there
 | 
			
		||||
  // were some non-ascii characters to deal with. Go to slow-mode for
 | 
			
		||||
  // the rest of the string.
 | 
			
		||||
  if(inp)
 | 
			
		||||
    // If we're not at the null terminator at this point, then there
 | 
			
		||||
    // were some non-ascii characters to deal with. Go to slow-mode for
 | 
			
		||||
    // the rest of the string.
 | 
			
		||||
    if (inp)
 | 
			
		||||
    {
 | 
			
		||||
      ascii = false;
 | 
			
		||||
      while(inp)
 | 
			
		||||
        ascii = false;
 | 
			
		||||
        while (inp)
 | 
			
		||||
        {
 | 
			
		||||
          // Find the translated length of this character in the
 | 
			
		||||
          // lookup table.
 | 
			
		||||
          len += arr[inp*6];
 | 
			
		||||
          inp = *(++ptr);
 | 
			
		||||
            // Find the translated length of this character in the
 | 
			
		||||
            // lookup table.
 | 
			
		||||
            len += translationArray[inp*6];
 | 
			
		||||
            inp = *(++ptr);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  return len;
 | 
			
		||||
    return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Translate one character 'ch' using the translation array 'arr', and
 | 
			
		||||
// advance the output pointer accordingly.
 | 
			
		||||
static void copyFromArray(const char *arr, unsigned char ch, char* &out)
 | 
			
		||||
void Utf8Encoder::copyFromArray(unsigned char ch, char* &out)
 | 
			
		||||
{
 | 
			
		||||
  // Optimize for ASCII values
 | 
			
		||||
  if(ch < 128)
 | 
			
		||||
    // Optimize for ASCII values
 | 
			
		||||
    if (ch < 128)
 | 
			
		||||
    {
 | 
			
		||||
      *(out++) = ch;
 | 
			
		||||
      return;
 | 
			
		||||
        *(out++) = ch;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  const char *in = arr + ch*6;
 | 
			
		||||
  int len = *(in++);
 | 
			
		||||
  for(int i=0; i<len; i++)
 | 
			
		||||
    *(out++) = *(in++);
 | 
			
		||||
    const char *in = translationArray + ch*6;
 | 
			
		||||
    int len = *(in++);
 | 
			
		||||
    for (int i=0; i<len; i++)
 | 
			
		||||
        *(out++) = *(in++);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string ToUTF8::getUtf8(ToUTF8::FromType from)
 | 
			
		||||
size_t Utf8Encoder::getLength2(const char* input, bool &ascii)
 | 
			
		||||
{
 | 
			
		||||
  // Pick translation array
 | 
			
		||||
  const char *arr;
 | 
			
		||||
  switch (from)
 | 
			
		||||
  {
 | 
			
		||||
    case ToUTF8::WINDOWS_1252:
 | 
			
		||||
    ascii = true;
 | 
			
		||||
    size_t len = 0;
 | 
			
		||||
    const char* ptr = input;
 | 
			
		||||
    unsigned char inp = *ptr;
 | 
			
		||||
 | 
			
		||||
    // Do away with the ascii part of the string first (this is almost
 | 
			
		||||
    // always the entire string.)
 | 
			
		||||
    while (inp && inp < 128)
 | 
			
		||||
        inp = *(++ptr);
 | 
			
		||||
    len += (ptr-input);
 | 
			
		||||
 | 
			
		||||
    // If we're not at the null terminator at this point, then there
 | 
			
		||||
    // were some non-ascii characters to deal with. Go to slow-mode for
 | 
			
		||||
    // the rest of the string.
 | 
			
		||||
    if (inp)
 | 
			
		||||
    {
 | 
			
		||||
      arr = ToUTF8::windows_1252;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ToUTF8::WINDOWS_1250:
 | 
			
		||||
    {
 | 
			
		||||
      arr = ToUTF8::windows_1250;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ToUTF8::WINDOWS_1251:
 | 
			
		||||
    {
 | 
			
		||||
      arr = ToUTF8::windows_1251;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
    {
 | 
			
		||||
      assert(0);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Double check that the input string stops at some point (it might
 | 
			
		||||
  // contain zero terminators before this, inside its own data, which
 | 
			
		||||
  // is also ok.)
 | 
			
		||||
  const char* input = &buf[0];
 | 
			
		||||
  assert(input[size] == 0);
 | 
			
		||||
 | 
			
		||||
  // TODO: The rest of this function is designed for single-character
 | 
			
		||||
  // input encodings only. It also assumes that the input the input
 | 
			
		||||
  // encoding shares its first 128 values (0-127) with ASCII. These
 | 
			
		||||
  // conditions must be checked again if you add more input encodings
 | 
			
		||||
  // later.
 | 
			
		||||
 | 
			
		||||
  // Compute output length, and check for pure ascii input at the same
 | 
			
		||||
  // time.
 | 
			
		||||
  bool ascii;
 | 
			
		||||
  size_t outlen = getLength(arr, input, ascii);
 | 
			
		||||
 | 
			
		||||
  // If we're pure ascii, then don't bother converting anything.
 | 
			
		||||
  if(ascii)
 | 
			
		||||
    return std::string(input, outlen);
 | 
			
		||||
 | 
			
		||||
  // Make sure the output is large enough
 | 
			
		||||
  resize(output, outlen);
 | 
			
		||||
  char *out = &output[0];
 | 
			
		||||
 | 
			
		||||
  // Translate
 | 
			
		||||
  while(*input)
 | 
			
		||||
    copyFromArray(arr, *(input++), out);
 | 
			
		||||
 | 
			
		||||
  // Make sure that we wrote the correct number of bytes
 | 
			
		||||
  assert((out-&output[0]) == (int)outlen);
 | 
			
		||||
 | 
			
		||||
  // And make extra sure the output is null terminated
 | 
			
		||||
  assert(output.size() > outlen);
 | 
			
		||||
  assert(output[outlen] == 0);
 | 
			
		||||
 | 
			
		||||
  // Return a string
 | 
			
		||||
  return std::string(&output[0], outlen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t getLength2(const char *arr, const char* input, bool &ascii)
 | 
			
		||||
{
 | 
			
		||||
  ascii = true;
 | 
			
		||||
  size_t len = 0;
 | 
			
		||||
  const char* ptr = input;
 | 
			
		||||
  unsigned char inp = *ptr;
 | 
			
		||||
 | 
			
		||||
  // Do away with the ascii part of the string first (this is almost
 | 
			
		||||
  // always the entire string.)
 | 
			
		||||
  while(inp && inp < 128)
 | 
			
		||||
    inp = *(++ptr);
 | 
			
		||||
  len += (ptr-input);
 | 
			
		||||
 | 
			
		||||
  // If we're not at the null terminator at this point, then there
 | 
			
		||||
  // were some non-ascii characters to deal with. Go to slow-mode for
 | 
			
		||||
  // the rest of the string.
 | 
			
		||||
  if(inp)
 | 
			
		||||
    {
 | 
			
		||||
      ascii = false;
 | 
			
		||||
      while(inp)
 | 
			
		||||
        ascii = false;
 | 
			
		||||
        while(inp)
 | 
			
		||||
        {
 | 
			
		||||
            len += 1;
 | 
			
		||||
          // Find the translated length of this character in the
 | 
			
		||||
          // lookup table.
 | 
			
		||||
            // Find the translated length of this character in the
 | 
			
		||||
            // lookup table.
 | 
			
		||||
            switch(inp)
 | 
			
		||||
            {
 | 
			
		||||
            case 0xe2: len -= 2; break;
 | 
			
		||||
            case 0xc2:
 | 
			
		||||
            case 0xcb:
 | 
			
		||||
            case 0xc4:
 | 
			
		||||
            case 0xc6:
 | 
			
		||||
            case 0xc3:
 | 
			
		||||
            case 0xd0:
 | 
			
		||||
            case 0xd1:
 | 
			
		||||
            case 0xd2:
 | 
			
		||||
            case 0xc5: len -= 1; break;
 | 
			
		||||
                case 0xe2: len -= 2; break;
 | 
			
		||||
                case 0xc2:
 | 
			
		||||
                case 0xcb:
 | 
			
		||||
                case 0xc4:
 | 
			
		||||
                case 0xc6:
 | 
			
		||||
                case 0xc3:
 | 
			
		||||
                case 0xd0:
 | 
			
		||||
                case 0xd1:
 | 
			
		||||
                case 0xd2:
 | 
			
		||||
                case 0xc5: len -= 1; break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          inp = *(++ptr);
 | 
			
		||||
            inp = *(++ptr);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  return len;
 | 
			
		||||
    return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
 | 
			
		||||
static void copyFromArray2(const char *arr, char*& chp, char* &out)
 | 
			
		||||
void Utf8Encoder::copyFromArray2(const char*& chp, char* &out)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char ch = *(chp++);
 | 
			
		||||
  // Optimize for ASCII values
 | 
			
		||||
  if(ch < 128)
 | 
			
		||||
    // Optimize for ASCII values
 | 
			
		||||
    if (ch < 128)
 | 
			
		||||
    {
 | 
			
		||||
      *(out++) = ch;
 | 
			
		||||
      return;
 | 
			
		||||
        *(out++) = ch;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  int len = 1;
 | 
			
		||||
  switch (ch)
 | 
			
		||||
  {
 | 
			
		||||
  case 0xe2: len = 3; break;
 | 
			
		||||
  case 0xc2:
 | 
			
		||||
  case 0xcb:
 | 
			
		||||
  case 0xc4:
 | 
			
		||||
  case 0xc6:
 | 
			
		||||
  case 0xc3:
 | 
			
		||||
  case 0xd0:
 | 
			
		||||
  case 0xd1:
 | 
			
		||||
  case 0xd2:
 | 
			
		||||
  case 0xc5: len = 2; break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (len == 1) // There is no 1 length utf-8 glyph that is not 0x20 (empty space)
 | 
			
		||||
  {
 | 
			
		||||
      *(out++) = ch;
 | 
			
		||||
      return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unsigned char ch2 = *(chp++);
 | 
			
		||||
  unsigned char ch3 = '\0';
 | 
			
		||||
  if (len == 3)
 | 
			
		||||
      ch3 = *(chp++);
 | 
			
		||||
 | 
			
		||||
  for (int i = 128; i < 256; i++)
 | 
			
		||||
  {
 | 
			
		||||
      unsigned char b1 = arr[i*6 + 1], b2 = arr[i*6 + 2], b3 = arr[i*6 + 3];
 | 
			
		||||
      if (b1 == ch && b2 == ch2 && (len != 3 || b3 == ch3))
 | 
			
		||||
      {
 | 
			
		||||
          *(out++) = (char)i;
 | 
			
		||||
          return;
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::cout << "Could not find glyph " << std::hex << (int)ch << " " << (int)ch2 << " " << (int)ch3 << std::endl;
 | 
			
		||||
 | 
			
		||||
  *(out++) = ch; // Could not find glyph, just put whatever
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string ToUTF8::getLegacyEnc(ToUTF8::FromType to)
 | 
			
		||||
{
 | 
			
		||||
  // Pick translation array
 | 
			
		||||
  const char *arr;
 | 
			
		||||
  switch (to)
 | 
			
		||||
  {
 | 
			
		||||
    case ToUTF8::WINDOWS_1252:
 | 
			
		||||
    int len = 1;
 | 
			
		||||
    switch (ch)
 | 
			
		||||
    {
 | 
			
		||||
      arr = ToUTF8::windows_1252;
 | 
			
		||||
      break;
 | 
			
		||||
        case 0xe2: len = 3; break;
 | 
			
		||||
        case 0xc2:
 | 
			
		||||
        case 0xcb:
 | 
			
		||||
        case 0xc4:
 | 
			
		||||
        case 0xc6:
 | 
			
		||||
        case 0xc3:
 | 
			
		||||
        case 0xd0:
 | 
			
		||||
        case 0xd1:
 | 
			
		||||
        case 0xd2:
 | 
			
		||||
        case 0xc5: len = 2; break;
 | 
			
		||||
    }
 | 
			
		||||
    case ToUTF8::WINDOWS_1250:
 | 
			
		||||
 | 
			
		||||
    if (len == 1) // There is no 1 length utf-8 glyph that is not 0x20 (empty space)
 | 
			
		||||
    {
 | 
			
		||||
      arr = ToUTF8::windows_1250;
 | 
			
		||||
      break;
 | 
			
		||||
        *(out++) = ch;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    case ToUTF8::WINDOWS_1251:
 | 
			
		||||
 | 
			
		||||
    unsigned char ch2 = *(chp++);
 | 
			
		||||
    unsigned char ch3 = '\0';
 | 
			
		||||
    if (len == 3)
 | 
			
		||||
        ch3 = *(chp++);
 | 
			
		||||
 | 
			
		||||
    for (int i = 128; i < 256; i++)
 | 
			
		||||
    {
 | 
			
		||||
      arr = ToUTF8::windows_1251;
 | 
			
		||||
      break;
 | 
			
		||||
        unsigned char b1 = translationArray[i*6 + 1], b2 = translationArray[i*6 + 2], b3 = translationArray[i*6 + 3];
 | 
			
		||||
        if (b1 == ch && b2 == ch2 && (len != 3 || b3 == ch3))
 | 
			
		||||
        {
 | 
			
		||||
            *(out++) = (char)i;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
    {
 | 
			
		||||
      assert(0);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Double check that the input string stops at some point (it might
 | 
			
		||||
  // contain zero terminators before this, inside its own data, which
 | 
			
		||||
  // is also ok.)
 | 
			
		||||
  char* input = &buf[0];
 | 
			
		||||
  assert(input[size] == 0);
 | 
			
		||||
    std::cout << "Could not find glyph " << std::hex << (int)ch << " " << (int)ch2 << " " << (int)ch3 << std::endl;
 | 
			
		||||
 | 
			
		||||
  // TODO: The rest of this function is designed for single-character
 | 
			
		||||
  // input encodings only. It also assumes that the input the input
 | 
			
		||||
  // encoding shares its first 128 values (0-127) with ASCII. These
 | 
			
		||||
  // conditions must be checked again if you add more input encodings
 | 
			
		||||
  // later.
 | 
			
		||||
 | 
			
		||||
  // Compute output length, and check for pure ascii input at the same
 | 
			
		||||
  // time.
 | 
			
		||||
  bool ascii;
 | 
			
		||||
  size_t outlen = getLength2(arr, input, ascii);
 | 
			
		||||
 | 
			
		||||
  // If we're pure ascii, then don't bother converting anything.
 | 
			
		||||
  if(ascii)
 | 
			
		||||
      return std::string(input, outlen);
 | 
			
		||||
 | 
			
		||||
  // Make sure the output is large enough
 | 
			
		||||
  resize(output, outlen);
 | 
			
		||||
  char *out = &output[0];
 | 
			
		||||
 | 
			
		||||
  // Translate
 | 
			
		||||
  while(*input)
 | 
			
		||||
    copyFromArray2(arr, input, out);
 | 
			
		||||
 | 
			
		||||
  // Make sure that we wrote the correct number of bytes
 | 
			
		||||
  assert((out-&output[0]) == (int)outlen);
 | 
			
		||||
 | 
			
		||||
  // And make extra sure the output is null terminated
 | 
			
		||||
  assert(output.size() > outlen);
 | 
			
		||||
  assert(output[outlen] == 0);
 | 
			
		||||
 | 
			
		||||
  // Return a string
 | 
			
		||||
  return std::string(&output[0], outlen);
 | 
			
		||||
    *(out++) = ch; // Could not find glyph, just put whatever
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ToUTF8::FromType ToUTF8::calculateEncoding(const std::string& encodingName)
 | 
			
		||||
{
 | 
			
		||||
  if (encodingName == "win1250")
 | 
			
		||||
    return ToUTF8::WINDOWS_1250;
 | 
			
		||||
  else if (encodingName == "win1251")
 | 
			
		||||
    return ToUTF8::WINDOWS_1251;
 | 
			
		||||
  else
 | 
			
		||||
    return ToUTF8::WINDOWS_1252;
 | 
			
		||||
    if (encodingName == "win1250")
 | 
			
		||||
        return ToUTF8::WINDOWS_1250;
 | 
			
		||||
    else if (encodingName == "win1251")
 | 
			
		||||
        return ToUTF8::WINDOWS_1251;
 | 
			
		||||
    else
 | 
			
		||||
        return ToUTF8::WINDOWS_1252;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string ToUTF8::encodingUsingMessage(const std::string& encodingName)
 | 
			
		||||
{
 | 
			
		||||
  if (encodingName == "win1250")
 | 
			
		||||
    return "Using Central and Eastern European font encoding.";
 | 
			
		||||
  else if (encodingName == "win1251")
 | 
			
		||||
    return "Using Cyrillic font encoding.";
 | 
			
		||||
  else
 | 
			
		||||
    return "Using default (English) font encoding.";
 | 
			
		||||
    if (encodingName == "win1250")
 | 
			
		||||
        return "Using Central and Eastern European font encoding.";
 | 
			
		||||
    else if (encodingName == "win1251")
 | 
			
		||||
        return "Using Cyrillic font encoding.";
 | 
			
		||||
    else
 | 
			
		||||
        return "Using default (English) font encoding.";
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,29 +2,53 @@
 | 
			
		|||
#define COMPONENTS_TOUTF8_H
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace ToUTF8
 | 
			
		||||
{
 | 
			
		||||
  // These are all the currently supported code pages
 | 
			
		||||
  enum FromType
 | 
			
		||||
    // These are all the currently supported code pages
 | 
			
		||||
    enum FromType
 | 
			
		||||
    {
 | 
			
		||||
      WINDOWS_1250,      // Central ane Eastern European languages
 | 
			
		||||
      WINDOWS_1251,      // Cyrillic languages
 | 
			
		||||
      WINDOWS_1252       // Used by English version of Morrowind (and
 | 
			
		||||
                         // probably others)
 | 
			
		||||
        WINDOWS_1250,      // Central ane Eastern European languages
 | 
			
		||||
        WINDOWS_1251,      // Cyrillic languages
 | 
			
		||||
        WINDOWS_1252       // Used by English version of Morrowind (and
 | 
			
		||||
            // probably others)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
  // Return a writable buffer of at least 'size' bytes. The buffer
 | 
			
		||||
  // does not have to be freed.
 | 
			
		||||
  char* getBuffer(int size);
 | 
			
		||||
    FromType calculateEncoding(const std::string& encodingName);
 | 
			
		||||
    std::string encodingUsingMessage(const std::string& encodingName);
 | 
			
		||||
 | 
			
		||||
  // Convert the previously written buffer to UTF8 from the given code
 | 
			
		||||
  // page.
 | 
			
		||||
  std::string getUtf8(FromType from);
 | 
			
		||||
  std::string getLegacyEnc(FromType to);
 | 
			
		||||
    // class
 | 
			
		||||
 | 
			
		||||
  FromType calculateEncoding(const std::string& encodingName);
 | 
			
		||||
  std::string encodingUsingMessage(const std::string& encodingName);
 | 
			
		||||
    class Utf8Encoder
 | 
			
		||||
    {
 | 
			
		||||
        public:
 | 
			
		||||
            Utf8Encoder(FromType sourceEncoding);
 | 
			
		||||
 | 
			
		||||
            // Convert to UTF8 from the previously given code page.
 | 
			
		||||
            std::string getUtf8(const char *input, int size);
 | 
			
		||||
            inline std::string getUtf8(const std::string &str)
 | 
			
		||||
            {
 | 
			
		||||
                return getUtf8(str.c_str(), str.size());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            std::string getLegacyEnc(const char *input, int size);
 | 
			
		||||
            inline std::string getLegacyEnc(const std::string &str)
 | 
			
		||||
            {
 | 
			
		||||
                return getLegacyEnc(str.c_str(), str.size());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
            void resize(size_t size);
 | 
			
		||||
            size_t getLength(const char* input, bool &ascii);
 | 
			
		||||
            void copyFromArray(unsigned char chp, char* &out);
 | 
			
		||||
            size_t getLength2(const char* input, bool &ascii);
 | 
			
		||||
            void copyFromArray2(const char*& chp, char* &out);
 | 
			
		||||
 | 
			
		||||
            std::vector<char> mOutput;
 | 
			
		||||
            char* translationArray;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ namespace Translation
 | 
			
		|||
        {
 | 
			
		||||
            std::string path = dataFileCollections.getCollection (extension).getPath (fileName).string();
 | 
			
		||||
 | 
			
		||||
            std::ifstream stream (path);
 | 
			
		||||
            std::ifstream stream (path.c_str());
 | 
			
		||||
 | 
			
		||||
            if (!stream.is_open())
 | 
			
		||||
                throw std::runtime_error ("failed to open translation file: " + fileName);
 | 
			
		||||
| 
						 | 
				
			
			@ -50,10 +50,7 @@ namespace Translation
 | 
			
		|||
 | 
			
		||||
            if (!line.empty())
 | 
			
		||||
            {
 | 
			
		||||
                char* buffer = ToUTF8::getBuffer(line.size() + 1);
 | 
			
		||||
                //buffer has at least line.size() + 1 bytes, so it must be safe
 | 
			
		||||
                strcpy(buffer, line.c_str());
 | 
			
		||||
                line = ToUTF8::getUtf8(mEncoding);
 | 
			
		||||
                line = mEncoder->getUtf8(line);
 | 
			
		||||
 | 
			
		||||
                size_t tab_pos = line.find('\t');
 | 
			
		||||
                if (tab_pos != std::string::npos && tab_pos > 0 && tab_pos < line.size() - 1)
 | 
			
		||||
| 
						 | 
				
			
			@ -104,9 +101,9 @@ namespace Translation
 | 
			
		|||
            return phrase;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Storage::setEncoding (const ToUTF8::FromType& encoding)
 | 
			
		||||
    void Storage::setEncoder(ToUTF8::Utf8Encoder* encoder)
 | 
			
		||||
    {
 | 
			
		||||
        mEncoding = encoding;
 | 
			
		||||
        mEncoder = encoder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool Storage::hasTranslation() const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ namespace Translation
 | 
			
		|||
        // Standard form usually means nominative case
 | 
			
		||||
        std::string topicStandardForm(const std::string& phrase) const;
 | 
			
		||||
 | 
			
		||||
        void setEncoding (const ToUTF8::FromType& encoding);
 | 
			
		||||
        void setEncoder(ToUTF8::Utf8Encoder* encoder);
 | 
			
		||||
 | 
			
		||||
        bool hasTranslation() const;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ namespace Translation
 | 
			
		|||
        void loadDataFromStream(ContainerType& container, std::istream& stream);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        ToUTF8::FromType mEncoding;
 | 
			
		||||
        ToUTF8::Utf8Encoder* mEncoder;
 | 
			
		||||
        ContainerType mCellNamesTranslations, mTopicIDs, mPhraseForms;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,7 +72,7 @@ compositor gbufferFinalizer
 | 
			
		|||
            pass render_scene
 | 
			
		||||
            {
 | 
			
		||||
                first_render_queue 51
 | 
			
		||||
                last_render_queue 100
 | 
			
		||||
                last_render_queue 105
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        target_output
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,19 @@
 | 
			
		|||
 | 
			
		||||
using namespace OEngine::GUI;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  As of MyGUI 3.2.0, MyGUI::OgreDataManager::isDataExist is unnecessarily complex
 | 
			
		||||
 *  this override fixes the resulting performance issue.
 | 
			
		||||
 */
 | 
			
		||||
class FixedOgreDataManager : public MyGUI::OgreDataManager
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    bool isDataExist(const std::string& _name)
 | 
			
		||||
    {
 | 
			
		||||
        return Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup (_name);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging, const std::string& logDir)
 | 
			
		||||
{
 | 
			
		||||
    assert(wnd);
 | 
			
		||||
| 
						 | 
				
			
			@ -25,11 +38,18 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool
 | 
			
		|||
    if(!logDir.empty())
 | 
			
		||||
        theLogFile.insert(0, logDir);
 | 
			
		||||
 | 
			
		||||
    // Set up OGRE platform. We might make this more generic later.
 | 
			
		||||
    mPlatform = new OgrePlatform();
 | 
			
		||||
    LogManager::getInstance().setSTDOutputEnabled(logging);
 | 
			
		||||
    mPlatform->initialise(wnd, mgr, "General", theLogFile);
 | 
			
		||||
    // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later.
 | 
			
		||||
    mLogManager = new LogManager();
 | 
			
		||||
    mRenderManager = new OgreRenderManager();
 | 
			
		||||
    mDataManager = new FixedOgreDataManager();
 | 
			
		||||
 | 
			
		||||
    LogManager::getInstance().setSTDOutputEnabled(logging);
 | 
			
		||||
 | 
			
		||||
    if (!theLogFile.empty())
 | 
			
		||||
        LogManager::getInstance().createDefaultSource(theLogFile);
 | 
			
		||||
 | 
			
		||||
    mRenderManager->initialise(wnd, mgr);
 | 
			
		||||
    mDataManager->initialise("General");
 | 
			
		||||
 | 
			
		||||
    // Create GUI
 | 
			
		||||
    mGui = new Gui();
 | 
			
		||||
| 
						 | 
				
			
			@ -40,11 +60,22 @@ void MyGUIManager::shutdown()
 | 
			
		|||
{
 | 
			
		||||
    mGui->shutdown ();
 | 
			
		||||
    delete mGui;
 | 
			
		||||
    if(mPlatform)
 | 
			
		||||
    if(mRenderManager)
 | 
			
		||||
    {
 | 
			
		||||
        mPlatform->shutdown();
 | 
			
		||||
        delete mPlatform;
 | 
			
		||||
        mRenderManager->shutdown();
 | 
			
		||||
        delete mRenderManager;
 | 
			
		||||
        mRenderManager = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if(mDataManager)
 | 
			
		||||
    {
 | 
			
		||||
        mDataManager->shutdown();
 | 
			
		||||
        delete mDataManager;
 | 
			
		||||
        mDataManager = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (mLogManager)
 | 
			
		||||
    {
 | 
			
		||||
        delete mLogManager;
 | 
			
		||||
        mLogManager = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    mGui = NULL;
 | 
			
		||||
    mPlatform = NULL;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,10 @@
 | 
			
		|||
 | 
			
		||||
namespace MyGUI
 | 
			
		||||
{
 | 
			
		||||
  class OgrePlatform;
 | 
			
		||||
  class Gui;
 | 
			
		||||
  class LogManager;
 | 
			
		||||
  class OgreDataManager;
 | 
			
		||||
  class OgreRenderManager;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Ogre
 | 
			
		||||
| 
						 | 
				
			
			@ -18,12 +20,15 @@ namespace GUI
 | 
			
		|||
{
 | 
			
		||||
    class MyGUIManager
 | 
			
		||||
    {
 | 
			
		||||
        MyGUI::OgrePlatform *mPlatform;
 | 
			
		||||
        MyGUI::Gui *mGui;
 | 
			
		||||
        MyGUI::LogManager* mLogManager;
 | 
			
		||||
        MyGUI::OgreDataManager* mDataManager;
 | 
			
		||||
        MyGUI::OgreRenderManager* mRenderManager;
 | 
			
		||||
        Ogre::SceneManager* mSceneMgr;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        MyGUIManager() : mPlatform(NULL), mGui(NULL) {}
 | 
			
		||||
        MyGUIManager() : mLogManager(NULL), mDataManager(NULL), mRenderManager(NULL),  mGui(NULL) {}
 | 
			
		||||
        MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string(""))
 | 
			
		||||
        {
 | 
			
		||||
            setup(wnd,mgr,logging, logDir);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,8 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest
 | 
			
		|||
{
 | 
			
		||||
    Root* root = Ogre::Root::getSingletonPtr();
 | 
			
		||||
 | 
			
		||||
    std::string destImageRot = std::string(destImage) + std::string("_rot");
 | 
			
		||||
 | 
			
		||||
    SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC);
 | 
			
		||||
    Camera* camera = sceneMgr->createCamera("ImageRotateCamera");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -48,8 +50,8 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest
 | 
			
		|||
    unsigned int width = sourceTexture->getWidth();
 | 
			
		||||
    unsigned int height = sourceTexture->getHeight();
 | 
			
		||||
 | 
			
		||||
    TexturePtr destTexture = TextureManager::getSingleton().createManual(
 | 
			
		||||
                    destImage,
 | 
			
		||||
    TexturePtr destTextureRot = TextureManager::getSingleton().createManual(
 | 
			
		||||
                    destImageRot,
 | 
			
		||||
                    ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
 | 
			
		||||
                    TEX_TYPE_2D,
 | 
			
		||||
                    width, height,
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +59,7 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest
 | 
			
		|||
                    PF_FLOAT16_RGBA,
 | 
			
		||||
                    TU_RENDERTARGET);
 | 
			
		||||
 | 
			
		||||
    RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget();
 | 
			
		||||
    RenderTarget* rtt = destTextureRot->getBuffer()->getRenderTarget();
 | 
			
		||||
    rtt->setAutoUpdated(false);
 | 
			
		||||
    Viewport* vp = rtt->addViewport(camera);
 | 
			
		||||
    vp->setOverlaysEnabled(false);
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +68,20 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest
 | 
			
		|||
 | 
			
		||||
    rtt->update();
 | 
			
		||||
 | 
			
		||||
    //copy the rotated image to a static texture
 | 
			
		||||
    TexturePtr destTexture = TextureManager::getSingleton().createManual(
 | 
			
		||||
            destImage,
 | 
			
		||||
            ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
 | 
			
		||||
            TEX_TYPE_2D,
 | 
			
		||||
            width, height,
 | 
			
		||||
            0,
 | 
			
		||||
            PF_FLOAT16_RGBA,
 | 
			
		||||
            Ogre::TU_STATIC);
 | 
			
		||||
 | 
			
		||||
    destTexture->getBuffer()->blit(destTextureRot->getBuffer());
 | 
			
		||||
 | 
			
		||||
    // remove all the junk we've created
 | 
			
		||||
    TextureManager::getSingleton().remove(destImageRot);
 | 
			
		||||
    MaterialManager::getSingleton().remove("ImageRotateMaterial");
 | 
			
		||||
    root->destroySceneManager(sceneMgr);
 | 
			
		||||
    delete rect;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -226,7 +226,7 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings&
 | 
			
		|||
                    1, 1,
 | 
			
		||||
                    0,
 | 
			
		||||
                    Ogre::PF_A8R8G8B8,
 | 
			
		||||
                    Ogre::TU_DYNAMIC_WRITE_ONLY);
 | 
			
		||||
                    Ogre::TU_WRITE_ONLY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OgreRenderer::createScene(const std::string& camName, float fov, float nearClip)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue