Quote:
|
Mir ist aufgefallen dir fehlte irgendwo ein Blend Renderstate (Mob Aggro).
|
Jaa, das war damals noch alles ziemlich hacky. Hatte davon irgendwann die Schnauze voll und hab nun Tabellen von JEDEM Render-State, Blend-State und Texture-Stage-State mit den jeweiligen Default-Values und erstelle mir zu Anfang einen Stateblock damit. Jetzt läuft das Ganze auch tatsächlich in jedem Game ohne Probleme.
Die Möglichkeit mit den Vertex-Shadern ist natürlich auch nicht schlecht.
Sprites sind im Grunde nur Rechtecke mit einer Textur drüber.
NSprite.hpp
Code:
/*****************************************************************************
Narea project - NextGen gamehacking framework (c) [removed url here]
------------------------------------------------------------------------------
Author: Ende!
UpdateV: v2.0
Compatibility: Crossplattform
******************************************************************************/
/**
* \file This file contains the NSprite class
*/
#ifndef NSPRITE_H
#define NSPRITE_H
#include "NTypes.hpp"
#include "NColor.hpp"
namespace Narea
{
// =========================================================================
/**
* \brief Pure virtual base class for sprites
*/
class NSprite : public _NResource
{
// ----------------------------------------------------------------------
// Private variables
uint m_width;
uint m_height;
NSimpleColor m_diffuseColor;
bool m_alphaAsStencil;
public:
// ----------------------------------------------------------------------
// Virtual destructor & constructor
NSprite(NSimpleColor diffuseColor, bool useAlphaAsStencil);
virtual ~NSprite() {}
// ----------------------------------------------------------------------
// Public inlined getters and setters
uint width () const { return m_width; }
uint height () const { return m_height; }
NSimpleColor diffuseColor () const { return m_diffuseColor; }
bool isAlphaUsedAsStencil () const { return m_alphaAsStencil; }
void diffuseColor(NSimpleColor color) { m_diffuseColor = color; }
// ----------------------------------------------------------------------
// Public pure virtual methods
virtual void draw(float x,
float y,
float w,
float h,
float rot = 0.f,
short alpha = 255) const = 0;
virtual void draw(float x, float y, short alpha = 255) const = 0;
protected:
// ----------------------------------------------------------------------
// Protected setters
void width (uint width) { m_width = width; }
void height (uint height) { m_height = height; }
// ----------------------------------------------------------------------
}; // ==> NSprite
// =========================================================================
// Implementation of inline methods
/**
* \brief Constructor
* \param diffuseColor The diffuse color
* \param useAlphaAsStencil true to use alpha as stencil for diffuse
* color
*/
inline NSprite::NSprite(NSimpleColor diffuseColor, bool useAlphaAsStencil)
: m_diffuseColor(diffuseColor)
, m_alphaAsStencil(useAlphaAsStencil)
{} // ==> ctor
// =========================================================================
} // ==> Narea
#endif // ==> NSPRITE_H
NFont.hpp
Code:
/*****************************************************************************
Narea project - NextGen gamehacking framework (c) [removed url here]
------------------------------------------------------------------------------
Author: Ende!
UpdateV: v2.0
Compatibility: Win32
******************************************************************************/
#ifndef NFONT_H
#define NFONT_H
#ifndef _WIN32
# error This part of Narea can only be used in a windows environment
#endif
#include "NGFWObjectFactory.hpp"
#include "NCritSec.hpp"
#include <map>
#include <list>
namespace Narea
{
// =========================================================================
/**
* \brief Cross-GFW font class implementation
*
* Thread-safe.
*/
class NFont
{
// ----------------------------------------------------------------------
// Private attributes
uint m_height;
uint32_t m_flags;
std::wstring m_fontFace;
protected:
// ----------------------------------------------------------------------
// Protected POD structure(s)
/// POD container struct describing a cached glyph
struct CachedGlyph
{
/// Ptr to glyph image if printable, else nullptr
NSprite *pSprite;
/// Size of a box exactly wrapping the glyph
NDimensions glyphDimensions;
/// Size of the whole glyph cell
NDimensions cellDimensions;
/// Relative position offset of the glyph-wrapping box
NPos relGlyphPosition;
/// true in case the character is present in this font, else false
bool presentInFont;
}; // ==> CachedGlyph
// ----------------------------------------------------------------------
// Protected constructors
NFont(const std::wstring &rFontFace,
uint height,
uint32_t flags = Normal);
NFont(const NFont &rCopyFrom);
// ----------------------------------------------------------------------
// Protected attributes
HFONT m_hFont;
HDC m_hDC;
mutable std::map<wchar_t, const CachedGlyph> m_cachedGlyphs;
mutable NCritSec m_lock;
// ----------------------------------------------------------------------
// Static stuff
static NCritSec m_cacheLock;
static std::list<std::weak_ptr<NFont>> m_fontCache;
public:
// ----------------------------------------------------------------------
// Public enumeration
enum FontFlags : uint32_t
{
Normal = 0x00, ///< Default font mode
Bold = 0x01, ///< Bold (fat) text
Underlined = 0x02, ///< Underlined text
Italic = 0x04 ///< Italic text
}; // ==> FontFlags
// ----------------------------------------------------------------------
// Public destructor and factory methods
static NShared<NFont> get(const std::wstring &rFontFace,
uint height,
uint32_t flags = Normal);
virtual ~NFont();
// ----------------------------------------------------------------------
// Public methods and overloaded operators
// Visible
void draw (const NPos &rPos,
wchar_t ch,
NSimpleColor color) const;
void draw (const NPos &rPos,
const std::string &rText,
NSimpleColor color) const;
void draw (const NPos &rPos,
const std::wstring &rText,
NSimpleColor color) const;
// Measurement
uint getGlyphWidth (wchar_t ch ) const;
uint calcTextLen (const std::wstring &rText ) const;
uint calcTextLen (const std::string &rText ) const;
int textOffsFromPxOffs (const std::wstring &rText, uint pxOffs) const;
int textOffsFromPxOffs (const std::string &rText, uint pxOffs ) const;
// Operators
bool operator == (const NFont &rhs) const;
NFont& operator = (const NFont &rhs);
// ----------------------------------------------------------------------
// Public getters and setters
const std::wstring& fontFace () const;
uint height () const;
bool isBold () const;
bool isItalic () const;
bool isUnderlined () const;
uint32_t flags () const;
void fontFace (const std::wstring &rFontFace);
void height (uint height );
void isBold (bool bold );
void isItalic (bool italic );
void isUnderlined (bool underlined );
void flags (uint32_t flags );
protected:
// ----------------------------------------------------------------------
// Helpers
void _createFont ( );
bool _cacheGlyph (wchar_t character) const;
const CachedGlyph& _getCachedGlyph (wchar_t character) const;
const CachedGlyph* _getActualGlyph (wchar_t character) const;
bool _isGlyphPresentInFont (wchar_t character) const;
// ----------------------------------------------------------------------
}; // ==> NFont
// =========================================================================
// Implementation of inline methods [NFont]
/**
* \brief Sets the font face
* \param rFontFace The new font face
*/
inline void NFont::fontFace(const std::wstring &rFontFace)
{
NScopedLock lock(&m_lock);
m_fontFace = rFontFace;
_createFont();
} // ==> fontFace
// -------------------------------------------------------------------------
/**
* \brief Sets the font height
* \param height The new height
*/
inline void NFont::height(uint height)
{
NScopedLock lock(&m_lock);
m_height = height;
_createFont();
} // ==> height(uint)
// -------------------------------------------------------------------------
/**
* \brief Sets if the font's glyphs are bold
* \param bold true if bold, else false
*/
inline void NFont::isBold(bool bold)
{
NScopedLock lock(&m_lock);
m_flags = bold ? (m_flags | Bold) : (m_flags & ~Bold);
_createFont();
} // ==> isBold(bool)
// -------------------------------------------------------------------------
/**
* \brief Sets if the font's glyphs are italic
* \param bold true if italic, else false
*/
inline void NFont::isItalic(bool italic)
{
NScopedLock lock(&m_lock);
m_flags = italic ? (m_flags | Italic) : (m_flags & ~Italic);
_createFont();
} // ==> isItalic(bool)
// -------------------------------------------------------------------------
/**
* \brief Sets if the font's glyphs are underlined
* \param bold true if underlined, else false
*/
inline void NFont::isUnderlined(bool underlined)
{
NScopedLock lock(&m_lock);
m_flags = underlined ? (m_flags | Underlined) : (m_flags & ~Underlined);
} // ==> isUnderlined(bool)
// -------------------------------------------------------------------------
/**
* \brief Sets new font flags
* \param flags The flags
* \see FontFlags
*/
inline void NFont::flags(uint32_t flags)
{
NScopedLock lock(&m_lock);
m_flags = flags;
_createFont();
} // ==> flags(uint32_t)
// -------------------------------------------------------------------------
/**
* \copydoc NFont::draw
*/
inline void NFont::draw(const NPos &rPos,
const std::string &rText,
NSimpleColor color) const
{
draw(rPos, multiByteToWide(rText), color);
} // ==> draw(const NPos&, const std::string&, NSimpleColor)
// -------------------------------------------------------------------------
/**
* \copydoc NFont::calcTextLen
*/
inline uint NFont::calcTextLen(const std::string &rText) const
{
return calcTextLen(multiByteToWide(rText));
} // ==> calcTextLen(const std::string&)
// -------------------------------------------------------------------------
/**
* \brief Returns the width of the glyph representation of a character
* \param character The character to query the width for
* \return The glyph width
*/
inline uint NFont::getGlyphWidth(wchar_t character) const
{
NScopedLock lock(&m_lock);
const CachedGlyph *pGlyph = _getActualGlyph(character);
return (pGlyph == nullptr) ? 0 : pGlyph->cellDimensions.width;
} // ==> getGlyphWidth
// -------------------------------------------------------------------------
/**
* \brief Gets the font face
* \return The font face
*/
inline const std::wstring& NFont::fontFace() const
{
NScopedLock lock(&m_lock);
return m_fontFace;
} // ==> fontFace()
// -------------------------------------------------------------------------
/**
* \brief Gets the height
* \return The height
*/
inline uint NFont::height() const
{
return m_height;
} // ==> height()
// -------------------------------------------------------------------------
/**
* \brief Query if this font is bold
* \return true if bold, false if not
*/
inline bool NFont::isBold() const
{
return (m_flags & Bold) ? true : false;
} // ==> isBold() const
// -------------------------------------------------------------------------
/**
* \brief Query if this font is italic
* \return true if italic, false if not
*/
inline bool NFont::isItalic() const
{
return (m_flags & Italic) ? true : false;
} // ==> isItalic() const
// -------------------------------------------------------------------------
/**
* \brief Query if this font is underlined
* \return true if underlined, false if not
*/
inline bool NFont::isUnderlined() const
{
return (m_flags & Underlined) ? true : false;
} // ==> isUnderlined() const
// -------------------------------------------------------------------------
/**
* \brief Gets the font flags
* \return The font flags
* \see FontFlags
*/
inline uint32_t NFont::flags() const
{
return m_flags;
} // ==> flags() const
// -------------------------------------------------------------------------
/**
* \brief Equality operator
* \param rhs The right hand side
* \return true if equal, else false
*/
inline bool NFont::operator == (const NFont &rhs) const
{
NScopedLock lock(&m_lock);
NScopedLock lockRhs(&rhs.m_lock);
return (m_fontFace == rhs.m_fontFace
&& m_flags == rhs.m_flags
&& m_height == rhs.m_height);
} // ==> operator ==
// -------------------------------------------------------------------------
/**
* \brief Assignment operator
* \param rhs The right hand side
* \return This instance
*/
inline NFont& NFont::operator = (const NFont &rhs)
{
NScopedLock lock(&m_lock);
NScopedLock lockRhs(&rhs.m_lock);
// Copy core attributes
m_height = rhs.m_height;
m_flags = rhs.m_flags;
m_fontFace = rhs.m_fontFace;
// Generate rest
_createFont();
return *this;
} // ==> operator =
// -------------------------------------------------------------------------
/**
* \copydoc NFont::testOffsFromPxOffs
*/
inline int NFont::textOffsFromPxOffs(const std::string &rText,
uint pxOffs) const
{
return textOffsFromPxOffs(multiByteToWide(rText), pxOffs);
} // ==> textOffsFromPxOffs
// =========================================================================
} // ==> Narea
#endif // ==> NFONT_H
NFont.cpp
Code:
/*****************************************************************************
Narea project - NextGen gamehacking framework (c) [removed url here]
------------------------------------------------------------------------------
Author: Ende!
UpdateV: v2.0
Compatibility: Win32
******************************************************************************/
#include "NFont.hpp"
#include "NException.hpp"
#include "NAlgorithm.hpp"
#include "NConfig.hpp"
#include "NByteBuffer.hpp"
#include <vector>
#include <numeric>
#include <functional>
namespace Narea
{
// =========================================================================
// Static data initialization
std::list<std::weak_ptr<NFont>> NFont::m_fontCache;
NCritSec NFont::m_cacheLock;
// -------------------------------------------------------------------------
/**
* \brief Constructor
*
* \param rFontFace The font face
* \param height The font height
* \param flags The font flags
*
* \throws NXGeneral Thrown if the font couldn't be created
*/
NFont::NFont(const std::wstring &rFontFace,
uint height,
uint32_t flags)
: m_height(height)
, m_flags(flags)
, m_fontFace(rFontFace)
, m_hFont(NULL)
, m_hDC(NULL)
{
_createFont();
} // ==> ctor(const std::wstring&, uint, bool, bool, bool)
// -------------------------------------------------------------------------
/**
* \brief Copy constructor
* \param rCopyFrom The object to copy from
*/
NFont::NFont(const NFont &rCopyFrom)
: m_height(rCopyFrom.m_height)
, m_flags(rCopyFrom.m_flags)
, m_fontFace(rCopyFrom.m_fontFace)
, m_hFont(NULL)
, m_hDC(NULL)
{
_createFont();
} // ==> ctor(const NFont&)
// -------------------------------------------------------------------------
/**
* \brief Destructor
*/
NFont::~NFont()
{
NScopedLock lock(&m_lock);
if (m_hFont)
DeleteObject(m_hFont);
if (m_hDC)
DeleteDC(m_hDC);
walk_map(m_cachedGlyphs, [&](wchar_t, const CachedGlyph &rCur)
{
safeDelete(rCur.pSprite);
});
} // ==> dtor
// -------------------------------------------------------------------------
/**
* \brief Creates the font
* \throws NXGeneral Thrown if the font couldn't be created
*/
void NFont::_createFont()
{
NScopedLock lock(&m_lock);
// Create device context
HDC hDC = CreateCompatibleDC(NULL);
if (!hDC)
throw NX(NXGeneral, "could not create dc");
// Initialize font creation attribute struct
LOGFONTW lf =
{
/* .lfHeight = */ -MulDiv(height(),
GetDeviceCaps(hDC, LOGPIXELSY),
72),
/* .lfWidth = */ 0,
/* .lfEscapement = */ 0,
/* .lfOrientation = */ 0,
/* .lfWeight = */ isBold() ? FW_BOLD : FW_NORMAL,
/* .lfItalic = */ isItalic() ? TRUE : FALSE,
/* .lfUnderline = */ FALSE, // GetGlyphOutline ignores this
/* .lfStrikeOut = */ FALSE, // two values ;(
/* .lfCharSet = */ ANSI_CHARSET,
/* .lfOutPrecision = */ OUT_TT_ONLY_PRECIS,
/* .lfClipPrecision = */ CLIP_DEFAULT_PRECIS,
/* .lfQuality = */ CLEARTYPE_QUALITY,
/* .lfPitchAndFamily = */ FF_DONTCARE,
/* .lfFaceName = */ NULL
};
fontFace().copy(lf.lfFaceName, LF_FACESIZE, 0);
// Create font
HFONT hFont = CreateFontIndirectW(&lf);
if (!hFont)
{
DeleteDC(hDC);
throw NX(NXGeneral, "could not create font");
}
// Create device context and select object
if (!SelectObject(hDC, hFont))
{
DeleteDC(hDC);
DeleteObject(hFont);
throw NX(NXGeneral, "could not select font into DC");
}
// Everything fine so far, free old handles (if any) and copy new handles
// into attributes
if (m_hFont)
{
DeleteObject(m_hFont);
m_hFont = NULL;
}
if (m_hDC)
{
DeleteDC(m_hDC);
m_hDC = NULL;
}
m_hFont = hFont;
m_hDC = hDC;
// Cache all printable characters in ASCII range
for (wchar_t i = '!'; i <= '~'; ++i)
_cacheGlyph(i);
} // ==> _createFont
// -------------------------------------------------------------------------
/**
* \brief Caches a glyph
* \param ch The character to cache
* \return true if it succeeds, false if it fails
*/
bool NFont::_cacheGlyph(wchar_t ch) const
{
NScopedLock lock(&m_lock);
// Already cached?
if (m_cachedGlyphs.find(ch) != m_cachedGlyphs.end())
return true;
// Not present in font?
if (!_isGlyphPresentInFont(ch))
{
const CachedGlyph glyph =
{
nullptr,
NDimensions(),
NDimensions(),
NPos(),
false
};
m_cachedGlyphs.insert(std::make_pair(ch, glyph));
return true;
}
// Initialize parameters
GLYPHMETRICS gm = { 0 };
MAT2 matrix =
{
{0, 1}, {0, 0},
{0, 0}, {0, 1}
};
// Query data length
DWORD len = GetGlyphOutlineW(m_hDC,
UINT(ch),
GGO_GRAY8_BITMAP,
&gm,
0, nullptr,
&matrix);
if (len == GDI_ERROR)
return false;
// No visible representation of glyph? Whitespace.
if (len == 0)
{
// Put empty record into cache
const CachedGlyph glyph =
{
nullptr,
NDimensions(),
NDimensions(gm.gmCellIncX, gm.gmCellIncY),
NPos(),
true
};
m_cachedGlyphs.insert(std::make_pair(ch, glyph));
return true;
}
// Receive glyph image data
std::vector<byte> glyphImgData(len);
if (GetGlyphOutlineW(m_hDC,
UINT(ch),
GGO_GRAY8_BITMAP,
&gm,
len, glyphImgData.data(),
&matrix) == GDI_ERROR)
{
return false;
}
// Transform to raw sprite format
uint width = (gm.gmBlackBoxX + sizeof(uint) - 1) & ~(sizeof(uint) - 1);
std::vector<NSimpleColor> textureData(gm.gmBlackBoxX * gm.gmBlackBoxY);
for (uint y = 0; y < gm.gmBlackBoxY; ++y)
{
for (uint x = 0; x < gm.gmBlackBoxX; ++x)
{
// Transform 64 shades of gray color to 8 bit alpha channel
NSimpleColor curShade = glyphImgData[y * width + x];
curShade = curShade * 255 / 64;
textureData[y * gm.gmBlackBoxX + x] = curShade << 24;
}
}
// Put data into look-up map
const CachedGlyph glyph =
{
g_NConfig.gfwObjFactory().createSprite(
textureData.data(),
gm.gmBlackBoxX, gm.gmBlackBoxY,
true
),
NDimensions(gm.gmBlackBoxX, gm.gmBlackBoxY),
NDimensions(gm.gmCellIncX, gm.gmCellIncY),
NPos(gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y),
true
};
m_cachedGlyphs.insert(std::make_pair(ch, glyph));
return true;
} // ==> _cacheGlyph
// -------------------------------------------------------------------------
/**
* \brief Gets a cached glyph
* \param character The character to retrieve the glyph for
* \throws NXGeneral Thrown when caching the glyph fails
* \return The cached glyph
*/
const NFont::CachedGlyph& NFont::_getCachedGlyph(wchar_t character) const
{
NScopedLock lock(&m_lock);
// Is glyph already cached?
auto iGlyph = m_cachedGlyphs.find(character);
if (iGlyph != m_cachedGlyphs.end())
return (*iGlyph).second;
// Nope, try to cache it now
if (_cacheGlyph(character))
return _getCachedGlyph(character);
// Did not work, either? Throw exception.
throw NX(NXGeneral, "unable to cache glyph for font");
} // ==> _getCachedGlyph
// -------------------------------------------------------------------------
/**
* \brief Gets the glyph drawn for the given character
* \param character The character to retrieve the glyph for
* \return nullptr if it fails, else the glyph drawn for the given
* character. See remarks.
* \remarks If the font lacks the character, the glyph for '?' is returned
* instead. If the '?' glyph isn't present, either, nullptr is
* returned.
*/
const NFont::CachedGlyph* NFont::_getActualGlyph(wchar_t character) const
{
NScopedLock lock(&m_lock);
const CachedGlyph *pGlyph = &_getCachedGlyph(character);
// Does font lack this character? Use question mark instead.
if (!pGlyph->presentInFont)
{
pGlyph = &_getCachedGlyph('?');
// Still not present? Crappy font, return nullptr.
if (!pGlyph->presentInFont)
pGlyph = nullptr;
}
return pGlyph;
} // ==> _getActualGlyph
// -------------------------------------------------------------------------
/**
* \brief Draws a single character to a given position using the font
*
* \param rPos The screen position to draw the glyph to in pixels
* \param ch The character to draw
* \param color The color to draw with
*
* \throws NXGFWError Thrown in case drawing the glyph fails
*/
void NFont::draw(const NPos &rPos,
wchar_t ch,
NSimpleColor color) const
{
NScopedLock lock(&m_lock);
const CachedGlyph *pGlyph = _getActualGlyph(ch);
// If non-drawable, give up
if (pGlyph == nullptr || pGlyph->pSprite == nullptr)
return;
try
{
pGlyph->pSprite->diffuseColor(color);
pGlyph->pSprite->draw(float(rPos.x), float(rPos.y));
}
catch (const NXGFWError&)
{
throw NX(NXGFWError, "could not draw glyph");
}
} // ==> draw
// -------------------------------------------------------------------------
/**
* \brief Draws text to a given position using the font
*
* \param rPos The screen position to draw the text to in pixels
* \param rText The text to draw
* \param color The color to draw with
*
* \throws NXGFWError Thrown in case drawing the glyphs fails
*/
void NFont::draw(const NPos &rPos,
const std::wstring &rText,
NSimpleColor color) const
{
NScopedLock lock(&m_lock);
uint curX = rPos.x;
// Iterate through string
for (auto iCurChar = rText.cbegin()
; iCurChar != rText.cend()
; ++iCurChar)
{
const CachedGlyph *pGlyph = _getActualGlyph(*iCurChar);
// Skip lacking character
if (pGlyph == nullptr)
continue;
// Draw glyph, if non-whitespace
if (pGlyph->pSprite != nullptr)
{
try
{
pGlyph->pSprite->diffuseColor(color);
pGlyph->pSprite->draw(
float(curX + pGlyph->relGlyphPosition.x ),
float(rPos.y - pGlyph->relGlyphPosition.y + m_height)
);
}
catch (const NXGFWError&)
{
throw NX(NXGFWError, "could not draw glyphs");
}
}
// Adjust draw position
curX += pGlyph->cellDimensions.width;
}
// Underline, if requested
if (isUnderlined())
{
g_NConfig.renderEngine().drawRect(float(rPos.x),
float(rPos.y),
float(curX - rPos.x),
1.f,
makeBasicColor(color));
}
} // ==> draw(const NPos&, const std::wstring&, NSimpleColor)
// -------------------------------------------------------------------------
/**
* \brief Checks whether the given character is present in the font
* \param character The character
* \return true if it present, else false
*/
bool NFont::_isGlyphPresentInFont(wchar_t character) const
{
NScopedLock lock(&m_lock);
// Query supported characters
NByteBuffer data(GetFontUnicodeRanges(m_hDC, nullptr));
GetFontUnicodeRanges(m_hDC, data.ptr<GLYPHSET>());
// Check if character is inside of one of the ranges
const GLYPHSET *pGlyphSet = data.constPtr<GLYPHSET>();
for (uint i = 0; i < pGlyphSet->cRanges; ++i)
{
const WCRANGE *pCurRange = &pGlyphSet->ranges[i];
if (character >= pCurRange->wcLow
&& character <= pCurRange->wcLow + pCurRange->cGlyphs)
{
return true;
}
}
return false;
} // ==> _isGlyphPresentInFont
// -------------------------------------------------------------------------
/**
* \brief Calculates the text length in pixels
* \param rText The text to calculate the length for
* \return The calculated text length
*/
uint NFont::calcTextLen(const std::wstring &rText) const
{
NScopedLock lock(&m_lock);
uint len = 0;
// Accumulate widths of single glyphs
for (wchar_t curChar : rText)
len += getGlyphWidth(curChar);
return len;
} // ==> calcTextLen(const std::wstring&) const
// -------------------------------------------------------------------------
/**
* \brief Computes the text offset from a relative pixel offset
* \param rText The text to calculate the text offset for
* \param pxOffs The offset in pixels from the beginning of the text
* \return The translated offset
*/
int NFont::textOffsFromPxOffs(const std::wstring &rText, uint pxOffs) const
{
NScopedLock lock(&m_lock);
uint curPxOffs = 0;
uint curTextOffs = 0;
// Find first character below pxOffs
for (auto iCurChar = rText.cbegin()
; iCurChar != rText.cend()
; ++iCurChar, ++curTextOffs)
{
curPxOffs += getGlyphWidth(*iCurChar);
if (curPxOffs > pxOffs)
return curTextOffs;
}
return -1;
} // ==> textOffsFromPxOffs
// -------------------------------------------------------------------------
/**
* \brief Allocates a new font instance or retrieves one from cache
*
* \param rFontFace The font face
* \param height The height
* \param flags The font flags
*
* \throws NXGeneral Thrown if the font couldn't be created
*
* \return The font instance with the desired properties
*/
NShared<NFont> NFont::get(const std::wstring &rFontFace,
uint height,
uint32_t flags)
{
NScopedLock lock(&m_cacheLock);
size_t fontFaceHash = std::hash<std::wstring>()(rFontFace);
// Already cached?
for (auto i = m_fontCache.begin(); i != m_fontCache.end();)
{
auto pCurItem = i->lock();
// Dead reference? Remove from cache
if (pCurItem == nullptr)
{
i = m_fontCache.erase(i);
continue;
}
// Desired item?
if (std::hash<std::wstring>()(pCurItem->fontFace()) == fontFaceHash
&& pCurItem->flags() == flags
&& pCurItem->height() == height)
{
return std::move(pCurItem);
}
++i;
}
// Nope, cache now
std::shared_ptr<NFont> pNew(new NFont(rFontFace, height, flags));
m_fontCache.push_back(pNew);
return std::move(pNew);
} // ==> get(const std::wstring&, uint, uint32_t)
// =========================================================================
} // ==> Narea