home *** CD-ROM | disk | FTP | other *** search
- // rendertext.cpp: font rendering
-
- #include "cube.h"
-
- struct font
- {
- struct charinfo
- {
- short x, y, w, h;
- };
-
- char *name;
- Texture *tex;
- vector<charinfo> chars;
- short defaultw, defaulth;
- short offsetx, offsety, offsetw, offseth;
- };
-
- static hashtable<char *, font> fonts;
- static font *fontdef = NULL, *curfont = NULL;
-
- void newfont(char *name, char *tex, char *defaultw, char *defaulth, char *offsetx, char *offsety, char *offsetw, char *offseth)
- {
- font *f = fonts.access(name);
- if(!f)
- {
- name = newstring(name);
- f = &fonts[name];
- f->name = name;
- }
-
- f->tex = textureload(tex);
- f->chars.setsize(0);
- f->defaultw = ATOI(defaultw);
- f->defaulth = ATOI(defaulth);
- f->offsetx = ATOI(offsetx);
- f->offsety = ATOI(offsety);
- f->offsetw = ATOI(offsetw);
- f->offseth = ATOI(offseth);
-
- fontdef = f;
- }
-
- void fontchar(int x, int y, int w, int h)
- {
- if(!fontdef) return;
-
- font::charinfo &c = fontdef->chars.add();
- c.x = x;
- c.y = y;
- c.w = w ? w : fontdef->defaultw;
- c.h = h ? h : fontdef->defaulth;
- }
-
- COMMANDN(font, newfont, ARG_8STR);
- COMMANDN(fontchar, fontchar, ARG_4INT);
-
- bool setfont(char *name)
- {
- font *f = fonts.access(name);
- if(!f) return false;
- curfont = f;
- return true;
- }
-
- int char_width(int c, int x)
- {
- if(!curfont) return x;
- else if(c=='\t') x = (x+PIXELTAB)/PIXELTAB*PIXELTAB;
- else if(c==' ') x += curfont->defaultw;
- else if(curfont->chars.inrange(c-33))
- {
- c -= 33;
- x += curfont->chars[c].w + 1;
- }
- return x;
- }
-
- static vector<int> *columns = NULL;
-
- void text_startcolumns()
- {
- if(!columns) columns = new vector<int>;
- }
-
- void text_endcolumns()
- {
- DELETEP(columns);
- }
-
- int text_width(const char *str, int limit)
- {
- int x = 0, col = 0;
- for(int i = 0; str[i] && (limit<0 || i<limit); i++)
- {
- switch(str[i])
- {
- case '\f':
- i++;
- break;
-
- case '\t':
- x = char_width('\t', x);
- if(columns)
- {
- while(col>=columns->length()) columns->add(0);
- x = max(x, (*columns)[col]);
- (*columns)[col] = x;
- col++;
- }
- break;
-
- default:
- x = char_width(str[i], x);
- break;
- }
- }
- return x;
- }
-
- int text_visible(const char *str, int max)
- {
- int i = 0, x = 0;
- while(str[i])
- {
- if(str[i]=='\f')
- {
- i += 2;
- continue;
- }
- x = char_width(str[i], x);
- if(x > max) return i;
- ++i;
- }
- return i;
- }
-
- // cut strings to fit on screen
- void text_block(const char *str, int max, vector<char *> &lines)
- {
- if(!str) return;
- int visible;
- while((visible = text_visible(str, max)))
- {
- const char *newline = (const char *)memchr(str, '\n', visible);
- if(newline) visible = newline+1-str;
- else if(str[visible]) // wrap words
- {
- int v = visible;
- while(v > 0 && str[v] != ' ') v--;
- if(v) visible = v+1;
- }
- char *t = lines.add(newstring((size_t)visible));
- s_strncpy(t, str, visible+1);
- str += visible;
- }
- }
-
- void draw_textf(const char *fstr, int left, int top, ...)
- {
- s_sprintfdlv(str, top, fstr);
- draw_text(str, left, top);
- }
-
- void draw_text(const char *str, int left, int top)
- {
- if(!curfont) return;
-
- glBlendFunc(GL_ONE, GL_ONE);
- glBindTexture(GL_TEXTURE_2D, curfont->tex->id);
- glColor3ub(255, 255, 255);
-
- static float colorstack[8][4];
- int colorpos = 0, x = left, y = top, col = 0;
-
- glBegin(GL_QUADS);
- for(int i = 0; str[i]; i++)
- {
- int c = str[i];
- switch(c)
- {
- case '\t':
- if(columns && col<columns->length()) x = left + (*columns)[col++];
- else x = (x-left+PIXELTAB)/PIXELTAB*PIXELTAB+left;
- continue;
-
- case '\f':
- switch(str[i+1])
- {
- case '0': glColor3ub(64, 255, 128); i++; continue; // green: player talk
- case '1': glColor3ub(96, 160, 255); i++; continue; // blue: team chat
- case '2': glColor3ub(255, 192, 64); i++; continue; // yellow: gameplay action messages, only actions done by players
- case '3': glColor3ub(255, 64, 64); i++; continue; // red: important errors
- case '4': glColor3ub(128, 128, 128); i++; continue; // gray
- case '5': glColor3ub(255, 255, 255); i++; continue; // white: everything else
- case '6': glColor3ub(192, 64, 192); i++; continue; // magenta
- case 's': // save color
- if((size_t)colorpos<sizeof(colorstack)/sizeof(colorstack[0]))
- {
- glEnd();
- glGetFloatv(GL_CURRENT_COLOR, colorstack[colorpos++]);
- glBegin(GL_QUADS);
- }
- i++;
- continue;
- case 'r': // restore color
- if(colorpos>0)
- glColor4fv(colorstack[--colorpos]);
- i++;
- continue;
- default: i++; continue;
- }
-
- case ' ':
- x += curfont->defaultw;
- continue;
- }
-
- c -= 33;
- if(!curfont->chars.inrange(c)) continue;
-
- font::charinfo &info = curfont->chars[c];
- float tc_left = (info.x + curfont->offsetx) / float(curfont->tex->xs);
- float tc_top = (info.y + curfont->offsety) / float(curfont->tex->ys);
- float tc_right = (info.x + info.w + curfont->offsetw) / float(curfont->tex->xs);
- float tc_bottom = (info.y + info.h + curfont->offseth) / float(curfont->tex->ys);
-
- glTexCoord2f(tc_left, tc_top ); glVertex2i(x, y);
- glTexCoord2f(tc_right, tc_top ); glVertex2i(x + info.w, y);
- glTexCoord2f(tc_right, tc_bottom); glVertex2i(x + info.w, y + info.h);
- glTexCoord2f(tc_left, tc_bottom); glVertex2i(x, y + info.h);
-
- xtraverts += 4;
- x += info.w + 1;
- }
- glEnd();
- }
-
-