diff --git a/.gitignore b/.gitignore index 774478e2b..b17b5a584 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ build *~ Doxygen -prebuilt \ No newline at end of file +prebuilt +apps/openmw/config.hpp +Docs/mainpage.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e6e9bb80b..cbfb24837 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,18 @@ IF (APPLE) set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.6.sdk") ENDIF (APPLE) +# Version + +set (OPENMW_VERSION_MAJOR 0) +set (OPENMW_VERSION_MINOR 12) +set (OPENMW_VERSION_RELEASE 0) + +set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") + +# doxygen main page + +configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp") + # Sound source selection option(USE_AUDIERE "use Audiere for sound" OFF) option(USE_FFMPEG "use ffmpeg for sound" OFF) @@ -58,7 +70,7 @@ IF(EXISTS "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd/ogre_1_7_1") set(AUDIERE_LIBRARY "${PREBUILT_DIR}/audiere-1.9.4/lib/audiere.lib") set(ENV{OPENALDIR} "${PREBUILT_DIR}/OpenAL 1.1 SDK") - + set(BULLET_ROOT "${PREBUILT_DIR}/bullet") ELSE() message (STATUS "OpenMW pre-built binaries not found. Using standard locations.") @@ -436,8 +448,7 @@ if(DPKG_PROGRAM) exec_program("git" ARGS "config --get user.email" OUTPUT_VARIABLE GIT_EMAIL) set(PACKAGE_MAINTAINER "${GIT_NAME} <${GIT_EMAIL}>") else() - #FIXME this should probably be read from some file like ${CMAKE_CURRENT_SOURCE_DIR}/VERSION or something that gets updated when changing version - set(VERSION_STRING "0.10.0") + set(VERSION_STRING "${OPENMW_VERSION}") set(PACKAGE_MAINTAINER "unknown") endif() diff --git a/Docs/Doxyfile b/Docs/Doxyfile index 0a1e0eae8..43c3312ad 100644 --- a/Docs/Doxyfile +++ b/Docs/Doxyfile @@ -576,6 +576,7 @@ WARN_LOGFILE = INPUT = apps \ components \ libs \ + Docs # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is diff --git a/Docs/DoxyfilePages b/Docs/DoxyfilePages index 943e2eef0..5ce82a7c2 100644 --- a/Docs/DoxyfilePages +++ b/Docs/DoxyfilePages @@ -576,6 +576,7 @@ WARN_LOGFILE = INPUT = apps \ components \ libs \ + Docs # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is diff --git a/Docs/mainpage.hpp.cmake b/Docs/mainpage.hpp.cmake new file mode 100644 index 000000000..f8cdf8a82 --- /dev/null +++ b/Docs/mainpage.hpp.cmake @@ -0,0 +1,5 @@ +/// \mainpage +/// +/// This is the source documentation for: +/// +/// OpenMW @OPENMW_VERSION@ diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b20693417..f8b4d7a59 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -1,5 +1,9 @@ project(OpenMW) +# config file + +configure_file ("${OpenMW_SOURCE_DIR}/config.hpp.cmake" "${OpenMW_SOURCE_DIR}/config.hpp") + # local files set(GAME @@ -7,7 +11,8 @@ set(GAME engine.cpp ) set(GAME_HEADER - engine.hpp) + engine.hpp + config.hpp) source_group(game FILES ${GAME} ${GAME_HEADER}) set(GAMEREND @@ -50,6 +55,7 @@ set(GAMEGUI_HEADER mwgui/dialogue_history.hpp mwgui/window_base.hpp mwgui/stats_window.hpp + mwgui/messagebox.hpp ) set(GAMEGUI mwgui/window_manager.cpp @@ -65,6 +71,7 @@ set(GAMEGUI mwgui/dialogue_history.cpp mwgui/window_base.cpp mwgui/stats_window.cpp + mwgui/messagebox.cpp ) source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI}) diff --git a/apps/openmw/config.hpp.cmake b/apps/openmw/config.hpp.cmake new file mode 100644 index 000000000..848fbe0eb --- /dev/null +++ b/apps/openmw/config.hpp.cmake @@ -0,0 +1,9 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define OPENMW_VERSION_MAJOR @OPENMW_VERSION_MAJOR@ +#define OPENMW_VERSION_MINOR @OPENMW_VERSION_MINOR@ +#define OPENMW_VERSION_RELEASE @OPENMW_VERSION_RELEASE@ +#define OPENMW_VERSION "@OPENMW_VERSION@" + +#endif diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0d688a9f6..d70631cf8 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "components/esm/records.hpp" #include @@ -88,6 +89,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) std::string effect; MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell(); + + //If the region has changed if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10){ timer.restart(); @@ -149,6 +152,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { mEnvironment.mFrameDuration = evt.timeSinceLastFrame; + // + mEnvironment.mWindowManager->onFrame(mEnvironment.mFrameDuration); + // global scripts mEnvironment.mGlobalScripts->run (mEnvironment); @@ -244,6 +250,10 @@ void OMW::Engine::loadBSA() std::cout << "Adding " << iter->second.string() << std::endl; Bsa::addBSA (iter->second.string()); } + + std::string m = mDataDir.string(); + std::cout << "Data dir" << m << "\n"; + Bsa::addDir(m, mFSStrict); } // add resources directory @@ -341,9 +351,6 @@ void OMW::Engine::go() mOgre.configure(!Misc::isFile(ogreCfg.c_str()), cfgUserDir, plugCfg, false); - addResourcesDirectory (mDataDir / "Meshes"); - addResourcesDirectory (mDataDir / "Textures"); - // This has to be added BEFORE MyGUI is initialized, as it needs // to find core.xml here. addResourcesDirectory(mResDir / "mygui"); @@ -359,7 +366,7 @@ void OMW::Engine::go() // Create the world mEnvironment.mWorld = new MWWorld::World (mOgre, mPhysicEngine, mFileCollections, mMaster, - mResDir, mNewGame, mEnvironment); + mResDir, mNewGame, mEnvironment, mEncoding); // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mOgre.getWindow(), mOgre.getScene(), false, cfgDir); @@ -380,7 +387,7 @@ void OMW::Engine::go() mOgre.getCamera(), mEnvironment.mWorld->getStore(), (mDataDir), - mUseSound); + mUseSound, mFSStrict); // Create script system mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full, @@ -508,3 +515,8 @@ void OMW::Engine::setCompileAll (bool all) { mCompileAll = all; } + +void OMW::Engine::setEncoding(const std::string& encoding) +{ + mEncoding = encoding; +} \ No newline at end of file diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 4c70d7f35..9d1466655 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -56,6 +56,7 @@ namespace OMW class Engine : private Ogre::FrameListener { + std::string mEncoding; boost::filesystem::path mDataDir; boost::filesystem::path mResDir; OEngine::Render::OgreRenderer mOgre; @@ -157,6 +158,9 @@ namespace OMW /// Compile all scripts (excludign dialogue scripts) at startup? void setCompileAll (bool all); + + /// Font encoding + void setEncoding(const std::string& encoding); }; } diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 4df511173..ed85f4beb 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -31,6 +31,8 @@ #include #endif +#include "config.hpp" + using namespace std; /// Parse command line options and openmw.cfg file (if one exists). Results are directly @@ -46,7 +48,8 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) "Syntax: openmw \nAllowed options"); desc.add_options() - ("help", "print help message") + ("help", "print help message and quit") + ("version", "print version information and quit") ("data", bpo::value >() ->default_value (std::vector(), "data") ->multitoken(), @@ -82,6 +85,13 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) ( "fs-strict", boost::program_options::value()-> implicit_value (true)->default_value (false), "strict file system handling (no case folding)") + + ( "encoding", boost::program_options::value()-> + default_value("win1252"), + "Character encoding used in OpenMW game messages:\n" + "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" + "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" + "\n\twin1252 - Western European (Latin) alphabet, used by default") ; bpo::variables_map variables; @@ -110,10 +120,39 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) if (globalConfigFile.is_open()) bpo::store ( bpo::parse_config_file (globalConfigFile, desc), variables); + bool run = true; + if (variables.count ("help")) { std::cout << desc << std::endl; + run = false; + } + + if (variables.count ("version")) + { + std::cout << "OpenMW version " << OPENMW_VERSION << std::endl; + run = false; + } + + if (!run) return false; + + // Font encoding settings + std::string encoding(variables["encoding"].as()); + if (encoding == "win1250") + { + std::cout << "Using Central and Eastern European font encoding." << std::endl; + engine.setEncoding(encoding); + } + else if (encoding == "win1251") + { + std::cout << "Using Cyrillic font encoding." << std::endl; + engine.setEncoding(encoding); + } + else + { + std::cout << "Using default (English) font encoding." << std::endl; + engine.setEncoding("win1252"); } // directory settings diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 8cde67671..0bd133f21 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -34,7 +34,7 @@ namespace MWClass if (!model.empty()) { MWRender::Rendering rendering (cellRender, ref->ref); - cellRender.insertMesh ("meshes\\" + model); + cellRender.insertMesh("meshes\\" + model); cellRender.insertActorPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bb5578f6d..9ef5e6f40 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -95,8 +95,7 @@ namespace MWClass upperright[uppernumbers++] = npcName + "chest"; neckandup[neckNumbers++] = npcName + "chest"; } - //std::cout << "GETTING NPC PART"; - //Orgre::SceneNode test = cellRender.getNpcPart(); + const ESM::BodyPart *upperleg = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg"); const ESM::BodyPart *groin = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "groin"); @@ -113,8 +112,6 @@ namespace MWClass const ESM::BodyPart *hands = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "hands.1st"); - //std::cout << "RACE" << bodyRaceID << "\n"; - Ogre::Vector3 pos2 = Ogre::Vector3( 0, .5, 75); if (groin){ @@ -124,10 +121,9 @@ namespace MWClass } if (tail) { cellRender.insertMesh("tail\\" + tail->model, Ogre::Vector3(0 , 0, -76), axis, kOgrePi, npcName + "tail", addresses, numbers, "tail"); - //std::cout << "TAIL\n"; } - //addresses[1] = npcName + "groin"; + if(upperleg){ cellRender.insertMesh ("meshes\\" + upperleg->model, Ogre::Vector3( 6, 0, -16), axis, kOgrePi, npcName + "upper leg", addresses, numbers); //-18 cellRender.insertMesh ("meshes\\" + upperleg->model, Ogre::Vector3( -6, 0, -16), axis, Ogre::Radian(0), npcName + "upper leg2", addresses2, numbers); @@ -218,9 +214,6 @@ namespace MWClass if(hand) { - //std::cout << "WE FOUND A HAND\n"; - //-50, 0, -120 - //std::cout << "WE FOUND HANDS\n"; std::string pass; if(hand->model.compare("b\\B_N_Dark Elf_F_Hands.1st.NIF")==0 && bodyRaceID.compare("b_n_dark elf_m_") == 0) pass = "b\\B_N_Dark Elf_M_Hands.1st.NIF"; @@ -230,7 +223,6 @@ namespace MWClass cellRender.insertMesh("meshes\\" + pass, Ogre::Vector3(42, 1, -110), Ogre::Vector3(0, 0,0), kOgrePi, npcName + "hand2", upperright, uppernumbers, false); //0, 100, -100 0,0,120 upperleft[uppernumbers] = npcName + "hand"; upperright[uppernumbers++] = npcName + "hand2"; - //cellRender.rotateMesh(Ogre::Vector3(0, 0,0), kOgrePi, upperleft, uppernumbers); cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), upperleft, uppernumbers); cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), upperright, uppernumbers); } @@ -244,7 +236,6 @@ namespace MWClass else pass =hands->model; //-50, 0, -120 cellRender.insertMesh("meshes\\" + pass, Ogre::Vector3(42, 1,-110), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "hand", upperleft, uppernumbers, false); //0, 100, -100 42, 0, -110 - //cellRender.insertMesh("meshes\\" + hands->model, Ogre::Vector3(42, 0,110), Ogre::Vector3(1, 0, 0), kOgrePi, npcName + "hand", upperleft, uppernumbers, false); //0, 100, -100 42, 0, -110 cellRender.insertMesh("meshes\\" + pass, Ogre::Vector3(42, 1, -110), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "hand2", upperright, uppernumbers, false); //0, 100, -100 0,0,120 upperleft[uppernumbers] = npcName + "hand"; upperright[uppernumbers++] = npcName + "hand2"; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index baa1309af..0e2e692d3 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -171,6 +171,22 @@ namespace MWGui MyGUI::KeyCode key, MyGUI::Char _char) { + if( key == MyGUI::KeyCode::Tab) + { + std::vector matches; + listNames(); + command->setCaption(complete( command->getCaption(), matches )); +#if 0 + int i = 0; + for(std::vector::iterator it=matches.begin(); it < matches.end(); it++,i++ ) + { + printOK( *it ); + if( i == 50 ) + break; + } +#endif + } + if(command_history.empty()) return; // Traverse history with up and down arrows @@ -237,4 +253,119 @@ namespace MWGui command->setCaption(""); } + + std::string Console::complete( std::string input, std::vector &matches ) + { + using namespace std; + string output=input; + string tmp=input; + bool has_front_quote = false; + + /* Does the input string contain things that don't have to be completed? If yes erase them. */ + /* Are there quotation marks? */ + if( tmp.find('"') != string::npos ) { + int numquotes=0; + for(string::iterator it=tmp.begin(); it < tmp.end(); it++) { + if( *it == '"' ) + numquotes++; + } + + /* Is it terminated?*/ + if( numquotes % 2 ) { + tmp.erase( 0, tmp.rfind('"')+1 ); + has_front_quote = true; + } + else { + size_t pos; + if( ( ((pos = tmp.rfind(' ')) != string::npos ) ) && ( pos > tmp.rfind('"') ) ) { + tmp.erase( 0, tmp.rfind(' ')+1); + } + else { + tmp.clear(); + } + has_front_quote = false; + } + } + /* No quotation marks. Are there spaces?*/ + else { + size_t rpos; + if( (rpos=tmp.rfind(' ')) != string::npos ) { + if( rpos == 0 ) { + tmp.clear(); + } + else { + tmp.erase(0, rpos+1); + } + } + } + /* Erase the input from the output string so we can easily append the completed form later. */ + output.erase(output.end()-tmp.length(), output.end()); + + /* Is there still something in the input string? If not just display all commands and return the unchanged input. */ + if( tmp.length() == 0 ) { + matches=mNames; + return input; + } + + /* Iterate through the vector. */ + for(vector::iterator it=mNames.begin(); it < mNames.end();it++) { + bool string_different=false; + + /* Is the string shorter than the input string? If yes skip it. */ + if( (*it).length() < tmp.length() ) + continue; + + /* Is the beginning of the string different from the input string? If yes skip it. */ + for( string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();iter++, iter2++) { + if( tolower(*iter) != tolower(*iter2) ) { + string_different=true; + break; + } + } + + if( string_different ) + continue; + + /* The beginning of the string matches the input string, save it for the next test. */ + matches.push_back(*it); + } + + /* There are no matches. Return the unchanged input. */ + if( matches.empty() ) + { + return input; + } + + /* Only one match. We're done. */ + if( matches.size() == 1 ) { + /* Adding quotation marks when the input string started with a quotation mark or has spaces in it*/ + if( ( matches.front().find(' ') != string::npos ) ) { + if( !has_front_quote ) + output.append(string("\"")); + return output.append(matches.front() + string("\" ")); + } + else if( has_front_quote ) { + return output.append(matches.front() + string("\" ")); + } + else { + return output.append(matches.front() + string(" ")); + } + } + + /* Check if all matching strings match further than input. If yes complete to this match. */ + int i = tmp.length(); + + for(string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); iter++, i++) { + for(vector::iterator it=matches.begin(); it < matches.end();it++) { + if( tolower((*it)[i]) != tolower(*iter) ) { + /* Append the longest match to the end of the output string*/ + output.append(matches.front().substr( 0, i)); + return output; + } + } + } + + /* All keywords match with the shortest. Append it to the output string and return it. */ + return output.append(matches.front()); + } } diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index d08ac5887..eaf4299be 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -80,6 +80,8 @@ namespace MWGui MyGUI::Char _char); void acceptCommand(MyGUI::EditPtr _sender); + + std::string complete( std::string input, std::vector &matches ); }; } #endif diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp new file mode 100644 index 000000000..f0745bbbe --- /dev/null +++ b/apps/openmw/mwgui/messagebox.cpp @@ -0,0 +1,394 @@ +#include "messagebox.hpp" + +using namespace MWGui; + +MessageBoxManager::MessageBoxManager (WindowManager *windowManager) +{ + mWindowManager = windowManager; + // defines + mMessageBoxSpeed = 0.1; + mInterMessageBoxe = NULL; +} + +void MessageBoxManager::onFrame (float frameDuration) +{ + std::vector::iterator it; + for(it = mTimers.begin(); it != mTimers.end();) + { + it->current += frameDuration; + if(it->current >= it->max) + { + it->messageBox->mMarkedToDelete = true; + + if(*mMessageBoxes.begin() == it->messageBox) // if this box is the last one + { + // collect all with mMarkedToDelete and delete them. + // and place the other messageboxes on the right position + int height = 0; + std::vector::iterator it2 = mMessageBoxes.begin(); + while(it2 != mMessageBoxes.end()) + { + if((*it2)->mMarkedToDelete) + { + delete (*it2); + it2 = mMessageBoxes.erase(it2); + } + else { + (*it2)->update(height); + height += (*it2)->getHeight(); + it2++; + } + } + } + it = mTimers.erase(it); + } + else + { + it++; + } + } + + if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { + delete mInterMessageBoxe; + mInterMessageBoxe = NULL; + mWindowManager->setNextMode(GM_Game); + } +} + +void MessageBoxManager::createMessageBox (const std::string& message) +{ + std::cout << "MessageBox: " << message << std::endl; + + MessageBox *box = new MessageBox(*this, message); + + removeMessageBox(message.length()*mMessageBoxSpeed, box); + + mMessageBoxes.push_back(box); + std::vector::iterator it; + + if(mMessageBoxes.size() > 3) { + delete *mMessageBoxes.begin(); + mMessageBoxes.erase(mMessageBoxes.begin()); + } + + int height = 0; + for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + { + (*it)->update(height); + height += (*it)->getHeight(); + } +} + +bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) +{ + if(mInterMessageBoxe != NULL) { + std::cout << "there is a MessageBox already" << std::endl; + return false; + } + std::cout << "interactive MessageBox: " << message << " - "; + std::copy (buttons.begin(), buttons.end(), std::ostream_iterator (std::cout, ", ")); + std::cout << std::endl; + + mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); + + return true; +} + +bool MessageBoxManager::isInteractiveMessageBox () +{ + return mInterMessageBoxe != NULL; +} + +void MessageBoxManager::removeMessageBox (float time, MessageBox *msgbox) +{ + MessageBoxManagerTimer timer; + timer.current = 0; + timer.max = time; + timer.messageBox = msgbox; + + mTimers.insert(mTimers.end(), timer); +} + +bool MessageBoxManager::removeMessageBox (MessageBox *msgbox) +{ + std::vector::iterator it; + for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + { + if((*it) == msgbox) + { + delete (*it); + mMessageBoxes.erase(it); + return true; + } + } + return false; +} + +void MessageBoxManager::setMessageBoxSpeed (int speed) +{ + mMessageBoxSpeed = speed; +} + + +int MessageBoxManager::readPressedButton () +{ + if(mInterMessageBoxe != NULL) + { + return mInterMessageBoxe->readPressedButton(); + } + return -1; +} + + + + +MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message) + : Layout("openmw_messagebox_layout.xml") + , mMessageBoxManager(parMessageBoxManager) + , cMessage(message) +{ + // defines + mFixedWidth = 300; + mBottomPadding = 20; + mNextBoxPadding = 20; + mMarkedToDelete = false; + + getWidget(mMessageWidget, "message"); + + mMessageWidget->setOverflowToTheLeft(true); + mMessageWidget->addText(cMessage); + + MyGUI::IntSize size; + size.width = mFixedWidth; + size.height = 100; // dummy + + MyGUI::IntCoord coord; + coord.left = 10; // dummy + coord.top = 10; // dummy + + mMessageWidget->setSize(size); + + MyGUI::IntSize textSize = mMessageWidget->_getTextSize(); + size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box + + mMainWidget->setSize(size); + size.width -= 15; // this is to center the text (see messagebox_layout.xml, Widget type="Edit" position="-2 -3 0 0") + mMessageWidget->setSize(size); +} + +void MessageBox::update (int height) +{ + MyGUI::IntSize gameWindowSize = mMessageBoxManager.mWindowManager->getGui()->getViewSize(); + MyGUI::IntCoord coord; + coord.left = (gameWindowSize.width - mFixedWidth)/2; + coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding); + + MyGUI::IntSize size; + size.width = mFixedWidth; + size.height = mHeight; + + mMainWidget->setCoord(coord); + mMainWidget->setSize(size); + mMainWidget->setVisible(true); +} + +int MessageBox::getHeight () +{ + return mHeight+mNextBoxPadding; // 20 is the padding between this and the next MessageBox +} + + + +InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) + : Layout("openmw_interactive_messagebox_layout.xml") + , mMessageBoxManager(parMessageBoxManager) + , mButtonPressed(-1) +{ + int fixedWidth = 500; + int textPadding = 10; // padding between text-widget and main-widget + int textButtonPadding = 20; // padding between the text-widget und the button-widget + int buttonLeftPadding = 10; // padding between the buttons if horizontal + int buttonTopPadding = 5; // ^-- if vertical + int buttonPadding = 5; // padding between button label and button itself + int buttonMainPadding = 10; // padding between buttons and bottom of the main widget + + mMarkedToDelete = false; + + + getWidget(mMessageWidget, "message"); + getWidget(mButtonsWidget, "buttons"); + + mMessageWidget->setOverflowToTheLeft(true); + mMessageWidget->addText(message); + + MyGUI::IntSize textSize = mMessageWidget->_getTextSize(); + + MyGUI::IntSize gameWindowSize = mMessageBoxManager.mWindowManager->getGui()->getViewSize(); + + int biggestButtonWidth = 0; + int buttonWidth = 0; + int buttonsWidth = 0; + int buttonHeight = 0; + MyGUI::IntCoord dummyCoord(0, 0, 0, 0); + + std::vector::const_iterator it; + for(it = buttons.begin(); it != buttons.end(); ++it) + { + MyGUI::ButtonPtr button = mButtonsWidget->createWidget( + MyGUI::WidgetStyle::Child, + std::string("MW_Button"), + dummyCoord, + MyGUI::Align::Default); + button->setCaption(*it); + + button->eventMouseButtonClick = MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); + + mButtons.push_back(button); + + buttonWidth = button->_getTextSize().width + 2*buttonPadding + buttonLeftPadding; + buttonsWidth += buttonWidth; + buttonHeight = button->_getTextSize().height + 2*buttonPadding + buttonTopPadding; + + if(buttonWidth > biggestButtonWidth) + { + biggestButtonWidth = buttonWidth; + } + } + buttonsWidth += buttonLeftPadding; + + MyGUI::IntSize mainWidgetSize; + if(buttonsWidth < fixedWidth) + { + // on one line + std::cout << "on one line" << std::endl; + + if(textSize.width + 2*textPadding < buttonsWidth) + { + std::cout << "width = buttonsWidth" << std::endl; + mainWidgetSize.width = buttonsWidth; + } + else + { + mainWidgetSize.width = textSize.width + 3*textPadding; + } + mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding; + + MyGUI::IntCoord absCoord; + absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; + absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; + + std::cout << "width " << mainWidgetSize.width << " height " << mainWidgetSize.height << std::endl; + std::cout << "left " << absCoord.left << " top " << absCoord.top << std::endl; + + mMainWidget->setCoord(absCoord); + mMainWidget->setSize(mainWidgetSize); + + + MyGUI::IntCoord messageWidgetCoord; + messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; + messageWidgetCoord.top = textPadding; + mMessageWidget->setCoord(messageWidgetCoord); + + mMessageWidget->setSize(textSize); + + MyGUI::IntCoord buttonCord; + MyGUI::IntSize buttonSize(0, buttonHeight); + int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; + + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + buttonCord.left = left; + buttonCord.top = textSize.height + textButtonPadding; + + buttonSize.width = (*button)->_getTextSize().width + 2*buttonPadding; + buttonSize.height = (*button)->_getTextSize().height + 2*buttonPadding; + + (*button)->setCoord(buttonCord); + (*button)->setSize(buttonSize); + + left += buttonSize.width + buttonLeftPadding; + } + } + else + { + // among each other + + if(biggestButtonWidth > textSize.width) { + mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; + } + else { + mainWidgetSize.width = textSize.width + 3*textPadding; + } + mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding; + + std::cout << "biggestButtonWidth " << biggestButtonWidth << " textSize.width " << textSize.width << std::endl; + std::cout << "width " << mainWidgetSize.width << " height " << mainWidgetSize.height << std::endl; + mMainWidget->setSize(mainWidgetSize); + + MyGUI::IntCoord absCoord; + absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; + absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; + + mMainWidget->setCoord(absCoord); + mMainWidget->setSize(mainWidgetSize); + + + MyGUI::IntCoord messageWidgetCoord; + messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; + messageWidgetCoord.top = textPadding; + mMessageWidget->setCoord(messageWidgetCoord); + + mMessageWidget->setSize(textSize); + + MyGUI::IntCoord buttonCord; + MyGUI::IntSize buttonSize(0, buttonHeight); + + int top = textButtonPadding + buttonTopPadding + textSize.height; + + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + buttonSize.width = (*button)->_getTextSize().width + buttonPadding*2; + buttonSize.height = (*button)->_getTextSize().height + buttonPadding*2; + + buttonCord.top = top; + buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/ + + (*button)->setCoord(buttonCord); + (*button)->setSize(buttonSize); + + top += buttonSize.height + 2*buttonTopPadding; + } + + } +} + +void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) +{ + mMarkedToDelete = true; + int index = 0; + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + if(*button == pressed) + { + mButtonPressed = index; + return; + } + index++; + } + std::cout << "Cant be possible :/" << std::endl; +} + +int InteractiveMessageBox::readPressedButton () +{ + int pressed = mButtonPressed; + mButtonPressed = -1; + return pressed; +} + + + + + diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp new file mode 100644 index 000000000..bf3307acc --- /dev/null +++ b/apps/openmw/mwgui/messagebox.hpp @@ -0,0 +1,89 @@ +#ifndef MWGUI_MESSAGE_BOX_H +#define MWGUI_MESSAGE_BOX_H + +#include +#include + +#include "window_base.hpp" +#include "window_manager.hpp" + + +namespace MWGui +{ + + class InteractiveMessageBox; + class MessageBoxManager; + class MessageBox; + + struct MessageBoxManagerTimer { + float current; + float max; + MessageBox *messageBox; + }; + + class MessageBoxManager + { + public: + MessageBoxManager (WindowManager* windowManager); + void onFrame (float frameDuration); + void createMessageBox (const std::string& message); + bool createInteractiveMessageBox (const std::string& message, const std::vector& buttons); + bool isInteractiveMessageBox (); + + void removeMessageBox (float time, MessageBox *msgbox); + bool removeMessageBox (MessageBox *msgbox); + void setMessageBoxSpeed (int speed); + + int readPressedButton (); + + WindowManager *mWindowManager; + + private: + std::vector mMessageBoxes; + InteractiveMessageBox* mInterMessageBoxe; + std::vector mTimers; + float mMessageBoxSpeed; + }; + + class MessageBox : public OEngine::GUI::Layout + { + public: + MessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message); + void setMessage (const std::string& message); + int getHeight (); + void update (int height); + + bool mMarkedToDelete; + + protected: + MessageBoxManager& mMessageBoxManager; + int mHeight; + const std::string& cMessage; + MyGUI::EditPtr mMessageWidget; + int mFixedWidth; + int mBottomPadding; + int mNextBoxPadding; + }; + + class InteractiveMessageBox : public OEngine::GUI::Layout + { + public: + InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons); + void mousePressed (MyGUI::Widget* _widget); + int readPressedButton (); + + bool mMarkedToDelete; + + private: + MessageBoxManager& mMessageBoxManager; + MyGUI::EditPtr mMessageWidget; + MyGUI::WidgetPtr mButtonsWidget; + std::vector mButtons; + + int mTextButtonPadding; + int mButtonPressed; + }; + +} + +#endif diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 313b097cf..b0dc14029 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -26,7 +26,10 @@ namespace MWGui GM_ClassGenerate, GM_ClassPick, GM_ClassCreate, - GM_Review + GM_Review, + + // interactive MessageBox + GM_InterMessageBox }; // Windows shown in inventory mode diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 2d7f70ef8..84e45859f 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -8,6 +8,7 @@ #include "dialogue.hpp" #include "dialogue_history.hpp" #include "stats_window.hpp" +#include "messagebox.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -60,6 +61,7 @@ WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment inventory = new InventoryWindow (); #endif console = new Console(w,h, environment, extensions); + mMessageBoxManager = new MessageBoxManager(this); // The HUD is always on hud->setVisible(true); @@ -82,6 +84,7 @@ WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment WindowManager::~WindowManager() { delete console; + delete mMessageBoxManager; delete hud; delete map; delete menu; @@ -326,6 +329,14 @@ void WindowManager::updateVisible() dialogueWindow->open(); return; } + + if(mode == GM_InterMessageBox) + { + if(!mMessageBoxManager->isInteractiveMessageBox()) { + setGuiMode(GM_Game); + } + return; + } // Unsupported mode, switch back to game @@ -446,16 +457,22 @@ void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) void WindowManager::messageBox (const std::string& message, const std::vector& buttons) { - std::cout << "message box: " << message << std::endl; - - if (!buttons.empty()) + if (buttons.empty()) + { + mMessageBoxManager->createMessageBox(message); + } + else { - std::cout << "buttons: "; - std::copy (buttons.begin(), buttons.end(), std::ostream_iterator (std::cout, ", ")); - std::cout << std::endl; + mMessageBoxManager->createInteractiveMessageBox(message, buttons); + setGuiMode(GM_InterMessageBox); } } +int WindowManager::readPressedButton () +{ + return mMessageBoxManager->readPressedButton(); +} + const std::string &WindowManager::getGameSettingString(const std::string &id, const std::string &default_) { const ESM::GameSetting *setting = environment.mWorld->getStore().gameSettings.search(id); @@ -555,6 +572,11 @@ void WindowManager::onClassChoice(int _index) }; } +void WindowManager::onFrame (float frameDuration) +{ + mMessageBoxManager->onFrame(frameDuration); +} + namespace MWGui { diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index d3fbf3ea3..293bac601 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -62,6 +62,7 @@ namespace MWGui class CreateClassDialog; class BirthDialog; class ReviewDialog; + class MessageBoxManager; struct ClassPoint { @@ -84,6 +85,7 @@ namespace MWGui MapWindow *map; MainMenu *menu; StatsWindow *stats; + MessageBoxManager *mMessageBoxManager; #if 0 InventoryWindow *inventory; #endif @@ -245,8 +247,13 @@ namespace MWGui void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. - + void messageBox (const std::string& message, const std::vector& buttons); + + int readPressedButton (); + ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) + + void onFrame (float frameDuration); /** * Fetches a GMST string from the store, if there is no setting with the given diff --git a/apps/openmw/mwrender/exterior.hpp b/apps/openmw/mwrender/exterior.hpp index 40d9c60ae..6c7f6effc 100644 --- a/apps/openmw/mwrender/exterior.hpp +++ b/apps/openmw/mwrender/exterior.hpp @@ -6,6 +6,7 @@ #include "OgreColourValue.h" #include +#include namespace Ogre { @@ -74,6 +75,7 @@ namespace MWRender virtual void insertMesh(const std::string &mesh, Ogre::Vector3 vec, Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName, std::string sceneParent[], int elements, bool translateFirst); virtual void insertMesh(const std::string &mesh); + virtual void rotateMesh(Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName[], int elements); virtual void scaleMesh(Ogre::Vector3 axis, std::string sceneNodeName[], int elements); diff --git a/apps/openmw/mwrender/interior.cpp b/apps/openmw/mwrender/interior.cpp index 4fa5191b8..02bed0898 100644 --- a/apps/openmw/mwrender/interior.cpp +++ b/apps/openmw/mwrender/interior.cpp @@ -182,11 +182,11 @@ void InteriorCellRender::insertMesh(const std::string &mesh, Ogre::Vector3 vec, void InteriorCellRender::insertMesh(const std::string &mesh) { - assert (insert); + assert (insert); - NifOgre::NIFLoader::load(mesh); - MovableObject *ent = scene.getMgr()->createEntity(mesh); - insert->attachObject(ent); + NifOgre::NIFLoader::load(mesh); + MovableObject *ent = scene.getMgr()->createEntity(mesh); + insert->attachObject(ent); if (mInsertMesh.empty()) mInsertMesh = mesh; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index fcebaae2b..33ce38cdd 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -108,4 +108,5 @@ op 0x2000133: Journal op 0x2000134: SetJournalIndex op 0x2000135: GetJournalIndex op 0x2000136: GetPCCell -opcodes 0x2000137-0x3ffffff unused +op 0x2000137: GetButtonPressed +opcodes 0x2000138-0x3ffffff unused diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 0339a11f5..484c0d3ab 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -15,42 +15,57 @@ namespace MWScript { namespace Gui - { + { class OpEnableWindow : public Interpreter::Opcode0 { MWGui::GuiWindow mWindow; - + public: - + OpEnableWindow (MWGui::GuiWindow window) : mWindow (window) {} - + virtual void execute (Interpreter::Runtime& runtime) { InterpreterContext& context = static_cast (runtime.getContext()); - + context.getWindowManager().allow (mWindow); - } - }; - + } + }; + class OpShowDialogue : public Interpreter::Opcode0 { MWGui::GuiMode mDialogue; - + public: - + OpShowDialogue (MWGui::GuiMode dialogue) : mDialogue (dialogue) {} - + virtual void execute (Interpreter::Runtime& runtime) { InterpreterContext& context = static_cast (runtime.getContext()); - + context.getInputManager().setGuiMode(mDialogue); - } - }; + } + }; + + class OpGetButtonPressed : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = + static_cast (runtime.getContext()); + + MWWorld::Ptr ptr = context.getReference(); + + runtime.push (context.getWindowManager().readPressedButton()); + } + }; const int opcodeEnableBirthMenu = 0x200000e; const int opcodeEnableClassMenu = 0x200000f; @@ -63,7 +78,8 @@ namespace MWScript const int opcodeEnableStatsMenu = 0x2000016; const int opcodeEnableRest = 0x2000017; const int opcodeShowRestMenu = 0x2000018; - + const int opcodeGetButtonPressed = 0x2000137; + void registerExtensions (Compiler::Extensions& extensions) { extensions.registerInstruction ("enablebirthmenu", "", opcodeEnableBirthMenu); @@ -80,10 +96,12 @@ namespace MWScript extensions.registerInstruction ("enablerestmenu", "", opcodeEnableRest); extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableRest); - + extensions.registerInstruction ("showrestmenu", "", opcodeShowRestMenu); + + extensions.registerFunction ("getbuttonpressed", 'l', "", opcodeGetButtonPressed); } - + void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (opcodeEnableBirthMenu, @@ -115,6 +133,8 @@ namespace MWScript interpreter.installSegment5 (opcodeShowRestMenu, new OpShowDialogue (MWGui::GM_Rest)); + + interpreter.installSegment5 (opcodeGetButtonPressed, new OpGetButtonPressed); } } } diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 564ebe941..970118a13 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -84,20 +84,25 @@ namespace MWSound // finding. It takes DOS paths (any case, \\ slashes or / slashes) // relative to the sound dir, and translates them into full paths // of existing files in the filesystem, if they exist. + bool FSstrict; FileFinder::FileFinder files; + FileFinder::FileFinderStrict strict; + FileFinder::FileFinder musicpath; + FileFinder::FileFinderStrict musicpathStrict; SoundImpl(Ogre::Root *root, Ogre::Camera *camera, const ESMS::ESMStore &str, - const std::string &soundDir) + const std::string &soundDir, const std::string &musicDir, bool fsstrict) : mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY))) , updater(mgr) , cameraTracker(mgr) , store(str) - , files(soundDir) + , files(soundDir), strict(soundDir) + ,musicpath(musicDir), musicpathStrict(musicDir) { + FSstrict = fsstrict; cout << "Sound output: " << SOUND_OUT << endl; cout << "Sound decoder: " << SOUND_IN << endl; - // Attach the camera to the camera tracker cameraTracker.followCamera(camera); @@ -111,6 +116,8 @@ namespace MWSound cameraTracker.unfollowCamera(); } + + static std::string toMp3(std::string str) { std::string::size_type i = str.rfind('.'); @@ -122,28 +129,76 @@ namespace MWSound return str; } - bool hasFile(const std::string &str) + bool hasFile(const std::string &str, bool music = false) { - if(files.has(str)) return true; - // Not found? Try with .mp3 - return files.has(toMp3(str)); + if(FSstrict == false) + { + if(music) + { + if(musicpath.has(str)) return true; + + // Not found? Try with .mp3 + return musicpath.has(toMp3(str)); + } + else + { + if(files.has(str)) return true; + return files.has(toMp3(str)); + } + } + else + { + if(music) + { + if(musicpathStrict.has(str)) return true; + + // Not found? Try with .mp3 + return musicpathStrict.has(toMp3(str)); + } + else + { + if(strict.has(str)) return true; + return strict.has(toMp3(str)); + } + } } // Convert a Morrowind sound path (eg. Fx\funny.wav) to full path // with proper slash conversion (eg. datadir/Sound/Fx/funny.wav) - std::string convertPath(const std::string &str) + std::string convertPath(const std::string &str, bool music = false) { - // Search and return - if(files.has(str)) - return files.lookup(str); - - // Try mp3 if the wav wasn't found - std::string mp3 = toMp3(str); - if(files.has(mp3)) - return files.lookup(mp3); + if(FSstrict == false) + { + // Search and return + if(music && musicpath.has(str)) + return musicpath.lookup(str); + else if(files.has(str)) + return files.lookup(str); + + // Try mp3 if the wav wasn't found + std::string mp3 = toMp3(str); + if(music && musicpath.has(mp3)) + return musicpath.lookup(mp3); + else if(files.has(mp3)) + return files.lookup(mp3); + } + else + { + if(music && musicpathStrict.has(str)) + return musicpathStrict.lookup(str); + else if(strict.has(str)) + return strict.lookup(str); + + // Try mp3 if the wav wasn't found + std::string mp3 = toMp3(str); + if(music && musicpathStrict.has(mp3)) + return musicpathStrict.lookup(mp3); + else if(strict.has(str)) + return strict.lookup(mp3); + } - // Give up - return ""; + // Give up + return ""; } // Convert a soundId to file name, and modify the volume @@ -304,15 +359,31 @@ namespace MWSound } }; + void SoundManager::streamMusicFull (const std::string& filename) + { + if(!mData) return; + + // Play the sound and tell it to stream, if possible. TODO: + // Store the reference, the jukebox will need to check status, + // control volume etc. + if (mData->music) + mData->music->stop(); + mData->music = mData->mgr->load(filename); + mData->music->setStreaming(true); + mData->music->setVolume(0.4); + mData->music->play(); + + } + SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera, const ESMS::ESMStore &store, boost::filesystem::path dataDir, - bool useSound) - : mData(NULL) + bool useSound, bool fsstrict) + : mData(NULL), fsStrict (fsstrict) { MP3Lookup(dataDir / "Music/Explore/"); if(useSound) - mData = new SoundImpl(root, camera, store, (dataDir / "Sound").string()); + mData = new SoundImpl(root, camera, store, (dataDir / "Sound").string(), (dataDir / "Music").string(), fsstrict); } SoundManager::~SoundManager() @@ -321,6 +392,16 @@ namespace MWSound delete mData; } + void SoundManager::streamMusic(const std::string& filename) + { + if(mData->hasFile(filename, true)) + { + std::string fullpath = mData->convertPath(filename, true); + streamMusicFull(fullpath); + } + } + + void SoundManager::MP3Lookup(boost::filesystem::path dir) { boost::filesystem::directory_iterator dir_iter(dir), dir_end; @@ -353,7 +434,7 @@ namespace MWSound try { std::cout << "Playing " << music << "\n"; - streamMusic(music); + streamMusicFull(music); } catch(std::exception &e) { @@ -397,21 +478,6 @@ namespace MWSound return !mData->isPlaying(ptr, "_say_sound"); } - void SoundManager::streamMusic (const std::string& filename) - { - if(!mData) return; - - // Play the sound and tell it to stream, if possible. TODO: - // Store the reference, the jukebox will need to check status, - // control volume etc. - if (mData->music) - mData->music->stop(); - mData->music = mData->mgr->load(filename); - mData->music->setStreaming(true); - mData->music->setVolume(0.4); - mData->music->play(); - - } void SoundManager::playSound (const std::string& soundId, float volume, float pitch) { diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index 8c48986db..ab9559176 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -27,19 +27,28 @@ namespace MWSound // Hide implementation details - engine.cpp is compiling // enough as it is. struct SoundImpl; - + SoundImpl *mData; std::vector files; - + bool fsStrict; + + void streamMusicFull (const std::string& filename); + ///< Play a soundifle + /// \param absolute filename public: + SoundManager(Ogre::Root*, Ogre::Camera*, const ESMS::ESMStore &store, - boost::filesystem::path dataDir, bool useSound); + boost::filesystem::path dataDir, bool useSound, bool fsstrict); ~SoundManager(); + void streamMusic(const std::string& filename); + ///< Play a soundifle + /// \param filename name of a sound file in "Music/" in the data directory. + void startRandomTitle(); void MP3Lookup(boost::filesystem::path dir); - //struct SoundImpl; + bool isMusicPlaying(); SoundImpl getMData(); @@ -51,9 +60,7 @@ namespace MWSound bool sayDone (MWWorld::Ptr reference) const; ///< Is actor not speaking? - void streamMusic (const std::string& filename); - ///< Play a soundifle - /// \param filename name of a sound file in "Music/" in the data directory. + void playSound (const std::string& soundId, float volume, float pitch); ///< Play a sound, independently of 3D-position diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 3a4151e3a..063f54d6f 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -409,9 +409,9 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, - bool newGame, Environment& environment) + bool newGame, Environment& environment, const std::string& encoding) : mSkyManager (0), mScene (renderer,physEng), mPlayer (0), mCurrentCell (0), mGlobalVariables (0), - mSky (false), mCellChanged (false), mEnvironment (environment) + mSky (false), mCellChanged (false), mEnvironment (environment), mNextDynamicRecord (0) { mPhysEngine = physEng; @@ -420,6 +420,7 @@ namespace MWWorld std::cout << "Loading ESM " << masterPath.string() << "\n"; // This parses the ESM file and loads a sample cell + mEsm.setEncoding(encoding); mEsm.open (masterPath.string()); mStore.load (mEsm); @@ -870,4 +871,36 @@ namespace MWWorld { return mScene.toggleRenderMode (mode); } + + std::pair World::createRecord (const ESM::Potion& record) + { + /// \todo Rewrite the ESMStore so that a dynamic 2nd ESMStore can be attached to it. + /// This function should then insert the record into the 2nd store (the code for this + /// should also be moved to the ESMStore class). It might be a good idea to review + /// the STL-container usage of the ESMStore before the rewrite. + + std::ostringstream stream; + stream << "$dynamic" << mNextDynamicRecord++; + + const ESM::Potion *created = + &mStore.potions.list.insert (std::make_pair (stream.str(), record)).first->second; + + mStore.all.insert (std::make_pair (stream.str(), ESM::REC_ALCH)); + + return std::make_pair (stream.str(), created); + } + + std::pair World::createRecord (const ESM::Class& record) + { + /// \todo See function above. + std::ostringstream stream; + stream << "$dynamic" << mNextDynamicRecord++; + + const ESM::Class *created = + &mStore.classes.list.insert (std::make_pair (stream.str(), record)).first->second; + + mStore.all.insert (std::make_pair (stream.str(), ESM::REC_CLAS)); + + return std::make_pair (stream.str(), created); + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 160c20314..cccd8816d 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -79,6 +79,7 @@ namespace MWWorld bool mSky; bool mCellChanged; Environment& mEnvironment; + int mNextDynamicRecord; OEngine::Physic::PhysicEngine* mPhysEngine; @@ -115,7 +116,7 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, bool newGame, - Environment& environment); + Environment& environment, const std::string& encoding); ~World(); @@ -202,6 +203,14 @@ namespace MWWorld bool toggleRenderMode (RenderMode mode); ///< Toggle a render mode. ///< \return Resulting mode + + std::pair createRecord (const ESM::Potion& record); + ///< Create a new recrod (of type potion) in the ESM store. + /// \return ID, pointer to created record + + std::pair createRecord (const ESM::Class& record); + ///< Create a new recrod (of type class) in the ESM store. + /// \return ID, pointer to created record }; } diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 937a21d0a..2178be318 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -23,6 +23,7 @@ #include "bsa_archive.hpp" +#include #include #include #include @@ -36,7 +37,186 @@ using namespace Ogre; using namespace Mangle::Stream; using namespace Bsa; +struct ciLessBoost : std::binary_function +{ + bool operator() (const std::string & s1, const std::string & s2) const { + //case insensitive version of is_less + return lexicographical_compare(s1, s2, boost::algorithm::is_iless()); + } +}; + +static bool fsstrict = false; + /// An OGRE Archive wrapping a BSAFile archive +class DirArchive: public Ogre::FileSystemArchive +{ + + boost::filesystem::path currentdir; + std::map, ciLessBoost> m; + unsigned int cutoff; + + bool comparePortion(std::string file1, std::string file2, int start, int size) const + { + for(int i = start; i < start+size; i++) + { + char one = file1.at(i); + char two = file2.at(i); + if(tolower(one) != tolower(two) ) + return false; + } + return true; + } + + public: + + DirArchive(const String& name) + : FileSystemArchive(name, "Dir"), currentdir (name) + { + mType = "Dir"; + std::string s = name; + cutoff = s.size() + 1; + if(fsstrict == false) + populateMap(currentdir); + + } + void populateMap(boost::filesystem::path d){ + //need to cut off first + boost::filesystem::directory_iterator dir_iter(d), dir_end; + std::vector filesind; + boost::filesystem::path f; + for(;dir_iter != dir_end; dir_iter++) + { + if(boost::filesystem::is_directory(*dir_iter)) + populateMap(*dir_iter); + else + { + + f = *dir_iter; + std::string s = f.string(); + + std::string small; + if(cutoff < s.size()) + small = s.substr(cutoff, s.size() - cutoff); + else + small = s.substr(cutoff - 1, s.size() - cutoff); + + filesind.push_back(small); + } + } + std::string small; + std::string original = d.string(); + if(cutoff < original.size()) + small = original.substr(cutoff, original.size() - cutoff); + else + small = original.substr(cutoff - 1, original.size() - cutoff); + m[small] = filesind; + + } + + bool isCaseSensitive() const { return fsstrict; } + + // The archive is loaded in the constructor, and never unloaded. + void load() {} + void unload() {} + + bool exists(const String& filename) { + std::string copy = filename; + + + + for (unsigned int i = 0; i < filename.size(); i++) + { + if(copy.at(i) == '\\' ){ + copy.replace(i, 1, "/"); + } + } + + + if(copy.at(0) == '\\' || copy.at(0) == '/') + { + copy.erase(0, 1); + } + if(fsstrict == true) + { + //std::cout << "fsstrict " << copy << "\n"; + return FileSystemArchive::exists(copy); + } + + + int last = copy.size() - 1; + int i = last; + + for (;last >= 0; i--) + { + if(copy.at(i) == '/' || copy.at(i) == '\\') + break; + } + + std::string folder = copy.substr(0, i); //folder with no slash + + std::vector& current = m[folder]; + + for(std::vector::iterator iter = current.begin(); iter != current.end(); iter++) + { + if(comparePortion(*iter, copy, i + 1, copy.size() - i -1) == true){ + return FileSystemArchive::exists(*iter); + } + } + + + return false; + } + + DataStreamPtr open(const String& filename, bool readonly = true) const + { + std::map, ciLessBoost> mlocal = m; + std::string copy = filename; + + + + for (unsigned int i = 0; i < filename.size(); i++) + { + if(copy.at(i) == '\\' ){ + copy.replace(i, 1, "/"); + } + } + + + if(copy.at(0) == '\\' || copy.at(0) == '/') + { + copy.erase(0, 1); + } + + if(fsstrict == true) + { + return FileSystemArchive::open(copy, readonly); + } + + + int last = copy.size() - 1; + int i = last; + + for (;last >= 0; i--) + { + if(copy.at(i) == '/' || copy.at(i) == '\\') + break; + } + + std::string folder = copy.substr(0, i); //folder with no slash + std::vector current = mlocal[folder]; + + for(std::vector::iterator iter = current.begin(); iter != current.end(); iter++) + { + if(comparePortion(*iter, copy, i + 1, copy.size() - i -1) == true){ + return FileSystemArchive::open(*iter, readonly); + } + } + DataStreamPtr p; + return p; + } + +}; + class BSAArchive : public Archive { BSAFile arc; @@ -149,7 +329,27 @@ public: void destroyInstance( Archive* arch) { delete arch; } }; +class DirArchiveFactory : public FileSystemArchiveFactory +{ +public: + const String& getType() const + { + static String name = "Dir"; + return name; + } + + Archive *createInstance( const String& name ) + { + return new DirArchive(name); + } + + void destroyInstance( Archive* arch) { delete arch; } +}; + + static bool init = false; +static bool init2 = false; + static void insertBSAFactory() { if(!init) @@ -159,6 +359,15 @@ static void insertBSAFactory() } } +static void insertDirFactory() +{ + if(!init2) + { + ArchiveManager::getSingleton().addArchiveFactory( new DirArchiveFactory ); + init2 = true; + } +} + } namespace Bsa @@ -173,4 +382,13 @@ void addBSA(const std::string& name, const std::string& group) addResourceLocation(name, "BSA", group); } +void addDir(const std::string& name, const bool& fs, const std::string& group) +{ + fsstrict = fs; + insertDirFactory(); + + ResourceGroupManager::getSingleton(). + addResourceLocation(name, "Dir", group); +} + } diff --git a/components/bsa/bsa_archive.hpp b/components/bsa/bsa_archive.hpp index 9054966db..18f7377ff 100644 --- a/components/bsa/bsa_archive.hpp +++ b/components/bsa/bsa_archive.hpp @@ -22,6 +22,9 @@ */ #include +#include +#include +#include #ifndef BSA_BSA_ARCHIVE_H #define BSA_BSA_ARCHIVE_H @@ -32,6 +35,7 @@ namespace Bsa /// Add the given BSA file as an input archive in the Ogre resource /// system. void addBSA(const std::string& file, const std::string& group="General"); +void addDir(const std::string& file, const bool& fs, const std::string& group="General"); } diff --git a/components/esm/esm_reader.cpp b/components/esm/esm_reader.cpp index 2c342178b..e9bfcf5ee 100644 --- a/components/esm/esm_reader.cpp +++ b/components/esm/esm_reader.cpp @@ -326,7 +326,7 @@ std::string ESMReader::getString(int size) mEsm->read(ptr, size); // Convert to UTF8 and return - return ToUTF8::getUtf8(ToUTF8::WINDOWS_1252); + return ToUTF8::getUtf8(mEncoding); } void ESMReader::fail(const std::string &msg) @@ -344,4 +344,21 @@ void ESMReader::fail(const std::string &msg) throw std::runtime_error(ss.str()); } +void ESMReader::setEncoding(const std::string& encoding) +{ + if (encoding == "win1250") + { + mEncoding = ToUTF8::WINDOWS_1250; + } + else if (encoding == "win1251") + { + mEncoding = ToUTF8::WINDOWS_1251; + } + else + { + // Default Latin encoding + mEncoding = ToUTF8::WINDOWS_1252; + } +} + } diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index dea1980e2..e5b230748 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -350,6 +350,9 @@ public: /// Used for error handling void fail(const std::string &msg); + /// Sets font encoding for ESM strings + void setEncoding(const std::string& encoding); + private: Mangle::Stream::StreamPtr mEsm; @@ -360,6 +363,7 @@ private: SaveData mSaveData; MasterList mMasters; + ToUTF8::FromType mEncoding; }; } #endif diff --git a/components/esm_store/store.cpp b/components/esm_store/store.cpp index 9f301d163..2b5b977aa 100644 --- a/components/esm_store/store.cpp +++ b/components/esm_store/store.cpp @@ -85,7 +85,13 @@ void ESMStore::load(ESMReader &esm) dialogue = 0; // Insert the reference into the global lookup - if(!id.empty()) + if(!id.empty() && + (n.val==REC_ACTI || n.val==REC_ALCH || n.val==REC_APPA || n.val==REC_ARMO || + n.val==REC_BOOK || n.val==REC_CLOT || n.val==REC_CONT || n.val==REC_CREA || + n.val==REC_DOOR || n.val==REC_INGR || n.val==REC_LEVC || n.val==REC_LEVI || + n.val==REC_LIGH || n.val==REC_LOCK || n.val==REC_MISC || n.val==REC_NPC_ || + n.val==REC_PROB || n.val==REC_REPA || n.val==REC_STAT || n.val==REC_WEAP) + ) all[id] = n.val; } } diff --git a/components/file_finder/file_finder.hpp b/components/file_finder/file_finder.hpp index cfa07dce9..0e1e07226 100644 --- a/components/file_finder/file_finder.hpp +++ b/components/file_finder/file_finder.hpp @@ -20,9 +20,9 @@ class FileFinderT void add(const boost::filesystem::path &pth) { - std::string file = pth.string(); - std::string key = file.substr(cut); - owner->table[key] = file; + std::string file = pth.string(); + std::string key = file.substr(cut); + owner->table[key] = file; } }; @@ -50,17 +50,18 @@ public: bool has(const std::string& file) const { - return table.find(file) != table.end(); + return table.find(file) != table.end(); } // Find the full path from a relative path. const std::string &lookup(const std::string& file) const { - return table.find(file)->second; + return table.find(file)->second; } }; // The default is to use path_less for equality checks typedef FileFinderT FileFinder; +typedef FileFinderT FileFinderStrict; } #endif diff --git a/components/file_finder/filename_less.hpp b/components/file_finder/filename_less.hpp index 9f251b1c8..bc3186ce9 100644 --- a/components/file_finder/filename_less.hpp +++ b/components/file_finder/filename_less.hpp @@ -44,6 +44,41 @@ struct path_less return compareString(a.c_str(), b.c_str()) < 0; } }; + +struct path_slash +{ + int compareChar(char a, char b) const + { + if(a>b) return 1; + else if(a namespace Nif { @@ -433,67 +434,70 @@ public: class NiKeyframeData : public Record { -public: - void read(NIFFile *nif) - { - // Rotations first - int count = nif->getInt(); - if(count) - { - int type = nif->getInt(); - - if(type == 1) - nif->skip(count*4*5); // time + quaternion - else if(type == 3) - nif->skip(count*4*8); // rot1 + tension+bias+continuity - else if(type == 4) - { - for(int j=0;jgetFloat(); // time - for(int i=0; i<3; i++) - { - int cnt = nif->getInt(); - int type = nif->getInt(); - if(type == 1) - nif->skip(cnt*4*2); // time + unknown - else if(type == 2) - nif->skip(cnt*4*4); // time + unknown vector - else nif->fail("Unknown sub-rotation type"); - } - } - } - else nif->fail("Unknown rotation type in NiKeyframeData"); - } - - // Then translation - count = nif->getInt(); - if(count) - { - int type = nif->getInt(); - - if(type == 1) nif->getFloatLen(count*4); // time + translation - else if(type == 2) - nif->getFloatLen(count*10); // trans1 + forward + backward - else if(type == 3) - nif->getFloatLen(count*7); // trans1 + tension,bias,continuity - else nif->fail("Unknown translation type"); - } - - // Finally, scalings - count = nif->getInt(); - if(count) - { - int type = nif->getInt(); - - int size = 0; - if(type == 1) size = 2; // time+scale - else if(type == 2) size = 4; // 1 + forward + backward (floats) - else if(type == 3) size = 5; // 1 + tbc - else nif->fail("Unknown scaling type"); - nif->getFloatLen(count*size); - } - } + public: + + void read(NIFFile *nif) + { + // Rotations first + int count = nif->getInt(); + if(count) + { + int type = nif->getInt(); + + if(type == 1) + nif->skip(count*4*5); // time + quaternion + else if(type == 3) + nif->skip(count*4*8); // rot1 + tension+bias+continuity + else if(type == 4) + { + for(int j=0;jgetFloat(); // time + for(int i=0; i<3; i++) + { + int cnt = nif->getInt(); + int type = nif->getInt(); + if(type == 1) + nif->skip(cnt*4*2); // time + unknown + else if(type == 2) + nif->skip(cnt*4*4); // time + unknown vector + else nif->fail("Unknown sub-rotation type"); + } + } + } + else nif->fail("Unknown rotation type in NiKeyframeData"); + } + + // Then translation + count = nif->getInt(); + + if(count) + { + int type = nif->getInt(); + + if(type == 1) + nif->getFloatLen(count*4); // time + translation + else if(type == 2) + nif->getFloatLen(count*10); // trans1 + forward + backward + else if(type == 3) + nif->getFloatLen(count*7); // trans1 + tension,bias,continuity + else nif->fail("Unknown translation type"); + } + + // Finally, scalings + count = nif->getInt(); + if(count) + { + int type = nif->getInt(); + + int size = 0; + if(type == 1) size = 2; // time+scale + else if(type == 2) size = 4; // 1 + forward + backward (floats) + else if(type == 3) size = 5; // 1 + tbc + else nif->fail("Unknown scaling type"); + nif->getFloatLen(count*size); + } + } }; } // Namespace diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b2b102daf..668fdcceb 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -83,11 +83,11 @@ Vector3 NIFLoader::convertVector3(const Nif::Vector& vec) Quaternion NIFLoader::convertRotation(const Nif::Matrix& rot) { Real matrix[3][3]; - + for (int i=0; i<3; i++) for (int j=0; j<3; j++) matrix[i][j] = rot.v[i].array[j]; - + return Quaternion(Matrix3(matrix)); } @@ -267,7 +267,7 @@ void NIFLoader::createMaterial(const String &name, } else pass->setDepthWriteEnabled(true); */ - + // Add transparency if NiAlphaProperty was present if (alphaFlags != -1) @@ -348,16 +348,16 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std sub->vertexData = new VertexData(); sub->vertexData->vertexCount = numVerts; sub->useSharedVertices = false; - + VertexDeclaration *decl = sub->vertexData->vertexDeclaration; decl->addElement(nextBuf, 0, VET_FLOAT3, VES_POSITION); - + HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( VertexElement::getTypeSize(VET_FLOAT3), numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); vbuf->writeData(0, vbuf->getSizeInBytes(), data->vertices.ptr, true); - + VertexBufferBinding* bind = sub->vertexData->vertexBufferBinding; bind->setBinding(nextBuf++, vbuf); @@ -694,7 +694,7 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou if (verIndex < data->normals.length) { Vector3 absNormalsPos = vecRot * Vector3(ptrNormals + verIndex *3); - + for (int j=0; j<3; j++) (ptrNormals + verIndex*3)[j] = absNormalsPos[j]; } @@ -854,7 +854,7 @@ void NIFLoader::handleNode(Nif::Node *node, int flags, } for (; itrafo, bounds, bone); } @@ -869,7 +869,7 @@ void NIFLoader::handleNode(Nif::Node *node, int flags, Tri Chest */ if((isChest && stack < 10 ) || (isHands && counter < 3) || !(isChest || isHands)){ //(isBeast && isChest && stack < 10 && counter == skincounter ) - + std::string name = node->name.toString(); //if (isChest) //std::cout << "NAME: " << name << "\n"; @@ -896,15 +896,15 @@ void NIFLoader::handleNode(Nif::Node *node, int flags, //if(isBeast && isChest) //cout << "Handling Shape, Stack " << stack <<"\n"; - - + + counter++; } /*if(isHands){ //cout << "Handling Shape, Stack " << stack <<"\n"; counter++; }*/ - + } stack--; @@ -925,7 +925,7 @@ void NIFLoader::loadResource(Resource *resource) //std::cout <<"NAME:" << name; //if(name.length() >= 20) // {std::string split = name.substr(name.length() - 20, 20); - //if(name == + //if(name == //std::cout <<"NAME:" << name << "LEN: " << name.length() << "\n"; const std::string test ="meshes\\b\\B_N_Dark Elf_M_Skins.NIF"; const std::string test2 ="meshes\\b\\B_N_Dark Elf_M_Skins.nif"; @@ -953,15 +953,15 @@ void NIFLoader::loadResource(Resource *resource) const std::string test24 ="meshes\\b\\B_N_High Elf_M_Skins.nif"; //std::cout <<"LEN1:" << test.length() << "TEST: " << test << "\n"; - - + + if(name.compare(test) == 0 || name.compare(test2) == 0 || name.compare(test3) == 0 || name.compare(test4) == 0 || name.compare(test5) == 0 || name.compare(test6) == 0 || name.compare(test7) == 0 || name.compare(test8) == 0 || name.compare(test9) == 0 || name.compare(test10) == 0 || name.compare(test11) == 0 || name.compare(test12) == 0 || name.compare(test13) == 0 || name.compare(test14) == 0 || name.compare(test15) == 0 || name.compare(test16) == 0 || name.compare(test17) == 0 || name.compare(test18) == 0 || name.compare(test19) == 0 || name.compare(test20) == 0 || name.compare(test21) == 0 || name.compare(test22) == 0 || name.compare(test23) == 0 || name.compare(test24) == 0 - + ){ //std::cout << "Welcome Chest\n"; isChest = true; @@ -1030,7 +1030,7 @@ void NIFLoader::loadResource(Resource *resource) std::cout << "\n\n\nWelcome FRedguard Chest\n\n\n"; isChest = true; }*/ - + //if(split== "Skins.NIF") // std::cout << "\nSPECIAL PROPS\n"; resourceName = ""; @@ -1102,14 +1102,14 @@ void NIFLoader::loadResource(Resource *resource) // mesh->setSkeletonName(getSkeletonName()); } -MeshPtr NIFLoader::load(const std::string &name, +MeshPtr NIFLoader::load(const std::string &name, const std::string &group) { MeshManager *m = MeshManager::getSingletonPtr(); // Check if the resource already exists ResourcePtr ptr = m->getByName(name, group); MeshPtr resize; - + const std::string beast1 ="meshes\\b\\B_N_Khajiit_F_Skins.nif"; const std::string beast2 ="meshes\\b\\B_N_Khajiit_M_Skins.nif"; const std::string beast3 ="meshes\\b\\B_N_Argonian_F_Skins.nif"; @@ -1120,8 +1120,8 @@ MeshPtr NIFLoader::load(const std::string &name, const std::string beasttail3 ="tail\\b\\B_N_Argonian_F_Skins.nif"; const std::string beasttail4 ="tail\\b\\B_N_Argonian_M_Skins.nif"; - if (!ptr.isNull()){ - + if (!ptr.isNull()){ + //if(pieces > 1) //cout << "It exists\n"; resize = MeshPtr(ptr); @@ -1132,17 +1132,17 @@ MeshPtr NIFLoader::load(const std::string &name, { resize = MeshManager::getSingleton().createManual(name, group, NIFLoader::getSingletonPtr()); //cout <<"EXISTING" << name << "\n"; - + //if(pieces > 1) //cout << "Creating it\n"; - - + + //resize->load(); //resize->reload(); //return 0; ResourcePtr ptr = m->getByName(name, group); resize = MeshPtr(ptr); - + //NIFLoader::getSingletonPtr()-> /*ResourcePtr ptr = m->getByName(name, group); if (!ptr.isNull()){ @@ -1153,7 +1153,7 @@ MeshPtr NIFLoader::load(const std::string &name, } return resize; } - + /* More code currently not in use, from the old D source. This was used in the first attempt at loading NIF meshes, where each submesh diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index fd05ee866..bf8a94266 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -76,11 +76,11 @@ class NIFLoader : Ogre::ManualResourceLoader virtual void loadResource(Ogre::Resource *resource); - static Ogre::MeshPtr load(const std::string &name, + static Ogre::MeshPtr load(const std::string &name, const std::string &group="General"); - + Ogre::Vector3 convertVector3(const Nif::Vector& vec); Ogre::Quaternion convertRotation(const Nif::Matrix& rot); @@ -116,7 +116,7 @@ class NIFLoader : Ogre::ManualResourceLoader { return resourceName + ".skel"; } - + // This is the interface to the Ogre resource system. It allows us to // load NIFs from BSAs, in the file system and in any other place we // tell Ogre to look (eg. in zip or rar files.) It's also used to @@ -134,8 +134,7 @@ class NIFLoader : Ogre::ManualResourceLoader int counter; int numbers; int stack; - - std::multimap MaterialMap; + std::multimap MaterialMap; // pointer to the ogre mesh which is currently build Ogre::Mesh *mesh; diff --git a/components/to_utf8/gen_iconv.cpp b/components/to_utf8/gen_iconv.cpp index cf4d9ac3f..620205245 100644 --- a/components/to_utf8/gen_iconv.cpp +++ b/components/to_utf8/gen_iconv.cpp @@ -88,7 +88,23 @@ int main() // Write namespace cout << "namespace ToUTF8\n{\n\n"; + // Central European and Eastern European languages that use Latin script, such as + // Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian. + cout << "\n/// Central European and Eastern European languages that use Latin script," + "\n/// such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian," + "\n/// Serbian (Latin script), Romanian and Albanian." + "\n"; + write_table("WINDOWS-1250", "windows_1250"); + + // Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages + cout << "\n/// Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic" + "\n/// and other languages" + "\n"; + write_table("WINDOWS-1251", "windows_1251"); + // English + cout << "\n/// Latin alphabet used by English and some other Western languages" + "\n"; write_table("WINDOWS-1252", "windows_1252"); // Close namespace diff --git a/components/to_utf8/tables_gen.hpp b/components/to_utf8/tables_gen.hpp index a45d5d181..79945bddc 100644 --- a/components/to_utf8/tables_gen.hpp +++ b/components/to_utf8/tables_gen.hpp @@ -4,6 +4,533 @@ namespace ToUTF8 { + +/// Central European and Eastern European languages that use Latin script, +/// such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, +/// Serbian (Latin script), Romanian and Albanian. +static char windows_1250[] = +{ + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x8, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x9, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xa, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xb, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xc, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xd, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xe, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xf, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x10, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x11, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x12, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x13, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x14, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x15, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x16, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x17, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x18, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x19, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x21, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x22, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x23, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x24, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x25, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x26, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x27, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x28, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x29, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x30, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x31, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x32, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x33, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x34, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x35, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x36, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x37, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x38, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x39, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x40, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x41, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x42, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x43, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x44, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x45, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x46, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x47, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x48, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x49, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x50, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x51, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x52, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x53, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x54, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x55, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x56, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x57, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x58, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x59, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x60, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x61, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x62, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x63, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x64, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x65, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x66, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x67, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x68, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x69, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x70, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x71, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x72, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x73, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x74, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x75, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x76, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x77, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x78, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x79, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7f, 0x0, 0x0, 0x0, 0x0, + 0x3, 0xe2, 0x82, 0xac, 0x0, 0x0, + 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset + 0x3, 0xe2, 0x80, 0x9a, 0x0, 0x0, + 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset + 0x3, 0xe2, 0x80, 0x9e, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xa6, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xa0, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xa1, 0x0, 0x0, + 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset + 0x3, 0xe2, 0x80, 0xb0, 0x0, 0x0, + 0x2, 0xc5, 0xa0, 0x0, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xb9, 0x0, 0x0, + 0x2, 0xc5, 0x9a, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xa4, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xbd, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xb9, 0x0, 0x0, 0x0, + 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset + 0x3, 0xe2, 0x80, 0x98, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x99, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x9c, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x9d, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xa2, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x93, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x94, 0x0, 0x0, + 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset + 0x3, 0xe2, 0x84, 0xa2, 0x0, 0x0, + 0x2, 0xc5, 0xa1, 0x0, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xba, 0x0, 0x0, + 0x2, 0xc5, 0x9b, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xa5, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xbe, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xba, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa0, 0x0, 0x0, 0x0, + 0x2, 0xcb, 0x87, 0x0, 0x0, 0x0, + 0x2, 0xcb, 0x98, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x81, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa4, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x84, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa6, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa7, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa8, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa9, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x9e, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xab, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xac, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xad, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xae, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xbb, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb0, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb1, 0x0, 0x0, 0x0, + 0x2, 0xcb, 0x9b, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x82, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb4, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb5, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb6, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb7, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb8, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x85, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x9f, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xbb, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0xbd, 0x0, 0x0, 0x0, + 0x2, 0xcb, 0x9d, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0xbe, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xbc, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x94, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x81, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x82, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x82, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x84, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0xb9, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x86, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x87, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x8c, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x89, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x98, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x8b, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x9a, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x8d, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x8e, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x8e, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x90, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x83, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x87, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x93, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x94, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x90, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x96, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x97, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x98, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xae, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x9a, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xb0, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x9c, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x9d, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xa2, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0x9f, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x95, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xa1, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xa2, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x83, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xa4, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0xba, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x87, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xa7, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x8d, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xa9, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x99, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xab, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x9b, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xad, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xae, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x8f, 0x0, 0x0, 0x0, + 0x2, 0xc4, 0x91, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x84, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x88, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xb3, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xb4, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x91, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xb6, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xb7, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0x99, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xaf, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xba, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xb1, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xbc, 0x0, 0x0, 0x0, + 0x2, 0xc3, 0xbd, 0x0, 0x0, 0x0, + 0x2, 0xc5, 0xa3, 0x0, 0x0, 0x0, + 0x2, 0xcb, 0x99, 0x0, 0x0, 0x0 +}; + +/// Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic +/// and other languages +static char windows_1251[] = +{ + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x8, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x9, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xa, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xb, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xc, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xd, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xe, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xf, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x10, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x11, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x12, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x13, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x14, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x15, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x16, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x17, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x18, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x19, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x1f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x21, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x22, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x23, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x24, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x25, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x26, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x27, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x28, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x29, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x2f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x30, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x31, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x32, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x33, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x34, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x35, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x36, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x37, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x38, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x39, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x3f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x40, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x41, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x42, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x43, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x44, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x45, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x46, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x47, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x48, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x49, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x4f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x50, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x51, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x52, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x53, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x54, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x55, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x56, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x57, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x58, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x59, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x5f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x60, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x61, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x62, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x63, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x64, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x65, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x66, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x67, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x68, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x69, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x6f, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x70, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x71, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x72, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x73, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x74, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x75, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x76, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x77, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x78, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x79, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7a, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7b, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7c, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7d, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7e, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x7f, 0x0, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x82, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x83, 0x0, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x9a, 0x0, 0x0, + 0x2, 0xd1, 0x93, 0x0, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x9e, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xa6, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xa0, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xa1, 0x0, 0x0, + 0x3, 0xe2, 0x82, 0xac, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xb0, 0x0, 0x0, + 0x2, 0xd0, 0x89, 0x0, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xb9, 0x0, 0x0, + 0x2, 0xd0, 0x8a, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x8c, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x8b, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x8f, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x92, 0x0, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x98, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x99, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x9c, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x9d, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xa2, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x93, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0x94, 0x0, 0x0, + 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset + 0x3, 0xe2, 0x84, 0xa2, 0x0, 0x0, + 0x2, 0xd1, 0x99, 0x0, 0x0, 0x0, + 0x3, 0xe2, 0x80, 0xba, 0x0, 0x0, + 0x2, 0xd1, 0x9a, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x9c, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x9b, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x9f, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa0, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x8e, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x9e, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x88, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa4, 0x0, 0x0, 0x0, + 0x2, 0xd2, 0x90, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa6, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa7, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x81, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xa9, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x84, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xab, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xac, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xad, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xae, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x87, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb0, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb1, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x86, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x96, 0x0, 0x0, 0x0, + 0x2, 0xd2, 0x91, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb5, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb6, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xb7, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x91, 0x0, 0x0, 0x0, + 0x3, 0xe2, 0x84, 0x96, 0x0, 0x0, + 0x2, 0xd1, 0x94, 0x0, 0x0, 0x0, + 0x2, 0xc2, 0xbb, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x98, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x85, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x95, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x97, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x90, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x91, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x92, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x93, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x94, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x95, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x96, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x97, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x98, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x99, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x9a, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x9b, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x9c, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x9d, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x9e, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0x9f, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xa0, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xa1, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xa2, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xa3, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xa4, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xa5, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xa6, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xa7, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xa8, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xa9, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xaa, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xab, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xac, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xad, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xae, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xaf, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xb0, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xb1, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xb2, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xb3, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xb4, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xb5, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xb6, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xb7, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xb8, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xb9, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xba, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xbb, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xbc, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xbd, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xbe, 0x0, 0x0, 0x0, + 0x2, 0xd0, 0xbf, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x80, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x81, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x82, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x83, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x84, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x85, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x86, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x87, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x88, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x89, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x8a, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x8b, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x8c, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x8d, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x8e, 0x0, 0x0, 0x0, + 0x2, 0xd1, 0x8f, 0x0, 0x0, 0x0 +}; + +/// Latin alphabet used by English and some other Western languages static char windows_1252[] = { 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 5f38313aa..3fbbeb733 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -130,10 +130,28 @@ std::string ToUTF8::getUtf8(ToUTF8::FromType from) { // Pick translation array const char *arr; - if(from == ToUTF8::WINDOWS_1252) - arr = ToUTF8::windows_1252; - else - assert(0); + switch (from) + { + case ToUTF8::WINDOWS_1252: + { + 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 diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index ec2231be7..4cbee1019 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -8,8 +8,10 @@ namespace ToUTF8 // These are all the currently supported code pages enum FromType { - 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 diff --git a/extern/mygui_3.0.1/CMakeLists.txt b/extern/mygui_3.0.1/CMakeLists.txt index d7e0bd483..6e54d1adc 100644 --- a/extern/mygui_3.0.1/CMakeLists.txt +++ b/extern/mygui_3.0.1/CMakeLists.txt @@ -64,6 +64,8 @@ configure_file("${SDIR}/openmw_progress.skin.xml" "${DDIR}/openmw_progress.skin. configure_file("${SDIR}/openmw_stats_window_layout.xml" "${DDIR}/openmw_stats_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_text.skin.xml" "${DDIR}/openmw_text.skin.xml" COPYONLY) configure_file("${SDIR}/openmw_windows.skin.xml" "${DDIR}/openmw_windows.skin.xml" COPYONLY) +configure_file("${SDIR}/openmw_messagebox_layout.xml" "${DDIR}/openmw_messagebox_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_interactive_messagebox_layout.xml" "${DDIR}/openmw_interactive_messagebox_layout.xml" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) configure_file("${SDIR}/VeraMono.ttf" "${DDIR}/VeraMono.ttf" COPYONLY) diff --git a/extern/mygui_3.0.1/openmw_resources/openmw.font.xml b/extern/mygui_3.0.1/openmw_resources/openmw.font.xml index 5e283c549..76f164bcb 100644 --- a/extern/mygui_3.0.1/openmw_resources/openmw.font.xml +++ b/extern/mygui_3.0.1/openmw_resources/openmw.font.xml @@ -2,8 +2,9 @@ - + + @@ -11,15 +12,16 @@ - - + + - + + diff --git a/extern/mygui_3.0.1/openmw_resources/openmw_interactive_messagebox_layout.xml b/extern/mygui_3.0.1/openmw_resources/openmw_interactive_messagebox_layout.xml new file mode 100644 index 000000000..40c0787b8 --- /dev/null +++ b/extern/mygui_3.0.1/openmw_resources/openmw_interactive_messagebox_layout.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/extern/mygui_3.0.1/openmw_resources/openmw_messagebox_layout.xml b/extern/mygui_3.0.1/openmw_resources/openmw_messagebox_layout.xml new file mode 100644 index 000000000..890752db3 --- /dev/null +++ b/extern/mygui_3.0.1/openmw_resources/openmw_messagebox_layout.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + +