diff --git a/data/stk_config.xml b/data/stk_config.xml
index c3924751c..8b2259340 100644
--- a/data/stk_config.xml
+++ b/data/stk_config.xml
@@ -411,8 +411,7 @@
which leads to crash with STK), but the fonts are to blame, what's the point of not
using industry standard nowadays...
-->
-
+
diff --git a/data/ttf/Cantarell-Bold.otf b/data/ttf/Cantarell-Bold.otf
deleted file mode 100644
index 0d0f3afbd..000000000
Binary files a/data/ttf/Cantarell-Bold.otf and /dev/null differ
diff --git a/data/ttf/FreeSansBold.ttf b/data/ttf/FreeSansBold.ttf
deleted file mode 100644
index 6f36dc5fe..000000000
Binary files a/data/ttf/FreeSansBold.ttf and /dev/null differ
diff --git a/data/ttf/LICENSE b/data/ttf/LICENSE
index a65321afc..e595c3831 100644
--- a/data/ttf/LICENSE
+++ b/data/ttf/LICENSE
@@ -1,4 +1,4 @@
-GNU FreeFont (FreeSans, FreeSansBold) is released under the GPLv3
+GNU FreeFont (FreeSans) is released under the GPLv3
wqyMicroHei is released under the GPLv3 with font embedding exception and Apache-2.0 licenses
By Qianqian Fang and The WenQuanYi Project Contributors
diff --git a/sources.cmake b/sources.cmake
index ddc029d4f..f484b15d5 100644
--- a/sources.cmake
+++ b/sources.cmake
@@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
-# This will then trigger a new cmake run automatically.
+# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp
index d6701c680..288fef4c8 100644
--- a/src/config/stk_config.cpp
+++ b/src/config/stk_config.cpp
@@ -182,9 +182,8 @@ void STKConfig::init_defaults()
m_score_increase.clear();
m_leader_intervals.clear();
m_switch_items.clear();
- m_regular_faces.clear();
- m_bold_faces.clear();
- m_digit_faces.clear();
+ m_normal_ttf.clear();
+ m_digit_ttf.clear();
} // init_defaults
//-----------------------------------------------------------------------------
@@ -368,9 +367,8 @@ void STKConfig::getAllData(const XMLNode * root)
if (const XMLNode *fonts_list = root->getNode("fonts-list"))
{
- fonts_list->get("regular-faces", &m_regular_faces);
- fonts_list->get("bold-faces", &m_bold_faces );
- fonts_list->get("digit-faces", &m_digit_faces );
+ fonts_list->get("normal-ttf", &m_normal_ttf);
+ fonts_list->get("digit-ttf", &m_digit_ttf );
}
// Get the default KartProperties
diff --git a/src/config/stk_config.hpp b/src/config/stk_config.hpp
index 898d02ef8..21a8c678a 100644
--- a/src/config/stk_config.hpp
+++ b/src/config/stk_config.hpp
@@ -154,9 +154,8 @@ public:
std::string m_font_bold_fallback;
std::string m_font_digit;
/** Lists of TTF files used in STK. */
- std::vector m_regular_faces;
- std::vector m_bold_faces;
- std::vector m_digit_faces;
+ std::vector m_normal_ttf;
+ std::vector m_digit_ttf;
private:
/** True if stk_config has been loaded. This is necessary if the
diff --git a/src/font/bold_face.cpp b/src/font/bold_face.cpp
index 3efa6dc14..f32aea7b5 100644
--- a/src/font/bold_face.cpp
+++ b/src/font/bold_face.cpp
@@ -18,11 +18,10 @@
#include "font/bold_face.hpp"
-#include "config/stk_config.hpp"
-#include "font/regular_face.hpp"
+#include "font/face_ttf.hpp"
// ----------------------------------------------------------------------------
-BoldFace::BoldFace() : FontWithFace("BoldFace")
+BoldFace::BoldFace(FaceTTF* ttf) : FontWithFace("BoldFace", ttf)
{
} // BoldFace
@@ -32,8 +31,10 @@ void BoldFace::init()
FontWithFace::init();
// Reserve some space for characters added later
m_font_max_height = m_glyph_max_height + 20;
+
+ /* Use FT_Outline_Embolden for now, no more fallback font
setFallbackFont(font_manager->getFont());
- setFallbackFontScale(2.0f);
+ setFallbackFontScale(2.0f);*/
} // init
// ----------------------------------------------------------------------------
@@ -51,9 +52,3 @@ void BoldFace::reset()
insertCharacters(preload_chars.c_str());
updateCharactersList();
} // reset
-
-// ----------------------------------------------------------------------------
-std::vector BoldFace::getFacesList() const
-{
- return stk_config->m_bold_faces;
-} // getFacesList
diff --git a/src/font/bold_face.hpp b/src/font/bold_face.hpp
index f4f91a10e..53ddce8f5 100644
--- a/src/font/bold_face.hpp
+++ b/src/font/bold_face.hpp
@@ -21,11 +21,11 @@
#include "font/font_with_face.hpp"
+class FaceTTF;
+
class BoldFace : public FontWithFace
{
private:
- virtual std::vector getFacesList() const OVERRIDE;
- // ------------------------------------------------------------------------
virtual bool supportLazyLoadChar() const OVERRIDE { return true; }
// ------------------------------------------------------------------------
virtual unsigned int getGlyphPageSize() const OVERRIDE { return 1024; }
@@ -37,7 +37,7 @@ private:
public:
LEAK_CHECK()
// ------------------------------------------------------------------------
- BoldFace();
+ BoldFace(FaceTTF* ttf);
// ------------------------------------------------------------------------
virtual ~BoldFace() {}
// ------------------------------------------------------------------------
diff --git a/src/font/digit_face.cpp b/src/font/digit_face.cpp
index 672211b94..7b257fce5 100644
--- a/src/font/digit_face.cpp
+++ b/src/font/digit_face.cpp
@@ -18,10 +18,10 @@
#include "font/digit_face.hpp"
-#include "config/stk_config.hpp"
+#include "font/face_ttf.hpp"
// ----------------------------------------------------------------------------
-DigitFace::DigitFace() : FontWithFace("DigitFace")
+DigitFace::DigitFace(FaceTTF* ttf) : FontWithFace("DigitFace", ttf)
{
} // DigitFace
@@ -50,9 +50,3 @@ void DigitFace::reset()
insertCharacters(preload_chars.c_str(), true/*first_load*/);
updateCharactersList();
} // reset
-
-// ----------------------------------------------------------------------------
-std::vector DigitFace::getFacesList() const
-{
- return stk_config->m_digit_faces;
-} // getFacesList
diff --git a/src/font/digit_face.hpp b/src/font/digit_face.hpp
index 4ff08be62..35bbdb248 100644
--- a/src/font/digit_face.hpp
+++ b/src/font/digit_face.hpp
@@ -21,11 +21,11 @@
#include "font/font_with_face.hpp"
+class FaceTTF;
+
class DigitFace : public FontWithFace
{
private:
- virtual std::vector getFacesList() const OVERRIDE;
- // ------------------------------------------------------------------------
virtual bool supportLazyLoadChar() const OVERRIDE { return false; }
// ------------------------------------------------------------------------
virtual unsigned int getGlyphPageSize() const OVERRIDE { return 256; }
@@ -37,7 +37,7 @@ private:
public:
LEAK_CHECK()
// ------------------------------------------------------------------------
- DigitFace();
+ DigitFace(FaceTTF* ttf);
// ------------------------------------------------------------------------
virtual ~DigitFace() {}
// ------------------------------------------------------------------------
diff --git a/src/font/face_ttf.cpp b/src/font/face_ttf.cpp
new file mode 100644
index 000000000..fdb64d572
--- /dev/null
+++ b/src/font/face_ttf.cpp
@@ -0,0 +1,49 @@
+//
+// SuperTuxKart - a fun racing game with go-kart
+// Copyright (C) 2016 SuperTuxKart-Team
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include "font/face_ttf.hpp"
+
+#include "io/file_manager.hpp"
+
+// ----------------------------------------------------------------------------
+FaceTTF::FaceTTF(const std::vector& ttf_list)
+{
+ for (const std::string& font : ttf_list)
+ {
+ FT_Face face = NULL;
+ font_manager->checkFTError(FT_New_Face(font_manager->getFTLibrary(),
+ (file_manager->getAssetChecked(FileManager::TTF,
+ font.c_str(), true)).c_str(), 0, &face), "loading fonts");
+ m_faces.push_back(face);
+ }
+} // FaceTTF
+
+// ----------------------------------------------------------------------------
+FaceTTF::~FaceTTF()
+{
+ for (unsigned int i = 0; i < m_faces.size(); i++)
+ {
+ font_manager->checkFTError(FT_Done_Face(m_faces[i]), "removing face");
+ }
+} // ~FaceTTF
+// ----------------------------------------------------------------------------
+FT_Face FaceTTF::getFace(unsigned int i) const
+{
+ assert(i < m_faces.size());
+ return m_faces[i];
+} // getFace
diff --git a/src/font/face_ttf.hpp b/src/font/face_ttf.hpp
new file mode 100644
index 000000000..90663dab5
--- /dev/null
+++ b/src/font/face_ttf.hpp
@@ -0,0 +1,43 @@
+//
+// SuperTuxKart - a fun racing game with go-kart
+// Copyright (C) 2016 SuperTuxKart-Team
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 3
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef HEADER_FACE_TTF_HPP
+#define HEADER_FACE_TTF_HPP
+
+#include "font/font_manager.hpp"
+
+class FaceTTF : public NoCopy
+{
+private:
+ std::vector m_faces;
+
+public:
+ LEAK_CHECK();
+ // ------------------------------------------------------------------------
+ FaceTTF(const std::vector& ttf_list);
+ // ------------------------------------------------------------------------
+ ~FaceTTF();
+ // ------------------------------------------------------------------------
+ FT_Face getFace(unsigned int i) const;
+ // ------------------------------------------------------------------------
+ unsigned int getTotalFaces() const { return m_faces.size(); }
+
+}; // FaceTTF
+
+#endif
+/* EOF */
diff --git a/src/font/font_manager.cpp b/src/font/font_manager.cpp
index 2d839b997..772c7de22 100644
--- a/src/font/font_manager.cpp
+++ b/src/font/font_manager.cpp
@@ -18,8 +18,10 @@
#include "font/font_manager.hpp"
+#include "config/stk_config.hpp"
#include "font/bold_face.hpp"
#include "font/digit_face.hpp"
+#include "font/face_ttf.hpp"
#include "font/regular_face.hpp"
FontManager *font_manager = NULL;
@@ -33,6 +35,11 @@ FontManager::FontManager()
FontManager::~FontManager()
{
m_fonts.clearAndDeleteAll();
+ delete m_normal_ttf;
+ m_normal_ttf = NULL;
+ delete m_digit_ttf;
+ m_digit_ttf = NULL;
+
checkFTError(FT_Done_FreeType(m_ft_library), "removing freetype library");
m_ft_library = NULL;
} // ~FontManager
@@ -40,13 +47,20 @@ FontManager::~FontManager()
// ----------------------------------------------------------------------------
void FontManager::loadFonts()
{
- RegularFace* regular = new RegularFace();
+ // First load the TTF files required by each font
+ m_normal_ttf = new FaceTTF(stk_config->m_normal_ttf);
+ m_digit_ttf = new FaceTTF(stk_config->m_digit_ttf);
+
+ // Now load fonts with settings of ttf file
+ RegularFace* regular = new RegularFace(m_normal_ttf);
regular->init();
m_fonts.push_back(regular);
- BoldFace* bold = new BoldFace();
+
+ BoldFace* bold = new BoldFace(m_normal_ttf);
bold->init();
m_fonts.push_back(bold);
- DigitFace* digit = new DigitFace();
+
+ DigitFace* digit = new DigitFace(m_digit_ttf);
digit->init();
m_fonts.push_back(digit);
} // loadFonts
diff --git a/src/font/font_manager.hpp b/src/font/font_manager.hpp
index 6ceec0799..68f2118cc 100644
--- a/src/font/font_manager.hpp
+++ b/src/font/font_manager.hpp
@@ -29,6 +29,7 @@
#include
#include FT_FREETYPE_H
+class FaceTTF;
class FontWithFace;
class FontManager : public NoCopy
@@ -38,6 +39,10 @@ private:
FT_Library m_ft_library;
+ FaceTTF* m_normal_ttf;
+
+ FaceTTF* m_digit_ttf;
+
public:
LEAK_CHECK()
// ------------------------------------------------------------------------
diff --git a/src/font/font_with_face.cpp b/src/font/font_with_face.cpp
index e432a161e..579169131 100644
--- a/src/font/font_with_face.cpp
+++ b/src/font/font_with_face.cpp
@@ -19,14 +19,17 @@
#include "font/font_with_face.hpp"
#include "font/bold_face.hpp"
+#include "font/face_ttf.hpp"
#include "graphics/2dutils.hpp"
#include "graphics/irr_driver.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/skin.hpp"
#include "utils/string_utils.hpp"
+#include
+
// ----------------------------------------------------------------------------
-FontWithFace::FontWithFace(const std::string& name)
+FontWithFace::FontWithFace(const std::string& name, FaceTTF* ttf)
{
m_spritebank = irr_driver->getGUI()->addEmptySpriteBank(name.c_str());
@@ -36,6 +39,7 @@ FontWithFace::FontWithFace(const std::string& name)
m_fallback_font = NULL;
m_fallback_font_scale = 1.0f;
m_glyph_max_height = 0;
+ m_face_ttf = ttf;
} // FontWithFace
// ----------------------------------------------------------------------------
@@ -46,33 +50,24 @@ FontWithFace::~FontWithFace()
m_spritebank->drop();
m_spritebank = NULL;
- for (unsigned int i = 0; i < m_faces.size(); i++)
- {
- font_manager->checkFTError(FT_Done_Face(m_faces[i]), "removing face");
- }
+ // To be deleted by font_manager
+ m_face_ttf = NULL;
} // ~FontWithFace
// ----------------------------------------------------------------------------
void FontWithFace::init()
{
+ setDPI();
m_page = irr_driver->getVideoDriver()->createImage(video::ECF_A8R8G8B8,
core::dimension2du(getGlyphPageSize(), getGlyphPageSize()));
- for (const std::string& font : getFacesList())
- {
- FT_Face face = NULL;
- font_manager->checkFTError(FT_New_Face(font_manager->getFTLibrary(),
- (file_manager->getAssetChecked(FileManager::TTF,
- font.c_str(), true)).c_str(), 0, &face), "loading fonts");
- font_manager->checkFTError(FT_Set_Pixel_Sizes(face, 0, getDPI()),
- "setting DPI");
- m_faces.push_back(face);
- }
-
// Get the max height for this face
- assert(m_faces.size() > 0);
- FT_Face cur_face = m_faces[0];
+ assert(m_face_ttf->getTotalFaces() > 0);
+ FT_Face cur_face = m_face_ttf->getFace(0);
+ font_manager->checkFTError(FT_Set_Pixel_Sizes(cur_face, 0, getDPI()),
+ "setting DPI");
+
for (int i = 32; i < 128; i++)
{
// Test all basic latin characters
@@ -98,6 +93,20 @@ void FontWithFace::reset()
createNewGlyphPage();
} // reset
+// ----------------------------------------------------------------------------
+void FontWithFace::loadGlyphInfo(wchar_t c)
+{
+ unsigned int font_number = 0;
+ unsigned int glyph_index = 0;
+ while (font_number < m_face_ttf->getTotalFaces())
+ {
+ glyph_index = FT_Get_Char_Index(m_face_ttf->getFace(font_number), c);
+ if (glyph_index > 0) break;
+ font_number++;
+ }
+ m_character_glyph_info_map[c] = GlyphInfo(font_number, glyph_index);
+} // loadGlyphInfo
+
// ----------------------------------------------------------------------------
void FontWithFace::createNewGlyphPage()
{
@@ -124,13 +133,26 @@ void FontWithFace::createNewGlyphPage()
void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
{
assert(gi.glyph_index > 0);
- assert(gi.font_number < m_faces.size());
- FT_Face cur_face = m_faces[gi.font_number];
+ assert(gi.font_number < m_face_ttf->getTotalFaces());
+ FT_Face cur_face = m_face_ttf->getFace(gi.font_number);
FT_GlyphSlot slot = cur_face->glyph;
+ // Faces may be shared across regular and bold,
+ // so reset dpi each time
+ font_manager->checkFTError(FT_Set_Pixel_Sizes(cur_face, 0, getDPI()),
+ "setting DPI");
+
font_manager->checkFTError(FT_Load_Glyph(cur_face, gi.glyph_index,
- FT_LOAD_DEFAULT | FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL),
- "loading a glyph");
+ FT_LOAD_DEFAULT), "loading a glyph");
+
+ if (dynamic_cast(this))
+ {
+ // Embolden the outline of the glyph
+ FT_Outline_Embolden(&(slot->outline), getDPI() * 2);
+ }
+
+ font_manager->checkFTError(FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL),
+ "render a glyph to bitmap");
// Convert to an anti-aliased bitmap
FT_Bitmap bits = slot->bitmap;
@@ -297,7 +319,7 @@ void FontWithFace::dumpGlyphPage()
} // dumpGlyphPage
// ----------------------------------------------------------------------------
-unsigned int FontWithFace::getDPI() const
+void FontWithFace::setDPI()
{
// Get face dpi:
// Font size is resolution-dependent.
@@ -315,10 +337,10 @@ unsigned int FontWithFace::getDPI() const
if (screen_width < 900 || screen_height < 700)
scale = std::min(scale, 0.05f);
- return unsigned((getScalingFactorOne() + 0.2f * scale) *
+ m_face_dpi = unsigned((getScalingFactorOne() + 0.2f * scale) *
getScalingFactorTwo());
-} // getDPI
+} // setDPI
// ----------------------------------------------------------------------------
const FontWithFace::FontArea&
diff --git a/src/font/font_with_face.hpp b/src/font/font_with_face.hpp
index 239066fb4..e219c9c30 100644
--- a/src/font/font_with_face.hpp
+++ b/src/font/font_with_face.hpp
@@ -29,6 +29,8 @@
const int BEARING = 64;
+class FaceTTF;
+
class FontWithFace : public NoCopy
{
public:
@@ -53,8 +55,6 @@ public:
};
protected:
- std::vector m_faces;
-
int m_font_max_height;
int m_glyph_max_height;
@@ -104,6 +104,8 @@ private:
}
};
+ FaceTTF* m_face_ttf;
+
FontWithFace* m_fallback_font;
float m_fallback_font_scale;
@@ -120,6 +122,7 @@ private:
unsigned int m_temp_height;
unsigned int m_used_width;
unsigned int m_used_height;
+ unsigned int m_face_dpi;
std::map m_character_area_map;
std::map m_character_glyph_info_map;
@@ -162,27 +165,16 @@ private:
return false;
}
// ------------------------------------------------------------------------
- void loadGlyphInfo(wchar_t c)
- {
- unsigned int font_number = 0;
- unsigned int glyph_index = 0;
- while (font_number < m_faces.size())
- {
- glyph_index = FT_Get_Char_Index(m_faces[font_number], c);
- if (glyph_index > 0) break;
- font_number++;
- }
- m_character_glyph_info_map[c] = GlyphInfo(font_number, glyph_index);
- }
+ void loadGlyphInfo(wchar_t c);
// ------------------------------------------------------------------------
void createNewGlyphPage();
// ------------------------------------------------------------------------
- unsigned int getDPI() const;
- // ------------------------------------------------------------------------
void addLazyLoadChar(wchar_t c) { m_new_char_holder.insert(c); }
// ------------------------------------------------------------------------
void insertGlyph(wchar_t c, const GlyphInfo& gi);
// ------------------------------------------------------------------------
+ void setDPI();
+ // ------------------------------------------------------------------------
virtual bool supportLazyLoadChar() const = 0;
// ------------------------------------------------------------------------
virtual unsigned int getGlyphPageSize() const = 0;
@@ -190,13 +182,11 @@ private:
virtual float getScalingFactorOne() const = 0;
// ------------------------------------------------------------------------
virtual unsigned int getScalingFactorTwo() const = 0;
- // ------------------------------------------------------------------------
- virtual std::vector getFacesList() const = 0;
public:
LEAK_CHECK();
// ------------------------------------------------------------------------
- FontWithFace(const std::string& name);
+ FontWithFace(const std::string& name, FaceTTF* ttf);
// ------------------------------------------------------------------------
virtual ~FontWithFace();
// ------------------------------------------------------------------------
@@ -231,6 +221,8 @@ public:
// ------------------------------------------------------------------------
const FontArea& getAreaFromCharacter(const wchar_t c,
bool* fallback_font) const;
+ // ------------------------------------------------------------------------
+ unsigned int getDPI() const { return m_face_dpi; }
}; // FontWithFace
diff --git a/src/font/regular_face.cpp b/src/font/regular_face.cpp
index c764d894b..f86a9ffc1 100644
--- a/src/font/regular_face.cpp
+++ b/src/font/regular_face.cpp
@@ -16,12 +16,12 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#include "font/face_ttf.hpp"
+
#include "font/regular_face.hpp"
-#include "config/stk_config.hpp"
-
// ----------------------------------------------------------------------------
-RegularFace::RegularFace() : FontWithFace("RegularFace")
+RegularFace::RegularFace(FaceTTF* ttf) : FontWithFace("RegularFace", ttf)
{
} // RegularFace
@@ -48,9 +48,3 @@ void RegularFace::reset()
insertCharacters(preload_chars.c_str());
updateCharactersList();
} // reset
-
-// ----------------------------------------------------------------------------
-std::vector RegularFace::getFacesList() const
-{
- return stk_config->m_regular_faces;
-} // getFacesList
diff --git a/src/font/regular_face.hpp b/src/font/regular_face.hpp
index 4ddecf24c..54ac41d4a 100644
--- a/src/font/regular_face.hpp
+++ b/src/font/regular_face.hpp
@@ -21,11 +21,11 @@
#include "font/font_with_face.hpp"
+class FaceTTF;
+
class RegularFace : public FontWithFace
{
private:
- virtual std::vector getFacesList() const OVERRIDE;
- // ------------------------------------------------------------------------
virtual bool supportLazyLoadChar() const OVERRIDE { return true; }
// ------------------------------------------------------------------------
virtual unsigned int getGlyphPageSize() const OVERRIDE { return 512; }
@@ -37,7 +37,7 @@ private:
public:
LEAK_CHECK()
// ------------------------------------------------------------------------
- RegularFace();
+ RegularFace(FaceTTF* ttf);
// ------------------------------------------------------------------------
virtual ~RegularFace() {}
// ------------------------------------------------------------------------