libdrawtext

view src/drawgl.c @ 57:7b01e04c9c8b

added copyright notices
author John Tsiombikas <nuclear@mutantstargoat.com>
date Fri, 16 Sep 2011 08:42:07 +0300
parents fe0c54e574ae
children 7e0c702f1223
line source
1 /*
2 libdrawtext - a simple library for fast text rendering in OpenGL
3 Copyright (C) 2011 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #ifndef NO_OPENGL
19 #include <math.h>
20 #include <ctype.h>
22 #include <stdlib.h>
24 #if defined(__IPHONE_3_0) || defined(__IPHONE_3_2) || defined(__IPHONE_4_0)
25 #include <OpenGLES/ES2/gl.h>
26 #else
27 #include <GL/glew.h>
28 #endif
30 #include "drawtext.h"
31 #include "drawtext_impl.h"
33 struct vertex {
34 float x, y;
35 float s, t;
36 };
38 struct quad {
39 struct vertex v[6];
40 };
42 static int init(void);
43 static void cleanup(void);
44 static void add_glyph(struct glyph *g, float x, float y);
46 #define QBUF_SZ 512
47 static struct quad *qbuf;
48 static int num_quads;
49 static int vattr = -1;
50 static int tattr = -1;
51 static unsigned int font_tex;
52 static int buf_mode = DTX_NBF;
54 static struct dtx_font *font;
55 static int font_sz;
58 static int init(void)
59 {
60 if(qbuf) {
61 return 0; /* already initialized */
62 }
64 glewInit();
66 if(!(qbuf = malloc(QBUF_SZ * sizeof *qbuf))) {
67 return -1;
68 }
69 num_quads = 0;
71 atexit(cleanup);
72 return 0;
73 }
75 static void cleanup(void)
76 {
77 free(qbuf);
78 }
81 void dtx_use_font(struct dtx_font *fnt, int sz)
82 {
83 init();
85 font = fnt;
86 font_sz = sz;
87 }
89 void dtx_vertex_attribs(int vert_attr, int tex_attr)
90 {
91 vattr = vert_attr;
92 tattr = tex_attr;
93 }
95 static void set_glyphmap_texture(struct dtx_glyphmap *gmap)
96 {
97 if(!gmap->tex) {
98 glGenTextures(1, &gmap->tex);
99 glBindTexture(GL_TEXTURE_2D, gmap->tex);
100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
101 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
102 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
103 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
105 #ifdef GL_ES
106 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gmap->xsz, gmap->ysz, 0, GL_ALPHA, GL_UNSIGNED_BYTE, gmap->pixels);
107 glGenerateMipmap(GL_TEXTURE_2D);
108 #else
109 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_ALPHA, gmap->xsz, gmap->ysz, GL_ALPHA, GL_UNSIGNED_BYTE, gmap->pixels);
110 #endif
111 }
113 if(font_tex != gmap->tex) {
114 dtx_flush();
115 }
116 font_tex = gmap->tex;
117 }
119 void dtx_glyph(int code)
120 {
121 struct dtx_glyphmap *gmap;
123 if(!font || !(gmap = dtx_get_font_glyphmap(font, font_sz, code))) {
124 return;
125 }
126 set_glyphmap_texture(gmap);
128 add_glyph(gmap->glyphs + code - gmap->cstart, 0, 0);
129 dtx_flush();
130 }
132 void dtx_string(const char *str)
133 {
134 struct dtx_glyphmap *gmap;
135 int should_flush = buf_mode == DTX_NBF;
136 float pos_x = 0.0f;
137 float pos_y = 0.0f;
139 if(!font) {
140 return;
141 }
143 while(*str) {
144 int code = dtx_utf8_char_code(str);
145 str = dtx_utf8_next_char((char*)str);
147 switch(code) {
148 case '\n':
149 if(buf_mode == DTX_LBF) {
150 should_flush = 1;
151 }
152 pos_x = 0.0;
153 pos_y -= gmap->line_advance;
154 break;
156 case '\t':
157 pos_x = fmod(pos_x, 4.0) + 4.0;
158 break;
160 case '\r':
161 pos_x = 0.0;
162 break;
164 default:
165 if((gmap = dtx_get_font_glyphmap(font, font_sz, code))) {
166 int idx = code - gmap->cstart;
168 set_glyphmap_texture(gmap);
169 add_glyph(gmap->glyphs + idx, pos_x, pos_y);
170 pos_x += gmap->glyphs[idx].advance;
171 }
172 }
173 }
175 if(should_flush) {
176 dtx_flush();
177 }
178 }
180 static void qvertex(struct vertex *v, float x, float y, float s, float t)
181 {
182 v->x = x;
183 v->y = y;
184 v->s = s;
185 v->t = t;
186 }
188 static void add_glyph(struct glyph *g, float x, float y)
189 {
190 struct quad *qptr = qbuf + num_quads;
192 x -= g->orig_x;
193 y -= g->orig_y;
195 qvertex(qptr->v + 0, x, y, g->nx, g->ny + g->nheight);
196 qvertex(qptr->v + 1, x + g->width, y, g->nx + g->nwidth, g->ny + g->nheight);
197 qvertex(qptr->v + 2, x + g->width, y + g->height, g->nx + g->nwidth, g->ny);
199 qvertex(qptr->v + 3, x, y, g->nx, g->ny + g->nheight);
200 qvertex(qptr->v + 4, x + g->width, y + g->height, g->nx + g->nwidth, g->ny);
201 qvertex(qptr->v + 5, x, y + g->height, g->nx, g->ny);
203 if(++num_quads >= QBUF_SZ) {
204 dtx_flush();
205 }
206 }
208 void dtx_flush(void)
209 {
210 if(!num_quads) {
211 return;
212 }
214 #ifndef GL_ES
215 glPushAttrib(GL_ENABLE_BIT);
216 glEnable(GL_TEXTURE_2D);
217 #endif
218 glBindTexture(GL_TEXTURE_2D, font_tex);
220 if(vattr != -1 && glEnableVertexAttribArray) {
221 glEnableVertexAttribArray(vattr);
222 glVertexAttribPointer(vattr, 2, GL_FLOAT, 0, sizeof(struct vertex), qbuf);
223 #ifndef GL_ES
224 } else {
225 glEnableClientState(GL_VERTEX_ARRAY);
226 glVertexPointer(2, GL_FLOAT, sizeof(struct vertex), qbuf);
227 #endif
228 }
229 if(tattr != -1 && glEnableVertexAttribArray) {
230 glEnableVertexAttribArray(tattr);
231 glVertexAttribPointer(tattr, 2, GL_FLOAT, 0, sizeof(struct vertex), &qbuf->v[0].s);
232 #ifndef GL_ES
233 } else {
234 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
235 glTexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), &qbuf->v[0].s);
236 #endif
237 }
239 glEnable(GL_BLEND);
240 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
242 glDepthMask(0);
244 glDrawArrays(GL_TRIANGLES, 0, num_quads * 6);
246 glDepthMask(1);
248 if(vattr != -1 && glDisableVertexAttribArray) {
249 glDisableVertexAttribArray(vattr);
250 #ifndef GL_ES
251 } else {
252 glDisableClientState(GL_VERTEX_ARRAY);
253 #endif
254 }
255 if(tattr != -1 && glDisableVertexAttribArray) {
256 glDisableVertexAttribArray(tattr);
257 #ifndef GL_ES
258 } else {
259 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
260 #endif
261 }
263 #ifndef GL_ES
264 glPopAttrib();
265 #else
266 glDisable(GL_BLEND);
267 #endif
269 num_quads = 0;
270 }
272 #endif /* !def NO_OPENGL */