# HG changeset patch # User John Tsiombikas # Date 1397527839 -10800 # Node ID 838d473cf6ccff1c5d500e1cb6624251eb17821d # Parent 850335344428b9c3fe1dd0339f90d96c2afc2e33 - properly supported building of no-freetype version, separately installed as libdrawtext-noft.whatever - saving/loading glyphmaps now work correctly - added nofreetype program in examples, to illustrate how to use libdrawtext-noft with prebuilt glyphmaps (see tools/font2glyphmap) diff -r 850335344428 -r 838d473cf6cc Makefile.in --- a/Makefile.in Tue Apr 15 03:33:39 2014 +0300 +++ b/Makefile.in Tue Apr 15 05:10:39 2014 +0300 @@ -5,7 +5,6 @@ abi = 0 rev = 0 -name = libdrawtext lib_a = $(name).a ifeq ($(shell uname -s), Darwin) @@ -40,6 +39,9 @@ %.d: %.c @$(CPP) $(CFLAGS) -MM $< >$@ +.PHONY: cleanobj +cleanobj: + rm -f $(obj) .PHONY: clean clean: @@ -67,3 +69,23 @@ rm -f $(PREFIX)/lib/$(linkname) rm -f $(PREFIX)/lib/$(soname) rm -f $(PREFIX)/include/drawtext.h + + +.PHONY: both +both: + ./configure --disable-freetype + $(MAKE) cleanobj + $(MAKE) + ./configure --enable-freetype + $(MAKE) cleanobj + $(MAKE) + +.PHONY: both-install +both-install: + ./configure --disable-freetype + $(MAKE) cleanobj + $(MAKE) install + ./configure --enable-freetype + $(MAKE) cleanobj + $(MAKE) install + $(MAKE) cleanobj diff -r 850335344428 -r 838d473cf6cc configure --- a/configure Tue Apr 15 03:33:39 2014 +0300 +++ b/configure Tue Apr 15 05:10:39 2014 +0300 @@ -4,6 +4,7 @@ opt=false dbg=true use_ft2=true +name=libdrawtext while [ $# != 0 ]; do case $1 in @@ -24,24 +25,33 @@ ;; --enable-freetype) use_ft2=true + name=libdrawtext ;; --disable-freetype) use_ft2=false + name=libdrawtext-noft ;; esac shift done -echo 'Configuring libdrawtext...' +echo "installation prefix: $prefix" +$use_ft2 && echo 'use freetype: yes' || echo 'use freetype: no' +$opt && echo 'optimizations: yes' || echo 'optimizations: no' +$dbg && echo 'debug symbols: yes' || echo 'debug symbols: no' + +echo "Configuring ${name}..." echo "# do not modify this file manually, it's generated by the configure script" >Makefile echo "PREFIX = $prefix" >>Makefile $opt && echo '-O3' | xargs echo 'opt =' >>Makefile $dbg && echo '-g' | xargs echo 'dbg =' >>Makefile if $use_ft2; then + echo "name = $name" >>Makefile echo 'ft2_cflags = `pkg-config --cflags freetype2`' >>Makefile echo 'ft2_libs = `pkg-config --libs freetype2`' >>Makefile else + echo "name = $name" >>Makefile echo 'ft2_cflags = -DNO_FREETYPE' >>Makefile fi echo '# --- end of generated part, start of Makefile.in ---' >>Makefile diff -r 850335344428 -r 838d473cf6cc examples/nofreetype/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/nofreetype/Makefile Tue Apr 15 05:10:39 2014 +0300 @@ -0,0 +1,32 @@ +obj = simple-noft.o +bin = simple-noft + +CC = gcc +CFLAGS = -pedantic -Wall -g -I../../src -I/usr/local/include +LDFLAGS = -Wl,-rpath=. $(lib_so) $(libgl) + +font = serif.ttf + +ifeq ($(shell uname -s), Darwin) + libgl = -framework OpenGL -framework GLUT + lib_so = libdrawtext-noft.dylib +else + libgl = -lGL -lGLU -lglut + lib_so = libdrawtext-noft.so.0.0 + lib_soname = libdrawtext-noft.so.0 +endif + +$(bin): $(obj) $(lib_so) $(lib_soname) + $(CC) -o $@ $(obj) $(LDFLAGS) + +$(lib_so): ../../$(lib_so) + rm -f $@ + ln -s $< $@ + +$(lib_soname): ../../$(lib_so) + rm -f $@ + ln -s $< $@ + +.PHONY: clean +clean: + rm -f $(obj) $(bin) $(lib_so) diff -r 850335344428 -r 838d473cf6cc examples/nofreetype/serif_s24.glyphmap Binary file examples/nofreetype/serif_s24.glyphmap has changed diff -r 850335344428 -r 838d473cf6cc examples/nofreetype/simple-noft.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/nofreetype/simple-noft.c Tue Apr 15 05:10:39 2014 +0300 @@ -0,0 +1,92 @@ +/* Simple libdrawtext example without freetype. + */ +#include +#include + +#ifndef __APPLE__ +#include +#else +#include +#endif + +#include "drawtext.h" + +void disp(void); +void reshape(int x, int y); +void keyb(unsigned char key, int x, int y); + +struct dtx_font *font; + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitWindowSize(512, 384); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutCreateWindow("libdrawtext example: simple"); + + glutDisplayFunc(disp); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyb); + + if(!(font = dtx_open_font_glyphmap("serif_s24.glyphmap"))) { + fprintf(stderr, "failed to open font\n"); + return 1; + } + dtx_use_font(font, 24); + + glutMainLoop(); + return 0; +} + +const char *text = "Some sample text goes here.\n" + "Yada yada yada, more text...\n" + "foobar xyzzy\n"; + +void disp(void) +{ + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glPushMatrix(); + glTranslatef(-200, 150, 0); + glColor3f(1, 1, 1); + /* XXX call dtx_string to draw utf-8 text. + * any transformations and the current color apply + */ + dtx_string(text); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(-200, 50, 0); + glScalef(2, 0.7, 1); + glColor3f(0.6, 0.7, 1.0); + dtx_string(text); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(-80, -90, 0); + glRotatef(20, 0, 0, 1); + glColor3f(1.0, 0.7, 0.6); + dtx_string(text); + glPopMatrix(); + + glutSwapBuffers(); +} + +void reshape(int x, int y) +{ + glViewport(0, 0, x, y); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-x/2, x/2, -y/2, y/2, -1, 1); +} + +void keyb(unsigned char key, int x, int y) +{ + if(key == 27) { + exit(0); + } +} diff -r 850335344428 -r 838d473cf6cc src/drawtext.h --- a/src/drawtext.h Tue Apr 15 03:33:39 2014 +0300 +++ b/src/drawtext.h Tue Apr 15 05:10:39 2014 +0300 @@ -50,6 +50,11 @@ * nothing will be rendered. */ struct dtx_font *dtx_open_font(const char *fname, int sz); +/* open a font by loading a precompiled glyphmap (see: dtx_save_glyphmap) + * this works even when compiled without freetype support + */ +struct dtx_font *dtx_open_font_glyphmap(const char *fname); +/* close a font opened by either of the above */ void dtx_close_font(struct dtx_font *fnt); /* prepare an ASCII glyphmap for the specified font size */ @@ -89,6 +94,8 @@ int dtx_save_glyphmap(const char *fname, const struct dtx_glyphmap *gmap); int dtx_save_glyphmap_stream(FILE *fp, const struct dtx_glyphmap *gmap); +/* adds a glyphmap to a font */ +void dtx_add_glyphmap(struct dtx_font *fnt, struct dtx_glyphmap *gmap); /* ---- rendering ---- */ diff -r 850335344428 -r 838d473cf6cc src/font.c --- a/src/font.c Tue Apr 15 03:33:39 2014 +0300 +++ b/src/font.c Tue Apr 15 05:10:39 2014 +0300 @@ -68,11 +68,13 @@ FT_Done_FreeType(ft); } } +#endif /* USE_FREETYPE */ struct dtx_font *dtx_open_font(const char *fname, int sz) { - struct dtx_font *fnt; + struct dtx_font *fnt = 0; +#ifdef USE_FREETYPE init_freetype(); if(!(fnt = calloc(1, sizeof *fnt))) { @@ -93,15 +95,41 @@ dtx_use_font(fnt, sz); } } +#else + fprintf(stderr, "ignoring call to dtx_open_font: not compiled with freetype support!\n"); +#endif return fnt; } +struct dtx_font *dtx_open_font_glyphmap(const char *fname) +{ + struct dtx_font *fnt; + struct dtx_glyphmap *gmap; + + if(!(fnt = calloc(1, sizeof *fnt))) { + fperror("failed to allocate font structure"); + return 0; + } + + if(fname) { + if(!(gmap = dtx_load_glyphmap(fname))) { + free(fnt); + return 0; + } + + dtx_add_glyphmap(fnt, gmap); + } + return fnt; +} + void dtx_close_font(struct dtx_font *fnt) { if(!fnt) return; +#ifdef USE_FREETYPE FT_Done_Face(fnt->face); +#endif /* destroy the glyphmaps */ while(fnt->gmaps) { @@ -115,12 +143,16 @@ void dtx_prepare(struct dtx_font *fnt, int sz) { - dtx_get_font_glyphmap_range(fnt, sz, 0, 256); + if(!dtx_get_font_glyphmap_range(fnt, sz, 0, 256)) { + fprintf(stderr, "%s: failed (sz: %d, range: 0-255 [ascii])\n", __FUNCTION__, sz); + } } void dtx_prepare_range(struct dtx_font *fnt, int sz, int cstart, int cend) { - dtx_get_font_glyphmap_range(fnt, sz, cstart, cend); + if(!dtx_get_font_glyphmap_range(fnt, sz, cstart, cend)) { + fprintf(stderr, "%s: failed (sz: %d, range: %d-%d)\n", __FUNCTION__, sz, cstart, cend); + } } struct dtx_glyphmap *dtx_get_font_glyphmap(struct dtx_font *fnt, int sz, int code) @@ -168,8 +200,10 @@ struct dtx_glyphmap *dtx_create_glyphmap_range(struct dtx_font *fnt, int sz, int cstart, int cend) { + struct dtx_glyphmap *gmap = 0; + +#ifdef USE_FREETYPE FT_Face face = fnt->face; - struct dtx_glyphmap *gmap; int i, j; int gx, gy; int padding = 4; @@ -259,12 +293,11 @@ } /* add it to the glyphmaps list of the font */ - gmap->next = fnt->gmaps; - fnt->gmaps = gmap; + dtx_add_glyphmap(fnt, gmap); +#endif /* USE_FREETYPE */ return gmap; } -#endif /* USE_FREETYPE */ void dtx_free_glyphmap(struct dtx_glyphmap *gmap) { @@ -309,6 +342,7 @@ int hdr_lines = 0; struct dtx_glyphmap *gmap; struct glyph *glyphs = 0; + struct glyph *g; int min_code = INT_MAX; int max_code = INT_MIN; int i, max_pixval, num_pixels; @@ -317,6 +351,8 @@ fperror("failed to allocate glyphmap"); return 0; } + gmap->ptsize = -1; + gmap->line_advance = FLT_MIN; while(hdr_lines < 3) { char *line = buf; @@ -330,34 +366,47 @@ } if(line[0] == '#') { - struct glyph *g; int c, res; - float x, y, xsz, ysz; + float x, y, xsz, ysz, orig_x, orig_y, adv, line_adv; + int ptsize; - res = sscanf(line + 1, "%d: %fx%f+%f+%f\n", &c, &xsz, &ysz, &x, &y); - if(res != 5) { + if((res = sscanf(line + 1, " size: %d\n", &ptsize)) == 1) { + gmap->ptsize = ptsize; + + } else if((res = sscanf(line + 1, " advance: %f\n", &line_adv)) == 1) { + gmap->line_advance = line_adv; + + } else if((res = sscanf(line + 1, " %d: %fx%f+%f+%f o:%f,%f adv:%f\n", + &c, &xsz, &ysz, &x, &y, &orig_x, &orig_y, &adv)) == 8) { + if(!(g = malloc(sizeof *g))) { + fperror("failed to allocate glyph"); + goto err; + } + g->code = c; + g->x = x; + g->y = y; + g->width = xsz; + g->height = ysz; + g->orig_x = orig_x; + g->orig_y = orig_y; + g->advance = adv; + /* normalized coordinates will be precalculated after everything is loaded */ + + g->next = glyphs; + glyphs = g; + + if(c < min_code) { + min_code = c; + } + if(c > max_code) { + max_code = c; + } + + } else { fprintf(stderr, "%s: invalid glyph info line\n", __FUNCTION__); goto err; } - if(!(g = malloc(sizeof *g))) { - fperror("failed to allocate glyph"); - goto err; - } - g->code = c; - g->x = x; - g->y = y; - g->width = xsz; - g->height = ysz; - g->next = glyphs; - glyphs = g; - - if(c < min_code) { - min_code = c; - } - if(c > max_code) { - max_code = c; - } } else { switch(hdr_lines) { case 0: @@ -392,6 +441,21 @@ } } + if(gmap->ptsize == -1 || gmap->line_advance == FLT_MIN) { + fprintf(stderr, "%s: invalid glyphmap, insufficient information in ppm comments\n", __FUNCTION__); + goto err; + } + + /* precalculate normalized glyph coordinates */ + g = glyphs; + while(g) { + g->nx = g->x / gmap->xsz; + g->ny = g->y / gmap->ysz; + g->nwidth = g->width / gmap->xsz; + g->nheight = g->height / gmap->ysz; + g = g->next; + } + num_pixels = gmap->xsz * gmap->ysz; if(!(gmap->pixels = malloc(num_pixels))) { fperror("failed to allocate pixels"); @@ -456,8 +520,11 @@ struct glyph *g = gmap->glyphs; fprintf(fp, "P6\n%d %d\n", gmap->xsz, gmap->ysz); + fprintf(fp, "# size: %d\n", gmap->ptsize); + fprintf(fp, "# advance: %g\n", gmap->line_advance); for(i=0; icrange; i++) { - fprintf(fp, "# %d: %fx%f+%f+%f\n", g->code, g->width, g->height, g->x, g->y); + fprintf(fp, "# %d: %gx%g+%g+%g o:%g,%g adv:%g\n", g->code, g->width, g->height, g->x, g->y, + g->orig_x, g->orig_y, g->advance); g++; } fprintf(fp, "255\n"); @@ -472,6 +539,12 @@ return 0; } +void dtx_add_glyphmap(struct dtx_font *fnt, struct dtx_glyphmap *gmap) +{ + gmap->next = fnt->gmaps; + fnt->gmaps = gmap; +} + void dtx_use_font(struct dtx_font *fnt, int sz) { @@ -646,6 +719,7 @@ return gmap; } +#ifdef USE_FREETYPE static void calc_best_size(int total_width, int max_glyph_height, int padding, int pow2, int *imgw, int *imgh) { int xsz, ysz, num_rows; @@ -687,3 +761,4 @@ x = (x >> 16) | x; return x + 1; } +#endif