Skip to content

Commit

Permalink
Cleaning up text font and putting Mac in Freetype path
Browse files Browse the repository at this point in the history
  • Loading branch information
colincornaby committed May 7, 2023
1 parent 1b86422 commit 6e110c7
Showing 1 changed file with 85 additions and 193 deletions.
278 changes: 85 additions & 193 deletions Sources/Plasma/PubUtilLib/plPipeline/plTextFont.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#import <CoreText/CoreText.h>
#endif

#define DisplayableChar(c) (c >= 0 && c <= 128)

//// Constructor & Destructor /////////////////////////////////////////////////

plTextFont::plTextFont( plPipeline *pipe )
Expand All @@ -88,16 +86,9 @@ plTextFont::~plTextFont()

uint16_t *plTextFont::IInitFontTexture()
{
#ifdef HS_BUILD_FOR_WIN32
int nHeight, x, y, c;
int x, y, c;
char myChar[ 2 ] = "x";

BITMAPINFO bmi;
HDC hDC;
HFONT hFont;
SIZE size;
BYTE bAlpha;


// Figure out our texture size
if( fSize > 40 )
Expand All @@ -109,45 +100,78 @@ uint16_t *plTextFont::IInitFontTexture()

/// Now create the data block
uint16_t* data = new uint16_t[fTextureWidth * fTextureHeight]();

hDC = CreateCompatibleDC(nullptr);
SetMapMode( hDC, MM_TEXT );

nHeight = -MulDiv( fSize, GetDeviceCaps(hDC, LOGPIXELSY), 72 );
fFontHeight = -nHeight;

FT_Library library;
FT_Face face;
FT_Error ftError = FT_Init_FreeType(&library);
hsAssert(ftError == FT_Err_Ok, "FreeType did not initialize");

#ifdef HS_BUILD_FOR_WIN32

HDC hDC;
HFONT hFont;
BYTE bAlpha;

hDC = CreateCompatibleDC(nullptr);
SetMapMode( hDC, MM_TEXT );
// Get the font data

int nHeight = -MulDiv( fSize, GetDeviceCaps(hDC, LOGPIXELSY), 72 );

hFont = CreateFont( nHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, fFace );
hsAssert(hFont != nullptr, "Cannot create Windows font");

SelectObject( hDC, hFont );
// Get the font data

SelectObject(hDC, hFont);

DWORD fontDataSize = GetFontData( hDC, 0, 0, 0, 0 );
void* fontData = std::malloc( fontDataSize );
GetFontData(hDC, 0, 0, fontData, fontDataSize);
ftError = FT_New_Memory_Face(library, (FT_Byte *) fontData, fontDataSize, 0, &face);

FT_UInt freeTypeResolution = GetDeviceCaps(hDC, LOGPIXELSY);
ftError = FT_Set_Char_Size(face, 0, fSize * 64, freeTypeResolution, freeTypeResolution);

// Set text colors
SetTextColor( hDC, RGB( 255, 255, 255 ) );
SetBkColor( hDC, 0 );
SetTextAlign( hDC, TA_TOP );
DeleteDC( hDC );
DeleteObject( hFont );

#elif defined(HS_BUILD_FOR_APPLE)

CFStringRef fontName = CFStringCreateWithCString(nullptr, fFace, kCFStringEncodingUTF8);
CTFontDescriptorRef fontDescriptor = CTFontDescriptorCreateWithNameAndSize( fontName, 0.0f );
CTFontDescriptorRef fulfilledFontDescriptor = CTFontDescriptorCreateMatchingFontDescriptor(fontDescriptor, nullptr);
hsAssert(fulfilledFontDescriptor != nullptr, "Cannot create Mac font");
CFRelease(fontName);
CFRelease(fontDescriptor);

CFURLRef fontURL = (CFURLRef) CTFontDescriptorCopyAttribute(fulfilledFontDescriptor, kCTFontURLAttribute);
CFStringRef fileSystemPath = CFURLCopyFileSystemPath(fontURL, kCFURLPOSIXPathStyle);
char cPath[PATH_MAX];
CFStringGetCString(fileSystemPath, cPath, PATH_MAX, kCFStringEncodingUTF8);

ftError = FT_New_Face(library, cPath, 0, &face);

CFRelease(fulfilledFontDescriptor);
CFRelease(fontURL);
CFRelease(fileSystemPath);

FT_UInt freeTypeResolution = 192;
#else
FT_Done_FreeType(library);
FT_UInt freeTypeResolution = 0;
return nullptr;
#endif

ftError = FT_Set_Char_Size(face, 0, fSize * 64, freeTypeResolution, freeTypeResolution);
FT_Size_Metrics fontMetrics = face->size->metrics;

fFontHeight = int(fontMetrics.height / 64.f);

data[0] = 0xffff;

int maxDescent = abs(int(fontMetrics.descender / 64.f));
struct {
long cx;
long cy;
} size;

// Loop through characters, drawing them one at a time
for( c = 32, x = 1, y = 0; c < 127; c++ )
Expand All @@ -173,7 +197,7 @@ uint16_t *plTextFont::IInitFontTexture()
x = 0;
y += size.cy + 1;
}
int offset = fFontHeight - cBox.yMax;
int offset = int( fFontHeight - cBox.yMax );

//blit the bitmap into place
for (int glyphY = bitmap.rows - 1; glyphY >= 0 ; glyphY--) {
Expand Down Expand Up @@ -218,134 +242,7 @@ uint16_t *plTextFont::IInitFontTexture()
FT_Done_Face(face);
FT_Done_FreeType(library);

// Cleanup and return
DeleteDC( hDC );
DeleteObject( hFont );

return data;
#elif defined(HS_BUILD_FOR_APPLE)
int nHeight, x, y, c;
char myChar[ 2 ] = "x";
uint16_t *tBits;

uint32_t *bitmapBits;
uint32_t bAlpha;


// Figure out our texture size
if( fSize * 2 > 40 )
fTextureWidth = fTextureHeight = 1024;
else if( fSize * 2 > 20 )
fTextureWidth = fTextureHeight = 512;
else
fTextureWidth = fTextureHeight = 256;


// Create a new DC and bitmap that we can draw characters to
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGContextRef bitmapContext = CGBitmapContextCreate(nullptr,
fTextureWidth,
fTextureHeight,
8,
4 * fTextureWidth,
colorSpace,
kCGImageAlphaPremultipliedLast);
CFRelease(colorSpace);
CGContextSetTextMatrix(bitmapContext, CGAffineTransformMakeScale(1, -1));
CGContextTranslateCTM(bitmapContext, 0, fTextureHeight);
CGContextScaleCTM(bitmapContext, 1, -1);
CGContextScaleCTM(bitmapContext, 2.0, 2.0);

bitmapBits = (uint32_t *)CGBitmapContextGetData(bitmapContext);

//TEMPORARY: Mac client should vend through better data to make this decision
nHeight = fSize;
fFontHeight = (fSize * 144.0f) / 72.0f;

CFStringRef fontName = CFStringCreateWithCString(nullptr, fFace, kCFStringEncodingUTF8);
CTFontRef font = CTFontCreateWithName(fontName, nHeight, nullptr);
hsAssert(font != nullptr, "Cannot create Mac font");
CFRelease(fontName);

// Set text colors
CGFloat color[4] = { 255.0f, 255.0f, 255.0f, 255.0f };
CGContextSetFillColor(bitmapContext, color);
CGContextSetShouldAntialias(bitmapContext, false);

// Loop through characters, drawing them one at a time
CGRect r = CGRectMake(0, 0, 10, 10);

fTextureWidth /= 2;
fTextureHeight /= 2;

// (Make first character a black dot, for filling rectangles)
bitmapBits[0] = UINT32_MAX;
for( c = 32, x = 1, y = 0; c < 127; c++ )
{
myChar[ 0 ] = c;
CGGlyph glpyh;
CTFontGetGlyphsForCharacters(font, (UniChar *)myChar, &glpyh, 1);
CGRect rect;
CTFontGetOpticalBoundsForGlyphs(font, &glpyh, &rect, 1, 0);
CGSize size = rect.size;

if( (uint32_t)( x + size.width + 1 ) > fTextureWidth )
{
x = 0;
y += size.height + 1;
}

CGPoint position = CGPointMake(x, -y - size.height - rect.origin.y);
CTFontDrawGlyphs(font, &glpyh, &position, 1, bitmapContext);

fCharInfo[ c ].fW = (uint16_t)size.width * 2.0f;
fCharInfo[ c ].fH = (uint16_t)size.height * 2.0f;
fCharInfo[ c ].fUVs[ 0 ].fX = (float)x / (float)fTextureWidth;
fCharInfo[ c ].fUVs[ 0 ].fY = (float)y / (float)fTextureHeight;
fCharInfo[ c ].fUVs[ 1 ].fX = (float)( x + size.width ) / (float)fTextureWidth;
fCharInfo[ c ].fUVs[ 1 ].fY = (float)( y + size.height ) / (float)fTextureHeight;
fCharInfo[ c ].fUVs[ 0 ].fZ = fCharInfo[ c ].fUVs[ 1 ].fZ = 0;

x += ceil(size.width) + 1;
}
fCharInfo[ 32 ].fUVs[ 1 ].fX = fCharInfo[ 32 ].fUVs[ 0 ].fX;

// Special case the tab key
fCharInfo[ '\t' ].fUVs[ 1 ].fX = fCharInfo[ '\t' ].fUVs[ 0 ].fX = fCharInfo[ 32 ].fUVs[ 0 ].fX;
fCharInfo[ '\t' ].fUVs[ 1 ].fY = fCharInfo[ '\t' ].fUVs[ 0 ].fY = 0;
fCharInfo[ '\t' ].fUVs[ 0 ].fZ = fCharInfo[ '\t' ].fUVs[ 1 ].fZ = 0;
fCharInfo[ '\t' ].fW = fCharInfo[ 32 ].fW * 4;
fCharInfo[ '\t' ].fH = fCharInfo[ 32 ].fH;

fTextureWidth *= 2;
fTextureHeight *= 2;

/// Now create the data block
uint16_t *data = new uint16_t[ fTextureWidth * fTextureHeight ];
tBits = data;
for( y = 0; y < fTextureHeight; y++ )
{
for( x = 0; x < fTextureWidth; x++ )
{
bAlpha = (char)( ( bitmapBits[ fTextureWidth * y + x ] & 0xff ) >> 4 );

if( bitmapBits[ fTextureWidth * y + x ] )
*tBits = 0xffff;
else
*tBits = 0;

tBits++;
}
}

// Cleanup and return
CFRelease(font);
CFRelease(bitmapContext);

return data;
#else
return nullptr;
#endif
}

//// Create ///////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -384,7 +281,8 @@ void plTextFont::DrawString( const char *string, int sX, int sY, uint32_t hex
{
static std::vector<plFontVertex> verts;

int i, j, width, height, count, thisCount, italOffset;
size_t i, j, width, height, count, thisCount;
uint32_t italOffset;
float x = (float)sX;
char c, *strPtr;

Expand Down Expand Up @@ -414,49 +312,45 @@ void plTextFont::DrawString( const char *string, int sX, int sY, uint32_t hex
for( i = 0, j = 0; i < thisCount; i++, j += 6 )
{
c = strPtr[ i ];
// make sure its a character we will display
if ( DisplayableChar(c) )
width = fCharInfo[uint8_t(c)].fW + 1;
height = fCharInfo[uint8_t(c)].fH + 1;

if( rightEdge > 0 && x + width + italOffset >= rightEdge )
{
width = fCharInfo[uint8_t(c)].fW + 1;
height = fCharInfo[uint8_t(c)].fH + 1;

if( rightEdge > 0 && x + width + italOffset >= rightEdge )
{
count = 0;
thisCount = i;
break;
}
count = 0;
thisCount = i;
break;
}

verts[ j ].fPoint.fX = x + italOffset;
verts[ j ].fPoint.fY = (float)sY;
verts[ j ].fUV = fCharInfo[uint8_t(c)].fUVs[ 0 ];
verts[ j ].fPoint.fX = x + italOffset;
verts[ j ].fPoint.fY = (float)sY;
verts[ j ].fUV = fCharInfo[uint8_t(c)].fUVs[ 0 ];

verts[ j + 1 ].fPoint.fX = x + width + italOffset;
verts[ j + 1 ].fPoint.fY = (float)sY;
verts[ j + 1 ].fUV = fCharInfo[uint8_t(c)].fUVs[ 0 ];
verts[ j + 1 ].fUV.fX = fCharInfo[uint8_t(c)].fUVs[ 1 ].fX;
verts[ j + 1 ].fPoint.fX = x + width + italOffset;
verts[ j + 1 ].fPoint.fY = (float)sY;
verts[ j + 1 ].fUV = fCharInfo[uint8_t(c)].fUVs[ 0 ];
verts[ j + 1 ].fUV.fX = fCharInfo[uint8_t(c)].fUVs[ 1 ].fX;

verts[ j + 2 ].fPoint.fX = x;
verts[ j + 2 ].fPoint.fY = (float)sY + height;
verts[ j + 2 ].fUV = fCharInfo[uint8_t(c)].fUVs[ 0 ];
verts[ j + 2 ].fUV.fY = fCharInfo[uint8_t(c)].fUVs[ 1 ].fY;
verts[ j + 2 ].fPoint.fX = x;
verts[ j + 2 ].fPoint.fY = (float)sY + height;
verts[ j + 2 ].fUV = fCharInfo[uint8_t(c)].fUVs[ 0 ];
verts[ j + 2 ].fUV.fY = fCharInfo[uint8_t(c)].fUVs[ 1 ].fY;

verts[ j + 3 ].fPoint.fX = x;
verts[ j + 3 ].fPoint.fY = (float)sY + height;
verts[ j + 3 ].fUV = fCharInfo[uint8_t(c)].fUVs[ 0 ];
verts[ j + 3 ].fUV.fY = fCharInfo[uint8_t(c)].fUVs[ 1 ].fY;
verts[ j + 3 ].fPoint.fX = x;
verts[ j + 3 ].fPoint.fY = (float)sY + height;
verts[ j + 3 ].fUV = fCharInfo[uint8_t(c)].fUVs[ 0 ];
verts[ j + 3 ].fUV.fY = fCharInfo[uint8_t(c)].fUVs[ 1 ].fY;

verts[ j + 4 ].fPoint.fX = x + width + italOffset;
verts[ j + 4 ].fPoint.fY = (float)sY;
verts[ j + 4 ].fUV = fCharInfo[uint8_t(c)].fUVs[ 0 ];
verts[ j + 4 ].fUV.fX = fCharInfo[uint8_t(c)].fUVs[ 1 ].fX;
verts[ j + 4 ].fPoint.fX = x + width + italOffset;
verts[ j + 4 ].fPoint.fY = (float)sY;
verts[ j + 4 ].fUV = fCharInfo[uint8_t(c)].fUVs[ 0 ];
verts[ j + 4 ].fUV.fX = fCharInfo[uint8_t(c)].fUVs[ 1 ].fX;

verts[ j + 5 ].fPoint.fX = x + width;
verts[ j + 5 ].fPoint.fY = (float)sY + height;
verts[ j + 5 ].fUV = fCharInfo[uint8_t(c)].fUVs[ 1 ];
verts[ j + 5 ].fPoint.fX = x + width;
verts[ j + 5 ].fPoint.fY = (float)sY + height;
verts[ j + 5 ].fUV = fCharInfo[uint8_t(c)].fUVs[ 1 ];

x += width + 1;
}
x += width + 1;
}

if( thisCount == 0 )
Expand Down Expand Up @@ -502,7 +396,7 @@ void plTextFont::DrawString( const char *string, int sX, int sY, uint32_t hex


/// Draw a set of tris now
IDrawPrimitive(thisCount * ((style & plDebugText::kStyleBold) ? 4 : 2), verts.data());
IDrawPrimitive(thisCount * uint32_t((style & plDebugText::kStyleBold) ? 4 : 2), verts.data());

strPtr += thisCount;
}
Expand All @@ -522,9 +416,7 @@ uint32_t plTextFont::CalcStringWidth( const char *string )

for( i = 0; i < strlen( string ); i++ )
{
// make sure its a character we will display
if ( DisplayableChar(string[i]) )
width += fCharInfo[uint8_t(string[i])].fW + 2;
width += fCharInfo[uint8_t(string[i])].fW + 2;
}

return width;
Expand Down

0 comments on commit 6e110c7

Please sign in to comment.