diff --git a/win32_font.cpp b/win32_font.cpp index 97ef97b6..c9384621 100644 --- a/win32_font.cpp +++ b/win32_font.cpp @@ -9,6 +9,21 @@ // 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, @@ -44,20 +59,172 @@ win32_draw_font_load(Partition *part, HDC dc = CreateCompatibleDC(0); if (dc){ - // TODO(allen): Have to get metrics + 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; - HBITAMP bitmap = CreateCompatibleBitmap(dc, tex_width, tex_height); + 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); - // TODO(allen): pack each glyph into a texture - // and generate the equivalent data output by stb - // in the stbtt_packedchar array. + 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); } }