2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2010-05-29 07:25:38 +00:00
# include <base/math.h>
2020-09-26 19:41:58 +00:00
# include <base/system.h>
2021-09-12 17:40:23 +00:00
# include <cstddef>
# include <cstdint>
2010-05-29 07:25:38 +00:00
# include <engine/graphics.h>
2018-03-13 20:49:07 +00:00
# include <engine/storage.h>
2020-09-26 19:41:58 +00:00
# include <engine/textrender.h>
2010-05-29 07:25:38 +00:00
// ft2 texture
# include <ft2build.h>
# include FT_FREETYPE_H
2021-09-12 17:40:23 +00:00
# include <limits>
2010-05-29 07:25:38 +00:00
// TODO: Refactor: clean this up
enum
{
MAX_CHARACTERS = 64 ,
} ;
2018-03-13 20:49:07 +00:00
# include <map>
2020-09-26 19:41:58 +00:00
# include <vector>
2010-05-29 07:25:38 +00:00
2022-05-18 16:00:05 +00:00
# include <chrono>
using namespace std : : chrono_literals ;
2018-03-13 20:49:07 +00:00
struct SFontSizeChar
2010-05-29 07:25:38 +00:00
{
2011-02-12 10:40:36 +00:00
int m_ID ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// these values are scaled to the pFont size
// width * font_size == real_size
float m_Width ;
float m_Height ;
2021-09-12 17:40:23 +00:00
float m_CharWidth ;
float m_CharHeight ;
2010-05-29 07:25:38 +00:00
float m_OffsetX ;
float m_OffsetY ;
float m_AdvanceX ;
2011-04-13 18:37:12 +00:00
2018-03-13 20:49:07 +00:00
float m_aUVs [ 4 ] ;
2019-01-06 05:42:57 +00:00
FT_UInt m_GlyphIndex ;
2010-05-29 07:25:38 +00:00
} ;
2022-07-01 04:42:36 +00:00
typedef vector4_base < unsigned char > STextCharQuadVertexColor ;
2011-04-13 18:37:12 +00:00
2018-03-13 20:49:07 +00:00
struct STextCharQuadVertex
{
STextCharQuadVertex ( )
{
2022-07-01 04:42:36 +00:00
m_Color . r = m_Color . g = m_Color . b = m_Color . a = 255 ;
2018-03-13 20:49:07 +00:00
}
float m_X , m_Y ;
// do not use normalized floats as coordinates, since the texture might grow
float m_U , m_V ;
STextCharQuadVertexColor m_Color ;
} ;
2011-04-13 18:37:12 +00:00
2018-03-13 20:49:07 +00:00
struct STextCharQuad
{
2022-06-30 22:36:32 +00:00
STextCharQuadVertex m_aVertices [ 4 ] ;
2018-03-13 20:49:07 +00:00
} ;
2011-04-13 18:37:12 +00:00
2018-03-13 20:49:07 +00:00
struct STextureSkyline
{
// the height of each column
2022-06-11 19:38:18 +00:00
std : : vector < int > m_vCurHeightOfPixelColumn ;
2018-03-13 20:49:07 +00:00
} ;
2011-04-13 18:37:12 +00:00
2018-03-13 20:49:07 +00:00
struct CFontSizeData
{
int m_FontSize ;
FT_Face * m_pFace ;
2019-04-26 19:36:49 +00:00
2018-03-13 20:49:07 +00:00
std : : map < int , SFontSizeChar > m_Chars ;
2010-05-29 07:25:38 +00:00
} ;
2018-03-21 14:43:56 +00:00
# define MIN_FONT_SIZE 6
# define MAX_FONT_SIZE 128
2022-06-27 16:51:02 +00:00
# define NUM_FONT_SIZES (MAX_FONT_SIZE - MIN_FONT_SIZE + 1)
2018-03-21 14:43:56 +00:00
2010-07-05 18:57:07 +00:00
class CFont
2010-05-29 07:25:38 +00:00
{
2010-07-05 18:57:07 +00:00
public :
2020-09-30 21:38:05 +00:00
~ CFont ( )
{
free ( m_pBuf ) ;
2022-06-30 22:36:32 +00:00
delete [ ] m_apTextureData [ 0 ] ;
delete [ ] m_apTextureData [ 1 ] ;
2022-06-11 19:38:18 +00:00
for ( auto & FtFallbackFont : m_vFtFallbackFonts )
2020-09-30 21:38:05 +00:00
{
2020-10-26 14:14:07 +00:00
free ( FtFallbackFont . m_pBuf ) ;
2020-09-30 21:38:05 +00:00
}
}
2018-03-21 14:43:56 +00:00
void InitFontSizes ( )
{
for ( int i = 0 ; i < NUM_FONT_SIZES ; + + i )
{
m_aFontSizes [ i ] . m_FontSize = i + MIN_FONT_SIZE ;
m_aFontSizes [ i ] . m_pFace = & this - > m_FtFace ;
m_aFontSizes [ i ] . m_Chars . clear ( ) ;
}
}
2019-04-26 19:36:49 +00:00
2018-03-21 14:43:56 +00:00
CFontSizeData * GetFontSize ( int Pixelsize )
{
int FontSize = ( Pixelsize > = MIN_FONT_SIZE ? ( Pixelsize > MAX_FONT_SIZE ? MAX_FONT_SIZE : Pixelsize ) : MIN_FONT_SIZE ) ;
return & m_aFontSizes [ FontSize - MIN_FONT_SIZE ] ;
}
2020-09-30 21:38:05 +00:00
void * m_pBuf ;
2021-09-13 08:06:34 +00:00
char m_aFilename [ IO_MAX_PATH_LENGTH ] ;
2010-05-29 07:25:38 +00:00
FT_Face m_FtFace ;
2020-08-20 09:22:25 +00:00
struct SFontFallBack
{
2020-09-30 21:38:05 +00:00
void * m_pBuf ;
2021-09-13 08:06:34 +00:00
char m_aFilename [ IO_MAX_PATH_LENGTH ] ;
2020-08-20 09:22:25 +00:00
FT_Face m_FtFace ;
} ;
2022-06-11 19:38:18 +00:00
std : : vector < SFontFallBack > m_vFtFallbackFonts ;
2020-08-20 09:22:25 +00:00
2018-03-21 14:43:56 +00:00
CFontSizeData m_aFontSizes [ NUM_FONT_SIZES ] ;
2019-04-26 19:36:49 +00:00
2012-08-12 10:41:50 +00:00
IGraphics : : CTextureHandle m_aTextures [ 2 ] ;
2018-03-13 20:49:07 +00:00
// keep the full texture, because opengl doesn't provide texture copying
2022-06-30 22:36:32 +00:00
uint8_t * m_apTextureData [ 2 ] ;
2018-03-13 20:49:07 +00:00
// width and height are the same
2022-06-30 22:36:32 +00:00
int m_aCurTextureDimensions [ 2 ] ;
2018-03-13 20:49:07 +00:00
2022-06-30 22:36:32 +00:00
STextureSkyline m_aTextureSkyline [ 2 ] ;
2018-03-13 20:49:07 +00:00
} ;
struct STextString
{
int m_QuadBufferObjectIndex ;
int m_QuadBufferContainerIndex ;
size_t m_QuadNum ;
int m_SelectionQuadContainerIndex ;
2022-06-11 19:38:18 +00:00
std : : vector < STextCharQuad > m_vCharacterQuads ;
2018-03-13 20:49:07 +00:00
} ;
struct STextContainer
{
STextContainer ( ) { Reset ( ) ; }
2020-09-26 19:41:58 +00:00
CFont * m_pFont ;
2018-03-13 20:49:07 +00:00
int m_FontSize ;
STextString m_StringInfo ;
// keep these values to calculate offsets
2018-03-21 14:43:56 +00:00
float m_AlignedStartX ;
float m_AlignedStartY ;
2018-03-15 02:33:22 +00:00
float m_X ;
float m_Y ;
2018-03-13 20:49:07 +00:00
int m_Flags ;
int m_LineCount ;
2020-09-03 22:53:26 +00:00
int m_GlyphCount ;
2018-03-13 20:49:07 +00:00
int m_CharCount ;
int m_MaxLines ;
float m_StartX ;
float m_StartY ;
float m_LineWidth ;
float m_UnscaledFontSize ;
2018-03-21 14:43:56 +00:00
int m_RenderFlags ;
2021-09-16 14:50:17 +00:00
bool m_HasCursor ;
bool m_HasSelection ;
2022-03-20 17:03:25 +00:00
bool m_SingleTimeUse ;
2018-03-13 20:49:07 +00:00
void Reset ( )
{
2018-03-21 14:43:56 +00:00
m_pFont = NULL ;
m_FontSize = 0 ;
2018-03-13 20:49:07 +00:00
m_StringInfo . m_QuadBufferObjectIndex = m_StringInfo . m_QuadBufferContainerIndex = m_StringInfo . m_SelectionQuadContainerIndex = - 1 ;
m_StringInfo . m_QuadNum = 0 ;
2022-06-11 19:38:18 +00:00
m_StringInfo . m_vCharacterQuads . clear ( ) ;
2018-03-13 20:49:07 +00:00
2018-03-21 14:43:56 +00:00
m_AlignedStartX = m_AlignedStartY = m_X = m_Y = 0.f ;
2020-09-03 22:53:26 +00:00
m_Flags = m_LineCount = m_CharCount = m_GlyphCount = 0 ;
2018-03-13 20:49:07 +00:00
m_MaxLines = - 1 ;
m_StartX = m_StartY = 0.f ;
m_LineWidth = - 1.f ;
m_UnscaledFontSize = 0.f ;
2018-03-21 14:43:56 +00:00
m_RenderFlags = 0 ;
2021-09-16 14:50:17 +00:00
m_HasCursor = false ;
m_HasSelection = false ;
2022-03-20 17:03:25 +00:00
m_SingleTimeUse = false ;
2018-03-13 20:49:07 +00:00
}
2010-05-29 07:25:38 +00:00
} ;
class CTextRender : public IEngineTextRender
{
IGraphics * m_pGraphics ;
IGraphics * Graphics ( ) { return m_pGraphics ; }
2011-04-13 18:37:12 +00:00
2018-03-13 20:49:07 +00:00
unsigned int m_RenderFlags ;
2022-06-11 19:38:18 +00:00
std : : vector < STextContainer * > m_vpTextContainers ;
std : : vector < int > m_vTextContainerIndices ;
2018-03-13 20:49:07 +00:00
int m_FirstFreeTextContainerIndex ;
SBufferContainerInfo m_DefaultTextContainerInfo ;
2019-04-26 19:36:49 +00:00
2022-06-11 19:38:18 +00:00
std : : vector < CFont * > m_vpFonts ;
2018-03-13 20:49:07 +00:00
CFont * m_pCurFont ;
2022-05-18 16:00:05 +00:00
std : : chrono : : nanoseconds m_CursorRenderTime ;
2021-09-16 14:50:17 +00:00
2018-03-13 20:49:07 +00:00
int GetFreeTextContainerIndex ( )
{
if ( m_FirstFreeTextContainerIndex = = - 1 )
{
2022-06-11 19:38:18 +00:00
int Index = ( int ) m_vTextContainerIndices . size ( ) ;
m_vTextContainerIndices . push_back ( Index ) ;
2018-03-13 20:49:07 +00:00
return Index ;
}
else
{
int Index = m_FirstFreeTextContainerIndex ;
2022-06-11 19:38:18 +00:00
m_FirstFreeTextContainerIndex = m_vTextContainerIndices [ Index ] ;
m_vTextContainerIndices [ Index ] = Index ;
2018-03-13 20:49:07 +00:00
return Index ;
}
}
void FreeTextContainerIndex ( int Index )
{
2022-06-11 19:38:18 +00:00
m_vTextContainerIndices [ Index ] = m_FirstFreeTextContainerIndex ;
2018-03-13 20:49:07 +00:00
m_FirstFreeTextContainerIndex = Index ;
}
2020-10-13 20:08:52 +00:00
void FreeTextContainer ( int Index )
{
2022-06-11 19:38:18 +00:00
m_vpTextContainers [ Index ] - > Reset ( ) ;
2020-10-13 20:08:52 +00:00
FreeTextContainerIndex ( Index ) ;
}
2020-09-26 19:41:58 +00:00
STextContainer & GetTextContainer ( int Index )
2018-03-13 20:49:07 +00:00
{
2022-07-08 16:51:19 +00:00
dbg_assert ( Index > = 0 , " Text container index was invalid. " ) ;
2022-06-11 19:38:18 +00:00
if ( Index > = ( int ) m_vpTextContainers . size ( ) )
2018-03-13 20:49:07 +00:00
{
2022-06-11 19:38:18 +00:00
int Size = ( int ) m_vpTextContainers . size ( ) ;
2018-03-13 20:49:07 +00:00
for ( int i = 0 ; i < ( Index + 1 ) - Size ; + + i )
2022-06-11 19:38:18 +00:00
m_vpTextContainers . push_back ( new STextContainer ( ) ) ;
2018-03-13 20:49:07 +00:00
}
2022-06-11 19:38:18 +00:00
return * m_vpTextContainers [ Index ] ;
2018-03-13 20:49:07 +00:00
}
2010-05-29 07:25:38 +00:00
int WordLength ( const char * pText )
{
2021-12-20 01:17:10 +00:00
const char * pCursor = pText ;
2022-02-14 23:12:52 +00:00
while ( true )
2010-05-29 07:25:38 +00:00
{
2020-09-03 22:53:26 +00:00
if ( * pCursor = = 0 )
2021-12-20 01:34:02 +00:00
return pCursor - pText ;
2020-09-03 22:53:26 +00:00
if ( * pCursor = = ' \n ' | | * pCursor = = ' \t ' | | * pCursor = = ' ' )
2021-12-20 01:34:02 +00:00
return pCursor - pText + 1 ;
2021-12-20 01:17:10 +00:00
str_utf8_decode ( & pCursor ) ;
2010-05-29 07:25:38 +00:00
}
}
2019-04-26 22:34:20 +00:00
ColorRGBA m_Color ;
ColorRGBA m_OutlineColor ;
2021-09-12 17:40:23 +00:00
ColorRGBA m_SelectionColor ;
2010-07-05 18:57:07 +00:00
CFont * m_pDefaultFont ;
2010-05-29 07:25:38 +00:00
FT_Library m_FTLibrary ;
2019-04-26 19:36:49 +00:00
2022-05-17 18:33:27 +00:00
void SetRenderFlags ( unsigned int Flags ) override
2018-03-13 20:49:07 +00:00
{
m_RenderFlags = Flags ;
}
2019-04-26 19:36:49 +00:00
2022-05-17 18:33:27 +00:00
unsigned int GetRenderFlags ( ) override
2020-10-22 20:21:19 +00:00
{
return m_RenderFlags ;
}
2020-09-14 14:42:33 +00:00
void Grow ( unsigned char * pIn , unsigned char * pOut , int w , int h , int OutlineCount )
2010-05-29 07:25:38 +00:00
{
2011-04-13 18:37:12 +00:00
for ( int y = 0 ; y < h ; y + + )
for ( int x = 0 ; x < w ; x + + )
{
2020-09-26 19:41:58 +00:00
int c = pIn [ y * w + x ] ;
2010-05-29 07:25:38 +00:00
2020-09-14 14:42:33 +00:00
for ( int sy = - OutlineCount ; sy < = OutlineCount ; sy + + )
for ( int sx = - OutlineCount ; sx < = OutlineCount ; sx + + )
2010-05-29 07:25:38 +00:00
{
2020-09-26 19:41:58 +00:00
int GetX = x + sx ;
int GetY = y + sy ;
2018-03-13 20:49:07 +00:00
if ( GetX > = 0 & & GetY > = 0 & & GetX < w & & GetY < h )
2010-05-29 07:25:38 +00:00
{
2020-09-26 19:41:58 +00:00
int Index = GetY * w + GetX ;
2010-05-29 07:25:38 +00:00
if ( pIn [ Index ] > c )
2011-04-13 18:37:12 +00:00
c = pIn [ Index ] ;
2010-05-29 07:25:38 +00:00
}
}
2020-09-26 19:41:58 +00:00
pOut [ y * w + x ] = c ;
2010-05-29 07:25:38 +00:00
}
}
2022-03-20 17:03:25 +00:00
void InitTextures ( int Width , int Height , IGraphics : : CTextureHandle ( & aTextures ) [ 2 ] , uint8_t * ( & aTextureData ) [ 2 ] )
2019-04-26 19:36:49 +00:00
{
2022-03-20 17:03:25 +00:00
size_t NewTextureSize = ( size_t ) Width * ( size_t ) Height * 1 ;
void * pTmpTextData = malloc ( NewTextureSize ) ;
void * pTmpTextOutlineData = malloc ( NewTextureSize ) ;
mem_copy ( pTmpTextData , aTextureData [ 0 ] , NewTextureSize ) ;
mem_copy ( pTmpTextOutlineData , aTextureData [ 1 ] , NewTextureSize ) ;
Graphics ( ) - > LoadTextTextures ( Width , Height , aTextures [ 0 ] , aTextures [ 1 ] , pTmpTextData , pTmpTextOutlineData ) ;
2018-03-13 20:49:07 +00:00
}
2022-03-20 17:03:25 +00:00
void UnloadTextures ( IGraphics : : CTextureHandle ( & aTextures ) [ 2 ] )
2010-05-29 07:25:38 +00:00
{
2022-03-20 17:03:25 +00:00
Graphics ( ) - > UnloadTextTextures ( aTextures [ 0 ] , aTextures [ 1 ] ) ;
2018-03-13 20:49:07 +00:00
}
2022-03-20 17:03:25 +00:00
void IncreaseFontTextureImpl ( CFont * pFont , int TextureIndex , int NewDimensions )
2018-03-13 20:49:07 +00:00
{
2020-09-26 19:41:58 +00:00
unsigned char * pTmpTexBuffer = new unsigned char [ NewDimensions * NewDimensions ] ;
2020-10-05 17:03:14 +00:00
mem_zero ( pTmpTexBuffer , ( size_t ) NewDimensions * NewDimensions * sizeof ( unsigned char ) ) ;
2011-04-13 18:37:12 +00:00
2022-06-30 22:36:32 +00:00
for ( int y = 0 ; y < pFont - > m_aCurTextureDimensions [ TextureIndex ] ; + + y )
2011-12-31 08:40:11 +00:00
{
2022-06-30 22:36:32 +00:00
for ( int x = 0 ; x < pFont - > m_aCurTextureDimensions [ TextureIndex ] ; + + x )
2011-12-31 08:40:11 +00:00
{
2022-06-30 22:36:32 +00:00
pTmpTexBuffer [ x + y * NewDimensions ] = pFont - > m_apTextureData [ TextureIndex ] [ x + y * pFont - > m_aCurTextureDimensions [ TextureIndex ] ] ;
2011-12-31 08:40:11 +00:00
}
}
2019-04-26 19:36:49 +00:00
2022-06-30 22:36:32 +00:00
delete [ ] pFont - > m_apTextureData [ TextureIndex ] ;
pFont - > m_apTextureData [ TextureIndex ] = pTmpTexBuffer ;
pFont - > m_aCurTextureDimensions [ TextureIndex ] = NewDimensions ;
pFont - > m_aTextureSkyline [ TextureIndex ] . m_vCurHeightOfPixelColumn . resize ( NewDimensions , 0 ) ;
2010-05-29 07:25:38 +00:00
}
2022-03-20 17:03:25 +00:00
void IncreaseFontTexture ( CFont * pFont )
{
2022-06-30 22:36:32 +00:00
int NewDimensions = pFont - > m_aCurTextureDimensions [ 0 ] * 2 ;
2022-03-20 17:03:25 +00:00
UnloadTextures ( pFont - > m_aTextures ) ;
IncreaseFontTextureImpl ( pFont , 0 , NewDimensions ) ;
IncreaseFontTextureImpl ( pFont , 1 , NewDimensions ) ;
2022-06-30 22:36:32 +00:00
InitTextures ( NewDimensions , NewDimensions , pFont - > m_aTextures , pFont - > m_apTextureData ) ;
2022-03-20 17:03:25 +00:00
}
2011-01-29 17:48:55 +00:00
int AdjustOutlineThicknessToFontSize ( int OutlineThickness , int FontSize )
{
2018-03-21 14:43:56 +00:00
if ( FontSize > 48 )
2011-01-29 17:48:55 +00:00
OutlineThickness * = 4 ;
else if ( FontSize > = 18 )
OutlineThickness * = 2 ;
return OutlineThickness ;
2011-01-04 11:30:40 +00:00
}
2018-03-13 20:49:07 +00:00
void UploadGlyph ( CFont * pFont , int TextureIndex , int PosX , int PosY , int Width , int Height , const unsigned char * pData )
2010-05-29 07:25:38 +00:00
{
2018-03-13 20:49:07 +00:00
for ( int y = 0 ; y < Height ; + + y )
{
for ( int x = 0 ; x < Width ; + + x )
{
2022-06-30 22:36:32 +00:00
pFont - > m_apTextureData [ TextureIndex ] [ x + PosX + ( ( y + PosY ) * pFont - > m_aCurTextureDimensions [ TextureIndex ] ) ] = pData [ x + y * Width ] ;
2018-03-13 20:49:07 +00:00
}
}
2022-03-20 17:03:25 +00:00
Graphics ( ) - > UpdateTextTexture ( pFont - > m_aTextures [ TextureIndex ] , PosX , PosY , Width , Height , pData ) ;
2010-05-29 07:25:38 +00:00
}
2018-03-21 14:43:56 +00:00
// 128k * 2 of data used for rendering glyphs
2020-09-26 19:41:58 +00:00
unsigned char ms_aGlyphData [ ( 1024 / 4 ) * ( 1024 / 4 ) ] ;
unsigned char ms_aGlyphDataOutlined [ ( 1024 / 4 ) * ( 1024 / 4 ) ] ;
2018-03-13 20:49:07 +00:00
2020-09-26 19:41:58 +00:00
bool GetCharacterSpace ( CFont * pFont , int TextureIndex , int Width , int Height , int & PosX , int & PosY )
2010-05-29 07:25:38 +00:00
{
2022-06-30 22:36:32 +00:00
if ( pFont - > m_aCurTextureDimensions [ TextureIndex ] < Width )
2018-03-13 20:49:07 +00:00
return false ;
2022-06-30 22:36:32 +00:00
if ( pFont - > m_aCurTextureDimensions [ TextureIndex ] < Height )
2018-03-13 20:49:07 +00:00
return false ;
2010-05-29 07:25:38 +00:00
2018-03-26 03:08:21 +00:00
// skyline bottom left algorithm
2022-06-30 22:36:32 +00:00
std : : vector < int > & vSkylineHeights = pFont - > m_aTextureSkyline [ TextureIndex ] . m_vCurHeightOfPixelColumn ;
2018-03-13 20:49:07 +00:00
2018-03-26 03:08:21 +00:00
// search a fitting area with less pixel loss
2018-03-13 20:49:07 +00:00
int SmallestPixelLossAreaX = 0 ;
2022-06-30 22:36:32 +00:00
int SmallestPixelLossAreaY = pFont - > m_aCurTextureDimensions [ TextureIndex ] + 1 ;
int SmallestPixelLossCurPixelLoss = pFont - > m_aCurTextureDimensions [ TextureIndex ] * pFont - > m_aCurTextureDimensions [ TextureIndex ] ;
2018-03-13 20:49:07 +00:00
bool FoundAnyArea = false ;
2022-06-15 17:34:41 +00:00
for ( size_t i = 0 ; i < vSkylineHeights . size ( ) ; i + + )
2010-05-29 07:25:38 +00:00
{
2022-06-15 17:34:41 +00:00
int CurHeight = vSkylineHeights [ i ] ;
2018-03-13 20:49:07 +00:00
int CurPixelLoss = 0 ;
// find width pixels, and we are happy
int AreaWidth = 1 ;
2022-06-15 17:34:41 +00:00
for ( size_t n = i + 1 ; n < i + Width & & n < vSkylineHeights . size ( ) ; + + n )
2010-05-29 07:25:38 +00:00
{
2018-03-26 03:08:21 +00:00
+ + AreaWidth ;
2022-06-15 17:34:41 +00:00
if ( vSkylineHeights [ n ] < = CurHeight )
2018-03-13 20:49:07 +00:00
{
2022-06-15 17:34:41 +00:00
CurPixelLoss + = CurHeight - vSkylineHeights [ n ] ;
2018-03-13 20:49:07 +00:00
}
// if the height changed, we will use that new height and adjust the pixel loss
else
{
CurPixelLoss = 0 ;
2022-06-15 17:34:41 +00:00
CurHeight = vSkylineHeights [ n ] ;
2018-03-13 20:49:07 +00:00
for ( size_t l = i ; l < = n ; + + l )
{
2022-06-15 17:34:41 +00:00
CurPixelLoss + = CurHeight - vSkylineHeights [ l ] ;
2018-03-13 20:49:07 +00:00
}
}
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2018-03-13 20:49:07 +00:00
// if the area is too high, continue
2022-06-30 22:36:32 +00:00
if ( CurHeight + Height > pFont - > m_aCurTextureDimensions [ TextureIndex ] )
2018-03-13 20:49:07 +00:00
continue ;
// if the found area fits our needs, check if we can use it
if ( AreaWidth = = Width )
2010-05-29 07:25:38 +00:00
{
2018-03-13 20:49:07 +00:00
if ( SmallestPixelLossCurPixelLoss > = CurPixelLoss )
{
if ( CurHeight < SmallestPixelLossAreaY )
{
SmallestPixelLossCurPixelLoss = CurPixelLoss ;
SmallestPixelLossAreaX = ( int ) i ;
SmallestPixelLossAreaY = CurHeight ;
FoundAnyArea = true ;
if ( CurPixelLoss = = 0 )
break ;
}
}
2010-05-29 07:25:38 +00:00
}
2018-03-13 20:49:07 +00:00
}
2011-04-13 18:37:12 +00:00
2018-03-13 20:49:07 +00:00
if ( FoundAnyArea )
{
PosX = SmallestPixelLossAreaX ;
PosY = SmallestPixelLossAreaY ;
for ( int i = PosX ; i < PosX + Width ; + + i )
{
2022-06-15 17:34:41 +00:00
vSkylineHeights [ i ] = PosY + Height ;
2018-03-13 20:49:07 +00:00
}
return true ;
2010-05-29 07:25:38 +00:00
}
2018-03-13 20:49:07 +00:00
else
return false ;
2010-05-29 07:25:38 +00:00
}
2020-08-20 09:22:25 +00:00
void RenderGlyph ( CFont * pFont , CFontSizeData * pSizeData , int Chr )
2010-05-29 07:25:38 +00:00
{
FT_Bitmap * pBitmap ;
2018-03-13 20:49:07 +00:00
2021-09-12 17:40:23 +00:00
int x = 0 ;
int y = 0 ;
2017-03-12 15:47:37 +00:00
unsigned int px , py ;
2010-05-29 07:25:38 +00:00
2020-08-20 09:22:25 +00:00
FT_Face FtFace = pFont - > m_FtFace ;
2020-08-20 06:54:59 +00:00
2020-08-20 09:22:25 +00:00
FT_Set_Pixel_Sizes ( FtFace , 0 , pSizeData - > m_FontSize ) ;
2010-05-29 07:25:38 +00:00
2019-01-06 05:42:57 +00:00
FT_UInt GlyphIndex = 0 ;
2020-08-20 09:22:25 +00:00
if ( FtFace - > charmap )
GlyphIndex = FT_Get_Char_Index ( FtFace , ( FT_ULong ) Chr ) ;
2019-01-06 05:42:57 +00:00
2019-03-28 21:38:20 +00:00
if ( GlyphIndex = = 0 )
{
2022-06-11 19:38:18 +00:00
for ( CFont : : SFontFallBack & FallbackFont : pFont - > m_vFtFallbackFonts )
2020-08-20 06:54:59 +00:00
{
2020-08-20 09:22:25 +00:00
FtFace = FallbackFont . m_FtFace ;
FT_Set_Pixel_Sizes ( FtFace , 0 , pSizeData - > m_FontSize ) ;
if ( FtFace - > charmap )
GlyphIndex = FT_Get_Char_Index ( FtFace , ( FT_ULong ) Chr ) ;
2020-08-20 06:54:59 +00:00
2020-08-20 09:22:25 +00:00
if ( GlyphIndex ! = 0 )
break ;
2020-08-20 06:54:59 +00:00
}
2019-03-28 21:38:20 +00:00
if ( GlyphIndex = = 0 )
{
2020-08-20 06:54:59 +00:00
const int ReplacementChr = 0x25a1 ; // White square to indicate missing glyph
2020-08-20 09:22:25 +00:00
FtFace = pFont - > m_FtFace ;
GlyphIndex = FT_Get_Char_Index ( FtFace , ( FT_ULong ) ReplacementChr ) ;
2020-08-20 06:54:59 +00:00
if ( GlyphIndex = = 0 )
{
2020-10-26 08:57:41 +00:00
dbg_msg ( " textrender " , " font has no glyph for either %d or replacement char %d " , Chr , ReplacementChr ) ;
2020-08-20 06:54:59 +00:00
return ;
}
2019-03-28 21:38:20 +00:00
}
}
2020-09-26 19:41:58 +00:00
if ( FT_Load_Glyph ( FtFace , GlyphIndex , FT_LOAD_RENDER | FT_LOAD_NO_BITMAP ) )
2010-05-29 07:25:38 +00:00
{
2020-10-26 08:57:41 +00:00
dbg_msg ( " textrender " , " error loading glyph %d " , Chr ) ;
2018-03-13 20:49:07 +00:00
return ;
2010-05-29 07:25:38 +00:00
}
2022-02-16 19:54:11 +00:00
pBitmap = & FtFace - > glyph - > bitmap ;
2019-04-26 19:36:49 +00:00
2021-09-12 17:40:23 +00:00
unsigned int RealWidth = pBitmap - > width ;
unsigned int RealHeight = pBitmap - > rows ;
2010-05-29 07:25:38 +00:00
2021-09-12 17:40:23 +00:00
// adjust spacing
int OutlineThickness = 0 ;
if ( RealWidth > 0 )
{
OutlineThickness = AdjustOutlineThicknessToFontSize ( 1 , pSizeData - > m_FontSize ) ;
2010-05-29 07:25:38 +00:00
2021-09-12 17:40:23 +00:00
x + = ( OutlineThickness + 1 ) ;
y + = ( OutlineThickness + 1 ) ;
}
2018-03-13 20:49:07 +00:00
2021-09-12 17:40:23 +00:00
unsigned int Width = RealWidth + x * 2 ;
unsigned int Height = RealHeight + y * 2 ;
2019-04-26 19:36:49 +00:00
2018-03-13 20:49:07 +00:00
int X = 0 ;
int Y = 0 ;
2021-09-12 17:40:23 +00:00
if ( Width > 0 & & Height > 0 )
2018-03-13 20:49:07 +00:00
{
2021-09-12 17:40:23 +00:00
// prepare glyph data
mem_zero ( ms_aGlyphData , Width * Height ) ;
2011-04-13 18:37:12 +00:00
2022-02-16 19:54:11 +00:00
for ( py = 0 ; py < pBitmap - > rows ; py + + )
for ( px = 0 ; px < pBitmap - > width ; px + + )
ms_aGlyphData [ ( py + y ) * Width + px + x ] = pBitmap - > buffer [ py * pBitmap - > width + px ] ;
2020-09-14 14:42:33 +00:00
2021-09-12 17:40:23 +00:00
// upload the glyph
while ( ! GetCharacterSpace ( pFont , 0 , ( int ) Width , ( int ) Height , X , Y ) )
{
2022-03-20 17:03:25 +00:00
IncreaseFontTexture ( pFont ) ;
2021-09-12 17:40:23 +00:00
}
UploadGlyph ( pFont , 0 , X , Y , ( int ) Width , ( int ) Height , ms_aGlyphData ) ;
Grow ( ms_aGlyphData , ms_aGlyphDataOutlined , Width , Height , OutlineThickness ) ;
while ( ! GetCharacterSpace ( pFont , 1 , ( int ) Width , ( int ) Height , X , Y ) )
{
2022-03-20 17:03:25 +00:00
IncreaseFontTexture ( pFont ) ;
2021-09-12 17:40:23 +00:00
}
UploadGlyph ( pFont , 1 , X , Y , ( int ) Width , ( int ) Height , ms_aGlyphDataOutlined ) ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// set char info
{
2018-03-13 20:49:07 +00:00
SFontSizeChar * pFontchr = & pSizeData - > m_Chars [ Chr ] ;
int BMPHeight = pBitmap - > rows + y * 2 ;
int BMPWidth = pBitmap - > width + x * 2 ;
2011-04-13 18:37:12 +00:00
2011-02-12 10:40:36 +00:00
pFontchr - > m_ID = Chr ;
2018-03-13 20:49:07 +00:00
pFontchr - > m_Height = Height ;
pFontchr - > m_Width = Width ;
2021-09-12 17:40:23 +00:00
pFontchr - > m_CharHeight = RealHeight ;
pFontchr - > m_CharWidth = RealWidth ;
2022-02-16 19:54:11 +00:00
pFontchr - > m_OffsetX = ( FtFace - > glyph - > metrics . horiBearingX > > 6 ) ;
2020-08-20 09:22:25 +00:00
pFontchr - > m_OffsetY = - ( ( FtFace - > glyph - > metrics . height > > 6 ) - ( FtFace - > glyph - > metrics . horiBearingY > > 6 ) ) ;
2022-02-16 19:54:11 +00:00
pFontchr - > m_AdvanceX = ( FtFace - > glyph - > advance . x > > 6 ) ;
2018-03-13 20:49:07 +00:00
pFontchr - > m_aUVs [ 0 ] = X ;
pFontchr - > m_aUVs [ 1 ] = Y ;
pFontchr - > m_aUVs [ 2 ] = pFontchr - > m_aUVs [ 0 ] + BMPWidth ;
pFontchr - > m_aUVs [ 3 ] = pFontchr - > m_aUVs [ 1 ] + BMPHeight ;
2019-01-06 05:42:57 +00:00
pFontchr - > m_GlyphIndex = GlyphIndex ;
2010-05-29 07:25:38 +00:00
}
}
2020-08-20 09:22:25 +00:00
SFontSizeChar * GetChar ( CFont * pFont , CFontSizeData * pSizeData , int Chr )
2010-05-29 07:25:38 +00:00
{
2018-03-13 20:49:07 +00:00
std : : map < int , SFontSizeChar > : : iterator it = pSizeData - > m_Chars . find ( Chr ) ;
if ( it = = pSizeData - > m_Chars . end ( ) )
2010-05-29 07:25:38 +00:00
{
2018-03-13 20:49:07 +00:00
// render and add character
2020-09-26 19:41:58 +00:00
SFontSizeChar & FontSizeChr = pSizeData - > m_Chars [ Chr ] ;
2019-04-26 19:36:49 +00:00
2020-08-20 09:22:25 +00:00
RenderGlyph ( pFont , pSizeData , Chr ) ;
2019-04-26 19:36:49 +00:00
2018-03-13 20:49:07 +00:00
return & FontSizeChr ;
2010-05-29 07:25:38 +00:00
}
2018-03-13 20:49:07 +00:00
else
2010-05-29 07:25:38 +00:00
{
2018-03-13 20:49:07 +00:00
return & it - > second ;
2010-05-29 07:25:38 +00:00
}
}
2019-04-26 19:36:49 +00:00
2019-01-06 05:42:57 +00:00
float Kerning ( CFont * pFont , FT_UInt GlyphIndexLeft , FT_UInt GlyphIndexRight )
2010-05-29 07:25:38 +00:00
{
2020-09-26 19:41:58 +00:00
FT_Vector Kerning = { 0 , 0 } ;
2019-01-06 05:42:57 +00:00
FT_Get_Kerning ( pFont - > m_FtFace , GlyphIndexLeft , GlyphIndexRight , FT_KERNING_DEFAULT , & Kerning ) ;
2020-09-26 19:41:58 +00:00
return ( Kerning . x > > 6 ) ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
public :
CTextRender ( )
{
m_pGraphics = 0 ;
2021-09-12 17:40:23 +00:00
m_Color = DefaultTextColor ( ) ;
m_OutlineColor = DefaultTextOutlineColor ( ) ;
m_SelectionColor = DefaultSelectionColor ( ) ;
2010-05-29 07:25:38 +00:00
2018-03-13 20:49:07 +00:00
m_pCurFont = 0 ;
2010-05-29 07:25:38 +00:00
m_pDefaultFont = 0 ;
2017-07-21 18:45:23 +00:00
m_FTLibrary = 0 ;
2010-05-29 07:25:38 +00:00
2018-03-21 14:43:56 +00:00
m_RenderFlags = 0 ;
2022-06-13 16:07:29 +00:00
m_CursorRenderTime = time_get_nanoseconds ( ) ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2017-07-21 17:10:50 +00:00
virtual ~ CTextRender ( )
{
2022-06-11 19:38:18 +00:00
for ( auto * pTextCont : m_vpTextContainers )
2021-09-12 17:40:23 +00:00
{
pTextCont - > Reset ( ) ;
delete pTextCont ;
}
2022-06-11 19:38:18 +00:00
m_vpTextContainers . clear ( ) ;
2021-09-12 17:40:23 +00:00
2022-06-11 19:38:18 +00:00
for ( auto & pFont : m_vpFonts )
2018-03-13 20:49:07 +00:00
{
2020-10-26 14:14:07 +00:00
FT_Done_Face ( pFont - > m_FtFace ) ;
2020-09-30 21:38:05 +00:00
2022-06-11 19:38:18 +00:00
for ( CFont : : SFontFallBack & FallbackFont : pFont - > m_vFtFallbackFonts )
2020-09-30 21:38:05 +00:00
{
FT_Done_Face ( FallbackFont . m_FtFace ) ;
}
2020-10-26 14:14:07 +00:00
delete pFont ;
2018-03-13 20:49:07 +00:00
}
2017-07-21 18:45:23 +00:00
2017-07-28 18:44:03 +00:00
if ( m_FTLibrary ! = 0 )
2017-07-21 18:45:23 +00:00
FT_Done_FreeType ( m_FTLibrary ) ;
2017-07-21 17:10:50 +00:00
}
2022-05-17 18:33:27 +00:00
void Init ( ) override
2010-05-29 07:25:38 +00:00
{
m_pGraphics = Kernel ( ) - > RequestInterface < IGraphics > ( ) ;
FT_Init_FreeType ( & m_FTLibrary ) ;
2020-03-20 12:48:45 +00:00
// print freetype version
{
int LMajor , LMinor , LPatch ;
FT_Library_Version ( m_FTLibrary , & LMajor , & LMinor , & LPatch ) ;
2020-03-23 11:50:19 +00:00
dbg_msg ( " freetype " , " freetype version %d.%d.%d (compiled = %d.%d.%d) " , LMajor , LMinor , LPatch ,
FREETYPE_MAJOR , FREETYPE_MINOR , FREETYPE_PATCH ) ;
2020-03-20 12:48:45 +00:00
}
2018-03-13 20:49:07 +00:00
m_FirstFreeTextContainerIndex = - 1 ;
m_DefaultTextContainerInfo . m_Stride = sizeof ( STextCharQuadVertex ) ;
2022-03-20 17:03:25 +00:00
m_DefaultTextContainerInfo . m_VertBufferBindingIndex = - 1 ;
2018-03-13 20:49:07 +00:00
2022-06-11 19:38:18 +00:00
m_DefaultTextContainerInfo . m_vAttributes . emplace_back ( ) ;
SBufferContainerInfo : : SAttribute * pAttr = & m_DefaultTextContainerInfo . m_vAttributes . back ( ) ;
2018-03-13 20:49:07 +00:00
pAttr - > m_DataTypeCount = 2 ;
pAttr - > m_FuncType = 0 ;
pAttr - > m_Normalized = false ;
pAttr - > m_pOffset = 0 ;
pAttr - > m_Type = GRAPHICS_TYPE_FLOAT ;
2022-06-11 19:38:18 +00:00
m_DefaultTextContainerInfo . m_vAttributes . emplace_back ( ) ;
pAttr = & m_DefaultTextContainerInfo . m_vAttributes . back ( ) ;
2018-03-13 20:49:07 +00:00
pAttr - > m_DataTypeCount = 2 ;
pAttr - > m_FuncType = 0 ;
pAttr - > m_Normalized = false ;
2020-09-26 19:41:58 +00:00
pAttr - > m_pOffset = ( void * ) ( sizeof ( float ) * 2 ) ;
2018-03-13 20:49:07 +00:00
pAttr - > m_Type = GRAPHICS_TYPE_FLOAT ;
2022-06-11 19:38:18 +00:00
m_DefaultTextContainerInfo . m_vAttributes . emplace_back ( ) ;
pAttr = & m_DefaultTextContainerInfo . m_vAttributes . back ( ) ;
2018-03-13 20:49:07 +00:00
pAttr - > m_DataTypeCount = 4 ;
pAttr - > m_FuncType = 0 ;
pAttr - > m_Normalized = true ;
2020-09-26 19:41:58 +00:00
pAttr - > m_pOffset = ( void * ) ( sizeof ( float ) * 2 + sizeof ( float ) * 2 ) ;
2018-03-13 20:49:07 +00:00
pAttr - > m_Type = GRAPHICS_TYPE_UNSIGNED_BYTE ;
IStorage * pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
2021-09-13 08:06:34 +00:00
char aFilename [ IO_MAX_PATH_LENGTH ] ;
2022-03-19 10:21:47 +00:00
const char * pFontFile = " fonts/Icons.otf " ;
2018-03-13 20:49:07 +00:00
IOHANDLE File = pStorage - > OpenFile ( pFontFile , IOFLAG_READ , IStorage : : TYPE_ALL , aFilename , sizeof ( aFilename ) ) ;
if ( File )
{
2022-06-14 18:52:05 +00:00
void * pBuf ;
unsigned Size ;
io_read_all ( File , & pBuf , & Size ) ;
2018-03-13 20:49:07 +00:00
io_close ( File ) ;
2022-06-14 18:52:05 +00:00
LoadFont ( aFilename , ( unsigned char * ) pBuf , Size ) ;
2018-03-13 20:49:07 +00:00
}
2010-05-29 07:25:38 +00:00
}
2019-04-26 19:36:49 +00:00
2022-05-17 18:33:27 +00:00
CFont * LoadFont ( const char * pFilename , const unsigned char * pBuf , size_t Size ) override
2010-05-29 07:25:38 +00:00
{
2018-03-13 20:49:07 +00:00
CFont * pFont = new CFont ( ) ;
2011-04-13 18:37:12 +00:00
2022-07-09 16:14:56 +00:00
str_copy ( pFont - > m_aFilename , pFilename ) ;
2011-04-13 18:37:12 +00:00
2020-09-13 21:02:01 +00:00
if ( FT_New_Memory_Face ( m_FTLibrary , pBuf , Size , 0 , & pFont - > m_FtFace ) )
2010-05-29 07:25:38 +00:00
{
2018-03-13 20:49:07 +00:00
delete pFont ;
2010-05-29 07:25:38 +00:00
return NULL ;
}
2022-06-28 15:48:41 +00:00
dbg_msg ( " textrender " , " loaded font from '%s' " , pFilename ) ;
2018-03-13 20:49:07 +00:00
2020-09-30 21:38:05 +00:00
pFont - > m_pBuf = ( void * ) pBuf ;
2022-06-30 22:36:32 +00:00
pFont - > m_aCurTextureDimensions [ 0 ] = 1024 ;
pFont - > m_apTextureData [ 0 ] = new unsigned char [ pFont - > m_aCurTextureDimensions [ 0 ] * pFont - > m_aCurTextureDimensions [ 0 ] ] ;
mem_zero ( pFont - > m_apTextureData [ 0 ] , ( size_t ) pFont - > m_aCurTextureDimensions [ 0 ] * pFont - > m_aCurTextureDimensions [ 0 ] * sizeof ( unsigned char ) ) ;
pFont - > m_aCurTextureDimensions [ 1 ] = 1024 ;
pFont - > m_apTextureData [ 1 ] = new unsigned char [ pFont - > m_aCurTextureDimensions [ 1 ] * pFont - > m_aCurTextureDimensions [ 1 ] ] ;
mem_zero ( pFont - > m_apTextureData [ 1 ] , ( size_t ) pFont - > m_aCurTextureDimensions [ 1 ] * pFont - > m_aCurTextureDimensions [ 1 ] * sizeof ( unsigned char ) ) ;
2018-03-13 20:49:07 +00:00
2022-06-30 22:36:32 +00:00
InitTextures ( pFont - > m_aCurTextureDimensions [ 0 ] , pFont - > m_aCurTextureDimensions [ 0 ] , pFont - > m_aTextures , pFont - > m_apTextureData ) ;
2018-03-13 20:49:07 +00:00
2022-06-30 22:36:32 +00:00
pFont - > m_aTextureSkyline [ 0 ] . m_vCurHeightOfPixelColumn . resize ( pFont - > m_aCurTextureDimensions [ 0 ] , 0 ) ;
pFont - > m_aTextureSkyline [ 1 ] . m_vCurHeightOfPixelColumn . resize ( pFont - > m_aCurTextureDimensions [ 1 ] , 0 ) ;
2019-04-26 19:36:49 +00:00
2018-03-21 14:43:56 +00:00
pFont - > InitFontSizes ( ) ;
2022-06-11 19:38:18 +00:00
m_vpFonts . push_back ( pFont ) ;
2018-03-13 20:49:07 +00:00
2010-05-29 07:25:38 +00:00
return pFont ;
2020-08-20 09:22:25 +00:00
}
2022-05-17 18:33:27 +00:00
bool LoadFallbackFont ( CFont * pFont , const char * pFilename , const unsigned char * pBuf , size_t Size ) override
2020-08-20 09:22:25 +00:00
{
CFont : : SFontFallBack FallbackFont ;
2020-09-30 21:38:05 +00:00
FallbackFont . m_pBuf = ( void * ) pBuf ;
2022-07-09 16:14:56 +00:00
str_copy ( FallbackFont . m_aFilename , pFilename ) ;
2020-08-20 09:22:25 +00:00
2020-09-13 21:02:01 +00:00
if ( FT_New_Memory_Face ( m_FTLibrary , pBuf , Size , 0 , & FallbackFont . m_FtFace ) = = 0 )
2020-08-20 09:22:25 +00:00
{
dbg_msg ( " textrender " , " loaded fallback font from '%s' " , pFilename ) ;
2022-06-11 19:38:18 +00:00
pFont - > m_vFtFallbackFonts . emplace_back ( FallbackFont ) ;
2020-08-20 09:22:25 +00:00
return true ;
}
return false ;
}
2019-04-26 19:36:49 +00:00
2022-05-17 18:33:27 +00:00
CFont * GetFont ( int FontIndex ) override
2018-03-13 20:49:07 +00:00
{
2022-06-11 19:38:18 +00:00
if ( FontIndex > = 0 & & FontIndex < ( int ) m_vpFonts . size ( ) )
return m_vpFonts [ FontIndex ] ;
2018-03-13 20:49:07 +00:00
return NULL ;
}
2022-05-17 18:33:27 +00:00
CFont * GetFont ( const char * pFilename ) override
2018-03-13 20:49:07 +00:00
{
2022-06-11 19:38:18 +00:00
for ( auto & pFont : m_vpFonts )
2018-03-13 20:49:07 +00:00
{
2020-10-26 14:14:07 +00:00
if ( str_comp ( pFilename , pFont - > m_aFilename ) = = 0 )
return pFont ;
2018-03-13 20:49:07 +00:00
}
return NULL ;
}
2010-05-29 07:25:38 +00:00
2022-05-17 18:33:27 +00:00
void SetDefaultFont ( CFont * pFont ) override
2010-05-29 07:25:38 +00:00
{
2022-06-28 15:48:41 +00:00
dbg_msg ( " textrender " , " default font set to '%s' " , pFont - > m_aFilename ) ;
2010-05-29 07:25:38 +00:00
m_pDefaultFont = pFont ;
2018-03-13 20:49:07 +00:00
m_pCurFont = m_pDefaultFont ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2022-05-17 18:33:27 +00:00
void SetCurFont ( CFont * pFont ) override
2018-03-13 20:49:07 +00:00
{
if ( pFont = = NULL )
m_pCurFont = m_pDefaultFont ;
else
m_pCurFont = pFont ;
}
2011-04-13 18:37:12 +00:00
2022-05-17 18:33:27 +00:00
void SetCursor ( CTextCursor * pCursor , float x , float y , float FontSize , int Flags ) override
2010-05-29 07:25:38 +00:00
{
mem_zero ( pCursor , sizeof ( * pCursor ) ) ;
pCursor - > m_FontSize = FontSize ;
pCursor - > m_StartX = x ;
pCursor - > m_StartY = y ;
pCursor - > m_X = x ;
pCursor - > m_Y = y ;
pCursor - > m_LineCount = 1 ;
pCursor - > m_LineWidth = - 1 ;
pCursor - > m_Flags = Flags ;
2020-09-03 22:53:26 +00:00
pCursor - > m_GlyphCount = 0 ;
2010-05-29 07:25:38 +00:00
pCursor - > m_CharCount = 0 ;
2020-10-06 10:25:10 +00:00
pCursor - > m_MaxCharacterHeight = 0 ;
2020-10-13 20:08:52 +00:00
pCursor - > m_LongestLineWidth = 0 ;
2021-09-12 17:40:23 +00:00
pCursor - > m_CalculateSelectionMode = TEXT_CURSOR_SELECTION_MODE_NONE ;
pCursor - > m_PressMouseX = 0 ;
pCursor - > m_PressMouseY = 0 ;
pCursor - > m_ReleaseMouseX = 0 ;
pCursor - > m_ReleaseMouseY = 0 ;
pCursor - > m_SelectionStart = 0 ;
pCursor - > m_SelectionEnd = 0 ;
2021-09-16 14:50:17 +00:00
pCursor - > m_CursorMode = TEXT_CURSOR_CURSOR_MODE_NONE ;
pCursor - > m_CursorCharacter = - 1 ;
2020-10-13 20:08:52 +00:00
}
2022-05-17 18:33:27 +00:00
void MoveCursor ( CTextCursor * pCursor , float x , float y ) override
2020-10-13 20:08:52 +00:00
{
pCursor - > m_X + = x ;
pCursor - > m_Y + = y ;
2010-05-29 07:25:38 +00:00
}
2019-04-26 19:36:49 +00:00
2022-05-17 18:33:27 +00:00
void SetCursorPosition ( CTextCursor * pCursor , float x , float y ) override
2020-10-29 00:55:01 +00:00
{
pCursor - > m_X = x ;
pCursor - > m_Y = y ;
}
2022-05-17 18:33:27 +00:00
void Text ( void * pFontSetV , float x , float y , float Size , const char * pText , float LineWidth ) override
2010-05-29 07:25:38 +00:00
{
CTextCursor Cursor ;
SetCursor ( & Cursor , x , y , Size , TEXTFLAG_RENDER ) ;
2020-07-15 19:42:48 +00:00
Cursor . m_LineWidth = LineWidth ;
2020-10-06 10:25:10 +00:00
int OldRenderFlags = m_RenderFlags ;
if ( LineWidth < = 0 )
SetRenderFlags ( OldRenderFlags | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_LAST_CHARACTER_ADVANCE ) ;
2010-05-29 07:25:38 +00:00
TextEx ( & Cursor , pText , - 1 ) ;
2020-10-06 10:25:10 +00:00
SetRenderFlags ( OldRenderFlags ) ;
2010-05-29 07:25:38 +00:00
}
2022-05-17 18:33:27 +00:00
float TextWidth ( void * pFontSetV , float Size , const char * pText , int StrLength , float LineWidth , float * pAlignedHeight = NULL , float * pMaxCharacterHeightInLine = NULL ) override
2010-05-29 07:25:38 +00:00
{
CTextCursor Cursor ;
SetCursor ( & Cursor , 0 , 0 , Size , 0 ) ;
2020-07-15 19:10:13 +00:00
Cursor . m_LineWidth = LineWidth ;
2020-10-06 10:25:10 +00:00
int OldRenderFlags = m_RenderFlags ;
if ( LineWidth < = 0 )
SetRenderFlags ( OldRenderFlags | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_LAST_CHARACTER_ADVANCE ) ;
2020-07-15 19:10:13 +00:00
TextEx ( & Cursor , pText , StrLength ) ;
2020-10-06 10:25:10 +00:00
SetRenderFlags ( OldRenderFlags ) ;
2018-03-21 14:43:56 +00:00
if ( pAlignedHeight ! = NULL )
* pAlignedHeight = Cursor . m_AlignedFontSize ;
2020-10-06 10:25:10 +00:00
if ( pMaxCharacterHeightInLine ! = NULL )
* pMaxCharacterHeightInLine = Cursor . m_MaxCharacterHeight ;
2010-05-29 07:25:38 +00:00
return Cursor . m_X ;
}
2011-04-13 18:37:12 +00:00
2022-05-17 18:33:27 +00:00
int TextLineCount ( void * pFontSetV , float Size , const char * pText , float LineWidth ) override
2010-05-29 07:25:38 +00:00
{
CTextCursor Cursor ;
SetCursor ( & Cursor , 0 , 0 , Size , 0 ) ;
Cursor . m_LineWidth = LineWidth ;
2020-10-06 10:25:10 +00:00
int OldRenderFlags = m_RenderFlags ;
if ( LineWidth < = 0 )
SetRenderFlags ( OldRenderFlags | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_LAST_CHARACTER_ADVANCE ) ;
2010-05-29 07:25:38 +00:00
TextEx ( & Cursor , pText , - 1 ) ;
2020-10-06 10:25:10 +00:00
SetRenderFlags ( OldRenderFlags ) ;
2010-05-29 07:25:38 +00:00
return Cursor . m_LineCount ;
}
2022-05-17 18:33:27 +00:00
void TextColor ( float r , float g , float b , float a ) override
2010-05-29 07:25:38 +00:00
{
2019-04-26 22:34:20 +00:00
m_Color . r = r ;
m_Color . g = g ;
m_Color . b = b ;
m_Color . a = a ;
2010-05-29 07:25:38 +00:00
}
2022-05-17 18:33:27 +00:00
void TextColor ( ColorRGBA rgb ) override { m_Color = rgb ; }
2011-03-13 11:55:00 +00:00
2022-05-17 18:33:27 +00:00
void TextOutlineColor ( float r , float g , float b , float a ) override
2011-03-13 11:55:00 +00:00
{
2019-04-26 22:34:20 +00:00
m_OutlineColor . r = r ;
m_OutlineColor . g = g ;
m_OutlineColor . b = b ;
m_OutlineColor . a = a ;
2011-03-13 11:55:00 +00:00
}
2022-05-17 18:33:27 +00:00
void TextOutlineColor ( ColorRGBA rgb ) override { m_OutlineColor = rgb ; }
2011-04-13 18:37:12 +00:00
2022-05-17 18:33:27 +00:00
void TextSelectionColor ( float r , float g , float b , float a ) override
2021-09-12 17:40:23 +00:00
{
m_SelectionColor . r = r ;
m_SelectionColor . g = g ;
m_SelectionColor . b = b ;
m_SelectionColor . a = a ;
}
2022-05-17 18:33:27 +00:00
void TextSelectionColor ( ColorRGBA rgb ) override { m_SelectionColor = rgb ; }
2021-09-12 17:40:23 +00:00
2022-05-17 18:33:27 +00:00
ColorRGBA GetTextColor ( ) override { return m_Color ; }
ColorRGBA GetTextOutlineColor ( ) override { return m_OutlineColor ; }
ColorRGBA GetTextSelectionColor ( ) override { return m_SelectionColor ; }
2020-11-08 18:41:16 +00:00
2022-05-17 18:33:27 +00:00
void TextEx ( CTextCursor * pCursor , const char * pText , int Length ) override
2010-05-29 07:25:38 +00:00
{
2022-03-20 17:03:25 +00:00
int OldRenderFlags = m_RenderFlags ;
m_RenderFlags | = TEXT_RENDER_FLAG_ONE_TIME_USE ;
2022-07-08 16:51:19 +00:00
int TextCont = - 1 ;
CreateTextContainer ( TextCont , pCursor , pText , Length ) ;
2022-03-20 17:03:25 +00:00
m_RenderFlags = OldRenderFlags ;
2021-09-12 17:40:23 +00:00
if ( TextCont ! = - 1 )
2018-03-13 20:49:07 +00:00
{
2021-09-12 17:40:23 +00:00
if ( ( pCursor - > m_Flags & TEXTFLAG_RENDER ) ! = 0 )
2018-03-13 20:49:07 +00:00
{
2022-07-01 04:42:36 +00:00
ColorRGBA TextColor = DefaultTextColor ( ) ;
ColorRGBA TextColorOutline = DefaultTextOutlineColor ( ) ;
RenderTextContainer ( TextCont , TextColor , TextColorOutline ) ;
2018-03-13 20:49:07 +00:00
}
2021-09-12 17:40:23 +00:00
DeleteTextContainer ( TextCont ) ;
2018-03-13 20:49:07 +00:00
}
}
2022-07-08 16:51:19 +00:00
bool CreateTextContainer ( int & TextContainerIndex , CTextCursor * pCursor , const char * pText , int Length = - 1 ) override
2018-03-13 20:49:07 +00:00
{
2022-07-08 16:51:19 +00:00
dbg_assert ( TextContainerIndex = = - 1 , " Text container index was not cleared. " ) ;
TextContainerIndex = - 1 ;
2018-03-13 20:49:07 +00:00
CFont * pFont = pCursor - > m_pFont ;
// fetch pFont data
if ( ! pFont )
pFont = m_pCurFont ;
if ( ! pFont )
2022-07-08 16:51:19 +00:00
return false ;
2018-03-13 20:49:07 +00:00
2021-09-12 17:40:23 +00:00
bool IsRendered = ( pCursor - > m_Flags & TEXTFLAG_RENDER ) ! = 0 ;
2022-07-08 16:51:19 +00:00
TextContainerIndex = GetFreeTextContainerIndex ( ) ;
STextContainer & TextContainer = GetTextContainer ( TextContainerIndex ) ;
2018-03-13 20:49:07 +00:00
TextContainer . m_pFont = pFont ;
2022-03-20 17:03:25 +00:00
TextContainer . m_SingleTimeUse = ( m_RenderFlags & TEXT_RENDER_FLAG_ONE_TIME_USE ) ! = 0 ;
2018-03-13 20:49:07 +00:00
CFontSizeData * pSizeData = NULL ;
float ScreenX0 , ScreenY0 , ScreenX1 , ScreenY1 ;
2018-03-21 14:43:56 +00:00
float FakeToScreenX , FakeToScreenY ;
2018-03-13 20:49:07 +00:00
int ActualSize ;
float Size = pCursor - > m_FontSize ;
2018-03-15 02:33:22 +00:00
// calculate the font size of the displayed glyphs
2018-03-13 20:49:07 +00:00
Graphics ( ) - > GetScreen ( & ScreenX0 , & ScreenY0 , & ScreenX1 , & ScreenY1 ) ;
2018-03-21 14:43:56 +00:00
FakeToScreenX = ( Graphics ( ) - > ScreenWidth ( ) / ( ScreenX1 - ScreenX0 ) ) ;
2018-03-13 20:49:07 +00:00
FakeToScreenY = ( Graphics ( ) - > ScreenHeight ( ) / ( ScreenY1 - ScreenY0 ) ) ;
2021-05-02 08:32:05 +00:00
int ActualX = ( int ) ( ( pCursor - > m_X * FakeToScreenX ) + 0.5f ) ;
int ActualY = ( int ) ( ( pCursor - > m_Y * FakeToScreenY ) + 0.5f ) ;
2018-03-21 14:43:56 +00:00
TextContainer . m_AlignedStartX = ActualX / FakeToScreenX ;
TextContainer . m_AlignedStartY = ActualY / FakeToScreenY ;
2018-03-15 02:33:22 +00:00
TextContainer . m_X = pCursor - > m_X ;
TextContainer . m_Y = pCursor - > m_Y ;
2018-03-13 20:49:07 +00:00
TextContainer . m_Flags = pCursor - > m_Flags ;
2020-10-12 15:46:06 +00:00
int OldRenderFlags = m_RenderFlags ;
if ( pCursor - > m_LineWidth < = 0 )
SetRenderFlags ( OldRenderFlags | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_LAST_CHARACTER_ADVANCE ) ;
2020-10-13 20:08:52 +00:00
2018-03-21 14:43:56 +00:00
TextContainer . m_RenderFlags = m_RenderFlags ;
2020-10-12 15:46:06 +00:00
SetRenderFlags ( OldRenderFlags ) ;
2018-03-21 14:43:56 +00:00
2018-03-13 20:49:07 +00:00
// same with size
ActualSize = ( int ) ( Size * FakeToScreenY ) ;
2018-03-21 14:43:56 +00:00
pSizeData = pFont - > GetFontSize ( ActualSize ) ;
2019-04-26 19:36:49 +00:00
2018-03-13 20:49:07 +00:00
TextContainer . m_FontSize = pSizeData - > m_FontSize ;
2019-04-26 19:36:49 +00:00
2022-07-08 16:51:19 +00:00
AppendTextContainer ( TextContainerIndex , pCursor , pText , Length ) ;
2018-03-13 20:49:07 +00:00
2022-06-11 19:38:18 +00:00
if ( TextContainer . m_StringInfo . m_vCharacterQuads . empty ( ) & & TextContainer . m_StringInfo . m_SelectionQuadContainerIndex = = - 1 & & IsRendered )
2018-03-13 20:49:07 +00:00
{
2022-07-08 16:51:19 +00:00
FreeTextContainer ( TextContainerIndex ) ;
TextContainerIndex = - 1 ;
return false ;
2018-03-13 20:49:07 +00:00
}
else
{
2022-06-11 19:38:18 +00:00
TextContainer . m_StringInfo . m_QuadNum = TextContainer . m_StringInfo . m_vCharacterQuads . size ( ) ;
if ( Graphics ( ) - > IsTextBufferingEnabled ( ) & & IsRendered & & ! TextContainer . m_StringInfo . m_vCharacterQuads . empty ( ) )
2018-03-13 20:49:07 +00:00
{
2020-10-22 20:21:19 +00:00
if ( ( TextContainer . m_RenderFlags & TEXT_RENDER_FLAG_NO_AUTOMATIC_QUAD_UPLOAD ) = = 0 )
{
2022-07-08 16:51:19 +00:00
UploadTextContainer ( TextContainerIndex ) ;
2020-10-22 20:21:19 +00:00
}
2018-03-13 20:49:07 +00:00
}
2019-04-26 19:36:49 +00:00
2018-03-13 20:49:07 +00:00
TextContainer . m_LineCount = pCursor - > m_LineCount ;
2020-09-03 22:53:26 +00:00
TextContainer . m_GlyphCount = pCursor - > m_GlyphCount ;
2018-03-13 20:49:07 +00:00
TextContainer . m_CharCount = pCursor - > m_CharCount ;
TextContainer . m_MaxLines = pCursor - > m_MaxLines ;
TextContainer . m_StartX = pCursor - > m_StartX ;
TextContainer . m_StartY = pCursor - > m_StartY ;
TextContainer . m_LineWidth = pCursor - > m_LineWidth ;
TextContainer . m_UnscaledFontSize = pCursor - > m_FontSize ;
}
2022-07-08 16:51:19 +00:00
return true ;
2018-03-13 20:49:07 +00:00
}
2022-07-08 16:51:19 +00:00
void AppendTextContainer ( int TextContainerIndex , CTextCursor * pCursor , const char * pText , int Length = - 1 ) override
2018-03-13 20:49:07 +00:00
{
2020-09-26 19:41:58 +00:00
STextContainer & TextContainer = GetTextContainer ( TextContainerIndex ) ;
2018-03-13 20:49:07 +00:00
CFontSizeData * pSizeData = NULL ;
float ScreenX0 , ScreenY0 , ScreenX1 , ScreenY1 ;
2018-03-21 14:43:56 +00:00
float FakeToScreenX , FakeToScreenY ;
2018-03-13 20:49:07 +00:00
int ActualSize ;
int GotNewLine = 0 ;
2020-10-28 14:56:02 +00:00
int GotNewLineLast = 0 ;
2018-03-13 20:49:07 +00:00
float DrawX = 0.0f , DrawY = 0.0f ;
int LineCount = 0 ;
2018-03-21 14:43:56 +00:00
float CursorX , CursorY ;
2018-03-13 20:49:07 +00:00
float Size = pCursor - > m_FontSize ;
2018-03-15 02:33:22 +00:00
// calculate the font size of the displayed glyphs
2018-03-13 20:49:07 +00:00
Graphics ( ) - > GetScreen ( & ScreenX0 , & ScreenY0 , & ScreenX1 , & ScreenY1 ) ;
2018-03-21 14:43:56 +00:00
FakeToScreenX = ( Graphics ( ) - > ScreenWidth ( ) / ( ScreenX1 - ScreenX0 ) ) ;
2018-03-13 20:49:07 +00:00
FakeToScreenY = ( Graphics ( ) - > ScreenHeight ( ) / ( ScreenY1 - ScreenY0 ) ) ;
2021-05-02 08:32:05 +00:00
int ActualX = ( int ) ( ( pCursor - > m_X * FakeToScreenX ) + 0.5f ) ;
int ActualY = ( int ) ( ( pCursor - > m_Y * FakeToScreenY ) + 0.5f ) ;
2018-03-21 14:43:56 +00:00
CursorX = ActualX / FakeToScreenX ;
CursorY = ActualY / FakeToScreenY ;
2018-03-13 20:49:07 +00:00
// same with size
ActualSize = ( int ) ( Size * FakeToScreenY ) ;
Size = ActualSize / FakeToScreenY ;
2018-03-21 14:43:56 +00:00
pCursor - > m_AlignedFontSize = Size ;
pSizeData = TextContainer . m_pFont - > GetFontSize ( TextContainer . m_FontSize ) ;
2018-03-13 20:49:07 +00:00
// string length
2020-10-12 10:29:47 +00:00
if ( Length < 0 )
Length = str_length ( pText ) ;
2018-03-13 20:49:07 +00:00
float Scale = 1.0f / pSizeData - > m_FontSize ;
const char * pCurrent = ( char * ) pText ;
const char * pEnd = pCurrent + Length ;
2022-05-31 10:20:45 +00:00
const char * pEllipsis = " … " ;
SFontSizeChar * pEllipsisChr = nullptr ;
if ( pCursor - > m_Flags & TEXTFLAG_ELLIPSIS_AT_END )
{
if ( pCursor - > m_LineWidth ! = - 1 & & pCursor - > m_LineWidth < TextWidth ( 0 , pCursor - > m_FontSize , pText , - 1 , - 1.0f ) )
{
pEllipsisChr = GetChar ( TextContainer . m_pFont , pSizeData , 0x2026 ) ; // …
if ( pEllipsisChr = = nullptr )
{
// no ellipsis char in font, just stop at end instead
pCursor - > m_Flags & = ~ TEXTFLAG_ELLIPSIS_AT_END ;
pCursor - > m_Flags | = TEXTFLAG_STOP_AT_END ;
}
}
}
2018-03-15 02:33:22 +00:00
2018-03-21 14:43:56 +00:00
int RenderFlags = TextContainer . m_RenderFlags ;
2020-09-26 19:41:58 +00:00
if ( ( RenderFlags & TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT ) ! = 0 )
2018-03-21 14:43:56 +00:00
{
DrawX = pCursor - > m_X ;
DrawY = pCursor - > m_Y ;
}
else
{
DrawX = CursorX ;
DrawY = CursorY ;
}
2018-03-13 20:49:07 +00:00
LineCount = pCursor - > m_LineCount ;
2019-04-26 19:36:49 +00:00
2019-01-06 05:42:57 +00:00
FT_UInt LastCharGlyphIndex = 0 ;
size_t CharacterCounter = 0 ;
2021-09-12 17:40:23 +00:00
bool IsRendered = ( pCursor - > m_Flags & TEXTFLAG_RENDER ) ! = 0 ;
2022-06-30 22:36:32 +00:00
IGraphics : : CQuadItem aCursorQuads [ 2 ] ;
2021-09-16 14:50:17 +00:00
bool HasCursor = false ;
float CursorInnerWidth = ( ( ( ScreenX1 - ScreenX0 ) / Graphics ( ) - > ScreenWidth ( ) ) ) * 2 ;
float CursorOuterWidth = CursorInnerWidth * 2 ;
float CursorOuterInnerDiff = ( CursorOuterWidth - CursorInnerWidth ) / 2 ;
2022-06-15 17:34:41 +00:00
std : : vector < IGraphics : : CQuadItem > vSelectionQuads ;
2021-09-12 17:40:23 +00:00
bool SelectionStarted = false ;
bool SelectionUsedPress = false ;
bool SelectionUsedRelease = false ;
int SelectionStartChar = - 1 ;
int SelectionEndChar = - 1 ;
2022-03-20 11:57:50 +00:00
auto & & CheckInsideChar = [ & ] ( bool CheckOuter , int CursorX_ , int CursorY_ , float LastCharX , float LastCharWidth , float CharX , float CharWidth , float CharY ) - > bool {
return ( LastCharX - LastCharWidth / 2 < = CursorX_ & &
CharX + CharWidth / 2 > CursorX_ & &
CharY - Size < = CursorY_ & &
CharY > CursorY_ ) | |
2022-01-22 16:34:23 +00:00
( CheckOuter & &
2022-03-20 11:57:50 +00:00
CharY - Size > CursorY_ ) ;
2021-09-16 14:50:17 +00:00
} ;
2022-03-20 11:57:50 +00:00
auto & & CheckSelectionStart = [ & ] ( bool CheckOuter , int CursorX_ , int CursorY_ , int & SelectionChar , bool & SelectionUsedCase , float LastCharX , float LastCharWidth , float CharX , float CharWidth , float CharY ) {
2021-09-12 17:40:23 +00:00
if ( ! SelectionStarted & & ! SelectionUsedCase )
{
2022-03-20 11:57:50 +00:00
if ( CheckInsideChar ( CheckOuter , CursorX_ , CursorY_ , LastCharX , LastCharWidth , CharX , CharWidth , CharY ) )
2021-09-12 17:40:23 +00:00
{
SelectionChar = CharacterCounter ;
SelectionStarted = ! SelectionStarted ;
SelectionUsedCase = true ;
}
}
} ;
2022-03-20 11:57:50 +00:00
auto & & CheckOutsideChar = [ & ] ( bool CheckOuter , int CursorX_ , int CursorY_ , float CharX , float CharWidth , float CharY ) - > bool {
return ( CharX + CharWidth / 2 > CursorX_ & &
CharY - Size < = CursorY_ & &
CharY > CursorY_ ) | |
2022-01-22 16:34:23 +00:00
( CheckOuter & &
2022-03-20 11:57:50 +00:00
CharY < = CursorY_ ) ;
2021-09-16 14:50:17 +00:00
} ;
2022-03-20 11:57:50 +00:00
auto & & CheckSelectionEnd = [ & ] ( bool CheckOuter , int CursorX_ , int CursorY_ , int & SelectionChar , bool & SelectionUsedCase , float CharX , float CharWidth , float CharY ) {
2021-09-12 17:40:23 +00:00
if ( SelectionStarted & & ! SelectionUsedCase )
{
2022-03-20 11:57:50 +00:00
if ( CheckOutsideChar ( CheckOuter , CursorX_ , CursorY_ , CharX , CharWidth , CharY ) )
2021-09-12 17:40:23 +00:00
{
SelectionChar = CharacterCounter ;
SelectionStarted = ! SelectionStarted ;
SelectionUsedCase = true ;
}
}
} ;
float LastSelX = DrawX ;
float LastSelWidth = 0 ;
float LastCharX = DrawX ;
float LastCharWidth = 0 ;
auto & & StartNewLine = [ & ] ( ) {
DrawX = pCursor - > m_StartX ;
DrawY + = Size ;
if ( ( RenderFlags & TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT ) = = 0 )
{
DrawX = ( int ) ( ( DrawX * FakeToScreenX ) + 0.5f ) / FakeToScreenX ; // realign
DrawY = ( int ) ( ( DrawY * FakeToScreenY ) + 0.5f ) / FakeToScreenY ;
}
LastSelX = DrawX ;
LastSelWidth = 0 ;
LastCharX = DrawX ;
LastCharWidth = 0 ;
+ + LineCount ;
} ;
2021-09-16 14:50:17 +00:00
if ( pCursor - > m_CalculateSelectionMode ! = TEXT_CURSOR_SELECTION_MODE_NONE | | pCursor - > m_CursorMode ! = TEXT_CURSOR_CURSOR_MODE_NONE )
2021-09-12 17:40:23 +00:00
{
if ( IsRendered )
{
if ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex ! = - 1 )
Graphics ( ) - > QuadContainerReset ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex ) ;
}
2021-09-16 14:50:17 +00:00
// if in calculate mode, also calculate the cursor
if ( pCursor - > m_CursorMode = = TEXT_CURSOR_CURSOR_MODE_CALCULATE )
pCursor - > m_CursorCharacter = - 1 ;
2021-09-12 17:40:23 +00:00
}
2022-05-31 10:20:45 +00:00
while ( pCurrent < pEnd & & ( pCursor - > m_MaxLines < 1 | | LineCount < = pCursor - > m_MaxLines ) & & pCurrent ! = pEllipsis )
2018-03-13 20:49:07 +00:00
{
int NewLine = 0 ;
const char * pBatchEnd = pEnd ;
2022-05-31 10:20:45 +00:00
if ( pCursor - > m_LineWidth > 0 & & ! ( pCursor - > m_Flags & TEXTFLAG_STOP_AT_END ) & & ! ( pCursor - > m_Flags & TEXTFLAG_ELLIPSIS_AT_END ) )
2018-03-13 20:49:07 +00:00
{
2019-04-26 19:36:49 +00:00
int Wlen = minimum ( WordLength ( ( char * ) pCurrent ) , ( int ) ( pEnd - pCurrent ) ) ;
2018-03-13 20:49:07 +00:00
CTextCursor Compare = * pCursor ;
2021-09-12 17:40:23 +00:00
Compare . m_CalculateSelectionMode = TEXT_CURSOR_SELECTION_MODE_NONE ;
2021-09-16 14:50:17 +00:00
Compare . m_CursorMode = TEXT_CURSOR_CURSOR_MODE_NONE ;
2018-03-13 20:49:07 +00:00
Compare . m_X = DrawX ;
Compare . m_Y = DrawY ;
Compare . m_Flags & = ~ TEXTFLAG_RENDER ;
Compare . m_LineWidth = - 1 ;
TextEx ( & Compare , pCurrent , Wlen ) ;
if ( Compare . m_X - DrawX > pCursor - > m_LineWidth )
{
// word can't be fitted in one line, cut it
CTextCursor Cutter = * pCursor ;
2021-09-12 17:40:23 +00:00
Cutter . m_CalculateSelectionMode = TEXT_CURSOR_SELECTION_MODE_NONE ;
2021-09-16 14:50:17 +00:00
Cutter . m_CursorMode = TEXT_CURSOR_CURSOR_MODE_NONE ;
2020-09-03 22:53:26 +00:00
Cutter . m_GlyphCount = 0 ;
2018-03-13 20:49:07 +00:00
Cutter . m_CharCount = 0 ;
Cutter . m_X = DrawX ;
Cutter . m_Y = DrawY ;
Cutter . m_Flags & = ~ TEXTFLAG_RENDER ;
Cutter . m_Flags | = TEXTFLAG_STOP_AT_END ;
2019-04-11 10:21:42 +00:00
TextEx ( & Cutter , pCurrent , Wlen ) ;
2020-09-03 22:53:26 +00:00
int WordGlyphs = Cutter . m_GlyphCount ;
2018-03-13 20:49:07 +00:00
Wlen = Cutter . m_CharCount ;
NewLine = 1 ;
2020-10-28 14:56:02 +00:00
if ( WordGlyphs < = 3 & & GotNewLineLast = = 0 ) // if we can't place 3 chars of the word on this line, take the next
2018-03-13 20:49:07 +00:00
Wlen = 0 ;
}
2020-10-28 14:56:02 +00:00
else if ( Compare . m_X - pCursor - > m_StartX > pCursor - > m_LineWidth & & GotNewLineLast = = 0 )
2018-03-13 20:49:07 +00:00
{
NewLine = 1 ;
Wlen = 0 ;
}
pBatchEnd = pCurrent + Wlen ;
}
const char * pTmp = pCurrent ;
int NextCharacter = str_utf8_decode ( & pTmp ) ;
2020-10-13 20:08:52 +00:00
2022-05-31 10:20:45 +00:00
while ( pCurrent < pBatchEnd & & pCurrent ! = pEllipsis )
2018-03-13 20:49:07 +00:00
{
2021-09-12 17:40:23 +00:00
pCursor - > m_CharCount + = pTmp - pCurrent ;
2022-05-22 21:04:32 +00:00
pCurrent = pTmp ;
2022-05-31 10:20:45 +00:00
int Character = NextCharacter ;
2018-03-13 20:49:07 +00:00
NextCharacter = str_utf8_decode ( & pTmp ) ;
if ( Character = = ' \n ' )
{
2019-01-06 05:42:57 +00:00
LastCharGlyphIndex = 0 ;
+ + CharacterCounter ;
2021-09-12 17:40:23 +00:00
StartNewLine ( ) ;
2018-03-13 20:49:07 +00:00
if ( pCursor - > m_MaxLines > 0 & & LineCount > pCursor - > m_MaxLines )
break ;
continue ;
}
2020-08-20 09:22:25 +00:00
SFontSizeChar * pChr = GetChar ( TextContainer . m_pFont , pSizeData , Character ) ;
2018-03-13 20:49:07 +00:00
if ( pChr )
{
2020-09-26 19:41:58 +00:00
bool ApplyBearingX = ! ( ( ( RenderFlags & TEXT_RENDER_FLAG_NO_X_BEARING ) ! = 0 ) | | ( CharacterCounter = = 0 & & ( RenderFlags & TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING ) ! = 0 ) ) ;
2021-09-12 17:40:23 +00:00
float Advance = ( ( ( ( RenderFlags & TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH ) ! = 0 ) ? ( pChr - > m_Width ) : ( pChr - > m_AdvanceX + ( ( ! ApplyBearingX ) ? ( - pChr - > m_OffsetX ) : 0.f ) ) ) ) * Scale * Size ;
float OutLineRealDiff = ( pChr - > m_Width - pChr - > m_CharWidth ) * Scale * Size ;
2019-04-26 19:36:49 +00:00
2019-01-06 05:42:57 +00:00
float CharKerning = 0.f ;
2020-09-26 19:41:58 +00:00
if ( ( RenderFlags & TEXT_RENDER_FLAG_KERNING ) ! = 0 )
CharKerning = Kerning ( TextContainer . m_pFont , LastCharGlyphIndex , pChr - > m_GlyphIndex ) * Scale * Size ;
2019-01-06 05:42:57 +00:00
LastCharGlyphIndex = pChr - > m_GlyphIndex ;
2022-05-31 10:20:45 +00:00
if ( pEllipsisChr ! = nullptr & & pCursor - > m_Flags & TEXTFLAG_ELLIPSIS_AT_END & & pCurrent < pBatchEnd & & pCurrent ! = pEllipsis )
{
float AdvanceEllipsis = ( ( ( ( RenderFlags & TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH ) ! = 0 ) ? ( pEllipsisChr - > m_Width ) : ( pEllipsisChr - > m_AdvanceX + ( ( ! ApplyBearingX ) ? ( - pEllipsisChr - > m_OffsetX ) : 0.f ) ) ) ) * Scale * Size ;
float CharKerningEllipsis = 0.f ;
if ( ( RenderFlags & TEXT_RENDER_FLAG_KERNING ) ! = 0 )
{
CharKerningEllipsis = Kerning ( TextContainer . m_pFont , pChr - > m_GlyphIndex , pEllipsisChr - > m_GlyphIndex ) * Scale * Size ;
}
if ( DrawX + CharKerning + Advance + CharKerningEllipsis + AdvanceEllipsis - pCursor - > m_StartX > pCursor - > m_LineWidth )
{
// we hit the end, only render ellipsis and finish
pTmp = pEllipsis ;
NextCharacter = 0x2026 ;
continue ;
}
}
2022-05-22 21:04:32 +00:00
if ( pCursor - > m_Flags & TEXTFLAG_STOP_AT_END & & ( DrawX + CharKerning ) + Advance - pCursor - > m_StartX > pCursor - > m_LineWidth )
2018-03-13 20:49:07 +00:00
{
// we hit the end of the line, no more to render or count
pCurrent = pEnd ;
break ;
}
2020-09-26 19:41:58 +00:00
float BearingX = ( ! ApplyBearingX ? 0.f : pChr - > m_OffsetX ) * Scale * Size ;
float CharWidth = pChr - > m_Width * Scale * Size ;
2019-04-26 19:36:49 +00:00
2020-10-06 10:25:10 +00:00
float BearingY = ( ( ( RenderFlags & TEXT_RENDER_FLAG_NO_Y_BEARING ) ! = 0 ) ? 0.f : ( pChr - > m_OffsetY * Scale * Size ) ) ;
float CharHeight = pChr - > m_Height * Scale * Size ;
if ( ( RenderFlags & TEXT_RENDER_FLAG_NO_OVERSIZE ) ! = 0 )
{
if ( CharHeight + BearingY > Size )
{
BearingY = 0 ;
float ScaleChar = ( CharHeight + BearingY ) / Size ;
CharHeight = Size ;
CharWidth / = ScaleChar ;
}
}
2021-09-12 17:40:23 +00:00
float TmpY = ( DrawY + Size ) ;
float CharX = ( DrawX + CharKerning ) + BearingX ;
float CharY = TmpY - BearingY ;
2018-07-10 09:29:02 +00:00
// don't add text that isn't drawn, the color overwrite is used for that
2021-09-12 17:40:23 +00:00
if ( m_Color . a ! = 0.f & & IsRendered )
2018-03-13 20:49:07 +00:00
{
2022-06-11 19:38:18 +00:00
TextContainer . m_StringInfo . m_vCharacterQuads . emplace_back ( ) ;
STextCharQuad & TextCharQuad = TextContainer . m_StringInfo . m_vCharacterQuads . back ( ) ;
2018-03-13 20:49:07 +00:00
2022-06-30 22:36:32 +00:00
TextCharQuad . m_aVertices [ 0 ] . m_X = CharX ;
TextCharQuad . m_aVertices [ 0 ] . m_Y = CharY ;
TextCharQuad . m_aVertices [ 0 ] . m_U = pChr - > m_aUVs [ 0 ] ;
TextCharQuad . m_aVertices [ 0 ] . m_V = pChr - > m_aUVs [ 3 ] ;
TextCharQuad . m_aVertices [ 0 ] . m_Color . r = ( unsigned char ) ( m_Color . r * 255.f ) ;
TextCharQuad . m_aVertices [ 0 ] . m_Color . g = ( unsigned char ) ( m_Color . g * 255.f ) ;
TextCharQuad . m_aVertices [ 0 ] . m_Color . b = ( unsigned char ) ( m_Color . b * 255.f ) ;
TextCharQuad . m_aVertices [ 0 ] . m_Color . a = ( unsigned char ) ( m_Color . a * 255.f ) ;
TextCharQuad . m_aVertices [ 1 ] . m_X = CharX + CharWidth ;
TextCharQuad . m_aVertices [ 1 ] . m_Y = CharY ;
TextCharQuad . m_aVertices [ 1 ] . m_U = pChr - > m_aUVs [ 2 ] ;
TextCharQuad . m_aVertices [ 1 ] . m_V = pChr - > m_aUVs [ 3 ] ;
TextCharQuad . m_aVertices [ 1 ] . m_Color . r = ( unsigned char ) ( m_Color . r * 255.f ) ;
TextCharQuad . m_aVertices [ 1 ] . m_Color . g = ( unsigned char ) ( m_Color . g * 255.f ) ;
TextCharQuad . m_aVertices [ 1 ] . m_Color . b = ( unsigned char ) ( m_Color . b * 255.f ) ;
TextCharQuad . m_aVertices [ 1 ] . m_Color . a = ( unsigned char ) ( m_Color . a * 255.f ) ;
TextCharQuad . m_aVertices [ 2 ] . m_X = CharX + CharWidth ;
TextCharQuad . m_aVertices [ 2 ] . m_Y = CharY - CharHeight ;
TextCharQuad . m_aVertices [ 2 ] . m_U = pChr - > m_aUVs [ 2 ] ;
TextCharQuad . m_aVertices [ 2 ] . m_V = pChr - > m_aUVs [ 1 ] ;
TextCharQuad . m_aVertices [ 2 ] . m_Color . r = ( unsigned char ) ( m_Color . r * 255.f ) ;
TextCharQuad . m_aVertices [ 2 ] . m_Color . g = ( unsigned char ) ( m_Color . g * 255.f ) ;
TextCharQuad . m_aVertices [ 2 ] . m_Color . b = ( unsigned char ) ( m_Color . b * 255.f ) ;
TextCharQuad . m_aVertices [ 2 ] . m_Color . a = ( unsigned char ) ( m_Color . a * 255.f ) ;
TextCharQuad . m_aVertices [ 3 ] . m_X = CharX ;
TextCharQuad . m_aVertices [ 3 ] . m_Y = CharY - CharHeight ;
TextCharQuad . m_aVertices [ 3 ] . m_U = pChr - > m_aUVs [ 0 ] ;
TextCharQuad . m_aVertices [ 3 ] . m_V = pChr - > m_aUVs [ 1 ] ;
TextCharQuad . m_aVertices [ 3 ] . m_Color . r = ( unsigned char ) ( m_Color . r * 255.f ) ;
TextCharQuad . m_aVertices [ 3 ] . m_Color . g = ( unsigned char ) ( m_Color . g * 255.f ) ;
TextCharQuad . m_aVertices [ 3 ] . m_Color . b = ( unsigned char ) ( m_Color . b * 255.f ) ;
TextCharQuad . m_aVertices [ 3 ] . m_Color . a = ( unsigned char ) ( m_Color . a * 255.f ) ;
2018-03-13 20:49:07 +00:00
}
2021-09-12 17:40:23 +00:00
// calculate the full width from the last selection point to the end of this selection draw on screen
float SelWidth = ( CharX + maximum ( Advance , CharWidth - OutLineRealDiff / 2 ) ) - ( LastSelX + LastSelWidth ) ;
float SelX = ( LastSelX + LastSelWidth ) ;
2021-09-16 14:50:17 +00:00
if ( pCursor - > m_CursorMode = = TEXT_CURSOR_CURSOR_MODE_CALCULATE )
{
if ( pCursor - > m_CursorCharacter = = - 1 & & CheckInsideChar ( CharacterCounter = = 0 , pCursor - > m_ReleaseMouseX , pCursor - > m_ReleaseMouseY , CharacterCounter = = 0 ? std : : numeric_limits < float > : : lowest ( ) : LastCharX , LastCharWidth , CharX , CharWidth , TmpY ) )
{
pCursor - > m_CursorCharacter = CharacterCounter ;
}
}
2021-09-12 17:40:23 +00:00
if ( pCursor - > m_CalculateSelectionMode = = TEXT_CURSOR_SELECTION_MODE_CALCULATE )
{
if ( CharacterCounter = = 0 )
{
2021-09-16 14:50:17 +00:00
CheckSelectionStart ( true , pCursor - > m_PressMouseX , pCursor - > m_PressMouseY , SelectionStartChar , SelectionUsedPress , std : : numeric_limits < float > : : lowest ( ) , 0 , CharX , CharWidth , TmpY ) ;
CheckSelectionStart ( true , pCursor - > m_ReleaseMouseX , pCursor - > m_ReleaseMouseY , SelectionEndChar , SelectionUsedRelease , std : : numeric_limits < float > : : lowest ( ) , 0 , CharX , CharWidth , TmpY ) ;
2021-09-12 17:40:23 +00:00
}
2022-10-25 16:51:56 +00:00
// if selection didn't start and the mouse pos is at least on 50% of the right side of the character start
2021-09-12 17:40:23 +00:00
CheckSelectionStart ( false , pCursor - > m_PressMouseX , pCursor - > m_PressMouseY , SelectionStartChar , SelectionUsedPress , LastCharX , LastCharWidth , CharX , CharWidth , TmpY ) ;
CheckSelectionStart ( false , pCursor - > m_ReleaseMouseX , pCursor - > m_ReleaseMouseY , SelectionEndChar , SelectionUsedRelease , LastCharX , LastCharWidth , CharX , CharWidth , TmpY ) ;
CheckSelectionEnd ( false , pCursor - > m_ReleaseMouseX , pCursor - > m_ReleaseMouseY , SelectionEndChar , SelectionUsedRelease , CharX , CharWidth , TmpY ) ;
CheckSelectionEnd ( false , pCursor - > m_PressMouseX , pCursor - > m_PressMouseY , SelectionStartChar , SelectionUsedPress , CharX , CharWidth , TmpY ) ;
}
if ( pCursor - > m_CalculateSelectionMode = = TEXT_CURSOR_SELECTION_MODE_SET )
{
if ( ( int ) CharacterCounter = = pCursor - > m_SelectionStart )
{
SelectionStarted = ! SelectionStarted ;
2021-09-16 14:50:17 +00:00
SelectionStartChar = CharacterCounter ;
2021-09-12 17:40:23 +00:00
SelectionUsedPress = true ;
}
if ( ( int ) CharacterCounter = = pCursor - > m_SelectionEnd )
{
SelectionStarted = ! SelectionStarted ;
2021-09-16 14:50:17 +00:00
SelectionEndChar = CharacterCounter ;
2021-09-12 17:40:23 +00:00
SelectionUsedRelease = true ;
}
}
2021-09-16 14:50:17 +00:00
if ( pCursor - > m_CursorMode ! = TEXT_CURSOR_CURSOR_MODE_NONE )
{
if ( ( int ) CharacterCounter = = pCursor - > m_CursorCharacter )
{
HasCursor = true ;
2022-06-30 22:36:32 +00:00
aCursorQuads [ 0 ] = IGraphics : : CQuadItem ( SelX - CursorOuterInnerDiff , DrawY , CursorOuterWidth , Size ) ;
aCursorQuads [ 1 ] = IGraphics : : CQuadItem ( SelX , DrawY + CursorOuterInnerDiff , CursorInnerWidth , Size - CursorOuterInnerDiff * 2 ) ;
2021-09-16 14:50:17 +00:00
}
}
2020-10-06 10:25:10 +00:00
pCursor - > m_MaxCharacterHeight = maximum ( pCursor - > m_MaxCharacterHeight , CharHeight + BearingY ) ;
2020-10-16 18:00:57 +00:00
if ( NextCharacter = = 0 & & ( RenderFlags & TEXT_RENDER_FLAG_NO_LAST_CHARACTER_ADVANCE ) ! = 0 & & Character ! = ' ' )
2019-01-06 05:42:57 +00:00
DrawX + = BearingX + CharKerning + CharWidth ;
else
2021-09-12 17:40:23 +00:00
DrawX + = Advance + CharKerning ;
2020-09-03 22:53:26 +00:00
pCursor - > m_GlyphCount + + ;
2019-01-06 05:42:57 +00:00
+ + CharacterCounter ;
2021-09-12 17:40:23 +00:00
if ( SelectionStarted & & IsRendered )
{
2022-06-15 17:34:41 +00:00
vSelectionQuads . emplace_back ( SelX , DrawY , SelWidth , Size ) ;
2021-09-12 17:40:23 +00:00
}
LastSelX = SelX ;
LastSelWidth = SelWidth ;
LastCharX = CharX ;
LastCharWidth = CharWidth ;
2018-03-13 20:49:07 +00:00
}
2020-10-13 20:08:52 +00:00
if ( DrawX > pCursor - > m_LongestLineWidth )
pCursor - > m_LongestLineWidth = DrawX ;
2018-03-13 20:49:07 +00:00
}
if ( NewLine )
{
2021-09-12 17:40:23 +00:00
StartNewLine ( ) ;
2018-03-13 20:49:07 +00:00
GotNewLine = 1 ;
2020-10-28 14:56:02 +00:00
GotNewLineLast = 1 ;
2018-03-13 20:49:07 +00:00
}
2020-10-28 14:56:02 +00:00
else
GotNewLineLast = 0 ;
2018-03-13 20:49:07 +00:00
}
2022-06-11 19:38:18 +00:00
if ( ! TextContainer . m_StringInfo . m_vCharacterQuads . empty ( ) & & IsRendered )
2018-03-13 20:49:07 +00:00
{
2022-06-11 19:38:18 +00:00
TextContainer . m_StringInfo . m_QuadNum = TextContainer . m_StringInfo . m_vCharacterQuads . size ( ) ;
2018-03-13 20:49:07 +00:00
// setup the buffers
2020-08-29 10:10:38 +00:00
if ( Graphics ( ) - > IsTextBufferingEnabled ( ) )
2018-03-13 20:49:07 +00:00
{
2022-06-11 19:38:18 +00:00
size_t DataSize = TextContainer . m_StringInfo . m_vCharacterQuads . size ( ) * sizeof ( STextCharQuad ) ;
2022-07-10 19:22:50 +00:00
void * pUploadData = TextContainer . m_StringInfo . m_vCharacterQuads . data ( ) ;
2018-03-13 20:49:07 +00:00
2020-10-22 20:21:19 +00:00
if ( TextContainer . m_StringInfo . m_QuadBufferObjectIndex ! = - 1 & & ( TextContainer . m_RenderFlags & TEXT_RENDER_FLAG_NO_AUTOMATIC_QUAD_UPLOAD ) = = 0 )
2018-03-13 20:49:07 +00:00
{
2022-03-20 17:03:25 +00:00
Graphics ( ) - > RecreateBufferObject ( TextContainer . m_StringInfo . m_QuadBufferObjectIndex , DataSize , pUploadData , TextContainer . m_SingleTimeUse ? IGraphics : : EBufferObjectCreateFlags : : BUFFER_OBJECT_CREATE_FLAGS_ONE_TIME_USE_BIT : 0 ) ;
2018-03-13 20:49:07 +00:00
Graphics ( ) - > IndicesNumRequiredNotify ( TextContainer . m_StringInfo . m_QuadNum * 6 ) ;
}
}
}
2021-09-12 17:40:23 +00:00
if ( pCursor - > m_CalculateSelectionMode = = TEXT_CURSOR_SELECTION_MODE_CALCULATE )
{
pCursor - > m_SelectionStart = - 1 ;
pCursor - > m_SelectionEnd = - 1 ;
if ( SelectionStarted )
{
CheckSelectionEnd ( true , pCursor - > m_ReleaseMouseX , pCursor - > m_ReleaseMouseY , SelectionEndChar , SelectionUsedRelease , std : : numeric_limits < float > : : max ( ) , 0 , DrawY + Size ) ;
CheckSelectionEnd ( true , pCursor - > m_PressMouseX , pCursor - > m_PressMouseY , SelectionStartChar , SelectionUsedPress , std : : numeric_limits < float > : : max ( ) , 0 , DrawY + Size ) ;
}
}
else if ( pCursor - > m_CalculateSelectionMode = = TEXT_CURSOR_SELECTION_MODE_SET )
{
2021-09-16 14:50:17 +00:00
if ( ( int ) CharacterCounter = = pCursor - > m_SelectionStart )
{
SelectionStarted = ! SelectionStarted ;
SelectionStartChar = CharacterCounter ;
SelectionUsedPress = true ;
}
2021-09-12 17:40:23 +00:00
if ( ( int ) CharacterCounter = = pCursor - > m_SelectionEnd )
{
SelectionStarted = ! SelectionStarted ;
2021-09-16 14:50:17 +00:00
SelectionEndChar = CharacterCounter ;
2021-09-12 17:40:23 +00:00
SelectionUsedRelease = true ;
}
}
2021-09-16 14:50:17 +00:00
if ( pCursor - > m_CursorMode ! = TEXT_CURSOR_CURSOR_MODE_NONE )
2021-09-12 17:40:23 +00:00
{
2021-09-16 14:50:17 +00:00
if ( pCursor - > m_CursorMode = = TEXT_CURSOR_CURSOR_MODE_CALCULATE & & pCursor - > m_CursorCharacter = = - 1 & & CheckOutsideChar ( true , pCursor - > m_ReleaseMouseX , pCursor - > m_ReleaseMouseY , std : : numeric_limits < float > : : max ( ) , 0 , DrawY + Size ) )
2021-09-12 17:40:23 +00:00
{
2021-09-16 14:50:17 +00:00
pCursor - > m_CursorCharacter = CharacterCounter ;
}
2021-09-12 17:40:23 +00:00
2021-09-16 14:50:17 +00:00
if ( ( int ) CharacterCounter = = pCursor - > m_CursorCharacter )
{
HasCursor = true ;
2022-06-30 22:36:32 +00:00
aCursorQuads [ 0 ] = IGraphics : : CQuadItem ( ( LastSelX + LastSelWidth ) - CursorOuterInnerDiff , DrawY , CursorOuterWidth , Size ) ;
aCursorQuads [ 1 ] = IGraphics : : CQuadItem ( ( LastSelX + LastSelWidth ) , DrawY + CursorOuterInnerDiff , CursorInnerWidth , Size - CursorOuterInnerDiff * 2 ) ;
2021-09-12 17:40:23 +00:00
}
}
2022-06-15 17:34:41 +00:00
bool HasSelection = ! vSelectionQuads . empty ( ) & & SelectionUsedPress & & SelectionUsedRelease ;
2021-09-16 14:50:17 +00:00
if ( ( HasSelection | | HasCursor ) & & IsRendered )
{
Graphics ( ) - > SetColor ( 1.f , 1.f , 1.f , 1.f ) ;
if ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex = = - 1 )
TextContainer . m_StringInfo . m_SelectionQuadContainerIndex = Graphics ( ) - > CreateQuadContainer ( false ) ;
if ( HasCursor )
2022-06-30 22:36:32 +00:00
Graphics ( ) - > QuadContainerAddQuads ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex , aCursorQuads , 2 ) ;
2021-09-16 14:50:17 +00:00
if ( HasSelection )
2022-07-10 19:22:50 +00:00
Graphics ( ) - > QuadContainerAddQuads ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex , vSelectionQuads . data ( ) , ( int ) vSelectionQuads . size ( ) ) ;
2021-09-16 14:50:17 +00:00
Graphics ( ) - > QuadContainerUpload ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex ) ;
TextContainer . m_HasCursor = HasCursor ;
TextContainer . m_HasSelection = HasSelection ;
2021-11-02 23:08:00 +00:00
if ( HasSelection )
{
pCursor - > m_SelectionStart = SelectionStartChar ;
pCursor - > m_SelectionEnd = SelectionEndChar ;
}
else
{
pCursor - > m_SelectionStart = - 1 ;
pCursor - > m_SelectionEnd = - 1 ;
}
2021-09-16 14:50:17 +00:00
}
2018-03-13 20:49:07 +00:00
// even if no text is drawn the cursor position will be adjusted
pCursor - > m_X = DrawX ;
2010-10-11 00:29:30 +00:00
pCursor - > m_LineCount = LineCount ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( GotNewLine )
pCursor - > m_Y = DrawY ;
}
2011-04-13 18:37:12 +00:00
2022-07-08 16:51:19 +00:00
bool CreateOrAppendTextContainer ( int & TextContainerIndex , CTextCursor * pCursor , const char * pText , int Length = - 1 ) override
{
if ( TextContainerIndex = = - 1 )
{
return CreateTextContainer ( TextContainerIndex , pCursor , pText , Length ) ;
}
else
{
AppendTextContainer ( TextContainerIndex , pCursor , pText , Length ) ;
return true ;
}
}
2018-03-13 20:49:07 +00:00
// just deletes and creates text container
2022-05-17 18:33:27 +00:00
void
2022-07-08 16:51:19 +00:00
RecreateTextContainer ( CTextCursor * pCursor , int & TextContainerIndex , const char * pText , int Length = - 1 ) override
2018-03-13 20:49:07 +00:00
{
DeleteTextContainer ( TextContainerIndex ) ;
2022-07-08 16:51:19 +00:00
CreateTextContainer ( TextContainerIndex , pCursor , pText , Length ) ;
2018-03-13 20:49:07 +00:00
}
2022-07-08 16:51:19 +00:00
void RecreateTextContainerSoft ( CTextCursor * pCursor , int & TextContainerIndex , const char * pText , int Length = - 1 ) override
2018-03-13 20:49:07 +00:00
{
2020-09-26 19:41:58 +00:00
STextContainer & TextContainer = GetTextContainer ( TextContainerIndex ) ;
2022-06-11 19:38:18 +00:00
TextContainer . m_StringInfo . m_vCharacterQuads . clear ( ) ;
2018-03-13 20:49:07 +00:00
TextContainer . m_StringInfo . m_QuadNum = 0 ;
// the text buffer gets then recreated by the appended quads
2022-07-08 16:51:19 +00:00
AppendTextContainer ( TextContainerIndex , pCursor , pText , Length ) ;
2018-03-13 20:49:07 +00:00
}
2022-07-08 16:51:19 +00:00
void DeleteTextContainer ( int & TextContainerIndex ) override
2018-03-13 20:49:07 +00:00
{
2022-07-08 16:51:19 +00:00
if ( TextContainerIndex ! = - 1 )
2018-03-13 20:49:07 +00:00
{
2022-07-08 16:51:19 +00:00
STextContainer & TextContainer = GetTextContainer ( TextContainerIndex ) ;
if ( Graphics ( ) - > IsTextBufferingEnabled ( ) )
{
if ( TextContainer . m_StringInfo . m_QuadBufferContainerIndex ! = - 1 )
Graphics ( ) - > DeleteBufferContainer ( TextContainer . m_StringInfo . m_QuadBufferContainerIndex , true ) ;
}
if ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex ! = - 1 )
Graphics ( ) - > DeleteQuadContainer ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex ) ;
FreeTextContainer ( TextContainerIndex ) ;
TextContainerIndex = - 1 ;
2018-03-13 20:49:07 +00:00
}
}
2022-05-17 18:33:27 +00:00
void UploadTextContainer ( int TextContainerIndex ) override
2020-10-22 20:21:19 +00:00
{
2021-09-24 23:57:54 +00:00
if ( Graphics ( ) - > IsTextBufferingEnabled ( ) )
{
STextContainer & TextContainer = GetTextContainer ( TextContainerIndex ) ;
2022-06-11 19:38:18 +00:00
size_t DataSize = TextContainer . m_StringInfo . m_vCharacterQuads . size ( ) * sizeof ( STextCharQuad ) ;
void * pUploadData = TextContainer . m_StringInfo . m_vCharacterQuads . data ( ) ;
2022-03-20 17:03:25 +00:00
TextContainer . m_StringInfo . m_QuadBufferObjectIndex = Graphics ( ) - > CreateBufferObject ( DataSize , pUploadData , TextContainer . m_SingleTimeUse ? IGraphics : : EBufferObjectCreateFlags : : BUFFER_OBJECT_CREATE_FLAGS_ONE_TIME_USE_BIT : 0 ) ;
2020-10-22 20:21:19 +00:00
2022-03-20 17:03:25 +00:00
m_DefaultTextContainerInfo . m_VertBufferBindingIndex = TextContainer . m_StringInfo . m_QuadBufferObjectIndex ;
2020-10-22 20:21:19 +00:00
2021-09-24 23:57:54 +00:00
TextContainer . m_StringInfo . m_QuadBufferContainerIndex = Graphics ( ) - > CreateBufferContainer ( & m_DefaultTextContainerInfo ) ;
Graphics ( ) - > IndicesNumRequiredNotify ( TextContainer . m_StringInfo . m_QuadNum * 6 ) ;
}
2020-10-22 20:21:19 +00:00
}
2022-07-01 04:42:36 +00:00
void RenderTextContainer ( int TextContainerIndex , const ColorRGBA & TextColor , const ColorRGBA & TextOutlineColor ) override
2018-03-13 20:49:07 +00:00
{
2020-09-26 19:41:58 +00:00
STextContainer & TextContainer = GetTextContainer ( TextContainerIndex ) ;
2018-03-13 20:49:07 +00:00
CFont * pFont = TextContainer . m_pFont ;
if ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex ! = - 1 )
{
2021-09-16 14:50:17 +00:00
if ( TextContainer . m_HasSelection )
{
Graphics ( ) - > TextureClear ( ) ;
Graphics ( ) - > SetColor ( m_SelectionColor ) ;
Graphics ( ) - > RenderQuadContainerEx ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex , TextContainer . m_HasCursor ? 2 : 0 , - 1 , 0 , 0 ) ;
Graphics ( ) - > SetColor ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
}
2018-03-13 20:49:07 +00:00
}
2021-09-16 14:50:17 +00:00
if ( TextContainer . m_StringInfo . m_QuadNum > 0 )
2018-03-13 20:49:07 +00:00
{
2021-09-16 14:50:17 +00:00
if ( Graphics ( ) - > IsTextBufferingEnabled ( ) )
2018-03-13 20:49:07 +00:00
{
2021-09-16 14:50:17 +00:00
Graphics ( ) - > TextureClear ( ) ;
// render buffered text
2022-06-30 22:36:32 +00:00
Graphics ( ) - > RenderText ( TextContainer . m_StringInfo . m_QuadBufferContainerIndex , TextContainer . m_StringInfo . m_QuadNum , pFont - > m_aCurTextureDimensions [ 0 ] , pFont - > m_aTextures [ 0 ] . Id ( ) , pFont - > m_aTextures [ 1 ] . Id ( ) , TextColor , TextOutlineColor ) ;
2018-03-13 20:49:07 +00:00
}
2021-09-16 14:50:17 +00:00
else
2018-03-13 20:49:07 +00:00
{
2021-09-16 14:50:17 +00:00
// render tiles
2022-06-30 22:36:32 +00:00
float UVScale = 1.0f / pFont - > m_aCurTextureDimensions [ 0 ] ;
2018-05-07 03:52:02 +00:00
2021-09-16 14:50:17 +00:00
Graphics ( ) - > FlushVertices ( ) ;
Graphics ( ) - > TextureSet ( pFont - > m_aTextures [ 1 ] ) ;
Graphics ( ) - > QuadsBegin ( ) ;
2019-04-26 19:36:49 +00:00
2018-04-03 15:40:21 +00:00
for ( size_t i = 0 ; i < TextContainer . m_StringInfo . m_QuadNum ; + + i )
{
2022-06-11 19:38:18 +00:00
STextCharQuad & TextCharQuad = TextContainer . m_StringInfo . m_vCharacterQuads [ i ] ;
2021-09-16 14:50:17 +00:00
2022-06-30 22:36:32 +00:00
Graphics ( ) - > SetColor ( TextCharQuad . m_aVertices [ 0 ] . m_Color . r / 255.f * TextOutlineColor . r , TextCharQuad . m_aVertices [ 0 ] . m_Color . g / 255.f * TextOutlineColor . g , TextCharQuad . m_aVertices [ 0 ] . m_Color . b / 255.f * TextOutlineColor . b , TextCharQuad . m_aVertices [ 0 ] . m_Color . a / 255.f * TextOutlineColor . a ) ;
2021-09-16 14:50:17 +00:00
2022-06-30 22:36:32 +00:00
Graphics ( ) - > QuadsSetSubset ( TextCharQuad . m_aVertices [ 0 ] . m_U * UVScale , TextCharQuad . m_aVertices [ 0 ] . m_V * UVScale , TextCharQuad . m_aVertices [ 2 ] . m_U * UVScale , TextCharQuad . m_aVertices [ 2 ] . m_V * UVScale ) ;
IGraphics : : CQuadItem QuadItem ( TextCharQuad . m_aVertices [ 0 ] . m_X , TextCharQuad . m_aVertices [ 0 ] . m_Y , TextCharQuad . m_aVertices [ 1 ] . m_X - TextCharQuad . m_aVertices [ 0 ] . m_X , TextCharQuad . m_aVertices [ 2 ] . m_Y - TextCharQuad . m_aVertices [ 0 ] . m_Y ) ;
2021-09-16 14:50:17 +00:00
Graphics ( ) - > QuadsDrawTL ( & QuadItem , 1 ) ;
}
2022-07-01 04:42:36 +00:00
if ( TextColor . a ! = 0 )
2021-09-16 14:50:17 +00:00
{
Graphics ( ) - > QuadsEndKeepVertices ( ) ;
Graphics ( ) - > TextureSet ( pFont - > m_aTextures [ 0 ] ) ;
for ( size_t i = 0 ; i < TextContainer . m_StringInfo . m_QuadNum ; + + i )
{
2022-06-11 19:38:18 +00:00
STextCharQuad & TextCharQuad = TextContainer . m_StringInfo . m_vCharacterQuads [ i ] ;
2022-06-30 22:36:32 +00:00
unsigned char CR = ( unsigned char ) ( ( float ) ( TextCharQuad . m_aVertices [ 0 ] . m_Color . r ) * TextColor . r ) ;
unsigned char CG = ( unsigned char ) ( ( float ) ( TextCharQuad . m_aVertices [ 0 ] . m_Color . g ) * TextColor . g ) ;
unsigned char CB = ( unsigned char ) ( ( float ) ( TextCharQuad . m_aVertices [ 0 ] . m_Color . b ) * TextColor . b ) ;
unsigned char CA = ( unsigned char ) ( ( float ) ( TextCharQuad . m_aVertices [ 0 ] . m_Color . a ) * TextColor . a ) ;
2021-09-16 14:50:17 +00:00
Graphics ( ) - > ChangeColorOfQuadVertices ( ( int ) i , CR , CG , CB , CA ) ;
}
// render non outlined
Graphics ( ) - > QuadsDrawCurrentVertices ( false ) ;
2018-04-03 15:40:21 +00:00
}
2021-09-16 14:50:17 +00:00
else
Graphics ( ) - > QuadsEnd ( ) ;
2019-04-26 19:36:49 +00:00
2021-09-16 14:50:17 +00:00
// reset
Graphics ( ) - > SetColor ( 1.f , 1.f , 1.f , 1.f ) ;
2018-03-13 20:49:07 +00:00
}
2021-09-16 14:50:17 +00:00
}
2018-03-13 20:49:07 +00:00
2021-09-16 14:50:17 +00:00
if ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex ! = - 1 )
{
if ( TextContainer . m_HasCursor )
{
2022-06-13 16:07:29 +00:00
auto CurTime = time_get_nanoseconds ( ) ;
2021-09-16 14:50:17 +00:00
Graphics ( ) - > TextureClear ( ) ;
2022-05-18 16:00:05 +00:00
if ( ( CurTime - m_CursorRenderTime ) > 500 ms )
2021-09-16 14:50:17 +00:00
{
2022-07-01 04:42:36 +00:00
Graphics ( ) - > SetColor ( TextOutlineColor ) ;
2021-09-16 14:50:17 +00:00
Graphics ( ) - > RenderQuadContainerEx ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex , 0 , 1 , 0 , 0 ) ;
2022-07-01 04:42:36 +00:00
Graphics ( ) - > SetColor ( TextColor ) ;
2021-09-16 14:50:17 +00:00
Graphics ( ) - > RenderQuadContainerEx ( TextContainer . m_StringInfo . m_SelectionQuadContainerIndex , 1 , 1 , 0 , 0 ) ;
}
2022-05-18 16:00:05 +00:00
if ( ( CurTime - m_CursorRenderTime ) > 1 s )
2022-06-13 16:07:29 +00:00
m_CursorRenderTime = time_get_nanoseconds ( ) ;
2021-09-16 14:50:17 +00:00
Graphics ( ) - > SetColor ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
}
2018-03-13 20:49:07 +00:00
}
}
2022-07-01 04:42:36 +00:00
void RenderTextContainer ( int TextContainerIndex , const ColorRGBA & TextColor , const ColorRGBA & TextOutlineColor , float X , float Y ) override
2018-03-13 20:49:07 +00:00
{
2020-09-26 19:41:58 +00:00
STextContainer & TextContainer = GetTextContainer ( TextContainerIndex ) ;
2018-03-21 14:43:56 +00:00
2018-03-13 20:49:07 +00:00
// remap the current screen, after render revert the change again
float ScreenX0 , ScreenY0 , ScreenX1 , ScreenY1 ;
2019-04-26 19:36:49 +00:00
Graphics ( ) - > GetScreen ( & ScreenX0 , & ScreenY0 , & ScreenX1 , & ScreenY1 ) ;
2020-09-26 19:41:58 +00:00
if ( ( TextContainer . m_RenderFlags & TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT ) = = 0 )
2018-03-21 14:43:56 +00:00
{
float FakeToScreenX = ( Graphics ( ) - > ScreenWidth ( ) / ( ScreenX1 - ScreenX0 ) ) ;
float FakeToScreenY = ( Graphics ( ) - > ScreenHeight ( ) / ( ScreenY1 - ScreenY0 ) ) ;
2021-05-02 08:32:05 +00:00
int ActualX = ( int ) ( ( ( TextContainer . m_X + X ) * FakeToScreenX ) + 0.5f ) ;
int ActualY = ( int ) ( ( ( TextContainer . m_Y + Y ) * FakeToScreenY ) + 0.5f ) ;
2018-03-21 14:43:56 +00:00
float AlignedX = ActualX / FakeToScreenX ;
float AlignedY = ActualY / FakeToScreenY ;
X = AlignedX - TextContainer . m_AlignedStartX ;
Y = AlignedY - TextContainer . m_AlignedStartY ;
}
2019-04-26 19:36:49 +00:00
2018-03-13 20:49:07 +00:00
Graphics ( ) - > MapScreen ( ScreenX0 - X , ScreenY0 - Y , ScreenX1 - X , ScreenY1 - Y ) ;
2022-07-01 04:42:36 +00:00
RenderTextContainer ( TextContainerIndex , TextColor , TextOutlineColor ) ;
2018-03-13 20:49:07 +00:00
Graphics ( ) - > MapScreen ( ScreenX0 , ScreenY0 , ScreenX1 , ScreenY1 ) ;
}
2022-05-17 18:33:27 +00:00
void UploadEntityLayerText ( void * pTexBuff , int ImageColorChannelCount , int TexWidth , int TexHeight , int TexSubWidth , int TexSubHeight , const char * pText , int Length , float x , float y , int FontSize ) override
2017-09-12 18:10:27 +00:00
{
2020-09-26 19:41:58 +00:00
if ( FontSize < 1 )
2019-05-11 15:59:47 +00:00
return ;
2019-05-06 12:19:10 +00:00
const char * pCurrent = ( char * ) pText ;
const char * pEnd = pCurrent + Length ;
2017-09-12 18:10:27 +00:00
CFont * pFont = m_pDefaultFont ;
FT_Bitmap * pBitmap ;
int WidthLastChars = 0 ;
2019-04-26 19:36:49 +00:00
2017-09-27 10:19:39 +00:00
while ( pCurrent < pEnd )
2019-04-26 19:36:49 +00:00
{
2017-09-12 18:10:27 +00:00
const char * pTmp = pCurrent ;
int NextCharacter = str_utf8_decode ( & pTmp ) ;
2019-04-26 19:36:49 +00:00
2017-09-13 18:33:58 +00:00
if ( NextCharacter )
{
2017-09-12 18:10:27 +00:00
unsigned int px , py ;
2019-04-26 19:36:49 +00:00
2019-05-11 15:59:47 +00:00
FT_Set_Pixel_Sizes ( pFont - > m_FtFace , 0 , FontSize ) ;
2017-09-12 18:10:27 +00:00
2020-09-26 19:41:58 +00:00
if ( FT_Load_Char ( pFont - > m_FtFace , NextCharacter , FT_LOAD_RENDER | FT_LOAD_NO_BITMAP ) )
2017-09-12 18:10:27 +00:00
{
2020-10-26 08:57:41 +00:00
dbg_msg ( " textrender " , " error loading glyph %d " , NextCharacter ) ;
2017-09-12 18:10:27 +00:00
pCurrent = pTmp ;
continue ;
}
2019-04-26 19:36:49 +00:00
2022-02-16 19:54:11 +00:00
pBitmap = & pFont - > m_FtFace - > glyph - > bitmap ;
2020-03-20 12:48:45 +00:00
2019-05-06 12:19:10 +00:00
int SlotW = pBitmap - > width ;
int SlotH = pBitmap - > rows ;
2020-09-26 19:41:58 +00:00
int SlotSize = SlotW * SlotH ;
2020-03-20 12:48:45 +00:00
2019-05-06 12:19:10 +00:00
// prepare glyph data
mem_zero ( ms_aGlyphData , SlotSize ) ;
2022-02-16 19:54:11 +00:00
if ( pBitmap - > pixel_mode = = FT_PIXEL_MODE_GRAY )
2020-08-29 10:10:38 +00:00
{
2022-02-16 19:54:11 +00:00
for ( py = 0 ; py < ( unsigned ) SlotH ; py + + )
2020-08-29 10:10:38 +00:00
for ( px = 0 ; px < ( unsigned ) SlotW ; px + + )
{
2022-02-16 19:54:11 +00:00
ms_aGlyphData [ ( py ) * SlotW + px ] = pBitmap - > buffer [ py * pBitmap - > width + px ] ;
2020-08-29 10:10:38 +00:00
}
}
2020-09-26 19:41:58 +00:00
uint8_t * pImageBuff = ( uint8_t * ) pTexBuff ;
2020-08-29 10:10:38 +00:00
for ( int OffY = 0 ; OffY < SlotH ; + + OffY )
{
for ( int OffX = 0 ; OffX < SlotW ; + + OffX )
2017-09-15 01:01:26 +00:00
{
2020-09-14 14:39:05 +00:00
int ImgOffX = clamp ( x + OffX + WidthLastChars , x , ( x + TexSubWidth ) - 1 ) ;
int ImgOffY = clamp ( y + OffY , y , ( y + TexSubHeight ) - 1 ) ;
size_t ImageOffset = ImgOffY * ( TexWidth * ImageColorChannelCount ) + ImgOffX * ImageColorChannelCount ;
size_t GlyphOffset = ( OffY ) * SlotW + OffX ;
2020-08-29 10:10:38 +00:00
for ( size_t i = 0 ; i < ( size_t ) ImageColorChannelCount ; + + i )
{
if ( i ! = ( size_t ) ImageColorChannelCount - 1 )
{
* ( pImageBuff + ImageOffset + i ) = 255 ;
}
else
2017-09-15 01:01:26 +00:00
{
2020-08-29 10:10:38 +00:00
* ( pImageBuff + ImageOffset + i ) = * ( ms_aGlyphData + GlyphOffset ) ;
2017-09-15 01:01:26 +00:00
}
2020-08-29 10:10:38 +00:00
}
2017-09-15 01:01:26 +00:00
}
2020-08-29 10:10:38 +00:00
}
2020-03-20 12:48:45 +00:00
2019-05-06 12:19:10 +00:00
WidthLastChars + = ( SlotW + 1 ) ;
}
pCurrent = pTmp ;
}
}
2020-03-20 12:48:45 +00:00
2022-05-17 18:33:27 +00:00
int AdjustFontSize ( const char * pText , int TextLength , int MaxSize , int MaxWidth ) override
2019-05-06 12:19:10 +00:00
{
int WidthOfText = CalculateTextWidth ( pText , TextLength , 0 , 100 ) ;
2020-08-29 10:10:38 +00:00
int FontSize = 100.f / ( ( float ) WidthOfText / ( float ) MaxWidth ) ;
2019-05-06 12:19:10 +00:00
2020-09-26 19:41:58 +00:00
if ( MaxSize > 0 & & FontSize > MaxSize )
2019-05-06 12:19:10 +00:00
FontSize = MaxSize ;
return FontSize ;
}
2022-05-17 18:33:27 +00:00
float GetGlyphOffsetX ( int FontSize , char TextCharacter ) override
2020-10-16 18:00:57 +00:00
{
CFont * pFont = m_pDefaultFont ;
FT_Set_Pixel_Sizes ( pFont - > m_FtFace , 0 , FontSize ) ;
const char * pTmp = & TextCharacter ;
int NextCharacter = str_utf8_decode ( & pTmp ) ;
if ( NextCharacter )
{
FT_Int32 FTFlags = 0 ;
# if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 7 && (FREETYPE_MINOR > 7 || FREETYPE_PATCH >= 1)
FTFlags = FT_LOAD_BITMAP_METRICS_ONLY | FT_LOAD_NO_BITMAP ;
# else
FTFlags = FT_LOAD_RENDER | FT_LOAD_NO_BITMAP ;
# endif
if ( FT_Load_Char ( pFont - > m_FtFace , NextCharacter , FTFlags ) )
{
2020-10-26 08:57:41 +00:00
dbg_msg ( " textrender " , " error loading glyph %d in GetGlyphOffsetX " , NextCharacter ) ;
2020-10-16 18:00:57 +00:00
return - 1 ;
}
return ( float ) ( pFont - > m_FtFace - > glyph - > metrics . horiBearingX > > 6 ) ;
}
return 0 ;
}
2022-05-17 18:33:27 +00:00
int CalculateTextWidth ( const char * pText , int TextLength , int FontWidth , int FontHeight ) override
2019-05-06 12:19:10 +00:00
{
CFont * pFont = m_pDefaultFont ;
const char * pCurrent = ( char * ) pText ;
const char * pEnd = pCurrent + TextLength ;
2019-04-26 19:36:49 +00:00
2019-05-06 12:19:10 +00:00
int WidthOfText = 0 ;
FT_Set_Pixel_Sizes ( pFont - > m_FtFace , FontWidth , FontHeight ) ;
2020-09-26 19:41:58 +00:00
while ( pCurrent < pEnd )
2019-05-06 12:19:10 +00:00
{
const char * pTmp = pCurrent ;
int NextCharacter = str_utf8_decode ( & pTmp ) ;
if ( NextCharacter )
{
FT_Int32 FTFlags = 0 ;
# if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 7 && (FREETYPE_MINOR > 7 || FREETYPE_PATCH >= 1)
FTFlags = FT_LOAD_BITMAP_METRICS_ONLY | FT_LOAD_NO_BITMAP ;
# else
FTFlags = FT_LOAD_RENDER | FT_LOAD_NO_BITMAP ;
# endif
if ( FT_Load_Char ( pFont - > m_FtFace , NextCharacter , FTFlags ) )
{
2020-10-26 08:57:41 +00:00
dbg_msg ( " textrender " , " error loading glyph %d in CalculateTextWidth " , NextCharacter ) ;
2019-05-06 12:19:10 +00:00
pCurrent = pTmp ;
continue ;
2017-09-12 18:10:27 +00:00
}
2019-05-06 12:19:10 +00:00
WidthOfText + = ( pFont - > m_FtFace - > glyph - > metrics . width > > 6 ) + 1 ;
2017-09-12 18:10:27 +00:00
}
pCurrent = pTmp ;
}
2018-03-21 14:43:56 +00:00
2019-05-06 12:19:10 +00:00
return WidthOfText ;
}
2020-03-20 12:48:45 +00:00
2022-05-17 18:33:27 +00:00
bool SelectionToUTF8OffSets ( const char * pText , int SelStart , int SelEnd , int & OffUTF8Start , int & OffUTF8End ) override
2021-09-12 17:40:23 +00:00
{
const char * pIt = pText ;
OffUTF8Start = - 1 ;
OffUTF8End = - 1 ;
int CharCount = 0 ;
while ( * pIt )
{
const char * pTmp = pIt ;
int Character = str_utf8_decode ( & pTmp ) ;
if ( Character = = - 1 )
return false ;
if ( CharCount = = SelStart )
OffUTF8Start = ( int ) ( ( std : : intptr_t ) ( pIt - pText ) ) ;
if ( CharCount = = SelEnd )
OffUTF8End = ( int ) ( ( std : : intptr_t ) ( pIt - pText ) ) ;
pIt = pTmp ;
+ + CharCount ;
}
if ( CharCount = = SelStart )
OffUTF8Start = ( int ) ( ( std : : intptr_t ) ( pIt - pText ) ) ;
if ( CharCount = = SelEnd )
OffUTF8End = ( int ) ( ( std : : intptr_t ) ( pIt - pText ) ) ;
return OffUTF8Start ! = - 1 & & OffUTF8End ! = - 1 ;
}
2022-05-17 18:33:27 +00:00
bool UTF8OffToDecodedOff ( const char * pText , int UTF8Off , int & DecodedOff ) override
2021-09-16 14:50:17 +00:00
{
const char * pIt = pText ;
DecodedOff = - 1 ;
int CharCount = 0 ;
while ( * pIt )
{
if ( ( int ) ( intptr_t ) ( pIt - pText ) = = UTF8Off )
{
DecodedOff = CharCount ;
return true ;
}
const char * pTmp = pIt ;
int Character = str_utf8_decode ( & pTmp ) ;
if ( Character = = - 1 )
return false ;
pIt = pTmp ;
+ + CharCount ;
}
if ( ( int ) ( std : : intptr_t ) ( pIt - pText ) = = UTF8Off )
{
DecodedOff = CharCount ;
return true ;
}
return false ;
}
2022-05-17 18:33:27 +00:00
bool DecodedOffToUTF8Off ( const char * pText , int DecodedOff , int & UTF8Off ) override
2021-09-16 14:50:17 +00:00
{
const char * pIt = pText ;
UTF8Off = - 1 ;
int CharCount = 0 ;
while ( * pIt )
{
const char * pTmp = pIt ;
int Character = str_utf8_decode ( & pTmp ) ;
if ( Character = = - 1 )
return false ;
if ( CharCount = = DecodedOff )
{
UTF8Off = ( int ) ( ( std : : intptr_t ) ( pIt - pText ) ) ;
return true ;
}
pIt = pTmp ;
+ + CharCount ;
}
if ( CharCount = = DecodedOff )
UTF8Off = ( int ) ( ( std : : intptr_t ) ( pIt - pText ) ) ;
return UTF8Off ! = - 1 ;
}
2022-05-17 18:33:27 +00:00
void OnWindowResize ( ) override
2018-03-21 14:43:56 +00:00
{
2022-05-18 16:23:02 +00:00
bool HasNonEmptyTextContainer = false ;
2022-06-11 19:38:18 +00:00
for ( auto * pTextContainer : m_vpTextContainers )
2018-03-21 15:07:03 +00:00
{
2022-02-09 12:25:00 +00:00
if ( pTextContainer - > m_StringInfo . m_QuadBufferContainerIndex ! = - 1 )
{
2022-05-18 16:23:02 +00:00
dbg_msg ( " textrender " , " Found non empty text container with index %d with %d quads " , pTextContainer - > m_StringInfo . m_QuadBufferContainerIndex , ( int ) pTextContainer - > m_StringInfo . m_QuadNum ) ;
2022-07-10 22:48:38 +00:00
HasNonEmptyTextContainer = true ; // NOLINT(clang-analyzer-deadcode.DeadStores)
2022-02-09 12:25:00 +00:00
}
2018-03-21 15:07:03 +00:00
}
2018-03-21 14:43:56 +00:00
2022-05-18 16:23:02 +00:00
dbg_assert ( ! HasNonEmptyTextContainer , " text container was not empty " ) ;
2022-06-11 19:38:18 +00:00
for ( auto & pFont : m_vpFonts )
2018-03-21 14:43:56 +00:00
{
// reset the skylines
for ( int j = 0 ; j < 2 ; + + j )
2018-05-07 03:52:02 +00:00
{
2022-06-30 22:36:32 +00:00
for ( int & k : pFont - > m_aTextureSkyline [ j ] . m_vCurHeightOfPixelColumn )
2020-10-26 13:11:11 +00:00
k = 0 ;
2018-03-21 14:43:56 +00:00
2022-06-30 22:36:32 +00:00
mem_zero ( pFont - > m_apTextureData [ j ] , ( size_t ) pFont - > m_aCurTextureDimensions [ j ] * pFont - > m_aCurTextureDimensions [ j ] * sizeof ( unsigned char ) ) ;
Graphics ( ) - > UpdateTextTexture ( pFont - > m_aTextures [ j ] , 0 , 0 , pFont - > m_aCurTextureDimensions [ j ] , pFont - > m_aCurTextureDimensions [ j ] , pFont - > m_apTextureData [ j ] ) ;
2018-05-07 03:52:02 +00:00
}
2020-10-26 14:14:07 +00:00
pFont - > InitFontSizes ( ) ;
2018-03-21 14:43:56 +00:00
}
}
2010-05-29 07:25:38 +00:00
} ;
IEngineTextRender * CreateEngineTextRender ( ) { return new CTextRender ; }