From 4dcaf040e670809af60a8c915b0ff113e8dd4641 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 4 Aug 2017 20:21:13 +0400 Subject: [PATCH 01/18] A Russian journal index --- apps/openmw/mwgui/journalbooks.cpp | 14 ++++++++------ apps/openmw/mwgui/journalviewmodel.cpp | 24 +++++++++++++++++++++--- apps/openmw/mwgui/journalviewmodel.hpp | 4 ++-- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 5634eb080..19a2a9afe 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -224,20 +224,22 @@ book JournalBooks::createTopicIndexBook () BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); - for (int i = 0; i < 26; ++i) + for (int i = 0; i < 32; ++i) { - char ch = 'A' + i; - char buffer [32]; - sprintf (buffer, "( %c )", ch); + sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, ch); + textColours.journalTopicPressed, i+1); + + // Words can not be started with these characters + if (i == 26 || i == 28) + continue; - if (i == 13) + if (i == 15) typesetter->sectionBreak (); typesetter->write (style, to_utf8_span (buffer)); diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index b5d08eec6..02103280b 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -305,18 +305,36 @@ struct JournalViewModelImpl : JournalViewModel visitor (toUtf8Span (topic.getName())); } - void visitTopicNamesStartingWith (char character, std::function < void (const std::string&) > visitor) const + void visitTopicNamesStartingWith (int index, std::function < void (const std::string&) > visitor) const { MWBase::Journal * journal = MWBase::Environment::get().getJournal(); for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - if (i->first [0] != Misc::StringUtils::toLower(character)) + if (i->first.length() < 2) + continue; + + unsigned char byte1 = i->first[0]; + unsigned char byte2 = i->first[1]; + + // Upper case + if (byte1 == 0xd0 && byte2 >= 0xb0 && byte2 < 0xc0) + byte2 -= 32; + + if (byte1 == 0xd1 && byte2 >= 0x80 && byte2 < 0x90) + { + byte1 -= 1; + byte2 += 32; + } + + // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + // so we can use 0xd08f + index + // (index is a position of letter in alphabet, begins from 1) + if (byte1 != 0xd0 || byte2 != 0x8f + index) continue; visitor (i->second.getName()); } - } struct TopicEntryImpl : BaseEntry diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 3edde3d31..88f8acd55 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -75,8 +75,8 @@ namespace MWGui /// provides the name of the topic specified by its id virtual void visitTopicName (TopicId topicId, std::function visitor) const = 0; - /// walks over the topics whose names start with the specified character providing the topics name - virtual void visitTopicNamesStartingWith (char character, std::function < void (const std::string&) > visitor) const = 0; + /// walks over the topics whose names start with the character, specified by its index in the alphabet, providing the topics name + virtual void visitTopicNamesStartingWith (int index, std::function < void (const std::string&) > visitor) const = 0; /// walks over the topic entries for the topic specified by its identifier virtual void visitTopicEntries (TopicId topicId, std::function visitor) const = 0; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 105f95085..b4279e03d 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -431,7 +431,7 @@ namespace MWBase::Environment::get().getWindowManager()->playSound("book page"); } - void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId character) + void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId index) { setVisible (LeftTopicIndex, false); setVisible (RightTopicIndex, false); @@ -444,7 +444,7 @@ namespace AddNamesToList add(list); - mModel->visitTopicNamesStartingWith((char) character, add); + mModel->visitTopicNamesStartingWith(index, add); list->adjustSize(); From a391990f2a52695b3c56afedaea5ffb80581f1e4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Nov 2017 21:30:46 +0400 Subject: [PATCH 02/18] Provide multibyte toLower() and single chars comparator --- apps/openmw/mwgui/journalviewmodel.cpp | 46 ++++++++++++++++---------- components/misc/stringops.hpp | 30 +++++++++++++++++ 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 02103280b..33935f040 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -311,29 +311,39 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - if (i->first.length() < 2) - continue; - unsigned char byte1 = i->first[0]; - unsigned char byte2 = i->first[1]; + // First, check for two-byte UTF-8 symbols, e.g. Cyrillic ones + // TODO: check which language journal index is using + if ((byte1 == 0xd0 || byte1 == 0xd1) && i->first.length() >= 2) + { + unsigned char byte2 = i->first[1]; - // Upper case - if (byte1 == 0xd0 && byte2 >= 0xb0 && byte2 < 0xc0) - byte2 -= 32; + std::pair symbol = Misc::StringUtils::toLower(byte1, byte2); - if (byte1 == 0xd1 && byte2 >= 0x80 && byte2 < 0x90) - { - byte1 -= 1; - byte2 += 32; - } + // CYRILLIC LETTER A - CYRILLIC LETTER PE + // index from 1 to 16 + if (symbol.first == 0xd0 && symbol.second >= (0xaf + index) && symbol.second < (0xbf + index) && symbol.second == (0xaf + index)) + { + visitor (i->second.getName()); + continue; + } - // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 - // so we can use 0xd08f + index - // (index is a position of letter in alphabet, begins from 1) - if (byte1 != 0xd0 || byte2 != 0x8f + index) - continue; + // CYRILLIC LETTERL R - CYRILLIC LETTER YA + // index from 17 to 32 + if (symbol.first == 0xd1 && symbol.second >= (0x6f + index) && symbol.second < (0x7f + index) && symbol.second == (0x6f + index)) + { + visitor (i->second.getName()); + continue; + } + } + else + { + // Otherwise check for regular Latin symbols, 0x61 = 'a' + if (i->first [0] != 0x60 + index) + continue; - visitor (i->second.getName()); + visitor (i->second.getName()); + } } } diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 9acd81710..97865a44c 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -55,6 +55,36 @@ public: }; } + static std::pair toLower(unsigned char byte1, unsigned char byte2) + { + std::pair symbol = std::make_pair(byte1, byte2); + // CYRILLIC CAPITAL IO + if (symbol.first == 0xd0 && symbol.second == 0x01) + { + symbol.first++; + symbol.second = 0x91; + } + // CYRILLIC CAPITAL A - CYRILLIC CAPITAL PE + else if (symbol.first == 0xd0 && symbol.second >= 0x90 && symbol.second < 0xa0) + { + symbol.second += 0x20; + } + // CYRILLIC CAPITAL R - CYRILLIC CAPITAL YA + else if (symbol.first == 0xd0 && symbol.second >= 0xa0 && symbol.second < 0xb0) + { + symbol.first++; + symbol.second -= 0x20; + } + // Other symbols + else + { + symbol.first = toLower(symbol.first); + symbol.second = toLower(symbol.second); + } + + return symbol; + } + static bool ciLess(const std::string &x, const std::string &y) { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); } From ce5bdd636183691ea7187698cb370cbf154bf522 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Nov 2017 22:25:53 +0400 Subject: [PATCH 03/18] Split the JournalBooks::createTopicIndexBook() --- apps/openmw/mwgui/journalbooks.cpp | 44 ++++++++++++++++++++++++++++-- apps/openmw/mwgui/journalbooks.hpp | 2 ++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 19a2a9afe..b4f9147b5 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -217,19 +217,59 @@ book JournalBooks::createQuestBook (const std::string& questName) } book JournalBooks::createTopicIndexBook () +{ + // TODO: determine actual index alphabet + bool isRussian = true; + + BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); + + return typesetter->complete (); +} + +BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () { BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250); typesetter->setSectionAlignment (BookTypesetter::AlignCenter); - BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); + for (int i = 0; i < 26; ++i) + { + char ch = 'A' + i; + char buffer [32]; + + sprintf (buffer, "( %c )", ch); + + // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) + const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); + BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, + textColours.journalTopicOver, + textColours.journalTopicPressed, i+1); + if (i == 13) + typesetter->sectionBreak (); + + typesetter->write (style, to_utf8_span (buffer)); + typesetter->lineBreak (); + } + + return typesetter; +} + +BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () +{ + BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250); + + typesetter->setSectionAlignment (BookTypesetter::AlignCenter); + + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); for (int i = 0; i < 32; ++i) { char buffer [32]; sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, @@ -246,7 +286,7 @@ book JournalBooks::createTopicIndexBook () typesetter->lineBreak (); } - return typesetter->complete (); + return typesetter; } BookTypesetter::Ptr JournalBooks::createTypesetter () diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 8f87825f0..769f05823 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -24,6 +24,8 @@ namespace MWGui private: BookTypesetter::Ptr createTypesetter (); + BookTypesetter::Ptr createLatinJournalIndex (); + BookTypesetter::Ptr createCyrillicJournalIndex (); }; } From a83a43e37613667b956752be5f1fff049ca959ce Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 09:32:35 +0400 Subject: [PATCH 04/18] Determine when need to use the Cyrillic journal index --- apps/openmw/mwbase/windowmanager.hpp | 3 +++ apps/openmw/mwgui/journalbooks.cpp | 6 ++++-- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 416a7ad87..ffcbe0502 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -9,6 +9,8 @@ #include "../mwgui/mode.hpp" +#include + namespace Loading { class Listener; @@ -365,6 +367,7 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; + virtual ToUTF8::FromType getEncoding() = 0; }; } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index b4f9147b5..73796c381 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -5,6 +5,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include + #include "textcolours.hpp" @@ -218,8 +220,8 @@ book JournalBooks::createQuestBook (const std::string& questName) book JournalBooks::createTopicIndexBook () { - // TODO: determine actual index alphabet - bool isRussian = true; + ToUTF8::FromType encoding = MWBase::Environment::get().getWindowManager()->getEncoding(); + bool isRussian = (encoding == ToUTF8::WINDOWS_1251); BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 97aedab81..920b8c1ac 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -205,6 +205,7 @@ namespace MWGui , mRestAllowed(true) , mFallbackMap(fallbackMap) , mShowOwned(0) + , mEncoding(encoding) , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); @@ -2174,4 +2175,8 @@ namespace MWGui return mTextColours; } + ToUTF8::FromType WindowManager::getEncoding() + { + return mEncoding; + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f74ba21a3..a1ec7cdb4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -393,6 +393,7 @@ namespace MWGui void writeFog(MWWorld::CellStore* cell); virtual const MWGui::TextColours& getTextColours(); + virtual ToUTF8::FromType getEncoding(); private: const MWWorld::ESMStore* mStore; @@ -515,6 +516,8 @@ namespace MWGui int mShowOwned; + ToUTF8::FromType mEncoding; + std::string mVersionDescription; MWGui::TextColours mTextColours; From ba91cd658b019dbf1ee93c4185333687c3e086a7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 12:31:23 +0400 Subject: [PATCH 05/18] Convert topic name to Unicode --- apps/openmw/mwgui/journalbooks.cpp | 19 +++++++++--- apps/openmw/mwgui/journalviewmodel.cpp | 41 ++++++-------------------- apps/openmw/mwgui/journalviewmodel.hpp | 4 +-- components/misc/stringops.hpp | 39 ++++++++---------------- 4 files changed, 39 insertions(+), 64 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 49c1aa972..3b1463b45 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -6,10 +6,10 @@ #include "../mwbase/windowmanager.hpp" #include +#include #include "textcolours.hpp" - namespace { struct AddContent @@ -242,11 +242,17 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () sprintf (buffer, "( %c )", ch); + char buffer2 [32]; + sprintf(buffer2, "%c", ch); + const char * c = buffer2; + Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + uint32_t first = stream.peek(); + // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, i+1); + textColours.journalTopicPressed, first); if (i == 13) typesetter->sectionBreak (); @@ -271,11 +277,16 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 - // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) + char buffer2 [32]; + sprintf(buffer2, "%c%c", 0xd0, 0x90 + i); + const char * c = buffer2; + Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + uint32_t first = stream.peek(); + const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, i+1); + textColours.journalTopicPressed, first); // Words can not be started with these characters if (i == 26 || i == 28) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 33935f040..3f8992e31 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" @@ -305,45 +307,20 @@ struct JournalViewModelImpl : JournalViewModel visitor (toUtf8Span (topic.getName())); } - void visitTopicNamesStartingWith (int index, std::function < void (const std::string&) > visitor) const + void visitTopicNamesStartingWith (uint32_t character, std::function < void (const std::string&) > visitor) const { MWBase::Journal * journal = MWBase::Environment::get().getJournal(); for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - unsigned char byte1 = i->first[0]; - // First, check for two-byte UTF-8 symbols, e.g. Cyrillic ones - // TODO: check which language journal index is using - if ((byte1 == 0xd0 || byte1 == 0xd1) && i->first.length() >= 2) - { - unsigned char byte2 = i->first[1]; - - std::pair symbol = Misc::StringUtils::toLower(byte1, byte2); - - // CYRILLIC LETTER A - CYRILLIC LETTER PE - // index from 1 to 16 - if (symbol.first == 0xd0 && symbol.second >= (0xaf + index) && symbol.second < (0xbf + index) && symbol.second == (0xaf + index)) - { - visitor (i->second.getName()); - continue; - } + const char * c = i->first.c_str(); + Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + uint32_t first = Misc::StringUtils::toUpper(stream.peek()); - // CYRILLIC LETTERL R - CYRILLIC LETTER YA - // index from 17 to 32 - if (symbol.first == 0xd1 && symbol.second >= (0x6f + index) && symbol.second < (0x7f + index) && symbol.second == (0x6f + index)) - { - visitor (i->second.getName()); - continue; - } - } - else - { - // Otherwise check for regular Latin symbols, 0x61 = 'a' - if (i->first [0] != 0x60 + index) - continue; + if (first != character) + continue; - visitor (i->second.getName()); - } + visitor (i->second.getName()); } } diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 88f8acd55..01dcb49de 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -75,8 +75,8 @@ namespace MWGui /// provides the name of the topic specified by its id virtual void visitTopicName (TopicId topicId, std::function visitor) const = 0; - /// walks over the topics whose names start with the character, specified by its index in the alphabet, providing the topics name - virtual void visitTopicNamesStartingWith (int index, std::function < void (const std::string&) > visitor) const = 0; + /// walks over the topics whose names start with the character + virtual void visitTopicNamesStartingWith (uint32_t character, std::function < void (const std::string&) > visitor) const = 0; /// walks over the topic entries for the topic specified by its identifier virtual void visitTopicEntries (TopicId topicId, std::function visitor) const = 0; diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 0d9c2489f..5ce5360d1 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -56,34 +56,21 @@ public: }; } - static std::pair toLower(unsigned char byte1, unsigned char byte2) + static uint32_t toUpper(uint32_t ch) { - std::pair symbol = std::make_pair(byte1, byte2); - // CYRILLIC CAPITAL IO - if (symbol.first == 0xd0 && symbol.second == 0x01) - { - symbol.first++; - symbol.second = 0x91; - } - // CYRILLIC CAPITAL A - CYRILLIC CAPITAL PE - else if (symbol.first == 0xd0 && symbol.second >= 0x90 && symbol.second < 0xa0) - { - symbol.second += 0x20; - } - // CYRILLIC CAPITAL R - CYRILLIC CAPITAL YA - else if (symbol.first == 0xd0 && symbol.second >= 0xa0 && symbol.second < 0xb0) - { - symbol.first++; - symbol.second -= 0x20; - } - // Other symbols - else - { - symbol.first = toLower(symbol.first); - symbol.second = toLower(symbol.second); - } + // Russian alphabete + if (ch >= 0x0430 && ch < 0x0450) + ch -= 0x20; + + // Cyrillic YO character + if (ch == 0x0451) + ch -= 0x50; + + // Latin alphabete + if (ch >= 0x61 && ch < 0x80) + ch -= 0x20; - return symbol; + return ch; } static bool ciLess(const std::string &x, const std::string &y) { From 5f41f7c48df215f160a9418dd39595c954370cf8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 12:59:47 +0400 Subject: [PATCH 06/18] Clean code up a bit --- apps/openmw/mwgui/journalbooks.cpp | 10 +++------- apps/openmw/mwgui/journalviewmodel.cpp | 3 +-- components/misc/stringops.hpp | 4 ++-- components/misc/utf8stream.hpp | 5 +++++ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 3b1463b45..68b1d8403 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -239,16 +239,13 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () { char ch = 'A' + i; char buffer [32]; - sprintf (buffer, "( %c )", ch); char buffer2 [32]; sprintf(buffer2, "%c", ch); - const char * c = buffer2; - Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + Utf8Stream stream (buffer2); uint32_t first = stream.peek(); - // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, @@ -274,13 +271,12 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () for (int i = 0; i < 32; ++i) { char buffer [32]; - sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 char buffer2 [32]; sprintf(buffer2, "%c%c", 0xd0, 0x90 + i); - const char * c = buffer2; - Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + + Utf8Stream stream (buffer2); uint32_t first = stream.peek(); const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 3f8992e31..d7b233ff3 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -313,8 +313,7 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - const char * c = i->first.c_str(); - Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + Utf8Stream stream (i->first.c_str()); uint32_t first = Misc::StringUtils::toUpper(stream.peek()); if (first != character) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 5ce5360d1..cec2a34a4 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -58,7 +58,7 @@ public: static uint32_t toUpper(uint32_t ch) { - // Russian alphabete + // Russian alphabet if (ch >= 0x0430 && ch < 0x0450) ch -= 0x20; @@ -66,7 +66,7 @@ public: if (ch == 0x0451) ch -= 0x50; - // Latin alphabete + // Latin alphabet if (ch >= 0x61 && ch < 0x80) ch -= 0x20; diff --git a/components/misc/utf8stream.hpp b/components/misc/utf8stream.hpp index 760015902..368374a64 100644 --- a/components/misc/utf8stream.hpp +++ b/components/misc/utf8stream.hpp @@ -18,6 +18,11 @@ public: { } + Utf8Stream (const char * str) : + cur ((unsigned char*) str), nxt ((unsigned char*) str), end ((unsigned char*) str + strlen(str)), val(Utf8Stream::sBadChar()) + { + } + Utf8Stream (std::pair range) : cur (range.first), nxt (range.first), end (range.second), val(Utf8Stream::sBadChar()) { From 67acb83b62861e865c0fd04ff19f8922ed74c8e7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 13:27:33 +0400 Subject: [PATCH 07/18] Add missing include --- components/misc/stringops.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index cec2a34a4..1edb5ea61 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,6 +1,7 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H +#include #include #include #include From 3571f7f41379833848467c50c0ef1879c105a68c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 22 Nov 2017 08:32:38 +0400 Subject: [PATCH 08/18] Remove getEncoding() from WindowManager --- apps/openmw/mwbase/windowmanager.hpp | 1 - apps/openmw/mwgui/journalbooks.cpp | 7 +++---- apps/openmw/mwgui/journalbooks.hpp | 6 +++++- apps/openmw/mwgui/journalwindow.cpp | 8 ++++---- apps/openmw/mwgui/journalwindow.hpp | 4 +++- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +------ apps/openmw/mwgui/windowmanagerimp.hpp | 1 - 7 files changed, 16 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4a346a14f..6c866fbc2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -351,7 +351,6 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; - virtual ToUTF8::FromType getEncoding() = 0; virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0; }; } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 68b1d8403..07dacd0c2 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -156,8 +156,8 @@ MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text) typedef TypesetBook::Ptr book; -JournalBooks::JournalBooks (JournalViewModel::Ptr model) : - mModel (model) +JournalBooks::JournalBooks (JournalViewModel::Ptr model, ToUTF8::FromType encoding) : + mModel (model), mEncoding(encoding) { } @@ -220,8 +220,7 @@ book JournalBooks::createQuestBook (const std::string& questName) book JournalBooks::createTopicIndexBook () { - ToUTF8::FromType encoding = MWBase::Environment::get().getWindowManager()->getEncoding(); - bool isRussian = (encoding == ToUTF8::WINDOWS_1251); + bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251); BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 769f05823..aa36eecdf 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -4,6 +4,8 @@ #include "bookpage.hpp" #include "journalviewmodel.hpp" +#include + namespace MWGui { MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text); @@ -13,7 +15,7 @@ namespace MWGui typedef TypesetBook::Ptr Book; JournalViewModel::Ptr mModel; - JournalBooks (JournalViewModel::Ptr model); + JournalBooks (JournalViewModel::Ptr model, ToUTF8::FromType encoding); Book createEmptyJournalBook (); Book createJournalBook (); @@ -22,6 +24,8 @@ namespace MWGui Book createQuestBook (const std::string& questName); Book createTopicIndexBook (); + ToUTF8::FromType mEncoding; + private: BookTypesetter::Ptr createTypesetter (); BookTypesetter::Ptr createLatinJournalIndex (); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3c3205d91..a26f8d4ec 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -100,8 +100,8 @@ namespace return getWidget (name); } - JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) - : JournalBooks (Model), JournalWindow() + JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList, ToUTF8::FromType encoding) + : JournalBooks (Model, encoding), JournalWindow() { center(); @@ -643,9 +643,9 @@ namespace } // glue the implementation to the interface -MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model, bool questList) +MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model, bool questList, ToUTF8::FromType encoding) { - return new JournalWindowImpl (Model, questList); + return new JournalWindowImpl (Model, questList, encoding); } MWGui::JournalWindow::JournalWindow() diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index c9bf0ef0a..62080f72e 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -3,6 +3,8 @@ #include "windowbase.hpp" +#include + #include namespace MWBase { class WindowManager; } @@ -16,7 +18,7 @@ namespace MWGui JournalWindow(); /// construct a new instance of the one JournalWindow implementation - static JournalWindow * create (std::shared_ptr Model, bool questList); + static JournalWindow * create (std::shared_ptr Model, bool questList, ToUTF8::FromType encoding); /// destroy this instance of the JournalWindow implementation virtual ~JournalWindow () {}; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c302313f2..2084786b3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -347,7 +347,7 @@ namespace MWGui mGuiModeStates[GM_Console] = GuiModeState(mConsole); bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); - JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList); + JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList, mEncoding); mWindows.push_back(journal); mGuiModeStates[GM_Journal] = GuiModeState(journal); mGuiModeStates[GM_Journal].mCloseSound = "book close"; @@ -2034,11 +2034,6 @@ namespace MWGui return mTextColours; } - ToUTF8::FromType WindowManager::getEncoding() - { - return mEncoding; - } - bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text) { if (!mKeyboardNavigation->injectKeyPress(key, text)) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a264128b3..1d250f6d4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -378,7 +378,6 @@ namespace MWGui void writeFog(MWWorld::CellStore* cell); virtual const MWGui::TextColours& getTextColours(); - virtual ToUTF8::FromType getEncoding(); virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); From 86a17b1e3ed68cab4114bb14ea8307774f646f12 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 22 Nov 2017 09:06:54 +0400 Subject: [PATCH 09/18] Get rid of the redundant Utf8Stream when during journal index creation --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/journalbooks.cpp | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 6c866fbc2..f2b4a526d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -351,6 +351,7 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0; }; } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 07dacd0c2..f3ee8162e 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -233,28 +233,26 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () typesetter->setSectionAlignment (BookTypesetter::AlignCenter); + char ch = 'A'; + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); for (int i = 0; i < 26; ++i) { - char ch = 'A' + i; char buffer [32]; sprintf (buffer, "( %c )", ch); - char buffer2 [32]; - sprintf(buffer2, "%c", ch); - Utf8Stream stream (buffer2); - uint32_t first = stream.peek(); - const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, first); + textColours.journalTopicPressed, (uint32_t) ch); if (i == 13) typesetter->sectionBreak (); typesetter->write (style, to_utf8_span (buffer)); typesetter->lineBreak (); + + ch++; } return typesetter; @@ -267,15 +265,15 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () typesetter->setSectionAlignment (BookTypesetter::AlignCenter); BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); + + unsigned char ch[2] = {0xd0, 0x90}; // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + for (int i = 0; i < 32; ++i) { char buffer [32]; - sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + sprintf(buffer, "( %c%c )", ch[0], ch[1]); - char buffer2 [32]; - sprintf(buffer2, "%c%c", 0xd0, 0x90 + i); - - Utf8Stream stream (buffer2); + Utf8Stream stream ((char*) ch); uint32_t first = stream.peek(); const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); @@ -292,6 +290,8 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () typesetter->write (style, to_utf8_span (buffer)); typesetter->lineBreak (); + + ch[1]++; } return typesetter; From de42aa9d03842bc1c84acd76985a36261afd339d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 00:32:22 +0100 Subject: [PATCH 10/18] Make thrown projectiles rotate --- apps/openmw/mwworld/projectilemanager.cpp | 17 ++++++++++++++++- apps/openmw/mwworld/projectilemanager.hpp | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index ede8c34c4..1d53c1909 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -316,6 +316,8 @@ namespace MWWorld state.mIdArrow = projectile.getCellRef().getRefId(); state.mCasterHandle = actor; state.mAttackStrength = attackStrength; + state.mThrown = projectile.get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown; + state.mTime = 0.0; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); @@ -453,12 +455,25 @@ namespace MWWorld // gravity constant - must be way lower than the gravity affecting actors, since we're not // simulating aerodynamics at all it->mVelocity -= osg::Vec3f(0, 0, 627.2f * 0.1f) * duration; + it->mTime += duration; osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + it->mVelocity * duration; osg::Quat orient; - orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); + + orient.set( + osg::Matrixd::rotate(it->mThrown ? -1 * it->mTime : 0.0,osg::Vec3f(0,0,1)) * + osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * + osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * + osg::Matrixd::inverse( + osg::Matrixd::lookAt( + osg::Vec3f(0,0,0), + it->mVelocity, + osg::Vec3f(0,0,1)) + ) + ); + it->mNode->setAttitude(orient); it->mNode->setPosition(newPos); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 0dfbf6080..1e0de4dbe 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -112,6 +112,8 @@ namespace MWWorld osg::Vec3f mVelocity; float mAttackStrength; + float mTime; + bool mThrown; }; std::vector mMagicBolts; From 4d384889af728c2ba76b3ef1aeb589bbbe29f999 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 10:14:45 +0400 Subject: [PATCH 11/18] Fix the Topics button position if the Tribunal is not installed --- apps/openmw/mwgui/journalwindow.cpp | 52 +++++++++++++++-------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3fbe44f95..3dc583ac2 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -161,6 +161,15 @@ namespace Gui::ImageButton* showActiveButton = getWidget(ShowActiveBTN); Gui::ImageButton* showAllButton = getWidget(ShowAllBTN); Gui::ImageButton* questsButton = getWidget(QuestsBTN); + + Gui::ImageButton* nextButton = getWidget(NextPageBTN); + if (nextButton->getSize().width == 64) + { + // english button has a 7 pixel wide strip of garbage on its right edge + nextButton->setSize(64-7, nextButton->getSize().height); + nextButton->setImageCoord(MyGUI::IntCoord(0,0,64-7,nextButton->getSize().height)); + } + if (!questList) { // If tribunal is not installed (-> no options button), we still want the Topics button available, @@ -176,6 +185,8 @@ namespace showActiveButton->setVisible(false); showAllButton->setVisible(false); questsButton->setVisible(false); + + adjustButton(TopicsBTN); } else { @@ -188,33 +199,24 @@ namespace adjustButton(ShowActiveBTN); adjustButton(OptionsBTN); adjustButton(QuestsBTN); - } - - Gui::ImageButton* nextButton = getWidget(NextPageBTN); - if (nextButton->getSize().width == 64) - { - // english button has a 7 pixel wide strip of garbage on its right edge - nextButton->setSize(64-7, nextButton->getSize().height); - nextButton->setImageCoord(MyGUI::IntCoord(0,0,64-7,nextButton->getSize().height)); - } - - adjustButton(TopicsBTN); - int topicsWidth = getWidget(TopicsBTN)->getSize().width; - int cancelLeft = getWidget(CancelBTN)->getPosition().left; - int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; + adjustButton(TopicsBTN); + int topicsWidth = getWidget(TopicsBTN)->getSize().width; + int cancelLeft = getWidget(CancelBTN)->getPosition().left; + int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; - getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); + getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); - // Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button. - // But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button. - if (getWidget(TopicsBTN)->getSize().width == 64) - { - getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); - } - else - { - int questLeft = getWidget(QuestsBTN)->getPosition().left; - getWidget(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + // Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button. + // But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button. + if (topicsWidth == 64) + { + getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } + else + { + int questLeft = getWidget(QuestsBTN)->getPosition().left; + getWidget(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } } mQuestMode = false; From 2b9a0a77328d69b215cf4ad0fb51f28944407b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 12:11:26 +0100 Subject: [PATCH 12/18] Save new projectile state --- apps/openmw/mwworld/projectilemanager.cpp | 5 +++++ components/esm/projectilestate.cpp | 8 ++++++++ components/esm/projectilestate.hpp | 2 ++ 3 files changed, 15 insertions(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 1d53c1909..1c080aec1 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -567,6 +567,9 @@ namespace MWWorld state.mVelocity = it->mVelocity; state.mAttackStrength = it->mAttackStrength; + state.mThrown = it->mThrown; + state.mTime = it->mTime; + state.save(writer); writer.endRecord(ESM::REC_PROJ); @@ -604,6 +607,8 @@ namespace MWWorld state.mVelocity = esm.mVelocity; state.mIdArrow = esm.mId; state.mAttackStrength = esm.mAttackStrength; + state.mThrown = esm.mThrown; + state.mTime = esm.mTime; std::string model; try diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 8ade9d5b2..1c8a10bcb 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -52,6 +52,8 @@ namespace ESM esm.writeHNString ("BOW_", mBowId); esm.writeHNT ("VEL_", mVelocity); esm.writeHNT ("STR_", mAttackStrength); + esm.writeHNT ("THR_", mThrown); + esm.writeHNT ("TIM_", mTime); } void ProjectileState::load(ESMReader &esm) @@ -63,6 +65,12 @@ namespace ESM mAttackStrength = 1.f; esm.getHNOT(mAttackStrength, "STR_"); + + mThrown = false; + esm.getHNOT (mThrown, "THR_"); + + mTime = 0.f; + esm.getHNOT (mTime, "TIM_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 67ec89bb6..625d34b6a 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -42,6 +42,8 @@ namespace ESM std::string mBowId; Vector3 mVelocity; float mAttackStrength; + float mTime; + bool mThrown; void load (ESMReader &esm); void save (ESMWriter &esm) const; From 3dbcda6686deb5fd31d0a1992eb36884b4b369ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 15:14:15 +0100 Subject: [PATCH 13/18] Make use of mEffectAnimationTime for projectile rotation --- apps/openmw/mwworld/projectilemanager.cpp | 6 +----- apps/openmw/mwworld/projectilemanager.hpp | 1 - components/esm/projectilestate.cpp | 4 ---- components/esm/projectilestate.hpp | 1 - 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 1c080aec1..d38931700 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -317,7 +317,6 @@ namespace MWWorld state.mCasterHandle = actor; state.mAttackStrength = attackStrength; state.mThrown = projectile.get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown; - state.mTime = 0.0; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); @@ -455,7 +454,6 @@ namespace MWWorld // gravity constant - must be way lower than the gravity affecting actors, since we're not // simulating aerodynamics at all it->mVelocity -= osg::Vec3f(0, 0, 627.2f * 0.1f) * duration; - it->mTime += duration; osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + it->mVelocity * duration; @@ -463,7 +461,7 @@ namespace MWWorld osg::Quat orient; orient.set( - osg::Matrixd::rotate(it->mThrown ? -1 * it->mTime : 0.0,osg::Vec3f(0,0,1)) * + osg::Matrixd::rotate(it->mThrown ? -1 * it->mEffectAnimationTime->getTime() * 10.0 : 0.0,osg::Vec3f(0,0,1)) * osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * osg::Matrixd::inverse( @@ -568,7 +566,6 @@ namespace MWWorld state.mAttackStrength = it->mAttackStrength; state.mThrown = it->mThrown; - state.mTime = it->mTime; state.save(writer); @@ -608,7 +605,6 @@ namespace MWWorld state.mIdArrow = esm.mId; state.mAttackStrength = esm.mAttackStrength; state.mThrown = esm.mThrown; - state.mTime = esm.mTime; std::string model; try diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 1e0de4dbe..ba2fe7a74 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -112,7 +112,6 @@ namespace MWWorld osg::Vec3f mVelocity; float mAttackStrength; - float mTime; bool mThrown; }; diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 1c8a10bcb..7b6c419f2 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -53,7 +53,6 @@ namespace ESM esm.writeHNT ("VEL_", mVelocity); esm.writeHNT ("STR_", mAttackStrength); esm.writeHNT ("THR_", mThrown); - esm.writeHNT ("TIM_", mTime); } void ProjectileState::load(ESMReader &esm) @@ -68,9 +67,6 @@ namespace ESM mThrown = false; esm.getHNOT (mThrown, "THR_"); - - mTime = 0.f; - esm.getHNOT (mTime, "TIM_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 625d34b6a..c89bb7683 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -42,7 +42,6 @@ namespace ESM std::string mBowId; Vector3 mVelocity; float mAttackStrength; - float mTime; bool mThrown; void load (ESMReader &esm); From a8bf4cdd98fea8bbb05925cc737c8c9e3eb3a63b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 19:29:40 +0400 Subject: [PATCH 14/18] Remove redundant include --- apps/openmw/mwbase/windowmanager.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index f2b4a526d..d454067c8 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -11,8 +11,6 @@ #include "../mwgui/mode.hpp" -#include - namespace Loading { class Listener; From 94c0e3ed10dd58b122ddecb4192b19365e8befe8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 19:37:45 +0400 Subject: [PATCH 15/18] Move toUpper() from StringUtils to the JournalViewModel --- apps/openmw/mwgui/journalviewmodel.cpp | 19 ++++++++++++++++++- components/misc/stringops.hpp | 18 ------------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index d7b233ff3..6ff68c9c5 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -314,7 +314,7 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { Utf8Stream stream (i->first.c_str()); - uint32_t first = Misc::StringUtils::toUpper(stream.peek()); + uint32_t first = toUpper(stream.peek()); if (first != character) continue; @@ -323,6 +323,23 @@ struct JournalViewModelImpl : JournalViewModel } } + static uint32_t toUpper(uint32_t ch) + { + // Russian alphabet + if (ch >= 0x0430 && ch < 0x0450) + ch -= 0x20; + + // Cyrillic IO character + if (ch == 0x0451) + ch -= 0x50; + + // Latin alphabet + if (ch >= 0x61 && ch < 0x80) + ch -= 0x20; + + return ch; + } + struct TopicEntryImpl : BaseEntry { MWDialogue::Topic const & mTopic; diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 1edb5ea61..9f4931d72 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,7 +1,6 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H -#include #include #include #include @@ -57,23 +56,6 @@ public: }; } - static uint32_t toUpper(uint32_t ch) - { - // Russian alphabet - if (ch >= 0x0430 && ch < 0x0450) - ch -= 0x20; - - // Cyrillic YO character - if (ch == 0x0451) - ch -= 0x50; - - // Latin alphabet - if (ch >= 0x61 && ch < 0x80) - ch -= 0x20; - - return ch; - } - static bool ciLess(const std::string &x, const std::string &y) { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); } From 38bda3bd710a7cabb8168d1c9785c561d1ad4aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 18:00:10 +0100 Subject: [PATCH 16/18] Do not save thrown state for projectiles --- apps/openmw/mwworld/projectilemanager.cpp | 4 +--- components/esm/projectilestate.cpp | 4 ---- components/esm/projectilestate.hpp | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index d38931700..707e8b193 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -565,8 +565,6 @@ namespace MWWorld state.mVelocity = it->mVelocity; state.mAttackStrength = it->mAttackStrength; - state.mThrown = it->mThrown; - state.save(writer); writer.endRecord(ESM::REC_PROJ); @@ -604,7 +602,6 @@ namespace MWWorld state.mVelocity = esm.mVelocity; state.mIdArrow = esm.mId; state.mAttackStrength = esm.mAttackStrength; - state.mThrown = esm.mThrown; std::string model; try @@ -612,6 +609,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId); MWWorld::Ptr ptr = ref.getPtr(); model = ptr.getClass().getModel(ptr); + state.mThrown = ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown; } catch(...) { diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 7b6c419f2..8ade9d5b2 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -52,7 +52,6 @@ namespace ESM esm.writeHNString ("BOW_", mBowId); esm.writeHNT ("VEL_", mVelocity); esm.writeHNT ("STR_", mAttackStrength); - esm.writeHNT ("THR_", mThrown); } void ProjectileState::load(ESMReader &esm) @@ -64,9 +63,6 @@ namespace ESM mAttackStrength = 1.f; esm.getHNOT(mAttackStrength, "STR_"); - - mThrown = false; - esm.getHNOT (mThrown, "THR_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index c89bb7683..67ec89bb6 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -42,7 +42,6 @@ namespace ESM std::string mBowId; Vector3 mVelocity; float mAttackStrength; - bool mThrown; void load (ESMReader &esm); void save (ESMWriter &esm) const; From d0a299caabc3feef0d8009189d0ec25fa51b89f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 20:02:12 +0100 Subject: [PATCH 17/18] Rotate thrown projectiles around the bb center --- apps/openmw/mwworld/projectilemanager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 707e8b193..73b8d4d49 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -202,6 +203,12 @@ namespace MWWorld osg::ref_ptr projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo); + osg::ref_ptr boundVisitor = new osg::ComputeBoundsVisitor(); + projectile->accept(*boundVisitor.get()); + osg::BoundingBox bb = boundVisitor->getBoundingBox(); + + state.mNode->setPivotPoint(bb.center()); + if (state.mIdMagic.size() > 1) for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter) { From 4373fea21e008375b974447f48c84844ac690bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 20:27:22 +0100 Subject: [PATCH 18/18] Correct projectile rotation --- apps/openmw/mwworld/projectilemanager.cpp | 28 ++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 73b8d4d49..a4a22ea4a 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -386,7 +386,6 @@ namespace MWWorld static float fTargetSpellMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get() .find("fTargetSpellMaxSpeed")->getFloat(); float speed = fTargetSpellMaxSpeed * it->mSpeed; - osg::Vec3f direction = orient * osg::Vec3f(0,1,0); direction.normalize(); osg::Vec3f pos(it->mNode->getPosition()); @@ -466,18 +465,21 @@ namespace MWWorld osg::Vec3f newPos = pos + it->mVelocity * duration; osg::Quat orient; - - orient.set( - osg::Matrixd::rotate(it->mThrown ? -1 * it->mEffectAnimationTime->getTime() * 10.0 : 0.0,osg::Vec3f(0,0,1)) * - osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * - osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * - osg::Matrixd::inverse( - osg::Matrixd::lookAt( - osg::Vec3f(0,0,0), - it->mVelocity, - osg::Vec3f(0,0,1)) - ) - ); + + if (it->mThrown) + orient.set( + osg::Matrixd::rotate(it->mEffectAnimationTime->getTime() * -10.0,osg::Vec3f(0,0,1)) * + osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * + osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * + osg::Matrixd::inverse( + osg::Matrixd::lookAt( + osg::Vec3f(0,0,0), + it->mVelocity, + osg::Vec3f(0,0,1)) + ) + ); + else + orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); it->mNode->setAttitude(orient); it->mNode->setPosition(newPos);