132001f49Smrg#include <stdio.h> 232001f49Smrg#include <stdlib.h> 332001f49Smrg#include <string.h> 432001f49Smrg 532001f49Smrg#include <ft2build.h> 632001f49Smrg#include FT_FREETYPE_H 732001f49Smrg 832001f49Smrg#include <VG/openvg.h> 932001f49Smrg 1032001f49Smrg#include "eglut.h" 1132001f49Smrg 1232001f49Smrg#define MAX_GLYPHS 256 1332001f49Smrgstatic struct glyph { 1432001f49Smrg VGboolean is_path; 1532001f49Smrg VGHandle handle; 1632001f49Smrg VGfloat origin[2]; 1732001f49Smrg VGfloat escapement[2]; 1832001f49Smrg} glyph_string[MAX_GLYPHS]; 1932001f49Smrg 2032001f49Smrgstatic int glyph_string_len; 2132001f49Smrgstatic VGHandle glyph_string_font = VG_INVALID_HANDLE; 2232001f49Smrg 2332001f49Smrgstatic VGint width, height; 2432001f49Smrg 2532001f49Smrgstatic VGint 2632001f49Smrgglyph_string_add_path(VGPath path, const VGfloat origin[2], VGfloat escapement[2]) 2732001f49Smrg{ 2832001f49Smrg struct glyph *g; 2932001f49Smrg 3032001f49Smrg if (glyph_string_len >= MAX_GLYPHS) 3132001f49Smrg return -1; 3232001f49Smrg 3332001f49Smrg#ifdef OPENVG_VERSION_1_1 3432001f49Smrg if (glyph_string_font != VG_INVALID_HANDLE) { 3532001f49Smrg vgSetGlyphToPath(glyph_string_font, glyph_string_len, 3632001f49Smrg path, VG_TRUE, origin, escapement); 3732001f49Smrg return glyph_string_len++; 3832001f49Smrg } 3932001f49Smrg#endif 4032001f49Smrg 4132001f49Smrg g = &glyph_string[glyph_string_len]; 4232001f49Smrg g->is_path = VG_TRUE; 4332001f49Smrg g->handle = (VGHandle) path; 4432001f49Smrg g->origin[0] = origin[0]; 4532001f49Smrg g->origin[1] = origin[1]; 4632001f49Smrg g->escapement[0] = escapement[0]; 4732001f49Smrg g->escapement[1] = escapement[1]; 4832001f49Smrg 4932001f49Smrg return glyph_string_len++; 5032001f49Smrg} 5132001f49Smrg 5232001f49Smrgstatic VGint 5332001f49Smrgglyph_string_add_image(VGImage image, const VGfloat origin[2], VGfloat escapement[2]) 5432001f49Smrg{ 5532001f49Smrg struct glyph *g; 5632001f49Smrg 5732001f49Smrg if (glyph_string_len >= MAX_GLYPHS) 5832001f49Smrg return -1; 5932001f49Smrg 6032001f49Smrg#ifdef OPENVG_VERSION_1_1 6132001f49Smrg if (glyph_string_font != VG_INVALID_HANDLE) { 6232001f49Smrg vgSetGlyphToImage(glyph_string_font, glyph_string_len, 6332001f49Smrg image, origin, escapement); 6432001f49Smrg return glyph_string_len++; 6532001f49Smrg } 6632001f49Smrg#endif 6732001f49Smrg 6832001f49Smrg g = &glyph_string[glyph_string_len]; 6932001f49Smrg g->is_path = VG_FALSE; 7032001f49Smrg g->handle = (VGHandle) image; 7132001f49Smrg g->origin[0] = origin[0]; 7232001f49Smrg g->origin[1] = origin[1]; 7332001f49Smrg g->escapement[0] = escapement[0]; 7432001f49Smrg g->escapement[1] = escapement[1]; 7532001f49Smrg 7632001f49Smrg return glyph_string_len++; 7732001f49Smrg} 7832001f49Smrg 7932001f49Smrgstatic void 8032001f49Smrgglyph_string_draw(VGfloat x, VGfloat y) 8132001f49Smrg{ 8232001f49Smrg VGfloat pen[2]; 8332001f49Smrg int i; 8432001f49Smrg 8532001f49Smrg#ifdef OPENVG_VERSION_1_1 8632001f49Smrg if (glyph_string_font != VG_INVALID_HANDLE) { 8732001f49Smrg VGuint indices[MAX_GLYPHS]; 8832001f49Smrg 8932001f49Smrg for (i = 0; i < glyph_string_len; i++) 9032001f49Smrg indices[i] = i; 9132001f49Smrg 9232001f49Smrg pen[0] = x; 9332001f49Smrg pen[1] = y; 9432001f49Smrg vgSetfv(VG_GLYPH_ORIGIN, 2, pen); 9532001f49Smrg vgDrawGlyphs(glyph_string_font, glyph_string_len, indices, 9632001f49Smrg NULL, NULL, VG_FILL_PATH, VG_TRUE); 9732001f49Smrg 9832001f49Smrg return; 9932001f49Smrg } 10032001f49Smrg#endif 10132001f49Smrg 10232001f49Smrg pen[0] = (VGint) (x + 0.5f); 10332001f49Smrg pen[1] = (VGint) (y + 0.5f); 10432001f49Smrg 10532001f49Smrg for (i = 0; i < glyph_string_len; i++) { 10632001f49Smrg const struct glyph *g = &glyph_string[i]; 10732001f49Smrg 10832001f49Smrg if (g->handle == VG_INVALID_HANDLE) 10932001f49Smrg continue; 11032001f49Smrg 11132001f49Smrg vgSeti(VG_MATRIX_MODE, (glyph_string[i].is_path) ? 11232001f49Smrg VG_MATRIX_PATH_USER_TO_SURFACE : VG_MATRIX_IMAGE_USER_TO_SURFACE); 11332001f49Smrg vgLoadIdentity(); 11432001f49Smrg vgTranslate(pen[0] - (VGint) g->origin[0], pen[1] - (VGint) g->origin[1]); 11532001f49Smrg 11632001f49Smrg if (glyph_string[i].is_path) 11732001f49Smrg vgDrawPath((VGPath) glyph_string[i].handle, VG_FILL_PATH); 11832001f49Smrg else 11932001f49Smrg vgDrawImage((VGImage) glyph_string[i].handle); 12032001f49Smrg 12132001f49Smrg pen[0] += (VGint) (g->escapement[0] + 0.5f); 12232001f49Smrg pen[1] += (VGint) (g->escapement[1] + 0.5f); 12332001f49Smrg } 12432001f49Smrg} 12532001f49Smrg 12632001f49Smrgstatic int 12732001f49Smrgpath_append(VGPath path, VGubyte segment, const FT_Vector **vectors) 12832001f49Smrg{ 12932001f49Smrg VGfloat coords[6]; 13032001f49Smrg int i, num_vectors; 13132001f49Smrg 13232001f49Smrg switch (segment) { 13332001f49Smrg case VG_MOVE_TO: 13432001f49Smrg case VG_LINE_TO: 13532001f49Smrg num_vectors = 1; 13632001f49Smrg break; 13732001f49Smrg case VG_QUAD_TO: 13832001f49Smrg num_vectors = 2; 13932001f49Smrg break; 14032001f49Smrg case VG_CUBIC_TO: 14132001f49Smrg num_vectors = 3; 14232001f49Smrg break; 14332001f49Smrg default: 14432001f49Smrg return -1; 14532001f49Smrg break; 14632001f49Smrg } 14732001f49Smrg 14832001f49Smrg for (i = 0; i < num_vectors; i++) { 14932001f49Smrg coords[2 * i + 0] = (float) vectors[i]->x / 64.0f; 15032001f49Smrg coords[2 * i + 1] = (float) vectors[i]->y / 64.0f; 15132001f49Smrg } 15232001f49Smrg 15332001f49Smrg vgAppendPathData(path, 1, &segment, (const void *) coords); 15432001f49Smrg 15532001f49Smrg return 0; 15632001f49Smrg} 15732001f49Smrg 15832001f49Smrgstatic int 15932001f49Smrgdecompose_move_to(const FT_Vector *to, void *user) 16032001f49Smrg{ 16132001f49Smrg VGPath path = (VGPath) (long) user; 16232001f49Smrg 16332001f49Smrg return path_append(path, VG_MOVE_TO, &to); 16432001f49Smrg} 16532001f49Smrg 16632001f49Smrgstatic int 16732001f49Smrgdecompose_line_to(const FT_Vector *to, void *user) 16832001f49Smrg{ 16932001f49Smrg VGPath path = (VGPath) (long) user; 17032001f49Smrg 17132001f49Smrg return path_append(path, VG_LINE_TO, &to); 17232001f49Smrg} 17332001f49Smrg 17432001f49Smrgstatic int 17532001f49Smrgdecompose_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) 17632001f49Smrg{ 17732001f49Smrg VGPath path = (VGPath) (long) user; 17832001f49Smrg const FT_Vector *vectors[2] = { control, to }; 17932001f49Smrg 18032001f49Smrg return path_append(path, VG_QUAD_TO, vectors); 18132001f49Smrg} 18232001f49Smrg 18332001f49Smrgstatic int 18432001f49Smrgdecompose_cubic_to(const FT_Vector *control1, const FT_Vector *control2, 18532001f49Smrg const FT_Vector *to, void *user) 18632001f49Smrg{ 18732001f49Smrg VGPath path = (VGPath) (long) user; 18832001f49Smrg const FT_Vector *vectors[3] = { control1, control2, to }; 18932001f49Smrg 19032001f49Smrg return path_append(path, VG_CUBIC_TO, vectors); 19132001f49Smrg} 19232001f49Smrg 19332001f49Smrgstatic VGHandle 19432001f49Smrgconvert_outline_glyph(FT_GlyphSlot glyph) 19532001f49Smrg{ 19632001f49Smrg FT_Outline_Funcs funcs = { 19732001f49Smrg decompose_move_to, 19832001f49Smrg decompose_line_to, 19932001f49Smrg decompose_conic_to, 20032001f49Smrg decompose_cubic_to, 20132001f49Smrg 0, 0 20232001f49Smrg }; 20332001f49Smrg VGPath path; 20432001f49Smrg 20532001f49Smrg path = vgCreatePath(VG_PATH_FORMAT_STANDARD, 20632001f49Smrg VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, glyph->outline.n_points, 20732001f49Smrg VG_PATH_CAPABILITY_ALL); 20832001f49Smrg 20932001f49Smrg if (FT_Outline_Decompose(&glyph->outline, &funcs, (void *) (long) path)) { 21032001f49Smrg vgDestroyPath(path); 21132001f49Smrg path = VG_INVALID_HANDLE; 21232001f49Smrg } 21332001f49Smrg 21432001f49Smrg return (VGHandle) path; 21532001f49Smrg} 21632001f49Smrg 21732001f49Smrgstatic VGHandle 21832001f49Smrgconvert_bitmap_glyph(FT_GlyphSlot glyph) 21932001f49Smrg{ 22032001f49Smrg VGImage image; 22132001f49Smrg VGint width, height, stride; 22232001f49Smrg unsigned char *data; 22332001f49Smrg int i, j; 22432001f49Smrg 22532001f49Smrg switch (glyph->bitmap.pixel_mode) { 22632001f49Smrg case FT_PIXEL_MODE_MONO: 22732001f49Smrg case FT_PIXEL_MODE_GRAY: 22832001f49Smrg break; 22932001f49Smrg default: 23032001f49Smrg return VG_INVALID_HANDLE; 23132001f49Smrg break; 23232001f49Smrg } 23332001f49Smrg 23432001f49Smrg data = glyph->bitmap.buffer; 23532001f49Smrg width = glyph->bitmap.width; 23632001f49Smrg height = glyph->bitmap.rows; 23732001f49Smrg stride = glyph->bitmap.pitch; 23832001f49Smrg 23932001f49Smrg /* mono to gray, and flip if needed */ 24032001f49Smrg if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { 24132001f49Smrg data = malloc(width * height); 24232001f49Smrg if (!data) 24332001f49Smrg return VG_INVALID_HANDLE; 24432001f49Smrg 24532001f49Smrg for (i = 0; i < height; i++) { 24632001f49Smrg char *dst = &data[width * i]; 24732001f49Smrg const unsigned char *src; 24832001f49Smrg 24932001f49Smrg if (stride > 0) 25032001f49Smrg src = glyph->bitmap.buffer + stride * (height - i - 1); 25132001f49Smrg else 25232001f49Smrg src = glyph->bitmap.buffer - stride * i; 25332001f49Smrg 25432001f49Smrg for (j = 0; j < width; j++) { 25532001f49Smrg if (src[j / 8] & (1 << (7 - (j % 8)))) 25632001f49Smrg dst[j] = 0xff; 25732001f49Smrg else 25832001f49Smrg dst[j] = 0x0; 25932001f49Smrg } 26032001f49Smrg } 26132001f49Smrg stride = -width; 26232001f49Smrg } 26332001f49Smrg 26432001f49Smrg image = vgCreateImage(VG_A_8, width, height, 26532001f49Smrg VG_IMAGE_QUALITY_NONANTIALIASED); 26632001f49Smrg 26732001f49Smrg if (stride < 0) { 26832001f49Smrg stride = -stride; 26932001f49Smrg vgImageSubData(image, data, stride, VG_A_8, 27032001f49Smrg 0, 0, width, height); 27132001f49Smrg } 27232001f49Smrg else { 27332001f49Smrg /* flip vertically */ 27432001f49Smrg for (i = 0; i < height; i++) { 27532001f49Smrg const char *row = data + stride * i; 27632001f49Smrg 27732001f49Smrg vgImageSubData(image, row, stride, VG_A_8, 27832001f49Smrg 0, height - i - 1, width, 1); 27932001f49Smrg } 28032001f49Smrg } 28132001f49Smrg 28232001f49Smrg if (data != glyph->bitmap.buffer) 28332001f49Smrg free(data); 28432001f49Smrg 28532001f49Smrg return (VGHandle) image; 28632001f49Smrg} 28732001f49Smrg 28832001f49Smrgstatic void 28932001f49Smrgglyph_string_init(const char *font, int size, const char *str) 29032001f49Smrg{ 29132001f49Smrg FT_Library lib = NULL; 29232001f49Smrg FT_Face face = NULL; 29332001f49Smrg int i; 29432001f49Smrg 29532001f49Smrg if (FT_Init_FreeType(&lib)) { 29632001f49Smrg printf("failed to initialize freetype\n"); 29732001f49Smrg goto fail; 29832001f49Smrg } 29932001f49Smrg 30032001f49Smrg if (FT_New_Face(lib, font, 0, &face)) { 30132001f49Smrg printf("failed to load %s\n", glyph_string); 30232001f49Smrg goto fail; 30332001f49Smrg } 30432001f49Smrg 30532001f49Smrg if (FT_Select_Charmap(face, FT_ENCODING_UNICODE)) { 30632001f49Smrg printf("failed to select an unicode charmap\n"); 30732001f49Smrg goto fail; 30832001f49Smrg } 30932001f49Smrg 31032001f49Smrg if (FT_Set_Pixel_Sizes(face, size, size)) 31132001f49Smrg printf("failed to set pixel sizes\n"); 31232001f49Smrg 31332001f49Smrg for (i = 0; str[i]; i++) { 31432001f49Smrg VGfloat origin[2], escapement[2]; 31532001f49Smrg VGHandle handle; 31632001f49Smrg 31732001f49Smrg /* 31832001f49Smrg * if a character appears more than once, it will be loaded and converted 31932001f49Smrg * again... 32032001f49Smrg */ 32132001f49Smrg if (FT_Load_Char(face, str[i], FT_LOAD_DEFAULT)) { 32232001f49Smrg printf("failed to load glyph '%c'\n", str[i]); 32332001f49Smrg goto fail; 32432001f49Smrg } 32532001f49Smrg 32632001f49Smrg escapement[0] = (VGfloat) face->glyph->advance.x / 64.0f; 32732001f49Smrg escapement[1] = (VGfloat) face->glyph->advance.y / 64.0f; 32832001f49Smrg 32932001f49Smrg switch (face->glyph->format) { 33032001f49Smrg case FT_GLYPH_FORMAT_OUTLINE: 33132001f49Smrg handle = convert_outline_glyph(face->glyph); 33232001f49Smrg origin[0] = 0.0f; 33332001f49Smrg origin[1] = 0.0f; 33432001f49Smrg glyph_string_add_path((VGPath) handle, origin, escapement); 33532001f49Smrg break; 33632001f49Smrg case FT_GLYPH_FORMAT_BITMAP: 33732001f49Smrg handle = convert_bitmap_glyph(face->glyph); 33832001f49Smrg origin[0] = (VGfloat) (-face->glyph->bitmap_left); 33932001f49Smrg origin[1] = (VGfloat) 34032001f49Smrg (face->glyph->bitmap.rows - face->glyph->bitmap_top); 34132001f49Smrg glyph_string_add_image((VGImage) handle, origin, escapement); 34232001f49Smrg break; 34332001f49Smrg default: 34432001f49Smrg printf("unsupported format for glyph '%c'\n", str[i]); 34532001f49Smrg break; 34632001f49Smrg } 34732001f49Smrg if (handle == VG_INVALID_HANDLE) 34832001f49Smrg printf("failed to add glyph '%c'\n", str[i]); 34932001f49Smrg } 35032001f49Smrg 35132001f49Smrgfail: 35232001f49Smrg if (face) 35332001f49Smrg FT_Done_Face(face); 35432001f49Smrg if (lib) 35532001f49Smrg FT_Done_FreeType(lib); 35632001f49Smrg} 35732001f49Smrg 35832001f49Smrgstatic void 35932001f49Smrgdisplay(void) 36032001f49Smrg{ 36132001f49Smrg vgClear(0, 0, width, height); 36232001f49Smrg glyph_string_draw(10.0, 10.0); 36332001f49Smrg} 36432001f49Smrg 36532001f49Smrg 36632001f49Smrg/* new window size or exposure */ 36732001f49Smrgstatic void 36832001f49Smrgreshape(int w, int h) 36932001f49Smrg{ 37032001f49Smrg width = w; 37132001f49Smrg height = h; 37232001f49Smrg} 37332001f49Smrg 37432001f49Smrg 37532001f49Smrgstatic void 37632001f49Smrginit(void) 37732001f49Smrg{ 37832001f49Smrg VGPaint paint; 37932001f49Smrg float clear_color[4] = { 0.9, 0.9, 0.9, 1.0 }; 38032001f49Smrg 38132001f49Smrg vgSetfv(VG_CLEAR_COLOR, 4, clear_color); 38232001f49Smrg vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL); 38332001f49Smrg 38432001f49Smrg paint = vgCreatePaint(); 38532001f49Smrg vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); 38632001f49Smrg vgSetColor(paint, 0x660000ff); 38732001f49Smrg vgSetPaint(paint, VG_FILL_PATH); 38832001f49Smrg 38932001f49Smrg#ifdef OPENVG_VERSION_1_1 39032001f49Smrg { 39132001f49Smrg const char *ver = (const char *) vgGetString(VG_VERSION); 39232001f49Smrg 39332001f49Smrg if (!strcmp(ver, "1.1")) 39432001f49Smrg glyph_string_font = vgCreateFont(0); 39532001f49Smrg } 39632001f49Smrg#endif 39732001f49Smrg 39832001f49Smrg if (glyph_string_font != VG_INVALID_HANDLE) 39932001f49Smrg printf("using OpenVG text support\n"); 40032001f49Smrg} 40132001f49Smrg 40232001f49Smrgint 40332001f49Smrgmain(int argc, char *argv[]) 40432001f49Smrg{ 40532001f49Smrg const char *font, *str; 40632001f49Smrg 40732001f49Smrg if (argc < 2) { 40832001f49Smrg printf("Usage: %s <path-to-font> [<string>]\n", argv[0]); 40932001f49Smrg return 1; 41032001f49Smrg } 41132001f49Smrg 41232001f49Smrg font = argv[1]; 41332001f49Smrg str = (argc > 2) ? argv[2] : "Hello World"; 41432001f49Smrg 41532001f49Smrg eglutInitWindowSize(480, 80); 41632001f49Smrg eglutInitAPIMask(EGLUT_OPENVG_BIT); 41732001f49Smrg eglutInit(argc, argv); 41832001f49Smrg 41932001f49Smrg eglutCreateWindow("Text Example"); 42032001f49Smrg 42132001f49Smrg eglutReshapeFunc(reshape); 42232001f49Smrg eglutDisplayFunc(display); 42332001f49Smrg 42432001f49Smrg init(); 42532001f49Smrg glyph_string_init(font, 64, str); 42632001f49Smrg 42732001f49Smrg eglutMainLoop(); 42832001f49Smrg 42932001f49Smrg return 0; 43032001f49Smrg} 431