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