Cleanups for font drivers

This commit is contained in:
libretroadmin 2023-06-15 12:36:44 +02:00
parent 1fc5c600a4
commit ae3ac72356
6 changed files with 167 additions and 167 deletions

View File

@ -57,29 +57,14 @@ typedef struct
uint32_t ascent; uint32_t ascent;
} d3dfonts_t; } d3dfonts_t;
static void d3d9x_font_release(ID3DXFont *font)
{
font->lpVtbl->Release(font);
}
static void d3d9x_font_get_text_metrics(ID3DXFont *font, TEXTMETRICA *metrics)
{
font->lpVtbl->GetTextMetrics(font, metrics);
}
static void d3d9x_font_draw_text(ID3DXFont *font, LPD3DXSPRITE sprite_data, LPCTSTR string_data,
unsigned count, LPRECT rect_data, DWORD format, D3DCOLOR color)
{
font->lpVtbl->DrawText(font, sprite_data,
string_data, count, rect_data, format, color);
}
static void *d3d9x_win32_font_init(void *video_data, static void *d3d9x_win32_font_init(void *video_data,
const char *font_path, float font_size, const char *font_path, float font_size,
bool is_threaded) bool is_threaded)
{ {
TEXTMETRICA metrics; TEXTMETRICA metrics;
d3d9x_font_desc_t desc; d3d9x_font_desc_t desc;
uint32_t new_font_size = 0;
ID3DXFont *font = NULL;
d3dfonts_t *d3dfonts = (d3dfonts_t*)calloc(1, sizeof(*d3dfonts)); d3dfonts_t *d3dfonts = (d3dfonts_t*)calloc(1, sizeof(*d3dfonts));
if (!d3dfonts) if (!d3dfonts)
return NULL; return NULL;
@ -93,6 +78,7 @@ static void *d3d9x_win32_font_init(void *video_data,
desc.OutputPrecision = OUT_TT_PRECIS; desc.OutputPrecision = OUT_TT_PRECIS;
desc.Quality = CLIP_DEFAULT_PRECIS; desc.Quality = CLIP_DEFAULT_PRECIS;
desc.PitchAndFamily = DEFAULT_PITCH; desc.PitchAndFamily = DEFAULT_PITCH;
/* TODO/FIXME - don't hardcode this font */ /* TODO/FIXME - don't hardcode this font */
#ifdef UNICODE #ifdef UNICODE
strlcpy(desc.FaceName, T(L"Verdana"), sizeof(desc.FaceName)); strlcpy(desc.FaceName, T(L"Verdana"), sizeof(desc.FaceName));
@ -100,16 +86,19 @@ static void *d3d9x_win32_font_init(void *video_data,
strlcpy(desc.FaceName, (const char*)_T("Verdana"), sizeof(desc.FaceName)); strlcpy(desc.FaceName, (const char*)_T("Verdana"), sizeof(desc.FaceName));
#endif #endif
d3dfonts->font_size = font_size * 1.2; /* To match the other font drivers */ new_font_size = font_size * 1.2; /* To match the other font drivers */
d3dfonts->font_size = new_font_size;
d3dfonts->d3d = (d3d9_video_t*)video_data; d3dfonts->d3d = (d3d9_video_t*)video_data;
desc.Height = d3dfonts->font_size; desc.Height = new_font_size;
if (!d3d9x_create_font_indirect(d3dfonts->d3d->dev, if (!d3d9x_create_font_indirect(d3dfonts->d3d->dev,
&desc, (void**)&d3dfonts->font)) &desc, (void**)&d3dfonts->font))
goto error; goto error;
d3d9x_font_get_text_metrics(d3dfonts->font, &metrics); font = d3dfonts->font;
font->lpVtbl->GetTextMetrics(font, &metrics);
d3dfonts->ascent = metrics.tmAscent; d3dfonts->ascent = metrics.tmAscent;
@ -122,13 +111,16 @@ error:
static void d3d9x_win32_font_free(void *data, bool is_threaded) static void d3d9x_win32_font_free(void *data, bool is_threaded)
{ {
ID3DXFont *font = NULL;
d3dfonts_t *d3dfonts = (d3dfonts_t*)data; d3dfonts_t *d3dfonts = (d3dfonts_t*)data;
if (!d3dfonts) if (!d3dfonts)
return; return;
if (d3dfonts->font) font = d3dfonts->font;
d3d9x_font_release((ID3DXFont*)d3dfonts->font);
if (font)
font->lpVtbl->Release(font);
free(d3dfonts); free(d3dfonts);
} }
@ -138,12 +130,15 @@ static int d3d9x_win32_font_get_message_width(void* data, const char* msg,
{ {
RECT box = {0,0,0,0}; RECT box = {0,0,0,0};
d3dfonts_t *d3dfonts = (d3dfonts_t*)data; d3dfonts_t *d3dfonts = (d3dfonts_t*)data;
ID3DXFont *font = NULL;
if (!d3dfonts || !msg) if (!d3dfonts || !msg)
return 0; return 0;
d3d9x_font_draw_text(d3dfonts->font, NULL, (void*)msg, font = d3dfonts->font;
msg_len ? msg_len : -1, &box, DT_CALCRECT, 0);
font->lpVtbl->DrawText(font, NULL,
(void*)msg, msg_len ? (INT)msg_len : -1, &box, DT_CALCRECT, 0);
return box.right - box.left; return box.right - box.left;
} }
@ -159,6 +154,7 @@ static void d3d9x_win32_font_render_msg(
RECT rect, rect_shifted; RECT rect, rect_shifted;
RECT *p_rect_shifted = NULL; RECT *p_rect_shifted = NULL;
RECT *p_rect = NULL; RECT *p_rect = NULL;
ID3DXFont *font = NULL;
d3dfonts_t *d3dfonts = (d3dfonts_t*)data; d3dfonts_t *d3dfonts = (d3dfonts_t*)data;
float drop_mod = 0.3f; float drop_mod = 0.3f;
float drop_alpha = 1.0f; float drop_alpha = 1.0f;
@ -168,6 +164,8 @@ static void d3d9x_win32_font_render_msg(
if (!d3dfonts || !msg) if (!d3dfonts || !msg)
return; return;
font = d3dfonts->font;
width = d3dfonts->d3d->video_info.width; width = d3dfonts->d3d->video_info.width;
height = d3dfonts->d3d->video_info.height; height = d3dfonts->d3d->video_info.height;
@ -242,13 +240,14 @@ static void d3d9x_win32_font_render_msg(
unsigned drop_g = g * drop_mod; unsigned drop_g = g * drop_mod;
unsigned drop_b = b * drop_mod; unsigned drop_b = b * drop_mod;
d3d9x_font_draw_text(d3dfonts->font, NULL, font->lpVtbl->DrawText(font, NULL,
(void*)msg, -1, p_rect_shifted, format, (void*)msg, -1, p_rect_shifted, format,
D3DCOLOR_ARGB(drop_a , drop_r, drop_g, drop_b)); D3DCOLOR_ARGB(drop_a , drop_r, drop_g, drop_b));
} }
d3d9x_font_draw_text(d3dfonts->font, NULL, (void*)msg, -1, font->lpVtbl->DrawText(font, NULL,
p_rect, format, D3DCOLOR_ARGB(a, r, g, b)); (void*)msg, -1, p_rect, format,
D3DCOLOR_ARGB(a, r, g, b));
} }
font_renderer_t d3d9x_win32_font = { font_renderer_t d3d9x_win32_font = {

View File

@ -55,8 +55,7 @@ bitmapfont_lut_t *bitmapfont_get_lut(void)
size_t i, j; size_t i, j;
/* Initialise font struct */ /* Initialise font struct */
font = (bitmapfont_lut_t*)calloc(1, sizeof(bitmapfont_lut_t)); if (!(font = (bitmapfont_lut_t*)calloc(1, sizeof(bitmapfont_lut_t))))
if (!font)
goto error; goto error;
font->glyph_min = 0; font->glyph_min = 0;
@ -109,8 +108,8 @@ void bitmapfont_free_lut(bitmapfont_lut_t *font)
if (font->lut) if (font->lut)
{ {
size_t num_glyphs = (font->glyph_max - font->glyph_min) + 1;
size_t i; size_t i;
size_t num_glyphs = (font->glyph_max - font->glyph_min) + 1;
for (i = 0; i < num_glyphs; i++) for (i = 0; i < num_glyphs; i++)
{ {
@ -137,9 +136,9 @@ static const struct font_glyph *font_renderer_bmp_get_glyph(
void *data, uint32_t code) void *data, uint32_t code)
{ {
bm_renderer_t *handle = (bm_renderer_t*)data; bm_renderer_t *handle = (bm_renderer_t*)data;
if (!handle) if (handle && (code < BMP_ATLAS_SIZE))
return &handle->glyphs[code];
return NULL; return NULL;
return code < BMP_ATLAS_SIZE ? &handle->glyphs[code] : NULL;
} }
static void char_to_texture(bm_renderer_t *handle, uint8_t letter, static void char_to_texture(bm_renderer_t *handle, uint8_t letter,
@ -179,10 +178,7 @@ static void *font_renderer_bmp_init(const char *font_path, float font_size)
if (!handle) if (!handle)
return NULL; return NULL;
(void)font_path; if (!(handle->scale_factor = (unsigned)roundf(font_size / FONT_HEIGHT)))
handle->scale_factor = (unsigned)roundf(font_size / FONT_HEIGHT);
if (!handle->scale_factor)
handle->scale_factor = 1; handle->scale_factor = 1;
handle->atlas.width = (BMP_ATLAS_PADDING + (FONT_WIDTH * handle->scale_factor)) * BMP_ATLAS_COLS; handle->atlas.width = (BMP_ATLAS_PADDING + (FONT_WIDTH * handle->scale_factor)) * BMP_ATLAS_COLS;

View File

@ -90,7 +90,6 @@ static void font_renderer_ct_free(void *data)
static bool coretext_font_renderer_create_atlas(CTFontRef face, ct_font_renderer_t *handle) static bool coretext_font_renderer_create_atlas(CTFontRef face, ct_font_renderer_t *handle)
{ {
int max_width, max_height;
unsigned i; unsigned i;
size_t bytesPerRow; size_t bytesPerRow;
CGGlyph glyphs[CT_ATLAS_SIZE]; CGGlyph glyphs[CT_ATLAS_SIZE];
@ -101,6 +100,8 @@ static bool coretext_font_renderer_create_atlas(CTFontRef face, ct_font_renderer
CFDictionaryRef attr; CFDictionaryRef attr;
CFTypeRef values[1]; CFTypeRef values[1];
CFStringRef keys[1]; CFStringRef keys[1];
int max_height = 0;
int max_width = 0;
void *bitmapData = NULL; void *bitmapData = NULL;
bool ret = true; bool ret = true;
size_t bitsPerComponent = 8; size_t bitsPerComponent = 8;
@ -133,9 +134,6 @@ static bool coretext_font_renderer_create_atlas(CTFontRef face, ct_font_renderer
ascent = CTFontGetAscent(face); ascent = CTFontGetAscent(face);
descent = CTFontGetDescent(face); descent = CTFontGetDescent(face);
max_width = 0;
max_height = 0;
for (i = 0; i < CT_ATLAS_SIZE; i++) for (i = 0; i < CT_ATLAS_SIZE; i++)
{ {
int origin_x, origin_y; int origin_x, origin_y;
@ -176,15 +174,16 @@ static bool coretext_font_renderer_create_atlas(CTFontRef face, ct_font_renderer
handle->line_metrics.ascender + handle->line_metrics.descender + handle->line_metrics.ascender + handle->line_metrics.descender +
(float)CTFontGetLeading(face); (float)CTFontGetLeading(face);
handle->atlas.buffer = (uint8_t*) handle->atlas.buffer = (uint8_t*)calloc(
calloc(handle->atlas.width * handle->atlas.height, 1); handle->atlas.width * handle->atlas.height, 1);
if (!handle->atlas.buffer) if (!handle->atlas.buffer)
return false; return false;
bytesPerRow = max_width; bytesPerRow = max_width;
bitmapData = calloc(max_height, bytesPerRow); bitmapData = calloc(max_height, bytesPerRow);
offscreen = CGBitmapContextCreate(bitmapData, max_width, max_height, offscreen = CGBitmapContextCreate(
bitmapData, max_width, max_height,
bitsPerComponent, bytesPerRow, NULL, kCGImageAlphaOnly); bitsPerComponent, bytesPerRow, NULL, kCGImageAlphaOnly);
CGContextSetTextMatrix(offscreen, CGAffineTransformIdentity); CGContextSetTextMatrix(offscreen, CGAffineTransformIdentity);
@ -195,13 +194,13 @@ static bool coretext_font_renderer_create_atlas(CTFontRef face, ct_font_renderer
for (i = 0; i < CT_ATLAS_SIZE; i++) for (i = 0; i < CT_ATLAS_SIZE; i++)
{ {
unsigned offset_x, offset_y, r, c;
char glyph_cstr[2]; char glyph_cstr[2];
const uint8_t *src; const uint8_t *src;
uint8_t *dst; uint8_t *dst;
unsigned offset_x, offset_y, r, c; CTLineRef line;
CFStringRef glyph_cfstr; CFStringRef glyph_cfstr;
CFAttributedStringRef attrString; CFAttributedStringRef attrString;
CTLineRef line;
struct font_glyph *glyph = &handle->atlas_slots[i].glyph; struct font_glyph *glyph = &handle->atlas_slots[i].glyph;
if (!glyph) if (!glyph)
@ -220,11 +219,12 @@ static bool coretext_font_renderer_create_atlas(CTFontRef face, ct_font_renderer
glyph_cstr[1] = 0; glyph_cstr[1] = 0;
glyph_cfstr = CFStringCreateWithCString( glyph_cfstr = CFStringCreateWithCString(
NULL, glyph_cstr, kCFStringEncodingASCII); NULL, glyph_cstr, kCFStringEncodingASCII);
attrString = attrString = CFAttributedStringCreate(
CFAttributedStringCreate(NULL, glyph_cfstr, attr); NULL, glyph_cfstr, attr);
CFRelease(glyph_cfstr); CFRelease(glyph_cfstr);
glyph_cfstr = NULL; glyph_cfstr = NULL;
line = CTLineCreateWithAttributedString(attrString); line = CTLineCreateWithAttributedString(
attrString);
CFRelease(attrString); CFRelease(attrString);
attrString = NULL; attrString = NULL;
@ -247,7 +247,6 @@ static bool coretext_font_renderer_create_atlas(CTFontRef face, ct_font_renderer
unsigned dest_idx = unsigned dest_idx =
(r + offset_y) * (CT_ATLAS_COLS * max_width) + (c + offset_x); (r + offset_y) * (CT_ATLAS_COLS * max_width) + (c + offset_x);
uint8_t v = src[src_idx]; uint8_t v = src[src_idx];
dst[dest_idx] = v; dst[dest_idx] = v;
} }
} }
@ -280,10 +279,8 @@ static void *font_renderer_ct_init(const char *font_path, float font_size)
goto error; goto error;
} }
cf_font_path = CFStringCreateWithCString( if (!(cf_font_path = CFStringCreateWithCString(
NULL, font_path, kCFStringEncodingASCII); NULL, font_path, kCFStringEncodingASCII)))
if (!cf_font_path)
{ {
err = 1; err = 1;
goto error; goto error;
@ -319,21 +316,25 @@ error:
CFRelease(cf_font_path); CFRelease(cf_font_path);
cf_font_path = NULL; cf_font_path = NULL;
} }
if (face) if (face)
{ {
CFRelease(face); CFRelease(face);
face = NULL; face = NULL;
} }
if (url) if (url)
{ {
CFRelease(url); CFRelease(url);
url = NULL; url = NULL;
} }
if (dataProvider) if (dataProvider)
{ {
CFRelease(dataProvider); CFRelease(dataProvider);
dataProvider = NULL; dataProvider = NULL;
} }
if (theCGFont) if (theCGFont)
{ {
CFRelease(theCGFont); CFRelease(theCGFont);
@ -343,14 +344,12 @@ error:
return handle; return handle;
} }
static const char *font_renderer_ct_get_default_font(void)
{
/* We can't tell if a font is going to be there until we actually /* We can't tell if a font is going to be there until we actually
initialize CoreText and the best way to get fonts is by name, not initialize CoreText and the best way to get fonts is by name, not
by path. */ by path. */
static const char *default_font = "Verdana"; return "Verdana";
static const char *font_renderer_ct_get_default_font(void)
{
return default_font;
} }
static void font_renderer_ct_get_line_metrics( static void font_renderer_ct_get_line_metrics(

View File

@ -216,14 +216,15 @@ static bool font_renderer_create_atlas(ft_font_renderer_t *handle, float font_si
unsigned i, x, y; unsigned i, x, y;
freetype_atlas_slot_t* slot = NULL; freetype_atlas_slot_t* slot = NULL;
unsigned max_width = round((handle->face->bbox.xMax - handle->face->bbox.xMin) * font_size / handle->face->units_per_EM); unsigned max_width = round((handle->face->bbox.xMax - handle->face->bbox.xMin)
unsigned max_height = round((handle->face->bbox.yMax - handle->face->bbox.yMin) * font_size / handle->face->units_per_EM); * font_size / handle->face->units_per_EM);
unsigned max_height = round((handle->face->bbox.yMax - handle->face->bbox.yMin)
* font_size / handle->face->units_per_EM);
unsigned atlas_width = (max_width + FT_ATLAS_PADDING) * FT_ATLAS_COLS; unsigned atlas_width = (max_width + FT_ATLAS_PADDING) * FT_ATLAS_COLS;
unsigned atlas_height = (max_height + FT_ATLAS_PADDING) * FT_ATLAS_ROWS; unsigned atlas_height = (max_height + FT_ATLAS_PADDING) * FT_ATLAS_ROWS;
uint8_t *atlas_buffer = (uint8_t*) uint8_t *atlas_buffer = (uint8_t*)calloc(atlas_width * atlas_height, 1);
calloc(atlas_width * atlas_height, 1);
if (!atlas_buffer) if (!atlas_buffer)
return false; return false;

View File

@ -128,11 +128,11 @@ static bool font_renderer_stb_create_atlas(stb_font_renderer_t *self,
return true; return true;
error: error:
self->atlas.width = self->atlas.height = 0;
if (self->atlas.buffer) if (self->atlas.buffer)
free(self->atlas.buffer); free(self->atlas.buffer);
self->atlas.width = 0;
self->atlas.height = 0;
self->atlas.buffer = NULL; self->atlas.buffer = NULL;
return false; return false;
@ -140,9 +140,9 @@ error:
static void *font_renderer_stb_init(const char *font_path, float font_size) static void *font_renderer_stb_init(const char *font_path, float font_size)
{ {
int ascent, descent, line_gap;
float scale_factor; float scale_factor;
stbtt_fontinfo info; stbtt_fontinfo info;
int ascent, descent, line_gap;
uint8_t *font_data = NULL; uint8_t *font_data = NULL;
stb_font_renderer_t *self = (stb_font_renderer_t*) calloc(1, sizeof(*self)); stb_font_renderer_t *self = (stb_font_renderer_t*) calloc(1, sizeof(*self));
@ -150,7 +150,7 @@ static void *font_renderer_stb_init(const char *font_path, float font_size)
font_size = STBTT_POINT_SIZE(font_size); font_size = STBTT_POINT_SIZE(font_size);
if (!self) if (!self)
goto error; return NULL;
if (!path_is_valid(font_path) || !filestream_read_file(font_path, (void**)&font_data, NULL)) if (!path_is_valid(font_path) || !filestream_read_file(font_path, (void**)&font_data, NULL))
goto error; goto error;
@ -163,9 +163,9 @@ static void *font_renderer_stb_init(const char *font_path, float font_size)
stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap); stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap);
scale_factor = (font_size < 0) ? scale_factor = (font_size < 0)
stbtt_ScaleForMappingEmToPixels(&info, -font_size) : ? stbtt_ScaleForMappingEmToPixels(&info, -font_size)
stbtt_ScaleForPixelHeight(&info, font_size); : stbtt_ScaleForPixelHeight(&info, font_size);
/* Ascender, descender and line_gap values always /* Ascender, descender and line_gap values always
* end up ~0.5 pixels too small when scaled... * end up ~0.5 pixels too small when scaled...

View File

@ -150,11 +150,10 @@ static const struct font_glyph *font_renderer_stb_unicode_get_glyph(
+ atlas_slot->glyph.atlas_offset_y * self->atlas.width; + atlas_slot->glyph.atlas_offset_y * self->atlas.width;
stbtt_GetGlyphHMetrics(&self->info, glyph_index, &advance_width, &left_side_bearing); stbtt_GetGlyphHMetrics(&self->info, glyph_index, &advance_width, &left_side_bearing);
if (stbtt_GetGlyphBox(&self->info, glyph_index, &x0, NULL, NULL, &y1)) if (stbtt_GetGlyphBox(&self->info, glyph_index, &x0, NULL, NULL, &y1))
{
stbtt_MakeGlyphBitmap(&self->info, dst, self->max_glyph_width, self->max_glyph_height, stbtt_MakeGlyphBitmap(&self->info, dst, self->max_glyph_width, self->max_glyph_height,
self->atlas.width, self->scale_factor, self->scale_factor, glyph_index); self->atlas.width, self->scale_factor, self->scale_factor, glyph_index);
}
else else
{ {
/* This means the glyph is empty. In this case, stbtt_MakeGlyphBitmap() /* This means the glyph is empty. In this case, stbtt_MakeGlyphBitmap()
@ -168,21 +167,26 @@ static const struct font_glyph *font_renderer_stb_unicode_get_glyph(
atlas_slot->glyph.width = self->max_glyph_width; atlas_slot->glyph.width = self->max_glyph_width;
atlas_slot->glyph.height = self->max_glyph_height; atlas_slot->glyph.height = self->max_glyph_height;
/* advance_x must always be rounded to the /* advance_x must always be rounded to the
* *nearest* integer */ * *nearest* integer */
glyph_advance_x = (float)advance_width * self->scale_factor; glyph_advance_x = (float)advance_width * self->scale_factor;
atlas_slot->glyph.advance_x = (int)((glyph_advance_x > 0.0f) ? atlas_slot->glyph.advance_x = (int)((glyph_advance_x > 0.0f)
(glyph_advance_x + 0.5f) : (glyph_advance_x - 0.5f)); ? (glyph_advance_x + 0.5f)
: (glyph_advance_x - 0.5f));
/* advance_y is always zero */ /* advance_y is always zero */
atlas_slot->glyph.advance_y = 0; atlas_slot->glyph.advance_y = 0;
/* draw_offset_x must always be rounded *down* /* draw_offset_x must always be rounded *down*
* to the nearest integer */ * to the nearest integer */
atlas_slot->glyph.draw_offset_x = (int)((float)x0 * self->scale_factor); atlas_slot->glyph.draw_offset_x = (int)((float)x0 * self->scale_factor);
/* draw_offset_y must always be rounded *up* /* draw_offset_y must always be rounded *up*
* to the nearest integer */ * to the nearest integer */
glyph_draw_offset_y = (float)(-y1) * self->scale_factor; glyph_draw_offset_y = (float)(-y1) * self->scale_factor;
atlas_slot->glyph.draw_offset_y = (int)((glyph_draw_offset_y < 0.0f) ? atlas_slot->glyph.draw_offset_y = (int)((glyph_draw_offset_y < 0.0f)
floor((double)glyph_draw_offset_y) : ceil((double)glyph_draw_offset_y)); ? floor((double)glyph_draw_offset_y)
: ceil((double)glyph_draw_offset_y));
self->atlas.dirty = true; self->atlas.dirty = true;
atlas_slot->last_used = self->usage_counter++; atlas_slot->last_used = self->usage_counter++;
@ -194,15 +198,16 @@ static bool font_renderer_stb_unicode_create_atlas(
{ {
unsigned i, x, y; unsigned i, x, y;
stb_unicode_atlas_slot_t* slot = NULL; stb_unicode_atlas_slot_t* slot = NULL;
int max_glyph_size = (font_size < 0) ? -font_size : font_size;
self->max_glyph_width = font_size < 0 ? -font_size : font_size; self->max_glyph_width = max_glyph_size;
self->max_glyph_height = font_size < 0 ? -font_size : font_size; self->max_glyph_height = max_glyph_size;
self->atlas.width = (self->max_glyph_width + STB_UNICODE_ATLAS_PADDING) * STB_UNICODE_ATLAS_COLS; self->atlas.width = (self->max_glyph_width + STB_UNICODE_ATLAS_PADDING) * STB_UNICODE_ATLAS_COLS;
self->atlas.height = (self->max_glyph_height + STB_UNICODE_ATLAS_PADDING) * STB_UNICODE_ATLAS_ROWS; self->atlas.height = (self->max_glyph_height + STB_UNICODE_ATLAS_PADDING) * STB_UNICODE_ATLAS_ROWS;
self->atlas.buffer = (uint8_t*) self->atlas.buffer = (uint8_t*)calloc(
calloc(self->atlas.width * self->atlas.height, sizeof(uint8_t)); self->atlas.width * self->atlas.height, sizeof(uint8_t));
if (!self->atlas.buffer) if (!self->atlas.buffer)
return false; return false;