Merge branch 'dev' into dev-graphics-overhaul

# Conflicts:
#	src/graphics/engine/text.cpp
#	src/graphics/engine/text.h
#	src/script/scriptfunc.cpp
dev
Tomasz Kapuściński 2022-02-26 04:21:39 +01:00
commit 89551c83cf
25 changed files with 392 additions and 198 deletions

2
data

@ -1 +1 @@
Subproject commit 8ad5e916e353094242823f716ea45b3df2cdfe5f Subproject commit 9e27e420d8b3c0619f148fa2c7b254b51338c5d1

View File

@ -1423,7 +1423,7 @@ Event CApplication::CreateVirtualEvent(const Event& sourceEvent)
if ((sourceEvent.type == EVENT_KEY_DOWN) || (sourceEvent.type == EVENT_KEY_UP)) if ((sourceEvent.type == EVENT_KEY_DOWN) || (sourceEvent.type == EVENT_KEY_UP))
{ {
auto sourceData = sourceEvent.GetData<KeyEventData>(); auto sourceData = sourceEvent.GetData<KeyEventData>();
auto virtualKey = GetVirtualKey(sourceData->key); auto virtualKey = GetVirtualKey(sourceData->key, sourceEvent.kmodState);
if (virtualKey == sourceData->key) if (virtualKey == sourceData->key)
{ {

View File

@ -38,31 +38,6 @@
namespace bp = boost::property_tree; namespace bp = boost::property_tree;
const std::map<Gfx::FontType, std::string> 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<Gfx::FontType, std::string> 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() CFontLoader::CFontLoader()
{ {
@ -99,17 +74,10 @@ bool CFontLoader::Init()
return true; return true;
} }
std::string CFontLoader::GetFont(Gfx::FontType type) std::optional<std::string> CFontLoader::GetFont(Gfx::FontType type) const
{ {
return std::string("/fonts/") + m_propertyTree.get<std::string>(GetFontType(type), GetDefaultFont(type)); auto font = m_propertyTree.get_optional<std::string>(ToString(type));
} if (font)
return std::string("/fonts/") + *font;
std::string CFontLoader::GetDefaultFont(Gfx::FontType type) const return std::nullopt;
{
return DEFAULT_FONT.at(type);
}
std::string CFontLoader::GetFontType(Gfx::FontType type) const
{
return FONT_TYPE.at(type);
} }

View File

@ -31,6 +31,7 @@
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <string> #include <string>
#include <optional>
/** /**
* \class CFontLoader * \class CFontLoader
@ -50,22 +51,10 @@ public:
*/ */
bool Init(); bool Init();
/** Reads given font from file /** Reads given font path from file
* \return return path to font file * \return return path to font file if font type is configured
*/ */
std::string GetFont(Gfx::FontType type); std::optional<std::string> GetFont(Gfx::FontType type) const;
/** 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;
private: private:
boost::property_tree::ptree m_propertyTree; boost::property_tree::ptree m_propertyTree;

View File

@ -19,7 +19,7 @@
#include "common/key.h" #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)) if(key == KEY(LCTRL) || key == KEY(RCTRL))
return VIRTUAL_KMOD(CTRL); return VIRTUAL_KMOD(CTRL);
@ -33,5 +33,26 @@ unsigned int GetVirtualKey(unsigned int key)
if(key == KEY(KP_ENTER)) if(key == KEY(KP_ENTER))
return KEY(RETURN); 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; return key;
} }

View File

@ -62,7 +62,7 @@ enum VirtualKmod
#define VIRTUAL_KMOD(x) VIRTUAL_KMOD_ ## x #define VIRTUAL_KMOD(x) VIRTUAL_KMOD_ ## x
//! Converts individual codes to virtual keys if needed //! 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 // Virtual key code generated on joystick button presses
// num is number of joystick button // num is number of joystick button

View File

@ -156,11 +156,17 @@ std::wstring StrUtils::Utf8StringToUnicode(const std::string &str)
{ {
std::wstring result; std::wstring result;
unsigned int pos = 0; unsigned int pos = 0;
int len;
while (pos < str.size()) while (pos < str.size())
{ {
int len = StrUtils::Utf8CharSizeAt(str, pos); try
if (len == 0) {
len = StrUtils::Utf8CharSizeAt(str, pos);
}
catch (std::out_of_range &e)
{
break; break;
}
std::string ch = str.substr(pos, len); std::string ch = str.substr(pos, len);
result += static_cast<wchar_t>(StrUtils::Utf8CharToUnicode(ch)); result += static_cast<wchar_t>(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) int StrUtils::Utf8CharSizeAt(const std::string &str, unsigned int pos)
{ {
if (pos >= str.size()) if (pos >= str.size())
return 0; throw std::out_of_range("Index is greater than size");
const char c = str[pos]; const char c = str[pos];
if((c & 0xF8) == 0xF0) if((c & 0b1000'0000) == 0b0000'0000)
return 4; return 1;
if((c & 0xF0) == 0xE0) if((c & 0b1110'0000) == 0b1100'0000)
return 3;
if((c & 0xE0) == 0xC0)
return 2; return 2;
if((c & 0b1111'0000) == 0b1110'0000)
return 3;
if((c & 0b1111'1000) == 0b1111'0000)
return 4;
// Invalid char - unexpected continuation byte // Invalid char - unexpected continuation byte
if((c & 0xC0) == 0x80) if (isUtf8ContinuationByte(c))
throw std::invalid_argument("Unexpected UTF-8 continuation byte"); 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) std::size_t StrUtils::Utf8StringLength(const std::string &str)
@ -201,3 +210,7 @@ std::size_t StrUtils::Utf8StringLength(const std::string &str)
return result; return result;
} }
bool StrUtils::isUtf8ContinuationByte(char c)
{
return (c & 0b1100'0000) == 0b1000'0000;
}

View File

@ -87,5 +87,8 @@ int Utf8CharSizeAt(const std::string &str, unsigned int pos);
//! Returns the length in characters of UTF-8 string \a str //! Returns the length in characters of UTF-8 string \a str
std::size_t Utf8StringLength(const std::string &str); std::size_t Utf8StringLength(const std::string &str);
//! Returns true if char is continuation UTF-8 byte
bool isUtf8ContinuationByte(char c);
} // namespace StrUtil } // namespace StrUtil

View File

@ -26,6 +26,7 @@
#include "graphics/core/triangle.h" #include "graphics/core/triangle.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/lightman.h" #include "graphics/engine/lightman.h"
#include "graphics/engine/particle.h" #include "graphics/engine/particle.h"
#include "graphics/engine/terrain.h" #include "graphics/engine/terrain.h"

View File

@ -85,6 +85,24 @@ struct CachedFont
font = TTF_OpenFontRW(this->fontFile->GetHandler(), 0, pointSize); 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() ~CachedFont()
{ {
if (font != nullptr) 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 namespace
{ {
constexpr glm::ivec2 REFERENCE_SIZE(800, 600); constexpr glm::ivec2 REFERENCE_SIZE(800, 600);
constexpr glm::ivec2 FONT_TEXTURE_SIZE(256, 256); constexpr glm::ivec2 FONT_TEXTURE_SIZE(256, 256);
Gfx::FontType ToBoldFontType(Gfx::FontType type)
{
return static_cast<Gfx::FontType>(type | FONT_BOLD);
}
Gfx::FontType ToItalicFontType(Gfx::FontType type)
{
return static_cast<Gfx::FontType>(type | FONT_ITALIC);
}
} // anonymous namespace } // anonymous namespace
/// The QuadBatch is responsible for collecting as many quad (aka rectangle) draws as possible and /// 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; TransparencyMode m_transparency = TransparencyMode::NONE;
}; };
class FontsCache
{
public:
using Fonts = std::map<FontType, std::unique_ptr<MultisizeFont>>;
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<MultisizeFont>(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<CachedFont> 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<CachedFont>(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) CText::CText(CEngine* engine)
{ {
@ -178,9 +383,7 @@ CText::CText(CEngine* engine)
m_defaultSize = 12.0f; m_defaultSize = 12.0f;
m_tabSize = 4; m_tabSize = 4;
m_lastFontType = FONT_COMMON; m_fontsCache = std::make_unique<FontsCache>();
m_lastFontSize = 0;
m_lastCachedFont = nullptr;
m_quadBatch = MakeUnique<CQuadBatch>(*engine); m_quadBatch = MakeUnique<CQuadBatch>(*engine);
} }
@ -212,42 +415,24 @@ bool CText::ReloadFonts()
CFontLoader fontLoader; CFontLoader fontLoader;
if (!fontLoader.Init()) 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 newCache = std::make_unique<FontsCache>();
auto fonts = std::move(m_fonts); if (!newCache->Reload(fontLoader, GetFontPointSize(m_defaultSize)))
m_fonts.clear();
for (auto type : {FONT_COMMON, FONT_STUDIO, FONT_SATCOM})
{ {
m_fonts[static_cast<Gfx::FontType>(type)] = MakeUnique<MultisizeFont>(fontLoader.GetFont(type)); m_error = newCache->GetError();
m_fonts[static_cast<Gfx::FontType>(type|FONT_BOLD)] = MakeUnique<MultisizeFont>(fontLoader.GetFont(static_cast<Gfx::FontType>(type|FONT_BOLD))); return false;
m_fonts[static_cast<Gfx::FontType>(type|FONT_ITALIC)] = MakeUnique<MultisizeFont>(fontLoader.GetFont(static_cast<Gfx::FontType>(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_fontsCache = std::move(newCache);
return true; return true;
} }
void CText::Destroy() void CText::Destroy()
{ {
m_fonts.clear(); m_fontsCache->Flush();
m_lastCachedFont = nullptr;
m_lastFontType = FONT_COMMON;
m_lastFontSize = 0;
TTF_Quit(); TTF_Quit();
} }
@ -271,17 +456,7 @@ void CText::FlushCache()
} }
m_fontTextures.clear(); m_fontTextures.clear();
for (auto& multisizeFont : m_fonts) m_fontsCache->Flush();
{
for (auto& cachedFont : multisizeFont.second->fonts)
{
cachedFont.second->cache.clear();
}
}
m_lastCachedFont = nullptr;
m_lastFontType = FONT_COMMON;
m_lastFontSize = 0;
} }
int CText::GetTabSize() int CText::GetTabSize()
@ -938,7 +1113,14 @@ int CText::GetCharSizeAt(Gfx::FontType font, const std::string& text, unsigned i
} }
else else
{ {
len = StrUtils::Utf8CharSizeAt(text, index); try
{
len = StrUtils::Utf8CharSizeAt(text, index);
}
catch (std::invalid_argument &e)
{
len = 1;
}
} }
return len; 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(); glm::ivec2 windowSize = m_engine->GetWindowSize();
int pointSize = static_cast<int>(size * (glm::length(glm::vec2(windowSize)) / glm::length(glm::vec2(REFERENCE_SIZE)))); return static_cast<int>(size * (glm::length(glm::vec2(windowSize)) / glm::length(glm::vec2(REFERENCE_SIZE))));
}
if (m_lastCachedFont != nullptr && CachedFont* CText::GetOrOpenFont(FontType type, float size)
m_lastFontType == font && {
m_lastFontSize == pointSize) auto* cachedFont = m_fontsCache->GetOrOpenFont(type, GetFontPointSize(size));
if (!cachedFont)
{ {
return m_lastCachedFont; m_error = m_fontsCache->GetError();
}
auto it = m_fonts.find(font);
if (it == m_fonts.end())
{
m_error = std::string("Invalid font type ") + StrUtils::ToString<int>(static_cast<int>(font));
return nullptr; return nullptr;
} }
return cachedFont;
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<float>(size) + ")";
return nullptr;
}
GetLogger()->Debug("Loaded font file %s (font size = %.1f)\n", mf->fileName.c_str(), size);
auto newFont = MakeUnique<CachedFont>(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;
} }
CharTexture CText::GetCharTexture(UTF8Char ch, FontType font, float size) CharTexture CText::GetCharTexture(UTF8Char ch, FontType font, float size)

View File

@ -68,38 +68,40 @@ typedef short FontMetaChar;
* *
* Bitmask in lower 4 bits (mask 0x00f) * Bitmask in lower 4 bits (mask 0x00f)
*/ */
enum FontType enum FontType : unsigned char
{ {
//! Flag for bold font subtype //! Flag for bold font subtype
FONT_BOLD = 0x04, FONT_BOLD = 0b0000'01'00,
//! Flag for italic font subtype //! Flag for italic font subtype
FONT_ITALIC = 0x08, FONT_ITALIC = 0b0000'10'00,
//! Default colobot font used for interface //! Default colobot font used for interface
FONT_COMMON = 0x00, FONT_COMMON = 0b0000'00'00,
//! Alias for bold colobot font //! Alias for bold colobot font
FONT_COMMON_BOLD = FONT_COMMON | FONT_BOLD, FONT_COMMON_BOLD = FONT_COMMON | FONT_BOLD,
//! Alias for italic colobot font //! Alias for italic colobot font
FONT_COMMON_ITALIC = FONT_COMMON | FONT_ITALIC, FONT_COMMON_ITALIC = FONT_COMMON | FONT_ITALIC,
//! Studio font used mainly in code editor //! Studio font used mainly in code editor
FONT_STUDIO = 0x01, FONT_STUDIO = 0b0000'00'01,
//! Alias for bold studio font //! Alias for bold studio font
FONT_STUDIO_BOLD = FONT_STUDIO | FONT_BOLD, FONT_STUDIO_BOLD = FONT_STUDIO | FONT_BOLD,
//! Alias for italic studio font (at this point not used anywhere) //! Alias for italic studio font (at this point not used anywhere)
FONT_STUDIO_ITALIC = FONT_STUDIO | FONT_ITALIC, FONT_STUDIO_ITALIC = FONT_STUDIO | FONT_ITALIC,
//! SatCom font used for interface (currently bold and italic wariants aren't used anywhere) //! 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 //! Alias for bold satcom font
FONT_SATCOM_BOLD = FONT_SATCOM | FONT_BOLD, FONT_SATCOM_BOLD = FONT_SATCOM | FONT_BOLD,
//! Alias for italic satcom font //! Alias for italic satcom font
FONT_SATCOM_ITALIC = FONT_SATCOM | FONT_ITALIC, FONT_SATCOM_ITALIC = FONT_SATCOM | FONT_ITALIC,
//! Pseudo-font loaded from textures for buttons, icons, etc. //! Pseudo-font loaded from textures for buttons, icons, etc.
FONT_BUTTON = 0x03, FONT_BUTTON = 0b0000'00'11,
}; };
std::string ToString(FontType);
/** /**
* \enum FontTitle * \enum FontTitle
* \brief Size of font title * \brief Size of font title
@ -203,6 +205,7 @@ struct CharTexture
}; };
// Definition is private - in text.cpp // Definition is private - in text.cpp
class FontsCache;
struct CachedFont; struct CachedFont;
struct MultisizeFont; struct MultisizeFont;
struct FontTexture; struct FontTexture;
@ -322,7 +325,8 @@ public:
glm::ivec2 GetFontTextureSize(); glm::ivec2 GetFontTextureSize();
protected: protected:
CachedFont* GetOrOpenFont(FontType font, float size); int GetFontPointSize(float size) const;
CachedFont* GetOrOpenFont(FontType type, float size);
CharTexture CreateCharTexture(UTF8Char ch, CachedFont* font); CharTexture CreateCharTexture(UTF8Char ch, CachedFont* font);
FontTexture* GetOrCreateFontTexture(const glm::ivec2& tileSize); FontTexture* GetOrCreateFontTexture(const glm::ivec2& tileSize);
FontTexture CreateFontTexture(const glm::ivec2& tileSize); FontTexture CreateFontTexture(const glm::ivec2& tileSize);
@ -348,13 +352,9 @@ protected:
float m_defaultSize; float m_defaultSize;
int m_tabSize; int m_tabSize;
std::map<FontType, std::unique_ptr<MultisizeFont>> m_fonts; std::unique_ptr<FontsCache> m_fontsCache;
std::vector<FontTexture> m_fontTextures; std::vector<FontTexture> m_fontTextures;
FontType m_lastFontType;
int m_lastFontSize;
CachedFont* m_lastCachedFont;
class CQuadBatch; class CQuadBatch;
std::unique_ptr<CQuadBatch> m_quadBatch; std::unique_ptr<CQuadBatch> m_quadBatch;
}; };

View File

@ -27,6 +27,8 @@
#include "common/resources/resourcemanager.h" #include "common/resources/resourcemanager.h"
#include "graphics/engine/engine.h"
#include "level/robotmain.h" #include "level/robotmain.h"
#include "level/scoreboard.h" #include "level/scoreboard.h"

View File

@ -22,6 +22,8 @@
#include "object/old_object.h" #include "object/old_object.h"
#include "graphics/engine/engine.h"
// Object's constructor. // Object's constructor.

View File

@ -22,6 +22,7 @@
#include "common/make_unique.h" #include "common/make_unique.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/terrain.h" #include "graphics/engine/terrain.h"
#include "level/parser/parserline.h" #include "level/parser/parserline.h"

View File

@ -20,6 +20,7 @@
#include "object/auto/autoroot.h" #include "object/auto/autoroot.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/particle.h" #include "graphics/engine/particle.h"
#include "graphics/engine/terrain.h" #include "graphics/engine/terrain.h"

View File

@ -22,6 +22,8 @@
#include "common/make_unique.h" #include "common/make_unique.h"
#include "graphics/engine/engine.h"
#include "level/robotmain.h" #include "level/robotmain.h"
#include "level/parser/parserline.h" #include "level/parser/parserline.h"

View File

@ -24,6 +24,8 @@
#include "common/make_unique.h" #include "common/make_unique.h"
#include "graphics/engine/engine.h"
#include "level/robotmain.h" #include "level/robotmain.h"
#include "level/parser/parserline.h" #include "level/parser/parserline.h"

View File

@ -22,6 +22,7 @@
#include "app/app.h" #include "app/app.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/oldmodelmanager.h" #include "graphics/engine/oldmodelmanager.h"
#include "graphics/engine/terrain.h" #include "graphics/engine/terrain.h"
#include "graphics/engine/water.h" #include "graphics/engine/water.h"

View File

@ -24,6 +24,7 @@
#include "common/stringutils.h" #include "common/stringutils.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/oldmodelmanager.h" #include "graphics/engine/oldmodelmanager.h"
#include "graphics/engine/particle.h" #include "graphics/engine/particle.h"
#include "graphics/engine/terrain.h" #include "graphics/engine/terrain.h"

View File

@ -22,6 +22,7 @@
#include "app/app.h" #include "app/app.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/oldmodelmanager.h" #include "graphics/engine/oldmodelmanager.h"
#include "graphics/engine/particle.h" #include "graphics/engine/particle.h"
#include "graphics/engine/terrain.h" #include "graphics/engine/terrain.h"

View File

@ -1544,7 +1544,7 @@ bool CScriptFunctions::rDeflag(CBotVar* var, CBotVar* result, int& exception, vo
return WaitForForegroundTask(script, result, exception); 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])". // or "produce(type[, power])".
CBotTypResult CScriptFunctions::cProduce(CBotVar* &var, void* user) 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); if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
var = var->GetNext(); 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); return CBotTypResult(CBotTypFloat);
} }
// Instruction "produce(pos, angle, type[, scriptName[, power]])" // Instruction "produce(pos, angle, type[, scriptName[, power[, team]]])"
// or "produce(type[, power])". // or "produce(type[, power])".
bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, void* user) 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<CScript*>(user); CScript* script = static_cast<CScript*>(user);
CObject* me = script->m_object; CObject* me = script->m_object;
std::string name = ""; std::string name = "";
glm::vec3 pos;
float angle = 0.0f; ObjectCreateParams params;
ObjectType type = OBJECT_NULL; params.angle = 0.0f;
float power = 0.0f; params.type = OBJECT_NULL;
params.power = 0.0f;
params.team = 0;
if ( var->GetType() <= CBotTypDouble ) if ( var->GetType() <= CBotTypDouble )
{ {
type = static_cast<ObjectType>(var->GetValInt()); params.type = static_cast<ObjectType>(var->GetValInt());
var = var->GetNext(); var = var->GetNext();
pos = me->GetPosition(); params.pos = me->GetPosition();
glm::vec3 rotation = me->GetRotation() + me->GetTilt(); glm::vec3 rotation = me->GetRotation() + me->GetTilt();
angle = rotation.y; params.angle = rotation.y;
if ( var != nullptr ) if ( var != nullptr )
power = var->GetValFloat(); params.power = var->GetValFloat();
else else
power = -1.0f; params.power = -1.0f;
} }
else 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(); var = var->GetNext();
type = static_cast<ObjectType>(var->GetValInt()); params.type = static_cast<ObjectType>(var->GetValInt());
var = var->GetNext(); var = var->GetNext();
if ( var != nullptr ) if ( var != nullptr )
@ -1637,28 +1645,34 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v
var = var->GetNext(); var = var->GetNext();
if ( var != nullptr ) if ( var != nullptr )
{ {
power = var->GetValFloat(); params.power = var->GetValFloat();
var = var->GetNext();
if ( var != nullptr )
{
params.team = var->GetValInt();
}
} }
else else
{ {
power = -1.0f; params.power = -1.0f;
} }
} }
else else
{ {
power = -1.0f; params.power = -1.0f;
} }
} }
CObject* object = nullptr; CObject* object = nullptr;
if ( type == OBJECT_ANT || if ( params.type == OBJECT_ANT ||
type == OBJECT_SPIDER || params.type == OBJECT_SPIDER ||
type == OBJECT_BEE || params.type == OBJECT_BEE ||
type == OBJECT_WORM ) params.type == OBJECT_WORM )
{ {
object = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type); object = CObjectManager::GetInstancePointer()->CreateObject(params);
CObjectManager::GetInstancePointer()->CreateObject(pos, angle, OBJECT_EGG); params.type = OBJECT_EGG;
CObjectManager::GetInstancePointer()->CreateObject(params);
if (object->Implements(ObjectInterfaceType::Programmable)) if (object->Implements(ObjectInterfaceType::Programmable))
{ {
dynamic_cast<CProgrammableObject&>(*object).SetActivity(false); dynamic_cast<CProgrammableObject&>(*object).SetActivity(false);
@ -1666,21 +1680,21 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v
} }
else 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) if (exists)
{ {
object = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type, power); object = CObjectManager::GetInstancePointer()->CreateObject(params);
} }
if (object == nullptr) if (object == nullptr)
{ {
result->SetValInt(1); // error result->SetValInt(1); // error
return true; return true;
} }
if (type == OBJECT_MOBILEdr) if (params.type == OBJECT_MOBILEdr)
{ {
assert(object->Implements(ObjectInterfaceType::Old)); // TODO: temporary hack assert(object->Implements(ObjectInterfaceType::Old)); // TODO: temporary hack
dynamic_cast<COldObject&>(*object).SetManual(true); dynamic_cast<COldObject&>(*object).SetManual(true);

View File

@ -27,6 +27,7 @@
#include "common/logger.h" #include "common/logger.h"
#include "common/make_unique.h" #include "common/make_unique.h"
#include "common/stringutils.h"
#include "common/resources/inputstream.h" #include "common/resources/inputstream.h"
#include "common/resources/outputstream.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 ) if ( event.type == EVENT_TEXT_INPUT && !bControl && m_bFocus )
{ {
auto data = event.GetData<TextInputData>(); auto data = event.GetData<TextInputData>();
Insert(data->text[0]); // TODO: insert utf-8 char for ( char c : data->text )
{
Insert(c);
}
SendModifEvent(); SendModifEvent();
return true; return true;
} }
@ -2270,7 +2274,7 @@ void CEdit::MoveChar(int move, bool bWord, bool bSelect)
{ {
int character; int character;
if ( move == -1 ) // back? if ( move == -1 ) // back
{ {
if ( bWord ) if ( bWord )
{ {
@ -2315,12 +2319,18 @@ void CEdit::MoveChar(int move, bool bWord, bool bSelect)
} }
else else
{ {
m_cursor1 --; if ( m_cursor1 > 0 )
if ( m_cursor1 < 0 ) 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 ) if ( bWord )
{ {
@ -2365,8 +2375,14 @@ void CEdit::MoveChar(int move, bool bWord, bool bSelect)
} }
else else
{ {
m_cursor1 ++; if ( m_cursor1 < m_len )
if ( m_cursor1 > m_len ) 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); 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; hole = m_cursor2-m_cursor1;
end = m_len-hole; end = m_len-hole;
for ( i=m_cursor1 ; i<end ; i++ ) for ( i=m_cursor1 ; i<end ; i++ )

View File

@ -79,7 +79,7 @@ bool CKey::EventProcess(const Event &event)
if (event.type == EVENT_KEY_DOWN && m_catch) if (event.type == EVENT_KEY_DOWN && m_catch)
{ {
m_catch = false; m_catch = false;
unsigned int key = GetVirtualKey(event.GetData<KeyEventData>()->key); unsigned int key = GetVirtualKey(event.GetData<KeyEventData>()->key, event.kmodState);
if (TestKey(key)) // impossible ? if (TestKey(key)) // impossible ?
{ {

View File

@ -24,6 +24,7 @@
#include "graphics/core/device.h" #include "graphics/core/device.h"
#include "graphics/core/renderers.h" #include "graphics/core/renderers.h"
#include "graphics/core/transparency.h"
#include "graphics/engine/engine.h" #include "graphics/engine/engine.h"
#include "math/func.h" #include "math/func.h"

View File

@ -24,6 +24,7 @@
#include "common/event.h" #include "common/event.h"
#include "common/stringutils.h" #include "common/stringutils.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/lightning.h" #include "graphics/engine/lightning.h"
#include "graphics/engine/terrain.h" #include "graphics/engine/terrain.h"