240 lines
12 KiB
C++
240 lines
12 KiB
C++
/*
|
|
* Mr. 4th Dimention - Allen Webster
|
|
*
|
|
* 12.12.2014
|
|
*
|
|
* Win32 font rendering for nicer fonts
|
|
*
|
|
*/
|
|
|
|
// TOP
|
|
|
|
struct Glyph_Bitmap{
|
|
HBITMAP bitmap_handle;
|
|
char *pixels;
|
|
};
|
|
|
|
void
|
|
win32_get_box(HDC dc, TCHAR character, int *x0, int *y0, int *x1, int *y1){
|
|
SIZE size;
|
|
GetTextExtentPoint32A(dc, &character, 1, &size);
|
|
*x0 = 0;
|
|
*y0 = 0;
|
|
*x1 = size.cx;
|
|
*y1 = size.cy;
|
|
}
|
|
|
|
internal i32
|
|
win32_draw_font_load(Partition *part,
|
|
Render_Font *font_out,
|
|
char *filename_untranslated,
|
|
i32 pt_size,
|
|
i32 tab_width,
|
|
i32 oversample,
|
|
b32 store_texture){
|
|
|
|
char space_[1024];
|
|
String filename = make_fixed_width_string(space_);
|
|
b32 translate_success = sysshared_to_binary_path(&filename, filename_untranslated);
|
|
if (!translate_success) return 0;
|
|
|
|
i32 result = 0;
|
|
|
|
AddFontResourceEx(filename.str, FR_PRIVATE, 0);
|
|
|
|
HFONT font_handle =
|
|
CreateFontA(pt_size, 0, 0, 0,
|
|
FW_NORMAL, // WEIGHT
|
|
FALSE, // ITALICS
|
|
FALSE, // UNDERLINE
|
|
FALSE, // STRIKE-OUT
|
|
ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS,
|
|
ANTIALIASED_QUALITY,
|
|
DEFAULT_PITCH|FF_DONTCARE,
|
|
filename.str);
|
|
|
|
if (font_handle){
|
|
HDC dc = CreateCompatibleDC(0);
|
|
|
|
if (dc){
|
|
TEXTMETRIC metrics;
|
|
GetTextMetrics(dc, &metrics);
|
|
font_out->height = metrics.tmHeight + metrics.tmExternalLeading;
|
|
font_out->ascent = metrics.tmAscent;
|
|
font_out->descent = -metrics.tmDescent;
|
|
font_out->line_skip = metrics.tmExternalLeading;
|
|
font_out->advance = metrics.tmMaxCharWidth;
|
|
|
|
result = 1;
|
|
if (store_texture){
|
|
Temp_Memory temp = begin_temp_memory(part);
|
|
|
|
i32 tex_width = pt_size*16*oversample;
|
|
i32 tex_height = pt_size*16*oversample;
|
|
|
|
Glyph_Bitmap glyph_bitmap;
|
|
glyph_bitmap.bitmap_handle = CreateCompatibleBitmap(dc, tex_width, tex_height);
|
|
glyph_bitmap.pixels = push_array(part, char, tex_width*tex_height);
|
|
|
|
SelectObject(dc, glyph_bitmap.bitmap_handle);
|
|
SelectObject(dc, font_handle);
|
|
|
|
SetBkColor(dc, RGB(0, 0, 0));
|
|
|
|
stbtt_pack_context context = {0};
|
|
stbtt_PackBegin(&context, (unsigned char*)glyph_bitmap.pixels, tex_width, tex_height, 0, 1, part);
|
|
|
|
{
|
|
stbtt_pack_context *spc = &context;
|
|
int first_unicode_char_in_range = 0;
|
|
int num_chars_in_range = 128;
|
|
stbtt_packedchar *chardata_for_range = font_out->chardata;
|
|
|
|
{
|
|
stbtt_pack_range range;
|
|
range.first_unicode_char_in_range = first_unicode_char_in_range;
|
|
range.num_chars_in_range = num_chars_in_range;
|
|
range.chardata_for_range = chardata_for_range;
|
|
|
|
{
|
|
stbtt_pack_range *ranges = ⦥
|
|
int num_ranges = 1;
|
|
|
|
{
|
|
float recip_h = 1.0f / spc->h_oversample;
|
|
float recip_v = 1.0f / spc->v_oversample;
|
|
float sub_x = stbtt__oversample_shift(spc->h_oversample);
|
|
float sub_y = stbtt__oversample_shift(spc->v_oversample);
|
|
int i,j,k,n, return_value = 1;
|
|
stbrp_context *context = (stbrp_context *) spc->pack_info;
|
|
stbrp_rect *rects;
|
|
|
|
// flag all characters as NOT packed
|
|
for (i=0; i < num_ranges; ++i)
|
|
for (j=0; j < ranges[i].num_chars_in_range; ++j)
|
|
ranges[i].chardata_for_range[j].x0 =
|
|
ranges[i].chardata_for_range[j].y0 =
|
|
ranges[i].chardata_for_range[j].x1 =
|
|
ranges[i].chardata_for_range[j].y1 = 0;
|
|
|
|
n = 0;
|
|
for (i=0; i < num_ranges; ++i)
|
|
n += ranges[i].num_chars_in_range;
|
|
|
|
rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
|
|
if (rects == NULL)
|
|
return 0;
|
|
|
|
k=0;
|
|
for (i=0; i < num_ranges; ++i) {
|
|
for (j=0; j < ranges[i].num_chars_in_range; ++j) {
|
|
int x0,y0,x1,y1;
|
|
|
|
TCHAR character = (TCHAR)(ranges[i].first_unicode_char_in_range + j);
|
|
win32_get_box(dc, character, &x0, &y0, &x1, &y1);
|
|
|
|
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
|
|
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
|
|
++k;
|
|
}
|
|
}
|
|
|
|
stbrp_pack_rects(context, rects, k);
|
|
|
|
k = 0;
|
|
for (i=0; i < num_ranges; ++i) {
|
|
for (j=0; j < ranges[i].num_chars_in_range; ++j) {
|
|
stbrp_rect *r = &rects[k];
|
|
if (r->was_packed) {
|
|
stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
|
|
int advance, x0,y0,x1,y1;
|
|
int glyph = ranges[i].first_unicode_char_in_range + j;
|
|
stbrp_coord pad = (stbrp_coord) spc->padding;
|
|
|
|
GetCharWidth32W(dc, glyph, glyph, &advance);
|
|
|
|
TCHAR character = (TCHAR)(ranges[i].first_unicode_char_in_range + j);
|
|
win32_get_box(dc, character, &x0, &y0, &x1, &y1);
|
|
|
|
// pad on left and top
|
|
r->x += pad;
|
|
r->y += pad;
|
|
r->w -= pad;
|
|
r->h -= pad;
|
|
|
|
SetTextColor(dc, RGB(255, 255, 255));
|
|
TextOutA(dc, r->x, r->y, &character, 1);
|
|
|
|
if (spc->h_oversample > 1)
|
|
stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
|
|
r->w, r->h, spc->stride_in_bytes,
|
|
spc->h_oversample);
|
|
|
|
if (spc->v_oversample > 1)
|
|
stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
|
|
r->w, r->h, spc->stride_in_bytes,
|
|
spc->v_oversample);
|
|
|
|
bc->x0 = (stbtt_int16) r->x;
|
|
bc->y0 = (stbtt_int16) r->y;
|
|
bc->x1 = (stbtt_int16) (r->x + r->w);
|
|
bc->y1 = (stbtt_int16) (r->y + r->h);
|
|
bc->xadvance = (float) advance;
|
|
bc->xoff = (float) x0 * recip_h + sub_x;
|
|
bc->yoff = (float) y0 * recip_v + sub_y;
|
|
bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
|
|
bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
|
|
} else {
|
|
return_value = 0; // if any fail, report failure
|
|
}
|
|
|
|
++k;
|
|
}
|
|
}
|
|
|
|
STBTT_free(rects, spc->user_allocator_context);
|
|
|
|
result = return_value;
|
|
|
|
if (return_value){
|
|
GLuint font_tex;
|
|
glGenTextures(1, &font_tex);
|
|
glBindTexture(GL_TEXTURE_2D, font_tex);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, glyph_bitmap.pixels);
|
|
|
|
font_out->tex = font_tex;
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
font_out->chardata['\r'] = font_out->chardata[' '];
|
|
font_out->chardata['\n'] = font_out->chardata[' '];
|
|
font_out->chardata['\t'] = font_out->chardata[' '];
|
|
font_out->chardata['\t'].xadvance *= tab_width;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
stbtt_PackEnd(&context);
|
|
|
|
end_temp_memory(temp);
|
|
}
|
|
}
|
|
|
|
DeleteObject(font_handle);
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
// BOTTOM
|
|
|
|
|