we do a minuscule amount of refactoring

This commit is contained in:
Lars Mueller 2024-12-30 15:47:22 +01:00
parent ea61fcd2bf
commit 12d861d295
2 changed files with 115 additions and 73 deletions

View File

@ -31,7 +31,11 @@
john@suckerfreegames.com john@suckerfreegames.com
*/ */
#include <cstdlib>
#include <freetype/freetype.h>
#include <iostream> #include <iostream>
#include <optional>
#include "irr_ptr.h"
#include "log.h" #include "log.h"
#include "filesys.h" #include "filesys.h"
#include "debug.h" #include "debug.h"
@ -45,29 +49,79 @@ namespace irr
namespace gui namespace gui
{ {
// Manages the FT_Face cache. std::map<io::path, SGUITTFace*> SGUITTFace::faces;
struct SGUITTFace : public irr::IReferenceCounted std::optional<FT_Library> SGUITTFace::freetype_library;
std::optional<FT_Library> SGUITTFace::getFreeTypeLibrary()
{
if (freetype_library) return *freetype_library;
FT_Library ft;
if (FT_Init_FreeType(&ft))
return std::nullopt; // TODO can't we just bail out entirely if this fails?
return freetype_library = ft;
}
SGUITTFace::SGUITTFace(std::string &&buffer) : face_buffer(std::move(buffer))
{ {
SGUITTFace()
{
memset((void*)&face, 0, sizeof(FT_Face)); memset((void*)&face, 0, sizeof(FT_Face));
} }
~SGUITTFace() SGUITTFace::~SGUITTFace()
{ {
FT_Done_Face(face); FT_Done_Face(face);
}
SGUITTFace* SGUITTFace::createFace(std::string &&buffer)
{
irr_ptr<SGUITTFace> face(new SGUITTFace(std::move(buffer)));
auto ft = getFreeTypeLibrary();
if (!ft) return nullptr;
return (FT_New_Memory_Face(*ft,
reinterpret_cast<const FT_Byte*>(face->face_buffer.data()),
face->face_buffer.size(), 0, &face->face))
? nullptr : face.release();
}
SGUITTFace* SGUITTFace::loadFace(const io::path &filename)
{
auto it = faces.find(filename);
if (it != faces.end()) {
it->second->grab();
return it->second;
} }
FT_Face face; std::string buffer;
std::string face_buffer; if (!fs::ReadFile(filename.c_str(), buffer, true)) {
}; errorstream << "CGUITTFont: Reading file " << filename.c_str() << " failed." << std::endl;
return nullptr;
}
// Static variables. auto *face = SGUITTFace::createFace(std::move(buffer));
FT_Library CGUITTFont::c_library; if (!face) {
std::map<io::path, SGUITTFace*> CGUITTFont::c_faces; errorstream << "CGUITTFont: FT_New_Memory_Face failed." << std::endl;
bool CGUITTFont::c_libraryLoaded = false; return nullptr;
}
faces.emplace(filename, face);
return face;
}
// void SGUITTFace::dropFilename(const io::path &filename)
{
auto it = faces.find(filename);
if (it == faces.end()) return;
SGUITTFace* f = it->second;
// Drop our face. If this was the last face, the destructor will clean up.
if (f->drop())
faces.erase(filename);
// If there are no more faces referenced by FreeType, clean up.
if (faces.empty()) {
assert(freetype_library);
FT_Done_FreeType(*freetype_library);
freetype_library = std::nullopt;
}
}
video::IImage* SGUITTGlyph::createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const video::IImage* SGUITTGlyph::createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const
{ {
@ -203,15 +257,12 @@ void SGUITTGlyph::unload()
////////////////////// //////////////////////
CGUITTFont* CGUITTFont::createTTFont(IGUIEnvironment *env, const io::path& filename, const u32 size, const bool antialias, const bool transparency, const u32 shadow, const u32 shadow_alpha) // TODO constructor which takes bogus filename and data
{
if (!c_libraryLoaded)
{
if (FT_Init_FreeType(&c_library))
return 0;
c_libraryLoaded = true;
}
CGUITTFont* CGUITTFont::createTTFont(IGUIEnvironment *env,
const io::path& filename, u32 size, bool antialias,
bool transparency, u32 shadow, u32 shadow_alpha)
{
CGUITTFont* font = new CGUITTFont(env); CGUITTFont* font = new CGUITTFont(env);
bool ret = font->load(filename, size, antialias, transparency); bool ret = font->load(filename, size, antialias, transparency);
if (!ret) if (!ret)
@ -266,32 +317,9 @@ bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antia
<< (transparency ? "+transparency" : "-transparency") << std::endl; << (transparency ? "+transparency" : "-transparency") << std::endl;
// Grab the face. // Grab the face.
SGUITTFace* face = nullptr; auto *face = SGUITTFace::loadFace(filename);
auto node = c_faces.find(filename); if (!face)
if (node == c_faces.end()) {
face = new SGUITTFace();
if (!fs::ReadFile(filename.c_str(), face->face_buffer, true)) {
delete face;
return false; return false;
}
// Create the face.
if (FT_New_Memory_Face(c_library,
reinterpret_cast<const FT_Byte*>(face->face_buffer.data()),
face->face_buffer.size(), 0, &face->face))
{
errorstream << "CGUITTFont: FT_New_Memory_Face failed." << std::endl;
delete face;
return false;
}
c_faces.emplace(filename, face);
} else {
// Using another instance of this face.
face = node->second;
face->grab();
}
// Store our face. // Store our face.
tt_face = face->face; tt_face = face->face;
@ -323,22 +351,7 @@ CGUITTFont::~CGUITTFont()
Glyphs.clear(); Glyphs.clear();
// We aren't using this face anymore. // We aren't using this face anymore.
auto n = c_faces.find(filename); SGUITTFace::dropFilename(filename);
if (n != c_faces.end())
{
SGUITTFace* f = n->second;
// Drop our face. If this was the last face, the destructor will clean up.
if (f->drop())
c_faces.erase(filename);
// If there are no more faces referenced by FreeType, clean up.
if (c_faces.empty())
{
FT_Done_FreeType(c_library);
c_libraryLoaded = false;
}
}
// Drop our driver now. // Drop our driver now.
if (Driver) if (Driver)

View File

@ -33,6 +33,7 @@
#pragma once #pragma once
#include <map> #include <map>
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
@ -44,11 +45,42 @@
#include "util/enriched_string.h" #include "util/enriched_string.h"
#include "util/basic_macros.h" #include "util/basic_macros.h"
// TODO these should be in the C++ when the struct is properly split into C++ & header
#include <optional>
#include "irr_ptr.h"
#include "log.h"
#include "filesys.h"
namespace irr namespace irr
{ {
namespace gui namespace gui
{ {
struct SGUITTFace; // Manages the FT_Face cache.
struct SGUITTFace : public irr::IReferenceCounted
{
private:
static std::map<io::path, SGUITTFace*> faces;
static std::optional<FT_Library> freetype_library;
static std::optional<FT_Library> getFreeTypeLibrary();
public:
SGUITTFace(std::string &&buffer);
~SGUITTFace();
FT_Face face;
/// Must not be deallocated until we are done with the face!
std::string face_buffer;
static SGUITTFace* createFace(std::string &&buffer);
static SGUITTFace* loadFace(const io::path &filename);
static void dropFilename(const io::path &filename);
};
class CGUITTFont; class CGUITTFont;
//! Structure representing a single TrueType glyph. //! Structure representing a single TrueType glyph.
@ -220,7 +252,9 @@ namespace gui
//! \param antialias set the use_monochrome (opposite to antialias) flag //! \param antialias set the use_monochrome (opposite to antialias) flag
//! \param transparency set the use_transparency flag //! \param transparency set the use_transparency flag
//! \return Returns a pointer to a CGUITTFont. Will return 0 if the font failed to load. //! \return Returns a pointer to a CGUITTFont. Will return 0 if the font failed to load.
static CGUITTFont* createTTFont(IGUIEnvironment *env, const io::path& filename, const u32 size, const bool antialias = true, const bool transparency = true, const u32 shadow = 0, const u32 shadow_alpha = 255); static CGUITTFont* createTTFont(IGUIEnvironment *env,
const io::path& filename, u32 size, bool antialias = true,
bool transparency = true, u32 shadow = 0, u32 shadow_alpha = 255);
//! Destructor //! Destructor
virtual ~CGUITTFont(); virtual ~CGUITTFont();
@ -329,11 +363,6 @@ namespace gui
core::dimension2du max_page_texture_size; core::dimension2du max_page_texture_size;
private: private:
// Manages the FreeType library.
static FT_Library c_library;
static std::map<io::path, SGUITTFace*> c_faces;
static bool c_libraryLoaded;
// Helper functions for the same-named public member functions above // Helper functions for the same-named public member functions above
// (Since std::u32string is nicer to work with than wchar_t *) // (Since std::u32string is nicer to work with than wchar_t *)
core::dimension2d<u32> getDimension(const std::u32string& text) const; core::dimension2d<u32> getDimension(const std::u32string& text) const;