/* * 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