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