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
*/
#include <cstdlib>
#include <freetype/freetype.h>
#include <iostream>
#include <optional>
#include "irr_ptr.h"
#include "log.h"
#include "filesys.h"
#include "debug.h"
@ -45,29 +49,79 @@ namespace irr
namespace gui
{
// Manages the FT_Face cache.
struct SGUITTFace : public irr::IReferenceCounted
std::map<io::path, SGUITTFace*> SGUITTFace::faces;
std::optional<FT_Library> SGUITTFace::freetype_library;
std::optional<FT_Library> SGUITTFace::getFreeTypeLibrary()
{
SGUITTFace()
{
memset((void*)&face, 0, sizeof(FT_Face));
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))
{
memset((void*)&face, 0, sizeof(FT_Face));
}
SGUITTFace::~SGUITTFace()
{
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;
}
~SGUITTFace()
{
FT_Done_Face(face);
std::string buffer;
if (!fs::ReadFile(filename.c_str(), buffer, true)) {
errorstream << "CGUITTFont: Reading file " << filename.c_str() << " failed." << std::endl;
return nullptr;
}
FT_Face face;
std::string face_buffer;
};
auto *face = SGUITTFace::createFace(std::move(buffer));
if (!face) {
errorstream << "CGUITTFont: FT_New_Memory_Face failed." << std::endl;
return nullptr;
}
faces.emplace(filename, face);
return face;
}
// Static variables.
FT_Library CGUITTFont::c_library;
std::map<io::path, SGUITTFace*> CGUITTFont::c_faces;
bool CGUITTFont::c_libraryLoaded = false;
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
{
@ -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)
{
if (!c_libraryLoaded)
{
if (FT_Init_FreeType(&c_library))
return 0;
c_libraryLoaded = true;
}
// TODO constructor which takes bogus filename and data
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);
bool ret = font->load(filename, size, antialias, transparency);
if (!ret)
@ -266,32 +317,9 @@ bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antia
<< (transparency ? "+transparency" : "-transparency") << std::endl;
// Grab the face.
SGUITTFace* face = nullptr;
auto node = c_faces.find(filename);
if (node == c_faces.end()) {
face = new SGUITTFace();
if (!fs::ReadFile(filename.c_str(), face->face_buffer, true)) {
delete face;
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();
}
auto *face = SGUITTFace::loadFace(filename);
if (!face)
return false;
// Store our face.
tt_face = face->face;
@ -323,22 +351,7 @@ CGUITTFont::~CGUITTFont()
Glyphs.clear();
// We aren't using this face anymore.
auto n = c_faces.find(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;
}
}
SGUITTFace::dropFilename(filename);
// Drop our driver now.
if (Driver)

View File

@ -33,6 +33,7 @@
#pragma once
#include <map>
#include <ft2build.h>
#include FT_FREETYPE_H
@ -44,11 +45,42 @@
#include "util/enriched_string.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 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;
//! Structure representing a single TrueType glyph.
@ -220,7 +252,9 @@ namespace gui
//! \param antialias set the use_monochrome (opposite to antialias) flag
//! \param transparency set the use_transparency flag
//! \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
virtual ~CGUITTFont();
@ -329,11 +363,6 @@ namespace gui
core::dimension2du max_page_texture_size;
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
// (Since std::u32string is nicer to work with than wchar_t *)
core::dimension2d<u32> getDimension(const std::u32string& text) const;