diff --git a/data b/data index 8ad5e916..9e27e420 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 8ad5e916e353094242823f716ea45b3df2cdfe5f +Subproject commit 9e27e420d8b3c0619f148fa2c7b254b51338c5d1 diff --git a/src/app/app.cpp b/src/app/app.cpp index 802eb9bf..cae2352e 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -1423,7 +1423,7 @@ Event CApplication::CreateVirtualEvent(const Event& sourceEvent) if ((sourceEvent.type == EVENT_KEY_DOWN) || (sourceEvent.type == EVENT_KEY_UP)) { auto sourceData = sourceEvent.GetData(); - auto virtualKey = GetVirtualKey(sourceData->key); + auto virtualKey = GetVirtualKey(sourceData->key, sourceEvent.kmodState); if (virtualKey == sourceData->key) { diff --git a/src/common/font_loader.cpp b/src/common/font_loader.cpp index 068ec746..9cb3eaeb 100644 --- a/src/common/font_loader.cpp +++ b/src/common/font_loader.cpp @@ -38,31 +38,6 @@ namespace bp = boost::property_tree; -const std::map DEFAULT_FONT = -{ - { Gfx::FONT_COMMON, "dvu_sans.ttf" }, - { Gfx::FONT_COMMON_BOLD, "dvu_sans_bold.ttf" }, - { Gfx::FONT_COMMON_ITALIC, "dvu_sans_italic.ttf" }, - { Gfx::FONT_STUDIO, "dvu_sans_mono.ttf" }, - { Gfx::FONT_STUDIO_BOLD, "dvu_sans_mono_bold.ttf" }, - { Gfx::FONT_STUDIO_ITALIC, "dvu_sans_mono.ttf" }, //placeholder for future use, DejaVu Sans Mono doesn't have italic variant - { Gfx::FONT_SATCOM, "dvu_sans.ttf" }, - { Gfx::FONT_SATCOM_BOLD, "dvu_sans_bold.ttf" }, - { Gfx::FONT_SATCOM_ITALIC, "dvu_sans_italic.ttf" }, -}; - -const std::map FONT_TYPE = -{ - { Gfx::FONT_COMMON, "FontCommon" }, - { Gfx::FONT_COMMON_BOLD, "FontCommonBold" }, - { Gfx::FONT_COMMON_ITALIC, "FontCommonItalic" }, - { Gfx::FONT_STUDIO, "FontStudio" }, - { Gfx::FONT_STUDIO_BOLD, "FontStudioBold" }, - { Gfx::FONT_STUDIO_ITALIC, "FontStudioItalic" }, - { Gfx::FONT_SATCOM, "FontSatCom" }, - { Gfx::FONT_SATCOM_BOLD, "FontSatComBold" }, - { Gfx::FONT_SATCOM_ITALIC, "FontSatComItalic" }, -}; CFontLoader::CFontLoader() { @@ -99,17 +74,10 @@ bool CFontLoader::Init() return true; } -std::string CFontLoader::GetFont(Gfx::FontType type) +std::optional CFontLoader::GetFont(Gfx::FontType type) const { - return std::string("/fonts/") + m_propertyTree.get(GetFontType(type), GetDefaultFont(type)); -} - -std::string CFontLoader::GetDefaultFont(Gfx::FontType type) const -{ - return DEFAULT_FONT.at(type); -} - -std::string CFontLoader::GetFontType(Gfx::FontType type) const -{ - return FONT_TYPE.at(type); + auto font = m_propertyTree.get_optional(ToString(type)); + if (font) + return std::string("/fonts/") + *font; + return std::nullopt; } diff --git a/src/common/font_loader.h b/src/common/font_loader.h index 8f853a90..644ed98e 100644 --- a/src/common/font_loader.h +++ b/src/common/font_loader.h @@ -31,6 +31,7 @@ #include #include +#include /** * \class CFontLoader @@ -50,22 +51,10 @@ public: */ bool Init(); - /** Reads given font from file - * \return return path to font file + /** Reads given font path from file + * \return return path to font file if font type is configured */ - std::string GetFont(Gfx::FontType type); - - /** Const type method to read filenames of fonts from defaultFont map - * used as a fallback if it wasn't possible to read font from fonts.ini - * \return return filename of default path - */ - std::string GetDefaultFont(Gfx::FontType type) const; - - /** Const type method converting Gfx::FontType to string - * \return return id of font used in fonts.ini file - */ - - std::string GetFontType(Gfx::FontType type) const; + std::optional GetFont(Gfx::FontType type) const; private: boost::property_tree::ptree m_propertyTree; diff --git a/src/common/key.cpp b/src/common/key.cpp index 81fd4610..e037766c 100644 --- a/src/common/key.cpp +++ b/src/common/key.cpp @@ -19,7 +19,7 @@ #include "common/key.h" -unsigned int GetVirtualKey(unsigned int key) +unsigned int GetVirtualKey(unsigned int key, unsigned int kmodState) { if(key == KEY(LCTRL) || key == KEY(RCTRL)) return VIRTUAL_KMOD(CTRL); @@ -33,5 +33,26 @@ unsigned int GetVirtualKey(unsigned int key) if(key == KEY(KP_ENTER)) return KEY(RETURN); + // Remap keypad navigation keys as a workaround for the SDL issue: https://github.com/libsdl-org/SDL/issues/1766 + if ((kmodState & KEY_MOD(NUM)) == 0) + { + if(key == KEY(KP_7)) + return KEY(HOME); + if(key == KEY(KP_1)) + return KEY(END); + if(key == KEY(KP_9)) + return KEY(PAGEUP); + if(key == KEY(KP_3)) + return KEY(PAGEDOWN); + if(key == KEY(KP_4)) + return KEY(LEFT); + if(key == KEY(KP_6)) + return KEY(RIGHT); + if(key == KEY(KP_8)) + return KEY(UP); + if(key == KEY(KP_2)) + return KEY(DOWN); + } + return key; } diff --git a/src/common/key.h b/src/common/key.h index 57bbd457..2b972321 100644 --- a/src/common/key.h +++ b/src/common/key.h @@ -62,7 +62,7 @@ enum VirtualKmod #define VIRTUAL_KMOD(x) VIRTUAL_KMOD_ ## x //! Converts individual codes to virtual keys if needed -unsigned int GetVirtualKey(unsigned int key); +unsigned int GetVirtualKey(unsigned int key, unsigned int kmodState); // Virtual key code generated on joystick button presses // num is number of joystick button diff --git a/src/common/stringutils.cpp b/src/common/stringutils.cpp index 660cd7b6..626c5c39 100644 --- a/src/common/stringutils.cpp +++ b/src/common/stringutils.cpp @@ -156,11 +156,17 @@ std::wstring StrUtils::Utf8StringToUnicode(const std::string &str) { std::wstring result; unsigned int pos = 0; + int len; while (pos < str.size()) { - int len = StrUtils::Utf8CharSizeAt(str, pos); - if (len == 0) + try + { + len = StrUtils::Utf8CharSizeAt(str, pos); + } + catch (std::out_of_range &e) + { break; + } std::string ch = str.substr(pos, len); result += static_cast(StrUtils::Utf8CharToUnicode(ch)); @@ -172,21 +178,24 @@ std::wstring StrUtils::Utf8StringToUnicode(const std::string &str) int StrUtils::Utf8CharSizeAt(const std::string &str, unsigned int pos) { if (pos >= str.size()) - return 0; + throw std::out_of_range("Index is greater than size"); const char c = str[pos]; - if((c & 0xF8) == 0xF0) - return 4; - if((c & 0xF0) == 0xE0) - return 3; - if((c & 0xE0) == 0xC0) + if((c & 0b1000'0000) == 0b0000'0000) + return 1; + if((c & 0b1110'0000) == 0b1100'0000) return 2; + if((c & 0b1111'0000) == 0b1110'0000) + return 3; + if((c & 0b1111'1000) == 0b1111'0000) + return 4; // Invalid char - unexpected continuation byte - if((c & 0xC0) == 0x80) + if (isUtf8ContinuationByte(c)) throw std::invalid_argument("Unexpected UTF-8 continuation byte"); - return 1; + // (c & 0b1111'1000) == 0b1111'1000 is true here + throw std::invalid_argument("Byte value has no sense in UTF-8"); } std::size_t StrUtils::Utf8StringLength(const std::string &str) @@ -201,3 +210,7 @@ std::size_t StrUtils::Utf8StringLength(const std::string &str) return result; } +bool StrUtils::isUtf8ContinuationByte(char c) +{ + return (c & 0b1100'0000) == 0b1000'0000; +} diff --git a/src/common/stringutils.h b/src/common/stringutils.h index 815528c4..54c8a2a1 100644 --- a/src/common/stringutils.h +++ b/src/common/stringutils.h @@ -87,5 +87,8 @@ int Utf8CharSizeAt(const std::string &str, unsigned int pos); //! Returns the length in characters of UTF-8 string \a str std::size_t Utf8StringLength(const std::string &str); +//! Returns true if char is continuation UTF-8 byte +bool isUtf8ContinuationByte(char c); + } // namespace StrUtil diff --git a/src/graphics/engine/pyro.cpp b/src/graphics/engine/pyro.cpp index dc047c41..1d4a870d 100644 --- a/src/graphics/engine/pyro.cpp +++ b/src/graphics/engine/pyro.cpp @@ -26,6 +26,7 @@ #include "graphics/core/triangle.h" +#include "graphics/engine/engine.h" #include "graphics/engine/lightman.h" #include "graphics/engine/particle.h" #include "graphics/engine/terrain.h" diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index 87c2d9ff..38be55fd 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -85,6 +85,24 @@ struct CachedFont font = TTF_OpenFontRW(this->fontFile->GetHandler(), 0, pointSize); } + CachedFont(CachedFont&& other) noexcept + : fontFile{std::move(other.fontFile)}, + font{std::exchange(other.font, nullptr)}, + cache{std::move(other.cache)} + { + } + + CachedFont& operator=(CachedFont&& other) noexcept + { + fontFile = std::move(other.fontFile); + std::swap(font, other.font); + cache = std::move(other.cache); + return *this; + } + + CachedFont(const CachedFont& other) = delete; + CachedFont& operator=(const CachedFont& other) = delete; + ~CachedFont() { if (font != nullptr) @@ -92,11 +110,38 @@ struct CachedFont } }; +std::string ToString(FontType type) +{ + switch (type) + { + case FontType::FONT_COMMON: return "FontCommon"; + case FontType::FONT_COMMON_BOLD: return "FontCommonBold"; + case FontType::FONT_COMMON_ITALIC: return "FontCommonItalic"; + case FontType::FONT_STUDIO: return "FontStudio"; + case FontType::FONT_STUDIO_BOLD: return "FontStudioBold"; + case FontType::FONT_STUDIO_ITALIC: return "FontStudioItalic"; + case FontType::FONT_SATCOM: return "FontSatCom"; + case FontType::FONT_SATCOM_BOLD: return "FontSatComBold"; + case FontType::FONT_SATCOM_ITALIC: return "FontSatComItalic"; + case FontType::FONT_BUTTON: return "FontButton"; + default: throw std::invalid_argument("Unsupported value for Gfx::FontType -> std::string conversion: " + std::to_string(type)); + } +} namespace { constexpr glm::ivec2 REFERENCE_SIZE(800, 600); constexpr glm::ivec2 FONT_TEXTURE_SIZE(256, 256); + +Gfx::FontType ToBoldFontType(Gfx::FontType type) +{ + return static_cast(type | FONT_BOLD); +} + +Gfx::FontType ToItalicFontType(Gfx::FontType type) +{ + return static_cast(type | FONT_ITALIC); +} } // anonymous namespace /// The QuadBatch is responsible for collecting as many quad (aka rectangle) draws as possible and @@ -169,6 +214,166 @@ private: TransparencyMode m_transparency = TransparencyMode::NONE; }; +class FontsCache +{ +public: + using Fonts = std::map>; + + FontsCache() + { + ClearLastCachedFont(); + } + + bool Reload(const CFontLoader& fontLoader, int pointSize) + { + Flush(); + if (!PrepareCache(fontLoader)) { Flush(); return false; } + if (!LoadDefaultFonts(fontLoader, pointSize)) { Flush(); return false; } + return true; + } + + CachedFont* GetOrOpenFont(FontType type, int pointSize) + { + if (IsLastCachedFont(type, pointSize)) + return m_lastCachedFont; + + auto multisizeFontIt = m_fonts.find(type); + if (multisizeFontIt == m_fonts.end()) + { + m_error = std::string("Font type not found in cache: ") + ToString(type); + return nullptr; + } + MultisizeFont* multisizeFont = multisizeFontIt->second.get(); + + auto cachedFontIt = multisizeFont->fonts.find(pointSize); + if (cachedFontIt != multisizeFont->fonts.end()) + { + auto* cachedFont = cachedFontIt->second.get(); + SaveLastCachedFont(cachedFont, type, pointSize); + return m_lastCachedFont; + } + + auto newFont = LoadFont(multisizeFont, pointSize); + if (!newFont) return nullptr; + + SaveLastCachedFont(newFont.get(), type, pointSize); + multisizeFont->fonts[pointSize] = std::move(newFont); + return m_lastCachedFont; + } + + void Flush() + { + Clear(); + ClearLastCachedFont(); + } + + ~FontsCache() + { + Flush(); + } + + std::string GetError() const + { + return m_error; + } + +private: + bool PrepareCache(const CFontLoader& fontLoader) + { + for (auto type : {FONT_COMMON, FONT_STUDIO, FONT_SATCOM}) + { + if (!PrepareCacheForFontType(type, fontLoader)) return false; + if (!PrepareCacheForFontType(ToBoldFontType(type), fontLoader)) return false; + if (!PrepareCacheForFontType(ToItalicFontType(type), fontLoader)) return false; + } + return true; + } + + bool PrepareCacheForFontType(Gfx::FontType type, const CFontLoader& fontLoader) + { + if (auto font = fontLoader.GetFont(type)) + { + m_fonts[type] = std::make_unique(std::move(*font)); + return true; + } + m_error = "Error on loading fonts: font type " + ToString(type) + " is not configured"; + return false; + } + + bool LoadDefaultFonts(const CFontLoader& fontLoader, int pointSize) + { + for (auto& font : m_fonts) + { + auto type = font.first; + auto* cachedFont = GetOrOpenFont(type, pointSize); + if (cachedFont == nullptr || cachedFont->font == nullptr) + return false; + } + return true; + } + + std::unique_ptr LoadFont(MultisizeFont* multisizeFont, int pointSize) + { + auto file = CResourceManager::GetSDLMemoryHandler(multisizeFont->fileName); + if (!file->IsOpen()) + { + m_error = "Unable to open file '" + multisizeFont->fileName + "' (font size = " + std::to_string(pointSize) + ")"; + return nullptr; + } + GetLogger()->Debug("Loaded font file %s (font size = %d)\n", multisizeFont->fileName.c_str(), pointSize); + auto newFont = std::make_unique(std::move(file), pointSize); + if (newFont->font == nullptr) + { + m_error = std::string("TTF_OpenFont error ") + std::string(TTF_GetError()); + return nullptr; + } + return newFont; + } + + void SaveLastCachedFont(CachedFont* font, FontType type, int pointSize) + { + m_lastCachedFont = font; + m_lastFontType = type; + m_lastFontSize = pointSize; + } + + bool IsLastCachedFont(FontType font, int pointSize) const + { + return + m_lastCachedFont != nullptr && + m_lastFontType == font && + m_lastFontSize == pointSize; + } + + void Clear() + { + for (auto& [fontType, multisizeFont] : m_fonts) + { + for (auto& cachedFont : multisizeFont->fonts) + { + cachedFont.second->cache.clear(); + } + } + m_fonts.clear(); + } + + void ClearLastCachedFont() + { + m_lastCachedFont = nullptr; + m_lastFontType = FONT_COMMON; + m_lastFontSize = 0; + } + +private: + Fonts m_fonts; + + CachedFont* m_lastCachedFont; + FontType m_lastFontType; + int m_lastFontSize; + + std::string m_error; +}; + CText::CText(CEngine* engine) { @@ -178,9 +383,7 @@ CText::CText(CEngine* engine) m_defaultSize = 12.0f; m_tabSize = 4; - m_lastFontType = FONT_COMMON; - m_lastFontSize = 0; - m_lastCachedFont = nullptr; + m_fontsCache = std::make_unique(); m_quadBatch = MakeUnique(*engine); } @@ -212,42 +415,24 @@ bool CText::ReloadFonts() CFontLoader fontLoader; if (!fontLoader.Init()) { - GetLogger()->Debug("Error on parsing fonts config file: failed to open file\n"); + m_error = "Error on parsing fonts config file: failed to open file"; + return false; } - // Backup previous fonts - auto fonts = std::move(m_fonts); - m_fonts.clear(); - - for (auto type : {FONT_COMMON, FONT_STUDIO, FONT_SATCOM}) + auto newCache = std::make_unique(); + if (!newCache->Reload(fontLoader, GetFontPointSize(m_defaultSize))) { - m_fonts[static_cast(type)] = MakeUnique(fontLoader.GetFont(type)); - m_fonts[static_cast(type|FONT_BOLD)] = MakeUnique(fontLoader.GetFont(static_cast(type|FONT_BOLD))); - m_fonts[static_cast(type|FONT_ITALIC)] = MakeUnique(fontLoader.GetFont(static_cast(type|FONT_ITALIC))); - } - - for (auto it = m_fonts.begin(); it != m_fonts.end(); ++it) - { - FontType type = (*it).first; - CachedFont* cf = GetOrOpenFont(type, m_defaultSize); - if (cf == nullptr || cf->font == nullptr) - { - m_fonts = std::move(fonts); - return false; - } + m_error = newCache->GetError(); + return false; } + m_fontsCache = std::move(newCache); return true; } void CText::Destroy() { - m_fonts.clear(); - - m_lastCachedFont = nullptr; - m_lastFontType = FONT_COMMON; - m_lastFontSize = 0; - + m_fontsCache->Flush(); TTF_Quit(); } @@ -271,17 +456,7 @@ void CText::FlushCache() } m_fontTextures.clear(); - for (auto& multisizeFont : m_fonts) - { - for (auto& cachedFont : multisizeFont.second->fonts) - { - cachedFont.second->cache.clear(); - } - } - - m_lastCachedFont = nullptr; - m_lastFontType = FONT_COMMON; - m_lastFontSize = 0; + m_fontsCache->Flush(); } int CText::GetTabSize() @@ -938,7 +1113,14 @@ int CText::GetCharSizeAt(Gfx::FontType font, const std::string& text, unsigned i } else { - len = StrUtils::Utf8CharSizeAt(text, index); + try + { + len = StrUtils::Utf8CharSizeAt(text, index); + } + catch (std::invalid_argument &e) + { + len = 1; + } } return len; } @@ -1098,54 +1280,21 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, glm::iv } } -CachedFont* CText::GetOrOpenFont(FontType font, float size) +int CText::GetFontPointSize(float size) const { glm::ivec2 windowSize = m_engine->GetWindowSize(); - int pointSize = static_cast(size * (glm::length(glm::vec2(windowSize)) / glm::length(glm::vec2(REFERENCE_SIZE)))); + return static_cast(size * (glm::length(glm::vec2(windowSize)) / glm::length(glm::vec2(REFERENCE_SIZE)))); +} - if (m_lastCachedFont != nullptr && - m_lastFontType == font && - m_lastFontSize == pointSize) +CachedFont* CText::GetOrOpenFont(FontType type, float size) +{ + auto* cachedFont = m_fontsCache->GetOrOpenFont(type, GetFontPointSize(size)); + if (!cachedFont) { - return m_lastCachedFont; - } - - auto it = m_fonts.find(font); - if (it == m_fonts.end()) - { - m_error = std::string("Invalid font type ") + StrUtils::ToString(static_cast(font)); + m_error = m_fontsCache->GetError(); return nullptr; } - - MultisizeFont* mf = it->second.get(); - - auto jt = mf->fonts.find(pointSize); - if (jt != mf->fonts.end()) - { - m_lastCachedFont = jt->second.get(); - m_lastFontType = font; - m_lastFontSize = pointSize; - return m_lastCachedFont; - } - - auto file = CResourceManager::GetSDLMemoryHandler(mf->fileName); - if (!file->IsOpen()) - { - m_error = std::string("Unable to open file '") + mf->fileName + "' (font size = " + StrUtils::ToString(size) + ")"; - return nullptr; - } - GetLogger()->Debug("Loaded font file %s (font size = %.1f)\n", mf->fileName.c_str(), size); - - auto newFont = MakeUnique(std::move(file), pointSize); - if (newFont->font == nullptr) - { - m_error = std::string("TTF_OpenFont error ") + std::string(TTF_GetError()); - return nullptr; - } - - m_lastCachedFont = newFont.get(); - mf->fonts[pointSize] = std::move(newFont); - return m_lastCachedFont; + return cachedFont; } CharTexture CText::GetCharTexture(UTF8Char ch, FontType font, float size) diff --git a/src/graphics/engine/text.h b/src/graphics/engine/text.h index 99c77258..6efd42b2 100644 --- a/src/graphics/engine/text.h +++ b/src/graphics/engine/text.h @@ -68,38 +68,40 @@ typedef short FontMetaChar; * * Bitmask in lower 4 bits (mask 0x00f) */ -enum FontType +enum FontType : unsigned char { //! Flag for bold font subtype - FONT_BOLD = 0x04, + FONT_BOLD = 0b0000'01'00, //! Flag for italic font subtype - FONT_ITALIC = 0x08, + FONT_ITALIC = 0b0000'10'00, //! Default colobot font used for interface - FONT_COMMON = 0x00, + FONT_COMMON = 0b0000'00'00, //! Alias for bold colobot font FONT_COMMON_BOLD = FONT_COMMON | FONT_BOLD, //! Alias for italic colobot font FONT_COMMON_ITALIC = FONT_COMMON | FONT_ITALIC, //! Studio font used mainly in code editor - FONT_STUDIO = 0x01, + FONT_STUDIO = 0b0000'00'01, //! Alias for bold studio font FONT_STUDIO_BOLD = FONT_STUDIO | FONT_BOLD, //! Alias for italic studio font (at this point not used anywhere) FONT_STUDIO_ITALIC = FONT_STUDIO | FONT_ITALIC, //! SatCom font used for interface (currently bold and italic wariants aren't used anywhere) - FONT_SATCOM = 0x02, + FONT_SATCOM = 0b0000'00'10, //! Alias for bold satcom font FONT_SATCOM_BOLD = FONT_SATCOM | FONT_BOLD, //! Alias for italic satcom font FONT_SATCOM_ITALIC = FONT_SATCOM | FONT_ITALIC, //! Pseudo-font loaded from textures for buttons, icons, etc. - FONT_BUTTON = 0x03, + FONT_BUTTON = 0b0000'00'11, }; +std::string ToString(FontType); + /** * \enum FontTitle * \brief Size of font title @@ -203,6 +205,7 @@ struct CharTexture }; // Definition is private - in text.cpp +class FontsCache; struct CachedFont; struct MultisizeFont; struct FontTexture; @@ -322,7 +325,8 @@ public: glm::ivec2 GetFontTextureSize(); protected: - CachedFont* GetOrOpenFont(FontType font, float size); + int GetFontPointSize(float size) const; + CachedFont* GetOrOpenFont(FontType type, float size); CharTexture CreateCharTexture(UTF8Char ch, CachedFont* font); FontTexture* GetOrCreateFontTexture(const glm::ivec2& tileSize); FontTexture CreateFontTexture(const glm::ivec2& tileSize); @@ -348,13 +352,9 @@ protected: float m_defaultSize; int m_tabSize; - std::map> m_fonts; + std::unique_ptr m_fontsCache; std::vector m_fontTextures; - FontType m_lastFontType; - int m_lastFontSize; - CachedFont* m_lastCachedFont; - class CQuadBatch; std::unique_ptr m_quadBatch; }; diff --git a/src/level/parser/parserparam.cpp b/src/level/parser/parserparam.cpp index 17694245..24001122 100644 --- a/src/level/parser/parserparam.cpp +++ b/src/level/parser/parserparam.cpp @@ -27,6 +27,8 @@ #include "common/resources/resourcemanager.h" +#include "graphics/engine/engine.h" + #include "level/robotmain.h" #include "level/scoreboard.h" diff --git a/src/object/auto/autojostle.cpp b/src/object/auto/autojostle.cpp index 92293895..711b2558 100644 --- a/src/object/auto/autojostle.cpp +++ b/src/object/auto/autojostle.cpp @@ -22,6 +22,8 @@ #include "object/old_object.h" +#include "graphics/engine/engine.h" + // Object's constructor. diff --git a/src/object/auto/autonest.cpp b/src/object/auto/autonest.cpp index ee725ee0..1a3386e6 100644 --- a/src/object/auto/autonest.cpp +++ b/src/object/auto/autonest.cpp @@ -22,6 +22,7 @@ #include "common/make_unique.h" +#include "graphics/engine/engine.h" #include "graphics/engine/terrain.h" #include "level/parser/parserline.h" diff --git a/src/object/auto/autoroot.cpp b/src/object/auto/autoroot.cpp index a13363f9..fad23cbf 100644 --- a/src/object/auto/autoroot.cpp +++ b/src/object/auto/autoroot.cpp @@ -20,6 +20,7 @@ #include "object/auto/autoroot.h" +#include "graphics/engine/engine.h" #include "graphics/engine/particle.h" #include "graphics/engine/terrain.h" diff --git a/src/object/auto/autotower.cpp b/src/object/auto/autotower.cpp index 4db5a2de..c3511266 100644 --- a/src/object/auto/autotower.cpp +++ b/src/object/auto/autotower.cpp @@ -22,6 +22,8 @@ #include "common/make_unique.h" +#include "graphics/engine/engine.h" + #include "level/robotmain.h" #include "level/parser/parserline.h" diff --git a/src/object/motion/motion.cpp b/src/object/motion/motion.cpp index c839c085..c5bc22a8 100644 --- a/src/object/motion/motion.cpp +++ b/src/object/motion/motion.cpp @@ -24,6 +24,8 @@ #include "common/make_unique.h" +#include "graphics/engine/engine.h" + #include "level/robotmain.h" #include "level/parser/parserline.h" diff --git a/src/object/motion/motionhuman.cpp b/src/object/motion/motionhuman.cpp index 4e69cb32..858a2a75 100644 --- a/src/object/motion/motionhuman.cpp +++ b/src/object/motion/motionhuman.cpp @@ -22,6 +22,7 @@ #include "app/app.h" +#include "graphics/engine/engine.h" #include "graphics/engine/oldmodelmanager.h" #include "graphics/engine/terrain.h" #include "graphics/engine/water.h" diff --git a/src/object/motion/motionvehicle.cpp b/src/object/motion/motionvehicle.cpp index 180b11f7..2c760b4a 100644 --- a/src/object/motion/motionvehicle.cpp +++ b/src/object/motion/motionvehicle.cpp @@ -24,6 +24,7 @@ #include "common/stringutils.h" +#include "graphics/engine/engine.h" #include "graphics/engine/oldmodelmanager.h" #include "graphics/engine/particle.h" #include "graphics/engine/terrain.h" diff --git a/src/object/motion/motionworm.cpp b/src/object/motion/motionworm.cpp index d1efdd55..ef52eee8 100644 --- a/src/object/motion/motionworm.cpp +++ b/src/object/motion/motionworm.cpp @@ -22,6 +22,7 @@ #include "app/app.h" +#include "graphics/engine/engine.h" #include "graphics/engine/oldmodelmanager.h" #include "graphics/engine/particle.h" #include "graphics/engine/terrain.h" diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index e8d0077b..c0f0c380 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -1544,7 +1544,7 @@ bool CScriptFunctions::rDeflag(CBotVar* var, CBotVar* result, int& exception, vo return WaitForForegroundTask(script, result, exception); } -// Compilation of the instruction "produce(pos, angle, type[, scriptName[, power]])" +// Compilation of the instruction "produce(pos, angle, type[, scriptName[, power[, team]]])" // or "produce(type[, power])". CBotTypResult CScriptFunctions::cProduce(CBotVar* &var, void* user) @@ -1584,6 +1584,12 @@ CBotTypResult CScriptFunctions::cProduce(CBotVar* &var, void* user) { if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); var = var->GetNext(); + + if ( var != nullptr ) + { + if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); + var = var->GetNext(); + } } } } @@ -1593,7 +1599,7 @@ CBotTypResult CScriptFunctions::cProduce(CBotVar* &var, void* user) return CBotTypResult(CBotTypFloat); } -// Instruction "produce(pos, angle, type[, scriptName[, power]])" +// Instruction "produce(pos, angle, type[, scriptName[, power[, team]]])" // or "produce(type[, power])". bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, void* user) @@ -1601,34 +1607,36 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v CScript* script = static_cast(user); CObject* me = script->m_object; std::string name = ""; - glm::vec3 pos; - float angle = 0.0f; - ObjectType type = OBJECT_NULL; - float power = 0.0f; + + ObjectCreateParams params; + params.angle = 0.0f; + params.type = OBJECT_NULL; + params.power = 0.0f; + params.team = 0; if ( var->GetType() <= CBotTypDouble ) { - type = static_cast(var->GetValInt()); + params.type = static_cast(var->GetValInt()); var = var->GetNext(); - pos = me->GetPosition(); + params.pos = me->GetPosition(); glm::vec3 rotation = me->GetRotation() + me->GetTilt(); - angle = rotation.y; + params.angle = rotation.y; if ( var != nullptr ) - power = var->GetValFloat(); + params.power = var->GetValFloat(); else - power = -1.0f; + params.power = -1.0f; } else { - if ( !GetPoint(var, exception, pos) ) return true; + if ( !GetPoint(var, exception, params.pos) ) return true; - angle = var->GetValFloat()*Math::PI/180.0f; + params.angle = var->GetValFloat()*Math::PI/180.0f; var = var->GetNext(); - type = static_cast(var->GetValInt()); + params.type = static_cast(var->GetValInt()); var = var->GetNext(); if ( var != nullptr ) @@ -1637,28 +1645,34 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v var = var->GetNext(); if ( var != nullptr ) { - power = var->GetValFloat(); + params.power = var->GetValFloat(); + var = var->GetNext(); + if ( var != nullptr ) + { + params.team = var->GetValInt(); + } } else { - power = -1.0f; + params.power = -1.0f; } } else { - power = -1.0f; + params.power = -1.0f; } } CObject* object = nullptr; - if ( type == OBJECT_ANT || - type == OBJECT_SPIDER || - type == OBJECT_BEE || - type == OBJECT_WORM ) + if ( params.type == OBJECT_ANT || + params.type == OBJECT_SPIDER || + params.type == OBJECT_BEE || + params.type == OBJECT_WORM ) { - object = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type); - CObjectManager::GetInstancePointer()->CreateObject(pos, angle, OBJECT_EGG); + object = CObjectManager::GetInstancePointer()->CreateObject(params); + params.type = OBJECT_EGG; + CObjectManager::GetInstancePointer()->CreateObject(params); if (object->Implements(ObjectInterfaceType::Programmable)) { dynamic_cast(*object).SetActivity(false); @@ -1666,21 +1680,21 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v } else { - if ((type == OBJECT_POWER || type == OBJECT_ATOMIC) && power == -1.0f) + if ((params.type == OBJECT_POWER || params.type == OBJECT_ATOMIC) && params.power == -1.0f) { - power = 1.0f; + params.power = 1.0f; } - bool exists = IsValidObjectTypeId(type) && type != OBJECT_NULL && type != OBJECT_MAX && type != OBJECT_MOBILEpr; + bool exists = IsValidObjectTypeId(params.type) && params.type != OBJECT_NULL && params.type != OBJECT_MAX && params.type != OBJECT_MOBILEpr; if (exists) { - object = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type, power); + object = CObjectManager::GetInstancePointer()->CreateObject(params); } if (object == nullptr) { result->SetValInt(1); // error return true; } - if (type == OBJECT_MOBILEdr) + if (params.type == OBJECT_MOBILEdr) { assert(object->Implements(ObjectInterfaceType::Old)); // TODO: temporary hack dynamic_cast(*object).SetManual(true); diff --git a/src/ui/controls/edit.cpp b/src/ui/controls/edit.cpp index 9da4933d..8701c756 100644 --- a/src/ui/controls/edit.cpp +++ b/src/ui/controls/edit.cpp @@ -27,6 +27,7 @@ #include "common/logger.h" #include "common/make_unique.h" +#include "common/stringutils.h" #include "common/resources/inputstream.h" #include "common/resources/outputstream.h" @@ -497,7 +498,10 @@ bool CEdit::EventProcess(const Event &event) if ( event.type == EVENT_TEXT_INPUT && !bControl && m_bFocus ) { auto data = event.GetData(); - Insert(data->text[0]); // TODO: insert utf-8 char + for ( char c : data->text ) + { + Insert(c); + } SendModifEvent(); return true; } @@ -2270,7 +2274,7 @@ void CEdit::MoveChar(int move, bool bWord, bool bSelect) { int character; - if ( move == -1 ) // back? + if ( move == -1 ) // back { if ( bWord ) { @@ -2315,12 +2319,18 @@ void CEdit::MoveChar(int move, bool bWord, bool bSelect) } else { - m_cursor1 --; - if ( m_cursor1 < 0 ) m_cursor1 = 0; + if ( m_cursor1 > 0 ) + { + m_cursor1 --; + while ( m_cursor1 > 0 && StrUtils::isUtf8ContinuationByte(m_text[m_cursor1]) ) + { + m_cursor1 --; + } + } } } - if ( move == 1 ) // advance? + if ( move == 1 ) // advance { if ( bWord ) { @@ -2365,8 +2375,14 @@ void CEdit::MoveChar(int move, bool bWord, bool bSelect) } else { - m_cursor1 ++; - if ( m_cursor1 > m_len ) m_cursor1 = m_len; + if ( m_cursor1 < m_len ) + { + m_cursor1 ++; + while ( m_cursor1 < m_len && StrUtils::isUtf8ContinuationByte(m_text[m_cursor1]) ) + { + m_cursor1 ++; + } + } } } @@ -2796,6 +2812,11 @@ void CEdit::DeleteOne(int dir) } if ( m_cursor1 > m_cursor2 ) Math::Swap(m_cursor1, m_cursor2); + + // Expands selection to delete integer number of UTF-8 symbols + while ( m_cursor1 > 0 && StrUtils::isUtf8ContinuationByte(m_text[m_cursor1]) ) m_cursor1 --; + while ( m_cursor2 < m_len && StrUtils::isUtf8ContinuationByte(m_text[m_cursor2]) ) m_cursor2 ++; + hole = m_cursor2-m_cursor1; end = m_len-hole; for ( i=m_cursor1 ; i()->key); + unsigned int key = GetVirtualKey(event.GetData()->key, event.kmodState); if (TestKey(key)) // impossible ? { diff --git a/src/ui/controls/list.cpp b/src/ui/controls/list.cpp index 2554923f..553a2989 100644 --- a/src/ui/controls/list.cpp +++ b/src/ui/controls/list.cpp @@ -24,6 +24,7 @@ #include "graphics/core/device.h" #include "graphics/core/renderers.h" +#include "graphics/core/transparency.h" #include "graphics/engine/engine.h" #include "math/func.h" diff --git a/src/ui/debug_menu.cpp b/src/ui/debug_menu.cpp index 0cb3d178..39bb677a 100644 --- a/src/ui/debug_menu.cpp +++ b/src/ui/debug_menu.cpp @@ -24,6 +24,7 @@ #include "common/event.h" #include "common/stringutils.h" +#include "graphics/engine/engine.h" #include "graphics/engine/lightning.h" #include "graphics/engine/terrain.h"