35 #include FT_FREETYPE_H
47 if (!szFontName || !*szFontName)
54 const char *szFontString = szFontName;
56 assert(*szFontString);
79 sscanf(FontParam,
"%i", &iDefFontSize);
84 sscanf(FontParam,
"%i", &iDefWeight);
85 dwDefWeight = iDefWeight;
88 if (rFont->
IsSameAs(FontFaceName, iDefFontSize, dwDefWeight))
95 LogF(
LoadResStr(
"IDS_PRC_UPDATEFONT"), FontFaceName, iDefFontSize, dwDefWeight);
98 const char *
const extensions[] = {
"ttf",
"otf",
"ttc",
"fon",
"fnt",
"fot",
nullptr };
120 catch (std::runtime_error & e)
143 throw std::runtime_error(
FormatString(
"Font face %s undefined", FontFaceName).getData());
147 catch (std::runtime_error & e)
163 catch (std::runtime_error & e)
192 bool fSuccess =
false;
193 HDC hDC = ::CreateCompatibleDC(
nullptr);
196 HFONT hFont = ::CreateFontA(0, 0, 0, 0, FW_DONTCARE,
false,
197 false,
false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
198 CLIP_DEFAULT_PRECIS, 5,
199 VARIABLE_PITCH, FontFaceName);
202 SelectObject( hDC, hFont );
203 uint32_t dwTTFSize = ::GetFontData(hDC, 0, 0,
nullptr, 0);
204 if (dwTTFSize && dwTTFSize != GDI_ERROR)
207 uint32_t dwRealTTFSize = ::GetFontData(hDC, 0, 0, Data.
getMData(), dwTTFSize);
208 if (dwRealTTFSize == dwTTFSize)
220 throw std::runtime_error(
"Some Win32 error");
222 if (FT_Init_FreeType(&library))
223 throw std::runtime_error(
"Cannot init Freetype");
226 if ((e=FT_New_Memory_Face(library,
static_cast<const FT_Byte *
>(Data.
getData()), Data.
getSize(), 0, &face)))
227 throw std::runtime_error(std::string(
"Cannot load font: ") +
FormatString(
"%d",e).getData());
231 if (FT_Init_FreeType(&library))
232 throw std::runtime_error(
"Cannot init Freetype");
235 if ((e=FT_New_Face(library, FontFaceName, 0, &face)))
236 throw std::runtime_error(std::string(
"Cannot load ") + FontFaceName +
": " +
FormatString(
"%d",e).getData());
242 if (FT_Init_FreeType(&library))
243 throw std::runtime_error(
"Cannot init Freetype");
246 if ((e=FT_New_Memory_Face(library,
static_cast<const FT_Byte *
>(Data.
getData()), Data.
getSize(), 0, &face)))
247 throw std::runtime_error(std::string(
"Cannot load font: ") +
FormatString(
"%d",e).getData());
252 FT_Done_FreeType(library);
254 operator FT_Face () {
return face; }
340 iBoldness = (1<<16) + (iBoldness<<16)/400;
342 mat.xx = iBoldness; mat.xy = mat.yx = 0; mat.yy = 1<<16;
350 if (FT_Load_Char(*
pVectorFont, dwChar, FT_LOAD_RENDER | FT_LOAD_NO_HINTING))
357 FT_GlyphSlot slot = (*pVectorFont)->glyph;
358 if (slot->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
365 int width = std::max<int>(slot->advance.x / 64, std::max(slot->bitmap_left,0) + slot->bitmap.width) +
fDoShadow;
369 int at_x =
iCurrentSfcX + std::max(slot->bitmap_left,0);
372 for (
unsigned int y = 0; y < slot->bitmap.rows +
fDoShadow; ++y)
374 for (
unsigned int x = 0; x < slot->bitmap.width +
fDoShadow; ++x)
376 unsigned char bAlpha, bAlphaShadow;
377 if (x < slot->bitmap.width && y < slot->bitmap.rows)
378 bAlpha = (
unsigned char)(slot->bitmap.buffer[slot->bitmap.width * y + x]);
387 if (x < slot->bitmap.width && y < slot->bitmap.rows) iShadow += slot->bitmap.buffer[(x - 0) + slot->bitmap.width * (y - 0)];
388 if (x > 1 && y < slot->bitmap.rows) iShadow += slot->bitmap.buffer[(x - 2) + slot->bitmap.width * (y - 0)];
389 if (x > 0 && y < slot->bitmap.rows) iShadow += slot->bitmap.buffer[(x - 1) + slot->bitmap.width * (y - 0)];
390 if (x < slot->bitmap.width && y > 1 ) iShadow += slot->bitmap.buffer[(x - 0) + slot->bitmap.width * (y - 2)];
391 if (x > 1 && y > 1 ) iShadow += slot->bitmap.buffer[(x - 2) + slot->bitmap.width * (y - 2)];
392 if (x > 0 && y > 1 ) iShadow += slot->bitmap.buffer[(x - 1) + slot->bitmap.width * (y - 2)];
393 if (x < slot->bitmap.width && y > 0 ) iShadow += slot->bitmap.buffer[(x - 0) + slot->bitmap.width * (y - 1)];
394 if (x > 1 && y > 0 ) iShadow += slot->bitmap.buffer[(x - 2) + slot->bitmap.width * (y - 1)];
395 if (x > 0 && y > 0 ) iShadow += slot->bitmap.buffer[(x - 1) + slot->bitmap.width * (y - 1)]*8;
396 bAlphaShadow += iShadow / 16;
399 unsigned char cBack = bAlpha;
400 dwPixVal =
RGBA(cBack/2, cBack/2, cBack/2, bAlphaShadow);
402 BltAlpha(dwPixVal, bAlpha << 24 | 0xffffff);
448 throw std::runtime_error(std::string(
"Cannot create surface (") +
szFontName +
")");
456 iLineHgt = (VectorFont->ascender - VectorFont->descender) * dwHeight / VectorFont->units_per_EM;
465 for (
int c=
' '; c <= cMax; ++c)
471 throw std::runtime_error(std::string(
"Cannot render characters for Font (") +
szFontName +
")");
508 if (!szText)
return false;
521 if (fCheckMarkup) MarkupChecker.
SkipTags(&szText);
527 if (c ==
'\n' || (fCheckMarkup && c ==
'|')) { iRowWdt=0; iHgt+=
iLineHgt;
continue; }
529 if (c <
' ')
continue;
532 if (fCheckMarkup && c==
'{' && szText[0]==
'{' && szText[1]!=
'{' && (iImgLgt=
SCharPos(
'}', szText+1))>0 && szText[iImgLgt+2]==
'}')
535 SCopy(szText+1, imgbuf, std::min(iImgLgt, 100));
552 if (*szText) iRowWdt +=
iHSpace;
554 if (iRowWdt>iWdt) iWdt=iRowWdt;
570 if (!iMaxOutLen)
return 0;
576 auto t =
BreakMessage(szMsg, iWdt, fCheckMarkup, fZoom);
577 auto str = std::get<0>(t);
578 auto len = str.copy(szOut, iMaxOutLen);
580 return std::get<1>(t);
589 if (!szMsg || !pOut)
return 0;
590 auto t =
BreakMessage(szMsg, iWdt, fCheckMarkup, fZoom);
591 auto str = std::get<0>(t);
593 pOut->
Append(str.c_str(), str.size());
594 return std::get<1>(t);
602 return std::make_tuple(
"", 0);
604 if (!szMsg)
return std::make_tuple(
"", 0);
608 const char *szPos=szMsg,
609 *szLastBreakPos = szMsg,
610 *szLastEmergenyBreakPos =
nullptr,
612 int iLastBreakOutLen = 0, iLastEmergencyBreakOutLen = 0;
615 iXEmergencyBreak = 0,
617 int iCharHOverlap = std::max<int>(-
iHSpace, 0);
618 bool fIsFirstLineChar =
true;
622 while (*(szLastPos = szPos))
625 if (fCheckMarkup) MarkupChecker.
SkipTags(&szPos);
632 if (c !=
'\n' && (!fCheckMarkup || c !=
'|'))
636 if (fCheckMarkup && c==
'{' && szPos[0]==
'{' && szPos[1]!=
'{' && (iImgLgt=
SCharPos(
'}', szPos+1))>0 && szPos[iImgLgt+2]==
'}')
639 SCopy(szPos+1, imgbuf, std::min(iImgLgt, 100));
658 out.append(szLastPos, szPos - szLastPos);
660 if ((iX+=iCharWdt)+iCharHOverlap <= iWdt || fIsFirstLineChar)
664 if (c<256)
if (isspace((
unsigned char)c) || c ==
'-')
666 szLastBreakPos = szPos;
667 iLastBreakOutLen = out.size();
670 if (c !=
'-' && !fIsFirstLineChar) --szLastBreakPos;
674 szLastEmergenyBreakPos = szPos;
675 iXEmergencyBreak = iX;
676 iLastEmergencyBreakOutLen = out.size();
678 fIsFirstLineChar =
false;
684 if (c<128 && isspace((
unsigned char)c))
686 szLastBreakPos = szPos-1;
687 iLastBreakOutLen = out.size();
691 else if (szLastBreakPos == szMsg)
693 szLastBreakPos = szLastEmergenyBreakPos;
694 iLastBreakOutLen = iLastEmergencyBreakOutLen;
695 iXBreak = iXEmergencyBreak;
699 if (uint8_t(*szLastBreakPos)<128 && isspace((
unsigned char)*szLastBreakPos))
700 out.at(iLastBreakOutLen-1) =
'\n';
704 out.insert(iLastBreakOutLen, 1,
'\n');
714 out.append(szLastPos, szPos - szLastPos);
717 szLastBreakPos = szMsg = szPos;
720 fIsFirstLineChar =
true;
723 out.append(szLastPos, szPos - szLastPos);
725 return std::make_tuple(out, iHgt);
735 while(**ppNewPos) ++*ppNewPos;
736 return *ppNewPos - szMsg;
739 if (!szMsg || !*szMsg) { *ppNewPos = szMsg;
return 0; }
740 const char *szPos = szMsg;
unsigned char c;
741 int iWdt = 0;
int iPos = 0;
743 while ((c = *szPos++))
751 if (iWdt > iBreakWidth)
break;
762 const char *szPos2 = szPos-1;
int i=0;
763 while ((!i++ || *szPos2 !=
'-') && *szPos2 !=
' ')
774 if (szPos2 <= szMsg) szPos2 = szMsg+1;
777 if (*szPos2 ==
' ') ++*ppNewPos;
779 return szPos2 - szMsg;
797 if (fWasModulated)
ModulateClr(dwColor, dwOldModClr);
799 DWORD dwAlphaMod = std::min<uint32_t>(((dwColor>>0x18)*0xff)/0xaf, 255)<<0x18 | 0xffffff;
809 sx = int(fZoom*sx); sy = int(fZoom*sy);
817 sx = int(fZoom*sx); sy = int(fZoom*sy);
823 if (!Markup.
Clean()) pbt=&bt;
830 if (c <
' ')
continue;
835 if (Markup.
Read(&--szText))
849 char imgbuf[101] =
"";
850 if (c==
'{' && szText[0]==
'{' && szText[1]!=
'{' && (iImgLgt=
SCharPos(
'}', szText+1))>0 && szText[iImgLgt+2]==
'}' && !(dwFlags &
STDFONT_NOMARKUP))
852 SCopy(szText+1, imgbuf, std::min(iImgLgt, 100));
857 if ((dwColor>>0x18) >= 0xaf)
867 if(!fctFromBlt.
Surface)
continue;
868 w2=int(fctFromBlt.
Wdt*fZoom); h2=int(fctFromBlt.
Hgt*fZoom);
875 DWORD dwBlitClr = dwColor;
876 bt.
Set(1,0,0,0,1,0,0,0,1);
878 Markup.
Apply(bt, dwBlitClr);
879 if (dwBlitClr != dwColor)
ModulateClrA(dwBlitClr, dwAlphaMod);
882 float fOffX=(float) w2/2 + iX;
883 float fOffY=(float) h2/2 + iY;
884 bt.
mat[2] += fOffX - fOffX*bt.
mat[0] - fOffY*bt.
mat[1];
885 bt.
mat[5] += fOffY - fOffX*bt.
mat[3] - fOffY*bt.
mat[4];
896 pDraw->
Blit(fctFromBlt.
Surface,
float(fctFromBlt.
X), float(fctFromBlt.
Y), float(fctFromBlt.
Wdt),float(fctFromBlt.
Hgt),
897 sfcDest, iX, iY, float(w2), float(h2),
919 if (aspect < 0.0f)
return false;
923 width =
static_cast<int>(height * aspect + 0.5f);
928 float scale =
static_cast<float>(height)/
static_cast<float>(width);
931 height =
static_cast<int32_t
>(height*scale + 0.5f);
#define STDFONT_RIGHTALGN
const char * LoadResStr(const char *id)
bool LogF(const char *strMessage,...)
bool LogFatal(const char *szMessage)
int SCharPos(char cTarget, const char *szInStr, int iIndex)
bool SCopySegment(const char *szString, int iSegment, char *sTarget, char cSeparator, int iMaxL, bool fSkipWhitespace)
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
bool IsValidUtf8(const char *text, int length)
void SCopyUntil(const char *szSource, char *sTarget, char cUntil, int iMaxL, int iIndex)
uint32_t GetNextCharacter(const char **pszString)
StdStrBuf FormatString(const char *szFmt,...)
uint32_t RGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
void ModulateClr(DWORD &dwDst, DWORD dwMod)
void BltAlpha(DWORD &dwDst, DWORD dwSrc)
void ModulateClrA(DWORD &dwDst, DWORD dwMod)
bool Blit(C4Surface *sfcSource, float fx, float fy, float fwdt, float fhgt, C4Surface *sfcTarget, float tx, float ty, float twdt, float thgt, bool fSrcColKey=false, const C4BltTransform *pTransform=nullptr)
void DeactivateBlitModulation()
bool GetBlitModulation(DWORD &rdwColor)
void ActivateBlitModulation(DWORD dwWithClr)
void Set(C4Surface &rSfc)
StdCopyStrBuf LastUsedName
bool InitFont(CStdFont *Font, const char *szFontName, FontType eType, int32_t iSize, C4GroupSet *pGfxGroups, bool fDoShadow=true)
void DestroyFont(CStdVectorFont *pFont)
CStdVectorFont * CreateFont(StdBuf &Data)
CStdVectorFont * pLastUsedFont
bool LoadEntry(const char *entry_name, char **buffer, size_t *size_info=nullptr, int zeros_to_append=0)
C4Group * FindSuitableFile(const char *szName, const char *const extensions[], char *szFileName, int32_t *pID=nullptr)
void Apply(C4BltTransform &rBltTrf, DWORD &dwClr)
bool SkipTags(const char **ppText)
bool Read(const char **ppText, bool fSkip=false)
bool SetPixDw(int iX, int iY, DWORD dwCol)
virtual bool DrawFontImage(const char *szImageTag, C4Facet &cgo, C4DrawTransform *transform)=0
virtual float GetFontImageAspect(const char *szImageTag)=0
CustomImages * pCustomImages
std::vector< std::unique_ptr< C4Surface > > psfcFontData
std::tuple< std::string, int > BreakMessage(const char *szMsg, int iWdt, bool fCheckMarkup, float fZoom=1.0f)
void Init(CStdVectorFont &VectorFont, const char *font_face_name, DWORD dwHeight, DWORD dwFontWeight=FW_NORMAL, bool fDoShadow=true)
C4Facet & GetUnicodeCharacterFacet(uint32_t c)
bool IsInitialized() const
bool CheckRenderedCharSpace(uint32_t iCharWdt, uint32_t iCharHgt)
bool AddRenderedChar(uint32_t dwChar, C4Facet *pfctTarget)
bool IsSameAs(const char *szCFontName, DWORD iCHeight, DWORD dwCWeight) const
bool GetFontImageSize(const char *szTag, int &width, int &height) const
C4Facet fctAsciiTexCoords[256-' ']
bool GetTextExtent(const char *szText, int32_t &rsx, int32_t &rsy, bool fCheckMarkup=true)
C4Facet & GetCharacterFacet(uint32_t c)
CStdVectorFont * pVectorFont
void DrawText(C4Surface *sfcDest, float iX, float iY, DWORD dwColor, const char *szText, DWORD dwFlags, C4Markup &Markup, float fZoom)
int GetMessageBreak(const char *szMsg, const char **ppNewPos, int iBreakWidth, float fZoom=1.0f)
std::map< uint32_t, C4Facet > fctUnicodeMap
CStdVectorFont(StdBuf &Data)
CStdVectorFont(const char *FontFaceName)
void SetSize(size_t inSize)
const void * getData() const
void Append(const char *pnData, size_t iChars)