void text_renderer_font_destroy(text_renderer_p renderer, int32_t font_handle) { text_renderer_font_p font = hash_get_ptr(renderer->fonts, font_handle); if (!font) return; // TODO: mark all cells of this font as free FT_Done_Face(font->face); hash_destroy(font->cell_refs); hash_remove(renderer->fonts, font_handle); }
/* TODO: eww. */ void wpa_connect_to_network(STATE *state, char *interface, KEYVALUE *options) { WPA_INTERFACE iface; WPA_NETWORK *net; wpa_interface_init(&iface, interface); net = hash_get_ptr(iface.networks, get_element("ssid", options).str); if (net == 0) { net = wpa_add_network(&iface, options); } else { /* TODO: merge options instead of overwriting? */ net->options = options; wpa_configure_network(&iface, net); } if (net != iface.current_network){ wpa_enable_network(&iface, net); wpa_handle_messages(state, &iface); } wpa_interface_disconnect(&iface); }
void text_renderer_prepare(text_renderer_p renderer, int32_t font_handle, uint32_t range_start, uint32_t range_end) { text_renderer_font_p font = hash_get_ptr(renderer->fonts, font_handle); if (!font) return; glBindTexture(GL_TEXTURE_RECTANGLE, renderer->texture); // Lookup the size of our texture (needed by find_free_cell_or_revoke_unused_cell() for some checks) GLint texture_width = 0, texture_height = 0; glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &texture_width); glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &texture_height); GLint unpack_alignment = 0; glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); for(uint32_t code_point = range_start; code_point <= range_end; code_point++) { // Handle line break. if (code_point == '\n') { continue; } // Look if this glyph is present in the texture. If so this font has a cell reference // for this code point. text_renderer_cell_ref_p cell_ref = hash_get_ptr(font->cell_refs, code_point); // Glyph not rendered yet, try to render it if (!cell_ref) { uint32_t glyph_index = FT_Get_Char_Index(font->face, code_point); if (glyph_index == 0) continue; FT_Error error = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER); if (error) continue; // Look for a free cell to store the rendered glyph uint32_t gw = font->face->glyph->bitmap.width, gh = font->face->glyph->bitmap.rows; size_t line_idx = 0, cell_idx = 0; text_renderer_cell_p free_cell = find_free_cell_or_revoke_unused_cell(renderer, font, gw, gh, texture_width, texture_height, &line_idx, &cell_idx); if (free_cell == NULL) continue; free_cell->glyph_index = glyph_index; free_cell->hori_bearing_x = font->face->glyph->metrics.horiBearingX / 64; free_cell->hori_bearing_y = font->face->glyph->metrics.horiBearingY / 64; free_cell->hori_advance = font->face->glyph->metrics.horiAdvance / 64; /* printf("%3u %c: %2ux%2u %3u bytes, pitch %2u, pos %3u/%3u hori_bearing: %2d/%2d, adv: %2d\n", code_point, code_point, gw, gh, gw*gh, font->face->glyph->bitmap.pitch, free_cell->x, free_cell->y, free_cell->hori_bearing_x, free_cell->hori_bearing_y, free_cell->hori_advance); */ glPixelStorei(GL_UNPACK_ROW_LENGTH, font->face->glyph->bitmap.pitch); glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, free_cell->x, free_cell->y, gw, gh, GL_RED, GL_UNSIGNED_BYTE, font->face->glyph->bitmap.buffer); cell_ref = hash_put_ptr(font->cell_refs, code_point); cell_ref->line_idx = line_idx; cell_ref->cell_idx = cell_idx; } } glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glBindTexture(GL_TEXTURE_RECTANGLE, 0); }
size_t text_renderer_render(text_renderer_p renderer, int32_t font_handle, char* text, size_t x, size_t y, float* buffer_ptr, size_t buffer_size) { text_renderer_font_p font = hash_get_ptr(renderer->fonts, font_handle); if (!font) return 0; // The current position is the baseline of the text so start one line down // from the position. Otherwise we would render above it. size_t pos_x = x, pos_y = y + (font->face->size->metrics.height / 64); float* p = buffer_ptr; FT_UInt glyph_index = 0, prev_glyph_index = 0; glBindTexture(GL_TEXTURE_RECTANGLE, renderer->texture); // Lookup the size of our texture (needed by find_free_cell_or_revoke_unused_cell() for some checks) GLint texture_width = 0, texture_height = 0; glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &texture_width); glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &texture_height); GLint unpack_alignment = 0; glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); for(utf8_iterator_t it = utf8_first(text); it.code_point != 0; it = utf8_next(it)) { // Handle line break. if (it.code_point == '\n') { pos_y += font->face->size->metrics.height / 64; pos_x = x; // Don't do kerning at the next character after the line break. prev_glyph_index = 0; continue; } // Look if this glyph is present in the texture. If so this font has a cell reference // for this code point. text_renderer_cell_ref_p cell_ref = hash_get_ptr(font->cell_refs, it.code_point); // Glyph not rendered yet, try to render it if (!cell_ref) { glyph_index = FT_Get_Char_Index(font->face, it.code_point); if (glyph_index == 0) goto render_error_glyph; FT_Error error = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER); if (error) goto render_error_glyph; // Look for a free cell to store the rendered glyph uint32_t gw = font->face->glyph->bitmap.width, gh = font->face->glyph->bitmap.rows; size_t line_idx = 0, cell_idx = 0; text_renderer_cell_p free_cell = find_free_cell_or_revoke_unused_cell(renderer, font, gw, gh, texture_width, texture_height, &line_idx, &cell_idx); if (free_cell == NULL) goto render_error_glyph; free_cell->glyph_index = glyph_index; free_cell->hori_bearing_x = font->face->glyph->metrics.horiBearingX / 64; free_cell->hori_bearing_y = font->face->glyph->metrics.horiBearingY / 64; free_cell->hori_advance = font->face->glyph->metrics.horiAdvance / 64; /* printf("%c: %2ux%2u %2u bytes, pitch %u, x: %u, y: %u hori_bearing: %2u/%2u, adv: %2u\n", it.code_point, gw, gh, gw*gh, font->face->glyph->bitmap.pitch, free_cell->x, free_cell->y, free_cell->hori_bearing_x, free_cell->hori_bearing_y, free_cell->hori_advance); */ glPixelStorei(GL_UNPACK_ROW_LENGTH, font->face->glyph->bitmap.pitch); glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, free_cell->x, free_cell->y, gw, gh, GL_RED, GL_UNSIGNED_BYTE, font->face->glyph->bitmap.buffer); cell_ref = hash_put_ptr(font->cell_refs, it.code_point); cell_ref->line_idx = line_idx; cell_ref->cell_idx = cell_idx; } // Glyph rendered successfully, do kerning and generate vertices for it text_renderer_line_t line = array_elem(renderer->lines, text_renderer_line_t, cell_ref->line_idx); text_renderer_cell_t cell = array_elem(line.cells, text_renderer_cell_t, cell_ref->cell_idx); if (cell.glyph_index && prev_glyph_index) { FT_Vector delta; FT_Get_Kerning(font->face, prev_glyph_index, glyph_index, FT_KERNING_DEFAULT, &delta); pos_x += delta.x / 64; } // We have the texture coordinates of the glyph, generate the vertex buffer if ( (p + 6*4 - buffer_ptr) * sizeof(float) < buffer_size ) { float w = cell.width, h = line.height; float cx = pos_x + cell.hori_bearing_x; float cy = pos_y - cell.hori_bearing_y; float tl_x = cx + 0, tl_y = cy + 0, tl_u = cell.x, tl_v = cell.y; float tr_x = cx + w, tr_y = cy + 0, tr_u = cell.x + w, tr_v = cell.y; float bl_x = cx + 0, bl_y = cy + h, bl_u = cell.x, bl_v = cell.y + h; float br_x = cx + w, br_y = cy + h, br_u = cell.x + w, br_v = cell.y + h; *(p++) = tl_x; *(p++) = tl_y; *(p++) = tl_u; *(p++) = tl_v; *(p++) = tr_x; *(p++) = tr_y; *(p++) = tr_u; *(p++) = tr_v; *(p++) = bl_x; *(p++) = bl_y; *(p++) = bl_u; *(p++) = bl_v; *(p++) = tr_x; *(p++) = tr_y; *(p++) = tr_u; *(p++) = tr_v; *(p++) = br_x; *(p++) = br_y; *(p++) = br_u; *(p++) = br_v; *(p++) = bl_x; *(p++) = bl_y; *(p++) = bl_u; *(p++) = bl_v; pos_x += cell.hori_advance; } prev_glyph_index = glyph_index; continue; render_error_glyph: // For now just output nothing when we fail to render a glyph. // TODO: Figure out how to render a kind of error glyph. prev_glyph_index = glyph_index; continue; } glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glBindTexture(GL_TEXTURE_RECTANGLE, 0); return (p - buffer_ptr) * sizeof(float); }