Merge branch 'dev' into dev-graphics-overhaul
# Conflicts: # src/graphics/engine/text.cpp # src/graphics/engine/text.h # src/script/scriptfunc.cppdev
commit
89551c83cf
2
data
2
data
|
@ -1 +1 @@
|
|||
Subproject commit 8ad5e916e353094242823f716ea45b3df2cdfe5f
|
||||
Subproject commit 9e27e420d8b3c0619f148fa2c7b254b51338c5d1
|
|
@ -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<KeyEventData>();
|
||||
auto virtualKey = GetVirtualKey(sourceData->key);
|
||||
auto virtualKey = GetVirtualKey(sourceData->key, sourceEvent.kmodState);
|
||||
|
||||
if (virtualKey == sourceData->key)
|
||||
{
|
||||
|
|
|
@ -38,31 +38,6 @@
|
|||
|
||||
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()
|
||||
{
|
||||
|
@ -99,17 +74,10 @@ bool CFontLoader::Init()
|
|||
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));
|
||||
}
|
||||
|
||||
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<std::string>(ToString(type));
|
||||
if (font)
|
||||
return std::string("/fonts/") + *font;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
/**
|
||||
* \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<std::string> GetFont(Gfx::FontType type) const;
|
||||
|
||||
private:
|
||||
boost::property_tree::ptree m_propertyTree;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<Gfx::FontType>(type | FONT_BOLD);
|
||||
}
|
||||
|
||||
Gfx::FontType ToItalicFontType(Gfx::FontType type)
|
||||
{
|
||||
return static_cast<Gfx::FontType>(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<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)
|
||||
{
|
||||
|
@ -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<FontsCache>();
|
||||
|
||||
m_quadBatch = MakeUnique<CQuadBatch>(*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<FontsCache>();
|
||||
if (!newCache->Reload(fontLoader, GetFontPointSize(m_defaultSize)))
|
||||
{
|
||||
m_fonts[static_cast<Gfx::FontType>(type)] = MakeUnique<MultisizeFont>(fontLoader.GetFont(type));
|
||||
m_fonts[static_cast<Gfx::FontType>(type|FONT_BOLD)] = MakeUnique<MultisizeFont>(fontLoader.GetFont(static_cast<Gfx::FontType>(type|FONT_BOLD)));
|
||||
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_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<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 &&
|
||||
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<int>(static_cast<int>(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<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;
|
||||
return cachedFont;
|
||||
}
|
||||
|
||||
CharTexture CText::GetCharTexture(UTF8Char ch, FontType font, float size)
|
||||
|
|
|
@ -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<FontType, std::unique_ptr<MultisizeFont>> m_fonts;
|
||||
std::unique_ptr<FontsCache> m_fontsCache;
|
||||
std::vector<FontTexture> m_fontTextures;
|
||||
|
||||
FontType m_lastFontType;
|
||||
int m_lastFontSize;
|
||||
CachedFont* m_lastCachedFont;
|
||||
|
||||
class CQuadBatch;
|
||||
std::unique_ptr<CQuadBatch> m_quadBatch;
|
||||
};
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include "common/resources/resourcemanager.h"
|
||||
|
||||
#include "graphics/engine/engine.h"
|
||||
|
||||
#include "level/robotmain.h"
|
||||
#include "level/scoreboard.h"
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include "object/old_object.h"
|
||||
|
||||
#include "graphics/engine/engine.h"
|
||||
|
||||
|
||||
// Object's constructor.
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "common/make_unique.h"
|
||||
|
||||
#include "graphics/engine/engine.h"
|
||||
#include "graphics/engine/terrain.h"
|
||||
|
||||
#include "level/parser/parserline.h"
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "object/auto/autoroot.h"
|
||||
|
||||
#include "graphics/engine/engine.h"
|
||||
#include "graphics/engine/particle.h"
|
||||
#include "graphics/engine/terrain.h"
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include "common/make_unique.h"
|
||||
|
||||
#include "graphics/engine/engine.h"
|
||||
|
||||
#include "level/robotmain.h"
|
||||
|
||||
#include "level/parser/parserline.h"
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include "common/make_unique.h"
|
||||
|
||||
#include "graphics/engine/engine.h"
|
||||
|
||||
#include "level/robotmain.h"
|
||||
|
||||
#include "level/parser/parserline.h"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<CScript*>(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<ObjectType>(var->GetValInt());
|
||||
params.type = static_cast<ObjectType>(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<ObjectType>(var->GetValInt());
|
||||
params.type = static_cast<ObjectType>(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<CProgrammableObject&>(*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<COldObject&>(*object).SetManual(true);
|
||||
|
|
|
@ -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<TextInputData>();
|
||||
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<end ; i++ )
|
||||
|
|
|
@ -79,7 +79,7 @@ bool CKey::EventProcess(const Event &event)
|
|||
if (event.type == EVENT_KEY_DOWN && m_catch)
|
||||
{
|
||||
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 ?
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
Loading…
Reference in New Issue