libdrawtext

changeset 74:838d473cf6cc

- 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)
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 15 Apr 2014 05:10:39 +0300
parents 850335344428
children 47f2f73026fc
files Makefile.in configure examples/nofreetype/Makefile examples/nofreetype/serif_s24.glyphmap examples/nofreetype/simple-noft.c src/drawtext.h src/font.c
diffstat 7 files changed, 270 insertions(+), 32 deletions(-) [+]
line diff
     1.1 --- a/Makefile.in	Tue Apr 15 03:33:39 2014 +0300
     1.2 +++ b/Makefile.in	Tue Apr 15 05:10:39 2014 +0300
     1.3 @@ -5,7 +5,6 @@
     1.4  abi = 0
     1.5  rev = 0
     1.6  
     1.7 -name = libdrawtext
     1.8  lib_a = $(name).a
     1.9  
    1.10  ifeq ($(shell uname -s), Darwin)
    1.11 @@ -40,6 +39,9 @@
    1.12  %.d: %.c
    1.13  	@$(CPP) $(CFLAGS) -MM $< >$@
    1.14  
    1.15 +.PHONY: cleanobj
    1.16 +cleanobj:
    1.17 +	rm -f $(obj)
    1.18  
    1.19  .PHONY: clean
    1.20  clean:
    1.21 @@ -67,3 +69,23 @@
    1.22  	rm -f $(PREFIX)/lib/$(linkname)
    1.23  	rm -f $(PREFIX)/lib/$(soname)
    1.24  	rm -f $(PREFIX)/include/drawtext.h
    1.25 +
    1.26 +
    1.27 +.PHONY: both
    1.28 +both:
    1.29 +	./configure --disable-freetype
    1.30 +	$(MAKE) cleanobj
    1.31 +	$(MAKE)
    1.32 +	./configure --enable-freetype
    1.33 +	$(MAKE) cleanobj
    1.34 +	$(MAKE)
    1.35 +
    1.36 +.PHONY: both-install
    1.37 +both-install:
    1.38 +	./configure --disable-freetype
    1.39 +	$(MAKE) cleanobj
    1.40 +	$(MAKE) install
    1.41 +	./configure --enable-freetype
    1.42 +	$(MAKE) cleanobj
    1.43 +	$(MAKE) install
    1.44 +	$(MAKE) cleanobj
     2.1 --- a/configure	Tue Apr 15 03:33:39 2014 +0300
     2.2 +++ b/configure	Tue Apr 15 05:10:39 2014 +0300
     2.3 @@ -4,6 +4,7 @@
     2.4  opt=false
     2.5  dbg=true
     2.6  use_ft2=true
     2.7 +name=libdrawtext
     2.8  
     2.9  while [ $# != 0 ]; do
    2.10  	case $1 in
    2.11 @@ -24,24 +25,33 @@
    2.12  		;;
    2.13  	--enable-freetype)
    2.14  		use_ft2=true
    2.15 +		name=libdrawtext
    2.16  		;;
    2.17  	--disable-freetype)
    2.18  		use_ft2=false
    2.19 +		name=libdrawtext-noft
    2.20  		;;
    2.21  	esac
    2.22  	shift
    2.23  done
    2.24  
    2.25 -echo 'Configuring libdrawtext...'
    2.26 +echo "installation prefix: $prefix"
    2.27 +$use_ft2 && echo 'use freetype: yes' || echo 'use freetype: no'
    2.28 +$opt && echo 'optimizations: yes' || echo 'optimizations: no'
    2.29 +$dbg && echo 'debug symbols: yes' || echo 'debug symbols: no'
    2.30 +
    2.31 +echo "Configuring ${name}..."
    2.32  
    2.33  echo "# do not modify this file manually, it's generated by the configure script" >Makefile
    2.34  echo "PREFIX = $prefix" >>Makefile
    2.35  $opt && echo '-O3' | xargs echo 'opt =' >>Makefile
    2.36  $dbg && echo '-g' | xargs echo 'dbg =' >>Makefile
    2.37  if $use_ft2; then
    2.38 +	echo "name = $name" >>Makefile
    2.39  	echo 'ft2_cflags = `pkg-config --cflags freetype2`' >>Makefile
    2.40  	echo 'ft2_libs = `pkg-config --libs freetype2`' >>Makefile
    2.41  else
    2.42 +	echo "name = $name" >>Makefile
    2.43  	echo 'ft2_cflags = -DNO_FREETYPE' >>Makefile
    2.44  fi
    2.45  echo '# --- end of generated part, start of Makefile.in ---' >>Makefile
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/examples/nofreetype/Makefile	Tue Apr 15 05:10:39 2014 +0300
     3.3 @@ -0,0 +1,32 @@
     3.4 +obj = simple-noft.o
     3.5 +bin = simple-noft
     3.6 +
     3.7 +CC = gcc
     3.8 +CFLAGS = -pedantic -Wall -g -I../../src -I/usr/local/include
     3.9 +LDFLAGS = -Wl,-rpath=. $(lib_so) $(libgl)
    3.10 +
    3.11 +font = serif.ttf
    3.12 +
    3.13 +ifeq ($(shell uname -s), Darwin)
    3.14 +	libgl = -framework OpenGL -framework GLUT
    3.15 +	lib_so = libdrawtext-noft.dylib
    3.16 +else
    3.17 +	libgl = -lGL -lGLU -lglut
    3.18 +	lib_so = libdrawtext-noft.so.0.0
    3.19 +	lib_soname = libdrawtext-noft.so.0
    3.20 +endif
    3.21 +
    3.22 +$(bin): $(obj) $(lib_so) $(lib_soname)
    3.23 +	$(CC) -o $@ $(obj) $(LDFLAGS)
    3.24 +
    3.25 +$(lib_so): ../../$(lib_so)
    3.26 +	rm -f $@
    3.27 +	ln -s $< $@
    3.28 +
    3.29 +$(lib_soname): ../../$(lib_so)
    3.30 +	rm -f $@
    3.31 +	ln -s $< $@
    3.32 +
    3.33 +.PHONY: clean
    3.34 +clean:
    3.35 +	rm -f $(obj) $(bin) $(lib_so)
     4.1 Binary file examples/nofreetype/serif_s24.glyphmap has changed
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/examples/nofreetype/simple-noft.c	Tue Apr 15 05:10:39 2014 +0300
     5.3 @@ -0,0 +1,92 @@
     5.4 +/* Simple libdrawtext example without freetype.
     5.5 + */
     5.6 +#include <stdio.h>
     5.7 +#include <stdlib.h>
     5.8 +
     5.9 +#ifndef __APPLE__
    5.10 +#include <GL/glut.h>
    5.11 +#else
    5.12 +#include <GLUT/glut.h>
    5.13 +#endif
    5.14 +
    5.15 +#include "drawtext.h"
    5.16 +
    5.17 +void disp(void);
    5.18 +void reshape(int x, int y);
    5.19 +void keyb(unsigned char key, int x, int y);
    5.20 +
    5.21 +struct dtx_font *font;
    5.22 +
    5.23 +int main(int argc, char **argv)
    5.24 +{
    5.25 +	glutInit(&argc, argv);
    5.26 +	glutInitWindowSize(512, 384);
    5.27 +	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    5.28 +	glutCreateWindow("libdrawtext example: simple");
    5.29 +
    5.30 +	glutDisplayFunc(disp);
    5.31 +	glutReshapeFunc(reshape);
    5.32 +	glutKeyboardFunc(keyb);
    5.33 +
    5.34 +	if(!(font = dtx_open_font_glyphmap("serif_s24.glyphmap"))) {
    5.35 +		fprintf(stderr, "failed to open font\n");
    5.36 +		return 1;
    5.37 +	}
    5.38 +	dtx_use_font(font, 24);
    5.39 +
    5.40 +	glutMainLoop();
    5.41 +	return 0;
    5.42 +}
    5.43 +
    5.44 +const char *text = "Some sample text goes here.\n"
    5.45 +	"Yada yada yada, more text...\n"
    5.46 +	"foobar xyzzy\n";
    5.47 +
    5.48 +void disp(void)
    5.49 +{
    5.50 +	glClear(GL_COLOR_BUFFER_BIT);
    5.51 +
    5.52 +	glMatrixMode(GL_MODELVIEW);
    5.53 +	glLoadIdentity();
    5.54 +
    5.55 +	glPushMatrix();
    5.56 +	glTranslatef(-200, 150, 0);
    5.57 +	glColor3f(1, 1, 1);
    5.58 +	/* XXX call dtx_string to draw utf-8 text.
    5.59 +	 * any transformations and the current color apply
    5.60 +	 */
    5.61 +	dtx_string(text);
    5.62 +	glPopMatrix();
    5.63 +
    5.64 +	glPushMatrix();
    5.65 +	glTranslatef(-200, 50, 0);
    5.66 +	glScalef(2, 0.7, 1);
    5.67 +	glColor3f(0.6, 0.7, 1.0);
    5.68 +	dtx_string(text);
    5.69 +	glPopMatrix();
    5.70 +
    5.71 +	glPushMatrix();
    5.72 +	glTranslatef(-80, -90, 0);
    5.73 +	glRotatef(20, 0, 0, 1);
    5.74 +	glColor3f(1.0, 0.7, 0.6);
    5.75 +	dtx_string(text);
    5.76 +	glPopMatrix();
    5.77 +
    5.78 +	glutSwapBuffers();
    5.79 +}
    5.80 +
    5.81 +void reshape(int x, int y)
    5.82 +{
    5.83 +	glViewport(0, 0, x, y);
    5.84 +
    5.85 +	glMatrixMode(GL_PROJECTION);
    5.86 +	glLoadIdentity();
    5.87 +	glOrtho(-x/2, x/2, -y/2, y/2, -1, 1);
    5.88 +}
    5.89 +
    5.90 +void keyb(unsigned char key, int x, int y)
    5.91 +{
    5.92 +	if(key == 27) {
    5.93 +		exit(0);
    5.94 +	}
    5.95 +}
     6.1 --- a/src/drawtext.h	Tue Apr 15 03:33:39 2014 +0300
     6.2 +++ b/src/drawtext.h	Tue Apr 15 05:10:39 2014 +0300
     6.3 @@ -50,6 +50,11 @@
     6.4   * nothing will be rendered.
     6.5   */
     6.6  struct dtx_font *dtx_open_font(const char *fname, int sz);
     6.7 +/* open a font by loading a precompiled glyphmap (see: dtx_save_glyphmap)
     6.8 + * this works even when compiled without freetype support
     6.9 + */
    6.10 +struct dtx_font *dtx_open_font_glyphmap(const char *fname);
    6.11 +/* close a font opened by either of the above */
    6.12  void dtx_close_font(struct dtx_font *fnt);
    6.13  
    6.14  /* prepare an ASCII glyphmap for the specified font size */
    6.15 @@ -89,6 +94,8 @@
    6.16  int dtx_save_glyphmap(const char *fname, const struct dtx_glyphmap *gmap);
    6.17  int dtx_save_glyphmap_stream(FILE *fp, const struct dtx_glyphmap *gmap);
    6.18  
    6.19 +/* adds a glyphmap to a font */
    6.20 +void dtx_add_glyphmap(struct dtx_font *fnt, struct dtx_glyphmap *gmap);
    6.21  
    6.22  /* ---- rendering ---- */
    6.23  
     7.1 --- a/src/font.c	Tue Apr 15 03:33:39 2014 +0300
     7.2 +++ b/src/font.c	Tue Apr 15 05:10:39 2014 +0300
     7.3 @@ -68,11 +68,13 @@
     7.4  		FT_Done_FreeType(ft);
     7.5  	}
     7.6  }
     7.7 +#endif	/* USE_FREETYPE */
     7.8  
     7.9  struct dtx_font *dtx_open_font(const char *fname, int sz)
    7.10  {
    7.11 -	struct dtx_font *fnt;
    7.12 +	struct dtx_font *fnt = 0;
    7.13  
    7.14 +#ifdef USE_FREETYPE
    7.15  	init_freetype();
    7.16  
    7.17  	if(!(fnt = calloc(1, sizeof *fnt))) {
    7.18 @@ -93,15 +95,41 @@
    7.19  			dtx_use_font(fnt, sz);
    7.20  		}
    7.21  	}
    7.22 +#else
    7.23 +	fprintf(stderr, "ignoring call to dtx_open_font: not compiled with freetype support!\n");
    7.24 +#endif
    7.25  
    7.26  	return fnt;
    7.27  }
    7.28  
    7.29 +struct dtx_font *dtx_open_font_glyphmap(const char *fname)
    7.30 +{
    7.31 +	struct dtx_font *fnt;
    7.32 +	struct dtx_glyphmap *gmap;
    7.33 +
    7.34 +	if(!(fnt = calloc(1, sizeof *fnt))) {
    7.35 +		fperror("failed to allocate font structure");
    7.36 +		return 0;
    7.37 +	}
    7.38 +
    7.39 +	if(fname) {
    7.40 +		if(!(gmap = dtx_load_glyphmap(fname))) {
    7.41 +			free(fnt);
    7.42 +			return 0;
    7.43 +		}
    7.44 +
    7.45 +		dtx_add_glyphmap(fnt, gmap);
    7.46 +	}
    7.47 +	return fnt;
    7.48 +}
    7.49 +
    7.50  void dtx_close_font(struct dtx_font *fnt)
    7.51  {
    7.52  	if(!fnt) return;
    7.53  
    7.54 +#ifdef USE_FREETYPE
    7.55  	FT_Done_Face(fnt->face);
    7.56 +#endif
    7.57  
    7.58  	/* destroy the glyphmaps */
    7.59  	while(fnt->gmaps) {
    7.60 @@ -115,12 +143,16 @@
    7.61  
    7.62  void dtx_prepare(struct dtx_font *fnt, int sz)
    7.63  {
    7.64 -	dtx_get_font_glyphmap_range(fnt, sz, 0, 256);
    7.65 +	if(!dtx_get_font_glyphmap_range(fnt, sz, 0, 256)) {
    7.66 +		fprintf(stderr, "%s: failed (sz: %d, range: 0-255 [ascii])\n", __FUNCTION__, sz);
    7.67 +	}
    7.68  }
    7.69  
    7.70  void dtx_prepare_range(struct dtx_font *fnt, int sz, int cstart, int cend)
    7.71  {
    7.72 -	dtx_get_font_glyphmap_range(fnt, sz, cstart, cend);
    7.73 +	if(!dtx_get_font_glyphmap_range(fnt, sz, cstart, cend)) {
    7.74 +		fprintf(stderr, "%s: failed (sz: %d, range: %d-%d)\n", __FUNCTION__, sz, cstart, cend);
    7.75 +	}
    7.76  }
    7.77  
    7.78  struct dtx_glyphmap *dtx_get_font_glyphmap(struct dtx_font *fnt, int sz, int code)
    7.79 @@ -168,8 +200,10 @@
    7.80  
    7.81  struct dtx_glyphmap *dtx_create_glyphmap_range(struct dtx_font *fnt, int sz, int cstart, int cend)
    7.82  {
    7.83 +	struct dtx_glyphmap *gmap = 0;
    7.84 +
    7.85 +#ifdef USE_FREETYPE
    7.86  	FT_Face face = fnt->face;
    7.87 -	struct dtx_glyphmap *gmap;
    7.88  	int i, j;
    7.89  	int gx, gy;
    7.90  	int padding = 4;
    7.91 @@ -259,12 +293,11 @@
    7.92  	}
    7.93  
    7.94  	/* add it to the glyphmaps list of the font */
    7.95 -	gmap->next = fnt->gmaps;
    7.96 -	fnt->gmaps = gmap;
    7.97 +	dtx_add_glyphmap(fnt, gmap);
    7.98 +#endif	/* USE_FREETYPE */
    7.99  
   7.100  	return gmap;
   7.101  }
   7.102 -#endif	/* USE_FREETYPE */
   7.103  
   7.104  void dtx_free_glyphmap(struct dtx_glyphmap *gmap)
   7.105  {
   7.106 @@ -309,6 +342,7 @@
   7.107  	int hdr_lines = 0;
   7.108  	struct dtx_glyphmap *gmap;
   7.109  	struct glyph *glyphs = 0;
   7.110 +	struct glyph *g;
   7.111  	int min_code = INT_MAX;
   7.112  	int max_code = INT_MIN;
   7.113  	int i, max_pixval, num_pixels;
   7.114 @@ -317,6 +351,8 @@
   7.115  		fperror("failed to allocate glyphmap");
   7.116  		return 0;
   7.117  	}
   7.118 +	gmap->ptsize = -1;
   7.119 +	gmap->line_advance = FLT_MIN;
   7.120  
   7.121  	while(hdr_lines < 3) {
   7.122  		char *line = buf;
   7.123 @@ -330,34 +366,47 @@
   7.124  		}
   7.125  
   7.126  		if(line[0] == '#') {
   7.127 -			struct glyph *g;
   7.128  			int c, res;
   7.129 -			float x, y, xsz, ysz;
   7.130 +			float x, y, xsz, ysz, orig_x, orig_y, adv, line_adv;
   7.131 +			int ptsize;
   7.132  
   7.133 -			res = sscanf(line + 1, "%d: %fx%f+%f+%f\n", &c, &xsz, &ysz, &x, &y);
   7.134 -			if(res != 5) {
   7.135 +			if((res = sscanf(line + 1, " size: %d\n", &ptsize)) == 1) {
   7.136 +				gmap->ptsize = ptsize;
   7.137 +
   7.138 +			} else if((res = sscanf(line + 1, " advance: %f\n", &line_adv)) == 1) {
   7.139 +				gmap->line_advance = line_adv;
   7.140 +
   7.141 +			} else if((res = sscanf(line + 1, " %d: %fx%f+%f+%f o:%f,%f adv:%f\n",
   7.142 +							&c, &xsz, &ysz, &x, &y, &orig_x, &orig_y, &adv)) == 8) {
   7.143 +				if(!(g = malloc(sizeof *g))) {
   7.144 +					fperror("failed to allocate glyph");
   7.145 +					goto err;
   7.146 +				}
   7.147 +				g->code = c;
   7.148 +				g->x = x;
   7.149 +				g->y = y;
   7.150 +				g->width = xsz;
   7.151 +				g->height = ysz;
   7.152 +				g->orig_x = orig_x;
   7.153 +				g->orig_y = orig_y;
   7.154 +				g->advance = adv;
   7.155 +				/* normalized coordinates will be precalculated after everything is loaded */
   7.156 +
   7.157 +				g->next = glyphs;
   7.158 +				glyphs = g;
   7.159 +
   7.160 +				if(c < min_code) {
   7.161 +					min_code = c;
   7.162 +				}
   7.163 +				if(c > max_code) {
   7.164 +					max_code = c;
   7.165 +				}
   7.166 +
   7.167 +			} else {
   7.168  				fprintf(stderr, "%s: invalid glyph info line\n", __FUNCTION__);
   7.169  				goto err;
   7.170  			}
   7.171  
   7.172 -			if(!(g = malloc(sizeof *g))) {
   7.173 -				fperror("failed to allocate glyph");
   7.174 -				goto err;
   7.175 -			}
   7.176 -			g->code = c;
   7.177 -			g->x = x;
   7.178 -			g->y = y;
   7.179 -			g->width = xsz;
   7.180 -			g->height = ysz;
   7.181 -			g->next = glyphs;
   7.182 -			glyphs = g;
   7.183 -
   7.184 -			if(c < min_code) {
   7.185 -				min_code = c;
   7.186 -			}
   7.187 -			if(c > max_code) {
   7.188 -				max_code = c;
   7.189 -			}
   7.190  		} else {
   7.191  			switch(hdr_lines) {
   7.192  			case 0:
   7.193 @@ -392,6 +441,21 @@
   7.194  		}
   7.195  	}
   7.196  
   7.197 +	if(gmap->ptsize == -1 || gmap->line_advance == FLT_MIN) {
   7.198 +		fprintf(stderr, "%s: invalid glyphmap, insufficient information in ppm comments\n", __FUNCTION__);
   7.199 +		goto err;
   7.200 +	}
   7.201 +
   7.202 +	/* precalculate normalized glyph coordinates */
   7.203 +	g = glyphs;
   7.204 +	while(g) {
   7.205 +		g->nx = g->x / gmap->xsz;
   7.206 +		g->ny = g->y / gmap->ysz;
   7.207 +		g->nwidth = g->width / gmap->xsz;
   7.208 +		g->nheight = g->height / gmap->ysz;
   7.209 +		g = g->next;
   7.210 +	}
   7.211 +
   7.212  	num_pixels = gmap->xsz * gmap->ysz;
   7.213  	if(!(gmap->pixels = malloc(num_pixels))) {
   7.214  		fperror("failed to allocate pixels");
   7.215 @@ -456,8 +520,11 @@
   7.216  	struct glyph *g = gmap->glyphs;
   7.217  
   7.218  	fprintf(fp, "P6\n%d %d\n", gmap->xsz, gmap->ysz);
   7.219 +	fprintf(fp, "# size: %d\n", gmap->ptsize);
   7.220 +	fprintf(fp, "# advance: %g\n", gmap->line_advance);
   7.221  	for(i=0; i<gmap->crange; i++) {
   7.222 -		fprintf(fp, "# %d: %fx%f+%f+%f\n", g->code, g->width, g->height, g->x, g->y);
   7.223 +		fprintf(fp, "# %d: %gx%g+%g+%g o:%g,%g adv:%g\n", g->code, g->width, g->height, g->x, g->y,
   7.224 +				g->orig_x, g->orig_y, g->advance);
   7.225  		g++;
   7.226  	}
   7.227  	fprintf(fp, "255\n");
   7.228 @@ -472,6 +539,12 @@
   7.229  	return 0;
   7.230  }
   7.231  
   7.232 +void dtx_add_glyphmap(struct dtx_font *fnt, struct dtx_glyphmap *gmap)
   7.233 +{
   7.234 +	gmap->next = fnt->gmaps;
   7.235 +	fnt->gmaps = gmap;
   7.236 +}
   7.237 +
   7.238  
   7.239  void dtx_use_font(struct dtx_font *fnt, int sz)
   7.240  {
   7.241 @@ -646,6 +719,7 @@
   7.242  	return gmap;
   7.243  }
   7.244  
   7.245 +#ifdef USE_FREETYPE
   7.246  static void calc_best_size(int total_width, int max_glyph_height, int padding, int pow2, int *imgw, int *imgh)
   7.247  {
   7.248  	int xsz, ysz, num_rows;
   7.249 @@ -687,3 +761,4 @@
   7.250  	x = (x >> 16) | x;
   7.251  	return x + 1;
   7.252  }
   7.253 +#endif