nuclear@0: #ifndef NO_OPENGL nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: #include nuclear@0: nuclear@0: #if defined(__IPHONE_3_0) || defined(__IPHONE_3_2) || defined(__IPHONE_4_0) nuclear@0: #include nuclear@0: #else nuclear@0: #include nuclear@0: #endif nuclear@0: nuclear@0: #include "drawtext.h" nuclear@0: #include "drawtext_impl.h" nuclear@0: nuclear@0: struct vertex { nuclear@0: float x, y; nuclear@0: float s, t; nuclear@0: }; nuclear@0: nuclear@0: struct quad { nuclear@0: struct vertex v[6]; nuclear@0: }; nuclear@0: nuclear@0: static int init(void); nuclear@0: static void cleanup(void); nuclear@0: static void add_glyph(struct glyph *g, float x, float y); nuclear@0: nuclear@0: #define QBUF_SZ 512 nuclear@0: static struct quad *qbuf; nuclear@0: static int num_quads; nuclear@0: static int vattr = -1; nuclear@0: static int tattr = -1; nuclear@0: static unsigned int font_tex; nuclear@3: static int buf_mode = DTX_NBF; nuclear@0: nuclear@0: static struct dtx_font *font; nuclear@0: static int font_sz; nuclear@0: nuclear@0: nuclear@0: static int init(void) nuclear@0: { nuclear@0: if(qbuf) { nuclear@0: return 0; /* already initialized */ nuclear@0: } nuclear@0: nuclear@0: glewInit(); nuclear@0: nuclear@0: if(!(qbuf = malloc(QBUF_SZ * sizeof *qbuf))) { nuclear@0: return -1; nuclear@0: } nuclear@0: num_quads = 0; nuclear@0: nuclear@0: atexit(cleanup); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static void cleanup(void) nuclear@0: { nuclear@0: free(qbuf); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: void dtx_use_font(struct dtx_font *fnt, int sz) nuclear@0: { nuclear@0: init(); nuclear@0: nuclear@0: font = fnt; nuclear@0: font_sz = sz; nuclear@0: } nuclear@0: nuclear@0: void dtx_vertex_attribs(int vert_attr, int tex_attr) nuclear@0: { nuclear@0: vattr = vert_attr; nuclear@0: tattr = tex_attr; nuclear@0: } nuclear@0: nuclear@0: static void set_glyphmap_texture(struct dtx_glyphmap *gmap) nuclear@0: { nuclear@0: if(!gmap->tex) { nuclear@0: glGenTextures(1, &gmap->tex); nuclear@0: glBindTexture(GL_TEXTURE_2D, gmap->tex); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); nuclear@0: nuclear@0: #ifdef GL_ES nuclear@0: glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gmap->xsz, gmap->ysz, 0, GL_ALPHA, GL_UNSIGNED_BYTE, gmap->pixels); nuclear@0: glGenerateMipmap(GL_TEXTURE_2D); nuclear@0: #else nuclear@0: gluBuild2DMipmaps(GL_TEXTURE_2D, GL_ALPHA, gmap->xsz, gmap->ysz, GL_ALPHA, GL_UNSIGNED_BYTE, gmap->pixels); nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: if(font_tex != gmap->tex) { nuclear@0: dtx_flush(); nuclear@0: } nuclear@0: font_tex = gmap->tex; nuclear@0: } nuclear@0: nuclear@0: void dtx_glyph(int code) nuclear@0: { nuclear@0: struct dtx_glyphmap *gmap; nuclear@0: nuclear@0: if(!font || !(gmap = dtx_get_font_glyphmap(font, font_sz, code))) { nuclear@0: return; nuclear@0: } nuclear@0: set_glyphmap_texture(gmap); nuclear@0: nuclear@0: add_glyph(gmap->glyphs + code - gmap->cstart, 0, 0); nuclear@0: dtx_flush(); nuclear@0: } nuclear@0: nuclear@0: void dtx_string(const char *str) nuclear@0: { nuclear@0: struct dtx_glyphmap *gmap; nuclear@0: int should_flush = buf_mode == DTX_NBF; nuclear@0: float pos_x = 0.0f; nuclear@0: float pos_y = 0.0f; nuclear@0: nuclear@0: if(!font) { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: while(*str) { nuclear@0: int code = dtx_utf8_char_code(str); nuclear@0: str = dtx_utf8_next_char((char*)str); nuclear@0: nuclear@0: switch(code) { nuclear@0: case '\n': nuclear@0: if(buf_mode == DTX_LBF) { nuclear@0: should_flush = 1; nuclear@0: } nuclear@0: pos_x = 0.0; nuclear@0: pos_y -= gmap->line_advance; nuclear@0: break; nuclear@0: nuclear@0: case '\t': nuclear@0: pos_x = fmod(pos_x, 4.0) + 4.0; nuclear@0: break; nuclear@0: nuclear@0: case '\r': nuclear@0: pos_x = 0.0; nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: if((gmap = dtx_get_font_glyphmap(font, font_sz, code))) { nuclear@0: int idx = code - gmap->cstart; nuclear@0: nuclear@0: set_glyphmap_texture(gmap); nuclear@0: add_glyph(gmap->glyphs + idx, pos_x, pos_y); nuclear@0: pos_x += gmap->glyphs[idx].advance; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(should_flush) { nuclear@0: dtx_flush(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static void qvertex(struct vertex *v, float x, float y, float s, float t) nuclear@0: { nuclear@0: v->x = x; nuclear@0: v->y = y; nuclear@0: v->s = s; nuclear@0: v->t = t; nuclear@0: } nuclear@0: nuclear@0: static void add_glyph(struct glyph *g, float x, float y) nuclear@0: { nuclear@0: struct quad *qptr = qbuf + num_quads; nuclear@0: nuclear@0: x -= g->orig_x; nuclear@0: y -= g->orig_y; nuclear@0: nuclear@0: qvertex(qptr->v + 0, x, y, g->nx, g->ny + g->nheight); nuclear@0: qvertex(qptr->v + 1, x + g->width, y, g->nx + g->nwidth, g->ny + g->nheight); nuclear@0: qvertex(qptr->v + 2, x + g->width, y + g->height, g->nx + g->nwidth, g->ny); nuclear@0: nuclear@0: qvertex(qptr->v + 3, x, y, g->nx, g->ny + g->nheight); nuclear@0: qvertex(qptr->v + 4, x + g->width, y + g->height, g->nx + g->nwidth, g->ny); nuclear@0: qvertex(qptr->v + 5, x, y + g->height, g->nx, g->ny); nuclear@0: nuclear@0: if(++num_quads >= QBUF_SZ) { nuclear@0: dtx_flush(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void dtx_flush(void) nuclear@0: { nuclear@0: if(!num_quads) { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: #ifndef GL_ES nuclear@0: glPushAttrib(GL_ENABLE_BIT); nuclear@0: glEnable(GL_TEXTURE_2D); nuclear@0: #endif nuclear@0: glBindTexture(GL_TEXTURE_2D, font_tex); nuclear@0: nuclear@0: if(vattr != -1 && glEnableVertexAttribArray) { nuclear@0: glEnableVertexAttribArray(vattr); nuclear@0: glVertexAttribPointer(vattr, 2, GL_FLOAT, 0, sizeof(struct vertex), qbuf); nuclear@0: #ifndef GL_ES nuclear@0: } else { nuclear@0: glEnableClientState(GL_VERTEX_ARRAY); nuclear@0: glVertexPointer(2, GL_FLOAT, sizeof(struct vertex), qbuf); nuclear@0: #endif nuclear@0: } nuclear@0: if(tattr != -1 && glEnableVertexAttribArray) { nuclear@0: glEnableVertexAttribArray(tattr); nuclear@0: glVertexAttribPointer(tattr, 2, GL_FLOAT, 0, sizeof(struct vertex), &qbuf->v[0].s); nuclear@0: #ifndef GL_ES nuclear@0: } else { nuclear@0: glEnableClientState(GL_TEXTURE_COORD_ARRAY); nuclear@0: glTexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), &qbuf->v[0].s); nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: glEnable(GL_BLEND); nuclear@0: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); nuclear@0: nuclear@0: glDepthMask(0); nuclear@0: nuclear@0: glDrawArrays(GL_TRIANGLES, 0, num_quads * 6); nuclear@0: nuclear@0: glDepthMask(1); nuclear@0: nuclear@0: if(vattr != -1 && glDisableVertexAttribArray) { nuclear@0: glDisableVertexAttribArray(vattr); nuclear@0: #ifndef GL_ES nuclear@0: } else { nuclear@0: glDisableClientState(GL_VERTEX_ARRAY); nuclear@0: #endif nuclear@0: } nuclear@0: if(tattr != -1 && glDisableVertexAttribArray) { nuclear@0: glDisableVertexAttribArray(tattr); nuclear@0: #ifndef GL_ES nuclear@0: } else { nuclear@0: glDisableClientState(GL_TEXTURE_COORD_ARRAY); nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: #ifndef GL_ES nuclear@0: glPopAttrib(); nuclear@0: #else nuclear@0: glDisable(GL_BLEND); nuclear@0: #endif nuclear@0: nuclear@0: num_quads = 0; nuclear@0: } nuclear@0: nuclear@0: #endif /* !def NO_OPENGL */