dungeon_crawler

changeset 24:e122ba214ee1

implementing the command console
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 23 Aug 2012 18:03:11 +0300
parents fa8f89d06f6f
children 527fede30057
files prototype/Makefile prototype/data/droid_sans_mono.ttf prototype/drawtext/drawgl.c prototype/drawtext/drawtext.h prototype/drawtext/drawtext_impl.h prototype/drawtext/font.c prototype/drawtext/utf8.c prototype/src/cmdcon.cc prototype/src/cmdcon.h prototype/src/main.cc
diffstat 10 files changed, 1533 insertions(+), 7 deletions(-) [+]
line diff
     1.1 --- a/prototype/Makefile	Thu Aug 23 00:10:10 2012 +0300
     1.2 +++ b/prototype/Makefile	Thu Aug 23 18:03:11 2012 +0300
     1.3 @@ -1,4 +1,4 @@
     1.4 -csrc = $(wildcard src/*.c) $(wildcard vmath/*.c)
     1.5 +csrc = $(wildcard src/*.c) $(wildcard vmath/*.c) $(wildcard drawtext/*.c)
     1.6  ccsrc = $(wildcard src/*.cc) $(wildcard vmath/*.cc)
     1.7  obj = $(csrc:.c=.o) $(ccsrc:.cc=.o)
     1.8  dep = $(obj:.o=.d)
     1.9 @@ -8,9 +8,11 @@
    1.10  dbg = -g
    1.11  warn = -Wall -Wno-format-extra-args -Wno-char-subscripts
    1.12  
    1.13 -CFLAGS = -pedantic $(warn) $(dbg) $(opt) -Ivmath
    1.14 +inc = -Ivmath -Idrawtext `pkg-config --cflags freetype2`
    1.15 +
    1.16 +CFLAGS = -pedantic $(warn) $(dbg) $(opt) $(inc)
    1.17  CXXFLAGS = $(CFLAGS) -std=c++11
    1.18 -LDFLAGS = $(libgl) -lm -lassimp -limago
    1.19 +LDFLAGS = $(libgl) -lm -lassimp -limago `pkg-config --libs freetype2`
    1.20  
    1.21  ifeq ($(shell uname -s), Darwin)
    1.22  	libgl = -framework OpenGL -framework GLUT -lglew
     2.1 Binary file prototype/data/droid_sans_mono.ttf has changed
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/prototype/drawtext/drawgl.c	Thu Aug 23 18:03:11 2012 +0300
     3.3 @@ -0,0 +1,248 @@
     3.4 +/*
     3.5 +libdrawtext - a simple library for fast text rendering in OpenGL
     3.6 +Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
     3.7 +
     3.8 +This program is free software: you can redistribute it and/or modify
     3.9 +it under the terms of the GNU Lesser General Public License as published by
    3.10 +the Free Software Foundation, either version 3 of the License, or
    3.11 +(at your option) any later version.
    3.12 +
    3.13 +This program is distributed in the hope that it will be useful,
    3.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.16 +GNU Lesser General Public License for more details.
    3.17 +
    3.18 +You should have received a copy of the GNU Lesser General Public License
    3.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
    3.20 +*/
    3.21 +#ifndef NO_OPENGL
    3.22 +#include <math.h>
    3.23 +#include <ctype.h>
    3.24 +
    3.25 +#include <stdlib.h>
    3.26 +
    3.27 +#ifdef TARGET_IPHONE
    3.28 +#include <OpenGLES/ES2/gl.h>
    3.29 +#else
    3.30 +#include <GL/glew.h>
    3.31 +#endif
    3.32 +
    3.33 +#include "drawtext.h"
    3.34 +#include "drawtext_impl.h"
    3.35 +
    3.36 +struct vertex {
    3.37 +	float x, y;
    3.38 +	float s, t;
    3.39 +};
    3.40 +
    3.41 +struct quad {
    3.42 +	struct vertex v[6];
    3.43 +};
    3.44 +
    3.45 +static void cleanup(void);
    3.46 +static void add_glyph(struct glyph *g, float x, float y);
    3.47 +
    3.48 +#define QBUF_SZ		512
    3.49 +static struct quad *qbuf;
    3.50 +static int num_quads;
    3.51 +static int vattr = -1;
    3.52 +static int tattr = -1;
    3.53 +static unsigned int font_tex;
    3.54 +static int buf_mode = DTX_NBF;
    3.55 +
    3.56 +
    3.57 +int dtx_gl_init(void)
    3.58 +{
    3.59 +	if(qbuf) {
    3.60 +		return 0;	/* already initialized */
    3.61 +	}
    3.62 +
    3.63 +	glewInit();
    3.64 +
    3.65 +	if(!(qbuf = malloc(QBUF_SZ * sizeof *qbuf))) {
    3.66 +		return -1;
    3.67 +	}
    3.68 +	num_quads = 0;
    3.69 +
    3.70 +	atexit(cleanup);
    3.71 +	return 0;
    3.72 +}
    3.73 +
    3.74 +static void cleanup(void)
    3.75 +{
    3.76 +	free(qbuf);
    3.77 +}
    3.78 +
    3.79 +
    3.80 +void dtx_vertex_attribs(int vert_attr, int tex_attr)
    3.81 +{
    3.82 +	vattr = vert_attr;
    3.83 +	tattr = tex_attr;
    3.84 +}
    3.85 +
    3.86 +static void set_glyphmap_texture(struct dtx_glyphmap *gmap)
    3.87 +{
    3.88 +	if(!gmap->tex) {
    3.89 +		glGenTextures(1, &gmap->tex);
    3.90 +		glBindTexture(GL_TEXTURE_2D, gmap->tex);
    3.91 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    3.92 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    3.93 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    3.94 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    3.95 +
    3.96 +#ifdef GL_ES
    3.97 +		glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gmap->xsz, gmap->ysz, 0, GL_ALPHA, GL_UNSIGNED_BYTE, gmap->pixels);
    3.98 +		glGenerateMipmap(GL_TEXTURE_2D);
    3.99 +#else
   3.100 +		gluBuild2DMipmaps(GL_TEXTURE_2D, GL_ALPHA, gmap->xsz, gmap->ysz, GL_ALPHA, GL_UNSIGNED_BYTE, gmap->pixels);
   3.101 +#endif
   3.102 +	}
   3.103 +
   3.104 +	if(font_tex != gmap->tex) {
   3.105 +		dtx_flush();
   3.106 +	}
   3.107 +	font_tex = gmap->tex;
   3.108 +}
   3.109 +
   3.110 +void dtx_glyph(int code)
   3.111 +{
   3.112 +	struct dtx_glyphmap *gmap;
   3.113 +
   3.114 +	if(!dtx_font || !(gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code))) {
   3.115 +		return;
   3.116 +	}
   3.117 +	set_glyphmap_texture(gmap);
   3.118 +
   3.119 +	add_glyph(gmap->glyphs + code - gmap->cstart, 0, 0);
   3.120 +	dtx_flush();
   3.121 +}
   3.122 +
   3.123 +void dtx_string(const char *str)
   3.124 +{
   3.125 +	struct dtx_glyphmap *gmap;
   3.126 +	int should_flush = buf_mode == DTX_NBF;
   3.127 +	float pos_x = 0.0f;
   3.128 +	float pos_y = 0.0f;
   3.129 +
   3.130 +	if(!dtx_font) {
   3.131 +		return;
   3.132 +	}
   3.133 +
   3.134 +	while(*str) {
   3.135 +		float px, py;
   3.136 +		int code = dtx_utf8_char_code(str);
   3.137 +		str = dtx_utf8_next_char((char*)str);
   3.138 +
   3.139 +		if(buf_mode == DTX_LBF && code == '\n') {
   3.140 +			should_flush = 1;
   3.141 +		}
   3.142 +
   3.143 +		px = pos_x;
   3.144 +		py = pos_y;
   3.145 +
   3.146 +		if((gmap = dtx_proc_char(code, &pos_x, &pos_y))) {
   3.147 +			int idx = code - gmap->cstart;
   3.148 +
   3.149 +			set_glyphmap_texture(gmap);
   3.150 +			add_glyph(gmap->glyphs + idx, px, py);
   3.151 +		}
   3.152 +	}
   3.153 +
   3.154 +	if(should_flush) {
   3.155 +		dtx_flush();
   3.156 +	}
   3.157 +}
   3.158 +
   3.159 +static void qvertex(struct vertex *v, float x, float y, float s, float t)
   3.160 +{
   3.161 +	v->x = x;
   3.162 +	v->y = y;
   3.163 +	v->s = s;
   3.164 +	v->t = t;
   3.165 +}
   3.166 +
   3.167 +static void add_glyph(struct glyph *g, float x, float y)
   3.168 +{
   3.169 +	struct quad *qptr = qbuf + num_quads;
   3.170 +
   3.171 +	x -= g->orig_x;
   3.172 +	y -= g->orig_y;
   3.173 +
   3.174 +	qvertex(qptr->v + 0, x, y, g->nx, g->ny + g->nheight);
   3.175 +	qvertex(qptr->v + 1, x + g->width, y, g->nx + g->nwidth, g->ny + g->nheight);
   3.176 +	qvertex(qptr->v + 2, x + g->width, y + g->height, g->nx + g->nwidth, g->ny);
   3.177 +
   3.178 +	qvertex(qptr->v + 3, x, y, g->nx, g->ny + g->nheight);
   3.179 +	qvertex(qptr->v + 4, x + g->width, y + g->height, g->nx + g->nwidth, g->ny);
   3.180 +	qvertex(qptr->v + 5, x, y + g->height, g->nx, g->ny);
   3.181 +
   3.182 +	if(++num_quads >= QBUF_SZ) {
   3.183 +		dtx_flush();
   3.184 +	}
   3.185 +}
   3.186 +
   3.187 +void dtx_flush(void)
   3.188 +{
   3.189 +	if(!num_quads) {
   3.190 +		return;
   3.191 +	}
   3.192 +
   3.193 +#ifndef GL_ES
   3.194 +	glPushAttrib(GL_ENABLE_BIT);
   3.195 +	glEnable(GL_TEXTURE_2D);
   3.196 +#endif
   3.197 +	glBindTexture(GL_TEXTURE_2D, font_tex);
   3.198 +
   3.199 +	if(vattr != -1 && glEnableVertexAttribArray) {
   3.200 +		glEnableVertexAttribArray(vattr);
   3.201 +		glVertexAttribPointer(vattr, 2, GL_FLOAT, 0, sizeof(struct vertex), qbuf);
   3.202 +#ifndef GL_ES
   3.203 +	} else {
   3.204 +		glEnableClientState(GL_VERTEX_ARRAY);
   3.205 +		glVertexPointer(2, GL_FLOAT, sizeof(struct vertex), qbuf);
   3.206 +#endif
   3.207 +	}
   3.208 +	if(tattr != -1 && glEnableVertexAttribArray) {
   3.209 +		glEnableVertexAttribArray(tattr);
   3.210 +		glVertexAttribPointer(tattr, 2, GL_FLOAT, 0, sizeof(struct vertex), &qbuf->v[0].s);
   3.211 +#ifndef GL_ES
   3.212 +	} else {
   3.213 +		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   3.214 +		glTexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), &qbuf->v[0].s);
   3.215 +#endif
   3.216 +	}
   3.217 +
   3.218 +	glEnable(GL_BLEND);
   3.219 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   3.220 +
   3.221 +	glDepthMask(0);
   3.222 +
   3.223 +	glDrawArrays(GL_TRIANGLES, 0, num_quads * 6);
   3.224 +
   3.225 +	glDepthMask(1);
   3.226 +
   3.227 +	if(vattr != -1 && glDisableVertexAttribArray) {
   3.228 +		glDisableVertexAttribArray(vattr);
   3.229 +#ifndef GL_ES
   3.230 +	} else {
   3.231 +		glDisableClientState(GL_VERTEX_ARRAY);
   3.232 +#endif
   3.233 +	}
   3.234 +	if(tattr != -1 && glDisableVertexAttribArray) {
   3.235 +		glDisableVertexAttribArray(tattr);
   3.236 +#ifndef GL_ES
   3.237 +	} else {
   3.238 +		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   3.239 +#endif
   3.240 +	}
   3.241 +
   3.242 +#ifndef GL_ES
   3.243 +	glPopAttrib();
   3.244 +#else
   3.245 +	glDisable(GL_BLEND);
   3.246 +#endif
   3.247 +
   3.248 +	num_quads = 0;
   3.249 +}
   3.250 +
   3.251 +#endif	/* !def NO_OPENGL */
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/prototype/drawtext/drawtext.h	Thu Aug 23 18:03:11 2012 +0300
     4.3 @@ -0,0 +1,178 @@
     4.4 +/*
     4.5 +libdrawtext - a simple library for fast text rendering in OpenGL
     4.6 +Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
     4.7 +
     4.8 +This program is free software: you can redistribute it and/or modify
     4.9 +it under the terms of the GNU Lesser General Public License as published by
    4.10 +the Free Software Foundation, either version 3 of the License, or
    4.11 +(at your option) any later version.
    4.12 +
    4.13 +This program is distributed in the hope that it will be useful,
    4.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.16 +GNU Lesser General Public License for more details.
    4.17 +
    4.18 +You should have received a copy of the GNU Lesser General Public License
    4.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
    4.20 +*/
    4.21 +#ifndef TEXT_H_
    4.22 +#define TEXT_H_
    4.23 +
    4.24 +#include <stdio.h>
    4.25 +#include <stdlib.h>
    4.26 +
    4.27 +struct dtx_font;
    4.28 +struct dtx_glyphmap;
    4.29 +
    4.30 +/* draw buffering modes */
    4.31 +enum {
    4.32 +	DTX_NBF,	/* unbuffered */
    4.33 +	DTX_LBF,	/* line buffered */
    4.34 +	DTX_FBF		/* fully buffered */
    4.35 +};
    4.36 +
    4.37 +struct dtx_box {
    4.38 +	float x, y;
    4.39 +	float width, height;
    4.40 +};
    4.41 +
    4.42 +#ifdef __cplusplus
    4.43 +extern "C" {
    4.44 +#endif
    4.45 +
    4.46 +/* Open a truetype/opentype/whatever font.
    4.47 + *
    4.48 + * If sz is non-zero, the default ASCII glyphmap at the requested point size is
    4.49 + * automatically created as well, and ready to use.
    4.50 + *
    4.51 + * To use other unicode ranges and different font sizes you must first call
    4.52 + * dtx_prepare or dtx_prepare_range before issuing any drawing calls, otherwise
    4.53 + * nothing will be rendered.
    4.54 + */
    4.55 +struct dtx_font *dtx_open_font(const char *fname, int sz);
    4.56 +void dtx_close_font(struct dtx_font *fnt);
    4.57 +
    4.58 +/* prepare an ASCII glyphmap for the specified font size */
    4.59 +void dtx_prepare(struct dtx_font *fnt, int sz);
    4.60 +/* prepare an arbitrary unicode range glyphmap for the specified font size */
    4.61 +void dtx_prepare_range(struct dtx_font *fnt, int sz, int cstart, int cend);
    4.62 +
    4.63 +/* Finds the glyphmap that contains the specified character code and matches the requested size
    4.64 + * Returns null if it hasn't been created (you should call dtx_prepare/dtx_prepare_range).
    4.65 + */
    4.66 +struct dtx_glyphmap *dtx_get_font_glyphmap(struct dtx_font *fnt, int sz, int code);
    4.67 +
    4.68 +/* Finds the glyphmap that contains the specified unicode range and matches the requested font size
    4.69 + * Will automatically generate one if it can't find it.
    4.70 + */
    4.71 +struct dtx_glyphmap *dtx_get_font_glyphmap_range(struct dtx_font *fnt, int sz, int cstart, int cend);
    4.72 +
    4.73 +/* Creates and returns a glyphmap for a particular unicode range and font size.
    4.74 + * The generated glyphmap is added to the font's list of glyphmaps.
    4.75 + */
    4.76 +struct dtx_glyphmap *dtx_create_glyphmap_range(struct dtx_font *fnt, int sz, int cstart, int cend);
    4.77 +/* free a glyphmap */
    4.78 +void dtx_free_glyphmap(struct dtx_glyphmap *gmap);
    4.79 +
    4.80 +/* returns a pointer to the raster image of a glyphmap (1 byte per pixel grayscale) */
    4.81 +unsigned char *dtx_get_glyphmap_image(struct dtx_glyphmap *gmap);
    4.82 +/* returns the width of the glyphmap image in pixels */
    4.83 +int dtx_get_glyphmap_width(struct dtx_glyphmap *gmap);
    4.84 +/* returns the height of the glyphmap image in pixels */
    4.85 +int dtx_get_glyphmap_height(struct dtx_glyphmap *gmap);
    4.86 +
    4.87 +/* The following functions can be used even when the library is compiled without
    4.88 + * freetype support. (TODO)
    4.89 + */
    4.90 +struct dtx_glyphmap *dtx_load_glyphmap(const char *fname);
    4.91 +struct dtx_glyphmap *dtx_load_glyphmap_stream(FILE *fp);
    4.92 +int dtx_save_glyphmap(const char *fname, const struct dtx_glyphmap *gmap);
    4.93 +int dtx_save_glyphmap_stream(FILE *fp, const struct dtx_glyphmap *gmap);
    4.94 +
    4.95 +
    4.96 +/* ---- rendering ---- */
    4.97 +
    4.98 +/* before drawing anything this function must set the font to use */
    4.99 +void dtx_use_font(struct dtx_font *fnt, int sz);
   4.100 +
   4.101 +/* sets the buffering mode
   4.102 + * - DTX_NBUF: every call to dtx_string gets rendered immediately.
   4.103 + * - DTX_LBUF: renders when the buffer is full or the string contains a newline.
   4.104 + * - DTX_FBUF: renders only when the buffer is full (you must call dtx_flush explicitly).
   4.105 + */
   4.106 +void dtx_draw_buffering(int mode);
   4.107 +
   4.108 +/* Sets the vertex attribute indices to use for passing vertex and texture coordinate
   4.109 + * data. By default both are -1 which means you don't have to use a shader, and if you
   4.110 + * do they are accessible through gl_Vertex and gl_MultiTexCoord0, as usual.
   4.111 + *
   4.112 + * NOTE: If you are using OpenGL ES 2.x or OpenGL >= 3.1 pure (non-compatibility) context
   4.113 + * you must specify valid attribute indices.
   4.114 + */
   4.115 +void dtx_vertex_attribs(int vert_attr, int tex_attr);
   4.116 +
   4.117 +/* draws a single glyph at the origin */
   4.118 +void dtx_glyph(int code);
   4.119 +/* draws a utf-8 string starting at the origin. \n \r and \t are handled appropriately. */
   4.120 +void dtx_string(const char *str);
   4.121 +
   4.122 +/* render any pending glyphs (see dtx_draw_buffering) */
   4.123 +void dtx_flush(void);
   4.124 +
   4.125 +
   4.126 +/* ---- encodings ---- */
   4.127 +
   4.128 +/* returns a pointer to the next character in a utf-8 stream */
   4.129 +char *dtx_utf8_next_char(char *str);
   4.130 +
   4.131 +/* returns the unicode character codepoint of the utf-8 character starting at str */
   4.132 +int dtx_utf8_char_code(const char *str);
   4.133 +
   4.134 +/* returns the number of bytes of the utf-8 character starting at str */
   4.135 +int dtx_utf8_nbytes(const char *str);
   4.136 +
   4.137 +/* returns the number of utf-8 character in a zero-terminated utf-8 string */
   4.138 +int dtx_utf8_char_count(const char *str);
   4.139 +
   4.140 +/* Converts a unicode code-point to a utf-8 character by filling in the buffer
   4.141 + * passed at the second argument, and returns the number of bytes taken by that
   4.142 + * utf-8 character.
   4.143 + * It's valid to pass a null buffer pointer, in which case only the byte count is
   4.144 + * returned (useful to figure out how much memory to allocate for a buffer).
   4.145 + */
   4.146 +size_t dtx_utf8_from_char_code(int code, char *buf);
   4.147 +
   4.148 +/* Converts a unicode utf-16 wchar_t string to utf-8, filling in the buffer passed
   4.149 + * at the second argument. Returns the size of the resulting string in bytes.
   4.150 + *
   4.151 + * It's valid to pass a null buffer pointer, in which case only the size gets
   4.152 + * calculated and returned, which is useful for figuring out how much memory to
   4.153 + * allocate for the utf-8 buffer.
   4.154 + */
   4.155 +size_t dtx_utf8_from_string(const wchar_t *str, char *buf);
   4.156 +
   4.157 +
   4.158 +/* ---- metrics ---- */
   4.159 +
   4.160 +/* rendered dimensions of a single glyph */
   4.161 +void dtx_glyph_box(int code, struct dtx_box *box);
   4.162 +float dtx_glyph_width(int code);
   4.163 +float dtx_glyph_height(int code);
   4.164 +
   4.165 +/* rendered dimensions of a string */
   4.166 +void dtx_string_box(const char *str, struct dtx_box *box);
   4.167 +float dtx_string_width(const char *str);
   4.168 +float dtx_string_height(const char *str);
   4.169 +
   4.170 +/* returns the horizontal position of the n-th character of the rendered string
   4.171 + * (useful for placing cursors)
   4.172 + */
   4.173 +float dtx_char_pos(const char *str, int n);
   4.174 +
   4.175 +int dtx_char_at_pt(const char *str, float pt);
   4.176 +
   4.177 +#ifdef __cplusplus
   4.178 +}
   4.179 +#endif
   4.180 +
   4.181 +#endif	/* TEXT_H_ */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/prototype/drawtext/drawtext_impl.h	Thu Aug 23 18:03:11 2012 +0300
     5.3 @@ -0,0 +1,72 @@
     5.4 +/*
     5.5 +libdrawtext - a simple library for fast text rendering in OpenGL
     5.6 +Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
     5.7 +
     5.8 +This program is free software: you can redistribute it and/or modify
     5.9 +it under the terms of the GNU Lesser General Public License as published by
    5.10 +the Free Software Foundation, either version 3 of the License, or
    5.11 +(at your option) any later version.
    5.12 +
    5.13 +This program is distributed in the hope that it will be useful,
    5.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.16 +GNU Lesser General Public License for more details.
    5.17 +
    5.18 +You should have received a copy of the GNU Lesser General Public License
    5.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
    5.20 +*/
    5.21 +#ifndef TEXT_IMPL_H_
    5.22 +#define TEXT_IMPL_H_
    5.23 +
    5.24 +struct glyph {
    5.25 +	int code;
    5.26 +	float x, y, width, height;
    5.27 +	/* normalized coords [0, 1] */
    5.28 +	float nx, ny, nwidth, nheight;
    5.29 +	float orig_x, orig_y;
    5.30 +	float advance;
    5.31 +	struct glyph *next;
    5.32 +};
    5.33 +
    5.34 +struct dtx_glyphmap {
    5.35 +	int ptsize;
    5.36 +
    5.37 +	int xsz, ysz;
    5.38 +	unsigned char *pixels;
    5.39 +	unsigned int tex;
    5.40 +
    5.41 +	int cstart, cend;	/* character range */
    5.42 +	int crange;
    5.43 +
    5.44 +	float line_advance;
    5.45 +
    5.46 +	struct glyph *glyphs;
    5.47 +	struct dtx_glyphmap *next;
    5.48 +};
    5.49 +
    5.50 +struct dtx_font {
    5.51 +	/* freetype FT_Face */
    5.52 +	void *face;
    5.53 +
    5.54 +	/* list of glyphmaps */
    5.55 +	struct dtx_glyphmap *gmaps;
    5.56 +
    5.57 +	/* last returned glyphmap (cache) */
    5.58 +	struct dtx_glyphmap *last_gmap;
    5.59 +};
    5.60 +
    5.61 +
    5.62 +struct dtx_font *dtx_font;
    5.63 +int dtx_font_sz;
    5.64 +
    5.65 +
    5.66 +#define fperror(str) \
    5.67 +	fprintf(stderr, "%s: %s: %s\n", __func__, (str), strerror(errno))
    5.68 +
    5.69 +int dtx_gl_init(void);
    5.70 +
    5.71 +/* returns zero if it should NOT be printed and modifies xpos/ypos */
    5.72 +/* implemented in font.c */
    5.73 +struct dtx_glyphmap *dtx_proc_char(int code, float *xpos, float *ypos);
    5.74 +
    5.75 +#endif	/* TEXT_IMPL_H_ */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/prototype/drawtext/font.c	Thu Aug 23 18:03:11 2012 +0300
     6.3 @@ -0,0 +1,678 @@
     6.4 +/*
     6.5 +libdrawtext - a simple library for fast text rendering in OpenGL
     6.6 +Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
     6.7 +
     6.8 +This program is free software: you can redistribute it and/or modify
     6.9 +it under the terms of the GNU Lesser General Public License as published by
    6.10 +the Free Software Foundation, either version 3 of the License, or
    6.11 +(at your option) any later version.
    6.12 +
    6.13 +This program is distributed in the hope that it will be useful,
    6.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.16 +GNU Lesser General Public License for more details.
    6.17 +
    6.18 +You should have received a copy of the GNU Lesser General Public License
    6.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
    6.20 +*/
    6.21 +#ifndef NO_FREETYPE
    6.22 +#define USE_FREETYPE
    6.23 +#endif
    6.24 +
    6.25 +#include <stdio.h>
    6.26 +#include <stdlib.h>
    6.27 +#include <string.h>
    6.28 +#include <math.h>
    6.29 +#include <limits.h>
    6.30 +#include <ctype.h>
    6.31 +#include <float.h>
    6.32 +#include <errno.h>
    6.33 +#ifdef USE_FREETYPE
    6.34 +#include <ft2build.h>
    6.35 +#include FT_FREETYPE_H
    6.36 +#endif
    6.37 +#include "drawtext.h"
    6.38 +#include "drawtext_impl.h"
    6.39 +
    6.40 +#define FTSZ_TO_PIXELS(x)	((x) / 64)
    6.41 +#define MAX_IMG_WIDTH		4096
    6.42 +
    6.43 +
    6.44 +#ifdef USE_FREETYPE
    6.45 +static int init_freetype(void);
    6.46 +static void cleanup(void);
    6.47 +
    6.48 +static void calc_best_size(int total_width, int max_glyph_height, int padding, int pow2, int *imgw, int *imgh);
    6.49 +static int next_pow2(int x);
    6.50 +
    6.51 +static FT_Library ft;
    6.52 +
    6.53 +
    6.54 +static int init_done;
    6.55 +
    6.56 +static int init_freetype(void)
    6.57 +{
    6.58 +	if(!init_done) {
    6.59 +		if(FT_Init_FreeType(&ft) != 0) {
    6.60 +			return -1;
    6.61 +		}
    6.62 +		atexit(cleanup);
    6.63 +		init_done = 1;
    6.64 +	}
    6.65 +	return 0;
    6.66 +}
    6.67 +
    6.68 +static void cleanup(void)
    6.69 +{
    6.70 +	if(init_done) {
    6.71 +		FT_Done_FreeType(ft);
    6.72 +	}
    6.73 +}
    6.74 +
    6.75 +struct dtx_font *dtx_open_font(const char *fname, int sz)
    6.76 +{
    6.77 +	struct dtx_font *fnt;
    6.78 +
    6.79 +	init_freetype();
    6.80 +
    6.81 +	if(!(fnt = calloc(1, sizeof *fnt))) {
    6.82 +		fperror("failed to allocate font structure");
    6.83 +		return 0;
    6.84 +	}
    6.85 +
    6.86 +	if(FT_New_Face(ft, fname, 0, (FT_Face*)&fnt->face) != 0) {
    6.87 +		fprintf(stderr, "failed to open font file: %s\n", fname);
    6.88 +		return 0;
    6.89 +	}
    6.90 +
    6.91 +	/* pre-create the extended ASCII range glyphmap */
    6.92 +	if(sz) {
    6.93 +		dtx_prepare_range(fnt, sz, 0, 256);
    6.94 +	}
    6.95 +
    6.96 +	return fnt;
    6.97 +}
    6.98 +
    6.99 +void dtx_close_font(struct dtx_font *fnt)
   6.100 +{
   6.101 +	if(!fnt) return;
   6.102 +
   6.103 +	FT_Done_Face(fnt->face);
   6.104 +
   6.105 +	/* destroy the glyphmaps */
   6.106 +	while(fnt->gmaps) {
   6.107 +		void *tmp = fnt->gmaps;
   6.108 +		fnt->gmaps = fnt->gmaps->next;
   6.109 +		dtx_free_glyphmap(tmp);
   6.110 +	}
   6.111 +
   6.112 +	free(fnt);
   6.113 +}
   6.114 +
   6.115 +void dtx_prepare(struct dtx_font *fnt, int sz)
   6.116 +{
   6.117 +	dtx_get_font_glyphmap_range(fnt, sz, 0, 256);
   6.118 +}
   6.119 +
   6.120 +void dtx_prepare_range(struct dtx_font *fnt, int sz, int cstart, int cend)
   6.121 +{
   6.122 +	dtx_get_font_glyphmap_range(fnt, sz, cstart, cend);
   6.123 +}
   6.124 +
   6.125 +struct dtx_glyphmap *dtx_get_font_glyphmap(struct dtx_font *fnt, int sz, int code)
   6.126 +{
   6.127 +	struct dtx_glyphmap *gm;
   6.128 +
   6.129 +	/* check to see if the last we've given out fits the bill */
   6.130 +	if(fnt->last_gmap && code >= fnt->last_gmap->cstart && code < fnt->last_gmap->cend && fnt->last_gmap->ptsize == sz) {
   6.131 +		return fnt->last_gmap;
   6.132 +	}
   6.133 +
   6.134 +	/* otherwise search for the appropriate glyphmap */
   6.135 +	gm = fnt->gmaps;
   6.136 +	while(gm) {
   6.137 +		if(code >= gm->cstart && code < gm->cend && sz == gm->ptsize) {
   6.138 +			fnt->last_gmap = gm;
   6.139 +			return gm;
   6.140 +		}
   6.141 +		gm = gm->next;
   6.142 +	}
   6.143 +	return 0;
   6.144 +}
   6.145 +
   6.146 +struct dtx_glyphmap *dtx_get_font_glyphmap_range(struct dtx_font *fnt, int sz, int cstart, int cend)
   6.147 +{
   6.148 +	struct dtx_glyphmap *gm;
   6.149 +
   6.150 +	/* search the available glyphmaps to see if we've got one that includes
   6.151 +	 * the requested range
   6.152 +	 */
   6.153 +	gm = fnt->gmaps;
   6.154 +	while(gm) {
   6.155 +		if(gm->cstart <= cstart && gm->cend >= cend && gm->ptsize == sz) {
   6.156 +			return gm;
   6.157 +		}
   6.158 +		gm = gm->next;
   6.159 +	}
   6.160 +
   6.161 +	/* not found, create one and add it to the list */
   6.162 +	if(!(gm = dtx_create_glyphmap_range(fnt, sz, cstart, cend))) {
   6.163 +		return 0;
   6.164 +	}
   6.165 +	return gm;
   6.166 +}
   6.167 +
   6.168 +struct dtx_glyphmap *dtx_create_glyphmap_range(struct dtx_font *fnt, int sz, int cstart, int cend)
   6.169 +{
   6.170 +	FT_Face face = fnt->face;
   6.171 +	struct dtx_glyphmap *gmap;
   6.172 +	int i, j;
   6.173 +	int gx, gy;
   6.174 +	int padding = 4;
   6.175 +	int total_width = padding;
   6.176 +	int max_height = 0;
   6.177 +
   6.178 +	FT_Set_Char_Size(fnt->face, 0, sz * 64, 72, 72);
   6.179 +
   6.180 +	if(!(gmap = calloc(1, sizeof *gmap))) {
   6.181 +		return 0;
   6.182 +	}
   6.183 +
   6.184 +	gmap->ptsize = sz;
   6.185 +	gmap->cstart = cstart;
   6.186 +	gmap->cend = cend;
   6.187 +	gmap->crange = cend - cstart;
   6.188 +	gmap->line_advance = FTSZ_TO_PIXELS((float)face->size->metrics.height);
   6.189 +
   6.190 +	if(!(gmap->glyphs = malloc(gmap->crange * sizeof *gmap->glyphs))) {
   6.191 +		free(gmap);
   6.192 +		return 0;
   6.193 +	}
   6.194 +
   6.195 +	for(i=0; i<gmap->crange; i++) {
   6.196 +		int h;
   6.197 +
   6.198 +		FT_Load_Char(face, i + cstart, 0);
   6.199 +		h = FTSZ_TO_PIXELS(face->glyph->metrics.height);
   6.200 +
   6.201 +		if(h > max_height) {
   6.202 +			max_height = h;
   6.203 +		}
   6.204 +		total_width += FTSZ_TO_PIXELS(face->glyph->metrics.width) + padding;
   6.205 +	}
   6.206 +
   6.207 +	calc_best_size(total_width, max_height, padding, 1, &gmap->xsz, &gmap->ysz);
   6.208 +
   6.209 +	if(!(gmap->pixels = malloc(gmap->xsz * gmap->ysz))) {
   6.210 +		free(gmap->glyphs);
   6.211 +		free(gmap);
   6.212 +		return 0;
   6.213 +	}
   6.214 +	memset(gmap->pixels, 0, gmap->xsz * gmap->ysz);
   6.215 +
   6.216 +	gx = padding;
   6.217 +	gy = padding;
   6.218 +
   6.219 +	for(i=0; i<gmap->crange; i++) {
   6.220 +		float gwidth, gheight;
   6.221 +		unsigned char *src, *dst;
   6.222 +		FT_GlyphSlot glyph;
   6.223 +
   6.224 +		FT_Load_Char(face, i + cstart, FT_LOAD_RENDER);
   6.225 +		glyph = face->glyph;
   6.226 +		gwidth = FTSZ_TO_PIXELS((float)glyph->metrics.width);
   6.227 +		gheight = FTSZ_TO_PIXELS((float)glyph->metrics.height);
   6.228 +
   6.229 +		if(gx > gmap->xsz - gwidth - padding) {
   6.230 +			gx = padding;
   6.231 +			gy += max_height + padding;
   6.232 +		}
   6.233 +
   6.234 +		src = glyph->bitmap.buffer;
   6.235 +		dst = gmap->pixels + gy * gmap->xsz + gx;
   6.236 +
   6.237 +		for(j=0; j<glyph->bitmap.rows; j++) {
   6.238 +			memcpy(dst, src, glyph->bitmap.width);
   6.239 +			dst += gmap->xsz;
   6.240 +			src += glyph->bitmap.pitch;
   6.241 +		}
   6.242 +
   6.243 +		gmap->glyphs[i].code = i;
   6.244 +		gmap->glyphs[i].x = gx - 1;
   6.245 +		gmap->glyphs[i].y = gy - 1;
   6.246 +		gmap->glyphs[i].width = gwidth + 2;
   6.247 +		gmap->glyphs[i].height = gheight + 2;
   6.248 +		gmap->glyphs[i].orig_x = -FTSZ_TO_PIXELS((float)glyph->metrics.horiBearingX) + 1;
   6.249 +		gmap->glyphs[i].orig_y = FTSZ_TO_PIXELS((float)glyph->metrics.height - glyph->metrics.horiBearingY) + 1;
   6.250 +		gmap->glyphs[i].advance = FTSZ_TO_PIXELS((float)glyph->metrics.horiAdvance);
   6.251 +		/* also precalc normalized */
   6.252 +		gmap->glyphs[i].nx = (float)gmap->glyphs[i].x / (float)gmap->xsz;
   6.253 +		gmap->glyphs[i].ny = (float)gmap->glyphs[i].y / (float)gmap->ysz;
   6.254 +		gmap->glyphs[i].nwidth = (float)gmap->glyphs[i].width / (float)gmap->xsz;
   6.255 +		gmap->glyphs[i].nheight = (float)gmap->glyphs[i].height / (float)gmap->ysz;
   6.256 +
   6.257 +		gx += gwidth + padding;
   6.258 +	}
   6.259 +
   6.260 +	/* add it to the glyphmaps list of the font */
   6.261 +	gmap->next = fnt->gmaps;
   6.262 +	fnt->gmaps = gmap;
   6.263 +
   6.264 +	return gmap;
   6.265 +}
   6.266 +#endif	/* USE_FREETYPE */
   6.267 +
   6.268 +void dtx_free_glyphmap(struct dtx_glyphmap *gmap)
   6.269 +{
   6.270 +	if(gmap) {
   6.271 +		free(gmap->pixels);
   6.272 +		free(gmap->glyphs);
   6.273 +		free(gmap);
   6.274 +	}
   6.275 +}
   6.276 +
   6.277 +unsigned char *dtx_get_glyphmap_pixels(struct dtx_glyphmap *gmap)
   6.278 +{
   6.279 +	return gmap->pixels;
   6.280 +}
   6.281 +
   6.282 +int dtx_get_glyphmap_width(struct dtx_glyphmap *gmap)
   6.283 +{
   6.284 +	return gmap->xsz;
   6.285 +}
   6.286 +
   6.287 +int dtx_get_glyphmap_height(struct dtx_glyphmap *gmap)
   6.288 +{
   6.289 +	return gmap->ysz;
   6.290 +}
   6.291 +
   6.292 +struct dtx_glyphmap *dtx_load_glyphmap(const char *fname)
   6.293 +{
   6.294 +	FILE *fp;
   6.295 +	struct dtx_glyphmap *gmap;
   6.296 +
   6.297 +	if(!(fp = fopen(fname, "r"))) {
   6.298 +		return 0;
   6.299 +	}
   6.300 +	gmap = dtx_load_glyphmap_stream(fp);
   6.301 +	fclose(fp);
   6.302 +	return gmap;
   6.303 +}
   6.304 +
   6.305 +struct dtx_glyphmap *dtx_load_glyphmap_stream(FILE *fp)
   6.306 +{
   6.307 +	char buf[512];
   6.308 +	int hdr_lines = 0;
   6.309 +	struct dtx_glyphmap *gmap;
   6.310 +	struct glyph *glyphs = 0;
   6.311 +	int min_code = INT_MAX;
   6.312 +	int max_code = INT_MIN;
   6.313 +	int i, max_pixval, num_pixels;
   6.314 +
   6.315 +	if(!(gmap = calloc(1, sizeof *gmap))) {
   6.316 +		fperror("failed to allocate glyphmap");
   6.317 +		return 0;
   6.318 +	}
   6.319 +
   6.320 +	while(hdr_lines < 3) {
   6.321 +		char *line = buf;
   6.322 +		if(!fgets(buf, sizeof buf, fp)) {
   6.323 +			fperror("unexpected end of file");
   6.324 +			goto err;
   6.325 +		}
   6.326 +
   6.327 +		while(isspace(*line)) {
   6.328 +			line++;
   6.329 +		}
   6.330 +
   6.331 +		if(line[0] == '#') {
   6.332 +			struct glyph *g;
   6.333 +			int c;
   6.334 +			float x, y, xsz, ysz, res;
   6.335 +
   6.336 +			res = sscanf(line + 1, "%d: %fx%f+%f+%f\n", &c, &xsz, &ysz, &x, &y);
   6.337 +			if(res != 5) {
   6.338 +				fprintf(stderr, "%s: invalid glyph info line\n", __func__);
   6.339 +				goto err;
   6.340 +			}
   6.341 +
   6.342 +			if(!(g = malloc(sizeof *g))) {
   6.343 +				fperror("failed to allocate glyph");
   6.344 +				goto err;
   6.345 +			}
   6.346 +			g->code = c;
   6.347 +			g->x = x;
   6.348 +			g->y = y;
   6.349 +			g->width = xsz;
   6.350 +			g->height = ysz;
   6.351 +			g->next = glyphs;
   6.352 +			glyphs = g;
   6.353 +
   6.354 +			if(c < min_code) {
   6.355 +				min_code = c;
   6.356 +			}
   6.357 +			if(c > max_code) {
   6.358 +				max_code = c;
   6.359 +			}
   6.360 +		} else {
   6.361 +			switch(hdr_lines) {
   6.362 +			case 0:
   6.363 +				if(0[line] != 'P' || 1[line] != '6') {
   6.364 +					fprintf(stderr, "%s: invalid file format (magic)\n", __func__);
   6.365 +					goto err;
   6.366 +				}
   6.367 +				break;
   6.368 +
   6.369 +			case 1:
   6.370 +				if(sscanf(line, "%d %d", &gmap->xsz, &gmap->ysz) != 2) {
   6.371 +					fprintf(stderr, "%s: invalid file format (dim)\n", __func__);
   6.372 +					goto err;
   6.373 +				}
   6.374 +				break;
   6.375 +
   6.376 +			case 2:
   6.377 +				{
   6.378 +					char *endp;
   6.379 +					max_pixval = strtol(line, &endp, 10);
   6.380 +					if(endp == line) {
   6.381 +						fprintf(stderr, "%s: invalid file format (maxval)\n", __func__);
   6.382 +						goto err;
   6.383 +					}
   6.384 +				}
   6.385 +				break;
   6.386 +
   6.387 +			default:
   6.388 +				break;	/* can't happen */
   6.389 +			}
   6.390 +			hdr_lines++;
   6.391 +		}
   6.392 +	}
   6.393 +
   6.394 +	num_pixels = gmap->xsz * gmap->ysz;
   6.395 +	if(!(gmap->pixels = malloc(num_pixels))) {
   6.396 +		fperror("failed to allocate pixels");
   6.397 +		goto err;
   6.398 +	}
   6.399 +
   6.400 +	for(i=0; i<num_pixels; i++) {
   6.401 +		long c = fgetc(fp);
   6.402 +		if(c == -1) {
   6.403 +			fprintf(stderr, "unexpected end of file while reading pixels\n");
   6.404 +			goto err;
   6.405 +		}
   6.406 +		gmap->pixels[i] = 255 * c / max_pixval;
   6.407 +		fseek(fp, 2, SEEK_CUR);
   6.408 +	}
   6.409 +
   6.410 +	gmap->cstart = min_code;
   6.411 +	gmap->cend = max_code + 1;
   6.412 +	gmap->crange = gmap->cend - gmap->cstart;
   6.413 +
   6.414 +	if(!(gmap->glyphs = calloc(gmap->crange, sizeof *gmap->glyphs))) {
   6.415 +		fperror("failed to allocate glyph info");
   6.416 +		goto err;
   6.417 +	}
   6.418 +
   6.419 +	while(glyphs) {
   6.420 +		struct glyph *g = glyphs;
   6.421 +		glyphs = glyphs->next;
   6.422 +
   6.423 +		gmap->glyphs[g->code - gmap->cstart] = *g;
   6.424 +		free(g);
   6.425 +	}
   6.426 +	return gmap;
   6.427 +
   6.428 +err:
   6.429 +	dtx_free_glyphmap(gmap);
   6.430 +	while(glyphs) {
   6.431 +		void *tmp = glyphs;
   6.432 +		glyphs = glyphs->next;
   6.433 +		free(tmp);
   6.434 +	}
   6.435 +	return 0;
   6.436 +}
   6.437 +
   6.438 +int dtx_save_glyphmap(const char *fname, const struct dtx_glyphmap *gmap)
   6.439 +{
   6.440 +	FILE *fp;
   6.441 +	int res;
   6.442 +
   6.443 +	if(!(fp = fopen(fname, "wb"))) {
   6.444 +		fprintf(stderr, "%s: failed to open file: %s: %s\n", __func__, fname, strerror(errno));
   6.445 +		return -1;
   6.446 +	}
   6.447 +	res = dtx_save_glyphmap_stream(fp, gmap);
   6.448 +	fclose(fp);
   6.449 +	return res;
   6.450 +}
   6.451 +
   6.452 +int dtx_save_glyphmap_stream(FILE *fp, const struct dtx_glyphmap *gmap)
   6.453 +{
   6.454 +	int i, num_pixels;
   6.455 +	struct glyph *g = gmap->glyphs;
   6.456 +
   6.457 +	fprintf(fp, "P6\n%d %d\n", gmap->xsz, gmap->ysz);
   6.458 +	for(i=0; i<gmap->crange; i++) {
   6.459 +		fprintf(fp, "# %d: %fx%f+%f+%f\n", g->code, g->width, g->height, g->x, g->y);
   6.460 +		g++;
   6.461 +	}
   6.462 +	fprintf(fp, "255\n");
   6.463 +
   6.464 +	num_pixels = gmap->xsz * gmap->ysz;
   6.465 +	for(i=0; i<num_pixels; i++) {
   6.466 +		int c = gmap->pixels[i];
   6.467 +		fputc(c, fp);
   6.468 +		fputc(c, fp);
   6.469 +		fputc(c, fp);
   6.470 +	}
   6.471 +	return 0;
   6.472 +}
   6.473 +
   6.474 +
   6.475 +void dtx_use_font(struct dtx_font *fnt, int sz)
   6.476 +{
   6.477 +	dtx_gl_init();
   6.478 +
   6.479 +	dtx_font = fnt;
   6.480 +	dtx_font_sz = sz;
   6.481 +}
   6.482 +
   6.483 +void dtx_glyph_box(int code, struct dtx_box *box)
   6.484 +{
   6.485 +	int cidx;
   6.486 +	struct dtx_glyphmap *gmap;
   6.487 +	gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code);
   6.488 +
   6.489 +	cidx = code - gmap->cstart;
   6.490 +
   6.491 +	box->x = gmap->glyphs[cidx].orig_x;
   6.492 +	box->y = gmap->glyphs[cidx].orig_y;
   6.493 +	box->width = gmap->glyphs[cidx].width;
   6.494 +	box->height = gmap->glyphs[cidx].height;
   6.495 +}
   6.496 +
   6.497 +float dtx_glyph_width(int code)
   6.498 +{
   6.499 +	struct dtx_box box;
   6.500 +	dtx_glyph_box(code, &box);
   6.501 +	return box.width;
   6.502 +}
   6.503 +
   6.504 +float dtx_glyph_height(int code)
   6.505 +{
   6.506 +	struct dtx_box box;
   6.507 +	dtx_glyph_box(code, &box);
   6.508 +	return box.height;
   6.509 +}
   6.510 +
   6.511 +void dtx_string_box(const char *str, struct dtx_box *box)
   6.512 +{
   6.513 +	int code;
   6.514 +	float pos_x = 0.0f, pos_y = 0.0f;
   6.515 +	struct glyph *g = 0;
   6.516 +	float x0, y0, x1, y1;
   6.517 +
   6.518 +	x0 = y0 = FLT_MAX;
   6.519 +	x1 = y1 = -FLT_MAX;
   6.520 +
   6.521 +	while(*str) {
   6.522 +		float px, py;
   6.523 +		struct dtx_glyphmap *gmap;
   6.524 +
   6.525 +		code = dtx_utf8_char_code(str);
   6.526 +		str = dtx_utf8_next_char((char*)str);
   6.527 +
   6.528 +		px = pos_x;
   6.529 +		py = pos_y;
   6.530 +
   6.531 +		if((gmap = dtx_proc_char(code, &pos_x, &pos_y))) {
   6.532 +			g = gmap->glyphs + code - gmap->cstart;
   6.533 +
   6.534 +			if(px + g->orig_x < x0) {
   6.535 +				x0 = px + g->orig_x;
   6.536 +			}
   6.537 +			if(py - g->orig_y < y0) {
   6.538 +				y0 = py - g->orig_y;
   6.539 +			}
   6.540 +			if(px + g->orig_x + g->width > x1) {
   6.541 +				x1 = px + g->orig_x + g->width;
   6.542 +			}
   6.543 +			if(py - g->orig_y + g->height > y1) {
   6.544 +				y1 = py - g->orig_y + g->height;
   6.545 +			}
   6.546 +		}
   6.547 +	}
   6.548 +
   6.549 +	box->x = x0;
   6.550 +	box->y = y0;
   6.551 +	box->width = x1 - x0;
   6.552 +	box->height = y1 - y0;
   6.553 +}
   6.554 +
   6.555 +float dtx_string_width(const char *str)
   6.556 +{
   6.557 +	struct dtx_box box;
   6.558 +
   6.559 +	dtx_string_box(str, &box);
   6.560 +	return box.width;
   6.561 +}
   6.562 +
   6.563 +float dtx_string_height(const char *str)
   6.564 +{
   6.565 +	struct dtx_box box;
   6.566 +
   6.567 +	dtx_string_box(str, &box);
   6.568 +	return box.height;
   6.569 +}
   6.570 +
   6.571 +float dtx_char_pos(const char *str, int n)
   6.572 +{
   6.573 +	int i;
   6.574 +	float pos = 0.0;
   6.575 +	struct dtx_glyphmap *gmap;
   6.576 +
   6.577 +	for(i=0; i<n; i++) {
   6.578 +		int code = dtx_utf8_char_code(str);
   6.579 +		str = dtx_utf8_next_char((char*)str);
   6.580 +
   6.581 +		gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code);
   6.582 +		pos += gmap->glyphs[i].advance;
   6.583 +	}
   6.584 +	return pos;
   6.585 +}
   6.586 +
   6.587 +int dtx_char_at_pt(const char *str, float pt)
   6.588 +{
   6.589 +	int i;
   6.590 +	float prev_pos = 0.0f, pos = 0.0f;
   6.591 +	struct dtx_glyphmap *gmap;
   6.592 +
   6.593 +	for(i=0; *str; i++) {
   6.594 +		int code = dtx_utf8_char_code(str);
   6.595 +		str = dtx_utf8_next_char((char*)str);
   6.596 +
   6.597 +		gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code);
   6.598 +		pos += gmap->glyphs[i].advance;
   6.599 +
   6.600 +		if(fabs(pt - prev_pos) < fabs(pt - pos)) {
   6.601 +			break;
   6.602 +		}
   6.603 +		prev_pos = pos;
   6.604 +	}
   6.605 +	return i;
   6.606 +}
   6.607 +
   6.608 +struct dtx_glyphmap *dtx_proc_char(int code, float *xpos, float *ypos)
   6.609 +{
   6.610 +	struct dtx_glyphmap *gmap;
   6.611 +	gmap = dtx_get_font_glyphmap(dtx_font, dtx_font_sz, code);
   6.612 +
   6.613 +	switch(code) {
   6.614 +	case '\n':
   6.615 +		*xpos = 0.0;
   6.616 +		if(gmap) {
   6.617 +			*ypos -= gmap->line_advance;
   6.618 +		}
   6.619 +		return 0;
   6.620 +
   6.621 +	case '\t':
   6.622 +		if(gmap) {
   6.623 +			*xpos = (fmod(*xpos, 4.0) + 4.0) * gmap->glyphs[0].advance;
   6.624 +		}
   6.625 +		return 0;
   6.626 +
   6.627 +	case '\r':
   6.628 +		*xpos = 0.0;
   6.629 +		return 0;
   6.630 +
   6.631 +	default:
   6.632 +		break;
   6.633 +	}
   6.634 +
   6.635 +	if(gmap) {
   6.636 +		*xpos += gmap->glyphs[code - gmap->cstart].advance;
   6.637 +	}
   6.638 +	return gmap;
   6.639 +}
   6.640 +
   6.641 +static void calc_best_size(int total_width, int max_glyph_height, int padding, int pow2, int *imgw, int *imgh)
   6.642 +{
   6.643 +	int xsz, ysz, num_rows;
   6.644 +	float aspect;
   6.645 +
   6.646 +	for(xsz=2; xsz<=MAX_IMG_WIDTH; xsz *= 2) {
   6.647 +		num_rows = total_width / xsz + 1;
   6.648 +
   6.649 +		/* take into account the one extra padding for each row after the first */
   6.650 +		num_rows = (total_width + padding * (num_rows - 1)) / xsz + 1;
   6.651 +
   6.652 +		ysz = num_rows * (max_glyph_height + padding) + padding;
   6.653 +		if(pow2) {
   6.654 +			ysz = next_pow2(ysz);
   6.655 +		}
   6.656 +		aspect = (float)xsz / (float)ysz;
   6.657 +
   6.658 +		if(aspect >= 1.0) {
   6.659 +			break;
   6.660 +		}
   6.661 +	}
   6.662 +
   6.663 +	if(xsz > MAX_IMG_WIDTH) {
   6.664 +		xsz = MAX_IMG_WIDTH;
   6.665 +	}
   6.666 +
   6.667 +	*imgw = xsz;
   6.668 +	*imgh = ysz;
   6.669 +}
   6.670 +
   6.671 +
   6.672 +static int next_pow2(int x)
   6.673 +{
   6.674 +	x--;
   6.675 +	x = (x >> 1) | x;
   6.676 +	x = (x >> 2) | x;
   6.677 +	x = (x >> 4) | x;
   6.678 +	x = (x >> 8) | x;
   6.679 +	x = (x >> 16) | x;
   6.680 +	return x + 1;
   6.681 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/prototype/drawtext/utf8.c	Thu Aug 23 18:03:11 2012 +0300
     7.3 @@ -0,0 +1,154 @@
     7.4 +/*
     7.5 +libdrawtext - a simple library for fast text rendering in OpenGL
     7.6 +Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
     7.7 +
     7.8 +This program is free software: you can redistribute it and/or modify
     7.9 +it under the terms of the GNU Lesser General Public License as published by
    7.10 +the Free Software Foundation, either version 3 of the License, or
    7.11 +(at your option) any later version.
    7.12 +
    7.13 +This program is distributed in the hope that it will be useful,
    7.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
    7.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    7.16 +GNU Lesser General Public License for more details.
    7.17 +
    7.18 +You should have received a copy of the GNU Lesser General Public License
    7.19 +along with this program.  If not, see <http://www.gnu.org/licenses/>.
    7.20 +*/
    7.21 +#include "drawtext.h"
    7.22 +
    7.23 +#define	U8_IS_FIRST(x)		(((((x) >> 7) & 1) == 0) || ((((x) >> 6) & 3) == 3))
    7.24 +
    7.25 +static const char first_mask[] = {
    7.26 +	0,
    7.27 +	0x7f,	/* single byte, 7 bits valid */
    7.28 +	0x1f,	/* two-bytes, 5 bits valid */
    7.29 +	0xf,	/* three-bytes, 4 bits valid */
    7.30 +	0x7		/* four-bytes, 3 bits valid */
    7.31 +};
    7.32 +static const char first_shift[] = { 0, 7, 5, 4, 3 };	/* see above */
    7.33 +
    7.34 +#define CONT_PREFIX	0x80
    7.35 +#define CONT_MASK	0x3f
    7.36 +#define CONT_SHIFT	6
    7.37 +
    7.38 +/* last charcodes for 1, 2, 3 or 4-byte utf8 chars */
    7.39 +static const int utf8_lastcode[] = { 0x7f, 0x7ff, 0xfff, 0x1fffff };
    7.40 +
    7.41 +#define prefix_mask(x)	(~first_mask[x])
    7.42 +#define prefix(x)		((prefix_mask(x) << 1) & 0xff)
    7.43 +
    7.44 +
    7.45 +char *dtx_utf8_next_char(char *str)
    7.46 +{
    7.47 +	return str + dtx_utf8_nbytes(str);
    7.48 +}
    7.49 +
    7.50 +int dtx_utf8_char_code(const char *str)
    7.51 +{
    7.52 +	int i, nbytes, shift, code = 0;
    7.53 +	int mask;
    7.54 +
    7.55 +	if(!U8_IS_FIRST(*str)) {
    7.56 +		return -1;
    7.57 +	}
    7.58 +
    7.59 +	nbytes = dtx_utf8_nbytes(str);
    7.60 +	mask = first_mask[nbytes];
    7.61 +	shift = 0;
    7.62 +
    7.63 +	for(i=0; i<nbytes; i++) {
    7.64 +		if(!*str) {
    7.65 +			break;
    7.66 +		}
    7.67 +
    7.68 +		code = (code << shift) | (*str++ & mask);
    7.69 +		mask = 0x3f;
    7.70 +		shift = 6;
    7.71 +	}
    7.72 +	return code;
    7.73 +}
    7.74 +
    7.75 +int dtx_utf8_nbytes(const char *str)
    7.76 +{
    7.77 +	int i, numset = 0;
    7.78 +	int c = *str;
    7.79 +
    7.80 +	if(!U8_IS_FIRST(c)) {
    7.81 +		for(i=0; !U8_IS_FIRST(str[i]); i++);
    7.82 +		return i;
    7.83 +	}
    7.84 +
    7.85 +	/* count the leading 1s */
    7.86 +	for(i=0; i<4; i++) {
    7.87 +		if(((c >> (7 - i)) & 1) == 0) {
    7.88 +			break;
    7.89 +		}
    7.90 +		numset++;
    7.91 +	}
    7.92 +
    7.93 +	if(!numset) {
    7.94 +		return 1;
    7.95 +	}
    7.96 +	return numset;
    7.97 +}
    7.98 +
    7.99 +int dtx_utf8_char_count(const char *str)
   7.100 +{
   7.101 +	int n = 0;
   7.102 +
   7.103 +	while(*str) {
   7.104 +		n++;
   7.105 +		str = dtx_utf8_next_char((char*)str);
   7.106 +	}
   7.107 +	return n;
   7.108 +}
   7.109 +
   7.110 +size_t dtx_utf8_from_char_code(int code, char *buf)
   7.111 +{
   7.112 +	size_t nbytes = 0;
   7.113 +	int i;
   7.114 +
   7.115 +	for(i=0; i<4; i++) {
   7.116 +		if(code <= utf8_lastcode[i]) {
   7.117 +			nbytes = i + 1;
   7.118 +			break;
   7.119 +		}
   7.120 +	}
   7.121 +
   7.122 +	if(!nbytes && buf) {
   7.123 +		for(i=0; i<nbytes; i++) {
   7.124 +			int idx = nbytes - i - 1;
   7.125 +			int mask, shift, prefix;
   7.126 +
   7.127 +			if(idx > 0) {
   7.128 +				mask = CONT_MASK;
   7.129 +				shift = CONT_SHIFT;
   7.130 +				prefix = CONT_PREFIX;
   7.131 +			} else {
   7.132 +				mask = first_mask[nbytes];
   7.133 +				shift = first_shift[nbytes];
   7.134 +				prefix = prefix(nbytes);
   7.135 +			}
   7.136 +
   7.137 +			buf[idx] = (code & mask) | (prefix & ~mask);
   7.138 +			code >>= shift;
   7.139 +		}
   7.140 +	}
   7.141 +	return nbytes;
   7.142 +}
   7.143 +
   7.144 +size_t dtx_utf8_from_string(const wchar_t *str, char *buf)
   7.145 +{
   7.146 +	size_t nbytes = 0;
   7.147 +	char *ptr = buf;
   7.148 +
   7.149 +	while(*str) {
   7.150 +		int cbytes = dtx_utf8_from_char_code(*str++, ptr);
   7.151 +		if(ptr) {
   7.152 +			ptr += cbytes;
   7.153 +		}
   7.154 +		nbytes += cbytes;
   7.155 +	}
   7.156 +	return nbytes;
   7.157 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/prototype/src/cmdcon.cc	Thu Aug 23 18:03:11 2012 +0300
     8.3 @@ -0,0 +1,153 @@
     8.4 +#include <stdlib.h>
     8.5 +#include <iostream>
     8.6 +#include <sstream>
     8.7 +#include <string>
     8.8 +#include "opengl.h"
     8.9 +#include "cmdcon.h"
    8.10 +#include "drawtext.h"
    8.11 +#include "datapath.h"
    8.12 +#include "cfg.h"
    8.13 +
    8.14 +#define FONT_FILENAME	"droid_sans_mono.ttf"
    8.15 +
    8.16 +static void runcmd();
    8.17 +static void complete();
    8.18 +
    8.19 +static struct dtx_font *font;
    8.20 +
    8.21 +std::string cmdline;
    8.22 +
    8.23 +bool init_cmdcon()
    8.24 +{
    8.25 +	const char *path = datafile_path(FONT_FILENAME);
    8.26 +	if(!path) {
    8.27 +		fprintf(stderr, "failed to locate font file: %s\n", FONT_FILENAME);
    8.28 +		return false;
    8.29 +	}
    8.30 +
    8.31 +	if(!(font = dtx_open_font(path, 12))) {
    8.32 +		fprintf(stderr, "failed to open font file: %s\n", path);
    8.33 +		return false;
    8.34 +	}
    8.35 +	dtx_use_font(font, 12);
    8.36 +	return true;
    8.37 +}
    8.38 +
    8.39 +void cleanup_cmdcon()
    8.40 +{
    8.41 +	if(font) {
    8.42 +		dtx_close_font(font);
    8.43 +	}
    8.44 +}
    8.45 +
    8.46 +void cmdcon_keypress(int key)
    8.47 +{
    8.48 +	if(isprint(key)) {
    8.49 +		cmdline.push_back(key);
    8.50 +		return;
    8.51 +	}
    8.52 +
    8.53 +	switch(key) {
    8.54 +	case '\n':
    8.55 +	case '\r':
    8.56 +		runcmd();
    8.57 +		cmdline.clear();
    8.58 +		break;
    8.59 +
    8.60 +	case '\t':
    8.61 +		complete();
    8.62 +		break;
    8.63 +
    8.64 +	case '\b':
    8.65 +		if(!cmdline.empty()) {
    8.66 +			cmdline.erase(cmdline.back());
    8.67 +		}
    8.68 +		break;
    8.69 +
    8.70 +	default:
    8.71 +		break;
    8.72 +	}
    8.73 +}
    8.74 +
    8.75 +void draw_cmdcon()
    8.76 +{
    8.77 +	glMatrixMode(GL_PROJECTION);
    8.78 +	glPushMatrix();
    8.79 +	glLoadIdentity();
    8.80 +	glOrtho(0, cfg.width, -cfg.height, 0, -1, 1);
    8.81 +	glMatrixMode(GL_MODELVIEW);
    8.82 +	glPushMatrix();
    8.83 +	glLoadIdentity();
    8.84 +
    8.85 +	glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
    8.86 +	glEnable(GL_BLEND);
    8.87 +	glDisable(GL_DEPTH_TEST);
    8.88 +	glDisable(GL_LIGHTING);
    8.89 +	glUseProgram(0);
    8.90 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    8.91 +
    8.92 +	glBegin(GL_QUADS);
    8.93 +	glColor4f(0.4, 0.4, 0.4, 0.5);
    8.94 +	glVertex2f(-10, -10);
    8.95 +	glVertex2f(10, -10);
    8.96 +	glVertex2f(10, 10);
    8.97 +	glVertex2f(-10, 10);
    8.98 +	glEnd();
    8.99 +
   8.100 +	glTranslatef(cfg.width / 2, cfg.height / 2, 0);
   8.101 +
   8.102 +	glColor4f(0.2, 0.9, 0.3, 1.0);
   8.103 +	dtx_string(cmdline.c_str());
   8.104 +	dtx_flush();
   8.105 +
   8.106 +	glPopAttrib();
   8.107 +
   8.108 +	glMatrixMode(GL_PROJECTION);
   8.109 +	glPopMatrix();
   8.110 +	glMatrixMode(GL_MODELVIEW);
   8.111 +	glPopMatrix();
   8.112 +}
   8.113 +
   8.114 +static bool cmd_toggle_wire(std::stringstream &strin)
   8.115 +{
   8.116 +	static bool wire;
   8.117 +	wire = !wire;
   8.118 +	glPolygonMode(GL_FRONT_AND_BACK, wire ? GL_LINE : GL_FILL);
   8.119 +	return true;
   8.120 +}
   8.121 +
   8.122 +static bool cmd_quit(std::stringstream &strin)
   8.123 +{
   8.124 +	exit(0);
   8.125 +}
   8.126 +
   8.127 +static struct {
   8.128 +	std::string name;
   8.129 +	bool (*func)(std::stringstream &strin);
   8.130 +} cmd[] = {
   8.131 +	{"wire", cmd_toggle_wire},
   8.132 +	{"quit", cmd_quit},
   8.133 +	{"exit", cmd_quit}
   8.134 +};
   8.135 +#define NUM_CMD		(int)(sizeof cmd / sizeof *cmd)
   8.136 +
   8.137 +static void runcmd()
   8.138 +{
   8.139 +	std::stringstream strin(cmdline);
   8.140 +
   8.141 +	std::string token;
   8.142 +	strin >> token;
   8.143 +
   8.144 +	for(int i=0; i<NUM_CMD; i++) {
   8.145 +		if(token == cmd[i].name) {
   8.146 +			cmd[i].func(strin);
   8.147 +			return;
   8.148 +		}
   8.149 +	}
   8.150 +
   8.151 +	std::cerr << "unrecognized command: " << token << std::endl;
   8.152 +}
   8.153 +
   8.154 +static void complete()
   8.155 +{
   8.156 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/prototype/src/cmdcon.h	Thu Aug 23 18:03:11 2012 +0300
     9.3 @@ -0,0 +1,11 @@
     9.4 +#ifndef CMDCON_H_
     9.5 +#define CMDCON_H_
     9.6 +
     9.7 +bool init_cmdcon();
     9.8 +void cleanup_cmdcon();
     9.9 +
    9.10 +void cmdcon_keypress(int key);
    9.11 +
    9.12 +void draw_cmdcon();
    9.13 +
    9.14 +#endif	// CMDCON_H_
    10.1 --- a/prototype/src/main.cc	Thu Aug 23 00:10:10 2012 +0300
    10.2 +++ b/prototype/src/main.cc	Thu Aug 23 18:03:11 2012 +0300
    10.3 @@ -8,6 +8,7 @@
    10.4  #include "datapath.h"
    10.5  #include "tileset.h"
    10.6  #include "renderer.h"
    10.7 +#include "cmdcon.h"
    10.8  #include "cfg.h"
    10.9  
   10.10  bool init(int xsz, int ysz);
   10.11 @@ -21,6 +22,7 @@
   10.12  void reshape(int x, int y);
   10.13  void keyb(unsigned char key, int x, int y);
   10.14  void key_release(unsigned char key, int x, int y);
   10.15 +void keyb_con(unsigned char key, int x, int y);
   10.16  void mouse(int bn, int state, int x, int y);
   10.17  void motion(int x, int y);
   10.18  
   10.19 @@ -33,6 +35,7 @@
   10.20  static float stereo_focus_dist = 0.25;
   10.21  static float stereo_eye_sep = stereo_focus_dist / 30.0;
   10.22  
   10.23 +static bool show_con;
   10.24  
   10.25  int main(int argc, char **argv)
   10.26  {
   10.27 @@ -128,7 +131,7 @@
   10.28  		glLoadIdentity();
   10.29  		view_matrix(-1);
   10.30  
   10.31 -		render_deferred(level);
   10.32 +		draw();
   10.33  
   10.34  		glDrawBuffer(GL_BACK_RIGHT);
   10.35  
   10.36 @@ -139,8 +142,7 @@
   10.37  		glLoadIdentity();
   10.38  		view_matrix(1);
   10.39  
   10.40 -		render_deferred(level);
   10.41 -
   10.42 +		draw();
   10.43  	} else {
   10.44  		glMatrixMode(GL_PROJECTION);
   10.45  		glLoadIdentity();
   10.46 @@ -149,7 +151,7 @@
   10.47  		glLoadIdentity();
   10.48  		view_matrix(0);
   10.49  
   10.50 -		render_deferred(level);
   10.51 +		draw();
   10.52  	}
   10.53  
   10.54  	glutSwapBuffers();
   10.55 @@ -158,6 +160,15 @@
   10.56  	usleep(10000);
   10.57  }
   10.58  
   10.59 +void draw()
   10.60 +{
   10.61 +	render_deferred(level);
   10.62 +
   10.63 +	if(show_con) {
   10.64 +		draw_cmdcon();
   10.65 +	}
   10.66 +}
   10.67 +
   10.68  void view_matrix(int eye)
   10.69  {
   10.70  	float offs = stereo_eye_sep * eye * 0.5;
   10.71 @@ -225,6 +236,13 @@
   10.72  	case 27:
   10.73  		exit(0);
   10.74  
   10.75 +	case '`':
   10.76 +		show_con = true;
   10.77 +		glutKeyboardFunc(keyb_con);
   10.78 +		glutKeyboardUpFunc(0);
   10.79 +		glutPostRedisplay();
   10.80 +		break;
   10.81 +
   10.82  	case 'z':
   10.83  		stereo_shift_pressed = true;
   10.84  		break;
   10.85 @@ -265,6 +283,18 @@
   10.86  	keystate[key] = false;
   10.87  }
   10.88  
   10.89 +void keyb_con(unsigned char key, int x, int y)
   10.90 +{
   10.91 +	if(key == '`' || key == 27) {
   10.92 +		show_con = false;
   10.93 +		glutKeyboardFunc(keyb);
   10.94 +		glutKeyboardUpFunc(key_release);
   10.95 +		glutPostRedisplay();
   10.96 +	} else {
   10.97 +		cmdcon_keypress(key);
   10.98 +	}
   10.99 +}
  10.100 +
  10.101  static int prev_x, prev_y;
  10.102  static bool bnstate[32];
  10.103